3c6285c0a0700c8c96c8e694982ff75dbb49485b
[linux-2.6.git] / arch / arm / mach-tegra / baseband-xmm-power2.c
1 /*
2  * arch/arm/mach-tegra/baseband-xmm-power2.c
3  *
4  * Copyright (C) 2011 NVIDIA Corporation
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
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/moduleparam.h>
21 #include <linux/platform_device.h>
22 #include <linux/gpio.h>
23 #include <linux/interrupt.h>
24 #include <linux/workqueue.h>
25 #include <linux/slab.h>
26 #include <linux/delay.h>
27 #include <linux/fs.h>
28 #include <linux/uaccess.h>
29 #include <linux/wakelock.h>
30 #include <mach/usb_phy.h>
31 #include "baseband-xmm-power.h"
32 #include "board.h"
33 #include "devices.h"
34
35 static unsigned long XYZ = 1000 * 1000000 + 800 * 1000 + 500;
36
37 module_param(modem_ver, ulong, 0644);
38 MODULE_PARM_DESC(modem_ver,
39         "baseband xmm power2 - modem software version");
40 module_param(modem_flash, ulong, 0644);
41 MODULE_PARM_DESC(modem_flash,
42         "baseband xmm power2 - modem flash (1 = flash, 0 = flashless)");
43 module_param(modem_pm, ulong, 0644);
44 MODULE_PARM_DESC(modem_pm,
45         "baseband xmm power2 - modem power management (1 = pm, 0 = no pm)");
46 module_param(XYZ, ulong, 0644);
47 MODULE_PARM_DESC(XYZ,
48         "baseband xmm power2 - timing parameters X/Y/Z delay in ms");
49
50 static struct workqueue_struct *workqueue;
51 static bool free_ipc_ap_wake_irq;
52
53 static enum {
54         IPC_AP_WAKE_UNINIT,
55         IPC_AP_WAKE_IRQ_READY,
56         IPC_AP_WAKE_INIT1,
57         IPC_AP_WAKE_INIT2,
58         IPC_AP_WAKE_L,
59         IPC_AP_WAKE_H,
60 } ipc_ap_wake_state;
61
62
63 static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
64 {
65         int value;
66         struct xmm_power_data *data = dev_id;
67         struct baseband_power_platform_data *pdata = data->pdata;
68
69         pr_debug("%s\n", __func__);
70
71         /* check for platform data */
72         if (!pdata)
73                 return IRQ_HANDLED;
74
75         value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
76
77         /* IPC_AP_WAKE state machine */
78         if (unlikely(ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY))
79                 pr_err("%s - spurious irq\n", __func__);
80         else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
81                 if (!value) {
82                         pr_debug("%s: IPC_AP_WAKE_INIT1 got falling edge\n",
83                                 __func__);
84                         /* go to IPC_AP_WAKE_INIT2 state */
85                         ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
86                         /* queue work */
87                         data->state =
88                                 BBXMM_WORK_INIT_FLASHLESS_PM_STEP2;
89                         queue_work(workqueue, &data->work);
90                 } else
91                         pr_debug("%s: IPC_AP_WAKE_INIT1"
92                                 " wait for falling edge\n", __func__);
93         } else {
94                 if (!value) {
95                         pr_debug("%s - falling\n", __func__);
96                         ipc_ap_wake_state = IPC_AP_WAKE_L;
97                 } else {
98                         pr_debug("%s - rising\n", __func__);
99                         ipc_ap_wake_state = IPC_AP_WAKE_H;
100                 }
101                 return xmm_power_ipc_ap_wake_irq(irq, dev_id);
102         }
103
104         return IRQ_HANDLED;
105 }
106
107 static void xmm_power2_step1(struct work_struct *work)
108 {
109         struct xmm_power_data *data =
110                         container_of(work, struct xmm_power_data, work);
111         struct baseband_power_platform_data *pdata = data->pdata;
112         int X = XYZ / 1000000;
113
114         pr_info("%s {\n", __func__);
115
116         /* check for platform data */
117         if (!pdata)
118                 return;
119
120         /* unregister usb host controller */
121         if (pdata->hsic_unregister)
122                 pdata->hsic_unregister(data->hsic_device);
123         else
124                 pr_err("%s: hsic_unregister is missing\n", __func__);
125
126         /* wait X ms */
127         msleep(X);
128
129         /* set IPC_HSIC_ACTIVE low */
130         gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
131
132         pr_info("%s }\n", __func__);
133 }
134
135 static void xmm_power2_step2(struct work_struct *work)
136 {
137         struct xmm_power_data *data =
138                         container_of(work, struct xmm_power_data, work);
139         struct baseband_power_platform_data *pdata = data->pdata;
140         int X = XYZ / 1000000;
141         int Y = XYZ / 1000 - X * 1000;
142         int Z = XYZ % 1000;
143
144         pr_info("%s {\n", __func__);
145
146         /* check for platform data */
147         if (!data || !pdata)
148                 return;
149
150         /* wait Y ms */
151         msleep(Y);
152
153         /* register usb host controller */
154         if (pdata->hsic_register)
155                 data->hsic_device = pdata->hsic_register();
156         else
157                 pr_err("%s: hsic_register is missing\n", __func__);
158
159         /* wait Z ms */
160         msleep(Z);
161
162         /* set IPC_HSIC_ACTIVE high */
163         gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
164
165         /* queue work function to check if enumeration succeeded */
166         data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP3;
167         queue_work(workqueue, &data->work);
168
169         pr_info("%s }\n", __func__);
170 }
171
172 static void xmm_power2_step3(struct work_struct *work)
173 {
174         struct xmm_power_data *data =
175                         container_of(work, struct xmm_power_data, work);
176         struct baseband_power_platform_data *pdata = data->pdata;
177         int enum_success = 0;
178         mm_segment_t oldfs;
179         struct file *filp;
180
181         pr_info("%s {\n", __func__);
182
183         /* check for platform data */
184         if (!data || !pdata)
185                 return;
186
187         /* wait 1 sec */
188         msleep(1000);
189
190         /* check if enumeration succeeded */
191         oldfs = get_fs();
192         set_fs(KERNEL_DS);
193         filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
194         if (IS_ERR(filp) || (filp == NULL))
195                 pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
196         else {
197                 filp_close(filp, NULL);
198                 enum_success = 1;
199         }
200         set_fs(oldfs);
201
202         /* if enumeration failed, attempt recovery pulse */
203         if (!enum_success) {
204                 pr_info("attempting recovery pulse...\n");
205                 /* wait 20 ms */
206                 msleep(20);
207                 /* set IPC_HSIC_ACTIVE low */
208                 gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
209                 /* wait 20 ms */
210                 msleep(20);
211                 /* set IPC_HSIC_ACTIVE high */
212                 gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
213                 /* check if recovery pulse worked */
214                 data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP4;
215                 queue_work(workqueue, &data->work);
216         }
217
218         pr_info("%s }\n", __func__);
219 }
220
221 static void xmm_power2_step4(struct work_struct *work)
222 {
223         struct xmm_power_data *data =
224                         container_of(work, struct xmm_power_data, work);
225         mm_segment_t oldfs;
226         struct file *filp;
227         int enum_success = 0;
228
229         pr_info("%s {\n", __func__);
230
231         /* check for platform data */
232         if (!data)
233                 return;
234
235         /* wait 500 ms */
236         msleep(500);
237
238         /* check if enumeration succeeded */
239         oldfs = get_fs();
240         set_fs(KERNEL_DS);
241         filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
242         if (IS_ERR(filp) || (filp == NULL))
243                 pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
244         else {
245                 filp_close(filp, NULL);
246                 enum_success = 1;
247         }
248         set_fs(oldfs);
249
250         /* if recovery pulse did not fix enumeration, retry from beginning */
251         if (!enum_success) {
252                 static int retry = 3;
253                 if (!retry) {
254                         pr_info("failed to enumerate modem software"
255                                 " - too many retry attempts\n");
256                 } else {
257                         pr_info("recovery pulse failed to fix modem"
258                                 " enumeration..."
259                                 " restarting from beginning"
260                                 " - attempt #%d\n",
261                                 retry);
262                         --retry;
263                         ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
264                         data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP1;
265                         queue_work(workqueue, &data->work);
266                 }
267         }
268
269         pr_info("%s }\n", __func__);
270 }
271
272 static void xmm_power2_work_func(struct work_struct *work)
273 {
274         struct xmm_power_data *data =
275                         container_of(work, struct xmm_power_data, work);
276         struct baseband_power_platform_data *pdata = data->pdata;
277         int err;
278
279         pr_debug("%s pdata->state=%d\n", __func__, data->state);
280
281         switch (data->state) {
282         case BBXMM_WORK_UNINIT:
283                 pr_debug("BBXMM_WORK_UNINIT\n");
284                 /* free baseband irq(s) */
285                 if (free_ipc_ap_wake_irq) {
286                         free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
287                                         data);
288                         free_ipc_ap_wake_irq = false;
289                 }
290                 break;
291         case BBXMM_WORK_INIT:
292                 pr_debug("BBXMM_WORK_INIT\n");
293                 /* request baseband irq(s) */
294                 ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
295                 err = request_threaded_irq(
296                                 gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
297                                 NULL, xmm_power2_ipc_ap_wake_irq,
298                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
299                                 "xmm_power2_ipc_ap_wake_irq", data);
300                 if (err < 0) {
301                         pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
302                                 __func__);
303                         return;
304                 }
305                 free_ipc_ap_wake_irq = true;
306                 ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
307
308                 /* go to next state */
309                 data->state = (modem_flash && !modem_pm)
310                         ? BBXMM_WORK_INIT_FLASH_STEP1
311                         : (modem_flash && modem_pm)
312                         ? BBXMM_WORK_INIT_FLASH_PM_STEP1
313                         : (!modem_flash && modem_pm)
314                         ? BBXMM_WORK_INIT_FLASHLESS_PM_STEP1
315                         : BBXMM_WORK_UNINIT;
316                 queue_work(workqueue, work);
317                 break;
318         case BBXMM_WORK_INIT_FLASH_STEP1:
319                 pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
320                 pr_info("%s: flashed modem is not supported here\n", __func__);
321                 break;
322         case BBXMM_WORK_INIT_FLASH_PM_STEP1:
323                 pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
324                 pr_info("%s: flashed modem is not supported here\n", __func__);
325                 break;
326         case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
327                 /* start flashless modem enum process */
328                 pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
329                 xmm_power2_step1(work);
330                 break;
331         case BBXMM_WORK_INIT_FLASHLESS_PM_STEP2:
332                 pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP2\n");
333                 xmm_power2_step2(work);
334                 break;
335         case BBXMM_WORK_INIT_FLASHLESS_PM_STEP3:
336                 pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP3\n");
337                 xmm_power2_step3(work);
338                 break;
339         case BBXMM_WORK_INIT_FLASHLESS_PM_STEP4:
340                 pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP4\n");
341                 xmm_power2_step4(work);
342                 break;
343         default:
344                 break;
345         }
346 }
347
348 static int xmm_power2_probe(struct platform_device *device)
349 {
350         pr_debug("%s\n", __func__);
351         if (!device->dev.platform_data) {
352                 pr_err("%s: no platform data found\n", __func__);
353                 return -ENOMEM;
354         }
355
356         xmm_power_drv_data.pdata = device->dev.platform_data;
357
358         /* create workqueue */
359         pr_debug("%s: init work queue\n", __func__);
360         workqueue = create_singlethread_workqueue("xmm_power2_wq");
361         if (unlikely(!workqueue)) {
362                 pr_err("%s: cannot create workqueue\n", __func__);
363                 return -ENOMEM;
364         }
365
366         /* init work */
367         pr_debug("%s: BBXMM_WORK_INIT\n", __func__);
368         INIT_WORK(&xmm_power_drv_data.work, xmm_power2_work_func);
369         xmm_power_drv_data.state = BBXMM_WORK_INIT;
370         queue_work(workqueue, &xmm_power_drv_data.work);
371
372         return 0;
373 }
374
375 static int xmm_power2_remove(struct platform_device *device)
376 {
377         struct baseband_power_platform_data *pdata =
378                         device->dev.platform_data;
379         struct xmm_power_data *data = &xmm_power_drv_data;
380
381         pr_debug("%s\n", __func__);
382
383         /* check for platform data */
384         if (!data)
385                 return -ENODEV;
386
387         /* free work queue */
388         if (workqueue) {
389                 cancel_work_sync(&data->work);
390                 destroy_workqueue(workqueue);
391         }
392
393         /* free irq */
394         if (free_ipc_ap_wake_irq) {
395                 free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), data);
396                 free_ipc_ap_wake_irq = false;
397         }
398
399         return 0;
400 }
401
402 #ifdef CONFIG_PM
403 static int xmm_power2_suspend(struct platform_device *device,
404         pm_message_t state)
405 {
406         struct baseband_power_platform_data *data =
407                         device->dev.platform_data;
408
409         pr_debug("%s - nop\n", __func__);
410
411         /* check for platform data */
412         if (!data)
413                 return 0;
414
415         return 0;
416 }
417
418 static int xmm_power2_resume(struct platform_device *device)
419 {
420         struct baseband_power_platform_data *data =
421                         device->dev.platform_data;
422
423         pr_debug("%s - nop\n", __func__);
424
425         /* check for platform data */
426         if (!data)
427                 return 0;
428
429         return 0;
430 }
431 #endif
432
433 static struct platform_driver baseband_power2_driver = {
434         .probe = xmm_power2_probe,
435         .remove = xmm_power2_remove,
436 #ifdef CONFIG_PM
437         .suspend = xmm_power2_suspend,
438         .resume = xmm_power2_resume,
439 #endif
440         .driver = {
441                 .name = "baseband_xmm_power2",
442         },
443 };
444
445 static int __init xmm_power2_init(void)
446 {
447         pr_debug("%s\n", __func__);
448
449         return platform_driver_register(&baseband_power2_driver);
450 }
451
452 static void __exit xmm_power2_exit(void)
453 {
454         pr_debug("%s\n", __func__);
455
456         platform_driver_unregister(&baseband_power2_driver);
457 }
458
459 module_init(xmm_power2_init)
460 module_exit(xmm_power2_exit)
461
462 MODULE_LICENSE("GPL");