134ee55075265d68ca858f2426e165733664385b4Heiko Stübner/* 234ee55075265d68ca858f2426e165733664385b4Heiko Stübner * S3C2416/2450 CPUfreq Support 334ee55075265d68ca858f2426e165733664385b4Heiko Stübner * 434ee55075265d68ca858f2426e165733664385b4Heiko Stübner * Copyright 2011 Heiko Stuebner <heiko@sntech.de> 534ee55075265d68ca858f2426e165733664385b4Heiko Stübner * 634ee55075265d68ca858f2426e165733664385b4Heiko Stübner * based on s3c64xx_cpufreq.c 734ee55075265d68ca858f2426e165733664385b4Heiko Stübner * 834ee55075265d68ca858f2426e165733664385b4Heiko Stübner * Copyright 2009 Wolfson Microelectronics plc 934ee55075265d68ca858f2426e165733664385b4Heiko Stübner * 1034ee55075265d68ca858f2426e165733664385b4Heiko Stübner * This program is free software; you can redistribute it and/or modify 1134ee55075265d68ca858f2426e165733664385b4Heiko Stübner * it under the terms of the GNU General Public License version 2 as 1234ee55075265d68ca858f2426e165733664385b4Heiko Stübner * published by the Free Software Foundation. 1334ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 1434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 1534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/kernel.h> 1634ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/types.h> 1734ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/init.h> 1834ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/cpufreq.h> 1934ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/clk.h> 2034ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/err.h> 2134ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/regulator/consumer.h> 2234ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/reboot.h> 2334ee55075265d68ca858f2426e165733664385b4Heiko Stübner#include <linux/module.h> 2434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 2534ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic DEFINE_MUTEX(cpufreq_lock); 2634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 2734ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstruct s3c2416_data { 2834ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct clk *armdiv; 2934ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct clk *armclk; 3034ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct clk *hclk; 3134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 3234ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned long regulator_latency; 3334ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 3434ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct regulator *vddarm; 3534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 3634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 3734ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct cpufreq_frequency_table *freq_table; 3834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 3934ee55075265d68ca858f2426e165733664385b4Heiko Stübner bool is_dvs; 4034ee55075265d68ca858f2426e165733664385b4Heiko Stübner bool disable_dvs; 4134ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 4234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 4334ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct s3c2416_data s3c2416_cpufreq; 4434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 4534ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstruct s3c2416_dvfs { 4634ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned int vddarm_min; 4734ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned int vddarm_max; 4834ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 4934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 5034ee55075265d68ca858f2426e165733664385b4Heiko Stübner/* pseudo-frequency for dvs mode */ 5134ee55075265d68ca858f2426e165733664385b4Heiko Stübner#define FREQ_DVS 132333 5234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 5334ee55075265d68ca858f2426e165733664385b4Heiko Stübner/* frequency to sleep and reboot in 5434ee55075265d68ca858f2426e165733664385b4Heiko Stübner * it's essential to leave dvs, as some boards do not reconfigure the 5534ee55075265d68ca858f2426e165733664385b4Heiko Stübner * regulator on reboot 5634ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 5734ee55075265d68ca858f2426e165733664385b4Heiko Stübner#define FREQ_SLEEP 133333 5834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 5934ee55075265d68ca858f2426e165733664385b4Heiko Stübner/* Sources for the ARMCLK */ 6034ee55075265d68ca858f2426e165733664385b4Heiko Stübner#define SOURCE_HCLK 0 6134ee55075265d68ca858f2426e165733664385b4Heiko Stübner#define SOURCE_ARMDIV 1 6234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 6334ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 6434ee55075265d68ca858f2426e165733664385b4Heiko Stübner/* S3C2416 only supports changing the voltage in the dvs-mode. 6534ee55075265d68ca858f2426e165733664385b4Heiko Stübner * Voltages down to 1.0V seem to work, so we take what the regulator 6634ee55075265d68ca858f2426e165733664385b4Heiko Stübner * can get us. 6734ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 6834ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct s3c2416_dvfs s3c2416_dvfs_table[] = { 6934ee55075265d68ca858f2426e165733664385b4Heiko Stübner [SOURCE_HCLK] = { 950000, 1250000 }, 7034ee55075265d68ca858f2426e165733664385b4Heiko Stübner [SOURCE_ARMDIV] = { 1250000, 1350000 }, 7134ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 7234ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 7334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 7434ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct cpufreq_frequency_table s3c2416_freq_table[] = { 757f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_HCLK, FREQ_DVS }, 767f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 133333 }, 777f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 266666 }, 787f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 400000 }, 797f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, 0, CPUFREQ_TABLE_END }, 8034ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 8134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 8234ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct cpufreq_frequency_table s3c2450_freq_table[] = { 837f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_HCLK, FREQ_DVS }, 847f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 133500 }, 857f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 267000 }, 867f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, SOURCE_ARMDIV, 534000 }, 877f4b04614a273089ad65654f53771c033fadc65eViresh Kumar { 0, 0, CPUFREQ_TABLE_END }, 8834ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 8934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 9034ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu) 9134ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 9234ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; 9334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 9434ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (cpu != 0) 9534ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 9634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 9734ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* return our pseudo-frequency when in dvs mode */ 9834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->is_dvs) 9934ee55075265d68ca858f2426e165733664385b4Heiko Stübner return FREQ_DVS; 10034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 10134ee55075265d68ca858f2426e165733664385b4Heiko Stübner return clk_get_rate(s3c_freq->armclk) / 1000; 10234ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 10334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 10434ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq, 10534ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned int freq) 10634ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 10734ee55075265d68ca858f2426e165733664385b4Heiko Stübner int ret; 10834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 10934ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) { 11034ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = clk_set_rate(s3c_freq->armdiv, freq * 1000); 11134ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret < 0) { 11234ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n", 11334ee55075265d68ca858f2426e165733664385b4Heiko Stübner freq, ret); 11434ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 11534ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 11634ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 11734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 11834ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 11934ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 12034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 12134ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx) 12234ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 12334ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 12434ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_dvfs *dvfs; 12534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 12634ee55075265d68ca858f2426e165733664385b4Heiko Stübner int ret; 12734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 12834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->is_dvs) { 12934ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: already in dvs mode, nothing to do\n"); 13034ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 13134ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 13234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 13334ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n", 13434ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_get_rate(s3c_freq->hclk) / 1000); 13534ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk); 13634ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret < 0) { 13734ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret); 13834ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 13934ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 14034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 14134ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 14234ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* changing the core voltage is only allowed when in dvs mode */ 14334ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->vddarm) { 14434ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs = &s3c2416_dvfs_table[idx]; 14534ee55075265d68ca858f2426e165733664385b4Heiko Stübner 146c03c3013747a4c9e01d1b48637e6dd0ea3ef65c1Masanari Iida pr_debug("cpufreq: setting regulator to %d-%d\n", 14734ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_min, dvfs->vddarm_max); 14834ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = regulator_set_voltage(s3c_freq->vddarm, 14934ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_min, 15034ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_max); 15134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 15234ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* when lowering the voltage failed, there is nothing to do */ 15334ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret != 0) 15434ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to set VDDARM: %d\n", ret); 15534ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 15634ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 15734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 15834ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->is_dvs = 1; 15934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 16034ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 16134ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 16234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 16334ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx) 16434ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 16534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 16634ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_dvfs *dvfs; 16734ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 16834ee55075265d68ca858f2426e165733664385b4Heiko Stübner int ret; 16934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 17034ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (!s3c_freq->is_dvs) { 17134ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: not in dvs mode, so can't leave\n"); 17234ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 17334ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 17434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 17534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 17634ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->vddarm) { 17734ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs = &s3c2416_dvfs_table[idx]; 17834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 179c03c3013747a4c9e01d1b48637e6dd0ea3ef65c1Masanari Iida pr_debug("cpufreq: setting regulator to %d-%d\n", 18034ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_min, dvfs->vddarm_max); 18134ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = regulator_set_voltage(s3c_freq->vddarm, 18234ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_min, 18334ee55075265d68ca858f2426e165733664385b4Heiko Stübner dvfs->vddarm_max); 18434ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret != 0) { 18534ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to set VDDARM: %d\n", ret); 18634ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 18734ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 18834ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 18934ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 19034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 19134ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* force armdiv to hclk frequency for transition from dvs*/ 19234ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) { 19334ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n", 19434ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_get_rate(s3c_freq->hclk) / 1000); 19534ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = s3c2416_cpufreq_set_armdiv(s3c_freq, 19634ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_get_rate(s3c_freq->hclk) / 1000); 19734ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret < 0) { 198278cee0515a3b3abb0d4e614d969b5be35c2c288Masanari Iida pr_err("cpufreq: Failed to set the armdiv to %lukHz: %d\n", 19934ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_get_rate(s3c_freq->hclk) / 1000, ret); 20034ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 20134ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 20234ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 20334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 20434ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n", 20534ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_get_rate(s3c_freq->armdiv) / 1000); 20634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 20734ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv); 20834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret < 0) { 20934ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n", 21034ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret); 21134ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 21234ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 21334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 21434ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->is_dvs = 0; 21534ee55075265d68ca858f2426e165733664385b4Heiko Stübner 21634ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 21734ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 21834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 21934ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, 2209c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar unsigned int index) 22134ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 22234ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; 223d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar unsigned int new_freq; 22434ee55075265d68ca858f2426e165733664385b4Heiko Stübner int idx, ret, to_dvs = 0; 22534ee55075265d68ca858f2426e165733664385b4Heiko Stübner 22634ee55075265d68ca858f2426e165733664385b4Heiko Stübner mutex_lock(&cpufreq_lock); 22734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 2289c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar idx = s3c_freq->freq_table[index].driver_data; 22934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 23034ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (idx == SOURCE_HCLK) 23134ee55075265d68ca858f2426e165733664385b4Heiko Stübner to_dvs = 1; 23234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 23334ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* switching to dvs when it's not allowed */ 23434ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (to_dvs && s3c_freq->disable_dvs) { 23534ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: entering dvs mode not allowed\n"); 23634ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = -EINVAL; 23734ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto out; 23834ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 23934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 24034ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* When leavin dvs mode, always switch the armdiv to the hclk rate 24134ee55075265d68ca858f2426e165733664385b4Heiko Stübner * The S3C2416 has stability issues when switching directly to 24234ee55075265d68ca858f2426e165733664385b4Heiko Stübner * higher frequencies. 24334ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 244d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar new_freq = (s3c_freq->is_dvs && !to_dvs) 24534ee55075265d68ca858f2426e165733664385b4Heiko Stübner ? clk_get_rate(s3c_freq->hclk) / 1000 2469c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar : s3c_freq->freq_table[index].frequency; 24734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 24834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (to_dvs) { 24934ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: enter dvs\n"); 25034ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx); 25134ee55075265d68ca858f2426e165733664385b4Heiko Stübner } else if (s3c_freq->is_dvs) { 25234ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: leave dvs\n"); 25334ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); 25434ee55075265d68ca858f2426e165733664385b4Heiko Stübner } else { 255d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq); 256d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq); 25734ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 25834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 25934ee55075265d68ca858f2426e165733664385b4Heiko Stübnerout: 26034ee55075265d68ca858f2426e165733664385b4Heiko Stübner mutex_unlock(&cpufreq_lock); 26134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 26234ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 26334ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 26434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 26534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 26634ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq) 26734ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 26834ee55075265d68ca858f2426e165733664385b4Heiko Stübner int count, v, i, found; 269041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis struct cpufreq_frequency_table *pos; 27034ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_dvfs *dvfs; 27134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 27234ee55075265d68ca858f2426e165733664385b4Heiko Stübner count = regulator_count_voltages(s3c_freq->vddarm); 27334ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (count < 0) { 27434ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Unable to check supported voltages\n"); 27534ee55075265d68ca858f2426e165733664385b4Heiko Stübner return; 27634ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 27734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 278041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis if (!count) 279041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis goto out; 28034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 281041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) { 282041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis dvfs = &s3c2416_dvfs_table[pos->driver_data]; 28334ee55075265d68ca858f2426e165733664385b4Heiko Stübner found = 0; 28434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 28534ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* Check only the min-voltage, more is always ok on S3C2416 */ 28634ee55075265d68ca858f2426e165733664385b4Heiko Stübner for (i = 0; i < count; i++) { 28734ee55075265d68ca858f2426e165733664385b4Heiko Stübner v = regulator_list_voltage(s3c_freq->vddarm, i); 28834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (v >= dvfs->vddarm_min) 28934ee55075265d68ca858f2426e165733664385b4Heiko Stübner found = 1; 29034ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 29134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 29234ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (!found) { 29334ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: %dkHz unsupported by regulator\n", 294041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency); 295041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency = CPUFREQ_ENTRY_INVALID; 29634ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 29734ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 29834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 299041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotisout: 30034ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* Guessed */ 30134ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->regulator_latency = 1 * 1000 * 1000; 30234ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 30334ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 30434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 30534ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this, 30634ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned long event, void *ptr) 30734ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 30834ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; 30934ee55075265d68ca858f2426e165733664385b4Heiko Stübner int ret; 31034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 31134ee55075265d68ca858f2426e165733664385b4Heiko Stübner mutex_lock(&cpufreq_lock); 31234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 31334ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* disable further changes */ 31434ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->disable_dvs = 1; 31534ee55075265d68ca858f2426e165733664385b4Heiko Stübner 31634ee55075265d68ca858f2426e165733664385b4Heiko Stübner mutex_unlock(&cpufreq_lock); 31734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 31834ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* some boards don't reconfigure the regulator on reboot, which 31934ee55075265d68ca858f2426e165733664385b4Heiko Stübner * could lead to undervolting the cpu when the clock is reset. 32034ee55075265d68ca858f2426e165733664385b4Heiko Stübner * Therefore we always leave the DVS mode on reboot. 32134ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 32234ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->is_dvs) { 32334ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: leave dvs on reboot\n"); 32434ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = cpufreq_driver_target(cpufreq_cpu_get(0), FREQ_SLEEP, 0); 32534ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret < 0) 32634ee55075265d68ca858f2426e165733664385b4Heiko Stübner return NOTIFY_BAD; 32734ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 32834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 32934ee55075265d68ca858f2426e165733664385b4Heiko Stübner return NOTIFY_DONE; 33034ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 33134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 33234ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct notifier_block s3c2416_cpufreq_reboot_notifier = { 33334ee55075265d68ca858f2426e165733664385b4Heiko Stübner .notifier_call = s3c2416_cpufreq_reboot_notifier_evt, 33434ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 33534ee55075265d68ca858f2426e165733664385b4Heiko Stübner 33634ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) 33734ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 33834ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; 339041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis struct cpufreq_frequency_table *pos; 34034ee55075265d68ca858f2426e165733664385b4Heiko Stübner struct clk *msysclk; 34134ee55075265d68ca858f2426e165733664385b4Heiko Stübner unsigned long rate; 34234ee55075265d68ca858f2426e165733664385b4Heiko Stübner int ret; 34334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 34434ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (policy->cpu != 0) 34534ee55075265d68ca858f2426e165733664385b4Heiko Stübner return -EINVAL; 34634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 34734ee55075265d68ca858f2426e165733664385b4Heiko Stübner msysclk = clk_get(NULL, "msysclk"); 34834ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (IS_ERR(msysclk)) { 34934ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = PTR_ERR(msysclk); 35034ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret); 35134ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 35234ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 35334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 35434ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* 35534ee55075265d68ca858f2426e165733664385b4Heiko Stübner * S3C2416 and S3C2450 share the same processor-ID and also provide no 35634ee55075265d68ca858f2426e165733664385b4Heiko Stübner * other means to distinguish them other than through the rate of 35734ee55075265d68ca858f2426e165733664385b4Heiko Stübner * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz. 35834ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 35934ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate = clk_get_rate(msysclk); 36034ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (rate == 800 * 1000 * 1000) { 36134ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n", 36234ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate / 1000); 36334ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->freq_table = s3c2416_freq_table; 36434ee55075265d68ca858f2426e165733664385b4Heiko Stübner policy->cpuinfo.max_freq = 400000; 36534ee55075265d68ca858f2426e165733664385b4Heiko Stübner } else if (rate / 1000 == 534000) { 36634ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n", 36734ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate / 1000); 36834ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->freq_table = s3c2450_freq_table; 36934ee55075265d68ca858f2426e165733664385b4Heiko Stübner policy->cpuinfo.max_freq = 534000; 37034ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 37134ee55075265d68ca858f2426e165733664385b4Heiko Stübner 37234ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* not needed anymore */ 37334ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_put(msysclk); 37434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 37534ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (s3c_freq->freq_table == NULL) { 37634ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n", 37734ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate / 1000); 37834ee55075265d68ca858f2426e165733664385b4Heiko Stübner return -ENODEV; 37934ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 38034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 38134ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->is_dvs = 0; 38234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 38334ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->armdiv = clk_get(NULL, "armdiv"); 38434ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (IS_ERR(s3c_freq->armdiv)) { 38534ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = PTR_ERR(s3c_freq->armdiv); 38634ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret); 38734ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 38834ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 38934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 39034ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->hclk = clk_get(NULL, "hclk"); 39134ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (IS_ERR(s3c_freq->hclk)) { 39234ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = PTR_ERR(s3c_freq->hclk); 39334ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret); 39434ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto err_hclk; 39534ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 39634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 39734ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* chech hclk rate, we only support the common 133MHz for now 39834ee55075265d68ca858f2426e165733664385b4Heiko Stübner * hclk could also run at 66MHz, but this not often used 39934ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 40034ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate = clk_get_rate(s3c_freq->hclk); 40134ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (rate < 133 * 1000 * 1000) { 40234ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: HCLK not at 133MHz\n"); 40334ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_put(s3c_freq->hclk); 40434ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = -EINVAL; 40534ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto err_armclk; 40634ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 40734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 40834ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->armclk = clk_get(NULL, "armclk"); 40934ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (IS_ERR(s3c_freq->armclk)) { 41034ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = PTR_ERR(s3c_freq->armclk); 41134ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret); 41234ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto err_armclk; 41334ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 41434ee55075265d68ca858f2426e165733664385b4Heiko Stübner 41534ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 41634ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->vddarm = regulator_get(NULL, "vddarm"); 41734ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (IS_ERR(s3c_freq->vddarm)) { 41834ee55075265d68ca858f2426e165733664385b4Heiko Stübner ret = PTR_ERR(s3c_freq->vddarm); 41934ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret); 42034ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto err_vddarm; 42134ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 42234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 42334ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c2416_cpufreq_cfg_regulator(s3c_freq); 42434ee55075265d68ca858f2426e165733664385b4Heiko Stübner#else 42534ee55075265d68ca858f2426e165733664385b4Heiko Stübner s3c_freq->regulator_latency = 0; 42634ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 42734ee55075265d68ca858f2426e165733664385b4Heiko Stübner 428041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis cpufreq_for_each_entry(pos, s3c_freq->freq_table) { 42934ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* special handling for dvs mode */ 430041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis if (pos->driver_data == 0) { 43134ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (!s3c_freq->hclk) { 43234ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n", 433041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency); 434041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency = CPUFREQ_ENTRY_INVALID; 43534ee55075265d68ca858f2426e165733664385b4Heiko Stübner } else { 43634ee55075265d68ca858f2426e165733664385b4Heiko Stübner continue; 43734ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 43834ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 43934ee55075265d68ca858f2426e165733664385b4Heiko Stübner 44034ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* Check for frequencies we can generate */ 44134ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate = clk_round_rate(s3c_freq->armdiv, 442041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency * 1000); 44334ee55075265d68ca858f2426e165733664385b4Heiko Stübner rate /= 1000; 444041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis if (rate != pos->frequency) { 44534ee55075265d68ca858f2426e165733664385b4Heiko Stübner pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n", 446041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency, rate); 447041526f915a90b2b628cd0253e2c85da8040276dStratos Karafotis pos->frequency = CPUFREQ_ENTRY_INVALID; 44834ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 44934ee55075265d68ca858f2426e165733664385b4Heiko Stübner } 45034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 45134ee55075265d68ca858f2426e165733664385b4Heiko Stübner /* Datasheet says PLL stabalisation time must be at least 300us, 45234ee55075265d68ca858f2426e165733664385b4Heiko Stübner * so but add some fudge. (reference in LOCKCON0 register description) 45334ee55075265d68ca858f2426e165733664385b4Heiko Stübner */ 454a307a1e6bc0da1ea1e5960fb386b2bbc3587e808Viresh Kumar ret = cpufreq_generic_init(policy, s3c_freq->freq_table, 455a307a1e6bc0da1ea1e5960fb386b2bbc3587e808Viresh Kumar (500 * 1000) + s3c_freq->regulator_latency); 45634ee55075265d68ca858f2426e165733664385b4Heiko Stübner if (ret) 45734ee55075265d68ca858f2426e165733664385b4Heiko Stübner goto err_freq_table; 45834ee55075265d68ca858f2426e165733664385b4Heiko Stübner 45934ee55075265d68ca858f2426e165733664385b4Heiko Stübner register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier); 46034ee55075265d68ca858f2426e165733664385b4Heiko Stübner 46134ee55075265d68ca858f2426e165733664385b4Heiko Stübner return 0; 46234ee55075265d68ca858f2426e165733664385b4Heiko Stübner 46334ee55075265d68ca858f2426e165733664385b4Heiko Stübnererr_freq_table: 46434ee55075265d68ca858f2426e165733664385b4Heiko Stübner#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE 46534ee55075265d68ca858f2426e165733664385b4Heiko Stübner regulator_put(s3c_freq->vddarm); 46634ee55075265d68ca858f2426e165733664385b4Heiko Stübnererr_vddarm: 46734ee55075265d68ca858f2426e165733664385b4Heiko Stübner#endif 46834ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_put(s3c_freq->armclk); 46934ee55075265d68ca858f2426e165733664385b4Heiko Stübnererr_armclk: 47034ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_put(s3c_freq->hclk); 47134ee55075265d68ca858f2426e165733664385b4Heiko Stübnererr_hclk: 47234ee55075265d68ca858f2426e165733664385b4Heiko Stübner clk_put(s3c_freq->armdiv); 47334ee55075265d68ca858f2426e165733664385b4Heiko Stübner 47434ee55075265d68ca858f2426e165733664385b4Heiko Stübner return ret; 47534ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 47634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 47734ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic struct cpufreq_driver s3c2416_cpufreq_driver = { 478ae6b427132ba39d023e332e7d920e9931ff05313Viresh Kumar .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, 479e96a410540764c21464c22660f7da9d3bfede815Viresh Kumar .verify = cpufreq_generic_frequency_table_verify, 4809c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar .target_index = s3c2416_cpufreq_set_target, 48134ee55075265d68ca858f2426e165733664385b4Heiko Stübner .get = s3c2416_cpufreq_get_speed, 48234ee55075265d68ca858f2426e165733664385b4Heiko Stübner .init = s3c2416_cpufreq_driver_init, 48334ee55075265d68ca858f2426e165733664385b4Heiko Stübner .name = "s3c2416", 484e96a410540764c21464c22660f7da9d3bfede815Viresh Kumar .attr = cpufreq_generic_attr, 48534ee55075265d68ca858f2426e165733664385b4Heiko Stübner}; 48634ee55075265d68ca858f2426e165733664385b4Heiko Stübner 48734ee55075265d68ca858f2426e165733664385b4Heiko Stübnerstatic int __init s3c2416_cpufreq_init(void) 48834ee55075265d68ca858f2426e165733664385b4Heiko Stübner{ 48934ee55075265d68ca858f2426e165733664385b4Heiko Stübner return cpufreq_register_driver(&s3c2416_cpufreq_driver); 49034ee55075265d68ca858f2426e165733664385b4Heiko Stübner} 49134ee55075265d68ca858f2426e165733664385b4Heiko Stübnermodule_init(s3c2416_cpufreq_init); 492