• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "governor.h"
18  
19  struct userspace_data {
20  	unsigned long user_frequency;
21  	bool valid;
22  };
23  
devfreq_userspace_func(struct devfreq * df,unsigned long * freq)24  static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
25  {
26  	struct userspace_data *data = df->data;
27  
28  	if (data->valid) {
29  		unsigned long adjusted_freq = data->user_frequency;
30  
31  		if (df->max_freq && adjusted_freq > df->max_freq)
32  			adjusted_freq = df->max_freq;
33  
34  		if (df->min_freq && adjusted_freq < df->min_freq)
35  			adjusted_freq = df->min_freq;
36  
37  		*freq = adjusted_freq;
38  	} else {
39  		*freq = df->previous_freq; /* No user freq specified yet */
40  	}
41  	return 0;
42  }
43  
store_freq(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)44  static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
45  			  const char *buf, size_t count)
46  {
47  	struct devfreq *devfreq = to_devfreq(dev);
48  	struct userspace_data *data;
49  	unsigned long wanted;
50  	int err = 0;
51  
52  
53  	mutex_lock(&devfreq->lock);
54  	data = devfreq->data;
55  
56  	sscanf(buf, "%lu", &wanted);
57  	data->user_frequency = wanted;
58  	data->valid = true;
59  	err = update_devfreq(devfreq);
60  	if (err == 0)
61  		err = count;
62  	mutex_unlock(&devfreq->lock);
63  	return err;
64  }
65  
show_freq(struct device * dev,struct device_attribute * attr,char * buf)66  static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
67  			 char *buf)
68  {
69  	struct devfreq *devfreq = to_devfreq(dev);
70  	struct userspace_data *data;
71  	int err = 0;
72  
73  	mutex_lock(&devfreq->lock);
74  	data = devfreq->data;
75  
76  	if (data->valid)
77  		err = sprintf(buf, "%lu\n", data->user_frequency);
78  	else
79  		err = sprintf(buf, "undefined\n");
80  	mutex_unlock(&devfreq->lock);
81  	return err;
82  }
83  
84  static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
85  static struct attribute *dev_entries[] = {
86  	&dev_attr_set_freq.attr,
87  	NULL,
88  };
89  static struct attribute_group dev_attr_group = {
90  	.name	= "userspace",
91  	.attrs	= dev_entries,
92  };
93  
userspace_init(struct devfreq * devfreq)94  static int userspace_init(struct devfreq *devfreq)
95  {
96  	int err = 0;
97  	struct userspace_data *data = kzalloc(sizeof(struct userspace_data),
98  					      GFP_KERNEL);
99  
100  	if (!data) {
101  		err = -ENOMEM;
102  		goto out;
103  	}
104  	data->valid = false;
105  	devfreq->data = data;
106  
107  	err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
108  out:
109  	return err;
110  }
111  
userspace_exit(struct devfreq * devfreq)112  static void userspace_exit(struct devfreq *devfreq)
113  {
114  	sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
115  	kfree(devfreq->data);
116  	devfreq->data = NULL;
117  }
118  
119  const struct devfreq_governor devfreq_userspace = {
120  	.name = "userspace",
121  	.get_target_freq = devfreq_userspace_func,
122  	.init = userspace_init,
123  	.exit = userspace_exit,
124  	.no_central_polling = true,
125  };
126