/* * Copyright 2014 Sigma Designs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include #include #include /* gbus_read, gbus_write */ #include "temp.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sigma Designs"); MODULE_DESCRIPTION("cpufreq driver for Tangox 87xx"); static struct cpufreq_frequency_table freq_table[] = { { .driver_data = 1 }, { .driver_data = 2 }, { .driver_data = 3 }, { .driver_data = 9 }, { .frequency = CPUFREQ_TABLE_END }, }; static unsigned int tangox_get_freq(unsigned int cpu) { union SYS_clkgen_pll pll; union SYS_clk_div_ctrl div; pll.val = gbus_read_reg32(SYS_clkgen0_pll); if (pll.f.Isel != 1 || pll.f.M != 0) return 0; div.val = gbus_read_reg32(SYS_cpuclk_div_ctrl); if (div.f.BP != 0 || div.f.F != 0) return 0; return TANGOX_XTAL_FREQ * (pll.f.N + 1) / div.f.I >> pll.f.K; } static int tangox_target(struct cpufreq_policy *policy, unsigned int index) { while (gbus_read_reg32(SYS_cpuclk_div_ctrl) >> 31) cpu_relax(); gbus_write_reg32(SYS_cpuclk_div_ctrl, freq_table[index].driver_data); return 0; } static int tangox_cpu_init(struct cpufreq_policy *policy) { struct cpufreq_frequency_table *p; unsigned int freq = tangox_get_freq(0); unsigned int transition_latency_ns = freq / SYS_FAST_RAMP_SPEED; for (p = freq_table; p->frequency != CPUFREQ_TABLE_END; ++p) { unsigned int I = p->driver_data; union SYS_clk_div_ctrl div = SYS_CLK_DIV_CTRL(I); p->driver_data = div.val; p->frequency = freq / I; } return cpufreq_generic_init(policy, freq_table, transition_latency_ns); } static struct cpufreq_driver tangox_cpufreq_driver = { .name = "tangox-cpufreq", .init = tangox_cpu_init, .verify = cpufreq_generic_frequency_table_verify, .target_index = tangox_target, .get = tangox_get_freq, .exit = cpufreq_generic_exit, .attr = cpufreq_generic_attr, }; static int __init tangox_cpufreq_init(void) { return cpufreq_register_driver(&tangox_cpufreq_driver); } static void __exit tangox_cpufreq_exit(void) { cpufreq_unregister_driver(&tangox_cpufreq_driver); } module_init(tangox_cpufreq_init); module_exit(tangox_cpufreq_exit);