diff options
-rw-r--r-- | drivers/cpufreq/s5pv210-cpufreq.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 48a4a9058864..9a5b28474342 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -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); } |