aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2011-12-09 02:42:19 -0500
committerMyungJoo Ham <myungjoo.ham@samsung.com>2012-01-19 20:12:38 -0500
commit6530b9dea1b7f33eaf79ba625e3a99f2455f3eb1 (patch)
tree70beddf04779d5941ba6ef851b30e02c7fa0c86c /drivers/devfreq
parenta95e1f5dbca385908aa4087bb98470b0e0ac58d8 (diff)
PM / devfreq: add min/max_freq limit requested by users.
The frequency requested to devfreq device driver from devfreq governors is restricted by min_freq and max_freq input. Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/devfreq.c70
-rw-r--r--drivers/devfreq/governor_performance.c5
-rw-r--r--drivers/devfreq/governor_powersave.c2
-rw-r--r--drivers/devfreq/governor_simpleondemand.c12
-rw-r--r--drivers/devfreq/governor_userspace.c15
5 files changed, 96 insertions, 8 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index c189b82f5ec..a129a7b6bfd 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -501,12 +501,82 @@ static ssize_t show_central_polling(struct device *dev,
501 !to_devfreq(dev)->governor->no_central_polling); 501 !to_devfreq(dev)->governor->no_central_polling);
502} 502}
503 503
504static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
505 const char *buf, size_t count)
506{
507 struct devfreq *df = to_devfreq(dev);
508 unsigned long value;
509 int ret;
510 unsigned long max;
511
512 ret = sscanf(buf, "%lu", &value);
513 if (ret != 1)
514 goto out;
515
516 mutex_lock(&df->lock);
517 max = df->max_freq;
518 if (value && max && value > max) {
519 ret = -EINVAL;
520 goto unlock;
521 }
522
523 df->min_freq = value;
524 update_devfreq(df);
525 ret = count;
526unlock:
527 mutex_unlock(&df->lock);
528out:
529 return ret;
530}
531
532static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr,
533 char *buf)
534{
535 return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq);
536}
537
538static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr,
539 const char *buf, size_t count)
540{
541 struct devfreq *df = to_devfreq(dev);
542 unsigned long value;
543 int ret;
544 unsigned long min;
545
546 ret = sscanf(buf, "%lu", &value);
547 if (ret != 1)
548 goto out;
549
550 mutex_lock(&df->lock);
551 min = df->min_freq;
552 if (value && min && value < min) {
553 ret = -EINVAL;
554 goto unlock;
555 }
556
557 df->max_freq = value;
558 update_devfreq(df);
559 ret = count;
560unlock:
561 mutex_unlock(&df->lock);
562out:
563 return ret;
564}
565
566static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr,
567 char *buf)
568{
569 return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
570}
571
504static struct device_attribute devfreq_attrs[] = { 572static struct device_attribute devfreq_attrs[] = {
505 __ATTR(governor, S_IRUGO, show_governor, NULL), 573 __ATTR(governor, S_IRUGO, show_governor, NULL),
506 __ATTR(cur_freq, S_IRUGO, show_freq, NULL), 574 __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
507 __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), 575 __ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
508 __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, 576 __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
509 store_polling_interval), 577 store_polling_interval),
578 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
579 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
510 { }, 580 { },
511}; 581};
512 582
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index c0596b29176..574a06b1b1d 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -18,7 +18,10 @@ static int devfreq_performance_func(struct devfreq *df,
18 * target callback should be able to get floor value as 18 * target callback should be able to get floor value as
19 * said in devfreq.h 19 * said in devfreq.h
20 */ 20 */
21 *freq = UINT_MAX; 21 if (!df->max_freq)
22 *freq = UINT_MAX;
23 else
24 *freq = df->max_freq;
22 return 0; 25 return 0;
23} 26}
24 27
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 2483a85a266..d742d4a82d6 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -18,7 +18,7 @@ static int devfreq_powersave_func(struct devfreq *df,
18 * target callback should be able to get ceiling value as 18 * target callback should be able to get ceiling value as
19 * said in devfreq.h 19 * said in devfreq.h
20 */ 20 */
21 *freq = 0; 21 *freq = df->min_freq;
22 return 0; 22 return 0;
23} 23}
24 24
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index efad8dcf902..a2e3eae7901 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -25,6 +25,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
25 unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; 25 unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
26 unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; 26 unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
27 struct devfreq_simple_ondemand_data *data = df->data; 27 struct devfreq_simple_ondemand_data *data = df->data;
28 unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
28 29
29 if (err) 30 if (err)
30 return err; 31 return err;
@@ -41,7 +42,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
41 42
42 /* Assume MAX if it is going to be divided by zero */ 43 /* Assume MAX if it is going to be divided by zero */
43 if (stat.total_time == 0) { 44 if (stat.total_time == 0) {
44 *freq = UINT_MAX; 45 *freq = max;
45 return 0; 46 return 0;
46 } 47 }
47 48
@@ -54,13 +55,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
54 /* Set MAX if it's busy enough */ 55 /* Set MAX if it's busy enough */
55 if (stat.busy_time * 100 > 56 if (stat.busy_time * 100 >
56 stat.total_time * dfso_upthreshold) { 57 stat.total_time * dfso_upthreshold) {
57 *freq = UINT_MAX; 58 *freq = max;
58 return 0; 59 return 0;
59 } 60 }
60 61
61 /* Set MAX if we do not know the initial frequency */ 62 /* Set MAX if we do not know the initial frequency */
62 if (stat.current_frequency == 0) { 63 if (stat.current_frequency == 0) {
63 *freq = UINT_MAX; 64 *freq = max;
64 return 0; 65 return 0;
65 } 66 }
66 67
@@ -79,6 +80,11 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
79 b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); 80 b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
80 *freq = (unsigned long) b; 81 *freq = (unsigned long) b;
81 82
83 if (df->min_freq && *freq < df->min_freq)
84 *freq = df->min_freq;
85 if (df->max_freq && *freq > df->max_freq)
86 *freq = df->max_freq;
87
82 return 0; 88 return 0;
83} 89}
84 90
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 4f8b563da78..0681246fc89 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -25,10 +25,19 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
25{ 25{
26 struct userspace_data *data = df->data; 26 struct userspace_data *data = df->data;
27 27
28 if (!data->valid) 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 {
29 *freq = df->previous_freq; /* No user freq specified yet */ 39 *freq = df->previous_freq; /* No user freq specified yet */
30 else 40 }
31 *freq = data->user_frequency;
32 return 0; 41 return 0;
33} 42}
34 43