blob: a7ba4a08fa08f9f1be01e1e8bf5e1ec4960c36da [file] [log] [blame]
Joel Kinge9cd5272012-01-28 12:48:59 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Joel Kingb6f0f612011-11-01 16:59:14 -07002 *
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
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/err.h>
17#include <linux/slab.h>
18#include <linux/io.h>
19#include <linux/mutex.h>
20#include <linux/miscdevice.h>
21#include <linux/fs.h>
22#include <linux/gpio.h>
23#include <linux/kernel.h>
24#include <linux/irq.h>
25#include <linux/ioctl.h>
26#include <linux/delay.h>
27#include <linux/reboot.h>
28#include <linux/debugfs.h>
29#include <linux/completion.h>
30#include <linux/workqueue.h>
31#include <linux/clk.h>
32#include <linux/mfd/pmic8058.h>
33#include <asm/mach-types.h>
34#include <asm/uaccess.h>
35#include <mach/mdm2.h>
36#include <mach/restart.h>
37#include <mach/subsystem_notif.h>
38#include <mach/subsystem_restart.h>
39#include <linux/msm_charm.h>
40#include "msm_watchdog.h"
41#include "mdm_private.h"
42
43#define MDM_MODEM_TIMEOUT 6000
44#define MDM_MODEM_DELTA 100
Joel King52d7fa62012-03-21 08:40:52 -070045#define MDM_BOOT_TIMEOUT 60000L
46#define MDM_RDUMP_TIMEOUT 60000L
Joel Kingb6f0f612011-11-01 16:59:14 -070047
48static int mdm_debug_on;
49static struct workqueue_struct *mdm_queue;
50
51#define EXTERNAL_MODEM "external_modem"
52
Joel Kingb6f0f612011-11-01 16:59:14 -070053static struct mdm_modem_drv *mdm_drv;
54
55DECLARE_COMPLETION(mdm_needs_reload);
56DECLARE_COMPLETION(mdm_boot);
57DECLARE_COMPLETION(mdm_ram_dumps);
58
59static int first_boot = 1;
60
61long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
62 unsigned long arg)
63{
64 int status, ret = 0;
65
66 if (_IOC_TYPE(cmd) != CHARM_CODE) {
67 pr_err("%s: invalid ioctl code\n", __func__);
68 return -EINVAL;
69 }
70
Joel King2a42f502012-02-03 11:36:25 -080071 pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
Joel Kingb6f0f612011-11-01 16:59:14 -070072 switch (cmd) {
73 case WAKE_CHARM:
Joel King2a42f502012-02-03 11:36:25 -080074 pr_info("%s: Powering on mdm\n", __func__);
Joel Kinge9cd5272012-01-28 12:48:59 -080075 mdm_drv->ops->power_on_mdm_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -070076 break;
77 case CHECK_FOR_BOOT:
78 if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
79 put_user(1, (unsigned long __user *) arg);
80 else
81 put_user(0, (unsigned long __user *) arg);
82 break;
83 case NORMAL_BOOT_DONE:
Joel King2a42f502012-02-03 11:36:25 -080084 pr_debug("%s: check if mdm is booted up\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -070085 get_user(status, (unsigned long __user *) arg);
Joel King2a42f502012-02-03 11:36:25 -080086 if (status) {
87 pr_debug("%s: normal boot failed\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -070088 mdm_drv->mdm_boot_status = -EIO;
Joel King2a42f502012-02-03 11:36:25 -080089 } else {
90 pr_info("%s: normal boot done\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -070091 mdm_drv->mdm_boot_status = 0;
Joel King2a42f502012-02-03 11:36:25 -080092 }
Joel Kingb6f0f612011-11-01 16:59:14 -070093 mdm_drv->mdm_ready = 1;
94
Joel Kinge9cd5272012-01-28 12:48:59 -080095 if (mdm_drv->ops->normal_boot_done_cb != NULL)
96 mdm_drv->ops->normal_boot_done_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -070097
98 if (!first_boot)
99 complete(&mdm_boot);
100 else
101 first_boot = 0;
102 break;
103 case RAM_DUMP_DONE:
Joel King2a42f502012-02-03 11:36:25 -0800104 pr_debug("%s: mdm done collecting RAM dumps\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700105 get_user(status, (unsigned long __user *) arg);
106 if (status)
107 mdm_drv->mdm_ram_dump_status = -EIO;
Joel King2a42f502012-02-03 11:36:25 -0800108 else {
109 pr_info("%s: ramdump collection completed\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700110 mdm_drv->mdm_ram_dump_status = 0;
Joel King2a42f502012-02-03 11:36:25 -0800111 }
Joel Kingb6f0f612011-11-01 16:59:14 -0700112 complete(&mdm_ram_dumps);
113 break;
114 case WAIT_FOR_RESTART:
Joel King2a42f502012-02-03 11:36:25 -0800115 pr_debug("%s: wait for mdm to need images reloaded\n",
Joel Kingb6f0f612011-11-01 16:59:14 -0700116 __func__);
117 ret = wait_for_completion_interruptible(&mdm_needs_reload);
118 if (!ret)
119 put_user(mdm_drv->boot_type,
120 (unsigned long __user *) arg);
121 INIT_COMPLETION(mdm_needs_reload);
122 break;
123 default:
124 pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
125 ret = -EINVAL;
126 break;
127 }
128
129 return ret;
130}
131
132static void mdm_fatal_fn(struct work_struct *work)
133{
Joel King2a42f502012-02-03 11:36:25 -0800134 pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700135 subsystem_restart(EXTERNAL_MODEM);
136}
137
138static DECLARE_WORK(mdm_fatal_work, mdm_fatal_fn);
139
140static void mdm_status_fn(struct work_struct *work)
141{
Vamsi Krishna33925632011-12-13 15:43:09 -0800142 int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
143
Vamsi Krishnaefbff972012-02-28 21:03:18 -0800144 if (!mdm_drv->mdm_ready)
145 return;
146
Joel Kingd8052c02012-02-03 12:33:31 -0800147 mdm_drv->ops->status_cb(mdm_drv, value);
Vamsi Krishna33925632011-12-13 15:43:09 -0800148
Joel King2a42f502012-02-03 11:36:25 -0800149 pr_debug("%s: status:%d\n", __func__, value);
Vamsi Krishna33925632011-12-13 15:43:09 -0800150
Vamsi Krishnaefbff972012-02-28 21:03:18 -0800151 if ((value == 0)) {
Joel King2a42f502012-02-03 11:36:25 -0800152 pr_info("%s: unexpected reset external modem\n", __func__);
Vamsi Krishna33925632011-12-13 15:43:09 -0800153 subsystem_restart(EXTERNAL_MODEM);
154 } else if (value == 1) {
Joel King2a42f502012-02-03 11:36:25 -0800155 pr_info("%s: status = 1: mdm is now ready\n", __func__);
Vamsi Krishna33925632011-12-13 15:43:09 -0800156 }
Joel Kingb6f0f612011-11-01 16:59:14 -0700157}
158
159static DECLARE_WORK(mdm_status_work, mdm_status_fn);
160
161static void mdm_disable_irqs(void)
162{
163 disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
164 disable_irq_nosync(mdm_drv->mdm_status_irq);
165
166}
167
168static irqreturn_t mdm_errfatal(int irq, void *dev_id)
169{
Joel King2a42f502012-02-03 11:36:25 -0800170 pr_debug("%s: mdm got errfatal interrupt\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700171 if (mdm_drv->mdm_ready &&
172 (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
Joel King2a42f502012-02-03 11:36:25 -0800173 pr_debug("%s: scheduling work now\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700174 queue_work(mdm_queue, &mdm_fatal_work);
175 }
176 return IRQ_HANDLED;
177}
178
179static int mdm_modem_open(struct inode *inode, struct file *file)
180{
181 return 0;
182}
183
184static const struct file_operations mdm_modem_fops = {
185 .owner = THIS_MODULE,
186 .open = mdm_modem_open,
187 .unlocked_ioctl = mdm_modem_ioctl,
188};
189
190
191static struct miscdevice mdm_modem_misc = {
192 .minor = MISC_DYNAMIC_MINOR,
193 .name = "mdm",
194 .fops = &mdm_modem_fops
195};
196
197static int mdm_panic_prep(struct notifier_block *this,
198 unsigned long event, void *ptr)
199{
200 int i;
201
Joel King2a42f502012-02-03 11:36:25 -0800202 pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
Joel Kingb6f0f612011-11-01 16:59:14 -0700203 __func__);
204 mdm_disable_irqs();
205 gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
206
207 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
208 gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
209
210 for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
211 pet_watchdog();
212 mdelay(MDM_MODEM_DELTA);
213 if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
214 break;
215 }
216 if (i <= 0)
217 pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
218 return NOTIFY_DONE;
219}
220
221static struct notifier_block mdm_panic_blk = {
222 .notifier_call = mdm_panic_prep,
223};
224
225static irqreturn_t mdm_status_change(int irq, void *dev_id)
226{
Joel King2a42f502012-02-03 11:36:25 -0800227 pr_debug("%s: mdm sent status change interrupt\n", __func__);
Vamsi Krishna33925632011-12-13 15:43:09 -0800228
229 queue_work(mdm_queue, &mdm_status_work);
230
Joel Kingb6f0f612011-11-01 16:59:14 -0700231 return IRQ_HANDLED;
232}
233
234static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
235{
236 mdm_drv->mdm_ready = 0;
237 gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
Joel King415af512012-02-03 10:22:43 -0800238 if (mdm_drv->pdata->ramdump_delay_ms > 0) {
239 /* Wait for the external modem to complete
240 * its preparation for ramdumps.
241 */
242 mdelay(mdm_drv->pdata->ramdump_delay_ms);
243 }
Joel Kinge9cd5272012-01-28 12:48:59 -0800244 mdm_drv->ops->power_down_mdm_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -0700245 return 0;
246}
247
248static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
249{
Joel Kingbc48e4c2012-02-27 13:18:52 -0800250 gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
251 gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
Joel Kinge9cd5272012-01-28 12:48:59 -0800252 mdm_drv->ops->power_on_mdm_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -0700253 mdm_drv->boot_type = CHARM_NORMAL_BOOT;
254 complete(&mdm_needs_reload);
Joel King52d7fa62012-03-21 08:40:52 -0700255 if (!wait_for_completion_timeout(&mdm_boot,
256 msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
257 mdm_drv->mdm_boot_status = -ETIMEDOUT;
258 pr_info("%s: mdm modem restart timed out.\n", __func__);
259 } else
260 pr_info("%s: mdm modem has been restarted\n", __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700261 INIT_COMPLETION(mdm_boot);
262 return mdm_drv->mdm_boot_status;
263}
264
265static int mdm_subsys_ramdumps(int want_dumps,
266 const struct subsys_data *crashed_subsys)
267{
268 mdm_drv->mdm_ram_dump_status = 0;
269 if (want_dumps) {
270 mdm_drv->boot_type = CHARM_RAM_DUMPS;
271 complete(&mdm_needs_reload);
Joel King52d7fa62012-03-21 08:40:52 -0700272 if (!wait_for_completion_timeout(&mdm_ram_dumps,
273 msecs_to_jiffies(MDM_RDUMP_TIMEOUT))) {
274 mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
275 pr_info("%s: mdm modem ramdumps timed out.\n",
276 __func__);
277 } else
278 pr_info("%s: mdm modem ramdumps completed.\n",
279 __func__);
Joel Kingb6f0f612011-11-01 16:59:14 -0700280 INIT_COMPLETION(mdm_ram_dumps);
281 gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
Joel Kinge9cd5272012-01-28 12:48:59 -0800282 mdm_drv->ops->power_down_mdm_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -0700283 }
284 return mdm_drv->mdm_ram_dump_status;
285}
286
287static struct subsys_data mdm_subsystem = {
288 .shutdown = mdm_subsys_shutdown,
289 .ramdump = mdm_subsys_ramdumps,
290 .powerup = mdm_subsys_powerup,
291 .name = EXTERNAL_MODEM,
292};
293
294static int mdm_debug_on_set(void *data, u64 val)
295{
296 mdm_debug_on = val;
Joel Kinge9cd5272012-01-28 12:48:59 -0800297 if (mdm_drv->ops->debug_state_changed_cb)
298 mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
Joel Kingb6f0f612011-11-01 16:59:14 -0700299 return 0;
300}
301
302static int mdm_debug_on_get(void *data, u64 *val)
303{
304 *val = mdm_debug_on;
305 return 0;
306}
307
308DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
309 mdm_debug_on_get,
310 mdm_debug_on_set, "%llu\n");
311
312static int mdm_debugfs_init(void)
313{
314 struct dentry *dent;
315
316 dent = debugfs_create_dir("mdm_dbg", 0);
317 if (IS_ERR(dent))
318 return PTR_ERR(dent);
319
320 debugfs_create_file("debug_on", 0644, dent, NULL,
321 &mdm_debug_on_fops);
322 return 0;
323}
324
325static void mdm_modem_initialize_data(struct platform_device *pdev,
Joel Kinge9cd5272012-01-28 12:48:59 -0800326 struct mdm_ops *mdm_ops)
Joel Kingb6f0f612011-11-01 16:59:14 -0700327{
328 struct resource *pres;
329
330 /* MDM2AP_ERRFATAL */
331 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
332 "MDM2AP_ERRFATAL");
333 if (pres)
334 mdm_drv->mdm2ap_errfatal_gpio = pres->start;
335
336 /* AP2MDM_ERRFATAL */
337 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
338 "AP2MDM_ERRFATAL");
339 if (pres)
340 mdm_drv->ap2mdm_errfatal_gpio = pres->start;
341
342 /* MDM2AP_STATUS */
343 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
344 "MDM2AP_STATUS");
345 if (pres)
346 mdm_drv->mdm2ap_status_gpio = pres->start;
347
348 /* AP2MDM_STATUS */
349 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
350 "AP2MDM_STATUS");
351 if (pres)
352 mdm_drv->ap2mdm_status_gpio = pres->start;
353
354 /* MDM2AP_WAKEUP */
355 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
356 "MDM2AP_WAKEUP");
357 if (pres)
358 mdm_drv->mdm2ap_wakeup_gpio = pres->start;
359
360 /* AP2MDM_WAKEUP */
361 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
362 "AP2MDM_WAKEUP");
363 if (pres)
364 mdm_drv->ap2mdm_wakeup_gpio = pres->start;
365
366 /* AP2MDM_PMIC_RESET_N */
367 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
368 "AP2MDM_PMIC_RESET_N");
369 if (pres)
370 mdm_drv->ap2mdm_pmic_reset_n_gpio = pres->start;
371
372 /* AP2MDM_KPDPWR_N */
373 pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
374 "AP2MDM_KPDPWR_N");
375 if (pres)
376 mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
377
378 mdm_drv->boot_type = CHARM_NORMAL_BOOT;
379
Joel Kinge9cd5272012-01-28 12:48:59 -0800380 mdm_drv->ops = mdm_ops;
Joel King415af512012-02-03 10:22:43 -0800381 mdm_drv->pdata = pdev->dev.platform_data;
Joel Kingb6f0f612011-11-01 16:59:14 -0700382}
383
384int mdm_common_create(struct platform_device *pdev,
Joel Kinge9cd5272012-01-28 12:48:59 -0800385 struct mdm_ops *p_mdm_cb)
Joel Kingb6f0f612011-11-01 16:59:14 -0700386{
387 int ret = -1, irq;
388
389 mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
390 if (mdm_drv == NULL) {
391 pr_err("%s: kzalloc fail.\n", __func__);
392 goto alloc_err;
393 }
394
395 mdm_modem_initialize_data(pdev, p_mdm_cb);
Joel Kinge9cd5272012-01-28 12:48:59 -0800396 if (mdm_drv->ops->debug_state_changed_cb)
397 mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
Joel Kingb6f0f612011-11-01 16:59:14 -0700398
399 gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
400 gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
401 gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
402 gpio_request(mdm_drv->ap2mdm_pmic_reset_n_gpio, "AP2MDM_PMIC_RESET_N");
403 gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
404 gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
405
406 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
407 gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
408
409 gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
410 gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
411
412 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
413 gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
414
415 gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
416 gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
417
418 mdm_queue = create_singlethread_workqueue("mdm_queue");
419 if (!mdm_queue) {
420 pr_err("%s: could not create workqueue. All mdm "
421 "functionality will be disabled\n",
422 __func__);
423 ret = -ENOMEM;
424 goto fatal_err;
425 }
426
427 atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
428 mdm_debugfs_init();
429
430 /* Register subsystem handlers */
431 ssr_register_subsystem(&mdm_subsystem);
432
433 /* ERR_FATAL irq. */
434 irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
435 if (irq < 0) {
436 pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
437 "error=%d No IRQ will be generated on errfatal.",
438 __func__, irq);
439 goto errfatal_err;
440 }
441 ret = request_irq(irq, mdm_errfatal,
442 IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
443
444 if (ret < 0) {
445 pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
446 ". No IRQ will be generated on errfatal.",
447 __func__, irq, ret);
448 goto errfatal_err;
449 }
450 mdm_drv->mdm_errfatal_irq = irq;
451
452errfatal_err:
453
454 /* status irq */
455 irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
456 if (irq < 0) {
457 pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
458 "error=%d No IRQ will be generated on status change.",
459 __func__, irq);
460 goto status_err;
461 }
462
463 ret = request_threaded_irq(irq, NULL, mdm_status_change,
Vamsi Krishna33925632011-12-13 15:43:09 -0800464 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
465 "mdm status", mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -0700466
467 if (ret < 0) {
468 pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
469 ". No IRQ will be generated on status change.",
470 __func__, irq, ret);
471 goto status_err;
472 }
473 mdm_drv->mdm_status_irq = irq;
474
475status_err:
Joel King35f819e2012-02-05 12:05:57 -0800476 /* Perform early powerup of the external modem in order to
477 * allow tabla devices to be found.
478 */
479 mdm_drv->ops->power_on_mdm_cb(mdm_drv);
480
Joel Kingb6f0f612011-11-01 16:59:14 -0700481 pr_info("%s: Registering mdm modem\n", __func__);
482 return misc_register(&mdm_modem_misc);
483
484fatal_err:
485 gpio_free(mdm_drv->ap2mdm_status_gpio);
486 gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
487 gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
488 gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
489 gpio_free(mdm_drv->mdm2ap_status_gpio);
490 gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
491
492 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
493 gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
494
495 kfree(mdm_drv);
496 ret = -ENODEV;
497
498alloc_err:
499 return ret;
500}
501
502int mdm_common_modem_remove(struct platform_device *pdev)
503{
504 int ret;
505
506 gpio_free(mdm_drv->ap2mdm_status_gpio);
507 gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
508 gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
509 gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
510 gpio_free(mdm_drv->mdm2ap_status_gpio);
511 gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
512
513 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
514 gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
515
516 kfree(mdm_drv);
517
518 ret = misc_deregister(&mdm_modem_misc);
519 return ret;
520}
521
522void mdm_common_modem_shutdown(struct platform_device *pdev)
523{
Joel Kingb6f0f612011-11-01 16:59:14 -0700524 mdm_disable_irqs();
525
Joel Kingb6f0f612011-11-01 16:59:14 -0700526 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
527 gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
528
Joel Kinge9cd5272012-01-28 12:48:59 -0800529 mdm_drv->ops->power_down_mdm_cb(mdm_drv);
Joel Kingb6f0f612011-11-01 16:59:14 -0700530
531 if (mdm_drv->ap2mdm_wakeup_gpio > 0)
532 gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 0);
533}
534