diff options
author | Steve Lin <stlin@nvidia.com> | 2013-04-26 16:41:38 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:10:33 -0700 |
commit | 4f1c7552beacfb64bfa880eec225b012843c76c5 (patch) | |
tree | 5750bc2953de6a0584407f002f296719f64c658f /drivers/misc/tegra-baseband | |
parent | c58a701d74111d278d6417a8dded5386397fa3ae (diff) |
misc: tegra-baseband: fix TEGRA_USB_MODEM_POWER driver issues
1) fix Kconfig dependency.
2) fix kernel crash if boot/wake gpio is not LP0 wakeable.
3) try to acquire wakelock earlier in the remote wake thread function.
Change-Id: I72dabe3a2e5122f6063cc75ed9d67d71334bd7a6
Signed-off-by: Steve Lin <stlin@nvidia.com>
Reviewed-on: http://git-master/r/223558
Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/misc/tegra-baseband')
-rw-r--r-- | drivers/misc/tegra-baseband/Kconfig | 18 | ||||
-rw-r--r-- | drivers/misc/tegra-baseband/tegra_usb_modem_power.c | 113 |
2 files changed, 68 insertions, 63 deletions
diff --git a/drivers/misc/tegra-baseband/Kconfig b/drivers/misc/tegra-baseband/Kconfig index c0f5d4c6d651..45480bdb21d2 100644 --- a/drivers/misc/tegra-baseband/Kconfig +++ b/drivers/misc/tegra-baseband/Kconfig @@ -1,14 +1,6 @@ menu "Tegra Baseband Modem Drivers" depends on ARCH_TEGRA -config TEGRA_USB_MODEM_POWER - bool "Tegra USB modem power driver" - ---help--- - Say Y if you want to use one of the following modems - i450 - i500 - i500 Nemo - config TEGRA_BB_SUPPORT bool "Tegra baseband support" ---help--- @@ -19,6 +11,16 @@ config TEGRA_BB_SUPPORT if TEGRA_BB_SUPPORT +config TEGRA_USB_MODEM_POWER + bool "Tegra USB modem power driver" + ---help--- + Say Y if you want to use one of the following modems + i450 + i500 + i500 Nemo + + Disabled by default. Choose Y here if you want to build the driver. + config TEGRA_BB_POWER bool "Enable tegra baseband power driver" ---help--- diff --git a/drivers/misc/tegra-baseband/tegra_usb_modem_power.c b/drivers/misc/tegra-baseband/tegra_usb_modem_power.c index b012f87b49c1..79bdedfe35da 100644 --- a/drivers/misc/tegra-baseband/tegra_usb_modem_power.c +++ b/drivers/misc/tegra-baseband/tegra_usb_modem_power.c @@ -47,7 +47,9 @@ struct tegra_usb_modem { struct platform_device *pdev; unsigned int wake_cnt; /* remote wakeup counter */ unsigned int wake_irq; /* remote wakeup irq */ + bool wake_irq_wakeable; /* LP0 wakeable */ unsigned int boot_irq; /* modem boot irq */ + bool boot_irq_wakeable; /* LP0 wakeable */ struct mutex lock; struct wake_lock wake_lock; /* modem wake lock */ unsigned int vid; /* modem vendor id */ @@ -188,13 +190,13 @@ static irqreturn_t tegra_usb_modem_wake_thread(int irq, void *data) mutex_lock(&modem->lock); if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED) { + wake_lock_timeout(&modem->wake_lock, + WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE); + dev_info(&modem->pdev->dev, "remote wake (%u)\n", ++(modem->wake_cnt)); if (!modem->system_suspend) { - wake_lock_timeout(&modem->wake_lock, - WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE); - usb_lock_device(modem->udev); if (usb_autopm_get_interface(modem->intf) == 0) usb_autopm_put_interface_async(modem->intf); @@ -410,11 +412,13 @@ static int mdm_pm_notifier(struct notifier_block *notifier, return NOTIFY_DONE; } -static int mdm_request_wakeable_irq(struct tegra_usb_modem *modem, - irq_handler_t thread_fn, - unsigned int irq_gpio, - unsigned long irq_flags, - const char *label, unsigned int *irq) +static int mdm_request_irq(struct tegra_usb_modem *modem, + irq_handler_t thread_fn, + unsigned int irq_gpio, + unsigned long irq_flags, + const char *label, + unsigned int *irq, + bool *is_wakeable) { int ret; @@ -432,12 +436,9 @@ static int mdm_request_wakeable_irq(struct tegra_usb_modem *modem, return ret; ret = enable_irq_wake(*irq); - if (ret) { - free_irq(*irq, modem); - return ret; - } + *is_wakeable = (ret) ? false : true; - return ret; + return 0; } /* load USB host controller */ @@ -768,19 +769,45 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev) /* get modem operations from platform data */ modem->ops = (const struct tegra_modem_operations *)pdata->ops; - if (modem->ops) { - /* modem init */ - if (modem->ops->init) { - ret = modem->ops->init(); - if (ret) - return ret; - } + /* modem init */ + if (modem->ops && modem->ops->init) { + ret = modem->ops->init(); + if (ret) + return ret; + } - /* start modem */ - if (modem->ops->start) - modem->ops->start(); + /* if wake gpio is not specified we rely on native usb remote wake */ + if (gpio_is_valid(pdata->wake_gpio)) { + /* request remote wakeup irq from platform data */ + ret = mdm_request_irq(modem, + tegra_usb_modem_wake_thread, + pdata->wake_gpio, + pdata->wake_irq_flags, + "mdm_wake", + &modem->wake_irq, + &modem->wake_irq_wakeable); + if (ret) { + dev_err(&pdev->dev, "request wake irq error\n"); + goto error; + } } + if (gpio_is_valid(pdata->boot_gpio)) { + /* request boot irq from platform data */ + ret = mdm_request_irq(modem, + tegra_usb_modem_boot_thread, + pdata->boot_gpio, + pdata->boot_irq_flags, + "mdm_boot", + &modem->boot_irq, + &modem->boot_irq_wakeable); + if (ret) { + dev_err(&pdev->dev, "request boot irq error\n"); + goto error; + } + } else + dev_warn(&pdev->dev, "boot irq not specified\n"); + /* create sysfs node to load/unload host controller */ ret = device_create_file(&pdev->dev, &dev_attr_load_host); if (ret) { @@ -808,54 +835,30 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev) pm_qos_add_request(&modem->cpu_boost_req, PM_QOS_CPU_FREQ_MIN, PM_QOS_DEFAULT_VALUE); - /* if wake gpio is not specified we rely on native usb remote wake */ - if (gpio_is_valid(pdata->wake_gpio)) { - /* request remote wakeup irq from platform data */ - ret = mdm_request_wakeable_irq(modem, - tegra_usb_modem_wake_thread, - pdata->wake_gpio, - pdata->wake_irq_flags, - "mdm_wake", &modem->wake_irq); - if (ret) { - dev_err(&pdev->dev, "request wake irq error\n"); - goto error; - } - } - - if (gpio_is_valid(pdata->boot_gpio)) { - /* request boot irq from platform data */ - ret = mdm_request_wakeable_irq(modem, - tegra_usb_modem_boot_thread, - pdata->boot_gpio, - pdata->boot_irq_flags, - "mdm_boot", &modem->boot_irq); - if (ret) { - dev_err(&pdev->dev, "request boot irq error\n"); - goto error; - } - } else { - dev_err(&pdev->dev, "boot irq not specified\n"); - goto error; - } - modem->pm_notifier.notifier_call = mdm_pm_notifier; modem->usb_notifier.notifier_call = mdm_usb_notifier; usb_register_notify(&modem->usb_notifier); register_pm_notifier(&modem->pm_notifier); + /* start modem */ + if (modem->ops && modem->ops->start) + modem->ops->start(); + return ret; error: if (modem->sysfs_file_created) device_remove_file(&pdev->dev, &dev_attr_load_host); if (modem->wake_irq) { - disable_irq_wake(modem->wake_irq); + if (modem->wake_irq_wakeable) + disable_irq_wake(modem->wake_irq); free_irq(modem->wake_irq, modem); } if (modem->boot_irq) { - disable_irq_wake(modem->boot_irq); + if (modem->boot_irq_wakeable) + disable_irq_wake(modem->boot_irq); free_irq(modem->boot_irq, modem); } |