summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/board-omap3h1-bluetooth.c')
-rw-r--r--arch/arm/mach-omap2/board-omap3h1-bluetooth.c170
1 files changed, 119 insertions, 51 deletions
diff --git a/arch/arm/mach-omap2/board-omap3h1-bluetooth.c b/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
index 3cec4bee656..b3cb230e16b 100644
--- a/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
+++ b/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
@@ -36,25 +36,30 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <asm/mach-types.h>
+#include <linux/platform_data/serial-omap.h>
#include "serial.h"
#include "board-omap3h1.h"
#include <linux/regulator/driver.h>
-static void update_host_wake_locked(int);
+static void set_host_wake_locked(int);
+#define BT_RESET_GPIO 179
#define BT_REG_GPIO 180
#define BT_WAKE_GPIO 93
#define BT_HOST_WAKE_GPIO 11
+#define UART_PORT 1
+
+#define olio_debug(format, ...) printk ("OLIO %s: ", __FUNCTION__); printk (format, ##__VA_ARGS__)
static struct rfkill *bt_rfkill;
static struct regulator *clk32ksys_reg;
static bool bt_enabled;
-static bool host_wake_uart_enabled;
-static bool wake_uart_enabled;
+static bool host_wake_uart_enabled = 0;
+static bool wake_uart_enabled = 0;
static struct dentry *btdebugdent;
-struct bcm_bt_lpm {
- int wake;
+static struct bcm_bt_lpm {
+ int bcm_wake;
int host_wake;
struct hrtimer enter_lpm_timer;
@@ -62,24 +67,36 @@ struct bcm_bt_lpm {
struct uart_port *uport;
- struct wake_lock wake_lock;
- char wake_lock_name[100];
+ /* Lock for use when host is communicating with chip */
+
+ struct wake_lock bcm_wake_lock;
+
+ /* Lock used when chip wakes up the host */
+
+ struct wake_lock host_wake_lock;
+
+ char host_wake_lock_name[100];
+ char bcm_wake_lock_name[100];
} bt_lpm;
static int bcm20702_bt_rfkill_set_power(void *data, bool blocked)
{
- // rfkill_ops callback. Turn transmitter on when blocked is false
+ // rfkill_ops callback. Turn transmitter on when blocked is false
if (!blocked) {
if (clk32ksys_reg && !bt_enabled)
regulator_enable(clk32ksys_reg);
+ gpio_set_value(BT_RESET_GPIO, 1);
gpio_set_value(BT_REG_GPIO, 1);
+ gpio_set_value(BT_RESET_GPIO, 1);
} else {
// Chip won't toggle host_wake after reset. Make sure
// we don't hold the wake_lock until chip wakes up again.
- update_host_wake_locked(0);
-
+ // set_host_wake_locked(0);
+ // OLIO removed, we'll let go of the wake lock when HOST_WAKE drops.
+
+ gpio_set_value(BT_RESET_GPIO, 0);
gpio_set_value(BT_REG_GPIO, 0);
if (clk32ksys_reg && bt_enabled)
regulator_disable(clk32ksys_reg);
@@ -96,20 +113,32 @@ static const struct rfkill_ops bcm20702_bt_rfkill_ops = {
static void set_wake_locked(int wake)
{
- bt_lpm.wake = wake;
+ if (bt_lpm.bcm_wake == wake) {
+ return;
+ }
- if (!wake)
- wake_unlock(&bt_lpm.wake_lock);
+ bt_lpm.bcm_wake = wake;
- //if (!wake_uart_enabled && wake)
- //omap_uart_enable(2);
+ if (wake) {
+ olio_debug ("Now locking wake lock\n");
+ wake_lock (&bt_lpm.bcm_wake_lock);
+ if (!wake_uart_enabled)
+ omap_serial_ext_uart_enable(UART_PORT);
+ }
gpio_set_value(BT_WAKE_GPIO, wake);
- //if (wake_uart_enabled && !wake)
- //omap_uart_disable(2);
+ /* Let UART know we're done with it */
+
+ if (wake_uart_enabled && !wake)
+ omap_serial_ext_uart_disable(UART_PORT);
wake_uart_enabled = wake;
+
+ if (!wake) {
+ olio_debug ("Now unlocking wake lock\n");
+ wake_unlock(&bt_lpm.bcm_wake_lock);
+ }
}
static enum hrtimer_restart enter_lpm(struct hrtimer *timer) {
@@ -122,41 +151,64 @@ static enum hrtimer_restart enter_lpm(struct hrtimer *timer) {
}
void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport) {
+ int ret;
+
bt_lpm.uport = uport;
- hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer);
+ ret = hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer);
+ if (ret == -1) {
+ olio_debug ("timer executing, unable to cancel\n");
+ }
+
set_wake_locked(1);
hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay,
- HRTIMER_MODE_REL);
+ HRTIMER_MODE_REL);
}
EXPORT_SYMBOL(bcm_bt_lpm_exit_lpm_locked);
-static void update_host_wake_locked(int host_wake)
+static void set_host_wake_locked(int host_wake)
{
- if (host_wake == bt_lpm.host_wake)
+ olio_debug ("Entered, requested host_wake is %d\n", host_wake);
+
+ if (host_wake == bt_lpm.host_wake) {
+ olio_debug ("Host wake lock is already in requested state\n");
return;
+ }
+
+ olio_debug ("host_wake (%d) is different from bt_lpm.host_wake (%d)\n",
+ host_wake, bt_lpm.host_wake);
bt_lpm.host_wake = host_wake;
if (host_wake) {
- wake_lock(&bt_lpm.wake_lock);
+ olio_debug ("host_wake is set, taking wake lock\n");
+ wake_lock(&bt_lpm.host_wake_lock);
+
if (!host_wake_uart_enabled) {
- //omap_uart_enable(2);
+ omap_serial_ext_uart_enable(UART_PORT);
}
} else {
if (host_wake_uart_enabled) {
- //omap_uart_disable(2);
+ omap_serial_ext_uart_disable(UART_PORT);
}
- // Take a timed wakelock, so that upper layers can take it.
- // The chipset deasserts the hostwake lock, when there is no
- // more data to send.
- wake_lock_timeout(&bt_lpm.wake_lock, HZ/2);
+
}
+
+ /* Set wake lock to time out, so that upper layers can take it.
+ * The chipset deasserts the host wake lock when there is no
+ * more data to send.
+ */
+
+ if (!host_wake) {
+ olio_debug ("host_wake isn't set, adding timeout to wake lock\n");
+ wake_lock_timeout(&bt_lpm.host_wake_lock, HZ/2);
+ }
host_wake_uart_enabled = host_wake;
+ olio_debug ("Exiting\n");
}
static irqreturn_t host_wake_isr(int irq, void *dev)
@@ -165,7 +217,11 @@ static irqreturn_t host_wake_isr(int irq, void *dev)
unsigned long flags;
host_wake = gpio_get_value(BT_HOST_WAKE_GPIO);
- irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+
+ /* Invert the interrupt type to catch the next transition */
+
+ irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
+ olio_debug ("Set next trigger to be %s\n", host_wake ? "falling" : "rising");
if (!bt_lpm.uport) {
bt_lpm.host_wake = host_wake;
@@ -173,7 +229,7 @@ static irqreturn_t host_wake_isr(int irq, void *dev)
}
spin_lock_irqsave(&bt_lpm.uport->lock, flags);
- update_host_wake_locked(host_wake);
+ set_host_wake_locked(host_wake);
spin_unlock_irqrestore(&bt_lpm.uport->lock, flags);
return IRQ_HANDLED;
@@ -203,8 +259,8 @@ static int bcm_bt_lpm_init(struct platform_device *pdev)
bt_lpm.host_wake = 0;
irq = gpio_to_irq(BT_HOST_WAKE_GPIO);
- ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_HIGH,
- "bt host_wake", NULL);
+ ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_RISING,
+ "bt host_wake", NULL);
if (ret) {
gpio_free(BT_WAKE_GPIO);
gpio_free(BT_HOST_WAKE_GPIO);
@@ -221,10 +277,16 @@ static int bcm_bt_lpm_init(struct platform_device *pdev)
gpio_direction_output(BT_WAKE_GPIO, 0);
gpio_direction_input(BT_HOST_WAKE_GPIO);
- snprintf(bt_lpm.wake_lock_name, sizeof(bt_lpm.wake_lock_name),
- "BTLowPower");
- wake_lock_init(&bt_lpm.wake_lock, WAKE_LOCK_SUSPEND,
- bt_lpm.wake_lock_name);
+ snprintf(bt_lpm.bcm_wake_lock_name, sizeof(bt_lpm.bcm_wake_lock_name),
+ "BCM BTLowPower");
+ snprintf(bt_lpm.host_wake_lock_name, sizeof(bt_lpm.host_wake_lock_name),
+ "HOST BTLowPower");
+
+ wake_lock_init(&bt_lpm.bcm_wake_lock, WAKE_LOCK_SUSPEND,
+ bt_lpm.bcm_wake_lock_name);
+ wake_lock_init(&bt_lpm.host_wake_lock, WAKE_LOCK_SUSPEND,
+ bt_lpm.host_wake_lock_name);
+
return 0;
}
@@ -232,7 +294,7 @@ static int btdebug_dump(struct seq_file *sf, void *private)
{
seq_printf(sf, "en=%d bt_wake=%d lpm.w=%d w_uart_en=%d\n",
bt_enabled, gpio_get_value(BT_WAKE_GPIO),
- bt_lpm.wake, wake_uart_enabled);
+ bt_lpm.bcm_wake, wake_uart_enabled);
seq_printf(sf, "bt_host_wake=%d lpm.hw=%d hw_uart_en=%d\n",
gpio_get_value(BT_HOST_WAKE_GPIO), bt_lpm.host_wake,
host_wake_uart_enabled);
@@ -256,14 +318,15 @@ static int bcm20702_bluetooth_probe(struct platform_device *pdev)
int rc = 0;
int ret = 0;
-// rc = gpio_request(BT_RESET_GPIO, "bcm20702_nreset_gpip");
-// if (unlikely(rc)) {
-// return rc;
-// }
+ rc = gpio_request(BT_RESET_GPIO, "bcm20702_nreset_gpip");
+
+ if (unlikely(rc)) {
+ return rc;
+ }
rc = gpio_request(BT_REG_GPIO, "bcm20702_nshutdown_gpio");
if (unlikely(rc)) {
- //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_RESET_GPIO);
return rc;
}
@@ -274,14 +337,14 @@ static int bcm20702_bluetooth_probe(struct platform_device *pdev)
}
gpio_direction_output(BT_REG_GPIO, 1);
- //gpio_direction_output(BT_RESET_GPIO, 1);
+ gpio_direction_output(BT_RESET_GPIO, 1);
bt_rfkill = rfkill_alloc("bcm20702 Bluetooth", &pdev->dev,
RFKILL_TYPE_BLUETOOTH, &bcm20702_bt_rfkill_ops,
NULL);
if (unlikely(!bt_rfkill)) {
- //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_RESET_GPIO);
gpio_free(BT_REG_GPIO);
return -ENOMEM;
}
@@ -291,7 +354,7 @@ static int bcm20702_bluetooth_probe(struct platform_device *pdev)
if (unlikely(rc)) {
rfkill_destroy(bt_rfkill);
- //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_RESET_GPIO);
gpio_free(BT_REG_GPIO);
return -1;
}
@@ -301,7 +364,7 @@ static int bcm20702_bluetooth_probe(struct platform_device *pdev)
rfkill_unregister(bt_rfkill);
rfkill_destroy(bt_rfkill);
- //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_RESET_GPIO);
gpio_free(BT_REG_GPIO);
}
@@ -322,12 +385,13 @@ static int bcm20702_bluetooth_remove(struct platform_device *pdev)
debugfs_remove(btdebugdent);
gpio_free(BT_REG_GPIO);
- //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_RESET_GPIO);
gpio_free(BT_WAKE_GPIO);
gpio_free(BT_HOST_WAKE_GPIO);
regulator_put(clk32ksys_reg);
- wake_lock_destroy(&bt_lpm.wake_lock);
+ wake_lock_destroy(&bt_lpm.bcm_wake_lock);
+ wake_lock_destroy(&bt_lpm.host_wake_lock);
return 0;
}
@@ -337,7 +401,8 @@ int bcm4430_bluetooth_suspend(struct platform_device *pdev, pm_message_t state)
int host_wake;
disable_irq(irq);
- host_wake = gpio_get_value(BT_HOST_WAKE_GPIO); /* Never goes low - what's up? */
+
+ host_wake = gpio_get_value(BT_HOST_WAKE_GPIO);
if (host_wake) {
enable_irq(irq);
@@ -354,11 +419,14 @@ int bcm4430_bluetooth_resume(struct platform_device *pdev)
return 0;
}
+/*
+ .suspend = bcm4430_bluetooth_suspend,
+ .resume = bcm4430_bluetooth_resume,
+*/
+
static struct platform_driver bcm20702_bluetooth_platform_driver = {
.probe = bcm20702_bluetooth_probe,
.remove = bcm20702_bluetooth_remove,
- .suspend = bcm4430_bluetooth_suspend,
- .resume = bcm4430_bluetooth_resume,
.driver = {
.name = "bcm20702_bluetooth",
.owner = THIS_MODULE,