aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2012-10-29 16:01:43 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2012-11-20 04:46:12 -0500
commit3aa173b8db200bb96354481acc0a5b9e123119fe (patch)
treef24511e8b86dd4c482f8551317363ed07fb327a6
parent2df5021fa9738905e8b1ab92fa0cd685430f54da (diff)
PM / devfreq: provide hooks for governors to be registered
Add devfreq_add_governor and devfreq_remove_governor which can be invoked by governors to register with devfreq. This sets up the stage to dynamically switch governors and allow governors to be dynamically loaded as well. Cc: Rajagopal Venkat <rajagopal.venkat@linaro.org> Cc: MyungJoo Ham <myungjoo.ham@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: Kevin Hilman <khilman@ti.com> Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon <nm@ti.com> Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
-rw-r--r--drivers/devfreq/devfreq.c91
-rw-r--r--drivers/devfreq/governor.h4
-rw-r--r--include/linux/devfreq.h3
3 files changed, 98 insertions, 0 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index e0002c5cbadc..679ac424472f 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -36,6 +36,8 @@ static struct class *devfreq_class;
36 */ 36 */
37static struct workqueue_struct *devfreq_wq; 37static struct workqueue_struct *devfreq_wq;
38 38
39/* The list of all device-devfreq governors */
40static LIST_HEAD(devfreq_governor_list);
39/* The list of all device-devfreq */ 41/* The list of all device-devfreq */
40static LIST_HEAD(devfreq_list); 42static LIST_HEAD(devfreq_list);
41static DEFINE_MUTEX(devfreq_list_lock); 43static DEFINE_MUTEX(devfreq_list_lock);
@@ -111,6 +113,32 @@ static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
111 return 0; 113 return 0;
112} 114}
113 115
116/**
117 * find_devfreq_governor() - find devfreq governor from name
118 * @name: name of the governor
119 *
120 * Search the list of devfreq governors and return the matched
121 * governor's pointer. devfreq_list_lock should be held by the caller.
122 */
123static struct devfreq_governor *find_devfreq_governor(const char *name)
124{
125 struct devfreq_governor *tmp_governor;
126
127 if (unlikely(IS_ERR_OR_NULL(name))) {
128 pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
129 return ERR_PTR(-EINVAL);
130 }
131 WARN(!mutex_is_locked(&devfreq_list_lock),
132 "devfreq_list_lock must be locked.");
133
134 list_for_each_entry(tmp_governor, &devfreq_governor_list, node) {
135 if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN))
136 return tmp_governor;
137 }
138
139 return ERR_PTR(-ENODEV);
140}
141
114/* Load monitoring helper functions for governors use */ 142/* Load monitoring helper functions for governors use */
115 143
116/** 144/**
@@ -515,6 +543,69 @@ int devfreq_resume_device(struct devfreq *devfreq)
515} 543}
516EXPORT_SYMBOL(devfreq_resume_device); 544EXPORT_SYMBOL(devfreq_resume_device);
517 545
546/**
547 * devfreq_add_governor() - Add devfreq governor
548 * @governor: the devfreq governor to be added
549 */
550int devfreq_add_governor(struct devfreq_governor *governor)
551{
552 struct devfreq_governor *g;
553 int err = 0;
554
555 if (!governor) {
556 pr_err("%s: Invalid parameters.\n", __func__);
557 return -EINVAL;
558 }
559
560 mutex_lock(&devfreq_list_lock);
561 g = find_devfreq_governor(governor->name);
562 if (!IS_ERR(g)) {
563 pr_err("%s: governor %s already registered\n", __func__,
564 g->name);
565 err = -EINVAL;
566 goto err_out;
567 }
568
569 list_add(&governor->node, &devfreq_governor_list);
570
571err_out:
572 mutex_unlock(&devfreq_list_lock);
573
574 return err;
575}
576EXPORT_SYMBOL(devfreq_add_governor);
577
578/**
579 * devfreq_remove_device() - Remove devfreq feature from a device.
580 * @governor: the devfreq governor to be removed
581 */
582int devfreq_remove_governor(struct devfreq_governor *governor)
583{
584 struct devfreq_governor *g;
585 int err = 0;
586
587 if (!governor) {
588 pr_err("%s: Invalid parameters.\n", __func__);
589 return -EINVAL;
590 }
591
592 mutex_lock(&devfreq_list_lock);
593 g = find_devfreq_governor(governor->name);
594 if (IS_ERR(g)) {
595 pr_err("%s: governor %s not registered\n", __func__,
596 g->name);
597 err = -EINVAL;
598 goto err_out;
599 }
600
601 list_del(&governor->node);
602err_out:
603 mutex_unlock(&devfreq_list_lock);
604
605 return err;
606}
607EXPORT_SYMBOL(devfreq_remove_governor);
608
518static ssize_t show_governor(struct device *dev, 609static ssize_t show_governor(struct device *dev,
519 struct device_attribute *attr, char *buf) 610 struct device_attribute *attr, char *buf)
520{ 611{
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
index 26432ac0a398..fad7d6321978 100644
--- a/drivers/devfreq/governor.h
+++ b/drivers/devfreq/governor.h
@@ -34,4 +34,8 @@ extern void devfreq_monitor_suspend(struct devfreq *devfreq);
34extern void devfreq_monitor_resume(struct devfreq *devfreq); 34extern void devfreq_monitor_resume(struct devfreq *devfreq);
35extern void devfreq_interval_update(struct devfreq *devfreq, 35extern void devfreq_interval_update(struct devfreq *devfreq,
36 unsigned int *delay); 36 unsigned int *delay);
37
38extern int devfreq_add_governor(struct devfreq_governor *governor);
39extern int devfreq_remove_governor(struct devfreq_governor *governor);
40
37#endif /* _GOVERNOR_H */ 41#endif /* _GOVERNOR_H */
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index bc35c4aee6a3..6484a3f8dda8 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -92,6 +92,7 @@ struct devfreq_dev_profile {
92 92
93/** 93/**
94 * struct devfreq_governor - Devfreq policy governor 94 * struct devfreq_governor - Devfreq policy governor
95 * @node: list node - contains registered devfreq governors
95 * @name: Governor's name 96 * @name: Governor's name
96 * @get_target_freq: Returns desired operating frequency for the device. 97 * @get_target_freq: Returns desired operating frequency for the device.
97 * Basically, get_target_freq will run 98 * Basically, get_target_freq will run
@@ -107,6 +108,8 @@ struct devfreq_dev_profile {
107 * Note that the callbacks are called with devfreq->lock locked by devfreq. 108 * Note that the callbacks are called with devfreq->lock locked by devfreq.
108 */ 109 */
109struct devfreq_governor { 110struct devfreq_governor {
111 struct list_head node;
112
110 const char name[DEVFREQ_NAME_LEN]; 113 const char name[DEVFREQ_NAME_LEN];
111 int (*get_target_freq)(struct devfreq *this, unsigned long *freq); 114 int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
112 int (*event_handler)(struct devfreq *devfreq, 115 int (*event_handler)(struct devfreq *devfreq,