blob: 8b81c844f2df953ab1015cc04fb2532ead263c1f [file] [log] [blame]
Srikanth Uyyalabbd45292013-07-17 18:28:08 +05301/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2
3* This program is free software; you can redistribute it and/or modify
4* it under the terms of the GNU General Public License version 2 and
5* only version 2 as published by the Free Software Foundation.
6
7* This program is distributed in the hope that it will be useful,
8* but WITHOUT ANY WARRANTY; without even the implied warranty of
9* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10* GNU General Public License for more details.
11*/
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/fs.h>
17#include <linux/cdev.h>
18#include <linux/uaccess.h>
19#include <linux/device.h>
20#include <linux/io.h>
21#include <linux/platform_device.h>
22#include <linux/avtimer.h>
23#include <mach/qdsp6v2/apr.h>
24
25#define DEVICE_NAME "avtimer"
26
27
28#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
29
30static int major; /* Major number assigned to our device driver */
31struct avtimer_t {
32 struct cdev myc;
33 struct class *avtimer_class;
34 struct mutex avtimer_lock;
35 int avtimer_open_cnt;
36 struct dev_avtimer_data *avtimer_pdata;
37};
38static struct avtimer_t avtimer;
39
40static struct apr_svc *core_handle;
41
42struct adsp_power_collapse {
43 struct apr_hdr hdr;
44 uint32_t power_collapse;
45};
46
47static int32_t avcs_core_callback(struct apr_client_data *data, void *priv)
48{
49 uint32_t *payload;
50
51 pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
52 data->payload_size, data->opcode);
53
54 switch (data->opcode) {
55
56 case APR_BASIC_RSP_RESULT:{
57
58 if (data->payload_size == 0) {
59 pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
60 __func__);
61 return 0;
62 }
63
64 payload = data->payload;
65
66 switch (payload[0]) {
67
68 case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
69 pr_debug("CMD_SET_POWER_COLLAPSE_STATE status[0x%x]\n",
70 payload[1]);
71 break;
72 default:
73 pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
74 payload[0], payload[1]);
75 break;
76 }
77 break;
78 }
79 case RESET_EVENTS:{
80 pr_debug("Reset event received in Core service");
81 apr_reset(core_handle);
82 core_handle = NULL;
83 break;
84 }
85
86 default:
87 pr_err("Message id from adsp core svc: %d\n", data->opcode);
88 break;
89 }
90
91 return 0;
92}
93
94int avcs_core_open(void)
95{
96 if (core_handle == NULL)
97 core_handle = apr_register("ADSP", "CORE",
98 avcs_core_callback, 0xFFFFFFFF, NULL);
99
100 pr_debug("Open_q %p\n", core_handle);
101 if (core_handle == NULL) {
102 pr_err("%s: Unable to register CORE\n", __func__);
103 return -ENODEV;
104 }
105 return 0;
106}
107
108int avcs_core_disable_power_collapse(int disable)
109{
110 struct adsp_power_collapse pc;
111 int rc = 0;
112
113 if (core_handle) {
114 pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
115 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
116 pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
117 sizeof(uint32_t));
118 pc.hdr.src_port = 0;
119 pc.hdr.dest_port = 0;
120 pc.hdr.token = 0;
121 pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
122 /*
123 * When power_collapse set to 1 -- If the aDSP is in the power
124 * collapsed state when this command is received, it is awakened
125 * from this state. The aDSP does not power collapse again until
126 * the client revokes this command
127 * When power_collapse set to 0 -- This indicates to the aDSP
128 * that the remote client does not need it to be out of power
129 * collapse any longer. This may not always put the aDSP into
130 * power collapse; the aDSP must honor an internal client's
131 * power requirements as well.
132 */
133 pc.power_collapse = disable;
134 rc = apr_send_pkt(core_handle, (uint32_t *)&pc);
135 if (rc < 0) {
136 pr_debug("disable power collapse = %d failed\n",
137 disable);
138 return rc;
139 }
140 pr_debug("disable power collapse = %d\n", disable);
141 }
142 return 0;
143}
144
145static int avtimer_open(struct inode *inode, struct file *file)
146{
147 int rc = 0;
148 struct avtimer_t *pavtimer = &avtimer;
149
150 pr_debug("avtimer_open\n");
151 mutex_lock(&pavtimer->avtimer_lock);
152
153 if (pavtimer->avtimer_open_cnt != 0) {
154 pavtimer->avtimer_open_cnt++;
155 pr_debug("%s: opened avtimer open count=%d\n",
156 __func__, pavtimer->avtimer_open_cnt);
157 mutex_unlock(&pavtimer->avtimer_lock);
158 return 0;
159 }
160 try_module_get(THIS_MODULE);
161
162 rc = avcs_core_open();
163 if (rc)
164 goto leave;
165 if (core_handle)
166 rc = avcs_core_disable_power_collapse(1);
167 if (!rc)
168 pavtimer->avtimer_open_cnt++;
169
170leave:
171 pr_debug("%s: opened avtimer open count=%d\n",
172 __func__, pavtimer->avtimer_open_cnt);
173 mutex_unlock(&pavtimer->avtimer_lock);
174 pr_debug("avtimer_open leave rc=%d\n", rc);
175
176 return rc;
177}
178
179static int avtimer_release(struct inode *inode, struct file *file)
180{
181 int rc = 0;
182 struct avtimer_t *pavtimer = &avtimer;
183
184 mutex_lock(&pavtimer->avtimer_lock);
185 pavtimer->avtimer_open_cnt--;
186
187 if (core_handle && pavtimer->avtimer_open_cnt == 0)
188 rc = avcs_core_disable_power_collapse(0);
189
190 pr_debug("device_release(%p,%p) open count=%d\n",
191 inode, file, pavtimer->avtimer_open_cnt);
192
193 module_put(THIS_MODULE);
194
195 mutex_unlock(&pavtimer->avtimer_lock);
196
197 return rc;
198}
199
200/*
201 * ioctl call provides GET_AVTIMER
202 */
203static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
204 unsigned long ioctl_param)
205{
206 struct avtimer_t *pavtimer = &avtimer;
207 pr_debug("avtimer_ioctl: ioctlnum=%d,param=%lx\n",
208 ioctl_num, ioctl_param);
209
210 switch (ioctl_num) {
211 case IOCTL_GET_AVTIMER_TICK:
212 {
213 void __iomem *p_avtimer_msw = NULL, *p_avtimer_lsw = NULL;
214 uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
215 uint32_t avtimer_msw_2nd = 0;
216 uint64_t avtimer_tick;
217
218 if (pavtimer->avtimer_pdata) {
219 p_avtimer_lsw = ioremap(
220 pavtimer->avtimer_pdata->avtimer_lsw_phy_addr, 4);
221 p_avtimer_msw = ioremap(
222 pavtimer->avtimer_pdata->avtimer_msw_phy_addr, 4);
223 }
224 if (!p_avtimer_lsw || !p_avtimer_msw) {
225 pr_err("ioremap failed\n");
226 return -EIO;
227 }
228 do {
229 avtimer_msw_1st = ioread32(p_avtimer_msw);
230 avtimer_lsw = ioread32(p_avtimer_lsw);
231 avtimer_msw_2nd = ioread32(p_avtimer_msw);
232 } while (avtimer_msw_1st != avtimer_msw_2nd);
233
234 avtimer_tick =
235 ((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw;
236
237 pr_debug("AV Timer tick: msw: %d, lsw: %d\n", avtimer_msw_1st,
238 avtimer_lsw);
239 if (copy_to_user((void *) ioctl_param, &avtimer_tick,
240 sizeof(avtimer_tick))) {
241 pr_err("copy_to_user failed\n");
242 iounmap(p_avtimer_lsw);
243 iounmap(p_avtimer_msw);
244 return -EFAULT;
245 }
246 iounmap(p_avtimer_lsw);
247 iounmap(p_avtimer_msw);
248 }
249 break;
250
251 default:
252 pr_err("invalid cmd\n");
253 break;
254 }
255
256 return 0;
257}
258
259static const struct file_operations avtimer_fops = {
260 .unlocked_ioctl = avtimer_ioctl,
261 .open = avtimer_open,
262 .release = avtimer_release
263};
264
265static int dev_avtimer_probe(struct platform_device *pdev)
266{
267 int result;
268 dev_t dev = MKDEV(major, 0);
269 struct device *device_handle;
270 struct avtimer_t *pavtimer = &avtimer;
271
272 /* get the device number */
273 if (major)
274 result = register_chrdev_region(dev, 1, DEVICE_NAME);
275 else {
276 result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
277 major = MAJOR(dev);
278 }
279
280 if (result < 0) {
281 pr_err("Registering avtimer device failed\n");
282 return result;
283 }
284
285 pavtimer->avtimer_class = class_create(THIS_MODULE, "avtimer");
286 if (IS_ERR(pavtimer->avtimer_class)) {
287 result = PTR_ERR(pavtimer->avtimer_class);
288 pr_err("Error creating avtimer class: %d\n", result);
289 goto unregister_chrdev_region;
290 }
291 pavtimer->avtimer_pdata = pdev->dev.platform_data;
292
293 cdev_init(&pavtimer->myc, &avtimer_fops);
294 result = cdev_add(&pavtimer->myc, dev, 1);
295
296 if (result < 0) {
297 pr_err("Registering file operations failed\n");
298 goto class_destroy;
299 }
300
301 device_handle = device_create(pavtimer->avtimer_class,
302 NULL, pavtimer->myc.dev, NULL, "avtimer");
303 if (IS_ERR(device_handle)) {
304 result = PTR_ERR(device_handle);
305 pr_err("device_create failed: %d\n", result);
306 goto class_destroy;
307 }
308
309 mutex_init(&pavtimer->avtimer_lock);
310 core_handle = NULL;
311 pavtimer->avtimer_open_cnt = 0;
312
313 pr_debug("Device create done for avtimer major=%d\n", major);
314
315 return 0;
316
317class_destroy:
318 class_destroy(pavtimer->avtimer_class);
319unregister_chrdev_region:
320 unregister_chrdev_region(MKDEV(major, 0), 1);
321 return result;
322
323}
324
325static int __devexit dev_avtimer_remove(struct platform_device *pdev)
326{
327 struct avtimer_t *pavtimer = &avtimer;
328
329 pr_debug("dev_avtimer_remove\n");
330
331 device_destroy(pavtimer->avtimer_class, pavtimer->myc.dev);
332 cdev_del(&pavtimer->myc);
333 class_destroy(pavtimer->avtimer_class);
334 unregister_chrdev_region(MKDEV(major, 0), 1);
335
336 return 0;
337}
338
339static struct platform_driver dev_avtimer_driver = {
340 .probe = dev_avtimer_probe,
341 .remove = __exit_p(dev_avtimer_remove),
342 .driver = {.name = "dev_avtimer"}
343};
344
345static int __init avtimer_init(void)
346{
347 s32 rc;
348 rc = platform_driver_register(&dev_avtimer_driver);
349 if (IS_ERR_VALUE(rc)) {
350 pr_err("platform_driver_register failed.\n");
351 goto error_platform_driver;
352 }
353 pr_debug("dev_avtimer_init : done\n");
354
355 return 0;
356error_platform_driver:
357
358 pr_err("encounterd error\n");
359 return -ENODEV;
360}
361
362static void __exit avtimer_exit(void)
363{
364 pr_debug("avtimer_exit\n");
365 platform_driver_unregister(&dev_avtimer_driver);
366}
367
368module_init(avtimer_init);
369module_exit(avtimer_exit);
370
371MODULE_DESCRIPTION("avtimer driver");
372MODULE_LICENSE("GPL v2");