summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/board-enterprise-baseband.c62
-rw-r--r--arch/arm/mach-tegra/board-whistler-baseband.c57
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h12
-rw-r--r--arch/arm/mach-tegra/tegra_usb_modem_power.c291
4 files changed, 264 insertions, 158 deletions
diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c
index 3ad83ad4fe8a..c73a7ad5e5b4 100644
--- a/arch/arm/mach-tegra/board-enterprise-baseband.c
+++ b/arch/arm/mach-tegra/board-enterprise-baseband.c
@@ -22,10 +22,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/err.h>
-#include <linux/wakelock.h>
#include <linux/platform_data/tegra_usb.h>
#include <mach/tegra_usb_modem_power.h>
#include "devices.h"
@@ -36,23 +33,19 @@
#define MODEM_RESET TEGRA_GPIO_PE1
#define BB_RST_OUT TEGRA_GPIO_PV1
-/* Icera BB GPIO */
+/* Icera modem handshaking GPIO */
#define AP2MDM_ACK TEGRA_GPIO_PE3
#define MDM2AP_ACK TEGRA_GPIO_PU5
#define AP2MDM_ACK2 TEGRA_GPIO_PE2
#define MDM2AP_ACK2 TEGRA_GPIO_PV0
-static struct wake_lock mdm_wake_lock;
-
static struct gpio modem_gpios[] = {
{MODEM_PWR_ON, GPIOF_OUT_INIT_LOW, "MODEM PWR ON"},
{MODEM_RESET, GPIOF_IN, "MODEM RESET"},
- {BB_RST_OUT, GPIOF_IN, "BB RST OUT"},
{AP2MDM_ACK2, GPIOF_OUT_INIT_HIGH, "AP2MDM ACK2"},
{AP2MDM_ACK, GPIOF_OUT_INIT_LOW, "AP2MDM ACK"},
};
-
static void baseband_post_phy_on(void);
static void baseband_pre_phy_off(void);
@@ -85,27 +78,6 @@ static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = {
.ops = &ulpi_null_plat_ops,
};
-static int __init tegra_null_ulpi_init(void)
-{
- tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_null_pdata;
- platform_device_register(&tegra_ehci2_device);
- return 0;
-}
-
-static irqreturn_t mdm_start_thread(int irq, void *data)
-{
- if (gpio_get_value(BB_RST_OUT)) {
- pr_info("BB_RST_OUT high\n");
- } else {
- pr_info("BB_RST_OUT low\n");
- }
-
- /* hold wait lock to complete the enumeration */
- wake_lock_timeout(&mdm_wake_lock, HZ * 10);
-
- return IRQ_HANDLED;
-}
-
static void baseband_post_phy_on(void)
{
/* set AP2MDM_ACK2 low */
@@ -139,7 +111,6 @@ static void baseband_reset(void)
static int baseband_init(void)
{
- int irq;
int ret;
ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
@@ -157,29 +128,6 @@ static int baseband_init(void)
/* export GPIO for user space access through sysfs */
gpio_export(MODEM_PWR_ON, false);
- /* phy init */
- tegra_null_ulpi_init();
-
- wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
-
- /* enable IRQ for BB_RST_OUT */
- irq = gpio_to_irq(BB_RST_OUT);
-
- ret = request_threaded_irq(irq, NULL, mdm_start_thread,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mdm_start", NULL);
- if (ret < 0) {
- pr_err("%s: request_threaded_irq error\n", __func__);
- return ret;
- }
-
- ret = enable_irq_wake(irq);
- if (ret) {
- pr_err("%s: enable_irq_wake error\n", __func__);
- free_irq(irq, NULL);
- return ret;
- }
-
return 0;
}
@@ -192,7 +140,13 @@ static const struct tegra_modem_operations baseband_operations = {
static struct tegra_usb_modem_power_platform_data baseband_pdata = {
.ops = &baseband_operations,
.wake_gpio = MDM2AP_ACK2,
- .flags = IRQF_TRIGGER_FALLING,
+ .wake_irq_flags = IRQF_TRIGGER_FALLING,
+ .boot_gpio = BB_RST_OUT,
+ .boot_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ .autosuspend_delay = 2000,
+ .short_autosuspend_delay = 50,
+ .tegra_ehci_device = &tegra_ehci2_device,
+ .tegra_ehci_pdata = &tegra_ehci2_ulpi_null_pdata,
};
static struct platform_device icera_baseband_device = {
diff --git a/arch/arm/mach-tegra/board-whistler-baseband.c b/arch/arm/mach-tegra/board-whistler-baseband.c
index ad3dbd316ded..4a479cfb871c 100644
--- a/arch/arm/mach-tegra/board-whistler-baseband.c
+++ b/arch/arm/mach-tegra/board-whistler-baseband.c
@@ -20,12 +20,9 @@
#include "board.h"
#include "board-whistler-baseband.h"
-static struct wake_lock mdm_wake_lock;
-
static struct gpio modem_gpios[] = {
{MODEM_PWR_ON, GPIOF_OUT_INIT_LOW, "MODEM PWR ON"},
{MODEM_RESET, GPIOF_IN, "MODEM RESET"},
- {BB_RST_OUT, GPIOF_IN, "BB RST OUT"},
{AP2MDM_ACK2, GPIOF_OUT_INIT_HIGH, "AP2MDM ACK2"},
{AP2MDM_ACK, GPIOF_OUT_INIT_LOW, "AP2MDM ACK"},
};
@@ -61,7 +58,7 @@ static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = {
.vbus_reg = NULL,
.hot_plug = false,
.remote_wakeup_supported = false,
- .power_off_on_suspend = false,
+ .power_off_on_suspend = true,
},
.u_cfg.ulpi = {
.shadow_clk_delay = 10,
@@ -75,26 +72,6 @@ static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = {
.ops = &ulpi_null_plat_ops,
};
-static int __init tegra_null_ulpi_init(void)
-{
- tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_null_pdata;
- platform_device_register(&tegra_ehci2_device);
- return 0;
-}
-
-static irqreturn_t mdm_start_thread(int irq, void *data)
-{
- if (gpio_get_value(BB_RST_OUT)) {
- pr_info("BB_RST_OUT high\n");
- } else {
- pr_info("BB_RST_OUT low\n");
- /* hold wait lock to complete the enumeration */
- wake_lock_timeout(&mdm_wake_lock, HZ * 10);
- }
-
- return IRQ_HANDLED;
-}
-
static void baseband_post_phy_on(void)
{
/* set AP2MDM_ACK2 low */
@@ -128,7 +105,6 @@ static void baseband_reset(void)
static int baseband_init(void)
{
- int irq;
int ret;
ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
@@ -142,29 +118,6 @@ static int baseband_init(void)
/* export GPIO for user space access through sysfs */
gpio_export(MODEM_PWR_ON, false);
- /* phy init */
- tegra_null_ulpi_init();
-
- wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
-
- /* enable IRQ for BB_RST_OUT */
- irq = gpio_to_irq(BB_RST_OUT);
-
- ret = request_threaded_irq(irq, NULL, mdm_start_thread,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mdm_start", NULL);
- if (ret < 0) {
- pr_err("%s: request_threaded_irq error\n", __func__);
- return ret;
- }
-
- ret = enable_irq_wake(irq);
- if (ret) {
- pr_err("%s: enable_irq_wake error\n", __func__);
- free_irq(irq, NULL);
- return ret;
- }
-
return 0;
}
@@ -177,7 +130,13 @@ static const struct tegra_modem_operations baseband_operations = {
static struct tegra_usb_modem_power_platform_data baseband_pdata = {
.ops = &baseband_operations,
.wake_gpio = MDM2AP_ACK2,
- .flags = IRQF_TRIGGER_FALLING,
+ .wake_irq_flags = IRQF_TRIGGER_FALLING,
+ .boot_gpio = BB_RST_OUT,
+ .boot_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ .autosuspend_delay = 2000,
+ .short_autosuspend_delay = 50,
+ .tegra_ehci_device = &tegra_ehci2_device,
+ .tegra_ehci_pdata = &tegra_ehci2_ulpi_null_pdata,
};
static struct platform_device icera_baseband_device = {
diff --git a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
index 0ce7fa40eb2e..210b9f61ecb5 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,8 +40,14 @@ struct tegra_modem_operations {
/* tegra usb modem power platform data */
struct tegra_usb_modem_power_platform_data {
const struct tegra_modem_operations *ops;
- unsigned int wake_gpio; /* remote wakeup gpio */
- unsigned int flags; /* remote wakeup irq flags */
+ unsigned int wake_gpio; /* remote wakeup gpio */
+ unsigned long wake_irq_flags; /* remote wakeup irq flags */
+ unsigned int boot_gpio; /* modem boot gpio */
+ unsigned long boot_irq_flags; /* modem boot irq flags */
+ int autosuspend_delay; /* autosuspend delay in milliseconds */
+ int short_autosuspend_delay; /* short autosuspend delay in ms */
+ const struct platform_device *tegra_ehci_device;
+ const struct tegra_usb_platform_data *tegra_ehci_pdata;
};
#endif /* __MACH_TEGRA_USB_MODEM_POWER_H */
diff --git a/arch/arm/mach-tegra/tegra_usb_modem_power.c b/arch/arm/mach-tegra/tegra_usb_modem_power.c
index 88543397f974..7590754d0133 100644
--- a/arch/arm/mach-tegra/tegra_usb_modem_power.c
+++ b/arch/arm/mach-tegra/tegra_usb_modem_power.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra_usb_modem_power.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_usb.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/usb.h>
@@ -32,15 +33,20 @@
#include <linux/wakelock.h>
#include <mach/tegra_usb_modem_power.h>
+#define WAKELOCK_TIMEOUT_FOR_USB_ENUM (HZ * 10)
+#define WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE (HZ)
+
struct tegra_usb_modem {
- unsigned int wake_gpio; /* remote wakeup gpio */
+ struct tegra_usb_modem_power_platform_data *pdata;
unsigned int wake_cnt; /* remote wakeup counter */
- int irq; /* remote wakeup irq */
+ unsigned int wake_irq; /* remote wakeup irq */
+ unsigned int boot_irq; /* modem boot irq */
struct mutex lock;
struct wake_lock wake_lock; /* modem wake lock */
unsigned int vid; /* modem vendor id */
unsigned int pid; /* modem product id */
struct usb_device *udev; /* modem usb device */
+ struct usb_device *parent; /* parent device */
struct usb_interface *intf; /* first modem usb interface */
struct workqueue_struct *wq; /* modem workqueue */
struct delayed_work recovery_work; /* modem recovery work */
@@ -49,8 +55,15 @@ struct tegra_usb_modem {
int system_suspend; /* system suspend flag */
struct notifier_block pm_notifier; /* pm event notifier */
struct notifier_block usb_notifier; /* usb event notifier */
+ int sysfs_file_created;
+ int short_autosuspend_enabled;
};
+static struct platform_device *hc = NULL; /* USB host controller */
+static struct mutex hc_lock;
+static const struct platform_device *hc_device;
+static const struct tegra_usb_platform_data *hc_pdata;
+
/* supported modems */
static const struct usb_device_id modem_list[] = {
{USB_DEVICE(0x1983, 0x0310), /* Icera 450 rev1 */
@@ -69,23 +82,54 @@ static irqreturn_t tegra_usb_modem_wake_thread(int irq, void *data)
{
struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
- wake_lock_timeout(&modem->wake_lock, HZ);
mutex_lock(&modem->lock);
- if (modem->udev) {
+ if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED) {
pr_info("modem 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);
usb_unlock_device(modem->udev);
}
+#ifdef CONFIG_PM
+ if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
+ modem->short_autosuspend_enabled) {
+ pm_runtime_set_autosuspend_delay(&modem->udev->dev,
+ modem->pdata->autosuspend_delay);
+ modem->short_autosuspend_enabled = 0;
+ }
+#endif
}
mutex_unlock(&modem->lock);
return IRQ_HANDLED;
}
+static irqreturn_t tegra_usb_modem_boot_thread(int irq, void *data)
+{
+ struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
+
+ if (gpio_get_value(modem->pdata->boot_gpio))
+ pr_info("BB_RST_OUT high\n");
+ else
+ pr_info("BB_RST_OUT low\n");
+
+ /* hold wait lock to complete the enumeration */
+ wake_lock_timeout(&modem->wake_lock, WAKELOCK_TIMEOUT_FOR_USB_ENUM);
+
+ /* USB disconnect maybe on going... */
+ mutex_lock(&modem->lock);
+ if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED)
+ pr_warn("Device is not disconnected!\n");
+ mutex_unlock(&modem->lock);
+
+ return IRQ_HANDLED;
+}
+
static void tegra_usb_modem_recovery(struct work_struct *ws)
{
struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
@@ -108,13 +152,15 @@ static void device_add_handler(struct tegra_usb_modem *modem,
if (id) {
/* hold wakelock to ensure ril has enough time to restart */
- wake_lock_timeout(&modem->wake_lock, HZ * 10);
+ wake_lock_timeout(&modem->wake_lock,
+ WAKELOCK_TIMEOUT_FOR_USB_ENUM);
pr_info("Add device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
mutex_lock(&modem->lock);
modem->udev = udev;
+ modem->parent = udev->parent;
modem->intf = intf;
modem->vid = desc->idVendor;
modem->pid = desc->idProduct;
@@ -126,7 +172,9 @@ static void device_add_handler(struct tegra_usb_modem *modem,
#ifdef CONFIG_PM
if (modem->capability & TEGRA_MODEM_AUTOSUSPEND) {
- pm_runtime_set_autosuspend_delay(&udev->dev, 2000);
+ pm_runtime_set_autosuspend_delay(&udev->dev,
+ modem->pdata->autosuspend_delay);
+ modem->short_autosuspend_enabled = 0;
usb_enable_autosuspend(udev);
pr_info("enable autosuspend for %s %s\n",
udev->manufacturer, udev->product);
@@ -140,8 +188,7 @@ static void device_remove_handler(struct tegra_usb_modem *modem,
{
const struct usb_device_descriptor *desc = &udev->descriptor;
- if (desc->idVendor == modem->vid &&
- desc->idProduct == modem->pid) {
+ if (desc->idVendor == modem->vid && desc->idProduct == modem->pid) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
@@ -158,11 +205,10 @@ static void device_remove_handler(struct tegra_usb_modem *modem,
}
static int mdm_usb_notifier(struct notifier_block *notifier,
- unsigned long usb_event,
- void *udev)
+ unsigned long usb_event, void *udev)
{
struct tegra_usb_modem *modem =
- container_of(notifier, struct tegra_usb_modem, usb_notifier);
+ container_of(notifier, struct tegra_usb_modem, usb_notifier);
switch (usb_event) {
case USB_DEVICE_ADD:
@@ -176,11 +222,10 @@ static int mdm_usb_notifier(struct notifier_block *notifier,
}
static int mdm_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event,
- void *unused)
+ unsigned long pm_event, void *unused)
{
struct tegra_usb_modem *modem =
- container_of(notifier, struct tegra_usb_modem, pm_notifier);
+ container_of(notifier, struct tegra_usb_modem, pm_notifier);
mutex_lock(&modem->lock);
if (!modem->udev) {
@@ -194,10 +239,20 @@ static int mdm_pm_notifier(struct notifier_block *notifier,
if (wake_lock_active(&modem->wake_lock)) {
pr_warn("%s: wakelock was active, aborting suspend\n",
__func__);
+ mutex_unlock(&modem->lock);
return NOTIFY_STOP;
}
modem->system_suspend = 1;
+#ifdef CONFIG_PM
+ if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
+ modem->udev &&
+ modem->udev->state != USB_STATE_NOTATTACHED) {
+ pm_runtime_set_autosuspend_delay(&modem->udev->dev,
+ modem->pdata->short_autosuspend_delay);
+ modem->short_autosuspend_enabled = 1;
+ }
+#endif
mutex_unlock(&modem->lock);
return NOTIFY_OK;
case PM_POST_SUSPEND:
@@ -210,12 +265,125 @@ 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)
+{
+ int ret;
+
+ ret = gpio_request(irq_gpio, label);
+ if (ret)
+ return ret;
+
+ tegra_gpio_enable(irq_gpio);
+
+ /* enable IRQ for GPIO */
+ *irq = gpio_to_irq(irq_gpio);
+
+ /* request threaded irq for GPIO */
+ ret = request_threaded_irq(*irq, NULL, thread_fn, irq_flags, label,
+ modem);
+ if (ret)
+ return ret;
+
+ ret = enable_irq_wake(*irq);
+ if (ret) {
+ free_irq(*irq, modem);
+ return ret;
+ }
+
+ return ret;
+}
+
+/* load USB host controller */
+static struct platform_device *tegra_usb_null_ulpi_host_register(void)
+{
+ struct platform_device *pdev;
+ int val;
+
+ pdev = platform_device_alloc(hc_device->name, hc_device->id);
+ if (!pdev)
+ return NULL;
+
+ val = platform_device_add_resources(pdev, hc_device->resource,
+ hc_device->num_resources);
+ if (val)
+ goto error;
+
+ pdev->dev.dma_mask = hc_device->dev.dma_mask;
+ pdev->dev.coherent_dma_mask = hc_device->dev.coherent_dma_mask;
+
+ val = platform_device_add_data(pdev, hc_pdata,
+ sizeof(struct tegra_usb_platform_data));
+ if (val)
+ goto error;
+
+ val = platform_device_add(pdev);
+ if (val)
+ goto error;
+
+ return pdev;
+
+error:
+ pr_err("%s: err %d\n", __func__, val);
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* unload USB host controller */
+static void tegra_usb_null_ulpi_host_unregister(struct platform_device *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static ssize_t show_usb_host(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", (hc) ? 1 : 0);
+}
+
+static ssize_t load_unload_usb_host(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int host;
+
+ if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
+ return -EINVAL;
+
+ pr_info("%s USB host\n", (host) ? "load" : "unload");
+
+ mutex_lock(&hc_lock);
+ if (host) {
+ if (!hc)
+ hc = tegra_usb_null_ulpi_host_register();
+ } else {
+ if (hc) {
+ tegra_usb_null_ulpi_host_unregister(hc);
+ hc = NULL;
+ }
+ }
+ mutex_unlock(&hc_lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(load_host, 0666, show_usb_host, load_unload_usb_host);
+
static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
{
struct tegra_usb_modem_power_platform_data *pdata =
pdev->dev.platform_data;
int ret = 0;
+ modem->pdata = pdata;
+
+ hc_device = pdata->tegra_ehci_device;
+ hc_pdata = pdata->tegra_ehci_pdata;
+ mutex_init(&hc_lock);
+
/* get modem operations from platform data */
modem->ops = (const struct tegra_modem_operations *)pdata->ops;
@@ -232,46 +400,41 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
modem->ops->start();
}
+ /* create sysfs node to load/unload host controller */
+ ret = device_create_file(&pdev->dev, &dev_attr_load_host);
+ if (ret) {
+ dev_err(&pdev->dev, "can't create sysfs file\n");
+ goto error;
+ }
+ modem->sysfs_file_created = 1;
+
mutex_init(&(modem->lock));
- wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND,
- "tegra_usb_mdm_lock");
+ wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
- /* create work queue platform_driver_registe*/
+ /* create work queue platform_driver_registe */
modem->wq = create_workqueue("tegra_usb_mdm_queue");
INIT_DELAYED_WORK(&(modem->recovery_work), tegra_usb_modem_recovery);
- /* create threaded irq for remote wakeup */
- if (gpio_is_valid(pdata->wake_gpio)) {
- /* get remote wakeup gpio from platform data */
- modem->wake_gpio = pdata->wake_gpio;
-
- ret = gpio_request(modem->wake_gpio, "usb_mdm_wake");
- if (ret)
- return ret;
-
- tegra_gpio_enable(modem->wake_gpio);
-
- /* enable IRQ for remote wakeup */
- modem->irq = gpio_to_irq(modem->wake_gpio);
-
- ret =
- request_threaded_irq(modem->irq, NULL,
- tegra_usb_modem_wake_thread,
- pdata->flags, "tegra_usb_mdm_wake",
- modem);
- if (ret < 0) {
- dev_err(&pdev->dev, "%s: request_threaded_irq error\n",
- __func__);
- return ret;
- }
+ /* 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;
+ }
- ret = enable_irq_wake(modem->irq);
- if (ret) {
- dev_err(&pdev->dev, "%s: enable_irq_wake error\n",
- __func__);
- free_irq(modem->irq, modem);
- return ret;
- }
+ /* 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;
}
modem->pm_notifier.notifier_call = mdm_pm_notifier;
@@ -281,6 +444,21 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
register_pm_notifier(&modem->pm_notifier);
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);
+ free_irq(modem->wake_irq, modem);
+ }
+
+ if (modem->boot_irq) {
+ disable_irq_wake(modem->boot_irq);
+ free_irq(modem->boot_irq, modem);
+ }
+
+ return ret;
}
static int tegra_usb_modem_probe(struct platform_device *pdev)
@@ -319,10 +497,19 @@ static int __exit tegra_usb_modem_remove(struct platform_device *pdev)
unregister_pm_notifier(&modem->pm_notifier);
usb_unregister_notify(&modem->usb_notifier);
- if (modem->irq) {
- disable_irq_wake(modem->irq);
- free_irq(modem->irq, modem);
+ if (modem->wake_irq) {
+ disable_irq_wake(modem->wake_irq);
+ free_irq(modem->wake_irq, modem);
+ }
+
+ if (modem->boot_irq) {
+ disable_irq_wake(modem->boot_irq);
+ free_irq(modem->boot_irq, modem);
}
+
+ if (modem->sysfs_file_created)
+ device_remove_file(&pdev->dev, &dev_attr_load_host);
+
kfree(modem);
return 0;
}