dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'pm-devfreq'

* pm-devfreq: (23 commits)
  PM / devfreq: remove compiler error with module governors (2)
  PM / devfreq: Fix return value in devfreq_remove_governor()
  PM / devfreq: Fix incorrect argument in error message
  PM / devfreq: missing rcu_read_lock() added for find_device_opp()
  PM / devfreq: remove compiler error when a governor is module
  PM / devfreq: exynos4_bus.c: Fixed an alignment of the func call args.
  PM / devfreq: Add sysfs node to expose available governors
  PM / devfreq: allow sysfs governor node to switch governor
  PM / devfreq: governors: add GPL module license and allow module build
  PM / devfreq: map devfreq drivers to governor using name
  PM / devfreq: register governors with devfreq framework
  PM / devfreq: provide hooks for governors to be registered
  PM / devfreq: export update_devfreq
  PM / devfreq: Add sysfs node for representing frequency transition information.
  PM / devfreq: Add sysfs node to expose available frequencies
  PM / devfreq: documentation cleanups for devfreq header
  PM / devfreq: Use devm_* functions in exynos4_bus.c
  PM / devfreq: make devfreq_class static
  PM / devfreq: fix sscanf handling for writable sysfs entries
  PM / devfreq: kernel-doc typo corrections
  ...
This commit is contained in:
Rafael J. Wysocki 2012-12-07 23:13:36 +01:00
commit bf58cdffac
10 changed files with 947 additions and 406 deletions

View File

@ -11,7 +11,7 @@ What: /sys/class/devfreq/.../governor
Date: September 2011 Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description: Description:
The /sys/class/devfreq/.../governor shows the name of the The /sys/class/devfreq/.../governor show or set the name of the
governor used by the corresponding devfreq object. governor used by the corresponding devfreq object.
What: /sys/class/devfreq/.../cur_freq What: /sys/class/devfreq/.../cur_freq
@ -19,15 +19,16 @@ Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description: Description:
The /sys/class/devfreq/.../cur_freq shows the current The /sys/class/devfreq/.../cur_freq shows the current
frequency of the corresponding devfreq object. frequency of the corresponding devfreq object. Same as
target_freq when get_cur_freq() is not implemented by
devfreq driver.
What: /sys/class/devfreq/.../central_polling What: /sys/class/devfreq/.../target_freq
Date: September 2011 Date: September 2012
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Description: Description:
The /sys/class/devfreq/.../central_polling shows whether The /sys/class/devfreq/.../target_freq shows the next governor
the devfreq ojbect is using devfreq-provided central predicted target frequency of the corresponding devfreq object.
polling mechanism or not.
What: /sys/class/devfreq/.../polling_interval What: /sys/class/devfreq/.../polling_interval
Date: September 2011 Date: September 2011
@ -43,6 +44,17 @@ Description:
(/sys/class/devfreq/.../central_polling is 0), this value (/sys/class/devfreq/.../central_polling is 0), this value
may be useless. may be useless.
What: /sys/class/devfreq/.../trans_stat
Date: October 2012
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Descrtiption:
This ABI shows the statistics of devfreq behavior on a
specific device. It shows the time spent in each state and
the number of transitions between states.
In order to activate this ABI, the devfreq target device
driver should provide the list of available frequencies
with its profile.
What: /sys/class/devfreq/.../userspace/set_freq What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011 Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
@ -50,3 +62,19 @@ Description:
The /sys/class/devfreq/.../userspace/set_freq shows and The /sys/class/devfreq/.../userspace/set_freq shows and
sets the requested frequency for the devfreq object if sets the requested frequency for the devfreq object if
userspace governor is in effect. userspace governor is in effect.
What: /sys/class/devfreq/.../available_frequencies
Date: October 2012
Contact: Nishanth Menon <nm@ti.com>
Description:
The /sys/class/devfreq/.../available_frequencies shows
the available frequencies of the corresponding devfreq object.
This is a snapshot of available frequencies and not limited
by the min/max frequency restrictions.
What: /sys/class/devfreq/.../available_governors
Date: October 2012
Contact: Nishanth Menon <nm@ti.com>
Description:
The /sys/class/devfreq/.../available_governors shows
currently available governors in the system.

View File

@ -30,7 +30,7 @@ if PM_DEVFREQ
comment "DEVFREQ Governors" comment "DEVFREQ Governors"
config DEVFREQ_GOV_SIMPLE_ONDEMAND config DEVFREQ_GOV_SIMPLE_ONDEMAND
bool "Simple Ondemand" tristate "Simple Ondemand"
help help
Chooses frequency based on the recent load on the device. Works Chooses frequency based on the recent load on the device. Works
similar as ONDEMAND governor of CPUFREQ does. A device with similar as ONDEMAND governor of CPUFREQ does. A device with
@ -39,7 +39,7 @@ config DEVFREQ_GOV_SIMPLE_ONDEMAND
values to the governor with data field at devfreq_add_device(). values to the governor with data field at devfreq_add_device().
config DEVFREQ_GOV_PERFORMANCE config DEVFREQ_GOV_PERFORMANCE
bool "Performance" tristate "Performance"
help help
Sets the frequency at the maximum available frequency. Sets the frequency at the maximum available frequency.
This governor always returns UINT_MAX as frequency so that This governor always returns UINT_MAX as frequency so that
@ -47,7 +47,7 @@ config DEVFREQ_GOV_PERFORMANCE
at any time. at any time.
config DEVFREQ_GOV_POWERSAVE config DEVFREQ_GOV_POWERSAVE
bool "Powersave" tristate "Powersave"
help help
Sets the frequency at the minimum available frequency. Sets the frequency at the minimum available frequency.
This governor always returns 0 as frequency so that This governor always returns 0 as frequency so that
@ -55,7 +55,7 @@ config DEVFREQ_GOV_POWERSAVE
at any time. at any time.
config DEVFREQ_GOV_USERSPACE config DEVFREQ_GOV_USERSPACE
bool "Userspace" tristate "Userspace"
help help
Sets the frequency at the user specified one. Sets the frequency at the user specified one.
This governor returns the user configured frequency if there This governor returns the user configured frequency if there

File diff suppressed because it is too large Load Diff

View File

@ -987,7 +987,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int err = 0; int err = 0;
data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL); data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL);
if (data == NULL) { if (data == NULL) {
dev_err(dev, "Cannot allocate memory.\n"); dev_err(dev, "Cannot allocate memory.\n");
return -ENOMEM; return -ENOMEM;
@ -1012,31 +1012,26 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
err = -EINVAL; err = -EINVAL;
} }
if (err) if (err)
goto err_regulator; return err;
data->vdd_int = regulator_get(dev, "vdd_int"); data->vdd_int = devm_regulator_get(dev, "vdd_int");
if (IS_ERR(data->vdd_int)) { if (IS_ERR(data->vdd_int)) {
dev_err(dev, "Cannot get the regulator \"vdd_int\"\n"); dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
err = PTR_ERR(data->vdd_int); return PTR_ERR(data->vdd_int);
goto err_regulator;
} }
if (data->type == TYPE_BUSF_EXYNOS4x12) { if (data->type == TYPE_BUSF_EXYNOS4x12) {
data->vdd_mif = regulator_get(dev, "vdd_mif"); data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
if (IS_ERR(data->vdd_mif)) { if (IS_ERR(data->vdd_mif)) {
dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n"); dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
err = PTR_ERR(data->vdd_mif); return PTR_ERR(data->vdd_mif);
regulator_put(data->vdd_int);
goto err_regulator;
} }
} }
opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq); opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
dev_err(dev, "Invalid initial frequency %lu kHz.\n", dev_err(dev, "Invalid initial frequency %lu kHz.\n",
exynos4_devfreq_profile.initial_freq); exynos4_devfreq_profile.initial_freq);
err = PTR_ERR(opp); return PTR_ERR(opp);
goto err_opp_add;
} }
data->curr_opp = opp; data->curr_opp = opp;
@ -1045,30 +1040,20 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
busfreq_mon_reset(data); busfreq_mon_reset(data);
data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
&devfreq_simple_ondemand, NULL); "simple_ondemand", NULL);
if (IS_ERR(data->devfreq)) { if (IS_ERR(data->devfreq))
err = PTR_ERR(data->devfreq); return PTR_ERR(data->devfreq);
goto err_opp_add;
}
devfreq_register_opp_notifier(dev, data->devfreq); devfreq_register_opp_notifier(dev, data->devfreq);
err = register_pm_notifier(&data->pm_notifier); err = register_pm_notifier(&data->pm_notifier);
if (err) { if (err) {
dev_err(dev, "Failed to setup pm notifier\n"); dev_err(dev, "Failed to setup pm notifier\n");
goto err_devfreq_add; devfreq_remove_device(data->devfreq);
return err;
} }
return 0; return 0;
err_devfreq_add:
devfreq_remove_device(data->devfreq);
err_opp_add:
if (data->vdd_mif)
regulator_put(data->vdd_mif);
regulator_put(data->vdd_int);
err_regulator:
kfree(data);
return err;
} }
static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
@ -1077,10 +1062,6 @@ static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
unregister_pm_notifier(&data->pm_notifier); unregister_pm_notifier(&data->pm_notifier);
devfreq_remove_device(data->devfreq); devfreq_remove_device(data->devfreq);
regulator_put(data->vdd_int);
if (data->vdd_mif)
regulator_put(data->vdd_mif);
kfree(data);
return 0; return 0;
} }

View File

@ -18,7 +18,24 @@
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev) #define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
/* Devfreq events */
#define DEVFREQ_GOV_START 0x1
#define DEVFREQ_GOV_STOP 0x2
#define DEVFREQ_GOV_INTERVAL 0x3
#define DEVFREQ_GOV_SUSPEND 0x4
#define DEVFREQ_GOV_RESUME 0x5
/* Caution: devfreq->lock must be locked before calling update_devfreq */ /* Caution: devfreq->lock must be locked before calling update_devfreq */
extern int update_devfreq(struct devfreq *devfreq); extern int update_devfreq(struct devfreq *devfreq);
extern void devfreq_monitor_start(struct devfreq *devfreq);
extern void devfreq_monitor_stop(struct devfreq *devfreq);
extern void devfreq_monitor_suspend(struct devfreq *devfreq);
extern void devfreq_monitor_resume(struct devfreq *devfreq);
extern void devfreq_interval_update(struct devfreq *devfreq,
unsigned int *delay);
extern int devfreq_add_governor(struct devfreq_governor *governor);
extern int devfreq_remove_governor(struct devfreq_governor *governor);
#endif /* _GOVERNOR_H */ #endif /* _GOVERNOR_H */

View File

@ -10,6 +10,7 @@
*/ */
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/module.h>
#include "governor.h" #include "governor.h"
static int devfreq_performance_func(struct devfreq *df, static int devfreq_performance_func(struct devfreq *df,
@ -26,14 +27,41 @@ static int devfreq_performance_func(struct devfreq *df,
return 0; return 0;
} }
static int performance_init(struct devfreq *devfreq) static int devfreq_performance_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{ {
return update_devfreq(devfreq); int ret = 0;
if (event == DEVFREQ_GOV_START) {
mutex_lock(&devfreq->lock);
ret = update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
}
return ret;
} }
const struct devfreq_governor devfreq_performance = { static struct devfreq_governor devfreq_performance = {
.name = "performance", .name = "performance",
.init = performance_init,
.get_target_freq = devfreq_performance_func, .get_target_freq = devfreq_performance_func,
.no_central_polling = true, .event_handler = devfreq_performance_handler,
}; };
static int __init devfreq_performance_init(void)
{
return devfreq_add_governor(&devfreq_performance);
}
subsys_initcall(devfreq_performance_init);
static void __exit devfreq_performance_exit(void)
{
int ret;
ret = devfreq_remove_governor(&devfreq_performance);
if (ret)
pr_err("%s: failed remove governor %d\n", __func__, ret);
return;
}
module_exit(devfreq_performance_exit);
MODULE_LICENSE("GPL");

View File

@ -10,6 +10,7 @@
*/ */
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/module.h>
#include "governor.h" #include "governor.h"
static int devfreq_powersave_func(struct devfreq *df, static int devfreq_powersave_func(struct devfreq *df,
@ -23,14 +24,41 @@ static int devfreq_powersave_func(struct devfreq *df,
return 0; return 0;
} }
static int powersave_init(struct devfreq *devfreq) static int devfreq_powersave_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{ {
return update_devfreq(devfreq); int ret = 0;
if (event == DEVFREQ_GOV_START) {
mutex_lock(&devfreq->lock);
ret = update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
}
return ret;
} }
const struct devfreq_governor devfreq_powersave = { static struct devfreq_governor devfreq_powersave = {
.name = "powersave", .name = "powersave",
.init = powersave_init,
.get_target_freq = devfreq_powersave_func, .get_target_freq = devfreq_powersave_func,
.no_central_polling = true, .event_handler = devfreq_powersave_handler,
}; };
static int __init devfreq_powersave_init(void)
{
return devfreq_add_governor(&devfreq_powersave);
}
subsys_initcall(devfreq_powersave_init);
static void __exit devfreq_powersave_exit(void)
{
int ret;
ret = devfreq_remove_governor(&devfreq_powersave);
if (ret)
pr_err("%s: failed remove governor %d\n", __func__, ret);
return;
}
module_exit(devfreq_powersave_exit);
MODULE_LICENSE("GPL");

View File

@ -10,8 +10,10 @@
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h>
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/math64.h> #include <linux/math64.h>
#include "governor.h"
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */ /* Default constants for DevFreq-Simple-Ondemand (DFSO) */
#define DFSO_UPTHRESHOLD (90) #define DFSO_UPTHRESHOLD (90)
@ -88,7 +90,58 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
return 0; return 0;
} }
const struct devfreq_governor devfreq_simple_ondemand = { static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{
switch (event) {
case DEVFREQ_GOV_START:
devfreq_monitor_start(devfreq);
break;
case DEVFREQ_GOV_STOP:
devfreq_monitor_stop(devfreq);
break;
case DEVFREQ_GOV_INTERVAL:
devfreq_interval_update(devfreq, (unsigned int *)data);
break;
case DEVFREQ_GOV_SUSPEND:
devfreq_monitor_suspend(devfreq);
break;
case DEVFREQ_GOV_RESUME:
devfreq_monitor_resume(devfreq);
break;
default:
break;
}
return 0;
}
static struct devfreq_governor devfreq_simple_ondemand = {
.name = "simple_ondemand", .name = "simple_ondemand",
.get_target_freq = devfreq_simple_ondemand_func, .get_target_freq = devfreq_simple_ondemand_func,
.event_handler = devfreq_simple_ondemand_handler,
}; };
static int __init devfreq_simple_ondemand_init(void)
{
return devfreq_add_governor(&devfreq_simple_ondemand);
}
subsys_initcall(devfreq_simple_ondemand_init);
static void __exit devfreq_simple_ondemand_exit(void)
{
int ret;
ret = devfreq_remove_governor(&devfreq_simple_ondemand);
if (ret)
pr_err("%s: failed remove governor %d\n", __func__, ret);
return;
}
module_exit(devfreq_simple_ondemand_exit);
MODULE_LICENSE("GPL");

View File

@ -14,6 +14,7 @@
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/module.h>
#include "governor.h" #include "governor.h"
struct userspace_data { struct userspace_data {
@ -116,10 +117,46 @@ static void userspace_exit(struct devfreq *devfreq)
devfreq->data = NULL; devfreq->data = NULL;
} }
const struct devfreq_governor devfreq_userspace = { static int devfreq_userspace_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{
int ret = 0;
switch (event) {
case DEVFREQ_GOV_START:
ret = userspace_init(devfreq);
break;
case DEVFREQ_GOV_STOP:
userspace_exit(devfreq);
break;
default:
break;
}
return ret;
}
static struct devfreq_governor devfreq_userspace = {
.name = "userspace", .name = "userspace",
.get_target_freq = devfreq_userspace_func, .get_target_freq = devfreq_userspace_func,
.init = userspace_init, .event_handler = devfreq_userspace_handler,
.exit = userspace_exit,
.no_central_polling = true,
}; };
static int __init devfreq_userspace_init(void)
{
return devfreq_add_governor(&devfreq_userspace);
}
subsys_initcall(devfreq_userspace_init);
static void __exit devfreq_userspace_exit(void)
{
int ret;
ret = devfreq_remove_governor(&devfreq_userspace);
if (ret)
pr_err("%s: failed remove governor %d\n", __func__, ret);
return;
}
module_exit(devfreq_userspace_exit);
MODULE_LICENSE("GPL");

View File

@ -25,12 +25,12 @@ struct devfreq;
* struct devfreq_dev_status - Data given from devfreq user device to * struct devfreq_dev_status - Data given from devfreq user device to
* governors. Represents the performance * governors. Represents the performance
* statistics. * statistics.
* @total_time The total time represented by this instance of * @total_time: The total time represented by this instance of
* devfreq_dev_status * devfreq_dev_status
* @busy_time The time that the device was working among the * @busy_time: The time that the device was working among the
* total_time. * total_time.
* @current_frequency The operating frequency. * @current_frequency: The operating frequency.
* @private_data An entry not specified by the devfreq framework. * @private_data: An entry not specified by the devfreq framework.
* A device and a specific governor may have their * A device and a specific governor may have their
* own protocol with private_data. However, because * own protocol with private_data. However, because
* this is governor-specific, a governor using this * this is governor-specific, a governor using this
@ -54,23 +54,27 @@ struct devfreq_dev_status {
/** /**
* struct devfreq_dev_profile - Devfreq's user device profile * struct devfreq_dev_profile - Devfreq's user device profile
* @initial_freq The operating frequency when devfreq_add_device() is * @initial_freq: The operating frequency when devfreq_add_device() is
* called. * called.
* @polling_ms The polling interval in ms. 0 disables polling. * @polling_ms: The polling interval in ms. 0 disables polling.
* @target The device should set its operating frequency at * @target: The device should set its operating frequency at
* freq or lowest-upper-than-freq value. If freq is * freq or lowest-upper-than-freq value. If freq is
* higher than any operable frequency, set maximum. * higher than any operable frequency, set maximum.
* Before returning, target function should set * Before returning, target function should set
* freq at the current frequency. * freq at the current frequency.
* The "flags" parameter's possible values are * The "flags" parameter's possible values are
* explained above with "DEVFREQ_FLAG_*" macros. * explained above with "DEVFREQ_FLAG_*" macros.
* @get_dev_status The device should provide the current performance * @get_dev_status: The device should provide the current performance
* status to devfreq, which is used by governors. * status to devfreq, which is used by governors.
* @exit An optional callback that is called when devfreq * @get_cur_freq: The device should provide the current frequency
* at which it is operating.
* @exit: An optional callback that is called when devfreq
* is removing the devfreq object due to error or * is removing the devfreq object due to error or
* from devfreq_remove_device() call. If the user * from devfreq_remove_device() call. If the user
* has registered devfreq->nb at a notifier-head, * has registered devfreq->nb at a notifier-head,
* this is the time to unregister it. * this is the time to unregister it.
* @freq_table: Optional list of frequencies to support statistics.
* @max_state: The size of freq_table.
*/ */
struct devfreq_dev_profile { struct devfreq_dev_profile {
unsigned long initial_freq; unsigned long initial_freq;
@ -79,63 +83,63 @@ struct devfreq_dev_profile {
int (*target)(struct device *dev, unsigned long *freq, u32 flags); int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev, int (*get_dev_status)(struct device *dev,
struct devfreq_dev_status *stat); struct devfreq_dev_status *stat);
int (*get_cur_freq)(struct device *dev, unsigned long *freq);
void (*exit)(struct device *dev); void (*exit)(struct device *dev);
unsigned int *freq_table;
unsigned int max_state;
}; };
/** /**
* struct devfreq_governor - Devfreq policy governor * struct devfreq_governor - Devfreq policy governor
* @name Governor's name * @node: list node - contains registered devfreq governors
* @get_target_freq Returns desired operating frequency for the device. * @name: Governor's name
* @get_target_freq: Returns desired operating frequency for the device.
* Basically, get_target_freq will run * Basically, get_target_freq will run
* devfreq_dev_profile.get_dev_status() to get the * devfreq_dev_profile.get_dev_status() to get the
* status of the device (load = busy_time / total_time). * status of the device (load = busy_time / total_time).
* If no_central_polling is set, this callback is called * If no_central_polling is set, this callback is called
* only with update_devfreq() notified by OPP. * only with update_devfreq() notified by OPP.
* @init Called when the devfreq is being attached to a device * @event_handler: Callback for devfreq core framework to notify events
* @exit Called when the devfreq is being removed from a * to governors. Events include per device governor
* device. Governor should stop any internal routines * init and exit, opp changes out of devfreq, suspend
* before return because related data may be * and resume of per device devfreq during device idle.
* freed after exit().
* @no_central_polling Do not use devfreq's central polling mechanism.
* When this is set, devfreq will not call
* get_target_freq with devfreq_monitor(). However,
* devfreq will call get_target_freq with
* devfreq_update() notified by OPP framework.
* *
* Note that the callbacks are called with devfreq->lock locked by devfreq. * Note that the callbacks are called with devfreq->lock locked by devfreq.
*/ */
struct devfreq_governor { struct devfreq_governor {
struct list_head node;
const char name[DEVFREQ_NAME_LEN]; const char name[DEVFREQ_NAME_LEN];
int (*get_target_freq)(struct devfreq *this, unsigned long *freq); int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
int (*init)(struct devfreq *this); int (*event_handler)(struct devfreq *devfreq,
void (*exit)(struct devfreq *this); unsigned int event, void *data);
const bool no_central_polling;
}; };
/** /**
* struct devfreq - Device devfreq structure * struct devfreq - Device devfreq structure
* @node list node - contains the devices with devfreq that have been * @node: list node - contains the devices with devfreq that have been
* registered. * registered.
* @lock a mutex to protect accessing devfreq. * @lock: a mutex to protect accessing devfreq.
* @dev device registered by devfreq class. dev.parent is the device * @dev: device registered by devfreq class. dev.parent is the device
* using devfreq. * using devfreq.
* @profile device-specific devfreq profile * @profile: device-specific devfreq profile
* @governor method how to choose frequency based on the usage. * @governor: method how to choose frequency based on the usage.
* @nb notifier block used to notify devfreq object that it should * @governor_name: devfreq governor name for use with this devfreq
* @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use * reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain. * devfreq.nb to the corresponding register notifier call chain.
* @polling_jiffies interval in jiffies. * @work: delayed work for load monitoring.
* @previous_freq previously configured frequency value. * @previous_freq: previously configured frequency value.
* @next_polling the number of remaining jiffies to poll with * @data: Private data of the governor. The devfreq framework does not
* "devfreq_monitor" executions to reevaluate
* frequency/voltage of the device. Set by
* profile's polling_ms interval.
* @data Private data of the governor. The devfreq framework does not
* touch this. * touch this.
* @being_removed a flag to mark that this object is being removed in * @min_freq: Limit minimum frequency requested by user (0: none)
* order to prevent trying to remove the object multiple times. * @max_freq: Limit maximum frequency requested by user (0: none)
* @min_freq Limit minimum frequency requested by user (0: none) * @stop_polling: devfreq polling status of a device.
* @max_freq Limit maximum frequency requested by user (0: none) * @total_trans: Number of devfreq transitions
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* *
* This structure stores the devfreq information for a give device. * This structure stores the devfreq information for a give device.
* *
@ -152,26 +156,33 @@ struct devfreq {
struct device dev; struct device dev;
struct devfreq_dev_profile *profile; struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor; const struct devfreq_governor *governor;
char governor_name[DEVFREQ_NAME_LEN];
struct notifier_block nb; struct notifier_block nb;
struct delayed_work work;
unsigned long polling_jiffies;
unsigned long previous_freq; unsigned long previous_freq;
unsigned int next_polling;
void *data; /* private data for governors */ void *data; /* private data for governors */
bool being_removed;
unsigned long min_freq; unsigned long min_freq;
unsigned long max_freq; unsigned long max_freq;
bool stop_polling;
/* information for device freqeuncy transition */
unsigned int total_trans;
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
}; };
#if defined(CONFIG_PM_DEVFREQ) #if defined(CONFIG_PM_DEVFREQ)
extern struct devfreq *devfreq_add_device(struct device *dev, extern struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile, struct devfreq_dev_profile *profile,
const struct devfreq_governor *governor, const char *governor_name,
void *data); void *data);
extern int devfreq_remove_device(struct devfreq *devfreq); extern int devfreq_remove_device(struct devfreq *devfreq);
extern int devfreq_suspend_device(struct devfreq *devfreq);
extern int devfreq_resume_device(struct devfreq *devfreq);
/* Helper functions for devfreq user device driver with OPP. */ /* Helper functions for devfreq user device driver with OPP. */
extern struct opp *devfreq_recommended_opp(struct device *dev, extern struct opp *devfreq_recommended_opp(struct device *dev,
@ -181,23 +192,13 @@ extern int devfreq_register_opp_notifier(struct device *dev,
extern int devfreq_unregister_opp_notifier(struct device *dev, extern int devfreq_unregister_opp_notifier(struct device *dev,
struct devfreq *devfreq); struct devfreq *devfreq);
#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
extern const struct devfreq_governor devfreq_powersave;
#endif
#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE
extern const struct devfreq_governor devfreq_performance;
#endif
#ifdef CONFIG_DEVFREQ_GOV_USERSPACE
extern const struct devfreq_governor devfreq_userspace;
#endif
#ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND
extern const struct devfreq_governor devfreq_simple_ondemand;
/** /**
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
* and devfreq_add_device * and devfreq_add_device
* @ upthreshold If the load is over this value, the frequency jumps. * @upthreshold: If the load is over this value, the frequency jumps.
* Specify 0 to use the default. Valid value = 0 to 100. * Specify 0 to use the default. Valid value = 0 to 100.
* @ downdifferential If the load is under upthreshold - downdifferential, * @downdifferential: If the load is under upthreshold - downdifferential,
* the governor may consider slowing the frequency down. * the governor may consider slowing the frequency down.
* Specify 0 to use the default. Valid value = 0 to 100. * Specify 0 to use the default. Valid value = 0 to 100.
* downdifferential < upthreshold must hold. * downdifferential < upthreshold must hold.
@ -214,7 +215,7 @@ struct devfreq_simple_ondemand_data {
#else /* !CONFIG_PM_DEVFREQ */ #else /* !CONFIG_PM_DEVFREQ */
static struct devfreq *devfreq_add_device(struct device *dev, static struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile, struct devfreq_dev_profile *profile,
struct devfreq_governor *governor, const char *governor_name,
void *data) void *data)
{ {
return NULL; return NULL;
@ -225,6 +226,16 @@ static int devfreq_remove_device(struct devfreq *devfreq)
return 0; return 0;
} }
static int devfreq_suspend_device(struct devfreq *devfreq)
{
return 0;
}
static int devfreq_resume_device(struct devfreq *devfreq)
{
return 0;
}
static struct opp *devfreq_recommended_opp(struct device *dev, static struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq, u32 flags) unsigned long *freq, u32 flags)
{ {
@ -243,11 +254,6 @@ static int devfreq_unregister_opp_notifier(struct device *dev,
return -EINVAL; return -EINVAL;
} }
#define devfreq_powersave NULL
#define devfreq_performance NULL
#define devfreq_userspace NULL
#define devfreq_simple_ondemand NULL
#endif /* CONFIG_PM_DEVFREQ */ #endif /* CONFIG_PM_DEVFREQ */
#endif /* __LINUX_DEVFREQ_H__ */ #endif /* __LINUX_DEVFREQ_H__ */