diff options
author | Steve Lin <stlin@nvidia.com> | 2011-10-25 18:49:55 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:52:34 -0800 |
commit | fd08bafdac5a57fdfd71928c92d697d21c00dc26 (patch) | |
tree | 6e4ebd9b57988537d7f40024ad8868b556d01dcb /arch/arm | |
parent | 2274e751774ae13dcb6a33c26876a77d433ce8b0 (diff) |
arm: tegra: baseband: Decouple modem operation and power management
Enabling the tegra usb modem power management and decoupling the modem
operation and power management functions.
Bug 854339
Reviewed-on: http://git-master/r/53247
(cherry picked from commit 6e605c46d10ae729d3de069052ee4fe33b88ad55)
Change-Id: Ida1c3657dff91859c07cb30d7d3b870264f692d0
Reviewed-on: http://git-master/r/60349
Reviewed-by: Sheshagiri Shenoy <sshenoy@nvidia.com>
Reviewed-by: Steve Lin <stlin@nvidia.com>
Tested-by: Steve Lin <stlin@nvidia.com>
Rebase-Id: Rbc8fdd1991e8058031e237ab8ff037aa09478f55
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/board-enterprise-baseband.c | 258 |
1 files changed, 41 insertions, 217 deletions
diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c index b3d8a2455a05..6f2afa113d33 100644 --- a/arch/arm/mach-tegra/board-enterprise-baseband.c +++ b/arch/arm/mach-tegra/board-enterprise-baseband.c @@ -25,57 +25,39 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/err.h> -#include <linux/device.h> -#include <linux/usb.h> #include <linux/wakelock.h> #include <linux/platform_data/tegra_usb.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/pinmux.h> #include <mach/usb_phy.h> +#include <mach/tegra_usb_modem_power.h> #include "devices.h" #include "gpio-names.h" -#define ENABLE_AUTO_SUSPEND 0 -#define ENABLE_HOST_RECOVERY 0 /* flashless only feature */ - /* Tegra3 BB GPIO */ #define MODEM_PWR_ON TEGRA_GPIO_PE0 #define MODEM_RESET TEGRA_GPIO_PE1 #define BB_RST_OUT TEGRA_GPIO_PV1 -/* PH450 GPIO */ +/* Icera 450 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 -struct ph450_priv { - unsigned int wake_gpio; - unsigned int wake_cnt; - unsigned int restart_gpio; - struct mutex lock; - struct wake_lock wake_lock; - unsigned int vid; - unsigned int pid; - struct usb_device *udev; - struct usb_interface *intf; - struct workqueue_struct *wq; - struct delayed_work reset_work; -}; +static struct wake_lock mdm_wake_lock; -static struct usb_device_id modem_list[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_VENDOR, - .idVendor = 0x1983, - }, - {}, +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"}, }; static int ph450_phy_on(void); static int ph450_phy_off(void); -static struct ph450_priv ph450_priv; static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 }; static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = { @@ -98,121 +80,19 @@ static int __init tegra_null_ulpi_init(void) return 0; } -static void device_add_handler(struct usb_device *udev) -{ - const struct usb_device_descriptor *desc = &udev->descriptor; - struct usb_interface *intf = usb_ifnum_to_if(udev, 0); - - if (usb_match_id(intf, modem_list)) { - pr_info("Add device %d <%s %s>\n", udev->devnum, - udev->manufacturer, udev->product); - - mutex_lock(&ph450_priv.lock); - ph450_priv.udev = udev; - ph450_priv.intf = intf; - ph450_priv.vid = desc->idVendor; - ph450_priv.pid = desc->idProduct; - ph450_priv.wake_cnt = 0; - mutex_unlock(&ph450_priv.lock); - - pr_info("persist_enabled: %u\n", udev->persist_enabled); - -#if ENABLE_AUTO_SUSPEND - usb_enable_autosuspend(udev); - pr_info("enable autosuspend for %s %s\n", udev->manufacturer, - udev->product); -#endif - } -} - -static void device_remove_handler(struct usb_device *udev) -{ - const struct usb_device_descriptor *desc = &udev->descriptor; - - if (desc->idVendor == ph450_priv.vid - && desc->idProduct == ph450_priv.pid) { - pr_info("Remove device %d <%s %s>\n", udev->devnum, - udev->manufacturer, udev->product); - - mutex_lock(&ph450_priv.lock); - ph450_priv.udev = NULL; - ph450_priv.intf = NULL; - ph450_priv.vid = 0; - mutex_unlock(&ph450_priv.lock); - -#if ENABLE_HOST_RECOVERY - queue_delayed_work(ph450_priv.wq, &ph450_priv.reset_work, - HZ * 10); -#endif - } -} - -static int usb_notify(struct notifier_block *self, unsigned long action, - void *blob) -{ - switch (action) { - case USB_DEVICE_ADD: - device_add_handler(blob); - break; - case USB_DEVICE_REMOVE: - device_remove_handler(blob); - break; - } - - return NOTIFY_OK; -} - -static struct notifier_block usb_nb = { - .notifier_call = usb_notify, -}; - static irqreturn_t mdm_start_thread(int irq, void *data) { - struct ph450_priv *priv = (struct ph450_priv *)data; - - if (gpio_get_value(priv->restart_gpio)) { + if (gpio_get_value(BB_RST_OUT)) { pr_info("BB_RST_OUT high\n"); - /* hold wait lock to complete the enumeration */ - wake_lock_timeout(&priv->wake_lock, HZ * 2); } else { pr_info("BB_RST_OUT low\n"); /* hold wait lock to complete the enumeration */ - wake_lock_timeout(&priv->wake_lock, HZ * 10); - } - - return IRQ_HANDLED; -} - -static irqreturn_t mdm_wake_thread(int irq, void *data) -{ - struct ph450_priv *priv = (struct ph450_priv *)data; - - wake_lock_timeout(&priv->wake_lock, HZ); - mutex_lock(&priv->lock); - if (priv->udev) { - usb_lock_device(priv->udev); - pr_info("mdm wake (%u)\n", ++(priv->wake_cnt)); - if (usb_autopm_get_interface(priv->intf) == 0) - usb_autopm_put_interface_async(priv->intf); - usb_unlock_device(priv->udev); + wake_lock_timeout(&mdm_wake_lock, HZ * 10); } - mutex_unlock(&priv->lock); return IRQ_HANDLED; } -static int ph450_reset(void) -{ - pr_info("modem reset\n"); - - gpio_set_value(AP2MDM_ACK2, 1); - gpio_set_value(MODEM_PWR_ON, 0); - mdelay(200); - gpio_set_value(MODEM_PWR_ON, 1); - - return 0; -} - static int ph450_phy_on(void) { /* set AP2MDM_ACK2 low */ @@ -229,54 +109,23 @@ static int ph450_phy_off(void) return 0; } -static void ph450_reset_work_handler(struct work_struct *ws) +static void ph450_reset(void) { - struct ph450_priv *priv = container_of(ws, struct ph450_priv, - reset_work.work); - - mutex_lock(&priv->lock); - if (!priv->udev) /* assume modem crashed */ - ph450_reset(); - mutex_unlock(&priv->lock); + pr_info("%s\n", __func__); + gpio_set_value(MODEM_PWR_ON, 0); + mdelay(200); + gpio_set_value(MODEM_PWR_ON, 1); } -static int __init ph450_init(void) +static int ph450_init(void) { int irq; int ret; - ret = gpio_request(MODEM_PWR_ON, "mdm_power"); + ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios)); if (ret) return ret; - ret = gpio_request(MODEM_RESET, "mdm_reset"); - if (ret) { - gpio_free(MODEM_PWR_ON); - return ret; - } - ret = gpio_request(AP2MDM_ACK2, "ap2mdm_ack2"); - if (ret) { - gpio_free(MODEM_PWR_ON); - gpio_free(MODEM_RESET); - return ret; - } - ret = gpio_request(MDM2AP_ACK2, "mdm2ap_ack2"); - if (ret) { - gpio_free(MODEM_PWR_ON); - gpio_free(MODEM_RESET); - gpio_free(AP2MDM_ACK2); - return ret; - } - - ret = gpio_request(BB_RST_OUT, "bb_rst_out"); - if (ret) { - gpio_free(MODEM_PWR_ON); - gpio_free(MODEM_RESET); - gpio_free(AP2MDM_ACK2); - gpio_free(MDM2AP_ACK2); - return ret; - } - /* enable pull-up for ULPI STP */ tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_ULPI_STP, TEGRA_PUPD_PULL_UP); @@ -288,39 +137,22 @@ static int __init ph450_init(void) tegra_gpio_enable(MODEM_PWR_ON); tegra_gpio_enable(MODEM_RESET); tegra_gpio_enable(AP2MDM_ACK2); - tegra_gpio_enable(MDM2AP_ACK2); tegra_gpio_enable(BB_RST_OUT); - gpio_direction_output(MODEM_PWR_ON, 0); /* export GPIO for user space access through sysfs */ gpio_export(MODEM_PWR_ON, false); - gpio_direction_input(MODEM_RESET); - gpio_direction_output(AP2MDM_ACK2, 1); - gpio_direction_input(MDM2AP_ACK2); - gpio_direction_input(BB_RST_OUT); /* phy init */ tegra_null_ulpi_init(); - ph450_priv.wake_gpio = TEGRA_GPIO_PV0; - ph450_priv.restart_gpio = TEGRA_GPIO_PV1; - - mutex_init(&(ph450_priv.lock)); - wake_lock_init(&(ph450_priv.wake_lock), WAKE_LOCK_SUSPEND, - "mdm_wake_lock"); - - /* create work queue */ - ph450_priv.wq = create_workqueue("mdm_queue"); - INIT_DELAYED_WORK(&(ph450_priv.reset_work), ph450_reset_work_handler); - - usb_register_notify(&usb_nb); + wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock"); /* enable IRQ for BB_RST_OUT */ - irq = gpio_to_irq(TEGRA_GPIO_PV1); + irq = gpio_to_irq(BB_RST_OUT); ret = request_threaded_irq(irq, NULL, mdm_start_thread, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "mdm_start", &ph450_priv); + "mdm_start", NULL); if (ret < 0) { pr_err("%s: request_threaded_irq error\n", __func__); return ret; @@ -329,43 +161,35 @@ static int __init ph450_init(void) ret = enable_irq_wake(irq); if (ret) { pr_err("%s: enable_irq_wake error\n", __func__); - free_irq(irq, &ph450_priv); + free_irq(irq, NULL); return ret; } - /* enable IRQ for MDM2AP_ACK2 */ - irq = gpio_to_irq(TEGRA_GPIO_PV0); - - ret = request_threaded_irq(irq, NULL, mdm_wake_thread, - IRQF_TRIGGER_FALLING, "mdm_wake", - &ph450_priv); - if (ret < 0) { - pr_err("%s: request_threaded_irq error\n", __func__); - return ret; - } + return 0; +} - ret = enable_irq_wake(irq); - if (ret) { - pr_err("%s: enable_irq_wake error\n", __func__); - free_irq(irq, &ph450_priv); - return ret; - } +static const struct tegra_modem_operations ph450_operations = { + .init = ph450_init, + .start = ph450_reset, + .reset = ph450_reset, +}; - /* reset modem */ - ph450_reset(); +static struct tegra_usb_modem_power_platform_data ph450_pdata = { + .ops = &ph450_operations, + .wake_gpio = MDM2AP_ACK2, + .flags = IRQF_TRIGGER_FALLING, +}; - return 0; -} +static struct platform_device icera_450_device = { + .name = "tegra_usb_modem_power", + .id = -1, + .dev = { + .platform_data = &ph450_pdata, + }, +}; int __init enterprise_modem_init(void) { - int ret; - - ret = ph450_init(); - if (ret) { - pr_err("modem init failed\n"); - return ret; - } - + platform_device_register(&icera_450_device); return 0; } |