diff options
Diffstat (limited to 'drivers/misc/ti-st/st_core.c')
| -rw-r--r-- | drivers/misc/ti-st/st_core.c | 52 | 
1 files changed, 52 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);  }  |