diff options
| -rw-r--r-- | drivers/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/Makefile | 2 | ||||
| -rw-r--r-- | drivers/devfreq/Kconfig | 39 | ||||
| -rw-r--r-- | drivers/devfreq/Makefile | 1 | ||||
| -rw-r--r-- | drivers/devfreq/devfreq.c | 532 | ||||
| -rw-r--r-- | drivers/devfreq/governor.h | 24 | ||||
| -rw-r--r-- | include/linux/devfreq.h | 203 |
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 | ||
| 131 | source "drivers/virt/Kconfig" | 131 | source "drivers/virt/Kconfig" |
| 132 | 132 | ||
| 133 | source "drivers/devfreq/Kconfig" | ||
| 134 | |||
| 133 | endmenu | 135 | endmenu |
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 |
| 129 | obj-$(CONFIG_VIRT_DRIVERS) += virt/ | 129 | obj-$(CONFIG_VIRT_DRIVERS) += virt/ |
| 130 | |||
| 131 | obj-$(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 @@ | |||
| 1 | config 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 | |||
| 10 | menuconfig 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 | |||
| 35 | if PM_DEVFREQ | ||
| 36 | |||
| 37 | comment "DEVFREQ Drivers" | ||
| 38 | |||
| 39 | endif # 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 | |||
| 28 | struct 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 | */ | ||
| 36 | static bool polling; | ||
| 37 | static struct workqueue_struct *devfreq_wq; | ||
| 38 | static struct delayed_work devfreq_work; | ||
| 39 | |||
| 40 | /* wait removing if this is to be removed */ | ||
| 41 | static struct devfreq *wait_remove_device; | ||
| 42 | |||
| 43 | /* The list of all device-devfreq */ | ||
| 44 | static LIST_HEAD(devfreq_list); | ||
| 45 | static 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 | */ | ||
| 54 | static 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 | */ | ||
| 80 | int 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 | */ | ||
| 112 | static 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 | |||
