summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrgoyal <rgoyal@nvidia.com>2010-10-26 10:43:01 +0530
committerVarun Colbert <vcolbert@nvidia.com>2010-10-28 19:41:25 -0700
commit7d5f8c651c06af7889a5d48c5886eb91e78ccb6d (patch)
tree099a3a0a948497af7ab0fab157c9308dc79ab957
parent4b1ae9254924cded7285f5166a8cf982cd7d6473 (diff)
csr lowpower mode:adding bluesleep support for csr
Adding bluesleep support for CSR chip BUG 691608 Change-Id: I5cb9420201e99b36a9ee26a411c0312b3c6e3fa1 Reviewed-on: http://git-master/r/9678 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/board-generic.c51
-rw-r--r--arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c2
-rw-r--r--arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c2
-rw-r--r--drivers/bluetooth/bluesleep.c151
4 files changed, 150 insertions, 56 deletions
diff --git a/arch/arm/mach-tegra/board-generic.c b/arch/arm/mach-tegra/board-generic.c
index f1f26ce2777f..d2de4a4ac4b1 100644
--- a/arch/arm/mach-tegra/board-generic.c
+++ b/arch/arm/mach-tegra/board-generic.c
@@ -326,7 +326,7 @@ static noinline void __init tegra_setup_bluesleep(void)
res[2].name = "host_wake";
res[2].start = gpio_to_irq(TEGRA_GPIO_PU6);
res[2].end = gpio_to_irq(TEGRA_GPIO_PU6);
- res[2].flags = IORESOURCE_IRQ;
+ res[2].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE ;
if (platform_device_add_resources(pdev, res, 3)) {
pr_err("unable to add resources to bluesleep device\n");
@@ -348,7 +348,54 @@ err_free_dev:
#else
static inline void tegra_setup_bluesleep(void) { }
#endif
+#ifdef CONFIG_BT_BLUESLEEP
+static noinline void __init tegra_setup_bluesleep_csr(void)
+{
+ struct platform_device *pdev = NULL;
+ struct resource *res;
+
+ pdev = platform_device_alloc("bluesleep", 0);
+ if (!pdev) {
+ pr_err("unable to allocate platform device for bluesleep");
+ return;
+ }
+
+ res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+ if (!res) {
+ pr_err("unable to allocate resource for bluesleep\n");
+ goto err_free_dev;
+ }
+
+ res[0].name = "gpio_host_wake";
+ res[0].start = TEGRA_GPIO_PU6;
+ res[0].end = TEGRA_GPIO_PU6;
+ res[0].flags = IORESOURCE_IO;
+ res[1].name = "host_wake";
+ res[1].start = gpio_to_irq(TEGRA_GPIO_PU6);
+ res[1].end = gpio_to_irq(TEGRA_GPIO_PU6);
+ res[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE;
+
+ if (platform_device_add_resources(pdev, res, 2)) {
+ pr_err("unable to add resources to bluesleep device\n");
+ goto err_free_res;
+ }
+
+ if (platform_device_add(pdev)) {
+ pr_err("unable to add bluesleep device\n");
+ goto err_free_res;
+ }
+ return;
+
+err_free_res:
+ kfree(res);
+err_free_dev:
+ platform_device_put(pdev);
+ return;
+}
+#else
+static inline void tegra_setup_bluesleep_csr(void) { }
+#endif
static void __init tegra_harmony_init(void)
@@ -357,6 +404,7 @@ static void __init tegra_harmony_init(void)
tegra_android_platform.product_name = harmony_dev;
#endif
do_system_init(true, true);
+ tegra_setup_bluesleep_csr();
}
@@ -379,6 +427,7 @@ static void __init tegra_generic_init(void)
#endif
do_system_init(true, true);
register_spi_ipc_devices();
+ tegra_setup_bluesleep_csr();
}
MACHINE_START(VENTANA, "NVIDIA Ventana Development System")
diff --git a/arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c b/arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c
index 5eb105409ace..23ae5bb3a7d9 100644
--- a/arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c
+++ b/arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c
@@ -301,7 +301,7 @@ static NvOdmWakeupPadInfo s_NvOdmWakeupPadInfo[] =
{NV_FALSE, 4, NvOdmWakeupPadPolarity_High}, // Wake Event 4 - hdmi_int (HDMI_HPD)
{NV_TRUE, 5, NvOdmWakeupPadPolarity_Low}, // Wake Event 5 - vgp[6] (VI_GP6, Flash_EN2)
{NV_FALSE, 6, NvOdmWakeupPadPolarity_High}, // Wake Event 6 - gp3_pu[5] (GPS_ON_OFF, GPS_IRQ)
- {NV_FALSE, 7, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 7 - gp3_pu[6] (GPS_INT, BT_IRQ)
+ {NV_TRUE, 7, NvOdmWakeupPadPolarity_AnyEdge}, /* Wake Event 7 - gp3_pu[6] (GPS_INT, BT_IRQ*/
{NV_FALSE, 8, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 8 - gmi_wp_n (MICRO SD_CD)
{NV_FALSE, 9, NvOdmWakeupPadPolarity_High}, // Wake Event 9 - gp3_ps[2] (KB_COL10)
{NV_FALSE, 10, NvOdmWakeupPadPolarity_High}, // Wake Event 10 - gmi_ad21 (Accelerometer_TH/TAP)
diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
index 84da33aa6215..346aa035cefe 100644
--- a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
+++ b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
@@ -1557,7 +1557,7 @@ static NvOdmWakeupPadInfo s_NvOdmWakeupPadInfo[] =
{NV_FALSE, 4, NvOdmWakeupPadPolarity_High}, // Wake Event 4 - hdmi_int (HDMI_HPD)
{NV_FALSE, 5, NvOdmWakeupPadPolarity_High}, // Wake Event 5 - vgp[6] (VI_GP6, Flash_EN2)
{NV_FALSE, 6, NvOdmWakeupPadPolarity_High}, // Wake Event 6 - gp3_pu[5] (GPS_ON_OFF, GPS_IRQ)
- {NV_FALSE, 7, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 7 - gp3_pu[6] (GPS_INT, BT_IRQ)
+ {NV_TRUE, 7, NvOdmWakeupPadPolarity_AnyEdge}, /* Wake Event 7 - gp3_pu[6] (GPS_INT, BT_IRQ)*/
{NV_FALSE, 8, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 8 - gmi_wp_n (MICRO SD_CD)
{NV_FALSE, 9, NvOdmWakeupPadPolarity_High}, // Wake Event 9 - gp3_ps[2] (KB_COL10)
{NV_FALSE, 10, NvOdmWakeupPadPolarity_High}, // Wake Event 10 - gmi_ad21 (Accelerometer_TH/TAP)
diff --git a/drivers/bluetooth/bluesleep.c b/drivers/bluetooth/bluesleep.c
index afd082170f66..75d28f455e45 100644
--- a/drivers/bluetooth/bluesleep.c
+++ b/drivers/bluetooth/bluesleep.c
@@ -42,6 +42,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/ioport.h>
#include <linux/param.h>
#include <linux/bitops.h>
#include <linux/termios.h>
@@ -64,12 +65,17 @@
#define VERSION "1.1"
#define PROC_DIR "bluetooth/sleep"
+#define POLARITY_LOW 0
+#define POLARITY_HIGH 1
+
struct bluesleep_info {
unsigned host_wake;
unsigned ext_wake;
unsigned host_wake_irq;
struct uart_port *uport;
struct wake_lock wake_lock;
+ int irq_polarity;
+ int has_ext_wake;
};
/* work function */
@@ -91,6 +97,7 @@ DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work);
#define BT_PROTO 0x01
#define BT_TXDATA 0x02
#define BT_ASLEEP 0x04
+#define BT_EXT_WAKE 0x08
/* global pointer to a single hci device. */
static struct hci_dev *bluesleep_hdev;
@@ -116,6 +123,8 @@ static void bluesleep_stop(void);
/** Global state flags */
static unsigned long flags;
+
+
/** Tasklet to respond to change in hostwake line */
static struct tasklet_struct hostwake_task;
@@ -155,9 +164,9 @@ static void hsuart_power(int on)
int bluesleep_can_sleep(void)
{
/* check if WAKE_BT_GPIO and BT_WAKE_GPIO are both deasserted */
- return !gpio_get_value(bsi->ext_wake) &&
- !gpio_get_value(bsi->host_wake) &&
- (bsi->uport != NULL);
+ return ((gpio_get_value(bsi->host_wake) != bsi->irq_polarity) &&
+ (!test_bit(BT_EXT_WAKE, &flags)) &&
+ (bsi->uport != NULL));
}
void bluesleep_sleep_wakeup(void)
@@ -167,7 +176,9 @@ void bluesleep_sleep_wakeup(void)
wake_lock(&bsi->wake_lock);
/* Start the timer */
mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
- gpio_set_value(bsi->ext_wake, 1);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
clear_bit(BT_ASLEEP, &flags);
/*Activating UART */
hsuart_power(1);
@@ -197,14 +208,18 @@ static void bluesleep_sleep_work(struct work_struct *work)
*/
wake_lock_timeout(&bsi->wake_lock, HZ / 2);
} else {
- mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
- return;
+ mod_timer(&tx_timer, jiffies +
+ (TX_TIMER_INTERVAL * HZ));
+ return;
}
- }else if (!gpio_get_value(bsi->ext_wake) && !test_bit(BT_ASLEEP, &flags)) {
- mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
- gpio_set_value(bsi->ext_wake, 1);
- }else {
- bluesleep_sleep_wakeup();
+ } else if (!test_bit(BT_EXT_WAKE, &flags)
+ && !test_bit(BT_ASLEEP, &flags)) {
+ mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
+ } else {
+ bluesleep_sleep_wakeup();
}
}
@@ -219,7 +234,7 @@ static void bluesleep_hostwake_task(unsigned long data)
spin_lock(&rw_lock);
- if (gpio_get_value(bsi->host_wake))
+ if ((gpio_get_value(bsi->host_wake) == bsi->irq_polarity))
bluesleep_rx_busy();
else
bluesleep_rx_idle();
@@ -241,12 +256,10 @@ static void bluesleep_outgoing_data(void)
set_bit(BT_TXDATA, &flags);
/* if the tx side is sleeping... */
- if (!gpio_get_value(bsi->ext_wake)) {
-
+ if (!test_bit(BT_EXT_WAKE, &flags)) {
BT_DBG("tx was sleeping");
- bluesleep_sleep_wakeup();
- }
-
+ bluesleep_sleep_wakeup();
+ }
spin_unlock_irqrestore(&rw_lock, irq_flags);
}
@@ -307,7 +320,9 @@ static void bluesleep_tx_timer_expire(unsigned long data)
/* were we silent during the last timeout? */
if (!test_bit(BT_TXDATA, &flags)) {
BT_DBG("Tx has been idle");
- gpio_set_value(bsi->ext_wake, 0);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 0);
+ clear_bit(BT_EXT_WAKE, &flags);
bluesleep_tx_idle();
} else {
BT_DBG("Tx data during last period");
@@ -328,8 +343,6 @@ static void bluesleep_tx_timer_expire(unsigned long data)
*/
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
- //nvUART gpio_clear_detect_status(bsi->host_wake_irq);
-
/* schedule a tasklet to handle the change in the host wake line */
tasklet_schedule(&hostwake_task);
return IRQ_HANDLED;
@@ -363,11 +376,20 @@ static int bluesleep_start(void)
mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
/* assert BT_WAKE */
- gpio_set_value(bsi->ext_wake, 1);
- retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "bluetooth hostwake", NULL);
- if (retval < 0) {
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+
+ set_bit(BT_EXT_WAKE, &flags);
+ if (bsi->irq_polarity == POLARITY_LOW) {
+ retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "bluetooth hostwake", NULL);
+ } else {
+ retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "bluetooth hostwake", NULL);
+ }
+ if (retval < 0) {
BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
goto fail;
}
@@ -379,8 +401,8 @@ static int bluesleep_start(void)
goto fail;
}
- set_bit(BT_PROTO, &flags);
- wake_lock(&bsi->wake_lock);
+ set_bit(BT_PROTO, &flags);
+ wake_lock(&bsi->wake_lock);
return 0;
fail:
del_timer(&tx_timer);
@@ -404,7 +426,9 @@ static void bluesleep_stop(void)
}
/* assert BT_WAKE */
- gpio_set_value(bsi->ext_wake, 1);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
del_timer(&tx_timer);
clear_bit(BT_PROTO, &flags);
@@ -437,7 +461,7 @@ static int bluepower_read_proc_btwake(char *page, char **start, off_t offset,
int count, int *eof, void *data)
{
*eof = 1;
- return sprintf(page, "btwake:%u\n", gpio_get_value(bsi->ext_wake));
+ return sprintf(page, "btwake:%u\n",test_bit(BT_EXT_WAKE, &flags));
}
/**
@@ -467,9 +491,13 @@ static int bluepower_write_proc_btwake(struct file *file, const char *buffer,
}
if (buf[0] == '0') {
- gpio_set_value(bsi->ext_wake, 0);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 0);
+ clear_bit(BT_EXT_WAKE, &flags);
} else if (buf[0] == '1') {
- gpio_set_value(bsi->ext_wake, 1);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
} else {
kfree(buf);
return -EINVAL;
@@ -608,33 +636,46 @@ static int __init bluesleep_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_IO,
"gpio_ext_wake");
+ if (!res)
+ bsi->has_ext_wake = 0;
+ else
+ bsi->has_ext_wake = 1;
+
+ if (bsi->has_ext_wake) {
+ bsi->ext_wake = res->start;
+
+ ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
+ if (ret)
+ goto free_bt_host_wake;
+
+ /* configure ext_wake as output mode*/
+ ret = gpio_direction_output(bsi->ext_wake, 1);
+ if (ret < 0) {
+ pr_err("gpio-keys: failed to configure output"
+ " direction for GPIO %d, error %d\n",
+ bsi->ext_wake, ret);
+ gpio_free(bsi->ext_wake);
+ goto free_bt_host_wake;
+ }
+ } else
+ set_bit(BT_EXT_WAKE, &flags);
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "host_wake");
if (!res) {
- BT_ERR("couldn't find ext_wake gpio\n");
+ BT_ERR("couldn't find host_wake irq\n");
ret = -ENODEV;
goto free_bt_host_wake;
}
- bsi->ext_wake = res->start;
-
- ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
- if (ret)
- goto free_bt_host_wake;
-
- // configure ext_wake as output mode
- ret = gpio_direction_output(bsi->ext_wake, 1);
- if (ret < 0) {
- pr_err("gpio-keys: failed to configure output"
- " direction for GPIO %d, error %d\n",
- bsi->ext_wake, ret);
- gpio_free(bsi->ext_wake);
- goto free_bt_host_wake;
- }
-
- bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");
- if (bsi->host_wake_irq < 0) {
+ bsi->host_wake_irq = res->start;
+ if (bsi->host_wake_irq < 0) {
BT_ERR("couldn't find host_wake irq\n");
ret = -ENODEV;
goto free_bt_ext_wake;
}
+ if (res->flags & IORESOURCE_IRQ_LOWEDGE)
+ bsi->irq_polarity = POLARITY_LOW;/*low edge (falling edge)*/
+ else
+ bsi->irq_polarity = POLARITY_HIGH;/*anything else*/
wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
return 0;
@@ -659,7 +700,7 @@ static int bluesleep_remove(struct platform_device *pdev)
static struct platform_driver bluesleep_driver = {
.probe = bluesleep_probe,
- .remove = bluesleep_remove,
+ .remove = bluesleep_remove,
.driver = {
.name = "bluesleep",
.owner = THIS_MODULE,
@@ -745,7 +786,9 @@ static int __init bluesleep_init(void)
tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
/* assert bt wake */
- gpio_set_value(bsi->ext_wake, 1);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
hci_register_notifier(&hci_event_nblock);
return 0;
@@ -766,7 +809,9 @@ fail:
static void __exit bluesleep_exit(void)
{
/* assert bt wake */
- gpio_set_value(bsi->ext_wake, 1);
+ if (bsi->has_ext_wake == 1)
+ gpio_set_value(bsi->ext_wake, 1);
+ set_bit(BT_EXT_WAKE, &flags);
if (test_bit(BT_PROTO, &flags)) {
if (disable_irq_wake(bsi->host_wake_irq))
BT_ERR("Couldn't disable hostwake IRQ wakeup mode \n");