summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
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
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')
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c484
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.h50
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power2.c540
3 files changed, 822 insertions, 252 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;
}
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h
index 8025c9a956ce..53e71bf7b32a 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.h
+++ b/arch/arm/mach-tegra/baseband-xmm-power.h
@@ -14,9 +14,24 @@
*
*/
+#ifndef BASEBAND_XMM_POWER_H
+#define BASREBAND_XMM_POWER_H
+
#include <linux/pm.h>
#include <linux/suspend.h>
+#define TEGRA_EHCI_DEVICE "/sys/devices/platform/tegra-ehci.1/ehci_power"
+
+#define XMM_MODEM_VER_1121 0x1121
+#define XMM_MODEM_VER_1130 0x1130
+
+/* shared between baseband-xmm-* modules so they can agree on same
+ * modem configuration
+ */
+extern unsigned long modem_ver;
+extern unsigned long modem_flash;
+extern unsigned long modem_pm;
+
enum baseband_type {
BASEBAND_XMM,
};
@@ -45,7 +60,34 @@ struct baseband_power_platform_data {
} modem;
};
-static enum {
+enum baseband_xmm_power_work_state_t {
+ BBXMM_WORK_UNINIT,
+ BBXMM_WORK_INIT,
+ /* initialize flash modem */
+ BBXMM_WORK_INIT_FLASH_STEP1,
+ /* initialize flash (with power management support) modem */
+ BBXMM_WORK_INIT_FLASH_PM_STEP1,
+ BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1,
+ BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1,
+ /* initialize flashless (with power management support) modem */
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP1,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3,
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4,
+};
+
+struct baseband_xmm_power_work_t {
+ /* work structure must be first structure member */
+ struct work_struct work;
+ /* xmm modem state */
+ enum baseband_xmm_power_work_state_t state;
+};
+
+enum baseband_xmm_powerstate_t {
BBXMM_PS_UNINIT = 0,
BBXMM_PS_INIT = 1,
BBXMM_PS_L0 = 2,
@@ -56,6 +98,10 @@ static enum {
BBXMM_PS_L3 = 7,
BBXMM_PS_L3TOL0 = 8,
BBXMM_PS_LAST = -1,
-} baseband_xmm_powerstate;
+};
+
+irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
void baseband_xmm_set_power_status(unsigned int status);
+
+#endif /* BASREBAND_XMM_POWER_H */
diff --git a/arch/arm/mach-tegra/baseband-xmm-power2.c b/arch/arm/mach-tegra/baseband-xmm-power2.c
index 9601ed49e6a1..acb2ac344266 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power2.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power2.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,24 @@
MODULE_LICENSE("GPL");
-static struct baseband_power_platform_data *baseband_power2_driver_data;
+static unsigned long XYZ = 500 * 1000000 + 30 * 1000 + 50;
+
+module_param(modem_ver, ulong, 0644);
+MODULE_PARM_DESC(modem_ver,
+ "baseband xmm power2 - modem software version");
+module_param(modem_flash, ulong, 0644);
+MODULE_PARM_DESC(modem_flash,
+ "baseband xmm power2 - modem flash (1 = flash, 0 = flashless)");
+module_param(modem_pm, ulong, 0644);
+MODULE_PARM_DESC(modem_pm,
+ "baseband xmm power2 - modem power management (1 = pm, 0 = no pm)");
+module_param(XYZ, ulong, 0644);
+MODULE_PARM_DESC(XYZ,
+ "baseband xmm power2 - timing parameters X/Y/Z delay in ms");
-static enum {
- IPC_HSIC_SUS_REQ_UNINIT,
- IPC_HSIC_SUS_REQ_IRQ_READY,
- IPC_HSIC_SUS_REQ_INIT,
- IPC_HSIC_SUS_REQ_L,
- IPC_HSIC_SUS_REQ_H,
-} ipc_hsic_sus_req_state;
+static struct baseband_power_platform_data *baseband_power2_driver_data;
+static struct workqueue_struct *workqueue;
+static struct baseband_xmm_power_work_t *baseband_xmm_power2_work;
static enum {
IPC_AP_WAKE_UNINIT,
@@ -51,11 +61,8 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
-static struct workqueue_struct *workqueue;
-static struct work_struct init1_work;
-static struct work_struct init2_work;
-
-static irqreturn_t ipc_hsic_sus_req_irq(int irq, void *dev_id)
+static irqreturn_t baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
+ (int irq, void *dev_id)
{
int value;
@@ -65,25 +72,65 @@ static irqreturn_t ipc_hsic_sus_req_irq(int irq, void *dev_id)
if (!baseband_power2_driver_data)
return IRQ_HANDLED;
- /* IPC_HSIC_SUS_REQ state machine */
- if (ipc_hsic_sus_req_state < IPC_HSIC_SUS_REQ_IRQ_READY) {
+ /* IPC_AP_WAKE state machine */
+ if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
pr_err("%s - spurious irq\n", __func__);
+ } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
+ value = gpio_get_value(baseband_power2_driver_data->
+ modem.xmm.ipc_ap_wake);
+ if (!value) {
+ 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 */
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+ } else {
+ 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_power2_driver_data->
+ modem.xmm.ipc_ap_wake);
+ if (!value) {
+ 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",
+ __func__);
+ /* go to IPC_AP_WAKE_INIT2 state */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
+ /* queue work */
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+ }
} else {
value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_sus_req);
+ modem.xmm.ipc_ap_wake);
if (!value) {
pr_debug("%s - falling\n", __func__);
- ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_L;
+ ipc_ap_wake_state = IPC_AP_WAKE_L;
} else {
pr_debug("%s - rising\n", __func__);
- ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_H;
+ ipc_ap_wake_state = IPC_AP_WAKE_H;
}
+ return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
}
return IRQ_HANDLED;
}
-static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
+static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2
+ (int irq, void *dev_id)
{
int value;
@@ -100,29 +147,20 @@ static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
value = gpio_get_value(baseband_power2_driver_data->
modem.xmm.ipc_ap_wake);
if (!value) {
- 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",
- __func__);
- }
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake);
- if (!value) {
- 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_INIT1"
+ " - got falling edge\n",
__func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
/* queue work */
- queue_work(workqueue, &init2_work);
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+ } else {
+ pr_debug("%s - IPC_AP_WAKE_INIT1"
+ " - wait for falling edge\n",
+ __func__);
}
} else {
value = gpio_get_value(baseband_power2_driver_data->
@@ -134,12 +172,14 @@ static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
pr_debug("%s - rising\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_H;
}
+ return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
}
return IRQ_HANDLED;
}
-static void baseband_xmm_power2_init1_work(struct work_struct *work)
+static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step1
+ (struct work_struct *work)
{
int value;
@@ -167,7 +207,8 @@ static void baseband_xmm_power2_init1_work(struct work_struct *work)
pr_debug("%s }\n", __func__);
}
-static void baseband_xmm_power2_init2_work(struct work_struct *work)
+static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step2
+ (struct work_struct *work)
{
int value;
@@ -194,8 +235,8 @@ static void baseband_xmm_power2_init2_work(struct work_struct *work)
struct file *filp;
oldfs = get_fs();
set_fs(KERNEL_DS);
- filp = filp_open("/sys/devices/platform/tegra-ehci.1/ehci_power", O_RDWR, 0);
- if (!filp) {
+ 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);
@@ -225,69 +266,381 @@ static void baseband_xmm_power2_init2_work(struct work_struct *work)
pr_debug("%s }\n", __func__);
}
+static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step1
+ (struct work_struct *work)
+{
+ int X = XYZ / 1000000;
+ int Y = XYZ / 1000 - X * 1000;
+ int Z = XYZ % 1000;
+
+ pr_info("%s {\n", __func__);
+
+ pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
+
+ /* check for platform data */
+ if (!baseband_power2_driver_data)
+ return;
+
+ /* turn off 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 (IS_ERR(filp) || (filp == NULL)) {
+ pr_err("open ehci_power failed\n");
+ } else {
+ filp->f_op->write(filp, "0", 1, &filp->f_pos);
+ filp_close(filp, NULL);
+ }
+ set_fs(oldfs);
+ }
+
+ /* wait X ms */
+ mdelay(X);
+
+ /* set IPC_HSIC_ACTIVE low */
+ gpio_set_value(baseband_power2_driver_data->
+ modem.xmm.ipc_hsic_active, 0);
+
+ pr_info("%s }\n", __func__);
+}
+
+static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step2
+ (struct work_struct *work)
+{
+ int X = XYZ / 1000000;
+ int Y = XYZ / 1000 - X * 1000;
+ int Z = XYZ % 1000;
+
+ pr_info("%s {\n", __func__);
+
+ pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
+
+ /* check for platform data */
+ if (!baseband_power2_driver_data)
+ return;
+
+ /* wait Y ms */
+ mdelay(Y);
+
+ /* 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 (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);
+ }
+
+ /* wait Z ms */
+ mdelay(Z);
+
+ /* set IPC_HSIC_ACTIVE high */
+ gpio_set_value(baseband_power2_driver_data->
+ modem.xmm.ipc_hsic_active, 1);
+
+ /* queue work function to check if enumeration succeeded */
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+
+ pr_info("%s }\n", __func__);
+}
+
+static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step3
+ (struct work_struct *work)
+{
+ int X = XYZ / 1000000;
+ int Y = XYZ / 1000 - X * 1000;
+ int Z = XYZ % 1000;
+ int enum_success = 0;
+
+ pr_info("%s {\n", __func__);
+
+ pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
+
+ /* check for platform data */
+ if (!baseband_power2_driver_data)
+ return;
+
+ /* wait 500 ms */
+ mdelay(500);
+
+ /* check if enumeration succeeded */
+ {
+ mm_segment_t oldfs;
+ struct file *filp;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/sys/bus/usb/devices/usb2/2-1/manufacturer",
+ O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL)) {
+ pr_err("open /sys/bus/usb/devices"
+ "/usb2/2-1/manufacturer failed %ld\n",
+ PTR_ERR(filp));
+ } else {
+ filp_close(filp, NULL);
+ enum_success = 1;
+ }
+ set_fs(oldfs);
+ }
+
+ /* if enumeration failed, attempt recovery pulse */
+ if (!enum_success) {
+ pr_info("attempting recovery pulse...\n");
+ /* wait 20 ms */
+ mdelay(20);
+ /* set IPC_HSIC_ACTIVE low */
+ gpio_set_value(baseband_power2_driver_data->
+ modem.xmm.ipc_hsic_active, 0);
+ /* wait 20 ms */
+ mdelay(20);
+ /* set IPC_HSIC_ACTIVE high */
+ gpio_set_value(baseband_power2_driver_data->
+ modem.xmm.ipc_hsic_active, 1);
+ /* check if recovery pulse worked */
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+ }
+
+ pr_info("%s }\n", __func__);
+}
+
+static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4
+ (struct work_struct *work)
+{
+ int X = XYZ / 1000000;
+ int Y = XYZ / 1000 - X * 1000;
+ int Z = XYZ % 1000;
+ int enum_success = 0;
+
+ pr_info("%s {\n", __func__);
+
+ pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
+
+ /* check for platform data */
+ if (!baseband_power2_driver_data)
+ return;
+
+ /* wait 500 ms */
+ mdelay(500);
+
+ /* check if enumeration succeeded */
+ {
+ mm_segment_t oldfs;
+ struct file *filp;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/sys/bus/usb/devices/usb2/2-1/manufacturer",
+ O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL)) {
+ pr_err("open /sys/bus/usb/devices"
+ "/usb2/2-1/manufacturer failed %ld\n",
+ PTR_ERR(filp));
+ } else {
+ filp_close(filp, NULL);
+ enum_success = 1;
+ }
+ set_fs(oldfs);
+ }
+
+ /* if recovery pulse did not fix enumeration, retry from beginning */
+ if (!enum_success) {
+ static int retry = 3;
+ if (!retry) {
+ pr_info("failed to enumerate modem software"
+ " - too many retry attempts\n");
+ } else {
+ pr_info("recovery pulse failed to fix modem"
+ " enumeration..."
+ " restarting from beginning"
+ " - attempt #%d\n",
+ retry);
+ --retry;
+ ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+ baseband_xmm_power2_work->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
+ queue_work(workqueue, (struct work_struct *)
+ baseband_xmm_power2_work);
+ }
+ }
+
+ pr_info("%s }\n", __func__);
+}
+
+static int free_ipc_ap_wake_irq;
+
+static void baseband_xmm_power2_work_func(struct work_struct *work)
+{
+ struct baseband_xmm_power_work_t *bbxmm_work
+ = (struct baseband_xmm_power_work_t *) work;
+ int err;
+
+ pr_debug("%s\n", __func__);
+
+ switch (bbxmm_work->state) {
+ case BBXMM_WORK_UNINIT:
+ pr_debug("BBXMM_WORK_UNINIT\n");
+ /* free baseband irq(s) */
+ if (free_ipc_ap_wake_irq) {
+ free_irq(gpio_to_irq(baseband_power2_driver_data
+ ->modem.xmm.ipc_ap_wake), NULL);
+ free_ipc_ap_wake_irq = 0;
+ }
+ break;
+ case BBXMM_WORK_INIT:
+ pr_debug("BBXMM_WORK_INIT\n");
+ /* request baseband irq(s) */
+ ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
+ err = request_irq(gpio_to_irq(baseband_power2_driver_data
+ ->modem.xmm.ipc_ap_wake),
+ (modem_ver < XMM_MODEM_VER_1130)
+ ? baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
+ : baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "BBXMM_POWER2_IPC_AP_WAKE_IRQ",
+ NULL);
+ if (err < 0) {
+ pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
+ __func__);
+ return;
+ }
+ free_ipc_ap_wake_irq = 1;
+ ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+ /* 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");
+ break;
+ case BBXMM_WORK_INIT_FLASH_PM_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
+ /* 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_WAIT_IRQ:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ"
+ " - waiting for IPC_AP_WAKE_IRQ to trigger step1\n");
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
+ baseband_xmm_power2_flashless_pm_ver_lt_1130_step1(work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2\n");
+ baseband_xmm_power2_flashless_pm_ver_lt_1130_step2(work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
+ baseband_xmm_power2_flashless_pm_ver_ge_1130_step1(work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2\n");
+ baseband_xmm_power2_flashless_pm_ver_ge_1130_step2(work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3\n");
+ baseband_xmm_power2_flashless_pm_ver_ge_1130_step3(work);
+ break;
+ case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4\n");
+ baseband_xmm_power2_flashless_pm_ver_ge_1130_step4(work);
+ break;
+ }
+
+}
+
static int baseband_xmm_power2_driver_probe(struct platform_device *device)
{
struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *) device->dev.platform_data;
- int err;
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
pr_debug("%s\n", __func__);
/* save platform data */
baseband_power2_driver_data = data;
- /* request baseband irq(s) */
- 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,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "IPC_HSIC_SUS_REQ_IRQ",
- NULL);
- if (err < 0) {
- pr_err("%s - request irq IPC_HSIC_SUS_REQ_IRQ failed\n",
- __func__);
- return err;
- }
- ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_IRQ_READY;
- ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
- err = request_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake),
- ipc_ap_wake_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "IPC_AP_WAKE_IRQ",
- NULL);
- if (err < 0) {
- pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
- __func__);
- return err;
- }
- ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
-
/* init work queue */
workqueue = create_singlethread_workqueue
- ("baseband_power_workqueue");
+ ("baseband_xmm_power2_workqueue");
if (!workqueue) {
pr_err("cannot create workqueue\n");
return -1;
}
- INIT_WORK(&init1_work, baseband_xmm_power2_init1_work);
- INIT_WORK(&init2_work, baseband_xmm_power2_init2_work);
+ baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *)
+ kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
+ if (!baseband_xmm_power2_work) {
+ pr_err("cannot allocate baseband_xmm_power2_work\n");
+ return -1;
+ }
+ INIT_WORK((struct work_struct *) baseband_xmm_power2_work,
+ baseband_xmm_power2_work_func);
+ baseband_xmm_power2_work->state = BBXMM_WORK_INIT;
+ queue_work(workqueue,
+ (struct work_struct *) baseband_xmm_power2_work);
return 0;
}
static int baseband_xmm_power2_driver_remove(struct platform_device *device)
{
+ struct baseband_power_platform_data *data
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+
pr_debug("%s\n", __func__);
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data)
return 0;
- /* free baseband irq(s) */
- free_irq(gpio_to_irq(baseband_power2_driver_data
- ->modem.xmm.ipc_ap_wake), NULL);
- free_irq(gpio_to_irq(baseband_power2_driver_data
- ->modem.xmm.ipc_hsic_sus_req), NULL);
+ /* free irq */
+ if (free_ipc_ap_wake_irq) {
+ free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL);
+ free_ipc_ap_wake_irq = 0;
+ }
+
+ /* free work structure */
+ destroy_workqueue(workqueue);
+ kfree(baseband_xmm_power2_work);
+ baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *) 0;
return 0;
}
@@ -296,35 +649,31 @@ static int baseband_xmm_power2_driver_remove(struct platform_device *device)
static int baseband_xmm_power2_driver_suspend(struct platform_device *device,
pm_message_t state)
{
- pr_debug("%s\n", __func__);
+ struct baseband_power_platform_data *data
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+
+ pr_debug("%s - nop\n", __func__);
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data)
return 0;
- /* signal bb to suspend hsic */
- gpio_set_value(baseband_power2_driver_data
- ->modem.xmm.ipc_hsic_active, 0);
-
return 0;
}
static int baseband_xmm_power2_driver_resume(struct platform_device *device)
{
- pr_debug("%s\n", __func__);
+ struct baseband_power_platform_data *data
+ = (struct baseband_power_platform_data *)
+ device->dev.platform_data;
+
+ pr_debug("%s - nop\n", __func__);
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data)
return 0;
- /* wake bb */
- gpio_set_value(baseband_power2_driver_data
- ->modem.xmm.ipc_bb_wake, 1);
-
- /* signal bb to resume hsic */
- gpio_set_value(baseband_power2_driver_data
- ->modem.xmm.ipc_hsic_active, 1);
-
return 0;
}
#endif
@@ -355,4 +704,3 @@ static void __exit baseband_xmm_power2_exit(void)
module_init(baseband_xmm_power2_init)
module_exit(baseband_xmm_power2_exit)
-