aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/baseband-xmm-power2.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/baseband-xmm-power2.c')
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power2.c681
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
35MODULE_LICENSE("GPL");
36
37static unsigned long XYZ = 1000 * 1000000 + 800 * 1000 + 500;
38
39module_param(modem_ver, ulong, 0644);
40MODULE_PARM_DESC(modem_ver,
41 "baseband xmm power2 - modem software version");
42module_param(modem_flash, ulong, 0644);
43MODULE_PARM_DESC(modem_flash,
44 "baseband xmm power2 - modem flash (1 = flash, 0 = flashless)");
45module_param(modem_pm, ulong, 0644);
46MODULE_PARM_DESC(modem_pm,
47 "baseband xmm power2 - modem power management (1 = pm, 0 = no pm)");
48module_param(XYZ, ulong, 0644);
49MODULE_PARM_DESC(XYZ,
50 "baseband xmm power2 - timing parameters X/Y/Z delay in ms");
51
52static struct baseband_power_platform_data *baseband_power2_driver_data;
53static struct workqueue_struct *workqueue;
54static struct baseband_xmm_power_work_t *baseband_xmm_power2_work;
55
56static 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
65static 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
130static 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
178static 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
207static 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
257static 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
289static 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
330static 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
390static 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
451static int free_ipc_ap_wake_irq;
452
453static 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
559static 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
593static 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
623static 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
639static 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
655static 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
667static 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
674static void __exit baseband_xmm_power2_exit(void)
675{
676 pr_debug("%s\n", __func__);
677 platform_driver_unregister(&baseband_power2_driver);
678}
679
680module_init(baseband_xmm_power2_init)
681module_exit(baseband_xmm_power2_exit)