summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorRaj Jayaraman <rjayaraman@nvidia.com>2012-01-30 14:34:37 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-02-03 05:56:17 -0800
commitda0048ebc17e2a45ef752588db33049d4aa4580a (patch)
treeb48a459a595bb0cefa04d7ac02ccb7d94467f054 /drivers/misc
parentde067308cce5e1adacc29e5d2fa4459a7f380fb2 (diff)
misc: tegra-baseband: Add usb core notification support.
Add support for notification from USB core about device atachment and removal. Add ARR support for M7400 modem. Bug 886459 Reviewed-on: http://git-master/r/78301 Change-Id: I583714498e17501cbfb620440a24b43094bc9573 Signed-off-by: Raj Jayaraman <rjayaraman@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/78900 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/tegra-baseband/bb-m7400.c56
-rw-r--r--drivers/misc/tegra-baseband/bb-power.c76
-rw-r--r--drivers/misc/tegra-baseband/bb-power.h25
3 files changed, 137 insertions, 20 deletions
diff --git a/drivers/misc/tegra-baseband/bb-m7400.c b/drivers/misc/tegra-baseband/bb-m7400.c
index 4c87245eede4..4209151e5f39 100644
--- a/drivers/misc/tegra-baseband/bb-m7400.c
+++ b/drivers/misc/tegra-baseband/bb-m7400.c
@@ -41,11 +41,14 @@ static struct tegra_bb_gpio_data m7400_gpios[] = {
{ { 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, GPIOF_OUT_INIT_LOW, "MDM_USB_ARR" }, false },
{ { GPIO_INVALID, 0, NULL }, false }, /* End of table */
};
static bool ehci_registered;
static int gpio_awr;
static int gpio_cwr;
+static int gpio_arr;
+static struct usb_device *m7400_usb_device;
static int gpio_wait_timeout(int gpio, int value, int timeout_msec)
{
@@ -62,15 +65,16 @@ static int m7400_enum_handshake(void)
{
int retval = 0;
- /* Wait for CP to indicate ready - by driving USB_CWR high. */
+ /* Wait for CP to indicate ready - by driving CWR high. */
if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
pr_info("%s: Error: timeout waiting for modem resume.\n",
__func__);
retval = -1;
}
- /* Signal AP ready - Drive USB_AWR high. */
+ /* Signal AP ready - Drive AWR and ARR high. */
gpio_set_value(gpio_awr, 1);
+ gpio_set_value(gpio_arr, 1);
return retval;
}
@@ -79,11 +83,11 @@ static int m7400_apup_handshake(bool checkresponse)
{
int retval = 0;
- /* Signal AP ready - Drive USB_AWR high. */
+ /* Signal AP ready - Drive AWR high. */
gpio_set_value(gpio_awr, 1);
if (checkresponse) {
- /* Wait for CP ack - by driving USB_CWR high. */
+ /* Wait for CP ack - by driving CWR high. */
if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
pr_info("%s: Error: timeout waiting for modem ack.\n",
__func__);
@@ -95,18 +99,29 @@ static int m7400_apup_handshake(bool checkresponse)
static void m7400_apdown_handshake(void)
{
- /* Signal AP going down to modem - Drive USB_AWR low. */
+ /* Signal AP going down to modem - Drive AWR low. */
/* No need to wait for a CP response */
gpio_set_value(gpio_awr, 0);
}
static int m7400_l2_suspend(void)
{
+ /* Post bus suspend: Drive ARR low. */
+ gpio_set_value(gpio_arr, 0);
return 0;
}
static int m7400_l2_resume(void)
{
+ /* Pre bus resume: Drive ARR high. */
+ gpio_set_value(gpio_arr, 1);
+
+ /* Wait for CP ack - by driving CWR high. */
+ if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
+ pr_info("%s: Error: timeout waiting for modem ack.\n",
+ __func__);
+ return -1;
+ }
return 0;
}
@@ -208,9 +223,16 @@ static int m7400_attrib_write(struct device *dev, int value)
return 0;
}
+static int m7400_registered(struct usb_device *udev)
+{
+ pr_info("%s called.\n", __func__);
+ m7400_usb_device = udev;
+ return 0;
+}
+
static struct tegra_bb_gpio_irqdata m7400_gpioirqs[] = {
{ GPIO_INVALID, "tegra_bb_wake", m7400_wake_irq,
- IRQF_TRIGGER_FALLING, NULL },
+ IRQF_TRIGGER_RISING, true, NULL },
{ GPIO_INVALID, NULL, NULL, 0, NULL }, /* End of table */
};
@@ -219,6 +241,19 @@ static struct tegra_bb_power_gdata m7400_gdata = {
.gpioirq = m7400_gpioirqs,
};
+static struct tegra_bb_power_mdata m7400_mdata = {
+ .vid = 0x04cc,
+ .pid = 0x230f,
+ .wake_capable = true,
+ .autosuspend_ready = true,
+ .reg_cb = m7400_registered,
+};
+
+static struct tegra_bb_power_data m7400_data = {
+ .gpio_data = &m7400_gdata,
+ .modem_data = &m7400_mdata,
+};
+
static void *m7400_init(void *pdata)
{
struct tegra_bb_pdata *platdata = (struct tegra_bb_pdata *) pdata;
@@ -231,6 +266,7 @@ static void *m7400_init(void *pdata)
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_gpios[6].data.gpio = id->m7400.uart_awr;
m7400_gpioirqs[0].id = id->m7400.usb_cwr;
if (!platdata->ehci_register || !platdata->ehci_unregister) {
@@ -241,18 +277,20 @@ static void *m7400_init(void *pdata)
gpio_awr = m7400_gpios[3].data.gpio;
gpio_cwr = m7400_gpios[4].data.gpio;
- if (gpio_awr == GPIO_INVALID || gpio_cwr == GPIO_INVALID) {
+ gpio_arr = m7400_gpios[6].data.gpio;
+ if (gpio_awr == GPIO_INVALID || gpio_cwr == GPIO_INVALID
+ || gpio_arr == GPIO_INVALID) {
pr_info("%s - Error: Invalid gpio data.\n", __func__);
return 0;
}
ehci_registered = false;
- return (void *) &m7400_gdata;
+ return (void *) &m7400_data;
}
static void *m7400_deinit(void)
{
- return (void *) &m7400_gdata;
+ return (void *) &m7400_data;
}
static struct tegra_bb_callback m7400_callbacks = {
diff --git a/drivers/misc/tegra-baseband/bb-power.c b/drivers/misc/tegra-baseband/bb-power.c
index 225d7667f86f..9210a8f3e84a 100644
--- a/drivers/misc/tegra-baseband/bb-power.c
+++ b/drivers/misc/tegra-baseband/bb-power.c
@@ -24,6 +24,7 @@
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/usb.h>
#include <linux/uaccess.h>
#include <linux/platform_data/tegra_usb.h>
#include <mach/usb_phy.h>
@@ -32,6 +33,7 @@
static struct tegra_bb_callback *callback;
static int attr_load_val;
+static struct tegra_bb_power_mdata *mdata;
static bb_get_cblist get_cblist[] = {
NULL,
NULL,
@@ -90,11 +92,14 @@ static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
, __func__);
return ret;
}
- ret = enable_irq_wake(irq);
- if (ret) {
- pr_err("%s: Error: enable_irq_wake failed.\n",
+
+ if (gpioirq->wake_capable) {
+ ret = enable_irq_wake(irq);
+ if (ret) {
+ pr_err("%s: Error: irqwake req fail.\n",
__func__);
- return ret;
+ return ret;
+ }
}
}
}
@@ -147,10 +152,56 @@ static ssize_t tegra_bb_attr_read(struct device *dev,
static DEVICE_ATTR(load, S_IRUSR | S_IWUSR | S_IRGRP,
tegra_bb_attr_read, tegra_bb_attr_write);
+static void tegra_usbdevice_added(struct usb_device *udev)
+{
+ const struct usb_device_descriptor *desc = &udev->descriptor;
+
+ if (desc->idVendor == mdata->vid &&
+ desc->idProduct == mdata->pid) {
+ pr_debug("%s: Device %s added.\n", udev->product, __func__);
+
+ if (mdata->wake_capable)
+ device_set_wakeup_enable(&udev->dev, true);
+ if (mdata->autosuspend_ready)
+ usb_enable_autosuspend(udev);
+ if (mdata->reg_cb)
+ mdata->reg_cb(udev);
+ }
+}
+
+static void tegra_usbdevice_removed(struct usb_device *udev)
+{
+ const struct usb_device_descriptor *desc = &udev->descriptor;
+
+ if (desc->idVendor == mdata->vid &&
+ desc->idProduct == mdata->pid) {
+ pr_debug("%s: Device %s removed.\n", udev->product, __func__);
+ }
+}
+
+static int tegra_usb_notify(struct notifier_block *self, unsigned long action,
+ void *dev)
+{
+ switch (action) {
+ case USB_DEVICE_ADD:
+ tegra_usbdevice_added((struct usb_device *)dev);
+ break;
+ case USB_DEVICE_REMOVE:
+ tegra_usbdevice_removed((struct usb_device *)dev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block tegra_usb_nb = {
+ .notifier_call = tegra_usb_notify,
+};
+
static int tegra_bb_power_probe(struct platform_device *device)
{
struct device *dev = &device->dev;
struct tegra_bb_pdata *pdata;
+ struct tegra_bb_power_data *data;
struct tegra_bb_power_gdata *gdata;
int err;
unsigned int bb_id;
@@ -166,9 +217,10 @@ static int tegra_bb_power_probe(struct platform_device *device)
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 *)
+ data = (struct tegra_bb_power_data *)
callback->init((void *)pdata);
+ gdata = data->gpio_data;
if (!gdata) {
pr_err("%s - Error: Gpio data is empty.\n",
__func__);
@@ -177,6 +229,11 @@ static int tegra_bb_power_probe(struct platform_device *device)
/* Initialize gpio as required */
tegra_bb_power_gpio_init(gdata);
+
+ mdata = data->modem_data;
+ if (mdata && mdata->vid && mdata->pid)
+ /* Register to notifications from usb core */
+ usb_register_notify(&tegra_usb_nb);
} else {
pr_err("%s - Error: init callback is empty.\n",
__func__);
@@ -201,20 +258,27 @@ 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_power_data *data;
struct tegra_bb_power_gdata *gdata;
/* BB specific callback */
if (callback && callback->deinit) {
- gdata = (struct tegra_bb_power_gdata *)
+ data = (struct tegra_bb_power_data *)
callback->deinit();
/* Deinitialize gpios */
+ gdata = data->gpio_data;
if (gdata)
tegra_bb_power_gpio_deinit(gdata);
else {
pr_err("%s - Error: Gpio data is empty.\n", __func__);
return -ENODEV;
}
+
+ mdata = data->modem_data;
+ if (mdata && mdata->vid && mdata->pid)
+ /* Register to notifications from usb core */
+ usb_unregister_notify(&tegra_usb_nb);
}
/* Remove the control sysfs node */
diff --git a/drivers/misc/tegra-baseband/bb-power.h b/drivers/misc/tegra-baseband/bb-power.h
index 4f85cca712e6..84f9e85994b1 100644
--- a/drivers/misc/tegra-baseband/bb-power.h
+++ b/drivers/misc/tegra-baseband/bb-power.h
@@ -30,19 +30,34 @@ struct tegra_bb_gpio_irqdata {
const char *name;
irq_handler_t handler;
int flags;
+ bool wake_capable;
void *cookie;
};
-struct tegra_bb_power_gdata {
- struct tegra_bb_gpio_data *gpio;
- struct tegra_bb_gpio_irqdata *gpioirq;
-};
-
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);
+typedef int (*modem_register_cb)(struct usb_device *udev);
+
+struct tegra_bb_power_gdata {
+ struct tegra_bb_gpio_data *gpio;
+ struct tegra_bb_gpio_irqdata *gpioirq;
+};
+
+struct tegra_bb_power_mdata {
+ int vid;
+ int pid;
+ bool wake_capable;
+ bool autosuspend_ready;
+ modem_register_cb reg_cb;
+};
+
+struct tegra_bb_power_data {
+ struct tegra_bb_power_gdata *gpio_data;
+ struct tegra_bb_power_mdata *modem_data;
+};
struct tegra_bb_callback {
bb_init_cb init;