[CPUFREQ] S5PV210: Add arm/int voltage control support
Jonghwan Choi [Fri, 24 Jun 2011 07:04:14 +0000 (16:04 +0900)]
Signed-off-by: Jonghwan Choi <jhbird.choi@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Dave Jones <davej@redhat.com>

drivers/cpufreq/s5pv210-cpufreq.c

index 48a4a90..9a5b284 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/cpufreq.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/map.h>
 #include <mach/regs-clock.h>
@@ -77,6 +78,40 @@ static struct cpufreq_frequency_table s5pv210_freq_table[] = {
        {0, CPUFREQ_TABLE_END},
 };
 
+static struct regulator *arm_regulator;
+static struct regulator *int_regulator;
+
+struct s5pv210_dvs_conf {
+       int arm_volt;   /* uV */
+       int int_volt;   /* uV */
+};
+
+static const int arm_volt_max = 1350000;
+static const int int_volt_max = 1250000;
+
+static struct s5pv210_dvs_conf dvs_conf[] = {
+       [L0] = {
+               .arm_volt       = 1250000,
+               .int_volt       = 1100000,
+       },
+       [L1] = {
+               .arm_volt       = 1200000,
+               .int_volt       = 1100000,
+       },
+       [L2] = {
+               .arm_volt       = 1050000,
+               .int_volt       = 1100000,
+       },
+       [L3] = {
+               .arm_volt       = 950000,
+               .int_volt       = 1100000,
+       },
+       [L4] = {
+               .arm_volt       = 950000,
+               .int_volt       = 1000000,
+       },
+};
+
 static u32 clkdiv_val[5][11] = {
        /*
         * Clock divider value for following
@@ -157,6 +192,8 @@ static int s5pv210_target(struct cpufreq_policy *policy,
        unsigned int index, priv_index;
        unsigned int pll_changing = 0;
        unsigned int bus_speed_changing = 0;
+       int arm_volt, int_volt;
+       int ret = 0;
 
        if (relation & ENABLE_FURTHER_CPUFREQ)
                no_cpufreq_access = false;
@@ -191,12 +228,23 @@ static int s5pv210_target(struct cpufreq_policy *policy,
                                           freqs.old, relation, &priv_index))
                return -EINVAL;
 
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       arm_volt = dvs_conf[index].arm_volt;
+       int_volt = dvs_conf[index].int_volt;
 
        if (freqs.new > freqs.old) {
-               /* Voltage up: will be implemented */
+               ret = regulator_set_voltage(arm_regulator,
+                               arm_volt, arm_volt_max);
+               if (ret)
+                       return ret;
+
+               ret = regulator_set_voltage(int_regulator,
+                               int_volt, int_volt_max);
+               if (ret)
+                       return ret;
        }
 
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
        /* Check if there need to change PLL */
        if ((index == L0) || (priv_index == L0))
                pll_changing = 1;
@@ -408,7 +456,11 @@ static int s5pv210_target(struct cpufreq_policy *policy,
        }
 
        if (freqs.new < freqs.old) {
-               /* Voltage down: will be implemented */
+               regulator_set_voltage(int_regulator,
+                               int_volt, int_volt_max);
+
+               regulator_set_voltage(arm_regulator,
+                               arm_volt, arm_volt_max);
        }
 
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -515,6 +567,19 @@ static struct cpufreq_driver s5pv210_driver = {
 
 static int __init s5pv210_cpufreq_init(void)
 {
+       arm_regulator = regulator_get(NULL, "vddarm");
+       if (IS_ERR(arm_regulator)) {
+               pr_err("failed to get regulator vddarm");
+               return PTR_ERR(arm_regulator);
+       }
+
+       int_regulator = regulator_get(NULL, "vddint");
+       if (IS_ERR(int_regulator)) {
+               pr_err("failed to get regulator vddint");
+               regulator_put(arm_regulator);
+               return PTR_ERR(int_regulator);
+       }
+
        return cpufreq_register_driver(&s5pv210_driver);
 }