summaryrefslogtreecommitdiffstats
path: root/patches/linux-3.2.27/0142-Add-cpufreq-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/linux-3.2.27/0142-Add-cpufreq-driver.patch')
-rw-r--r--patches/linux-3.2.27/0142-Add-cpufreq-driver.patch525
1 files changed, 525 insertions, 0 deletions
diff --git a/patches/linux-3.2.27/0142-Add-cpufreq-driver.patch b/patches/linux-3.2.27/0142-Add-cpufreq-driver.patch
new file mode 100644
index 0000000..8e79ba1
--- /dev/null
+++ b/patches/linux-3.2.27/0142-Add-cpufreq-driver.patch
@@ -0,0 +1,525 @@
+From: popcornmix <popcornmix@gmail.com>
+Date: Sun, 9 Sep 2012 23:47:03 +0100
+Subject: [PATCH] Add cpufreq driver
+
+---
+ arch/arm/Kconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 6 +
+ arch/arm/mach-bcm2708/include/mach/vcio.h | 81 +++++++++-
+ arch/arm/mach-bcm2708/vc_mem.c | 47 +++---
+ arch/arm/mach-bcm2708/vcio.c | 34 ++++
+ drivers/cpufreq/Kconfig.arm | 8 +
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/bcm2835-cpufreq.c | 239 +++++++++++++++++++++++++++++
+ 8 files changed, 380 insertions(+), 37 deletions(-)
+ create mode 100755 drivers/cpufreq/bcm2835-cpufreq.c
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 5285fbf..b58af94 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -963,6 +963,7 @@ config ARCH_BCM2708
+ select HAVE_SCHED_CLOCK
+ select NEED_MACH_MEMORY_H
+ select CLKDEV_LOOKUP
++ select ARCH_HAS_CPUFREQ
+ select GENERIC_CLOCKEVENTS
+ select ARM_ERRATA_411920
+ select MACH_BCM2708
+diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
+index 5ed9c30..35c5042 100644
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -46,6 +46,12 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
+ CONFIG_ZBOOT_ROM_BSS=0x0
+ CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait"
+ CONFIG_KEXEC=y
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=m
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+ CONFIG_CPU_IDLE=y
+ CONFIG_VFP=y
+ CONFIG_BINFMT_MISC=m
+diff --git a/arch/arm/mach-bcm2708/include/mach/vcio.h b/arch/arm/mach-bcm2708/include/mach/vcio.h
+index ace4ea4..7dfd14e 100644
+--- a/arch/arm/mach-bcm2708/include/mach/vcio.h
++++ b/arch/arm/mach-bcm2708/include/mach/vcio.h
+@@ -27,17 +27,82 @@
+ #define BCM_VCIO_DRIVER_NAME "bcm2708_vcio"
+
+ /* Constants shared with the ARM identifying separate mailbox channels */
+-#define MBOX_CHAN_POWER 0 /* for use by the power management interface */
+-#define MBOX_CHAN_FB 1 /* for use by the frame buffer */
+-#define MBOX_CHAN_VUART 2 /* for use by the virtual UART */
+-#define MBOX_CHAN_VCHIQ 3 /* for use by the VCHIQ interface */
+-#define MBOX_CHAN_LEDS 4 /* for use by the leds interface */
+-#define MBOX_CHAN_BUTTONS 5 /* for use by the buttons interface */
+-#define MBOX_CHAN_TOUCH 6 /* for use by the touchscreen interface */
++#define MBOX_CHAN_POWER 0 /* for use by the power management interface */
++#define MBOX_CHAN_FB 1 /* for use by the frame buffer */
++#define MBOX_CHAN_VCHIQ 3 /* for use by the VCHIQ interface */
+ #define MBOX_CHAN_PROPERTY 8 /* for use by the property channel */
+-#define MBOX_CHAN_COUNT 9
++#define MBOX_CHAN_COUNT 9
++
++/* Mailbox property tags */
++enum {
++ VCMSG_PROPERTY_END = 0x00000000,
++ VCMSG_GET_FIRMWARE_REVISION = 0x00000001,
++ VCMSG_GET_BOARD_MODEL = 0x00010001,
++ VCMSG_GET_BOARD_REVISION = 0x00020002,
++ VCMSG_GET_BOARD_MAC_ADDRESS = 0x00020003,
++ VCMSG_GET_BOARD_SERIAL = 0x00020004,
++ VCMSG_GET_ARM_MEMORY = 0x00020005,
++ VCMSG_GET_VC_MEMORY = 0x00020006,
++ VCMSG_GET_CLOCKS = 0x00020007,
++ VCMSG_GET_COMMAND_LINE = 0x00050001,
++ VCMSG_GET_DMA_CHANNELS = 0x00060001,
++ VCMSG_GET_POWER_STATE = 0x00020001,
++ VCMSG_GET_TIMING = 0x00020002,
++ VCMSG_SET_POWER_STATE = 0x00028001,
++ VCMSG_GET_CLOCK_STATE = 0x00030001,
++ VCMSG_SET_CLOCK_STATE = 0x00038001,
++ VCMSG_GET_CLOCK_RATE = 0x00030002,
++ VCMSG_SET_CLOCK_RATE = 0x00038002,
++ VCMSG_GET_VOLTAGE = 0x00030003,
++ VCMSG_SET_VOLTAGE = 0x00038003,
++ VCMSG_GET_MAX_CLOCK = 0x00030004,
++ VCMSG_GET_MAX_VOLTAGE = 0x00030005,
++ VCMSG_GET_TEMPERATURE = 0x00030006,
++ VCMSG_GET_MIN_CLOCK = 0x00030007,
++ VCMSG_GET_MIN_VOLTAGE = 0x00030008,
++ VCMSG_GET_TURBO = 0x00030009,
++ VCMSG_SET_TURBO = 0x00038009,
++ VCMSG_SET_ALLOCATE_BUFFER = 0x00040001,
++ VCMSG_SET_RELEASE_BUFFER = 0x00048001,
++ VCMSG_SET_BLANK_SCREEN = 0x00040002,
++ VCMSG_TST_BLANK_SCREEN = 0x00044002,
++ VCMSG_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
++ VCMSG_TST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
++ VCMSG_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
++ VCMSG_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
++ VCMSG_TST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
++ VCMSG_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
++ VCMSG_GET_DEPTH = 0x00040005,
++ VCMSG_TST_DEPTH = 0x00044005,
++ VCMSG_SET_DEPTH = 0x00048005,
++ VCMSG_GET_PIXEL_ORDER = 0x00040006,
++ VCMSG_TST_PIXEL_ORDER = 0x00044006,
++ VCMSG_SET_PIXEL_ORDER = 0x00048006,
++ VCMSG_GET_ALPHA_MODE = 0x00040007,
++ VCMSG_TST_ALPHA_MODE = 0x00044007,
++ VCMSG_SET_ALPHA_MODE = 0x00048007,
++ VCMSG_GET_PITCH = 0x00040008,
++ VCMSG_TST_PITCH = 0x00044008,
++ VCMSG_SET_PITCH = 0x00048008,
++ VCMSG_GET_VIRTUAL_OFFSET = 0x00040009,
++ VCMSG_TST_VIRTUAL_OFFSET = 0x00044009,
++ VCMSG_SET_VIRTUAL_OFFSET = 0x00048009,
++ VCMSG_GET_OVERSCAN = 0x0004000a,
++ VCMSG_TST_OVERSCAN = 0x0004400a,
++ VCMSG_SET_OVERSCAN = 0x0004800a,
++ VCMSG_GET_PALETTE = 0x0004000b,
++ VCMSG_TST_PALETTE = 0x0004400b,
++ VCMSG_SET_PALETTE = 0x0004800b,
++ VCMSG_GET_LAYER = 0x0004000c,
++ VCMSG_TST_LAYER = 0x0004400c,
++ VCMSG_SET_LAYER = 0x0004800c,
++ VCMSG_GET_TRANSFORM = 0x0004000d,
++ VCMSG_TST_TRANSFORM = 0x0004400d,
++ VCMSG_SET_TRANSFORM = 0x0004800d,
++};
+
+ extern int /*rc*/ bcm_mailbox_read(unsigned chan, uint32_t *data28);
+ extern int /*rc*/ bcm_mailbox_write(unsigned chan, uint32_t data28);
++extern int /*rc*/ bcm_mailbox_property(void *data, int size);
+
+ #endif
+diff --git a/arch/arm/mach-bcm2708/vc_mem.c b/arch/arm/mach-bcm2708/vc_mem.c
+index 775c213..ae1810c 100644
+--- a/arch/arm/mach-bcm2708/vc_mem.c
++++ b/arch/arm/mach-bcm2708/vc_mem.c
+@@ -128,44 +128,33 @@ struct vc_set_msg {
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+ };
+
+-#define VCMSG_GET_ARM_MEMORY 0x00010005
+-#define VCMSG_GET_VC_MEMORY 0x00010006
+-
+ static void vc_mem_update(void)
+ {
+- uint32_t success;
+- dma_addr_t vc_mem; /* the memory address accessed from videocore */
+- struct vc_set_msg *get_mem; /* the memory address accessed from driver */
+-
+- /* allocate some memory for the messages to use throughout the lifetime of the driver, use the larger of the two message structures */
+- get_mem = (struct vc_set_msg *)dma_alloc_coherent(NULL, PAGE_ALIGN(sizeof(struct vc_set_msg)), &vc_mem, GFP_ATOMIC);
+- /* clear any garbage */
+- memset(get_mem, 0, sizeof(struct vc_set_msg));
++ struct vc_set_msg msg; /* the memory address accessed from driver */
++ uint32_t s;
++
++ memset(&msg, 0, sizeof msg);
+ /* create the message */
+- get_mem->msg_size = sizeof(struct vc_set_msg);
+- get_mem->tag[0].tag_id = VCMSG_GET_VC_MEMORY;
+- get_mem->tag[0].buffer_size = 8;
+- get_mem->tag[0].data_size = 0;
+- get_mem->tag[1].tag_id = VCMSG_GET_ARM_MEMORY;
+- get_mem->tag[1].buffer_size = 8;
+- get_mem->tag[1].data_size = 0;
++ msg.msg_size = sizeof msg;
++ msg.tag[0].tag_id = VCMSG_GET_VC_MEMORY;
++ msg.tag[0].buffer_size = 8;
++ msg.tag[0].data_size = 0;
++ msg.tag[1].tag_id = VCMSG_GET_ARM_MEMORY;
++ msg.tag[1].buffer_size = 8;
++ msg.tag[1].data_size = 0;
+
+ /* send the message */
+- wmb();
+- bcm_mailbox_write(MBOX_CHAN_PROPERTY,(uint32_t)vc_mem);
+- bcm_mailbox_read(MBOX_CHAN_PROPERTY, &success);
+- rmb();
++ s = bcm_mailbox_property(&msg, sizeof msg);
+
+- LOG_DBG("%s: resp %x, vcbase=%x vcsize=%x armbase=%x armsize=%x", __func__, get_mem->request_code,
+- get_mem->tag[0].base, get_mem->tag[0].size, get_mem->tag[1].base, get_mem->tag[1].size);
++ LOG_DBG("%s: success=%d resp %x, vcbase=%x vcsize=%x armbase=%x armsize=%x", __func__, s, msg.request_code,
++ msg.tag[0].base, msg.tag[0].size, msg.tag[1].base, msg.tag[1].size);
+
+ /* check we're all good */
+- if (get_mem->request_code & 0x80000000) {
+- mm_vc_mem_base = get_mem->tag[0].base;
+- mm_vc_mem_size = get_mem->tag[0].size+get_mem->tag[1].size;
+- mm_vc_mem_phys_addr = get_mem->tag[1].base;
++ if (s == 0 && msg.request_code & 0x80000000) {
++ mm_vc_mem_base = msg.tag[0].base;
++ mm_vc_mem_size = msg.tag[0].size+msg.tag[1].size;
++ mm_vc_mem_phys_addr = msg.tag[1].base;
+ }
+- dma_free_coherent(NULL, PAGE_ALIGN(sizeof(struct vc_set_msg)), (void *)get_mem, vc_mem);
+ }
+
+
+diff --git a/arch/arm/mach-bcm2708/vcio.c b/arch/arm/mach-bcm2708/vcio.c
+index 3874051..468fdef 100644
+--- a/arch/arm/mach-bcm2708/vcio.c
++++ b/arch/arm/mach-bcm2708/vcio.c
+@@ -216,6 +216,40 @@ static void dev_mbox_register(const char *dev_name, struct device *dev)
+ mbox_dev = dev;
+ }
+
++extern int bcm_mailbox_property(void *data, int size)
++{
++ uint32_t success;
++ dma_addr_t mem_bus; /* the memory address accessed from videocore */
++ void *mem_kern; /* the memory address accessed from driver */
++ int s = 0;
++
++ /* allocate some memory for the messages communicating with GPU */
++ mem_kern = dma_alloc_coherent(NULL, PAGE_ALIGN(size), &mem_bus, GFP_ATOMIC);
++ if (mem_kern) {
++ /* create the message */
++ memcpy(mem_kern, data, size);
++
++ /* send the message */
++ wmb();
++ s = bcm_mailbox_write(MBOX_CHAN_PROPERTY, (uint32_t)mem_bus);
++ if (s == 0) {
++ s = bcm_mailbox_read(MBOX_CHAN_PROPERTY, &success);
++ }
++ if (s == 0) {
++ /* copy the response */
++ rmb();
++ memcpy(data, mem_kern, size);
++ }
++ dma_free_coherent(NULL, PAGE_ALIGN(size), mem_kern, mem_bus);
++ } else {
++ s = -ENOMEM;
++ }
++ if (s != 0)
++ printk(KERN_ERR DRIVER_NAME ": %s failed (%d)\n", __func__, s);
++ return s;
++}
++EXPORT_SYMBOL_GPL(bcm_mailbox_property);
++
+ /* ----------------------------------------------------------------------
+ * Platform Device for Mailbox
+ * -------------------------------------------------------------------- */
+diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
+index 72a0044..c28423d 100644
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -30,3 +30,11 @@ config ARM_EXYNOS4210_CPUFREQ
+ SoC (S5PV310 or S5PC210).
+
+ If in doubt, say N.
++
++config ARM_BCM2835_CPUFREQ
++ bool "BCM2835 Driver"
++ default y
++ help
++ This adds the CPUFreq driver for BCM2835
++
++ If in doubt, say N.
+diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
+index a48bc02..51ebbb3 100644
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
+ obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
+ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
+ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
++obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
+
+ ##################################################################################
+ # PowerPC platform drivers
+diff --git a/drivers/cpufreq/bcm2835-cpufreq.c b/drivers/cpufreq/bcm2835-cpufreq.c
+new file mode 100755
+index 0000000..aa6fc66
+--- /dev/null
++++ b/drivers/cpufreq/bcm2835-cpufreq.c
+@@ -0,0 +1,239 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++/*****************************************************************************
++* FILENAME: bcm2835-cpufreq.h
++* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM
++* processor. Messages are sent to Videocore either setting or requesting the
++* frequency of the ARM in order to match an appropiate frequency to the current
++* usage of the processor. The policy which selects the frequency to use is
++* defined in the kernel .config file, but can be changed during runtime.
++*****************************************************************************/
++
++/* ---------- INCLUDES ---------- */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/cpufreq.h>
++#include <mach/vcio.h>
++
++/* ---------- DEFINES ---------- */
++/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
++#define MODULE_NAME "bcm2835-cpufreq"
++
++#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
++
++/* debug printk macros */
++#ifdef CPUFREQ_DEBUG_ENABLE
++#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
++#else
++#define print_debug(fmt,...)
++#endif
++#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
++#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
++
++/* tag part of the message */
++struct vc_msg_tag {
++ uint32_t tag_id; /* the message id */
++ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
++ uint32_t data_size; /* amount of data being sent or received */
++ uint32_t dev_id; /* the ID of the clock/voltage to get or set */
++ uint32_t val; /* the value (e.g. rate (in Hz)) to set */
++};
++
++/* message structure to be sent to videocore */
++struct vc_msg {
++ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
++ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
++ struct vc_msg_tag tag; /* the tag structure above to make */
++ uint32_t end_tag; /* an end identifier, should be set to NULL */
++};
++
++/* ---------- GLOBALS ---------- */
++static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
++
++/*
++ ===============================================
++ clk_rate either gets or sets the clock rates.
++ ===============================================
++*/
++static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
++{
++ int s, actual_rate=0;
++ struct vc_msg msg;
++
++ /* wipe all previous message data */
++ memset(&msg, 0, sizeof msg);
++
++ msg.msg_size = sizeof msg;
++
++ msg.tag.tag_id = VCMSG_SET_CLOCK_RATE;
++ msg.tag.buffer_size = 8;
++ msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */
++ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
++ msg.tag.val = arm_rate * 1000;
++
++ /* send the message */
++ s = bcm_mailbox_property(&msg, sizeof msg);
++
++ /* check if it was all ok and return the rate in KHz */
++ if (s == 0 && (msg.request_code & 0x80000000))
++ actual_rate = msg.tag.val/1000;
++
++ print_debug("Setting new frequency = %d -> %d (actual %d)", cur_rate, arm_rate, actual_rate);
++ return actual_rate;
++}
++
++static uint32_t bcm2835_cpufreq_get_clock(int tag)
++{
++ int s;
++ int arm_rate = 0;
++ struct vc_msg msg;
++
++ /* wipe all previous message data */
++ memset(&msg, 0, sizeof msg);
++
++ msg.msg_size = sizeof msg;
++ msg.tag.tag_id = tag;
++ msg.tag.buffer_size = 8;
++ msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */
++ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
++
++ /* send the message */
++ s = bcm_mailbox_property(&msg, sizeof msg);
++
++ /* check if it was all ok and return the rate in KHz */
++ if (s == 0 && (msg.request_code & 0x80000000))
++ arm_rate = msg.tag.val/1000;
++
++ print_debug("%s frequency = %d",
++ tag == VCMSG_GET_CLOCK_RATE ? "Current":
++ tag == VCMSG_GET_MIN_CLOCK ? "Min":
++ tag == VCMSG_GET_MAX_CLOCK ? "Max":
++ "Unexpected", arm_rate);
++
++ return arm_rate;
++}
++
++/*
++ ====================================================
++ Module Initialisation registers the cpufreq driver
++ ====================================================
++*/
++static int __init bcm2835_cpufreq_module_init(void)
++{
++ print_debug("IN");
++ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
++}
++
++/*
++ =============
++ Module exit
++ =============
++*/
++static void __exit bcm2835_cpufreq_module_exit(void)
++{
++ print_debug("IN");
++ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
++ return;
++}
++
++/*
++ ==============================================================
++ Initialisation function sets up the CPU policy for first use
++ ==============================================================
++*/
++static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
++{
++ /* measured value of how long it takes to change frequency */
++ policy->cpuinfo.transition_latency = 355000; /* ns */
++
++ /* now find out what the maximum and minimum frequencies are */
++ policy->min = policy->cpuinfo.min_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK);
++ policy->max = policy->cpuinfo.max_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK);
++ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
++
++ print_info("min=%d max=%d cur=%d", policy->min, policy->max, policy->cur);
++ return 0;
++}
++
++/*
++ =================================================================================
++ Target function chooses the most appropriate frequency from the table to enable
++ =================================================================================
++*/
++
++static int bcm2835_cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
++{
++ unsigned int target = target_freq;
++ unsigned int cur = policy->cur;
++ print_debug("%s: min=%d max=%d cur=%d target=%d",policy->governor->name,policy->min,policy->max,policy->cur,target_freq);
++
++ /* if we are above min and using ondemand, then just use max */
++ if (strcmp("ondemand", policy->governor->name)==0 && target > policy->min)
++ target = policy->max;
++ /* if the frequency is the same, just quit */
++ if (target == policy->cur)
++ return 0;
++
++ /* otherwise were good to set the clock frequency */
++ policy->cur = bcm2835_cpufreq_set_clock(policy->cur, target);
++
++ if (!policy->cur)
++ {
++ print_err("Error occurred setting a new frequency (%d)!", target);
++ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
++ return -EINVAL;
++ }
++ print_info("Freq %d->%d (min=%d max=%d target=%d request=%d)", cur, policy->cur, policy->min, policy->max, target_freq, target);
++ return 0;
++}
++
++static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
++{
++ unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
++ print_debug("%d", actual_rate);
++ return actual_rate;
++}
++
++/*
++ =================================================================================
++ Verify ensures that when a policy is changed, it is suitable for the CPU to use
++ =================================================================================
++*/
++
++static int bcm2835_cpufreq_driver_verify(struct cpufreq_policy *policy)
++{
++ print_info("switching to governor %s", policy->governor->name);
++ return 0;
++}
++
++
++/* the CPUFreq driver */
++static struct cpufreq_driver bcm2835_cpufreq_driver = {
++ .name = "BCM2835 CPUFreq",
++ .owner = THIS_MODULE,
++ .init = bcm2835_cpufreq_driver_init,
++ .verify = bcm2835_cpufreq_driver_verify,
++ .target = bcm2835_cpufreq_driver_target,
++ .get = bcm2835_cpufreq_driver_get
++};
++
++MODULE_AUTHOR("Dorian Peake and Dom Cobley");
++MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
++MODULE_LICENSE("GPL");
++
++module_init(bcm2835_cpufreq_module_init);
++module_exit(bcm2835_cpufreq_module_exit);
++