summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/baseband-xmm-power.c
diff options
context:
space:
mode:
authorMichael Hsu <mhsu@nvidia.com>2011-10-14 17:26:07 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:52:39 -0800
commit645f91c68b19172da28779e86c2d60045fc64705 (patch)
treebc570f012238e1578d528f004048a477ad361a92 /arch/arm/mach-tegra/baseband-xmm-power.c
parent7a6f2363adc93e15bc2b1f96a3b4db9d75a43552 (diff)
arm: tegra: comms: GPIO changes for XMM modem ver 1130 or later
XMM modem version 1130 (or later) changes the GPIO power up sequence. Add module variable to support pre-1130 and post-1130 modem versions. BUG 828389 Reviewed-on: http://git-master/r/58240 (cherry picked from commit 0639c200face90d6dd0144acc7362c02909fa66c) Change-Id: If3a3486741d72d1251deeca3759af6b39c2031f1 Reviewed-on: http://git-master/r/62750 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Rf848b30671a8739c11a376011165db6165f0a259
Diffstat (limited to 'arch/arm/mach-tegra/baseband-xmm-power.c')
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c484
1 files changed, 330 insertions, 154 deletions
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c
index dc8f8191a95d..fc4e957c964e 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power.c
@@ -22,6 +22,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
+#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
@@ -32,15 +33,34 @@
#include "gpio-names.h"
#include "baseband-xmm-power.h"
+#define VENDOR_ID 0x1519
+#define PRODUCT_ID 0x0020
+
MODULE_LICENSE("GPL");
-unsigned long enum_delay_ms = 1000;
+unsigned long modem_ver = XMM_MODEM_VER_1121;
+EXPORT_SYMBOL(modem_ver);
-module_param(enum_delay_ms, ulong, 0644);
-MODULE_PARM_DESC(enum_delay_ms, "baseband xmm power"
- " - delay in ms between modem on and enumeration");
+unsigned long modem_flash;
+EXPORT_SYMBOL(modem_flash);
+
+unsigned long modem_pm = 1;
+EXPORT_SYMBOL(modem_pm);
-#define TEGRA_EHCI_DEVICE "/sys/devices/platform/tegra-ehci.1/ehci_power"
+unsigned long enum_delay_ms = 1000; /* ignored if !modem_flash */
+
+module_param(modem_ver, ulong, 0644);
+MODULE_PARM_DESC(modem_ver,
+ "baseband xmm power - modem software version");
+module_param(modem_flash, ulong, 0644);
+MODULE_PARM_DESC(modem_flash,
+ "baseband xmm power - modem flash (1 = flash, 0 = flashless)");
+module_param(modem_pm, ulong, 0644);
+MODULE_PARM_DESC(modem_pm,
+ "baseband xmm power - modem power management (1 = pm, 0 = no pm)");
+module_param(enum_delay_ms, ulong, 0644);
+MODULE_PARM_DESC(enum_delay_ms,
+ "baseband xmm power - delay in ms between modem on and enumeration");
/* Currently no baseband initiated suspend */
#define BB_INITIATED_L2_SUSPEND 0
@@ -73,6 +93,8 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
+enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
+
static struct workqueue_struct *workqueue;
static struct work_struct init1_work;
static struct work_struct init2_work;
@@ -81,59 +103,54 @@ static struct baseband_power_platform_data *baseband_power_driver_data;
static bool register_hsic_device;
static struct wake_lock wakelock;
-/* static functions */
-static int baseband_xmm_power_on(struct platform_device *device);
-static int baseband_xmm_power_off(struct platform_device *device);
-
-static ssize_t baseband_xmm_onoff(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int power_onoff;
- struct platform_device *device = to_platform_device(dev);
-
- pr_debug("%s\n", __func__);
-
- if (sscanf(buf, "%d", &power_onoff) != 1)
- return -EINVAL;
-
- if (power_onoff == 0)
- baseband_xmm_power_off(device);
- else if (power_onoff == 1)
- baseband_xmm_power_on(device);
- return count;
-}
-
-static DEVICE_ATTR(xmm_onoff, S_IRUSR | S_IWUSR | S_IRGRP,
- NULL, baseband_xmm_onoff);
-
static int baseband_xmm_power_on(struct platform_device *device)
{
- int value;
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
+ struct baseband_power_platform_data *data;
- pr_debug("%s{\n", __func__);
+ pr_debug("%s {\n", __func__);
- /* check for platform data */
- if (!baseband_power_driver_data)
+ /* check for device / platform data */
+ if (!device) {
+ pr_err("%s: !device\n", __func__);
return -EINVAL;
-
- /* check if IPC_HSIC_ACTIVE low */
- value = gpio_get_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active);
- if (value != 0) {
- pr_err("%s - expected IPC_HSIC_ACTIVE low!\n", __func__);
+ }
+ data = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+ if (!data) {
+ pr_err("%s: !data\n", __func__);
return -EINVAL;
}
+ /* turn on usb host controller */
+ if (!modem_flash) {
+ /* if already registered usb host controller, then turn on
+ * using ehci_power file
+ */
+ if (!register_hsic_device) {
+ mm_segment_t oldfs;
+ struct file *filp;
+ pr_debug("%s(%d) register usb host controller echo on\n",
+ __func__, __LINE__);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open(TEGRA_EHCI_DEVICE, O_RDWR, 0);
+ if (IS_ERR(filp) || (filp == NULL)) {
+ pr_err("open ehci_power failed\n");
+ } else {
+ filp->f_op->write(filp, "1", 1, &filp->f_pos);
+ filp_close(filp, NULL);
+ }
+ set_fs(oldfs);
+ }
+ /* else if usb host controller not registered yet, then turn
+ * on will occur later in this function (when usb host
+ * controller is registered for first time)
+ */
+ }
+
/* reset the state machine */
baseband_xmm_powerstate = BBXMM_PS_INIT;
- ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
/* wait 20 ms */
mdelay(20);
@@ -146,23 +163,15 @@ static int baseband_xmm_power_on(struct platform_device *device)
udelay(40);
gpio_set_value(data->modem.xmm.bb_on, 0);
- if (enum_delay_ms)
- mdelay(enum_delay_ms);
-
- /* turn on usb host controller */
- {
- mm_segment_t oldfs;
- struct file *filp;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- filp = filp_open(TEGRA_EHCI_DEVICE, O_RDWR, 0);
- if (!filp) {
- pr_err("open ehci_power failed\n");
- } else {
- filp->f_op->write(filp, "1", 1, &filp->f_pos);
- filp_close(filp, NULL);
+ /* register usb host controller */
+ if (!modem_flash) {
+ /* register usb host controller only once */
+ if (register_hsic_device) {
+ pr_debug("%s(%d) register usb host controller\n",
+ __func__, __LINE__);
+ platform_device_register(data->modem.xmm.hsic_device);
+ register_hsic_device = false;
}
- set_fs(oldfs);
}
pr_debug("%s }\n", __func__);
@@ -172,10 +181,21 @@ static int baseband_xmm_power_on(struct platform_device *device)
static int baseband_xmm_power_off(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
+ struct baseband_power_platform_data *data;
- pr_debug("%s\n", __func__);
+ pr_debug("%s {\n", __func__);
+
+ /* check for device / platform data */
+ if (!device) {
+ pr_err("%s: !device\n", __func__);
+ return -EINVAL;
+ }
+ data = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+ if (!data) {
+ pr_err("%s: !data\n", __func__);
+ return -EINVAL;
+ }
/* turn off usb host controller */
{
@@ -184,7 +204,7 @@ static int baseband_xmm_power_off(struct platform_device *device)
oldfs = get_fs();
set_fs(KERNEL_DS);
filp = filp_open(TEGRA_EHCI_DEVICE, O_RDWR, 0);
- if (!filp) {
+ if (IS_ERR(filp) || (filp == NULL)) {
pr_err("open ehci_power failed\n");
} else {
filp->f_op->write(filp, "0", 1, &filp->f_pos);
@@ -196,6 +216,7 @@ static int baseband_xmm_power_off(struct platform_device *device)
/* set IPC_HSIC_ACTIVE low */
gpio_set_value(baseband_power_driver_data->
modem.xmm.ipc_hsic_active, 0);
+
/* wait 20 ms */
mdelay(20);
@@ -203,24 +224,48 @@ static int baseband_xmm_power_off(struct platform_device *device)
gpio_set_value(data->modem.xmm.bb_rst, 0);
mdelay(1);
+ pr_debug("%s }\n", __func__);
+
return 0;
}
+static ssize_t baseband_xmm_onoff(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int power_onoff;
+ struct platform_device *device = to_platform_device(dev);
+
+ pr_debug("%s\n", __func__);
+
+ if (sscanf(buf, "%d", &power_onoff) != 1)
+ return -EINVAL;
+
+ if (power_onoff == 0)
+ baseband_xmm_power_off(device);
+ else if (power_onoff == 1)
+ baseband_xmm_power_on(device);
+ return count;
+}
+
+static DEVICE_ATTR(xmm_onoff, S_IRUSR | S_IWUSR | S_IRGRP,
+ NULL, baseband_xmm_onoff);
+
void baseband_xmm_set_power_status(unsigned int status)
{
switch (status) {
case BBXMM_PS_L0:
wake_lock(&wakelock);
- break;
+ break;
case BBXMM_PS_L2:
wake_unlock(&wakelock);
- break;
+ break;
case BBXMM_PS_L2TOL0:
/* do this only from L2 state */
if (baseband_xmm_powerstate == BBXMM_PS_L2)
queue_work(workqueue, &init3_work);
default:
- break;
+ break;
}
baseband_xmm_powerstate = status;
pr_debug("BB XMM POWER STATE = %d\n", status);
@@ -228,7 +273,8 @@ void baseband_xmm_set_power_status(unsigned int status)
EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status);
#if BB_INITIATED_L2_SUSPEND
-static irqreturn_t ipc_hsic_sus_req_irq(int irq, void *dev_id)
+static irqreturn_t baseband_xmm_power_ipc_hsic_sus_req_irq
+ (int irq, void *dev_id)
{
int value;
@@ -250,10 +296,9 @@ static irqreturn_t ipc_hsic_sus_req_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-
#endif
-static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
+irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
{
int value;
@@ -265,24 +310,28 @@ static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
value = gpio_get_value(baseband_power_driver_data->
modem.xmm.ipc_ap_wake);
if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT1 - got falling edge\n",
+ pr_debug("%s - IPC_AP_WAKE_INIT1"
+ " - got falling edge\n",
__func__);
/* go to IPC_AP_WAKE_INIT1 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
/* queue work */
queue_work(workqueue, &init1_work);
} else {
- pr_debug("%s - IPC_AP_WAKE_INIT1 - wait for falling edge\n",
+ pr_debug("%s - IPC_AP_WAKE_INIT1"
+ " - wait for falling edge\n",
__func__);
}
} else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
value = gpio_get_value(baseband_power_driver_data->
modem.xmm.ipc_ap_wake);
if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT2 - wait for rising edge\n",
+ pr_debug("%s - IPC_AP_WAKE_INIT2"
+ " - wait for rising edge\n",
__func__);
} else {
- pr_debug("%s - IPC_AP_WAKE_INIT2 - got rising edge\n",
+ pr_debug("%s - IPC_AP_WAKE_INIT2"
+ " - got rising edge\n",
__func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
@@ -294,21 +343,32 @@ static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
modem.xmm.ipc_ap_wake);
if (!value) {
pr_debug("%s - falling\n", __func__);
- pr_debug("gpio host wakeup done <-\n");
- /* Set the slave wakeup request */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_bb_wake, 0);
- pr_debug("gpio slave wakeup done ->\n");
+ /* save gpio state */
ipc_ap_wake_state = IPC_AP_WAKE_L;
- baseband_xmm_set_power_status(BBXMM_PS_L0);
} else {
pr_debug("%s - rising\n", __func__);
+ /* [ver >= 1130] gpio protocol rising edge */
+ if (modem_ver >= XMM_MODEM_VER_1130) {
+ pr_debug("gpio host wakeup done <-\n");
+ value = gpio_get_value
+ (baseband_power_driver_data->
+ modem.xmm.ipc_bb_wake);
+ if (value) {
+ /* Clear the slave wakeup request */
+ gpio_set_value
+ (baseband_power_driver_data->
+ modem.xmm.ipc_bb_wake, 0);
+ pr_debug("gpio slave wakeup done ->\n");
+ }
+ }
+ /* save gpio state */
ipc_ap_wake_state = IPC_AP_WAKE_H;
}
}
return IRQ_HANDLED;
}
+EXPORT_SYMBOL(baseband_xmm_power_ipc_ap_wake_irq);
static void baseband_xmm_power_init1_work(struct work_struct *work)
{
@@ -368,49 +428,162 @@ static void baseband_xmm_power_init3_work(struct work_struct *work)
modem.xmm.ipc_bb_wake, 1);
}
+static void baseband_xmm_power_reset_on(void)
+{
+ /* reset / power on sequence */
+ mdelay(40);
+ gpio_set_value(baseband_power_driver_data->modem.xmm.bb_rst, 1);
+ mdelay(1);
+ gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 1);
+ udelay(40);
+ gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 0);
+}
+
+static struct baseband_xmm_power_work_t *baseband_xmm_power_work;
+
+static void baseband_xmm_power_work_func(struct work_struct *work)
+{
+ struct baseband_xmm_power_work_t *bbxmm_work
+ = (struct baseband_xmm_power_work_t *) work;
+
+ pr_debug("%s\n", __func__);
+
+ switch (bbxmm_work->state) {
+ case BBXMM_WORK_UNINIT:
+ pr_debug("BBXMM_WORK_UNINIT\n");
+ break;
+ case BBXMM_WORK_INIT:
+ pr_debug("BBXMM_WORK_INIT\n");
+ /* go to next state */
+ bbxmm_work->state = (modem_flash && !modem_pm)
+ ? BBXMM_WORK_INIT_FLASH_STEP1
+ : (modem_flash && modem_pm)
+ ? BBXMM_WORK_INIT_FLASH_PM_STEP1
+ : (!modem_flash && modem_pm)
+ ? BBXMM_WORK_INIT_FLASHLESS_PM_STEP1
+ : BBXMM_WORK_UNINIT;
+ queue_work(workqueue, work);
+ break;
+ case BBXMM_WORK_INIT_FLASH_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
+ /* register usb host controller */
+ platform_device_register(baseband_power_driver_data->modem
+ .xmm.hsic_device);
+ break;
+ case BBXMM_WORK_INIT_FLASH_PM_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
+ /* [modem ver >= 1130] start with IPC_HSIC_ACTIVE low */
+ if (modem_ver >= XMM_MODEM_VER_1130) {
+ pr_debug("%s: ver > 1130:"
+ " ipc_hsic_active -> 0\n", __func__);
+ gpio_set_value(baseband_power_driver_data->
+ modem.xmm.ipc_hsic_active, 0);
+ }
+ /* reset / power on sequence */
+ baseband_xmm_power_reset_on();
+ /* optional delay
+ * 0 = flashless
+ * ==> causes next step to enumerate modem boot rom
+ * (058b / 0041)
+ * some delay > boot rom timeout
+ * ==> causes next step to enumerate modem software
+ * (1519 / 0020)
+ * (requires modem to be flash version, not flashless
+ * version)
+ */
+ if (enum_delay_ms)
+ mdelay(enum_delay_ms);
+ /* register usb host controller */
+ platform_device_register(baseband_power_driver_data->modem
+ .xmm.hsic_device);
+ /* go to next state */
+ bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
+ ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1
+ : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1;
+ queue_work(workqueue, work);
+ break;
+ case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n");
+ break;
+ case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n");
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
+ /* go to next state */
+ bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
+ ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ
+ : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
+ queue_work(workqueue, work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
+ break;
+ default:
+ break;
+ }
+
+}
+
static int baseband_xmm_power_driver_probe(struct platform_device *device)
{
- struct device *dev = &device->dev;
struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+ struct device *dev = &device->dev;
int err;
pr_debug("%s\n", __func__);
- register_hsic_device = true;
- baseband_xmm_powerstate = BBXMM_PS_UNINIT;
+ /* check for platform data */
+ if (!data)
+ return -ENODEV;
+
/* check if supported modem */
if (data->baseband_type != BASEBAND_XMM) {
pr_err("unsuppported modem\n");
return -ENODEV;
}
+ /* save platform data */
+ baseband_power_driver_data = data;
+
+ /* create device file */
err = device_create_file(dev, &dev_attr_xmm_onoff);
if (err < 0) {
pr_err("%s - device_create_file failed\n", __func__);
return -ENODEV;
}
- /* save platform data */
- baseband_power_driver_data = data;
+ /* init wake lock */
+ wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "baseband_xmm_power");
/* request baseband gpio(s) */
- tegra_baseband_gpios[0].gpio = data->modem.xmm.bb_rst;
- tegra_baseband_gpios[1].gpio = data->modem.xmm.bb_on;
- tegra_baseband_gpios[2].gpio = data->modem.xmm.ipc_bb_wake;
- tegra_baseband_gpios[3].gpio = data->modem.xmm.ipc_ap_wake;
- tegra_baseband_gpios[4].gpio = data->modem.xmm.ipc_hsic_active;
- tegra_baseband_gpios[5].gpio = data->modem.xmm.ipc_hsic_sus_req;
+ tegra_baseband_gpios[0].gpio = baseband_power_driver_data
+ ->modem.xmm.bb_rst;
+ tegra_baseband_gpios[1].gpio = baseband_power_driver_data
+ ->modem.xmm.bb_on;
+ tegra_baseband_gpios[2].gpio = baseband_power_driver_data
+ ->modem.xmm.ipc_bb_wake;
+ tegra_baseband_gpios[3].gpio = baseband_power_driver_data
+ ->modem.xmm.ipc_ap_wake;
+ tegra_baseband_gpios[4].gpio = baseband_power_driver_data
+ ->modem.xmm.ipc_hsic_active;
+ tegra_baseband_gpios[5].gpio = baseband_power_driver_data
+ ->modem.xmm.ipc_hsic_sus_req;
err = gpio_request_array(tegra_baseband_gpios,
ARRAY_SIZE(tegra_baseband_gpios));
if (err < 0) {
pr_err("%s - request gpio(s) failed\n", __func__);
- return err;
+ return -ENODEV;
}
/* request baseband irq(s) */
#if BB_INITIATED_L2_SUSPEND
- if (enum_delay_ms) {
+ if (modem_pm) {
ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_UNINIT;
err = request_irq(gpio_to_irq(data->modem.xmm.ipc_hsic_sus_req),
ipc_hsic_sus_req_irq,
@@ -425,10 +598,11 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_IRQ_READY;
}
#endif
- if (enum_delay_ms) {
+ if (modem_flash && modem_pm) {
+ pr_info("%s: request_irq IPC_AP_WAKE_IRQ\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake),
- ipc_ap_wake_irq,
+ baseband_xmm_power_ipc_ap_wake_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"IPC_AP_WAKE_IRQ",
NULL);
@@ -438,6 +612,11 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
return err;
}
ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+ if (modem_ver >= XMM_MODEM_VER_1130) {
+ pr_debug("%s: ver > 1130: AP_WAKE_INIT1\n", __func__);
+ /* ver 1130 or later starts in INIT1 state */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
+ }
}
/* init work queue */
@@ -447,52 +626,56 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
pr_err("cannot create workqueue\n");
return -1;
}
+ baseband_xmm_power_work = (struct baseband_xmm_power_work_t *)
+ kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
+ if (!baseband_xmm_power_work) {
+ pr_err("cannot allocate baseband_xmm_power_work\n");
+ return -1;
+ }
+ INIT_WORK((struct work_struct *) baseband_xmm_power_work,
+ baseband_xmm_power_work_func);
+ baseband_xmm_power_work->state = BBXMM_WORK_INIT;
+ queue_work(workqueue,
+ (struct work_struct *) baseband_xmm_power_work);
- wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "baseband_xmm_power");
-
- baseband_xmm_powerstate = BBXMM_PS_INIT;
+ /* init work objects */
INIT_WORK(&init1_work, baseband_xmm_power_init1_work);
INIT_WORK(&init2_work, baseband_xmm_power_init2_work);
INIT_WORK(&init3_work, baseband_xmm_power_init3_work);
- /* reset / power on sequence */
- mdelay(40);
- gpio_set_value(data->modem.xmm.bb_rst, 1);
- mdelay(1);
- gpio_set_value(data->modem.xmm.bb_on, 1);
- udelay(40);
- gpio_set_value(data->modem.xmm.bb_on, 0);
-
- /* optional delay
- * 0 = flashless
- * ==> causes next step to enumerate modem boot rom (058b / 0041)
- * some delay > boot rom timeout
- * ==> causes next step to enumerate modem software (1519 / 0020)
- * (requires modem to be flash version, not flashless version)
- */
- if (enum_delay_ms)
- mdelay(enum_delay_ms);
-
- /* register usb host controller */
- if (!enum_delay_ms)
- platform_device_register(data->modem.xmm.hsic_device);
+ /* init state variables */
+ register_hsic_device = true;
+ baseband_xmm_powerstate = BBXMM_PS_UNINIT;
return 0;
}
static int baseband_xmm_power_driver_remove(struct platform_device *device)
{
- struct device *dev = &device->dev;
struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+ struct device *dev = &device->dev;
pr_debug("%s\n", __func__);
+ /* check for platform data */
+ if (!data)
+ return 0;
+
+ /* free work structure */
+ kfree(baseband_xmm_power_work);
+ baseband_xmm_power_work = (struct baseband_xmm_power_work_t *) 0;
+
/* free baseband irq(s) */
- if (enum_delay_ms) {
- free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL);
+ if (modem_flash && modem_pm) {
+ free_irq(gpio_to_irq(baseband_power_driver_data
+ ->modem.xmm.ipc_ap_wake), NULL);
+ }
+ if (modem_pm) {
#if BB_INITIATED_L2_SUSPEND
- free_irq(gpio_to_irq(data->modem.xmm.ipc_hsic_sus_req), NULL);
+ free_irq(gpio_to_irq(baseband_power_driver_data
+ ->modem.xmm.ipc_hsic_sus_req), NULL);
#endif
}
@@ -500,9 +683,12 @@ static int baseband_xmm_power_driver_remove(struct platform_device *device)
gpio_free_array(tegra_baseband_gpios,
ARRAY_SIZE(tegra_baseband_gpios));
- device_remove_file(dev, &dev_attr_xmm_onoff);
+ /* destroy wake lock */
wake_lock_destroy(&wakelock);
+ /* delete device file */
+ device_remove_file(dev, &dev_attr_xmm_onoff);
+
/* unregister usb host controller */
platform_device_unregister(baseband_power_driver_data->
modem.xmm.hsic_device);
@@ -513,54 +699,44 @@ static int baseband_xmm_power_driver_remove(struct platform_device *device)
static int baseband_xmm_power_driver_suspend(struct platform_device *device,
pm_message_t state)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
-
pr_debug("%s\n", __func__);
-
- /* Indiate host active low to CP*/
- gpio_set_value(data->modem.xmm.ipc_hsic_active, 0);
- pr_debug("gpio host active low->\n");
-
- baseband_xmm_set_power_status(BBXMM_PS_L3);
-
return 0;
}
static int baseband_xmm_power_driver_resume(struct platform_device *device)
{
struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
int value;
int delay = 10000; /* maxmum delay in msec */
pr_debug("%s\n", __func__);
+ /* check for platform data */
+ if (!baseband_power_driver_data)
+ return 0;
+
+ baseband_xmm_set_power_status(BBXMM_PS_L3TOL0);
+
value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
- if (!value) {
- pr_info("AP Initiated L3 -> L0\n");
+ if (value) {
+ pr_info("AP L3 -> L0\n");
/* wake bb */
gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
- pr_debug("waiting for host wakeup\n");
+ pr_debug("waiting for host wakeup...\n");
do {
mdelay(1);
value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
delay--;
- } while ((!value) && (delay));
+ } while ((value) && (delay));
if (delay)
- pr_debug("gpio host wakeup high <-\n");
- else
- pr_err("%s host wakeup not happened\n", __func__);
+ pr_debug("gpio host wakeup low <-\n");
} else {
- pr_info("CP Initiated L3 -> L0\n");
+ pr_info("CP L3 -> L0\n");
}
- /* signal bb to resume hsic */
- gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
-
- baseband_xmm_set_power_status(BBXMM_PS_L3TOL0);
-
return 0;
}