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