diff options
author | Raj Jayaraman <rjayaraman@nvidia.com> | 2011-12-02 14:30:29 -0800 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2011-12-21 12:06:28 +0530 |
commit | 8482db48752b39f88a24c45219e0404854ba8f95 (patch) | |
tree | 3b968488a73bc68b7e493a6a7ca6eb556a96bdbf /drivers/misc | |
parent | ab058e3fc916d499f7763079756e2e21d9eb68c5 (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.c | 207 | ||||
-rw-r--r-- | drivers/misc/tegra-baseband/bb-power.c | 127 | ||||
-rw-r--r-- | drivers/misc/tegra-baseband/bb-power.h | 34 |
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 |