diff --git a/arch/arm/mach-msm/acpuclock-scorpion.c b/arch/arm/mach-msm/acpuclock-scorpion.c index c12fe44e..e7454f91 100644 --- a/arch/arm/mach-msm/acpuclock-scorpion.c +++ b/arch/arm/mach-msm/acpuclock-scorpion.c @@ -29,6 +29,9 @@ #include "acpuclock.h" #include "proc_comm.h" #include "clock.h" +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS +#include "board-htcleo.h" +#endif #if 0 #define DEBUG(x...) pr_info(x) @@ -693,3 +696,41 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) clk_set_rate(drv_state.clk_ebi1, drv_state.current_speed->axiclk_khz * 1000); #endif } + +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS + +ssize_t acpuclk_get_vdd_levels_str(char *buf) +{ + int i, len = 0; + if (buf) + { + mutex_lock(&drv_state.lock); + for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) + { + if (freq_table[i].frequency != CPUFREQ_ENTRY_INVALID) + len += sprintf(buf + len, "%8u: %4d\n", acpu_freq_tbl[i].acpu_khz, acpu_freq_tbl[i].vdd); + } + mutex_unlock(&drv_state.lock); + } + return len; +} + +void acpuclk_set_vdd(unsigned acpu_khz, int vdd) +{ + int i; + vdd = vdd / 25 * 25; //! regulator only accepts multiples of 25 (mV) + mutex_lock(&drv_state.lock); + for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) + { + if (freq_table[i].frequency != CPUFREQ_ENTRY_INVALID) + { + if (acpu_khz == 0) + acpu_freq_tbl[i].vdd = min(max((acpu_freq_tbl[i].vdd + vdd), HTCLEO_TPS65023_MIN_UV_MV), HTCLEO_TPS65023_MAX_UV_MV); + else if (acpu_freq_tbl[i].acpu_khz == acpu_khz) + acpu_freq_tbl[i].vdd = min(max(vdd, HTCLEO_TPS65023_MIN_UV_MV), HTCLEO_TPS65023_MAX_UV_MV); + } + } + mutex_unlock(&drv_state.lock); +} + +#endif diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index f4feeee3..75d7669e 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -110,8 +110,8 @@ static struct regulator_init_data tps65023_data[5] = .constraints = { .name = "dcdc1", /* VREG_MSMC2_1V29 */ - .min_uV = 800000, - .max_uV = 1350000, + .min_uV = HTCLEO_TPS65023_MIN_UV_MV * 1000, + .max_uV = HTCLEO_TPS65023_MAX_UV_MV * 1000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, }, .consumer_supplies = tps65023_dcdc1_supplies, diff --git a/arch/arm/mach-msm/board-htcleo.h b/arch/arm/mach-msm/board-htcleo.h index 61816de0..7e629764 100644 --- a/arch/arm/mach-msm/board-htcleo.h +++ b/arch/arm/mach-msm/board-htcleo.h @@ -168,7 +168,9 @@ #define HTCLEO_LCD_HSYNC (137) #define HTCLEO_LCD_DE (138) - +/* Voltage driver */ +#define HTCLEO_TPS65023_MIN_UV_MV (800) +#define HTCLEO_TPS65023_MAX_UV_MV (1350) int htcleo_pm_set_vreg(int enable, unsigned id); int __init htcleo_init_panel(void); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index ca7b0887..21a6e937 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -205,4 +205,12 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config CPU_FREQ_VDD_LEVELS + bool "CPU Vdd levels sysfs interface" + depends on CPU_FREQ_STAT + depends on ARCH_QSD8X50 + default n + help + CPU Vdd levels sysfs interface + endif # CPU_FREQ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index ff57c40e..24915247 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -647,6 +647,74 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) return policy->governor->show_setspeed(policy, buf); } +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS + +extern ssize_t acpuclk_get_vdd_levels_str(char *buf); +static ssize_t show_vdd_levels(struct cpufreq_policy *policy, char *buf) +{ + return acpuclk_get_vdd_levels_str(buf); +} + +extern void acpuclk_set_vdd(unsigned acpu_khz, int vdd); +static ssize_t store_vdd_levels(struct cpufreq_policy *policy, const char *buf, size_t count) +{ + int i = 0, j; + int pair[2] = { 0, 0 }; + int sign = 0; + + if (count < 1) + return 0; + + if (buf[0] == '-') + { + sign = -1; + i++; + } + else if (buf[0] == '+') + { + sign = 1; + i++; + } + + for (j = 0; i < count; i++) + { + char c = buf[i]; + if ((c >= '0') && (c <= '9')) + { + pair[j] *= 10; + pair[j] += (c - '0'); + } + else if ((c == ' ') || (c == '\t')) + { + if (pair[j] != 0) + { + j++; + if ((sign != 0) || (j > 1)) + break; + } + } + else + break; + } + + if (sign != 0) + { + if (pair[0] > 0) + acpuclk_set_vdd(0, sign * pair[0]); + } + else + { + if ((pair[0] > 0) && (pair[1] > 0)) + acpuclk_set_vdd((unsigned)pair[0], pair[1]); + else + return -EINVAL; + } + + return count; +} + +#endif + #define define_one_ro(_name) \ static struct freq_attr _name = \ __ATTR(_name, 0444, show_##_name, NULL) @@ -672,6 +740,9 @@ define_one_rw(scaling_min_freq); define_one_rw(scaling_max_freq); define_one_rw(scaling_governor); define_one_rw(scaling_setspeed); +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS +define_one_rw(vdd_levels); +#endif static struct attribute *default_attrs[] = { &cpuinfo_min_freq.attr, @@ -685,6 +756,9 @@ static struct attribute *default_attrs[] = { &scaling_driver.attr, &scaling_available_governors.attr, &scaling_setspeed.attr, +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS + &vdd_levels.attr, +#endif NULL };