diff options
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.patch | 525 |
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);
++
|