rk29: add cpufreq support
author黄涛 <huangtao@rock-chips.com>
Sun, 26 Dec 2010 09:20:25 +0000 (17:20 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sun, 26 Dec 2010 09:21:00 +0000 (17:21 +0800)
arch/arm/mach-rk29/Makefile
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/clock.c
arch/arm/mach-rk29/cpufreq.c [new file with mode: 0755]
drivers/regulator/rk29-pwm-regulator.c

index aec43165cc4013505b5fcc8b7f0de019276b93e5..a8d554287e1bcda167026e1f520b165986495781 100755 (executable)
@@ -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
index 686d152bb7053751448eda2b07fccf21ea5f0f79..9b99fd19628fd65b99079f6ccb6f7036d7cddf47 100755 (executable)
@@ -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,
index 0a90f11c93d3b998d986233fa7bf0f2a23d2d58e..fc49f16319d14b05e5267a59245da8d1ea35048a 100755 (executable)
 #include <mach/pmu.h>
 
 
-#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 (executable)
index 0000000..b1d437b
--- /dev/null
@@ -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 <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/regulator/consumer.h>
+
+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);
+
index da22de57766268bf9b947c473a9a06dfded764da..7f5b10ee9722ec13db15985152ada59f89b521ae 100644 (file)
@@ -57,7 +57,7 @@ REVISION 0.01
 \r
 \r
 const static int pwm_voltage_map[] = {\r
-       1200, 1250, 1300, 1350, 1400\r
+       950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400\r
 };\r
 \r
 static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate)\r
@@ -106,7 +106,7 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate)
        return -1;\r
        }\r
 \r
-       msleep(50);\r
+       msleep(5);\r
        \r
        \r
     return (0);\r
@@ -129,11 +129,9 @@ static int pwm_init(struct pwm_platform_data *pdata, int nHz, int rate)
 \r
 static int pwm_regulator_list_voltage(struct regulator_dev *dev,unsigned int index)\r
 {\r
-       int *pwm_voltage_table = pwm_voltage_map;\r
-
        DBG("Enter %s, index =%d\n",__FUNCTION__,index);\r
        if (index < sizeof(pwm_voltage_map)/sizeof(int))\r
-               return pwm_voltage_table[index];\r
+               return pwm_voltage_map[index];\r
        else\r
                return -1;\r
 }\r
@@ -285,7 +283,7 @@ static void __exit pwm_regulator_module_exit(void)
 }
 \r
 \r
-module_init(pwm_regulator_module_init);\r
+subsys_initcall(pwm_regulator_module_init);\r
 \r
 module_exit(pwm_regulator_module_exit);\r