diff options
Diffstat (limited to 'drivers/staging/cg2900/bluetooth/cg2900_uart.c')
-rw-r--r-- | drivers/staging/cg2900/bluetooth/cg2900_uart.c | 30 |
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"); |