From: Lin Huang <h...@rock-chips.com> Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional).
Signed-off-by: Lin Huang <h...@rock-chips.com> [cw00.choi: Support the passive governor and use separate devfreq_set_target()] Signed-off-by: Chanwoo Choi <cw00.c...@samsung.com> --- drivers/devfreq/devfreq.c | 31 ++++++++++++++++++++++++++++++- include/linux/devfreq.h | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index e386f14d91c3..8109fb71177b 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -620,6 +620,23 @@ struct devfreq *devfreq_add_device(struct device *dev, goto err_init; } + /* + * Get the suspend frequency from OPP table. But the devfreq device + * using passive governor don't need to get the suspend frequency + * because the passive devfreq device depend on the parent devfreq + * device. + */ + devfreq->suspend_freq = 0L; + if (strncmp(devfreq->governor_name, "passive", 7)) { + struct dev_pm_opp *opp; + + rcu_read_lock(); + opp = dev_pm_opp_get_suspend_opp(dev); + if (opp) + devfreq->suspend_freq = dev_pm_opp_get_freq(opp); + rcu_read_unlock(); + } + devfreq->governor = governor; err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, NULL); @@ -777,14 +794,26 @@ void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq) */ int devfreq_suspend_device(struct devfreq *devfreq) { + int ret; + if (!devfreq) return -EINVAL; if (!devfreq->governor) return 0; - return devfreq->governor->event_handler(devfreq, + ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_SUSPEND, NULL); + if (ret < 0) + return ret; + + if (devfreq->suspend_freq) { + ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0); + if (ret < 0) + return ret; + } + + return 0; } EXPORT_SYMBOL(devfreq_suspend_device); diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 2de4e2eea180..926bef5a6332 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -141,6 +141,7 @@ struct devfreq_governor { * devfreq.nb to the corresponding register notifier call chain. * @work: delayed work for load monitoring. * @previous_freq: previously configured frequency value. + * @suspend_freq: frequency to set during suspend mode. * @data: Private data of the governor. The devfreq framework does not * touch this. * @min_freq: Limit minimum frequency requested by user (0: none) @@ -172,6 +173,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + unsigned long suspend_freq; struct devfreq_dev_status last_status; void *data; /* private data for governors */ -- 1.9.1