summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorRaj Jayaraman <rjayaraman@nvidia.com>2011-12-02 14:30:29 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-21 12:06:28 +0530
commit8482db48752b39f88a24c45219e0404854ba8f95 (patch)
tree3b968488a73bc68b7e493a6a7ca6eb556a96bdbf /drivers/misc
parentab058e3fc916d499f7763079756e2e21d9eb68c5 (diff)
misc: tegra-baseband: Refactor power code.
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>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/tegra-baseband/bb-m7400.c207
-rw-r--r--drivers/misc/tegra-baseband/bb-power.c127
-rw-r--r--drivers/misc/tegra-baseband/bb-power.h34
3 files changed, 233 insertions, 135 deletions
diff --git a/drivers/misc/tegra-baseband/bb-m7400.c b/drivers/misc/tegra-baseband/bb-m7400.c
index 3040cb9c5267..4c87245eede4 100644
--- a/drivers/misc/tegra-baseband/bb-m7400.c
+++ b/drivers/misc/tegra-baseband/bb-m7400.c
@@ -31,17 +31,21 @@
#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;
+}
diff --git a/drivers/misc/tegra-baseband/bb-power.c b/drivers/misc/tegra-baseband/bb-power.c
index f0d40964cdbb..225d7667f86f 100644
--- a/drivers/misc/tegra-baseband/bb-power.c
+++ b/drivers/misc/tegra-baseband/bb-power.c
@@ -30,21 +30,13 @@
#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
diff --git a/drivers/misc/tegra-baseband/bb-power.h b/drivers/misc/tegra-baseband/bb-power.h
index 54cf1addf237..4f85cca712e6 100644
--- a/drivers/misc/tegra-baseband/bb-power.h
+++ b/drivers/misc/tegra-baseband/bb-power.h
@@ -14,14 +14,10 @@
*
*/
-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