linux/drivers/devfreq/governor_userspace.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/devfreq/governor_simpleondemand.c
   3 *
   4 *  Copyright (C) 2011 Samsung Electronics
   5 *      MyungJoo Ham <myungjoo.ham@samsung.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/slab.h>
  13#include <linux/device.h>
  14#include <linux/devfreq.h>
  15#include <linux/pm.h>
  16#include <linux/mutex.h>
  17#include <linux/module.h>
  18#include "governor.h"
  19
  20struct userspace_data {
  21        unsigned long user_frequency;
  22        bool valid;
  23};
  24
  25static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
  26{
  27        struct userspace_data *data = df->data;
  28
  29        if (data->valid) {
  30                unsigned long adjusted_freq = data->user_frequency;
  31
  32                if (df->max_freq && adjusted_freq > df->max_freq)
  33                        adjusted_freq = df->max_freq;
  34
  35                if (df->min_freq && adjusted_freq < df->min_freq)
  36                        adjusted_freq = df->min_freq;
  37
  38                *freq = adjusted_freq;
  39        } else {
  40                *freq = df->previous_freq; /* No user freq specified yet */
  41        }
  42        return 0;
  43}
  44
  45static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
  46                          const char *buf, size_t count)
  47{
  48        struct devfreq *devfreq = to_devfreq(dev);
  49        struct userspace_data *data;
  50        unsigned long wanted;
  51        int err = 0;
  52
  53
  54        mutex_lock(&devfreq->lock);
  55        data = devfreq->data;
  56
  57        sscanf(buf, "%lu", &wanted);
  58        data->user_frequency = wanted;
  59        data->valid = true;
  60        err = update_devfreq(devfreq);
  61        if (err == 0)
  62                err = count;
  63        mutex_unlock(&devfreq->lock);
  64        return err;
  65}
  66
  67static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
  68                         char *buf)
  69{
  70        struct devfreq *devfreq = to_devfreq(dev);
  71        struct userspace_data *data;
  72        int err = 0;
  73
  74        mutex_lock(&devfreq->lock);
  75        data = devfreq->data;
  76
  77        if (data->valid)
  78                err = sprintf(buf, "%lu\n", data->user_frequency);
  79        else
  80                err = sprintf(buf, "undefined\n");
  81        mutex_unlock(&devfreq->lock);
  82        return err;
  83}
  84
  85static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
  86static struct attribute *dev_entries[] = {
  87        &dev_attr_set_freq.attr,
  88        NULL,
  89};
  90static struct attribute_group dev_attr_group = {
  91        .name   = "userspace",
  92        .attrs  = dev_entries,
  93};
  94
  95static int userspace_init(struct devfreq *devfreq)
  96{
  97        int err = 0;
  98        struct userspace_data *data = kzalloc(sizeof(struct userspace_data),
  99                                              GFP_KERNEL);
 100
 101        if (!data) {
 102                err = -ENOMEM;
 103                goto out;
 104        }
 105        data->valid = false;
 106        devfreq->data = data;
 107
 108        err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
 109out:
 110        return err;
 111}
 112
 113static void userspace_exit(struct devfreq *devfreq)
 114{
 115        sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
 116        kfree(devfreq->data);
 117        devfreq->data = NULL;
 118}
 119
 120static int devfreq_userspace_handler(struct devfreq *devfreq,
 121                        unsigned int event, void *data)
 122{
 123        int ret = 0;
 124
 125        switch (event) {
 126        case DEVFREQ_GOV_START:
 127                ret = userspace_init(devfreq);
 128                break;
 129        case DEVFREQ_GOV_STOP:
 130                userspace_exit(devfreq);
 131                break;
 132        default:
 133                break;
 134        }
 135
 136        return ret;
 137}
 138
 139static struct devfreq_governor devfreq_userspace = {
 140        .name = "userspace",
 141        .get_target_freq = devfreq_userspace_func,
 142        .event_handler = devfreq_userspace_handler,
 143};
 144
 145static int __init devfreq_userspace_init(void)
 146{
 147        return devfreq_add_governor(&devfreq_userspace);
 148}
 149subsys_initcall(devfreq_userspace_init);
 150
 151static void __exit devfreq_userspace_exit(void)
 152{
 153        int ret;
 154
 155        ret = devfreq_remove_governor(&devfreq_userspace);
 156        if (ret)
 157                pr_err("%s: failed remove governor %d\n", __func__, ret);
 158
 159        return;
 160}
 161module_exit(devfreq_userspace_exit);
 162MODULE_LICENSE("GPL");
 163