From: Ziggy Date: Tue, 4 Sep 2012 12:49:22 +0000 (-0400) Subject: Add sysfs vdd interface X-Git-Url: https://ziggy471.com/git/gitweb.cgi?p=ziggy471-shooter-ics-kernel.git;a=commitdiff;h=fb55e2f1906133e7850fc100856f8ad2b0f5adf3 Add sysfs vdd interface --- --- a/arch/arm/mach-msm/acpuclock-8x60.c +++ b/arch/arm/mach-msm/acpuclock-8x60.c @@ -889,3 +889,36 @@ static int __init acpuclk_8x60_init(stru struct acpuclk_soc_data acpuclk_8x60_soc_data __initdata = { .init = acpuclk_8x60_init, }; + +#ifdef CONFIG_VDD_USERSPACE +ssize_t acpuclk_get_vdd_levels_str(char *buf) +{ + int i, len = 0; + if (buf) { + mutex_lock(&drv_state.lock); + len += sprintf(buf + len, "Min: %4d\n", MIN_VDD_SC); + len += sprintf(buf + len, "Max: %4d\n", MAX_VDD_SC); + for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) { + if (acpu_freq_tbl[i].use_for_scaling[0] || acpu_freq_tbl[i].use_for_scaling[1]) { + len += sprintf(buf + len, "%8u: %4d\n", acpu_freq_tbl[i].acpuclk_khz, acpu_freq_tbl[i].vdd_sc); + } + } + mutex_unlock(&drv_state.lock); + } + return len; +} + +void acpuclk_set_vdd(unsigned int 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].acpuclk_khz; i++) { + if (khz == 0) + acpu_freq_tbl[i].vdd_sc = min(max((unsigned int)(acpu_freq_tbl[i].vdd_sc + vdd), (unsigned int)MIN_VDD_SC), (unsigned int)MAX_VDD_SC); + else if (acpu_freq_tbl[i].acpuclk_khz == khz) + acpu_freq_tbl[i].vdd_sc = min(max((unsigned int)vdd, (unsigned int)MIN_VDD_SC), (unsigned int)MAX_VDD_SC); + } + mutex_unlock(&drv_state.lock); +} +#endif --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -219,6 +219,10 @@ static int __cpuinit msm_cpufreq_init(st init_completion(&cpu_work->complete); #endif +#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX + policy->min = CONFIG_MSM_CPU_FREQ_MIN; + policy->max = CONFIG_MSM_CPU_FREQ_MAX; +#endif return 0; } @@ -231,6 +235,8 @@ static int msm_cpufreq_suspend(void) per_cpu(cpufreq_suspend, cpu).device_suspended = 1; mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex); } + if (num_online_cpus() > 1) + cpu_down(1); return NOTIFY_DONE; } --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -290,6 +290,14 @@ config CPU_FREQ_SAMPLING_LATENCY_MULTIPL Sampling latency rate multiplied by the cpu switch latency. Affects governor polling. +config VDD_USERSPACE + bool "VDD sysfs interface" + default n + depends on CPU_FREQ_STAT + help + exposes the VDD table to userspace + allows users to adjust voltages on the fly + menu "x86 CPU frequency scaling drivers" depends on X86 source "drivers/cpufreq/Kconfig.x86" --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -576,6 +576,59 @@ static ssize_t show_bios_limit(struct cp return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); } +#ifdef CONFIG_VDD_USERSPACE +extern ssize_t acpuclk_get_vdd_levels_str(char *buf); +static ssize_t show_vdd_levels(struct kobject *a, struct attribute *b, 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 kobject *a, struct attribute *b, 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 /* CONFIG_VDD_USERSPACE */ + cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); cpufreq_freq_attr_ro(cpuinfo_min_freq); cpufreq_freq_attr_ro(cpuinfo_max_freq); @@ -591,6 +644,10 @@ cpufreq_freq_attr_rw(scaling_max_freq); cpufreq_freq_attr_rw(scaling_governor); cpufreq_freq_attr_rw(scaling_setspeed); +#ifdef CONFIG_VDD_USERSPACE +define_one_global_rw(vdd_levels); +#endif + static struct attribute *default_attrs[] = { &cpuinfo_min_freq.attr, &cpuinfo_max_freq.attr, @@ -606,6 +663,18 @@ static struct attribute *default_attrs[] NULL }; +#ifdef CONFIG_VDD_USERSPACE +static struct attribute *vddtbl_attrs[] = { + &vdd_levels.attr, + NULL +}; + +static struct attribute_group vddtbl_attr_group = { + .attrs = vddtbl_attrs, + .name = "vdd_table", +}; +#endif /* CONFIG_VDD_USERSPACE */ + struct kobject *cpufreq_global_kobject; EXPORT_SYMBOL(cpufreq_global_kobject); @@ -1916,6 +1985,9 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_dri static int __init cpufreq_core_init(void) { int cpu; +#ifdef CONFIG_VDD_USERSPACE + int rc; +#endif /* CONFIG_VDD_USERSPACE */ for_each_possible_cpu(cpu) { per_cpu(cpufreq_policy_cpu, cpu) = -1; @@ -1927,6 +1999,10 @@ static int __init cpufreq_core_init(void BUG_ON(!cpufreq_global_kobject); register_syscore_ops(&cpufreq_syscore_ops); +#ifdef CONFIG_VDD_USERSPACE + rc = sysfs_create_group(cpufreq_global_kobject, &vddtbl_attr_group); +#endif /* CONFIG_VDD_USERSPACE */ + return 0; } core_initcall(cpufreq_core_init);