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