mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 06:31:58 +02:00
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq
Pull devfreq framework changes for v4.21 from MyungJoo Ham: "This includes the suspend-frequency support for devfreq, which is similar with suspend_freq in cpufreq." * 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq: PM / devfreq: add devfreq_suspend/resume() functions PM / devfreq: add support for suspend/resume of a devfreq device PM / devfreq: refactor set_target frequency function
This commit is contained in:
commit
2c3b0463bb
|
|
@ -285,6 +285,44 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
|
||||
u32 flags)
|
||||
{
|
||||
struct devfreq_freqs freqs;
|
||||
unsigned long cur_freq;
|
||||
int err = 0;
|
||||
|
||||
if (devfreq->profile->get_cur_freq)
|
||||
devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
|
||||
else
|
||||
cur_freq = devfreq->previous_freq;
|
||||
|
||||
freqs.old = cur_freq;
|
||||
freqs.new = new_freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
|
||||
|
||||
err = devfreq->profile->target(devfreq->dev.parent, &new_freq, flags);
|
||||
if (err) {
|
||||
freqs.new = cur_freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
freqs.new = new_freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
|
||||
|
||||
if (devfreq_update_status(devfreq, new_freq))
|
||||
dev_err(&devfreq->dev,
|
||||
"Couldn't update frequency transition information.\n");
|
||||
|
||||
devfreq->previous_freq = new_freq;
|
||||
|
||||
if (devfreq->suspend_freq)
|
||||
devfreq->resume_freq = cur_freq;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Load monitoring helper functions for governors use */
|
||||
|
||||
/**
|
||||
|
|
@ -296,8 +334,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
|
|||
*/
|
||||
int update_devfreq(struct devfreq *devfreq)
|
||||
{
|
||||
struct devfreq_freqs freqs;
|
||||
unsigned long freq, cur_freq, min_freq, max_freq;
|
||||
unsigned long freq, min_freq, max_freq;
|
||||
int err = 0;
|
||||
u32 flags = 0;
|
||||
|
||||
|
|
@ -333,31 +370,8 @@ int update_devfreq(struct devfreq *devfreq)
|
|||
flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
|
||||
}
|
||||
|
||||
if (devfreq->profile->get_cur_freq)
|
||||
devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
|
||||
else
|
||||
cur_freq = devfreq->previous_freq;
|
||||
return devfreq_set_target(devfreq, freq, flags);
|
||||
|
||||
freqs.old = cur_freq;
|
||||
freqs.new = freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
|
||||
|
||||
err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
|
||||
if (err) {
|
||||
freqs.new = cur_freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
freqs.new = freq;
|
||||
devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
|
||||
|
||||
if (devfreq_update_status(devfreq, freq))
|
||||
dev_err(&devfreq->dev,
|
||||
"Couldn't update frequency transition information.\n");
|
||||
|
||||
devfreq->previous_freq = freq;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(update_devfreq);
|
||||
|
||||
|
|
@ -657,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);
|
||||
|
|
@ -857,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,
|
||||
DEVFREQ_GOV_SUSPEND, NULL);
|
||||
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);
|
||||
|
||||
|
|
@ -878,17 +909,75 @@ 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,
|
||||
DEVFREQ_GOV_RESUME, NULL);
|
||||
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);
|
||||
|
||||
/**
|
||||
* devfreq_suspend() - Suspend devfreq governors and devices
|
||||
*
|
||||
* Called during system wide Suspend/Hibernate cycles for suspending governors
|
||||
* and devices preserving the state for resume. On some platforms the devfreq
|
||||
* device must have precise state (frequency) after resume in order to provide
|
||||
* fully operating setup.
|
||||
*/
|
||||
void devfreq_suspend(void)
|
||||
{
|
||||
struct devfreq *devfreq;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&devfreq_list_lock);
|
||||
list_for_each_entry(devfreq, &devfreq_list, node) {
|
||||
ret = devfreq_suspend_device(devfreq);
|
||||
if (ret)
|
||||
dev_err(&devfreq->dev,
|
||||
"failed to suspend devfreq device\n");
|
||||
}
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* devfreq_resume() - Resume devfreq governors and devices
|
||||
*
|
||||
* Called during system wide Suspend/Hibernate cycle for resuming governors and
|
||||
* devices that are suspended with devfreq_suspend().
|
||||
*/
|
||||
void devfreq_resume(void)
|
||||
{
|
||||
struct devfreq *devfreq;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&devfreq_list_lock);
|
||||
list_for_each_entry(devfreq, &devfreq_list, node) {
|
||||
ret = devfreq_resume_device(devfreq);
|
||||
if (ret)
|
||||
dev_warn(&devfreq->dev,
|
||||
"failed to resume devfreq device\n");
|
||||
}
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* devfreq_add_governor() - Add devfreq governor
|
||||
* @governor: the devfreq governor to be added
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -198,6 +205,9 @@ extern void devm_devfreq_remove_device(struct device *dev,
|
|||
extern int devfreq_suspend_device(struct devfreq *devfreq);
|
||||
extern int devfreq_resume_device(struct devfreq *devfreq);
|
||||
|
||||
extern void devfreq_suspend(void);
|
||||
extern void devfreq_resume(void);
|
||||
|
||||
/**
|
||||
* update_devfreq() - Reevaluate the device and configure frequency
|
||||
* @devfreq: the devfreq device
|
||||
|
|
@ -324,6 +334,9 @@ static inline int devfreq_resume_device(struct devfreq *devfreq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void devfreq_suspend(void) {}
|
||||
static inline void devfreq_resume(void) {}
|
||||
|
||||
static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
|
||||
unsigned long *freq, u32 flags)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user