From f28b37859134e04d42fe23073943a2ef720191a6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 16 Mar 2009 16:43:03 +0100 Subject: i.MX27: add cpu frequency scaling support Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 2 +- arch/arm/mach-mx2/Makefile | 5 ++ arch/arm/mach-mx2/cpufreq_imx27.c | 149 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mx2/cpufreq_imx27.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2599b277743..7014f50da6f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1241,7 +1241,7 @@ endmenu menu "CPU Power Management" -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_PXA || ARCH_S3C64XX) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_PXA || ARCH_S3C64XX || MACH_MX27) source "drivers/cpufreq/Kconfig" diff --git a/arch/arm/mach-mx2/Makefile b/arch/arm/mach-mx2/Makefile index b9b1cca4e9b..a7e2f5264bc 100644 --- a/arch/arm/mach-mx2/Makefile +++ b/arch/arm/mach-mx2/Makefile @@ -12,6 +12,11 @@ obj-$(CONFIG_MACH_MX27) += cpu_imx27.o obj-$(CONFIG_MACH_MX27) += clock_imx27.o obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o + +ifeq ($(CONFIG_CPU_FREQ),y) +obj-$(CONFIG_MACH_MX27) += cpufreq_imx27.o +endif + obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o obj-$(CONFIG_MACH_PCM038) += pcm038.o obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o diff --git a/arch/arm/mach-mx2/cpufreq_imx27.c b/arch/arm/mach-mx2/cpufreq_imx27.c new file mode 100644 index 00000000000..db6ad6b7577 --- /dev/null +++ b/arch/arm/mach-mx2/cpufreq_imx27.c @@ -0,0 +1,149 @@ +/* + * linux/arch/arm/mach-mx2/cpufreq.c + * + * Copyright (C) 2009 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct cpufreq_frequency_table mx27_freq_table[4 + 1]; + +static struct clk *clk_cpu, *clk_mpll; +static unsigned long mpll_rate; + +static int mx27_verify_policy(struct cpufreq_policy *policy) +{ return cpufreq_frequency_table_verify(policy, mx27_freq_table); +} + +static unsigned int mx27_cpufreq_get(unsigned int cpu) +{ + return clk_get_rate(clk_cpu) / 1000; +} + +static unsigned char cpu_dividers[] = {2, 3, 6}; + +static int mx27_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned int idx; + + /* Lookup the next frequency */ + if (cpufreq_frequency_table_target(policy, mx27_freq_table, + target_freq, relation, &idx)) + return -EINVAL; + + freqs.old = policy->cur; + freqs.new = mx27_freq_table[idx].frequency; + freqs.cpu = policy->cpu; + + /* + * Tell everyone what we're about to do... + * you should add a notify client with any platform specific + * Vcc changing capability + */ + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + clk_set_rate(clk_cpu, mpll_rate * 2 / cpu_dividers[idx]); + + /* + * Tell everyone what we've just done... + * you should add a notify client with any platform specific + * SDRAM refresh timer adjustments + */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static __init int mx27_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret, i; + + clk_cpu = clk_get(NULL, "cpu"); + if (IS_ERR(clk_cpu)) + return PTR_ERR(clk_cpu); + + clk_mpll = clk_get(NULL, "mpll"); + if (IS_ERR(clk_mpll)) { + ret = PTR_ERR(clk_mpll); + goto out; + } + + mpll_rate = clk_get_rate(clk_mpll); + + /* set default policy and cpuinfo */ + policy->cpuinfo.transition_latency = 10; + policy->cur = clk_get_rate(clk_cpu) / 1000; + policy->min = mpll_rate / 3; + policy->max = mpll_rate; + + for (i = 0; i < ARRAY_SIZE(cpu_dividers); i++) { + mx27_freq_table[i].index = i; + mx27_freq_table[i].frequency = mpll_rate * 2 / cpu_dividers[i] / 1000; + } + mx27_freq_table[i].frequency = CPUFREQ_TABLE_END; + + cpufreq_frequency_table_cpuinfo(policy, mx27_freq_table); + + printk(KERN_INFO "i.MX27 CPU frequency change support initialized %d %d\n", + policy->min, policy->max); + + return 0; +out: + clk_put(clk_cpu); + + return ret; +} + +static struct cpufreq_driver mx27_cpufreq_driver = { + .verify = mx27_verify_policy, + .target = mx27_set_target, + .init = mx27_cpufreq_init, + .get = mx27_cpufreq_get, + .name = "i.MX27", +}; + +static int __init mx27_cpu_init(void) +{ + if (!cpu_is_mx27()) + return -ENODEV; + + return cpufreq_register_driver(&mx27_cpufreq_driver); +} + +static void __exit mx27_cpu_exit(void) +{ + cpufreq_unregister_driver(&mx27_cpufreq_driver); +} + + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("CPU frequency changing driver for the i.MX27"); +MODULE_LICENSE("GPL"); +module_init(mx27_cpu_init); +module_exit(mx27_cpu_exit); + -- cgit v1.2.3