PM / devfreq: allow sysfs governor node to switch governor
authorNishanth Menon <nm@ti.com>
Mon, 29 Oct 2012 20:01:47 +0000 (15:01 -0500)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 20 Nov 2012 09:46:23 +0000 (18:46 +0900)
This allows us to select governor runtime from the
default configuration without having to rebuild kernel
or the devfreq driver using the sysfs node:
/sys/class/devfreq/.../governor
cat of the governor will return valid governor
and an echo 'governor_name'>governor will switch
governor

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>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Documentation/ABI/testing/sysfs-class-devfreq
drivers/devfreq/devfreq.c

index 40f98a9428dce6f3380170e60b6f72e8257c1543..66876debca18473c8912593c0f8fce13068660c3 100644 (file)
@@ -11,7 +11,7 @@ What:         /sys/class/devfreq/.../governor
 Date:          September 2011
 Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
 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.
 
 What:          /sys/class/devfreq/.../cur_freq
index 0d7be03d561f12fea2f769b51bc4840bbb06116a..ff960f084c119632d2ca8a48c868be1c1526bce4 100644 (file)
@@ -688,6 +688,49 @@ static ssize_t show_governor(struct device *dev,
        return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
 }
 
+static ssize_t store_governor(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct devfreq *df = to_devfreq(dev);
+       int ret;
+       char str_governor[DEVFREQ_NAME_LEN + 1];
+       struct devfreq_governor *governor;
+
+       ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
+       if (ret != 1)
+               return -EINVAL;
+
+       mutex_lock(&devfreq_list_lock);
+       governor = find_devfreq_governor(str_governor);
+       if (IS_ERR(governor)) {
+               ret = PTR_ERR(governor);
+               goto out;
+       }
+       if (df->governor == governor)
+               goto out;
+
+       if (df->governor) {
+               ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
+               if (ret) {
+                       dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
+                                __func__, df->governor->name, ret);
+                       goto out;
+               }
+       }
+       df->governor = governor;
+       strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
+       ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
+       if (ret)
+               dev_warn(dev, "%s: Governor %s not started(%d)\n",
+                        __func__, df->governor->name, ret);
+out:
+       mutex_unlock(&devfreq_list_lock);
+
+       if (!ret)
+               ret = count;
+       return ret;
+}
+
 static ssize_t show_freq(struct device *dev,
                         struct device_attribute *attr, char *buf)
 {
@@ -873,7 +916,7 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att
 }
 
 static struct device_attribute devfreq_attrs[] = {
-       __ATTR(governor, S_IRUGO, show_governor, NULL),
+       __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor),
        __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
        __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL),
        __ATTR(target_freq, S_IRUGO, show_target_freq, NULL),