forked from mirrors/linux
		
	PM / devfreq: add support for suspend/resume of a devfreq device
The patch prepares devfreq device for handling suspend/resume functionality. The new fields will store needed information during this process. Devfreq framework handles opp-suspend DT entry and there is no need of modyfications in the drivers code. It uses atomic variables to make sure no race condition affects the process. Suggested-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de> Suggested-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
This commit is contained in:
		
							parent
							
								
									633141721b
								
							
						
					
					
						commit
						83f8ca45af
					
				
					 2 changed files with 48 additions and 6 deletions
				
			
		|  | @ -316,6 +316,10 @@ static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq, | |||
| 			"Couldn't update frequency transition information.\n"); | ||||
| 
 | ||||
| 	devfreq->previous_freq = new_freq; | ||||
| 
 | ||||
| 	if (devfreq->suspend_freq) | ||||
| 		devfreq->resume_freq = cur_freq; | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
|  | @ -667,6 +671,9 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 	} | ||||
| 	devfreq->max_freq = devfreq->scaling_max_freq; | ||||
| 
 | ||||
| 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); | ||||
| 	atomic_set(&devfreq->suspend_count, 0); | ||||
| 
 | ||||
| 	dev_set_name(&devfreq->dev, "devfreq%d", | ||||
| 				atomic_inc_return(&devfreq_no)); | ||||
| 	err = device_register(&devfreq->dev); | ||||
|  | @ -867,14 +874,28 @@ EXPORT_SYMBOL(devm_devfreq_remove_device); | |||
|  */ | ||||
| int devfreq_suspend_device(struct devfreq *devfreq) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!devfreq) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!devfreq->governor) | ||||
| 	if (atomic_inc_return(&devfreq->suspend_count) > 1) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return devfreq->governor->event_handler(devfreq, | ||||
| 	if (devfreq->governor) { | ||||
| 		ret = devfreq->governor->event_handler(devfreq, | ||||
| 					DEVFREQ_GOV_SUSPEND, NULL); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (devfreq->suspend_freq) { | ||||
| 		ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(devfreq_suspend_device); | ||||
| 
 | ||||
|  | @ -888,14 +909,28 @@ EXPORT_SYMBOL(devfreq_suspend_device); | |||
|  */ | ||||
| int devfreq_resume_device(struct devfreq *devfreq) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!devfreq) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!devfreq->governor) | ||||
| 	if (atomic_dec_return(&devfreq->suspend_count) >= 1) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return devfreq->governor->event_handler(devfreq, | ||||
| 	if (devfreq->resume_freq) { | ||||
| 		ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (devfreq->governor) { | ||||
| 		ret = devfreq->governor->event_handler(devfreq, | ||||
| 					DEVFREQ_GOV_RESUME, NULL); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(devfreq_resume_device); | ||||
| 
 | ||||
|  |  | |||
|  | @ -131,6 +131,9 @@ struct devfreq_dev_profile { | |||
|  * @scaling_min_freq:	Limit minimum frequency requested by OPP interface | ||||
|  * @scaling_max_freq:	Limit maximum frequency requested by OPP interface | ||||
|  * @stop_polling:	 devfreq polling status of a device. | ||||
|  * @suspend_freq:	 frequency of a device set during suspend phase. | ||||
|  * @resume_freq:	 frequency of a device set in resume phase. | ||||
|  * @suspend_count:	 suspend requests counter for a device. | ||||
|  * @total_trans:	Number of devfreq transitions | ||||
|  * @trans_table:	Statistics of devfreq transitions | ||||
|  * @time_in_state:	Statistics of devfreq states | ||||
|  | @ -167,6 +170,10 @@ struct devfreq { | |||
| 	unsigned long scaling_max_freq; | ||||
| 	bool stop_polling; | ||||
| 
 | ||||
| 	unsigned long suspend_freq; | ||||
| 	unsigned long resume_freq; | ||||
| 	atomic_t suspend_count; | ||||
| 
 | ||||
| 	/* information for device frequency transition */ | ||||
| 	unsigned int total_trans; | ||||
| 	unsigned int *trans_table; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Lukasz Luba
						Lukasz Luba