diff options
| -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   */  |