diff options
Diffstat (limited to 'arch/arm/mach-tegra/baseband-xmm-power2.c')
-rw-r--r-- | arch/arm/mach-tegra/baseband-xmm-power2.c | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/baseband-xmm-power2.c b/arch/arm/mach-tegra/baseband-xmm-power2.c new file mode 100644 index 00000000000..4295b395820 --- /dev/null +++ b/arch/arm/mach-tegra/baseband-xmm-power2.c | |||
@@ -0,0 +1,681 @@ | |||
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 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static unsigned long XYZ = 1000 * 1000000 + 800 * 1000 + 500; | ||
38 | |||
39 | module_param(modem_ver, ulong, 0644); | ||
40 | MODULE_PARM_DESC(modem_ver, | ||
41 | "baseband xmm power2 - modem software version"); | ||
42 | module_param(modem_flash, ulong, 0644); | ||
43 | MODULE_PARM_DESC(modem_flash, | ||
44 | "baseband xmm power2 - modem flash (1 = flash, 0 = flashless)"); | ||
45 | module_param(modem_pm, ulong, 0644); | ||
46 | MODULE_PARM_DESC(modem_pm, | ||
47 | "baseband xmm power2 - modem power management (1 = pm, 0 = no pm)"); | ||
48 | module_param(XYZ, ulong, 0644); | ||
49 | MODULE_PARM_DESC(XYZ, | ||
50 | "baseband xmm power2 - timing parameters X/Y/Z delay in ms"); | ||
51 | |||
52 | static struct baseband_power_platform_data *baseband_power2_driver_data; | ||
53 | static struct workqueue_struct *workqueue; | ||
54 | static struct baseband_xmm_power_work_t *baseband_xmm_power2_work; | ||
55 | |||
56 | static enum { | ||
57 | IPC_AP_WAKE_UNINIT, | ||
58 | IPC_AP_WAKE_IRQ_READY, | ||
59 | IPC_AP_WAKE_INIT1, | ||
60 | IPC_AP_WAKE_INIT2, | ||
61 | IPC_AP_WAKE_L, | ||
62 | IPC_AP_WAKE_H, | ||
63 | } ipc_ap_wake_state; | ||
64 | |||
65 | static irqreturn_t baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2 | ||
66 | (int irq, void *dev_id) | ||
67 | { | ||
68 | int value; | ||
69 | |||
70 | pr_debug("%s\n", __func__); | ||
71 | |||
72 | /* check for platform data */ | ||
73 | if (!baseband_power2_driver_data) | ||
74 | return IRQ_HANDLED; | ||
75 | |||
76 | value = gpio_get_value(baseband_power2_driver_data-> | ||
77 | modem.xmm.ipc_ap_wake); | ||
78 | |||
79 | /* IPC_AP_WAKE state machine */ | ||
80 | if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) { | ||
81 | pr_err("%s - spurious irq\n", __func__); | ||
82 | } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) { | ||
83 | if (!value) { | ||
84 | pr_debug("%s - IPC_AP_WAKE_INIT1" | ||
85 | " - got falling edge\n", | ||
86 | __func__); | ||
87 | /* go to IPC_AP_WAKE_INIT1 state */ | ||
88 | ipc_ap_wake_state = IPC_AP_WAKE_INIT1; | ||
89 | /* queue work */ | ||
90 | baseband_xmm_power2_work->state = | ||
91 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1; | ||
92 | queue_work(workqueue, (struct work_struct *) | ||
93 | baseband_xmm_power2_work); | ||
94 | } else { | ||
95 | pr_debug("%s - IPC_AP_WAKE_INIT1" | ||
96 | " - wait for falling edge\n", | ||
97 | __func__); | ||
98 | } | ||
99 | } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) { | ||
100 | if (!value) { | ||
101 | pr_debug("%s - IPC_AP_WAKE_INIT2" | ||
102 | " - wait for rising edge\n", | ||
103 | __func__); | ||
104 | } else { | ||
105 | pr_debug("%s - IPC_AP_WAKE_INIT2" | ||
106 | " - got rising edge\n", | ||
107 | __func__); | ||
108 | /* go to IPC_AP_WAKE_INIT2 state */ | ||
109 | ipc_ap_wake_state = IPC_AP_WAKE_INIT2; | ||
110 | /* queue work */ | ||
111 | baseband_xmm_power2_work->state = | ||
112 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2; | ||
113 | queue_work(workqueue, (struct work_struct *) | ||
114 | baseband_xmm_power2_work); | ||
115 | } | ||
116 | } else { | ||
117 | if (!value) { | ||
118 | pr_debug("%s - falling\n", __func__); | ||
119 | ipc_ap_wake_state = IPC_AP_WAKE_L; | ||
120 | } else { | ||
121 | pr_debug("%s - rising\n", __func__); | ||
122 | ipc_ap_wake_state = IPC_AP_WAKE_H; | ||
123 | } | ||
124 | return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id); | ||
125 | } | ||
126 | |||
127 | return IRQ_HANDLED; | ||
128 | } | ||
129 | |||
130 | static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2 | ||
131 | (int irq, void *dev_id) | ||
132 | { | ||
133 | int value; | ||
134 | |||
135 | pr_debug("%s\n", __func__); | ||
136 | |||
137 | /* check for platform data */ | ||
138 | if (!baseband_power2_driver_data) | ||
139 | return IRQ_HANDLED; | ||
140 | |||
141 | value = gpio_get_value(baseband_power2_driver_data-> | ||
142 | modem.xmm.ipc_ap_wake); | ||
143 | |||
144 | /* IPC_AP_WAKE state machine */ | ||
145 | if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) { | ||
146 | pr_err("%s - spurious irq\n", __func__); | ||
147 | } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) { | ||
148 | if (!value) { | ||
149 | pr_debug("%s - IPC_AP_WAKE_INIT1" | ||
150 | " - got falling edge\n", | ||
151 | __func__); | ||
152 | /* go to IPC_AP_WAKE_INIT2 state */ | ||
153 | ipc_ap_wake_state = IPC_AP_WAKE_INIT2; | ||
154 | /* queue work */ | ||
155 | baseband_xmm_power2_work->state = | ||
156 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2; | ||
157 | queue_work(workqueue, (struct work_struct *) | ||
158 | baseband_xmm_power2_work); | ||
159 | } else { | ||
160 | pr_debug("%s - IPC_AP_WAKE_INIT1" | ||
161 | " - wait for falling edge\n", | ||
162 | __func__); | ||
163 | } | ||
164 | } else { | ||
165 | if (!value) { | ||
166 | pr_debug("%s - falling\n", __func__); | ||
167 | ipc_ap_wake_state = IPC_AP_WAKE_L; | ||
168 | } else { | ||
169 | pr_debug("%s - rising\n", __func__); | ||
170 | ipc_ap_wake_state = IPC_AP_WAKE_H; | ||
171 | } | ||
172 | return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id); | ||
173 | } | ||
174 | |||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step1 | ||
179 | (struct work_struct *work) | ||
180 | { | ||
181 | int value; | ||
182 | |||
183 | pr_debug("%s {\n", __func__); | ||
184 | |||
185 | /* check for platform data */ | ||
186 | if (!baseband_power2_driver_data) | ||
187 | return; | ||
188 | |||
189 | /* check if IPC_HSIC_ACTIVE high */ | ||
190 | value = gpio_get_value(baseband_power2_driver_data-> | ||
191 | modem.xmm.ipc_hsic_active); | ||
192 | if (value != 1) { | ||
193 | pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | /* wait 30 ms */ | ||
198 | mdelay(30); | ||
199 | |||
200 | /* set IPC_HSIC_ACTIVE low */ | ||
201 | gpio_set_value(baseband_power2_driver_data-> | ||
202 | modem.xmm.ipc_hsic_active, 0); | ||
203 | |||
204 | pr_debug("%s }\n", __func__); | ||
205 | } | ||
206 | |||
207 | static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step2 | ||
208 | (struct work_struct *work) | ||
209 | { | ||
210 | int value; | ||
211 | |||
212 | pr_debug("%s {\n", __func__); | ||
213 | |||
214 | /* check for platform data */ | ||
215 | if (!baseband_power2_driver_data) | ||
216 | return; | ||
217 | |||
218 | /* check if IPC_HSIC_ACTIVE low */ | ||
219 | value = gpio_get_value(baseband_power2_driver_data-> | ||
220 | modem.xmm.ipc_hsic_active); | ||
221 | if (value != 0) { | ||
222 | pr_err("%s - expected IPC_HSIC_ACTIVE low!\n", __func__); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | /* wait 1 ms */ | ||
227 | mdelay(1); | ||
228 | |||
229 | /* unregister usb host controller */ | ||
230 | if (baseband_power2_driver_data->hsic_unregister) | ||
231 | baseband_power2_driver_data->hsic_unregister( | ||
232 | baseband_power2_driver_data->modem.xmm.hsic_device); | ||
233 | else | ||
234 | pr_err("%s: hsic_unregister is missing\n", __func__); | ||
235 | |||
236 | /* set IPC_HSIC_ACTIVE high */ | ||
237 | gpio_set_value(baseband_power2_driver_data-> | ||
238 | modem.xmm.ipc_hsic_active, 1); | ||
239 | |||
240 | /* wait 20 ms */ | ||
241 | mdelay(20); | ||
242 | |||
243 | /* set IPC_HSIC_ACTIVE low */ | ||
244 | gpio_set_value(baseband_power2_driver_data-> | ||
245 | modem.xmm.ipc_hsic_active, 0); | ||
246 | |||
247 | /* wait 20 ms */ | ||
248 | mdelay(20); | ||
249 | |||
250 | /* set IPC_HSIC_ACTIVE high */ | ||
251 | gpio_set_value(baseband_power2_driver_data-> | ||
252 | modem.xmm.ipc_hsic_active, 1); | ||
253 | |||
254 | pr_debug("%s }\n", __func__); | ||
255 | } | ||
256 | |||
257 | static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step1 | ||
258 | (struct work_struct *work) | ||
259 | { | ||
260 | int X = XYZ / 1000000; | ||
261 | int Y = XYZ / 1000 - X * 1000; | ||
262 | int Z = XYZ % 1000; | ||
263 | |||
264 | pr_info("%s {\n", __func__); | ||
265 | |||
266 | pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z); | ||
267 | |||
268 | /* check for platform data */ | ||
269 | if (!baseband_power2_driver_data) | ||
270 | return; | ||
271 | |||
272 | /* unregister usb host controller */ | ||
273 | if (baseband_power2_driver_data->hsic_unregister) | ||
274 | baseband_power2_driver_data->hsic_unregister( | ||
275 | baseband_power2_driver_data->modem.xmm.hsic_device); | ||
276 | else | ||
277 | pr_err("%s: hsic_unregister is missing\n", __func__); | ||
278 | |||
279 | /* wait X ms */ | ||
280 | mdelay(X); | ||
281 | |||
282 | /* set IPC_HSIC_ACTIVE low */ | ||
283 | gpio_set_value(baseband_power2_driver_data-> | ||
284 | modem.xmm.ipc_hsic_active, 0); | ||
285 | |||
286 | pr_info("%s }\n", __func__); | ||
287 | } | ||
288 | |||
289 | static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step2 | ||
290 | (struct work_struct *work) | ||
291 | { | ||
292 | int X = XYZ / 1000000; | ||
293 | int Y = XYZ / 1000 - X * 1000; | ||
294 | int Z = XYZ % 1000; | ||
295 | |||
296 | pr_info("%s {\n", __func__); | ||
297 | |||
298 | pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z); | ||
299 | |||
300 | /* check for platform data */ | ||
301 | if (!baseband_power2_driver_data) | ||
302 | return; | ||
303 | |||
304 | /* wait Y ms */ | ||
305 | mdelay(Y); | ||
306 | |||
307 | /* register usb host controller */ | ||
308 | if (baseband_power2_driver_data->hsic_register) | ||
309 | baseband_power2_driver_data->modem.xmm.hsic_device = | ||
310 | baseband_power2_driver_data->hsic_register(); | ||
311 | else | ||
312 | pr_err("%s: hsic_register is missing\n", __func__); | ||
313 | |||
314 | /* wait Z ms */ | ||
315 | mdelay(Z); | ||
316 | |||
317 | /* set IPC_HSIC_ACTIVE high */ | ||
318 | gpio_set_value(baseband_power2_driver_data-> | ||
319 | modem.xmm.ipc_hsic_active, 1); | ||
320 | |||
321 | /* queue work function to check if enumeration succeeded */ | ||
322 | baseband_xmm_power2_work->state = | ||
323 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3; | ||
324 | queue_work(workqueue, (struct work_struct *) | ||
325 | baseband_xmm_power2_work); | ||
326 | |||
327 | pr_info("%s }\n", __func__); | ||
328 | } | ||
329 | |||
330 | static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step3 | ||
331 | (struct work_struct *work) | ||
332 | { | ||
333 | int X = XYZ / 1000000; | ||
334 | int Y = XYZ / 1000 - X * 1000; | ||
335 | int Z = XYZ % 1000; | ||
336 | int enum_success = 0; | ||
337 | |||
338 | pr_info("%s {\n", __func__); | ||
339 | |||
340 | pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z); | ||
341 | |||
342 | /* check for platform data */ | ||
343 | if (!baseband_power2_driver_data) | ||
344 | return; | ||
345 | |||
346 | /* wait 500 ms */ | ||
347 | mdelay(500); | ||
348 | |||
349 | /* check if enumeration succeeded */ | ||
350 | { | ||
351 | mm_segment_t oldfs; | ||
352 | struct file *filp; | ||
353 | oldfs = get_fs(); | ||
354 | set_fs(KERNEL_DS); | ||
355 | filp = filp_open("/dev/ttyACM0", | ||
356 | O_RDONLY, 0); | ||
357 | if (IS_ERR(filp) || (filp == NULL)) { | ||
358 | pr_err("/dev/ttyACM0 %ld\n", | ||
359 | PTR_ERR(filp)); | ||
360 | } else { | ||
361 | filp_close(filp, NULL); | ||
362 | enum_success = 1; | ||
363 | } | ||
364 | set_fs(oldfs); | ||
365 | } | ||
366 | |||
367 | /* if enumeration failed, attempt recovery pulse */ | ||
368 | if (!enum_success) { | ||
369 | pr_info("attempting recovery pulse...\n"); | ||
370 | /* wait 20 ms */ | ||
371 | mdelay(20); | ||
372 | /* set IPC_HSIC_ACTIVE low */ | ||
373 | gpio_set_value(baseband_power2_driver_data-> | ||
374 | modem.xmm.ipc_hsic_active, 0); | ||
375 | /* wait 20 ms */ | ||
376 | mdelay(20); | ||
377 | /* set IPC_HSIC_ACTIVE high */ | ||
378 | gpio_set_value(baseband_power2_driver_data-> | ||
379 | modem.xmm.ipc_hsic_active, 1); | ||
380 | /* check if recovery pulse worked */ | ||
381 | baseband_xmm_power2_work->state = | ||
382 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4; | ||
383 | queue_work(workqueue, (struct work_struct *) | ||
384 | baseband_xmm_power2_work); | ||
385 | } | ||
386 | |||
387 | pr_info("%s }\n", __func__); | ||
388 | } | ||
389 | |||
390 | static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4 | ||
391 | (struct work_struct *work) | ||
392 | { | ||
393 | int X = XYZ / 1000000; | ||
394 | int Y = XYZ / 1000 - X * 1000; | ||
395 | int Z = XYZ % 1000; | ||
396 | int enum_success = 0; | ||
397 | |||
398 | pr_info("%s {\n", __func__); | ||
399 | |||
400 | pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z); | ||
401 | |||
402 | /* check for platform data */ | ||
403 | if (!baseband_power2_driver_data) | ||
404 | return; | ||
405 | |||
406 | /* wait 500 ms */ | ||
407 | mdelay(500); | ||
408 | |||
409 | /* check if enumeration succeeded */ | ||
410 | { | ||
411 | mm_segment_t oldfs; | ||
412 | struct file *filp; | ||
413 | oldfs = get_fs(); | ||
414 | set_fs(KERNEL_DS); | ||
415 | filp = filp_open("/dev/ttyACM0", | ||
416 | O_RDONLY, 0); | ||
417 | if (IS_ERR(filp) || (filp == NULL)) { | ||
418 | pr_err("open /dev/ttyACM0 failed %ld\n", | ||
419 | PTR_ERR(filp)); | ||
420 | } else { | ||
421 | filp_close(filp, NULL); | ||
422 | enum_success = 1; | ||
423 | } | ||
424 | set_fs(oldfs); | ||
425 | } | ||
426 | |||
427 | /* if recovery pulse did not fix enumeration, retry from beginning */ | ||
428 | if (!enum_success) { | ||
429 | static int retry = 3; | ||
430 | if (!retry) { | ||
431 | pr_info("failed to enumerate modem software" | ||
432 | " - too many retry attempts\n"); | ||
433 | } else { | ||
434 | pr_info("recovery pulse failed to fix modem" | ||
435 | " enumeration..." | ||
436 | " restarting from beginning" | ||
437 | " - attempt #%d\n", | ||
438 | retry); | ||
439 | --retry; | ||
440 | ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; | ||
441 | baseband_xmm_power2_work->state = | ||
442 | BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1; | ||
443 | queue_work(workqueue, (struct work_struct *) | ||
444 | baseband_xmm_power2_work); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | pr_info("%s }\n", __func__); | ||
449 | } | ||
450 | |||
451 | static int free_ipc_ap_wake_irq; | ||
452 | |||
453 | static void baseband_xmm_power2_work_func(struct work_struct *work) | ||
454 | { | ||
455 | struct baseband_xmm_power_work_t *bbxmm_work | ||
456 | = (struct baseband_xmm_power_work_t *) work; | ||
457 | int err; | ||
458 | |||
459 | pr_debug("%s bbxmm_work->state=%d\n", __func__, bbxmm_work->state); | ||
460 | |||
461 | switch (bbxmm_work->state) { | ||
462 | case BBXMM_WORK_UNINIT: | ||
463 | pr_debug("BBXMM_WORK_UNINIT\n"); | ||
464 | /* free baseband irq(s) */ | ||
465 | if (free_ipc_ap_wake_irq) { | ||
466 | free_irq(gpio_to_irq(baseband_power2_driver_data | ||
467 | ->modem.xmm.ipc_ap_wake), NULL); | ||
468 | free_ipc_ap_wake_irq = 0; | ||
469 | } | ||
470 | break; | ||
471 | case BBXMM_WORK_INIT: | ||
472 | pr_debug("BBXMM_WORK_INIT\n"); | ||
473 | /* request baseband irq(s) */ | ||
474 | ipc_ap_wake_state = IPC_AP_WAKE_UNINIT; | ||
475 | err = request_threaded_irq( | ||
476 | gpio_to_irq(baseband_power2_driver_data-> | ||
477 | modem.xmm.ipc_ap_wake), | ||
478 | NULL, | ||
479 | (modem_ver < XMM_MODEM_VER_1130) | ||
480 | ? baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2 | ||
481 | : baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2, | ||
482 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
483 | "BBXMM_POWER2_IPC_AP_WAKE_IRQ", | ||
484 | NULL); | ||
485 | if (err < 0) { | ||
486 | pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n", | ||
487 | __func__); | ||
488 | return; | ||
489 | } | ||
490 | free_ipc_ap_wake_irq = 1; | ||
491 | ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; | ||
492 | /* go to next state */ | ||
493 | bbxmm_work->state = (modem_flash && !modem_pm) | ||
494 | ? BBXMM_WORK_INIT_FLASH_STEP1 | ||
495 | : (modem_flash && modem_pm) | ||
496 | ? BBXMM_WORK_INIT_FLASH_PM_STEP1 | ||
497 | : (!modem_flash && modem_pm) | ||
498 | ? BBXMM_WORK_INIT_FLASHLESS_PM_STEP1 | ||
499 | : BBXMM_WORK_UNINIT; | ||
500 | queue_work(workqueue, work); | ||
501 | break; | ||
502 | case BBXMM_WORK_INIT_FLASH_STEP1: | ||
503 | pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n"); | ||
504 | break; | ||
505 | case BBXMM_WORK_INIT_FLASH_PM_STEP1: | ||
506 | pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n"); | ||
507 | /* go to next state */ | ||
508 | bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130) | ||
509 | ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1 | ||
510 | : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1; | ||
511 | queue_work(workqueue, work); | ||
512 | break; | ||
513 | case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1: | ||
514 | pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n"); | ||
515 | break; | ||
516 | case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1: | ||
517 | pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n"); | ||
518 | break; | ||
519 | case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1: | ||
520 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n"); | ||
521 | /* go to next state */ | ||
522 | bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130) | ||
523 | ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ | ||
524 | : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1; | ||
525 | queue_work(workqueue, work); | ||
526 | break; | ||
527 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ: | ||
528 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ" | ||
529 | " - waiting for IPC_AP_WAKE_IRQ to trigger step1\n"); | ||
530 | break; | ||
531 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1: | ||
532 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n"); | ||
533 | baseband_xmm_power2_flashless_pm_ver_lt_1130_step1(work); | ||
534 | break; | ||
535 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2: | ||
536 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2\n"); | ||
537 | baseband_xmm_power2_flashless_pm_ver_lt_1130_step2(work); | ||
538 | break; | ||
539 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1: | ||
540 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n"); | ||
541 | baseband_xmm_power2_flashless_pm_ver_ge_1130_step1(work); | ||
542 | break; | ||
543 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2: | ||
544 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2\n"); | ||
545 | baseband_xmm_power2_flashless_pm_ver_ge_1130_step2(work); | ||
546 | break; | ||
547 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3: | ||
548 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3\n"); | ||
549 | baseband_xmm_power2_flashless_pm_ver_ge_1130_step3(work); | ||
550 | break; | ||
551 | case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4: | ||
552 | pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4\n"); | ||
553 | baseband_xmm_power2_flashless_pm_ver_ge_1130_step4(work); | ||
554 | break; | ||
555 | } | ||
556 | |||
557 | } | ||
558 | |||
559 | static int baseband_xmm_power2_driver_probe(struct platform_device *device) | ||
560 | { | ||
561 | struct baseband_power_platform_data *data | ||
562 | = (struct baseband_power_platform_data *) | ||
563 | device->dev.platform_data; | ||
564 | |||
565 | pr_debug("%s\n", __func__); | ||
566 | |||
567 | /* save platform data */ | ||
568 | baseband_power2_driver_data = data; | ||
569 | |||
570 | /* init work queue */ | ||
571 | pr_debug("%s: init work queue\n", __func__); | ||
572 | workqueue = create_singlethread_workqueue | ||
573 | ("baseband_xmm_power2_workqueue"); | ||
574 | if (!workqueue) { | ||
575 | pr_err("cannot create workqueue\n"); | ||
576 | return -1; | ||
577 | } | ||
578 | baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *) | ||
579 | kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL); | ||
580 | if (!baseband_xmm_power2_work) { | ||
581 | pr_err("cannot allocate baseband_xmm_power2_work\n"); | ||
582 | return -1; | ||
583 | } | ||
584 | pr_debug("%s: BBXMM_WORK_INIT\n", __func__); | ||
585 | INIT_WORK((struct work_struct *) baseband_xmm_power2_work, | ||
586 | baseband_xmm_power2_work_func); | ||
587 | baseband_xmm_power2_work->state = BBXMM_WORK_INIT; | ||
588 | queue_work(workqueue, | ||
589 | (struct work_struct *) baseband_xmm_power2_work); | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int baseband_xmm_power2_driver_remove(struct platform_device *device) | ||
594 | { | ||
595 | struct baseband_power_platform_data *data | ||
596 | = (struct baseband_power_platform_data *) | ||
597 | device->dev.platform_data; | ||
598 | |||
599 | pr_debug("%s\n", __func__); | ||
600 | |||
601 | /* check for platform data */ | ||
602 | if (!data) | ||
603 | return 0; | ||
604 | |||
605 | /* free irq */ | ||
606 | if (free_ipc_ap_wake_irq) { | ||
607 | free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL); | ||
608 | free_ipc_ap_wake_irq = 0; | ||
609 | } | ||
610 | |||
611 | /* free work structure */ | ||
612 | if (workqueue) { | ||
613 | cancel_work_sync(baseband_xmm_power2_work); | ||
614 | destroy_workqueue(workqueue); | ||
615 | } | ||
616 | kfree(baseband_xmm_power2_work); | ||
617 | baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *) 0; | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | #ifdef CONFIG_PM | ||
623 | static int baseband_xmm_power2_driver_suspend(struct platform_device *device, | ||
624 | pm_message_t state) | ||
625 | { | ||
626 | struct baseband_power_platform_data *data | ||
627 | = (struct baseband_power_platform_data *) | ||
628 | device->dev.platform_data; | ||
629 | |||
630 | pr_debug("%s - nop\n", __func__); | ||
631 | |||
632 | /* check for platform data */ | ||
633 | if (!data) | ||
634 | return 0; | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int baseband_xmm_power2_driver_resume(struct platform_device *device) | ||
640 | { | ||
641 | struct baseband_power_platform_data *data | ||
642 | = (struct baseband_power_platform_data *) | ||
643 | device->dev.platform_data; | ||
644 | |||
645 | pr_debug("%s - nop\n", __func__); | ||
646 | |||
647 | /* check for platform data */ | ||
648 | if (!data) | ||
649 | return 0; | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | #endif | ||
654 | |||
655 | static struct platform_driver baseband_power2_driver = { | ||
656 | .probe = baseband_xmm_power2_driver_probe, | ||
657 | .remove = baseband_xmm_power2_driver_remove, | ||
658 | #ifdef CONFIG_PM | ||
659 | .suspend = baseband_xmm_power2_driver_suspend, | ||
660 | .resume = baseband_xmm_power2_driver_resume, | ||
661 | #endif | ||
662 | .driver = { | ||
663 | .name = "baseband_xmm_power2", | ||
664 | }, | ||
665 | }; | ||
666 | |||
667 | static int __init baseband_xmm_power2_init(void) | ||
668 | { | ||
669 | pr_debug("%s\n", __func__); | ||
670 | |||
671 | return platform_driver_register(&baseband_power2_driver); | ||
672 | } | ||
673 | |||
674 | static void __exit baseband_xmm_power2_exit(void) | ||
675 | { | ||
676 | pr_debug("%s\n", __func__); | ||
677 | platform_driver_unregister(&baseband_power2_driver); | ||
678 | } | ||
679 | |||
680 | module_init(baseband_xmm_power2_init) | ||
681 | module_exit(baseband_xmm_power2_exit) | ||