From a67558a6b3ed09c6e0507c3249132ca29e4d21f5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Sun, 26 Dec 2010 17:20:25 +0800 Subject: [PATCH] rk29: add cpufreq support --- arch/arm/mach-rk29/Makefile | 1 + arch/arm/mach-rk29/board-rk29sdk.c | 2 +- arch/arm/mach-rk29/clock.c | 79 ------------ arch/arm/mach-rk29/cpufreq.c | 159 +++++++++++++++++++++++++ drivers/regulator/rk29-pwm-regulator.c | 10 +- 5 files changed, 165 insertions(+), 86 deletions(-) create mode 100755 arch/arm/mach-rk29/cpufreq.c diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile index aec43165cc40..a8d554287e1b 100755 --- a/arch/arm/mach-rk29/Makefile +++ b/arch/arm/mach-rk29/Makefile @@ -1,4 +1,5 @@ obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_RK29_VPU) += vpu.o vpu_mem.o obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o obj-$(CONFIG_MACH_RK29WINACCORD) += board-rk29-winaccord.o board-rk29sdk-key.o diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index 686d152bb705..9b99fd19628f 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -870,7 +870,7 @@ static struct regulator_consumer_supply pwm_consumers[] = { static struct regulator_init_data rk29_pwm_regulator_data = { .constraints = { .name = "PWM2", - .min_uV = 1200000, + .min_uV = 950000, .max_uV = 1400000, .apply_uV = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c index 0a90f11c93d3..fc49f16319d1 100755 --- a/arch/arm/mach-rk29/clock.c +++ b/arch/arm/mach-rk29/clock.c @@ -33,12 +33,6 @@ #include -#define PWM_VCORE_120 40 -#define PWM_VCORE_125 32 -#define PWM_VCORE_130 21 -#define PWM_VCORE_135 10 -#define PWM_VCORE_140 0 - /* CRU PLL CON */ #define PLL_HIGH_BAND (0x01 << 16) #define PLL_LOW_BAND (0x00 << 16) @@ -390,77 +384,6 @@ static const struct arm_pll_set arm_pll[] = { #define CORE_PARENT_ARM_PLL (0 << 23) #define CORE_PARENT_GENERAL_PLL (1 << 23) -#define PWM_DIV2 (0<<9) -#define PWM_DIV4 (1<<9) -#define PWM_DIV8 (2<<9) -#define PWM_DIV16 (3<<9) -#define PWM_DIV32 (4<<9) -#define PWM_DIV64 (5<<9) -#define PWM_DIV128 (6<<9) -#define PWM_DIV256 (7<<9) -#define PWM_DIV512 (8<<9) -#define PWM_DIV1024 (9<<9) - -#define PWM_CAPTURE (1<<8) -#define PWM_RESET (1<<7) -#define PWM_INTCLR (1<<6) -#define PWM_INTEN (1<<5) -#define PWM_SINGLE (1<<6) - -#define PWM_ENABLE (1<<3) -#define PWM_TimeEN (1) - -#define PWM_DIV PWM_DIV2 - -static struct clk pclk_periph; -static struct clk clk_pwm; -void PWMInit(u32 nHz, u32 rate) -{ - u32 divh; - - clk_enable_nolock(&clk_pwm); - // iomux to pwm2 -#define REG_FILE_BASE_ADDR RK29_GRF_BASE - volatile unsigned int * pGRF_GPIO2L_IOMUX = (volatile unsigned int *)(REG_FILE_BASE_ADDR + 0x58); - *pGRF_GPIO2L_IOMUX &= ~(0x3<<6); - *pGRF_GPIO2L_IOMUX |= (0x2<<6); - // pwm2 clk enable - - // set pwm rate -#define PWM_BASE_ADDR RK29_PWM_BASE - volatile unsigned int * pPWM2_CTRL = (volatile unsigned int *)(PWM_BASE_ADDR + 0x2C); - volatile unsigned int * pPWM2_LRC = (volatile unsigned int *)(PWM_BASE_ADDR + 0x28); - volatile unsigned int * pPWM2_HRC = (volatile unsigned int *)(PWM_BASE_ADDR + 0x24); - volatile unsigned int * pPWM2_CNTR = (volatile unsigned int *)(PWM_BASE_ADDR + 0x20); - -#define GPIO2_BASE_ADDR RK29_GPIO2_BASE - volatile unsigned int *pGPIO2_DIR = (volatile unsigned int *)(GPIO2_BASE_ADDR + 0x4); - volatile unsigned int *pGPIO2_LEVEL = (volatile unsigned int *)GPIO2_BASE_ADDR; - - if (rate == 0) { - // iomux pwm2 to gpio2_a[3] - *pGRF_GPIO2L_IOMUX &= ~(0x3<<6); - // set gpio to low level - *pGPIO2_DIR |= 0x1<<3; - *pGPIO2_LEVEL &= ~(0x1<<3); - } else { - *pPWM2_CTRL= PWM_DIV|PWM_RESET; - divh = pclk_periph.rate / nHz; - divh = divh >> (1+(PWM_DIV>>9)); - *pPWM2_LRC = (divh == 0)?1:divh; - - divh = (*pPWM2_LRC)*rate/100; - *pPWM2_HRC = divh?divh:1; - - *pPWM2_CNTR = 0x0; - *pPWM2_CTRL = PWM_DIV|PWM_ENABLE|PWM_TimeEN; - printk("pclk_periph %d LRC %08x HRC %08x\n", pclk_periph.rate, *pPWM2_LRC, *pPWM2_HRC); - } - - int i; for (i = 0; i < 6000; i++) - delay_500ns(); -} - static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) { const struct arm_pll_set *ps, *pt; @@ -480,8 +403,6 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) pt++; } - PWMInit(1 * MHZ, PWM_VCORE_130); // 1.30V - /* make aclk safe & reparent to general pll */ cru_writel((cru_readl(CRU_CLKSEL0_CON) & ~(CORE_PARENT_MASK | CORE_ACLK_MASK)) | CORE_PARENT_GENERAL_PLL | CORE_ACLK_21, CRU_CLKSEL0_CON); diff --git a/arch/arm/mach-rk29/cpufreq.c b/arch/arm/mach-rk29/cpufreq.c new file mode 100755 index 000000000000..b1d437bdf4ff --- /dev/null +++ b/arch/arm/mach-rk29/cpufreq.c @@ -0,0 +1,159 @@ +/* arch/arm/mach-rk2818/cpufreq.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +static struct cpufreq_frequency_table freq_table[] = { +#if 0 +// { .index = 950000, .frequency = 204000 }, +// { .index = 1050000, .frequency = 300000 }, + { .index = 1050000, .frequency = 408000 }, +// { .index = 1125000, .frequency = 600000 }, + { .index = 1225000, .frequency = 816000 }, + { .index = 1250000, .frequency = 1008000 }, +// { .index = 1300000, .frequency = 1200000 }, +#else + { .index = 1100000, .frequency = 408000 }, +// { .index = 1200000, .frequency = 600000 }, + { .index = 1300000, .frequency = 816000 }, +// { .index = 1350000, .frequency = 1008000 }, +#endif + { .frequency = CPUFREQ_TABLE_END }, +}; +static struct clk *arm_clk; +static struct regulator *vcore; + +static int rk29_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) +{ + int index; + struct cpufreq_freqs freqs; + const struct cpufreq_frequency_table *freq; + int err = 0; + + if (policy->cpu != 0) + return -EINVAL; + if (cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &index)) { + pr_err("cpufreq: invalid target_freq: %d\n", target_freq); + return -EINVAL; + } + freq = &freq_table[index]; + + if (policy->cur == freq->frequency) + return 0; + + freqs.old = policy->cur; + freqs.new = freq->frequency; + freqs.cpu = 0; +#ifdef CONFIG_CPU_FREQ_DEBUG + printk(KERN_DEBUG "%s %d r %d (%d-%d) selected %d (%duV)\n", __func__, target_freq, relation, policy->min, policy->max, freq->frequency, freq->index); +#endif + +#ifdef CONFIG_REGULATOR + if (vcore && freqs.new > freqs.old) { + err = regulator_set_voltage(vcore, freq->index, freq->index); + if (err) { + pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n", + freq->index, freqs.new, err); + goto err_vol; + } + } +#endif + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + clk_set_rate(arm_clk, freqs.new * 1000); + freqs.new = clk_get_rate(arm_clk) / 1000; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + +#ifdef CONFIG_REGULATOR + if (vcore && freqs.new < freqs.old) { + err = regulator_set_voltage(vcore, freq->index, freq->index); + if (err) { + pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n", + freq->index, freqs.new, err); + } + } +#endif + +err_vol: + return err; +} + +extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + +static int __init rk29_cpufreq_init(struct cpufreq_policy *policy) +{ + arm_clk = clk_get(NULL, "arm_pll"); + if (IS_ERR(arm_clk)) + return PTR_ERR(arm_clk); + + if (policy->cpu != 0) + return -EINVAL; + +#ifdef CONFIG_REGULATOR + vcore = regulator_get(NULL, "vcore"); + if (IS_ERR(vcore)) { + pr_err("cpufreq: fail to get regulator vcore: %ld\n", PTR_ERR(vcore)); + vcore = NULL; + } +#endif + + BUG_ON(cpufreq_frequency_table_cpuinfo(policy, freq_table)); + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + policy->cur = clk_get_rate(arm_clk) / 1000; + + policy->cpuinfo.transition_latency = 400 * NSEC_PER_USEC; // make default sampling_rate to 40000 + + return 0; +} + +static int rk29_cpufreq_exit(struct cpufreq_policy *policy) +{ + if (vcore) + regulator_put(vcore); + clk_put(arm_clk); + return 0; +} + +static struct freq_attr *rk29_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver rk29_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .init = rk29_cpufreq_init, + .exit = rk29_cpufreq_exit, + .verify = rk29_cpufreq_verify, + .target = rk29_cpufreq_target, + .name = "rk29", + .attr = rk29_cpufreq_attr, +}; + +static int __init rk29_cpufreq_register(void) +{ + return cpufreq_register_driver(&rk29_cpufreq_driver); +} + +device_initcall(rk29_cpufreq_register); + diff --git a/drivers/regulator/rk29-pwm-regulator.c b/drivers/regulator/rk29-pwm-regulator.c index da22de577662..7f5b10ee9722 100644 --- a/drivers/regulator/rk29-pwm-regulator.c +++ b/drivers/regulator/rk29-pwm-regulator.c @@ -57,7 +57,7 @@ REVISION 0.01 const static int pwm_voltage_map[] = { - 1200, 1250, 1300, 1350, 1400 + 950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400 }; static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) @@ -106,7 +106,7 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) return -1; } - msleep(50); + msleep(5); return (0); @@ -129,11 +129,9 @@ static int pwm_init(struct pwm_platform_data *pdata, int nHz, int rate) static int pwm_regulator_list_voltage(struct regulator_dev *dev,unsigned int index) { - int *pwm_voltage_table = pwm_voltage_map; - DBG("Enter %s, index =%d\n",__FUNCTION__,index); if (index < sizeof(pwm_voltage_map)/sizeof(int)) - return pwm_voltage_table[index]; + return pwm_voltage_map[index]; else return -1; } @@ -285,7 +283,7 @@ static void __exit pwm_regulator_module_exit(void) } -module_init(pwm_regulator_module_init); +subsys_initcall(pwm_regulator_module_init); module_exit(pwm_regulator_module_exit); -- 2.34.1