summaryrefslogtreecommitdiff
path: root/drivers/staging
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-06-29 16:20:47 +0200
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 15:56:13 +0200
commitabd52985b45ed2f7cfdc0842dcf667c633a23eee (patch)
tree3c07af5d1552198ab0d5341560d2cfefa12f9621 /drivers/staging
parent35a98d6331295fab929b1e2c142e237a97b1b181 (diff)
bluetooth: Add wake locks for CG2900
This patch corrects some bad behavior for the CG2900 driver when system suspends. Wake locks are added to stop Android from suspending when chip should be contacted. Signed-off-by: Par-Gunnar Hjalmdahl <par-gunnar.p.hjalmdahl@stericsson.com>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/cg2900/bluetooth/cg2900_uart.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/staging/cg2900/bluetooth/cg2900_uart.c b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
index 4417525306a..c0c8d8e30bd 100644
--- a/drivers/staging/cg2900/bluetooth/cg2900_uart.c
+++ b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
@@ -31,6 +31,7 @@
#include <linux/tty.h>
#include <linux/tty_ldisc.h>
#include <linux/types.h>
+#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
@@ -285,6 +286,8 @@ struct uart_delayed_work_struct {
* @chip_dev: Chip device for current UART transport.
* @cts_irq: CTS interrupt for this UART.
* @cts_gpio: CTS GPIO for this UART.
+ * @wake_lock: Wake lock for keeping user space awake (for Android).
+ * @suspend_blocked: True if suspend operation is blocked in the framework.
*/
struct uart_info {
enum uart_rx_state rx_state;
@@ -312,6 +315,8 @@ struct uart_info {
struct cg2900_chip_dev chip_dev;
int cts_irq;
int cts_gpio;
+ struct wake_lock wake_lock;
+ bool suspend_blocked;
};
/* Module parameters */
@@ -432,6 +437,10 @@ static irqreturn_t cts_interrupt(int irq, void *dev_id)
disable_irq_wake(irq);
#endif
disable_irq_nosync(irq);
+ if (!uart_info->suspend_blocked) {
+ wake_lock(&uart_info->wake_lock);
+ uart_info->suspend_blocked = true;
+ }
/* Create work and leave IRQ context. */
(void)create_work_item(uart_info, handle_cts_irq);
@@ -586,6 +595,11 @@ static void wake_up_chip(struct uart_info *uart_info)
if (CHIP_POWERED_DOWN == uart_info->sleep_state)
goto finished;
+ if (!uart_info->suspend_blocked) {
+ wake_lock(&uart_info->wake_lock);
+ uart_info->suspend_blocked = true;
+ }
+
/*
* This function indicates data is transmitted.
* Therefore see to that the chip is awake.
@@ -698,6 +712,10 @@ static void set_chip_sleep_mode(struct work_struct *work)
dev_dbg(MAIN_DEV, "New sleep_state: CHIP_ASLEEP\n");
uart_info->sleep_state = CHIP_ASLEEP;
+ if (uart_info->suspend_blocked) {
+ wake_unlock(&uart_info->wake_lock);
+ uart_info->suspend_blocked = false;
+ }
break;
case CHIP_AWAKE:
chars_in_buffer = hci_uart_chars_in_buffer(uart_info->hu);
@@ -1327,6 +1345,10 @@ static void uart_set_chip_power(struct cg2900_chip_dev *dev, bool chip_on)
}
if (chip_on) {
+ if (!uart_info->suspend_blocked) {
+ wake_lock(&uart_info->wake_lock);
+ uart_info->suspend_blocked = true;
+ }
if (uart_info->sleep_state != CHIP_POWERED_DOWN) {
dev_err(MAIN_DEV, "Chip is already powered up (%d)\n",
uart_info->sleep_state);
@@ -1363,6 +1385,11 @@ static void uart_set_chip_power(struct cg2900_chip_dev *dev, bool chip_on)
break;
}
+ if (uart_info->suspend_blocked) {
+ wake_unlock(&uart_info->wake_lock);
+ uart_info->suspend_blocked = false;
+ }
+
if (pf_data->disable_chip) {
pf_data->disable_chip(dev);
dev_dbg(MAIN_DEV,
@@ -1914,6 +1941,8 @@ static int __devinit cg2900_uart_probe(struct platform_device *pdev)
uart_info->chip_dev.pdev = pdev;
uart_info->chip_dev.dev = &pdev->dev;
uart_info->chip_dev.t_data = uart_info;
+ wake_lock_init(&uart_info->wake_lock, WAKE_LOCK_SUSPEND, NAME);
+ uart_info->suspend_blocked = false;
resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"cts_irq");
@@ -2010,6 +2039,7 @@ static int __devexit cg2900_uart_remove(struct platform_device *pdev)
if (uart_info->hu)
hci_uart_unregister_proto(uart_info->hu->proto);
+ wake_lock_destroy(&uart_info->wake_lock);
destroy_workqueue(uart_info->wq);
dev_info(MAIN_DEV, "CG2900 UART removed\n");