diff options
author | rgoyal <rgoyal@nvidia.com> | 2010-10-26 10:43:01 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2010-10-28 19:41:25 -0700 |
commit | 7d5f8c651c06af7889a5d48c5886eb91e78ccb6d (patch) | |
tree | 099a3a0a948497af7ab0fab157c9308dc79ab957 | |
parent | 4b1ae9254924cded7285f5166a8cf982cd7d6473 (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.c | 51 | ||||
-rw-r--r-- | arch/arm/mach-tegra/odm_kit/query/harmony/nvodm_query.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/bluesleep.c | 151 |
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"); |