misc: tegra-baseband: Refactor power code.
Raj Jayaraman [Fri, 2 Dec 2011 22:30:29 +0000 (14:30 -0800)]
Bug 886459

Change-Id: I6005ba8081951a015f101ad864c00232ea88590a
Signed-off-by: Raj Jayaraman <rjayaraman@nvidia.com>
Reviewed-on: http://git-master/r/69567
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>

Rebase-Id: R7c12cdacd8fb4ebee6edc1541d59cc10c4844a0d

arch/arm/mach-tegra/include/mach/tegra-bb-power.h
drivers/misc/tegra-baseband/bb-m7400.c
drivers/misc/tegra-baseband/bb-power.c
drivers/misc/tegra-baseband/bb-power.h

index 893cc91..e0b7e3d 100644 (file)
@@ -49,8 +49,13 @@ union tegra_bb_gpio_id {
        } m7400;
 };
 
+typedef struct platform_device* (*ehci_register_cb)(void);
+typedef void (*ehci_unregister_cb)(struct platform_device *);
+
 struct tegra_bb_pdata {
        union tegra_bb_gpio_id *id;
        struct platform_device *device;
+       ehci_register_cb ehci_register;
+       ehci_unregister_cb ehci_unregister;
        int bb_id;
 };
index 3040cb9..4c87245 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/tegra-bb-power.h>
+#include <mach/usb_phy.h>
 #include "bb-power.h"
 
 static struct tegra_bb_gpio_data m7400_gpios[] = {
        { { GPIO_INVALID, GPIOF_OUT_INIT_LOW, "MDM_PWR_ON" }, true },
        { { GPIO_INVALID, GPIOF_IN, "MDM_PWRSTATUS" }, true },
        { { GPIO_INVALID, GPIOF_OUT_INIT_HIGH, "MDM_SERVICE" }, true },
-       { { GPIO_INVALID, GPIOF_OUT_INIT_HIGH, "MDM_USB_AWR" }, false },
+       { { GPIO_INVALID, GPIOF_OUT_INIT_LOW, "MDM_USB_AWR" }, false },
        { { GPIO_INVALID, GPIOF_IN, "MDM_USB_CWR" }, false },
        { { GPIO_INVALID, GPIOF_IN, "MDM_RESOUT2" }, true },
        { { GPIO_INVALID, 0, NULL }, false },   /* End of table */
 };
+static bool ehci_registered;
+static int gpio_awr;
+static int gpio_cwr;
 
 static int gpio_wait_timeout(int gpio, int value, int timeout_msec)
 {
@@ -54,39 +58,71 @@ static int gpio_wait_timeout(int gpio, int value, int timeout_msec)
        return -1;
 }
 
-static int baseband_l3_suspend(void)
+static int m7400_enum_handshake(void)
 {
-       int gpio_awr = m7400_gpios[3].data.gpio;
+       int retval = 0;
 
-       /* Signal L3 to modem - Drive USB_AWR low. */
-       gpio_set_value(gpio_awr, 0);
+       /* Wait for CP to indicate ready - by driving USB_CWR high. */
+       if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
+                       pr_info("%s: Error: timeout waiting for modem resume.\n",
+                                                       __func__);
+                       retval = -1;
+       }
 
-       return 0;
+       /* Signal AP ready - Drive USB_AWR high. */
+       gpio_set_value(gpio_awr, 1);
+
+       return retval;
 }
 
-static int baseband_l3_resume(void)
+static int m7400_apup_handshake(bool checkresponse)
 {
-       int gpio_awr = m7400_gpios[3].data.gpio;
-       int gpio_cwr = m7400_gpios[4].data.gpio;
+       int retval = 0;
 
-       /* Signal L0 to modem - Drive USB_AWR high. */
+       /* Signal AP ready - Drive USB_AWR high. */
        gpio_set_value(gpio_awr, 1);
 
-       /* If this is a AP driven wakeup, wait for CP
-          to ack by driving USB_CWR high.
-          If this is a CP driven wakeup, USB_CWR will
-          be high already. AP has already driven it's
-          response as above.
-       */
-       if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0)
-               pr_info("%s: timeout waiting for modem ack.\n", __func__);
+       if (checkresponse) {
+               /* Wait for CP ack - by driving USB_CWR high. */
+               if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
+                       pr_info("%s: Error: timeout waiting for modem ack.\n",
+                                                       __func__);
+                       retval = -1;
+               }
+       }
+       return retval;
+}
+
+static void m7400_apdown_handshake(void)
+{
+       /* Signal AP going down to modem - Drive USB_AWR low. */
+       /* No need to wait for a CP response */
+       gpio_set_value(gpio_awr, 0);
+}
+
+static int m7400_l2_suspend(void)
+{
+       return 0;
+}
 
+static int m7400_l2_resume(void)
+{
        return 0;
 }
 
-static irqreturn_t baseband_wake_irq(int irq, void *dev_id)
+static void m7400_l3_suspend(void)
+{
+       m7400_apdown_handshake();
+}
+
+static void m7400_l3_resume(void)
+{
+       m7400_apup_handshake(true);
+}
+
+static irqreturn_t m7400_wake_irq(int irq, void *dev_id)
 {
-       pr_info("%s {\n", __func__);
+       pr_info("%s called.\n", __func__);
 
        /* Resume usb host activity. */
        /* TBD */
@@ -94,18 +130,14 @@ static irqreturn_t baseband_wake_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int m7400_power_callback(int code)
+static int m7400_power(int code)
 {
        switch (code) {
-       case CB_CODE_L0L2:
-       break;
-       case CB_CODE_L2L0:
+       case PWRSTATE_L2L3:
+       m7400_l3_suspend();
        break;
-       case CB_CODE_L2L3:
-       baseband_l3_suspend();
-       break;
-       case CB_CODE_L3L0:
-       baseband_l3_resume();
+       case PWRSTATE_L3L0:
+       m7400_l3_resume();
        break;
        default:
        break;
@@ -113,10 +145,72 @@ int m7400_power_callback(int code)
        return 0;
 }
 
+static void m7400_ehci_customize(struct platform_device *pdev)
+{
+       struct tegra_ehci_platform_data *ehci_pdata;
+       struct tegra_uhsic_config *hsic_config;
+
+       ehci_pdata = (struct tegra_ehci_platform_data *)
+                       pdev->dev.platform_data;
+       hsic_config = (struct tegra_uhsic_config *)
+                       ehci_pdata->phy_config;
+
+       /* Register PHY callbacks */
+       hsic_config->postsuspend = m7400_l2_suspend;
+       hsic_config->preresume = m7400_l2_resume;
+
+       /* Override required settings */
+       ehci_pdata->power_down_on_bus_suspend = 0;
+}
+
+static int m7400_attrib_write(struct device *dev, int value)
+{
+       struct tegra_bb_pdata *pdata;
+       static struct platform_device *ehci_device;
+       static bool first_enum = true;
+
+       if (value > 1 || (!ehci_registered && !value)) {
+               /* Supported values are 0/1. */
+               return -1;
+       }
+
+       pdata = (struct tegra_bb_pdata *) dev->platform_data;
+       if (value) {
+
+               /* Check readiness for enumeration */
+               if (first_enum)
+                       first_enum = false;
+               else
+                       m7400_enum_handshake();
+
+               /* Register ehci controller */
+               ehci_device = pdata->ehci_register();
+               if (ehci_device == NULL) {
+                       pr_info("%s - Error: ehci register failed.\n",
+                                                        __func__);
+                       return -1;
+               }
+
+               /* Customize PHY setup/callbacks */
+               m7400_ehci_customize(ehci_device);
+
+               ehci_registered = true;
+       } else {
+               /* Unregister ehci controller */
+               if (ehci_device != NULL)
+                       pdata->ehci_unregister(ehci_device);
+
+               /* Signal AP going down */
+               m7400_apdown_handshake();
+               ehci_registered = false;
+       }
+
+       return 0;
+}
 
 static struct tegra_bb_gpio_irqdata m7400_gpioirqs[] = {
-       { GPIO_INVALID, "tegra_bb_wake", baseband_wake_irq,
-                                       IRQF_TRIGGER_RISING, NULL },
+       { GPIO_INVALID, "tegra_bb_wake", m7400_wake_irq,
+                                       IRQF_TRIGGER_FALLING, NULL },
        { GPIO_INVALID, NULL, NULL, 0, NULL },  /* End of table */
 };
 
@@ -125,21 +219,52 @@ static struct tegra_bb_power_gdata m7400_gdata = {
        .gpioirq = m7400_gpioirqs,
 };
 
-void *m7400_init(void *pdata, int code)
+static void *m7400_init(void *pdata)
 {
        struct tegra_bb_pdata *platdata = (struct tegra_bb_pdata *) pdata;
        union tegra_bb_gpio_id *id = platdata->id;
 
-       if (code == CB_CODE_INIT) {
-               /* Fill the gpio ids allocated by hardware */
-               m7400_gpios[0].data.gpio = id->m7400.pwr_on;
-               m7400_gpios[1].data.gpio = id->m7400.pwr_status;
-               m7400_gpios[2].data.gpio = id->m7400.service;
-               m7400_gpios[3].data.gpio = id->m7400.usb_awr;
-               m7400_gpios[4].data.gpio = id->m7400.usb_cwr;
-               m7400_gpios[5].data.gpio = id->m7400.resout2;
-               m7400_gpioirqs[0].id = id->m7400.usb_cwr;
+       /* Fill the gpio ids allocated by hardware */
+       m7400_gpios[0].data.gpio = id->m7400.pwr_on;
+       m7400_gpios[1].data.gpio = id->m7400.pwr_status;
+       m7400_gpios[2].data.gpio = id->m7400.service;
+       m7400_gpios[3].data.gpio = id->m7400.usb_awr;
+       m7400_gpios[4].data.gpio = id->m7400.usb_cwr;
+       m7400_gpios[5].data.gpio = id->m7400.resout2;
+       m7400_gpioirqs[0].id = id->m7400.usb_cwr;
+
+       if (!platdata->ehci_register || !platdata->ehci_unregister) {
+               pr_info("%s - Error: ehci reg/unreg functions missing.\n"
+                                                       , __func__);
+               return 0;
+       }
+
+       gpio_awr = m7400_gpios[3].data.gpio;
+       gpio_cwr = m7400_gpios[4].data.gpio;
+       if (gpio_awr == GPIO_INVALID || gpio_cwr == GPIO_INVALID) {
+               pr_info("%s - Error: Invalid gpio data.\n", __func__);
+               return 0;
        }
 
+       ehci_registered = false;
        return (void *) &m7400_gdata;
 }
+
+static void *m7400_deinit(void)
+{
+       return (void *) &m7400_gdata;
+}
+
+static struct tegra_bb_callback m7400_callbacks = {
+       .init = m7400_init,
+       .deinit = m7400_deinit,
+       .attrib = m7400_attrib_write,
+#ifdef CONFIG_PM
+       .power = m7400_power,
+#endif
+};
+
+void *m7400_get_cblist(void)
+{
+       return (void *) &m7400_callbacks;
+}
index f0d4096..225d766 100644 (file)
 #include <mach/tegra-bb-power.h>
 #include "bb-power.h"
 
-static int bb_id;
-static bool bb_registered;
-
-static bb_init_cb init_cb_list[] = {
+static struct tegra_bb_callback *callback;
+static int attr_load_val;
+static bb_get_cblist get_cblist[] = {
        NULL,
        NULL,
        NULL,
-       M7400_INIT_CB,
-};
-
-static bb_power_cb power_cb_list[] = {
-       NULL,
-       NULL,
-       NULL,
-       M7400_PWR_CB,
+       M7400_CB,
 };
 
 static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
@@ -66,7 +58,7 @@ static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
                /* Request the gpio */
                ret = gpio_request(gpio_id, gpio_label);
                if (ret) {
-                       pr_err("%s: gpio_request for gpio %d failed.\n",
+                       pr_err("%s: Error: gpio_request for gpio %d failed.\n",
                                                         __func__, gpio_id);
                        return ret;
                }
@@ -94,13 +86,14 @@ static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
                        ret = request_threaded_irq(irq, NULL, gpioirq->handler,
                                gpioirq->flags, gpioirq->name, gpioirq->cookie);
                        if (ret < 0) {
-                               pr_err("%s: request_threaded_irq error\n",
-                                                                __func__);
+                               pr_err("%s: Error: threaded_irq req fail.\n"
+                                                               , __func__);
                                return ret;
                        }
                        ret = enable_irq_wake(irq);
                        if (ret) {
-                               pr_err("%s: enable_irq_wake error\n", __func__);
+                               pr_err("%s: Error: enable_irq_wake failed.\n",
+                                                               __func__);
                                return ret;
                        }
                }
@@ -129,61 +122,26 @@ static int tegra_bb_power_gpio_deinit(struct tegra_bb_power_gdata *gdata)
        return 0;
 }
 
-static int baseband_l2_suspend(void)
-{
-       /* BB specific callback */
-       if (power_cb_list[bb_id] != NULL)
-               power_cb_list[bb_id](CB_CODE_L0L2);
-       return 0;
-}
-
-static int baseband_l2_resume(void)
-{
-       /* BB specific callback */
-       if (power_cb_list[bb_id] != NULL)
-               power_cb_list[bb_id](CB_CODE_L2L0);
-       return 0;
-}
-
 static ssize_t tegra_bb_attr_write(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct tegra_bb_pdata *pdata;
-       struct tegra_ehci_platform_data *ehci_data;
-       struct tegra_uhsic_config *hsic_config;
-       int load;
+       int val;
 
-       if (sscanf(buf, "%d", &load) != 1)
+       if (sscanf(buf, "%d", &val) != 1)
                return -EINVAL;
 
-       if (load == 1 && !bb_registered) {
-               pdata = (struct tegra_bb_pdata *) dev->platform_data;
-               ehci_data = (struct tegra_ehci_platform_data *)
-                                       pdata->device->dev.platform_data;
-               hsic_config = (struct tegra_uhsic_config *)
-                                       ehci_data->phy_config;
-
-               /* Register PHY callbacks */
-               hsic_config->postsuspend = baseband_l2_suspend;
-               hsic_config->preresume = baseband_l2_resume;
-
-               /* Override required settings */
-               ehci_data->power_down_on_bus_suspend = 0;
-
-               /* Register the ehci device. */
-               platform_device_register(pdata->device);
-               bb_registered = true;
+       if (callback && callback->attrib) {
+               if (!callback->attrib(dev, val))
+                       attr_load_val = val;
        }
-
        return count;
 }
 
 static ssize_t tegra_bb_attr_read(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       int ret = 0;
-       return sprintf(buf, "%d", ret);
+       return sprintf(buf, "%d", attr_load_val);
 }
 
 static DEVICE_ATTR(load, S_IRUSR | S_IWUSR | S_IRGRP,
@@ -195,6 +153,7 @@ static int tegra_bb_power_probe(struct platform_device *device)
        struct tegra_bb_pdata *pdata;
        struct tegra_bb_power_gdata *gdata;
        int err;
+       unsigned int bb_id;
 
        pdata = (struct tegra_bb_pdata *) dev->platform_data;
        if (!pdata) {
@@ -202,29 +161,39 @@ static int tegra_bb_power_probe(struct platform_device *device)
                return -ENODEV;
        }
 
-       /* BB specific callback */
+       /* Obtain BB specific callback list */
        bb_id = pdata->bb_id;
-       if (init_cb_list[bb_id] != NULL) {
-               gdata = (struct tegra_bb_power_gdata *)
-               init_cb_list[pdata->bb_id]((void *)pdata, CB_CODE_INIT);
+       if (get_cblist[bb_id] != NULL) {
+               callback = (struct tegra_bb_callback *) get_cblist[bb_id]();
+               if (callback && callback->init) {
+                       gdata = (struct tegra_bb_power_gdata *)
+                       callback->init((void *)pdata);
+
+                       if (!gdata) {
+                               pr_err("%s - Error: Gpio data is empty.\n",
+                                                               __func__);
+                               return -ENODEV;
+                       }
 
-               if (!gdata) {
-                       pr_err("%s - Error: Gpio data is empty.\n", __func__);
+                       /* Initialize gpio as required */
+                       tegra_bb_power_gpio_init(gdata);
+               } else {
+                       pr_err("%s - Error: init callback is empty.\n",
+                                                               __func__);
                        return -ENODEV;
                }
-
-               /* Initialize gpio as required */
-               tegra_bb_power_gpio_init(gdata);
+       } else {
+               pr_err("%s - Error: callback data is empty.\n", __func__);
+               return -ENODEV;
        }
 
-       bb_registered = false;
-
        /* Create the control sysfs node */
        err = device_create_file(dev, &dev_attr_load);
        if (err < 0) {
-               pr_err("%s - device_create_file failed\n", __func__);
+               pr_err("%s - Error: device_create_file failed.\n", __func__);
                return -ENODEV;
        }
+       attr_load_val = 0;
 
        return 0;
 }
@@ -232,18 +201,20 @@ static int tegra_bb_power_probe(struct platform_device *device)
 static int tegra_bb_power_remove(struct platform_device *device)
 {
        struct device *dev = &device->dev;
-       struct tegra_bb_pdata *pdata;
        struct tegra_bb_power_gdata *gdata;
 
        /* BB specific callback */
-       if (init_cb_list[bb_id] != NULL) {
-               pdata = (struct tegra_bb_pdata *) dev->platform_data;
+       if (callback && callback->deinit) {
                gdata = (struct tegra_bb_power_gdata *)
-                       init_cb_list[bb_id]((void *)pdata, CB_CODE_DEINIT);
+               callback->deinit();
 
                /* Deinitialize gpios */
                if (gdata)
                        tegra_bb_power_gpio_deinit(gdata);
+               else {
+                       pr_err("%s - Error: Gpio data is empty.\n", __func__);
+                       return -ENODEV;
+               }
        }
 
        /* Remove the control sysfs node */
@@ -257,18 +228,16 @@ static int tegra_bb_power_suspend(struct platform_device *device,
        pm_message_t state)
 {
        /* BB specific callback */
-       if (power_cb_list[bb_id] != NULL)
-               power_cb_list[bb_id](CB_CODE_L2L3);
-
+       if (callback && callback->power)
+               callback->power(PWRSTATE_L2L3);
        return 0;
 }
 
 static int tegra_bb_power_resume(struct platform_device *device)
 {
        /* BB specific callback */
-       if (power_cb_list[bb_id] != NULL)
-               power_cb_list[bb_id](CB_CODE_L3L0);
-
+       if (callback && callback->power)
+               callback->power(PWRSTATE_L3L0);
        return 0;
 }
 #endif
index 54cf1ad..4f85cca 100644 (file)
  *
  */
 
-enum tegra_bb_callback_code {
-       CB_CODE_INIT = 1,
-       CB_CODE_DEINIT,
-       CB_CODE_L0L2,
-       CB_CODE_L2L0,
-       CB_CODE_L2L3,
-       CB_CODE_L3L0,
-       CB_CODE_INVALID,
+enum tegra_bb_pwrstate {
+       PWRSTATE_L2L3,
+       PWRSTATE_L3L0,
+       PWRSTATE_INVALID,
 };
 
 struct tegra_bb_gpio_data {
@@ -42,15 +38,23 @@ struct tegra_bb_power_gdata {
        struct tegra_bb_gpio_irqdata *gpioirq;
 };
 
-typedef void* (*bb_init_cb)(void *pdata, int code);
+typedef void* (*bb_get_cblist)(void);
+typedef void* (*bb_init_cb)(void *pdata);
+typedef void* (*bb_deinit_cb)(void);
 typedef int (*bb_power_cb)(int code);
+typedef int (*bb_attrib_cb)(struct device *dev, int value);
+
+struct tegra_bb_callback {
+       bb_init_cb init;
+       bb_deinit_cb deinit;
+       bb_power_cb power;
+       bb_attrib_cb attrib;
+       bool valid;
+};
 
 #ifdef CONFIG_TEGRA_BB_M7400
-extern void *m7400_init(void *pdata, int code);
-#define M7400_INIT_CB m7400_init
-extern int m7400_power_callback(int code);
-#define M7400_PWR_CB m7400_power_callback
+extern void *m7400_get_cblist(void);
+#define M7400_CB m7400_get_cblist
 #else
-#define M7400_INIT_CB NULL
-#define M7400_PWR_CB NULL
+#define M7400_CB NULL
 #endif