aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/devfreq/Kconfig39
-rw-r--r--drivers/devfreq/Makefile1
-rw-r--r--drivers/devfreq/devfreq.c532
-rw-r--r--drivers/devfreq/governor.h24
-rw-r--r--include/linux/devfreq.h203
7 files changed, 803 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9e7eefadc..a1efd75070aa 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -130,4 +130,6 @@ source "drivers/iommu/Kconfig"
130 130
131source "drivers/virt/Kconfig" 131source "drivers/virt/Kconfig"
132 132
133source "drivers/devfreq/Kconfig"
134
133endmenu 135endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7fa433a7030c..97c957b50819 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -127,3 +127,5 @@ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
127 127
128# Virtualization drivers 128# Virtualization drivers
129obj-$(CONFIG_VIRT_DRIVERS) += virt/ 129obj-$(CONFIG_VIRT_DRIVERS) += virt/
130
131obj-$(CONFIG_PM_DEVFREQ) += devfreq/
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
new file mode 100644
index 000000000000..1fb42de4f420
--- /dev/null
+++ b/drivers/devfreq/Kconfig
@@ -0,0 +1,39 @@
1config ARCH_HAS_DEVFREQ
2 bool
3 depends on ARCH_HAS_OPP
4 help
5 Denotes that the architecture supports DEVFREQ. If the architecture
6 supports multiple OPP entries per device and the frequency of the
7 devices with OPPs may be altered dynamically, the architecture
8 supports DEVFREQ.
9
10menuconfig PM_DEVFREQ
11 bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
12 depends on PM_OPP && ARCH_HAS_DEVFREQ
13 help
14 With OPP support, a device may have a list of frequencies and
15 voltages available. DEVFREQ, a generic DVFS framework can be
16 registered for a device with OPP support in order to let the
17 governor provided to DEVFREQ choose an operating frequency
18 based on the OPP's list and the policy given with DEVFREQ.
19
20 Each device may have its own governor and policy. DEVFREQ can
21 reevaluate the device state periodically and/or based on the
22 OPP list changes (each frequency/voltage pair in OPP may be
23 disabled or enabled).
24
25 Like some CPUs with CPUFREQ, a device may have multiple clocks.
26 However, because the clock frequencies of a single device are
27 determined by the single device's state, an instance of DEVFREQ
28 is attached to a single device and returns a "representative"
29 clock frequency from the OPP of the device, which is also attached
30 to a device by 1-to-1. The device registering DEVFREQ takes the
31 responsiblity to "interpret" the frequency listed in OPP and
32 to set its every clock accordingly with the "target" callback
33 given to DEVFREQ.
34
35if PM_DEVFREQ
36
37comment "DEVFREQ Drivers"
38
39endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
new file mode 100644
index 000000000000..168934a12b38
--- /dev/null
+++ b/drivers/devfreq/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
new file mode 100644
index 000000000000..f3100b19f798
--- /dev/null
+++ b/drivers/devfreq/devfreq.c
@@ -0,0 +1,532 @@
1/*
2 * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
3 * for Non-CPU Devices.
4 *
5 * Copyright (C) 2011 Samsung Electronics
6 * MyungJoo Ham <myungjoo.ham@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/opp.h>
20#include <linux/devfreq.h>
21#include <linux/workqueue.h>
22#include <linux/platform_device.h>
23#include <linux/list.h>
24#include <linux/printk.h>
25#include <linux/hrtimer.h>
26#include "governor.h"
27
28struct class *devfreq_class;
29
30/*
31 * devfreq_work periodically monitors every registered device.
32 * The minimum polling interval is one jiffy. The polling interval is
33 * determined by the minimum polling period among all polling devfreq
34 * devices. The resolution of polling interval is one jiffy.
35 */
36static bool polling;
37static struct workqueue_struct *devfreq_wq;
38static struct delayed_work devfreq_work;
39
40/* wait removing if this is to be removed */
41static struct devfreq *wait_remove_device;
42
43/* The list of all device-devfreq */
44static LIST_HEAD(devfreq_list);
45static DEFINE_MUTEX(devfreq_list_lock);
46
47/**
48 * find_device_devfreq() - find devfreq struct using device pointer
49 * @dev: device pointer used to lookup device devfreq.
50 *
51 * Search the list of device devfreqs and return the matched device's
52 * devfreq info. devfreq_list_lock should be held by the caller.
53 */
54static struct devfreq *find_device_devfreq(struct device *dev)
55{
56 struct devfreq *tmp_devfreq;
57
58 if (unlikely(IS_ERR_OR_NULL(dev))) {
59 pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
60 return ERR_PTR(-EINVAL);
61 }
62 WARN(!mutex_is_locked(&devfreq_list_lock),
63 "devfreq_list_lock must be locked.");
64
65 list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
66 if (tmp_devfreq->dev.parent == dev)
67 return tmp_devfreq;
68 }
69
70 return ERR_PTR(-ENODEV);
71}
72
73/**
74 * update_devfreq() - Reevaluate the device and configure frequency.
75 * @devfreq: the devfreq instance.
76 *
77 * Note: Lock devfreq->lock before calling update_devfreq
78 * This function is exported for governors.
79 */
80int update_devfreq(struct devfreq *devfreq)
81{
82 unsigned long freq;
83 int err = 0;
84
85 if (!mutex_is_locked(&devfreq->lock)) {
86 WARN(true, "devfreq->lock must be locked by the caller.\n");
87 return -EINVAL;
88 }
89
90 /* Reevaluate the proper frequency */
91 err = devfreq->governor->get_target_freq(devfreq, &freq);
92 if (err)
93 return err;
94
95 err = devfreq->profile->target(devfreq->dev.parent, &freq);
96 if (err)
97 return err;
98
99 devfreq->previous_freq = freq;
100 return err;
101}
102
103/**
104 * devfreq_notifier_call() - Notify that the device frequency requirements
105 * has been changed out of devfreq framework.
106 * @nb the notifier_block (supposed to be devfreq->nb)
107 * @type not used
108 * @devp not used
109 *
110 * Called by a notifier that uses devfreq->nb.
111 */
112static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
113 void *devp)
114{
115 struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
116 int ret;
117
118 mutex_lock(&devfreq->lock);
119 ret = update_devfreq(devfreq);
120 mutex_unlock(&devfreq->lock);
121
122 return ret;
123}
124
125/**
126 * _remove_devfreq() - Remove devfreq from the device.
127 * @devfreq: the devfreq struct
128 * @skip: skip calling device_unregister().
129 *
130 * Note that the caller should lock devfreq->lock before calling
131 * this. _remove_devfreq() will unlock it and free devfreq
132 * internally. devfreq_list_lock should be locked by the caller
133