aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/cg2900/bluetooth/cg2900_uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/cg2900/bluetooth/cg2900_uart.c')
-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");