1ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham/* 2ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * linux/drivers/devfreq/governor_simpleondemand.c 3ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * 4ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * Copyright (C) 2011 Samsung Electronics 5ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * MyungJoo Ham <myungjoo.ham@samsung.com> 6ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * 7ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * This program is free software; you can redistribute it and/or modify 8ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * it under the terms of the GNU General Public License version 2 as 9ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham * published by the Free Software Foundation. 10ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham */ 11ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 12ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include <linux/slab.h> 13ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include <linux/device.h> 14ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include <linux/devfreq.h> 15ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include <linux/pm.h> 16ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include <linux/mutex.h> 17ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham#include "governor.h" 18ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 19ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstruct userspace_data { 20ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham unsigned long user_frequency; 21ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham bool valid; 22ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham}; 23ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 24ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) 25ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham{ 26ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct userspace_data *data = df->data; 27ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 286530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham if (data->valid) { 296530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham unsigned long adjusted_freq = data->user_frequency; 306530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham 316530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham if (df->max_freq && adjusted_freq > df->max_freq) 326530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham adjusted_freq = df->max_freq; 336530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham 346530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham if (df->min_freq && adjusted_freq < df->min_freq) 356530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham adjusted_freq = df->min_freq; 366530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham 376530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham *freq = adjusted_freq; 386530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham } else { 39ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham *freq = df->previous_freq; /* No user freq specified yet */ 406530b9dea1b7f33eaf79ba625e3a99f2455f3eb1MyungJoo Ham } 41ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham return 0; 42ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham} 43ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 44ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic ssize_t store_freq(struct device *dev, struct device_attribute *attr, 45ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham const char *buf, size_t count) 46ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham{ 47ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct devfreq *devfreq = to_devfreq(dev); 48ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct userspace_data *data; 49ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham unsigned long wanted; 50ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham int err = 0; 51ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 52ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 53ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham mutex_lock(&devfreq->lock); 54ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham data = devfreq->data; 55ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 56ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham sscanf(buf, "%lu", &wanted); 57ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham data->user_frequency = wanted; 58ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham data->valid = true; 59ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = update_devfreq(devfreq); 60ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham if (err == 0) 61ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = count; 62ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham mutex_unlock(&devfreq->lock); 63ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham return err; 64ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham} 65ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 66ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic ssize_t show_freq(struct device *dev, struct device_attribute *attr, 67ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham char *buf) 68ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham{ 69ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct devfreq *devfreq = to_devfreq(dev); 70ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct userspace_data *data; 71ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham int err = 0; 72ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 73ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham mutex_lock(&devfreq->lock); 74ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham data = devfreq->data; 75ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 76ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham if (data->valid) 77ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = sprintf(buf, "%lu\n", data->user_frequency); 78ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham else 79ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = sprintf(buf, "undefined\n"); 80ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham mutex_unlock(&devfreq->lock); 81ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham return err; 82ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham} 83ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 84ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic DEVICE_ATTR(set_freq, 0644, show_freq, store_freq); 85ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic struct attribute *dev_entries[] = { 86ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham &dev_attr_set_freq.attr, 87ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham NULL, 88ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham}; 89ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic struct attribute_group dev_attr_group = { 90ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .name = "userspace", 91ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .attrs = dev_entries, 92ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham}; 93ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 94ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic int userspace_init(struct devfreq *devfreq) 95ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham{ 96ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham int err = 0; 97ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham struct userspace_data *data = kzalloc(sizeof(struct userspace_data), 98ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham GFP_KERNEL); 99ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 100ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham if (!data) { 101ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = -ENOMEM; 102ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham goto out; 103ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham } 104ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham data->valid = false; 105ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham devfreq->data = data; 106ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 107ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group); 108ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamout: 109ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham return err; 110ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham} 111ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 112ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamstatic void userspace_exit(struct devfreq *devfreq) 113ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham{ 114ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); 115ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham kfree(devfreq->data); 116ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham devfreq->data = NULL; 117ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham} 118ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham 119ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Hamconst struct devfreq_governor devfreq_userspace = { 120ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .name = "userspace", 121ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .get_target_freq = devfreq_userspace_func, 122ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .init = userspace_init, 123ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .exit = userspace_exit, 124ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham .no_central_polling = true, 125ce26c5bb9569d8b826f01b8620fc16d8da6821e9MyungJoo Ham}; 126