142099322SDeepak Sikri /*
242099322SDeepak Sikri  * drivers/cpufreq/spear-cpufreq.c
342099322SDeepak Sikri  *
442099322SDeepak Sikri  * CPU Frequency Scaling for SPEAr platform
542099322SDeepak Sikri  *
642099322SDeepak Sikri  * Copyright (C) 2012 ST Microelectronics
742099322SDeepak Sikri  * Deepak Sikri <deepak.sikri@st.com>
842099322SDeepak Sikri  *
942099322SDeepak Sikri  * This file is licensed under the terms of the GNU General Public
1042099322SDeepak Sikri  * License version 2. This program is licensed "as is" without any
1142099322SDeepak Sikri  * warranty of any kind, whether express or implied.
1242099322SDeepak Sikri  */
1342099322SDeepak Sikri 
1442099322SDeepak Sikri #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1542099322SDeepak Sikri 
1642099322SDeepak Sikri #include <linux/clk.h>
1742099322SDeepak Sikri #include <linux/cpufreq.h>
1842099322SDeepak Sikri #include <linux/err.h>
1942099322SDeepak Sikri #include <linux/init.h>
2042099322SDeepak Sikri #include <linux/module.h>
2142099322SDeepak Sikri #include <linux/of.h>
2242099322SDeepak Sikri #include <linux/slab.h>
2342099322SDeepak Sikri #include <linux/types.h>
2442099322SDeepak Sikri 
2542099322SDeepak Sikri /* SPEAr CPUFreq driver data structure */
2642099322SDeepak Sikri static struct {
2742099322SDeepak Sikri 	struct clk *clk;
2842099322SDeepak Sikri 	unsigned int transition_latency;
2942099322SDeepak Sikri 	struct cpufreq_frequency_table *freq_tbl;
3042099322SDeepak Sikri 	u32 cnt;
3142099322SDeepak Sikri } spear_cpufreq;
3242099322SDeepak Sikri 
33f8517804SViresh Kumar static int spear_cpufreq_verify(struct cpufreq_policy *policy)
3442099322SDeepak Sikri {
3542099322SDeepak Sikri 	return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl);
3642099322SDeepak Sikri }
3742099322SDeepak Sikri 
3842099322SDeepak Sikri static unsigned int spear_cpufreq_get(unsigned int cpu)
3942099322SDeepak Sikri {
4042099322SDeepak Sikri 	return clk_get_rate(spear_cpufreq.clk) / 1000;
4142099322SDeepak Sikri }
4242099322SDeepak Sikri 
4342099322SDeepak Sikri static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq)
4442099322SDeepak Sikri {
4542099322SDeepak Sikri 	struct clk *sys_pclk;
4642099322SDeepak Sikri 	int pclk;
4742099322SDeepak Sikri 	/*
4842099322SDeepak Sikri 	 * In SPEAr1340, cpu clk's parent sys clk can take input from
4942099322SDeepak Sikri 	 * following sources
5042099322SDeepak Sikri 	 */
5142099322SDeepak Sikri 	const char *sys_clk_src[] = {
5242099322SDeepak Sikri 		"sys_syn_clk",
5342099322SDeepak Sikri 		"pll1_clk",
5442099322SDeepak Sikri 		"pll2_clk",
5542099322SDeepak Sikri 		"pll3_clk",
5642099322SDeepak Sikri 	};
5742099322SDeepak Sikri 
5842099322SDeepak Sikri 	/*
5942099322SDeepak Sikri 	 * As sys clk can have multiple source with their own range
6042099322SDeepak Sikri 	 * limitation so we choose possible sources accordingly
6142099322SDeepak Sikri 	 */
6242099322SDeepak Sikri 	if (newfreq <= 300000000)
6342099322SDeepak Sikri 		pclk = 0; /* src is sys_syn_clk */
6442099322SDeepak Sikri 	else if (newfreq > 300000000 && newfreq <= 500000000)
6542099322SDeepak Sikri 		pclk = 3; /* src is pll3_clk */
6642099322SDeepak Sikri 	else if (newfreq == 600000000)
6742099322SDeepak Sikri 		pclk = 1; /* src is pll1_clk */
6842099322SDeepak Sikri 	else
6942099322SDeepak Sikri 		return ERR_PTR(-EINVAL);
7042099322SDeepak Sikri 
7142099322SDeepak Sikri 	/* Get parent to sys clock */
7242099322SDeepak Sikri 	sys_pclk = clk_get(NULL, sys_clk_src[pclk]);
7342099322SDeepak Sikri 	if (IS_ERR(sys_pclk))
7442099322SDeepak Sikri 		pr_err("Failed to get %s clock\n", sys_clk_src[pclk]);
7542099322SDeepak Sikri 
7642099322SDeepak Sikri 	return sys_pclk;
7742099322SDeepak Sikri }
7842099322SDeepak Sikri 
7942099322SDeepak Sikri /*
8042099322SDeepak Sikri  * In SPEAr1340, we cannot use newfreq directly because we need to actually
8142099322SDeepak Sikri  * access a source clock (clk) which might not be ancestor of cpu at present.
8242099322SDeepak Sikri  * Hence in SPEAr1340 we would operate on source clock directly before switching
8342099322SDeepak Sikri  * cpu clock to it.
8442099322SDeepak Sikri  */
8542099322SDeepak Sikri static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq)
8642099322SDeepak Sikri {
8742099322SDeepak Sikri 	struct clk *sys_clk;
8842099322SDeepak Sikri 	int ret = 0;
8942099322SDeepak Sikri 
9042099322SDeepak Sikri 	sys_clk = clk_get_parent(spear_cpufreq.clk);
9142099322SDeepak Sikri 	if (IS_ERR(sys_clk)) {
9242099322SDeepak Sikri 		pr_err("failed to get cpu's parent (sys) clock\n");
9342099322SDeepak Sikri 		return PTR_ERR(sys_clk);
9442099322SDeepak Sikri 	}
9542099322SDeepak Sikri 
9642099322SDeepak Sikri 	/* Set the rate of the source clock before changing the parent */
9742099322SDeepak Sikri 	ret = clk_set_rate(sys_pclk, newfreq);
9842099322SDeepak Sikri 	if (ret) {
9942099322SDeepak Sikri 		pr_err("Failed to set sys clk rate to %lu\n", newfreq);
10042099322SDeepak Sikri 		return ret;
10142099322SDeepak Sikri 	}
10242099322SDeepak Sikri 
10342099322SDeepak Sikri 	ret = clk_set_parent(sys_clk, sys_pclk);
10442099322SDeepak Sikri 	if (ret) {
10542099322SDeepak Sikri 		pr_err("Failed to set sys clk parent\n");
10642099322SDeepak Sikri 		return ret;
10742099322SDeepak Sikri 	}
10842099322SDeepak Sikri 
10942099322SDeepak Sikri 	return 0;
11042099322SDeepak Sikri }
11142099322SDeepak Sikri 
11242099322SDeepak Sikri static int spear_cpufreq_target(struct cpufreq_policy *policy,
11342099322SDeepak Sikri 		unsigned int target_freq, unsigned int relation)
11442099322SDeepak Sikri {
11542099322SDeepak Sikri 	struct cpufreq_freqs freqs;
11642099322SDeepak Sikri 	unsigned long newfreq;
11742099322SDeepak Sikri 	struct clk *srcclk;
11842099322SDeepak Sikri 	int index, ret, mult = 1;
11942099322SDeepak Sikri 
12042099322SDeepak Sikri 	if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl,
12142099322SDeepak Sikri 				target_freq, relation, &index))
12242099322SDeepak Sikri 		return -EINVAL;
12342099322SDeepak Sikri 
12442099322SDeepak Sikri 	freqs.cpu = policy->cpu;
12542099322SDeepak Sikri 	freqs.old = spear_cpufreq_get(0);
12642099322SDeepak Sikri 
12742099322SDeepak Sikri 	newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000;
12842099322SDeepak Sikri 	if (of_machine_is_compatible("st,spear1340")) {
12942099322SDeepak Sikri 		/*
13042099322SDeepak Sikri 		 * SPEAr1340 is special in the sense that due to the possibility
13142099322SDeepak Sikri 		 * of multiple clock sources for cpu clk's parent we can have
13242099322SDeepak Sikri 		 * different clock source for different frequency of cpu clk.
13342099322SDeepak Sikri 		 * Hence we need to choose one from amongst these possible clock
13442099322SDeepak Sikri 		 * sources.
13542099322SDeepak Sikri 		 */
13642099322SDeepak Sikri 		srcclk = spear1340_cpu_get_possible_parent(newfreq);
13742099322SDeepak Sikri 		if (IS_ERR(srcclk)) {
13842099322SDeepak Sikri 			pr_err("Failed to get src clk\n");
13942099322SDeepak Sikri 			return PTR_ERR(srcclk);
14042099322SDeepak Sikri 		}
14142099322SDeepak Sikri 
14242099322SDeepak Sikri 		/* SPEAr1340: src clk is always 2 * intended cpu clk */
14342099322SDeepak Sikri 		mult = 2;
14442099322SDeepak Sikri 	} else {
14542099322SDeepak Sikri 		/*
14642099322SDeepak Sikri 		 * src clock to be altered is ancestor of cpu clock. Hence we
14742099322SDeepak Sikri 		 * can directly work on cpu clk
14842099322SDeepak Sikri 		 */
14942099322SDeepak Sikri 		srcclk = spear_cpufreq.clk;
15042099322SDeepak Sikri 	}
15142099322SDeepak Sikri 
15242099322SDeepak Sikri 	newfreq = clk_round_rate(srcclk, newfreq * mult);
15342099322SDeepak Sikri 	if (newfreq < 0) {
15442099322SDeepak Sikri 		pr_err("clk_round_rate failed for cpu src clock\n");
15542099322SDeepak Sikri 		return newfreq;
15642099322SDeepak Sikri 	}
15742099322SDeepak Sikri 
15842099322SDeepak Sikri 	freqs.new = newfreq / 1000;
15942099322SDeepak Sikri 	freqs.new /= mult;
1606f35a65fSViresh Kumar 
1616f35a65fSViresh Kumar 	for_each_cpu(freqs.cpu, policy->cpus)
16242099322SDeepak Sikri 		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
16342099322SDeepak Sikri 
16442099322SDeepak Sikri 	if (mult == 2)
16542099322SDeepak Sikri 		ret = spear1340_set_cpu_rate(srcclk, newfreq);
16642099322SDeepak Sikri 	else
16742099322SDeepak Sikri 		ret = clk_set_rate(spear_cpufreq.clk, newfreq);
16842099322SDeepak Sikri 
16942099322SDeepak Sikri 	/* Get current rate after clk_set_rate, in case of failure */
17042099322SDeepak Sikri 	if (ret) {
17142099322SDeepak Sikri 		pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret);
17242099322SDeepak Sikri 		freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
17342099322SDeepak Sikri 	}
17442099322SDeepak Sikri 
1756f35a65fSViresh Kumar 	for_each_cpu(freqs.cpu, policy->cpus)
17642099322SDeepak Sikri 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
17742099322SDeepak Sikri 	return ret;
17842099322SDeepak Sikri }
17942099322SDeepak Sikri 
18042099322SDeepak Sikri static int spear_cpufreq_init(struct cpufreq_policy *policy)
18142099322SDeepak Sikri {
18242099322SDeepak Sikri 	int ret;
18342099322SDeepak Sikri 
18442099322SDeepak Sikri 	ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl);
18542099322SDeepak Sikri 	if (ret) {
18642099322SDeepak Sikri 		pr_err("cpufreq_frequency_table_cpuinfo() failed");
18742099322SDeepak Sikri 		return ret;
18842099322SDeepak Sikri 	}
18942099322SDeepak Sikri 
19042099322SDeepak Sikri 	cpufreq_frequency_table_get_attr(spear_cpufreq.freq_tbl, policy->cpu);
19142099322SDeepak Sikri 	policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency;
19242099322SDeepak Sikri 	policy->cur = spear_cpufreq_get(0);
19342099322SDeepak Sikri 
1944c738d00SViresh Kumar 	cpumask_setall(policy->cpus);
19542099322SDeepak Sikri 
19642099322SDeepak Sikri 	return 0;
19742099322SDeepak Sikri }
19842099322SDeepak Sikri 
19942099322SDeepak Sikri static int spear_cpufreq_exit(struct cpufreq_policy *policy)
20042099322SDeepak Sikri {
20142099322SDeepak Sikri 	cpufreq_frequency_table_put_attr(policy->cpu);
20242099322SDeepak Sikri 	return 0;
20342099322SDeepak Sikri }
20442099322SDeepak Sikri 
20542099322SDeepak Sikri static struct freq_attr *spear_cpufreq_attr[] = {
20642099322SDeepak Sikri 	 &cpufreq_freq_attr_scaling_available_freqs,
20742099322SDeepak Sikri 	 NULL,
20842099322SDeepak Sikri };
20942099322SDeepak Sikri 
21042099322SDeepak Sikri static struct cpufreq_driver spear_cpufreq_driver = {
21142099322SDeepak Sikri 	.name		= "cpufreq-spear",
21242099322SDeepak Sikri 	.flags		= CPUFREQ_STICKY,
21342099322SDeepak Sikri 	.verify		= spear_cpufreq_verify,
21442099322SDeepak Sikri 	.target		= spear_cpufreq_target,
21542099322SDeepak Sikri 	.get		= spear_cpufreq_get,
21642099322SDeepak Sikri 	.init		= spear_cpufreq_init,
21742099322SDeepak Sikri 	.exit		= spear_cpufreq_exit,
21842099322SDeepak Sikri 	.attr		= spear_cpufreq_attr,
21942099322SDeepak Sikri };
22042099322SDeepak Sikri 
22142099322SDeepak Sikri static int spear_cpufreq_driver_init(void)
22242099322SDeepak Sikri {
22342099322SDeepak Sikri 	struct device_node *np;
22442099322SDeepak Sikri 	const struct property *prop;
22542099322SDeepak Sikri 	struct cpufreq_frequency_table *freq_tbl;
22642099322SDeepak Sikri 	const __be32 *val;
22742099322SDeepak Sikri 	int cnt, i, ret;
22842099322SDeepak Sikri 
22942099322SDeepak Sikri 	np = of_find_node_by_path("/cpus/cpu@0");
23042099322SDeepak Sikri 	if (!np) {
23142099322SDeepak Sikri 		pr_err("No cpu node found");
23242099322SDeepak Sikri 		return -ENODEV;
23342099322SDeepak Sikri 	}
23442099322SDeepak Sikri 
23542099322SDeepak Sikri 	if (of_property_read_u32(np, "clock-latency",
23642099322SDeepak Sikri 				&spear_cpufreq.transition_latency))
23742099322SDeepak Sikri 		spear_cpufreq.transition_latency = CPUFREQ_ETERNAL;
23842099322SDeepak Sikri 
23942099322SDeepak Sikri 	prop = of_find_property(np, "cpufreq_tbl", NULL);
24042099322SDeepak Sikri 	if (!prop || !prop->value) {
24142099322SDeepak Sikri 		pr_err("Invalid cpufreq_tbl");
24242099322SDeepak Sikri 		ret = -ENODEV;
24342099322SDeepak Sikri 		goto out_put_node;
24442099322SDeepak Sikri 	}
24542099322SDeepak Sikri 
24642099322SDeepak Sikri 	cnt = prop->length / sizeof(u32);
24742099322SDeepak Sikri 	val = prop->value;
24842099322SDeepak Sikri 
24942099322SDeepak Sikri 	freq_tbl = kmalloc(sizeof(*freq_tbl) * (cnt + 1), GFP_KERNEL);
25042099322SDeepak Sikri 	if (!freq_tbl) {
25142099322SDeepak Sikri 		ret = -ENOMEM;
25242099322SDeepak Sikri 		goto out_put_node;
25342099322SDeepak Sikri 	}
25442099322SDeepak Sikri 
25542099322SDeepak Sikri 	for (i = 0; i < cnt; i++) {
25642099322SDeepak Sikri 		freq_tbl[i].index = i;
25742099322SDeepak Sikri 		freq_tbl[i].frequency = be32_to_cpup(val++);
25842099322SDeepak Sikri 	}
25942099322SDeepak Sikri 
26042099322SDeepak Sikri 	freq_tbl[i].index = i;
26142099322SDeepak Sikri 	freq_tbl[i].frequency = CPUFREQ_TABLE_END;
26242099322SDeepak Sikri 
26342099322SDeepak Sikri 	spear_cpufreq.freq_tbl = freq_tbl;
26442099322SDeepak Sikri 
26542099322SDeepak Sikri 	of_node_put(np);
26642099322SDeepak Sikri 
26742099322SDeepak Sikri 	spear_cpufreq.clk = clk_get(NULL, "cpu_clk");
26842099322SDeepak Sikri 	if (IS_ERR(spear_cpufreq.clk)) {
26942099322SDeepak Sikri 		pr_err("Unable to get CPU clock\n");
27042099322SDeepak Sikri 		ret = PTR_ERR(spear_cpufreq.clk);
27142099322SDeepak Sikri 		goto out_put_mem;
27242099322SDeepak Sikri 	}
27342099322SDeepak Sikri 
27442099322SDeepak Sikri 	ret = cpufreq_register_driver(&spear_cpufreq_driver);
27542099322SDeepak Sikri 	if (!ret)
27642099322SDeepak Sikri 		return 0;
27742099322SDeepak Sikri 
27842099322SDeepak Sikri 	pr_err("failed register driver: %d\n", ret);
27942099322SDeepak Sikri 	clk_put(spear_cpufreq.clk);
28042099322SDeepak Sikri 
28142099322SDeepak Sikri out_put_mem:
28242099322SDeepak Sikri 	kfree(freq_tbl);
28342099322SDeepak Sikri 	return ret;
28442099322SDeepak Sikri 
28542099322SDeepak Sikri out_put_node:
28642099322SDeepak Sikri 	of_node_put(np);
28742099322SDeepak Sikri 	return ret;
28842099322SDeepak Sikri }
28942099322SDeepak Sikri late_initcall(spear_cpufreq_driver_init);
29042099322SDeepak Sikri 
29142099322SDeepak Sikri MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>");
29242099322SDeepak Sikri MODULE_DESCRIPTION("SPEAr CPUFreq driver");
29342099322SDeepak Sikri MODULE_LICENSE("GPL");
294