summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/cg2900/bluetooth/cg2900_uart.c45
-rw-r--r--drivers/staging/cg2900/include/cg2900.h2
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_core.c13
3 files changed, 48 insertions, 12 deletions
diff --git a/drivers/staging/cg2900/bluetooth/cg2900_uart.c b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
index 783b8327786..3c88ed6d18f 100644
--- a/drivers/staging/cg2900/bluetooth/cg2900_uart.c
+++ b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
@@ -126,6 +126,16 @@
#define CG2900_BAUD_RATE_3250000 0x28
#define CG2900_BAUD_RATE_4000000 0x2B
+/**
+ * enum sleep_allowed_bits - bits indicating if sleep is allowed.
+ * @SLEEP_TTY_READY: Bit for checking if break can be applied using tty.
+ * @SLEEP_CORE_READY: Bit for checking if core is ready for sleep or not.
+ */
+enum sleep_allowed_bits {
+ SLEEP_TTY_READY,
+ SLEEP_CORE_READY
+};
+
/* GNSS */
struct gnss_hci_hdr {
__u8 op_code;
@@ -290,7 +300,7 @@ struct uart_delayed_work_struct {
* @wakeup_work: Wake-up work struct.
* @restart_sleep_work: Reschedule sleep_work and wake-up work struct.
* @sleep_state_lock: Used to protect chip state.
- * @sleep_allowed: Indicates if tty has functions needed for sleep mode.
+ * @sleep_flags: Indicates whether sleep mode is allowed.
* @tx_in_progress: Indicates data sending in progress.
* @rx_in_progress: Indicates data receiving in progress.
* @transmission_lock: Spin_lock to protect tx/rx_in_progress.
@@ -320,7 +330,7 @@ struct uart_info {
struct uart_work_struct wakeup_work;
struct uart_work_struct restart_sleep_work;
struct mutex sleep_state_lock;
- bool sleep_allowed;
+ unsigned long sleep_flags;
bool tx_in_progress;
bool rx_in_progress;
spinlock_t transmission_lock;
@@ -559,16 +569,22 @@ static void unset_cts_irq(struct uart_info *uart_info)
* Check all conditions for sleep and return sleep timeout.
* Return:
* 0: sleep not allowed.
- * other: Timeout value in ms.
+ * other: Timeout value in jiffies.
*/
static unsigned long get_sleep_timeout(struct uart_info *uart_info)
{
- unsigned long timeout_jiffies = cg2900_get_sleep_timeout();
+ unsigned long timeout_jiffies = 0;
+ bool check_sleep = false;
+ if (uart_info->sleep_state == CHIP_FALLING_ASLEEP)
+ check_sleep = true;
+
+ timeout_jiffies = cg2900_get_sleep_timeout(check_sleep);
if (timeout_jiffies &&
uart_info->hu &&
uart_info->hu->fd &&
- uart_info->sleep_allowed)
+ test_bit(SLEEP_TTY_READY, &uart_info->sleep_flags) &&
+ test_bit(SLEEP_CORE_READY, &uart_info->sleep_flags))
return timeout_jiffies;
return 0;
@@ -789,7 +805,7 @@ schedule_sleep_work:
error:
/* Disable sleep mode.*/
dev_err(MAIN_DEV, "Disable sleep mode\n");
- uart_info->sleep_allowed = false;
+ clear_bit(SLEEP_CORE_READY, &uart_info->sleep_flags);
mutex_unlock(&(uart_info->sleep_state_lock));
}
@@ -1448,6 +1464,12 @@ static void uart_set_chip_power(struct cg2900_chip_dev *dev, bool chip_on)
dev_dbg(MAIN_DEV,
"New sleep_state: CHIP_POWERED_DOWN\n");
uart_info->sleep_state = CHIP_POWERED_DOWN;
+ /*
+ * This is to ensure when chip is switched
+ * on next time sleep_flags is again set with
+ * SLEEP_CORE_READY when startup is done properly
+ */
+ clear_bit(SLEEP_CORE_READY, &uart_info->sleep_flags);
}
cg2900_disable_regulator(uart_info);
@@ -1487,6 +1509,11 @@ static void uart_chip_startup_finished(struct cg2900_chip_dev *dev)
struct uart_info *uart_info = dev_get_drvdata(dev->dev);
unsigned long timeout_jiffies = get_sleep_timeout(uart_info);
+ /*
+ * Chip startup is done, now chip is allowed
+ * to go to sleep
+ */
+ set_bit(SLEEP_CORE_READY, &uart_info->sleep_flags);
/* Schedule work to put the chip and transport to sleep. */
if (timeout_jiffies)
queue_delayed_work(uart_info->wq, &uart_info->sleep_work.work,
@@ -1867,10 +1894,10 @@ static int cg2900_hu_open(struct hci_uart *hu)
err);
if (hu->tty->ops->tiocmget && hu->tty->ops->break_ctl)
- uart_info->sleep_allowed = true;
+ set_bit(SLEEP_TTY_READY, &uart_info->sleep_flags);
else {
dev_err(MAIN_DEV, "Sleep mode not available\n");
- uart_info->sleep_allowed = false;
+ clear_bit(SLEEP_TTY_READY, &uart_info->sleep_flags);
}
return err;
@@ -1893,6 +1920,8 @@ static int cg2900_hu_close(struct hci_uart *hu)
BUG_ON(!uart_info);
BUG_ON(!uart_info->wq);
+ clear_bit(SLEEP_TTY_READY, &uart_info->sleep_flags);
+
/* Purge any stored sk_buffers */
skb_queue_purge(&uart_info->tx_queue);
diff --git a/drivers/staging/cg2900/include/cg2900.h b/drivers/staging/cg2900/include/cg2900.h
index eddfb71c8e4..99ac90da58f 100644
--- a/drivers/staging/cg2900/include/cg2900.h
+++ b/drivers/staging/cg2900/include/cg2900.h
@@ -277,7 +277,7 @@ extern int cg2900_register_chip_driver(struct cg2900_id_callbacks *cb);
extern void cg2900_deregister_chip_driver(struct cg2900_id_callbacks *cb);
extern int cg2900_register_trans_driver(struct cg2900_chip_dev *dev);
extern int cg2900_deregister_trans_driver(struct cg2900_chip_dev *dev);
-extern unsigned long cg2900_get_sleep_timeout(void);
+extern unsigned long cg2900_get_sleep_timeout(bool check_sleep);
#endif /* __KERNEL__ */
#endif /* _CG2900_H_ */
diff --git a/drivers/staging/cg2900/mfd/cg2900_core.c b/drivers/staging/cg2900/mfd/cg2900_core.c
index b1f34d71eec..fe28ab6b7ae 100644
--- a/drivers/staging/cg2900/mfd/cg2900_core.c
+++ b/drivers/staging/cg2900/mfd/cg2900_core.c
@@ -55,7 +55,9 @@
*/
#define CHIP_READY_TIMEOUT (100) /* ms */
#define REVISION_READOUT_TIMEOUT (500) /* ms */
-#define SLEEP_TIMEOUT_MS (10000) /* ms */
+#define SLEEP_TIMEOUT_MS (150) /* ms */
+/* Timeout value to check CTS line for low power */
+#define READY_FOR_SLEEP_TIMEOUT_MS (50) /* ms */
/**
* enum boot_state - BOOT-state for CG2900 Core.
@@ -592,16 +594,21 @@ EXPORT_SYMBOL_GPL(cg2900_deregister_trans_driver);
/**
* cg2900_get_sleep_timeout() - Return sleep timeout in jiffies.
+ * @check_sleep: If we want to check whether chip has gone
+ * to sleep then use lesser timeout value
*
* Returns:
* Sleep timeout in jiffies. 0 means that sleep timeout shall not be used.
*/
-unsigned long cg2900_get_sleep_timeout(void)
+unsigned long cg2900_get_sleep_timeout(bool check_sleep)
{
if (!sleep_timeout_ms)
return 0;
- return msecs_to_jiffies(sleep_timeout_ms);
+ if (check_sleep)
+ return msecs_to_jiffies(READY_FOR_SLEEP_TIMEOUT_MS);
+ else
+ return msecs_to_jiffies(sleep_timeout_ms);
}
EXPORT_SYMBOL_GPL(cg2900_get_sleep_timeout);