blob: 3de71dddb589325a573052c35e762caa23a12b73 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/htc_acoustic.c
2 *
3 * Copyright (C) 2007-2008 HTC Corporation
4 * Author: Laurence Chen <Laurence_Chen@htc.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16#include <linux/device.h>
17#include <linux/fs.h>
18#include <linux/module.h>
19#include <linux/miscdevice.h>
20#include <linux/mm.h>
21#include <linux/err.h>
22#include <linux/delay.h>
23#include <linux/kernel.h>
24#include <linux/uaccess.h>
25#include <linux/mutex.h>
26#include <linux/sched.h>
27
28#include <mach/msm_smd.h>
29#include <mach/msm_rpcrouter.h>
30#include <mach/msm_iomap.h>
31
32#include "smd_private.h"
33
34#define ACOUSTIC_IOCTL_MAGIC 'p'
35#define ACOUSTIC_ARM11_DONE _IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int)
36
37#define HTCRPOG 0x30100002
38#define HTCVERS 0
39#define ONCRPC_SET_MIC_BIAS_PROC (1)
40#define ONCRPC_ACOUSTIC_INIT_PROC (5)
41#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6)
42
43#define HTC_ACOUSTIC_TABLE_SIZE (0x10000)
44
45#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
46#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
47
48struct set_smem_req {
49 struct rpc_request_hdr hdr;
50 uint32_t size;
51};
52
53struct set_smem_rep {
54 struct rpc_reply_hdr hdr;
55 int n;
56};
57
58struct set_acoustic_req {
59 struct rpc_request_hdr hdr;
60};
61
62struct set_acoustic_rep {
63 struct rpc_reply_hdr hdr;
64 int n;
65};
66
67static uint32_t htc_acoustic_vir_addr;
68static struct msm_rpc_endpoint *endpoint;
69static struct mutex api_lock;
70
71static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
72{
73 unsigned long pgoff, delta;
74 int rc = -EINVAL;
75 size_t size;
76
77 D("mmap\n");
78
79 mutex_lock(&api_lock);
80
81 size = vma->vm_end - vma->vm_start;
82
83 if (vma->vm_pgoff != 0) {
84 E("mmap failed: page offset %lx\n", vma->vm_pgoff);
85 goto done;
86 }
87
88 if (!htc_acoustic_vir_addr) {
89 E("mmap failed: smem region not allocated\n");
90 rc = -EIO;
91 goto done;
92 }
93
94 pgoff = MSM_SHARED_RAM_PHYS +
95 (htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
96 delta = PAGE_ALIGN(pgoff) - pgoff;
97
98 if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) {
99 E("mmap failed: size %d\n", size);
100 goto done;
101 }
102
103 pgoff += delta;
104 vma->vm_flags |= VM_IO | VM_RESERVED;
105
106 rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT,
107 size, vma->vm_page_prot);
108
109 if (rc < 0)
110 E("mmap failed: remap error %d\n", rc);
111
112done: mutex_unlock(&api_lock);
113 return rc;
114}
115
116static int acoustic_open(struct inode *inode, struct file *file)
117{
118 int rc = -EIO;
119 struct set_smem_req req_smem;
120 struct set_smem_rep rep_smem;
121
122 D("open\n");
123
124 mutex_lock(&api_lock);
125
126 if (!htc_acoustic_vir_addr) {
127 if (endpoint == NULL) {
128 endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0);
129 if (IS_ERR(endpoint)) {
130 E("init rpc failed! rc = %ld\n",
131 PTR_ERR(endpoint));
132 endpoint = NULL;
133 goto done;
134 }
135 }
136
137 req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
138 rc = msm_rpc_call_reply(endpoint,
139 ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
140 &req_smem, sizeof(req_smem),
141 &rep_smem, sizeof(rep_smem),
142 5 * HZ);
143
144 if (rep_smem.n != 0 || rc < 0) {
145 E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
146 rc);
147 goto done;
148 }
149 htc_acoustic_vir_addr =
150 (uint32_t)smem_alloc(SMEM_ID_VENDOR1,
151 HTC_ACOUSTIC_TABLE_SIZE);
152 if (!htc_acoustic_vir_addr) {
153 E("open failed: smem_alloc error\n");
154 goto done;
155 }
156 }
157
158 rc = 0;
159done:
160 mutex_unlock(&api_lock);
161 return rc;
162}
163
164static int acoustic_release(struct inode *inode, struct file *file)
165{
166 D("release\n");
167 return 0;
168}
169
170static long acoustic_ioctl(struct file *file, unsigned int cmd,
171 unsigned long arg)
172{
173 int rc, reply_value;
174 struct set_acoustic_req req;
175 struct set_acoustic_rep rep;
176
177 D("ioctl\n");
178
179 mutex_lock(&api_lock);
180
181 switch (cmd) {
182 case ACOUSTIC_ARM11_DONE:
183 D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid);
184 rc = msm_rpc_call_reply(endpoint,
185 ONCRPC_ACOUSTIC_INIT_PROC, &req,
186 sizeof(req), &rep, sizeof(rep),
187 5 * HZ);
188
189 reply_value = be32_to_cpu(rep.n);
190 if (reply_value != 0 || rc < 0) {
191 E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\
192 "error %d.\n", rc);
193 if (rc >= 0)
194 rc = -EIO;
195 break;
196 }
197 D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n");
198 break;
199 default:
200 E("ioctl: invalid command\n");
201 rc = -EINVAL;
202 }
203
204 mutex_unlock(&api_lock);
205 return 0;
206}
207
208
209static struct file_operations acoustic_fops = {
210 .owner = THIS_MODULE,
211 .open = acoustic_open,
212 .release = acoustic_release,
213 .mmap = acoustic_mmap,
214 .unlocked_ioctl = acoustic_ioctl,
215};
216
217static struct miscdevice acoustic_misc = {
218 .minor = MISC_DYNAMIC_MINOR,
219 .name = "htc-acoustic",
220 .fops = &acoustic_fops,
221};
222
223static int __init acoustic_init(void)
224{
225 mutex_init(&api_lock);
226 return misc_register(&acoustic_misc);
227}
228
229static void __exit acoustic_exit(void)
230{
231 misc_deregister(&acoustic_misc);
232}
233
234module_init(acoustic_init);
235module_exit(acoustic_exit);
236
237MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
238MODULE_DESCRIPTION("HTC acoustic driver");
239MODULE_LICENSE("GPL");