diff options
| author | Andrey Gostev <fga022c@motorola.com> | 2014-05-16 22:02:45 -0400 |
|---|---|---|
| committer | Andrey Gostev <fga022c@motorola.com> | 2014-05-19 15:42:45 +0000 |
| commit | 8ed52cf68c04f91a453e75a13b49202945695e47 (patch) | |
| tree | ee393da7ce93e4d7557ea32f3e9e6146cea87388 | |
| parent | 3171e60ee2a1077d863b4f2262b71f060dc728a8 (diff) | |
| download | olio-linux-3.10-8ed52cf68c04f91a453e75a13b49202945695e47.tar.xz olio-linux-3.10-8ed52cf68c04f91a453e75a13b49202945695e47.zip | |
IKXCLOCK-1236 Let TI shared transport driver control PM QoS
TI shared transport driver controls PM QoS constraint to avoid
holding CPU out of deep idle state when BT IC is already asleep.
Change-Id: I81b7b737c72f221f317afe13a70d21cc7ad49b6a
Signed-off-by: Andrey Gostev <fga022c@motorola.com>
| -rw-r--r-- | drivers/misc/ti-st/st_core.c | 52 | ||||
| -rw-r--r-- | drivers/misc/ti-st/st_ll.c | 7 | ||||
| -rw-r--r-- | include/linux/ti_wilink_st.h | 9 |
3 files changed, 68 insertions, 0 deletions
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 7a4647bc7ea..ef6e56907c2 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -30,11 +30,20 @@ #include <linux/wakelock.h> #include <linux/ti_wilink_st.h> +#include <linux/pm_qos.h> #define ST_WAKE_LOCK_TIMEOUT_MS 150 static struct wake_lock st_wk_lock_timeout; +struct st_pm_qos_t { + struct pm_qos_request st_pm_qos_request; + u32 st_pm_qos_latency; + spinlock_t st_pm_qos_lock; /* protect internal members */ +}; + +static struct st_pm_qos_t st_pm_qos; + extern void st_kim_recv(void *, const unsigned char *, long); void st_int_recv(void *, const unsigned char *, long); /* function pointer pointing to either, @@ -62,6 +71,44 @@ static void remove_channel_from_table(struct st_data_s *st_gdata, } /* + * called when Bluetooth IC changes sleep state. + * + * This function dynamically changes pm_qos to allow + * CPU to go to deep idle state when there is no + * communication between host and Bluetooth IC. + */ +void st_pm_qos_update(struct st_data_s *st_gdata, bool awake) +{ + struct kim_data_s *kim_plat_data; + u32 latency; + unsigned long flags; + + if (unlikely(st_gdata == NULL || st_gdata->kim_data == NULL)) { + pr_err("%s: Invalid argument\n", __func__); + return; + } + + spin_lock_irqsave(&st_pm_qos.st_pm_qos_lock, flags); + + kim_plat_data = (struct kim_data_s *)st_gdata->kim_data; + if (awake) { + /* UART FIFO is 64 bytes */ + latency = (USEC_PER_SEC * 64) / (kim_plat_data->baud_rate / 8); + } else { + /* drop PM QoS constraint */ + latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + } + + if (st_pm_qos.st_pm_qos_latency != latency) { + st_pm_qos.st_pm_qos_latency = latency; + pm_qos_update_request(&st_pm_qos.st_pm_qos_request, + st_pm_qos.st_pm_qos_latency); + } + + spin_unlock_irqrestore(&st_pm_qos.st_pm_qos_lock, flags); +} + +/* * called from KIM during firmware download. * * This is a wrapper function to tty->ops->write_room. @@ -852,6 +899,10 @@ int st_core_init(struct st_data_s **core_data) long err; wake_lock_init(&st_wk_lock_timeout, WAKE_LOCK_SUSPEND, "st_wake_lock"); + spin_lock_init(&st_pm_qos.st_pm_qos_lock); + pm_qos_add_request(&st_pm_qos.st_pm_qos_request, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE); err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); if (err) { pr_err("error registering %d line discipline %ld\n", @@ -913,6 +964,7 @@ void st_core_exit(struct st_data_s *st_gdata) /* free the global data pointer */ kfree(st_gdata); } + pm_qos_remove_request(&st_pm_qos.st_pm_qos_request); wake_lock_destroy(&st_wk_lock_timeout); } diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c index e0c110e7107..9b9ef562073 100644 --- a/drivers/misc/ti-st/st_ll.c +++ b/drivers/misc/ti-st/st_ll.c @@ -32,7 +32,14 @@ static void send_ll_cmd(struct st_data_s *st_data, { pr_debug("%s: writing %x\n", __func__, cmd); + + if (cmd == LL_WAKE_UP_IND || cmd == LL_WAKE_UP_ACK) + st_pm_qos_update(st_data, 1); + st_int_write(st_data, &cmd, 1); + + if (cmd == LL_SLEEP_ACK) + st_pm_qos_update(st_data, 0); return; } diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index 932b7639224..bf2a954c848 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -161,6 +161,15 @@ struct st_data_s { }; /* + * called when Bluetooth IC changes sleep state. + * + * This function dynamically changes pm_qos to allow + * CPU to go to deep idle state when there is no + * communication between host and Bluetooth IC. + */ +void st_pm_qos_update(struct st_data_s *st_gdata, bool awake); + +/* * wrapper around tty->ops->write_room to check * availability during firmware download */ |