/* * Cpufreq driver for the loongson-2 processors * * The 2E revision of loongson processor not support this feature. * * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology * Author: Yanhua, yanh@lemote.com * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #define DEBUG #include #include #include #include /* set_cpus_allowed() */ #include #include #include static struct clk *cpuclk; /* Minimum CLK support */ enum { FREQ_ZERO = 0, FREQ_166M, FREQ_200M, FREQ_250M, FREQ_267M, FREQ_RESV }; struct cpufreq_frequency_table gsc3280_cpufreq_table[] = { {FREQ_ZERO, CPUFREQ_ENTRY_INVALID}, {FREQ_166M, 166500}, {FREQ_200M, 200000}, {FREQ_250M, 250000}, {FREQ_267M, 267000}, {FREQ_RESV, CPUFREQ_TABLE_END}, }; static int gsc3280_cpu_freq_notifier(struct notifier_block *nb, unsigned long val, void *data); static struct notifier_block gsc3280_cpufreq_notifier_block = { .notifier_call = gsc3280_cpu_freq_notifier }; static int gsc3280_cpu_freq_notifier(struct notifier_block *nb, unsigned long val, void *data) { if (val == CPUFREQ_POSTCHANGE) current_cpu_data.udelay_val = loops_per_jiffy; return 0; } static unsigned int gsc3280_cpufreq_get(unsigned int cpu) { return clk_get_rate(cpuclk)/1000; } /* * Here we notify other drivers of the proposed change and the final change. */ static int gsc3280_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { unsigned int cpu = policy->cpu; unsigned int newstate = 0; cpumask_t cpus_allowed; struct cpufreq_freqs freqs; unsigned int freq; if (!cpu_online(cpu)) return -ENODEV; cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); if (cpufreq_frequency_table_target (policy, &gsc3280_cpufreq_table[0], target_freq, relation, &newstate)) return -EINVAL; freq = gsc3280_cpufreq_table[newstate].frequency; if (freq < policy->min || freq > policy->max) return -EINVAL; freqs.cpu = cpu; freqs.old = gsc3280_cpufreq_get(cpu); freqs.new = freq; freqs.flags = 0; if (freqs.new == freqs.old) return 0; /* notifiers */ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); set_cpus_allowed_ptr(current, &cpus_allowed); /* setting the cpu frequency */ clk_set_rate(cpuclk, freq*1000); /* notifiers */ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); pr_debug("cpufreq: set frequency %u kHz\n", freq); return 0; } static int gsc3280_cpufreq_cpu_init(struct cpufreq_policy *policy) { int i; if (!cpu_online(policy->cpu)) return -ENODEV; cpuclk = clk_get(NULL, "cpu"); if (IS_ERR(cpuclk)) { printk(KERN_ERR "cpufreq: couldn't get CPU clk\n"); return PTR_ERR(cpuclk); } cpuclk->rate = clk_get_rate(cpuclk); if (!cpuclk->rate) return -EINVAL; policy->cur = cpuclk->rate/1000; cpufreq_frequency_table_get_attr(&gsc3280_cpufreq_table[0], policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, &gsc3280_cpufreq_table[0]); } static int gsc3280_cpufreq_verify(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, &gsc3280_cpufreq_table[0]); } static int gsc3280_cpufreq_exit(struct cpufreq_policy *policy) { clk_put(cpuclk); return 0; } static struct freq_attr *gsc3280_table_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, }; static struct cpufreq_driver gsc3280_cpufreq_driver = { .owner = THIS_MODULE, .name = "gsc3280-cpufreq", .init = gsc3280_cpufreq_cpu_init, .verify = gsc3280_cpufreq_verify, .target = gsc3280_cpufreq_target, .get = gsc3280_cpufreq_get, .exit = gsc3280_cpufreq_exit, .attr = gsc3280_table_attr, }; static int __init cpufreq_init(void) { int ret; pr_info("cpufreq: GSC3280 CPU frequency driver.\n"); cpufreq_register_notifier(&gsc3280_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); ret = cpufreq_register_driver(&gsc3280_cpufreq_driver); return ret; } static void __exit cpufreq_exit(void) { cpufreq_unregister_driver(&gsc3280_cpufreq_driver); cpufreq_unregister_notifier(&gsc3280_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } module_init(cpufreq_init); module_exit(cpufreq_exit); MODULE_AUTHOR("Liu Jianhua "); MODULE_DESCRIPTION("CPU frequency scaling driver for gsc3280"); MODULE_LICENSE("GPL");