xref: /linux/arch/mips/lantiq/clk.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2171bb2f1SJohn Crispin /*
3171bb2f1SJohn Crispin  *
4171bb2f1SJohn Crispin  * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
597b92108SJohn Crispin  * Copyright (C) 2010 John Crispin <john@phrozen.org>
6171bb2f1SJohn Crispin  */
7171bb2f1SJohn Crispin #include <linux/io.h>
84af92e7aSJohn Crispin #include <linux/export.h>
9171bb2f1SJohn Crispin #include <linux/init.h>
10171bb2f1SJohn Crispin #include <linux/kernel.h>
11171bb2f1SJohn Crispin #include <linux/types.h>
12171bb2f1SJohn Crispin #include <linux/clk.h>
13287e3f3fSJohn Crispin #include <linux/clkdev.h>
14171bb2f1SJohn Crispin #include <linux/err.h>
15171bb2f1SJohn Crispin #include <linux/list.h>
16171bb2f1SJohn Crispin 
17171bb2f1SJohn Crispin #include <asm/time.h>
18171bb2f1SJohn Crispin #include <asm/irq.h>
19171bb2f1SJohn Crispin #include <asm/div64.h>
20171bb2f1SJohn Crispin 
21171bb2f1SJohn Crispin #include <lantiq_soc.h>
22171bb2f1SJohn Crispin 
23171bb2f1SJohn Crispin #include "clk.h"
24287e3f3fSJohn Crispin #include "prom.h"
25171bb2f1SJohn Crispin 
26171bb2f1SJohn Crispin /* lantiq socs have 3 static clocks */
27740c606eSJohn Crispin static struct clk cpu_clk_generic[4];
28287e3f3fSJohn Crispin 
clkdev_add_static(unsigned long cpu,unsigned long fpi,unsigned long io,unsigned long ppe)29740c606eSJohn Crispin void clkdev_add_static(unsigned long cpu, unsigned long fpi,
30740c606eSJohn Crispin 			unsigned long io, unsigned long ppe)
31171bb2f1SJohn Crispin {
32287e3f3fSJohn Crispin 	cpu_clk_generic[0].rate = cpu;
33287e3f3fSJohn Crispin 	cpu_clk_generic[1].rate = fpi;
34287e3f3fSJohn Crispin 	cpu_clk_generic[2].rate = io;
35740c606eSJohn Crispin 	cpu_clk_generic[3].rate = ppe;
36287e3f3fSJohn Crispin }
37171bb2f1SJohn Crispin 
clk_get_cpu(void)38287e3f3fSJohn Crispin struct clk *clk_get_cpu(void)
39171bb2f1SJohn Crispin {
40287e3f3fSJohn Crispin 	return &cpu_clk_generic[0];
41287e3f3fSJohn Crispin }
42287e3f3fSJohn Crispin 
clk_get_fpi(void)43287e3f3fSJohn Crispin struct clk *clk_get_fpi(void)
44287e3f3fSJohn Crispin {
45287e3f3fSJohn Crispin 	return &cpu_clk_generic[1];
46287e3f3fSJohn Crispin }
47287e3f3fSJohn Crispin EXPORT_SYMBOL_GPL(clk_get_fpi);
48287e3f3fSJohn Crispin 
clk_get_io(void)49287e3f3fSJohn Crispin struct clk *clk_get_io(void)
50287e3f3fSJohn Crispin {
51287e3f3fSJohn Crispin 	return &cpu_clk_generic[2];
52171bb2f1SJohn Crispin }
53*50255012SRandy Dunlap EXPORT_SYMBOL_GPL(clk_get_io);
54171bb2f1SJohn Crispin 
clk_get_ppe(void)55740c606eSJohn Crispin struct clk *clk_get_ppe(void)
56740c606eSJohn Crispin {
57740c606eSJohn Crispin 	return &cpu_clk_generic[3];
58740c606eSJohn Crispin }
59740c606eSJohn Crispin EXPORT_SYMBOL_GPL(clk_get_ppe);
60740c606eSJohn Crispin 
clk_good(struct clk * clk)61171bb2f1SJohn Crispin static inline int clk_good(struct clk *clk)
62171bb2f1SJohn Crispin {
63171bb2f1SJohn Crispin 	return clk && !IS_ERR(clk);
64171bb2f1SJohn Crispin }
65171bb2f1SJohn Crispin 
clk_get_rate(struct clk * clk)66171bb2f1SJohn Crispin unsigned long clk_get_rate(struct clk *clk)
67171bb2f1SJohn Crispin {
68171bb2f1SJohn Crispin 	if (unlikely(!clk_good(clk)))
69171bb2f1SJohn Crispin 		return 0;
70171bb2f1SJohn Crispin 
71171bb2f1SJohn Crispin 	if (clk->rate != 0)
72171bb2f1SJohn Crispin 		return clk->rate;
73171bb2f1SJohn Crispin 
74171bb2f1SJohn Crispin 	if (clk->get_rate != NULL)
75171bb2f1SJohn Crispin 		return clk->get_rate();
76171bb2f1SJohn Crispin 
77171bb2f1SJohn Crispin 	return 0;
78171bb2f1SJohn Crispin }
79171bb2f1SJohn Crispin EXPORT_SYMBOL(clk_get_rate);
80171bb2f1SJohn Crispin 
clk_set_rate(struct clk * clk,unsigned long rate)81287e3f3fSJohn Crispin int clk_set_rate(struct clk *clk, unsigned long rate)
82171bb2f1SJohn Crispin {
83287e3f3fSJohn Crispin 	if (unlikely(!clk_good(clk)))
84287e3f3fSJohn Crispin 		return 0;
85287e3f3fSJohn Crispin 	if (clk->rates && *clk->rates) {
86287e3f3fSJohn Crispin 		unsigned long *r = clk->rates;
87171bb2f1SJohn Crispin 
88287e3f3fSJohn Crispin 		while (*r && (*r != rate))
89287e3f3fSJohn Crispin 			r++;
90287e3f3fSJohn Crispin 		if (!*r) {
91287e3f3fSJohn Crispin 			pr_err("clk %s.%s: trying to set invalid rate %ld\n",
92287e3f3fSJohn Crispin 				clk->cl.dev_id, clk->cl.con_id, rate);
93287e3f3fSJohn Crispin 			return -1;
94171bb2f1SJohn Crispin 		}
95171bb2f1SJohn Crispin 	}
96287e3f3fSJohn Crispin 	clk->rate = rate;
97287e3f3fSJohn Crispin 	return 0;
98287e3f3fSJohn Crispin }
99287e3f3fSJohn Crispin EXPORT_SYMBOL(clk_set_rate);
100171bb2f1SJohn Crispin 
clk_round_rate(struct clk * clk,unsigned long rate)101500fab97SHauke Mehrtens long clk_round_rate(struct clk *clk, unsigned long rate)
102500fab97SHauke Mehrtens {
103500fab97SHauke Mehrtens 	if (unlikely(!clk_good(clk)))
104500fab97SHauke Mehrtens 		return 0;
105500fab97SHauke Mehrtens 	if (clk->rates && *clk->rates) {
106500fab97SHauke Mehrtens 		unsigned long *r = clk->rates;
107500fab97SHauke Mehrtens 
108500fab97SHauke Mehrtens 		while (*r && (*r != rate))
109500fab97SHauke Mehrtens 			r++;
110500fab97SHauke Mehrtens 		if (!*r) {
111500fab97SHauke Mehrtens 			return clk->rate;
112500fab97SHauke Mehrtens 		}
113500fab97SHauke Mehrtens 	}
114500fab97SHauke Mehrtens 	return rate;
115500fab97SHauke Mehrtens }
116500fab97SHauke Mehrtens EXPORT_SYMBOL(clk_round_rate);
117500fab97SHauke Mehrtens 
clk_enable(struct clk * clk)118744120aaSJohn Crispin int clk_enable(struct clk *clk)
119744120aaSJohn Crispin {
120287e3f3fSJohn Crispin 	if (unlikely(!clk_good(clk)))
121287e3f3fSJohn Crispin 		return -1;
122287e3f3fSJohn Crispin 
123287e3f3fSJohn Crispin 	if (clk->enable)
124287e3f3fSJohn Crispin 		return clk->enable(clk);
125287e3f3fSJohn Crispin 
126287e3f3fSJohn Crispin 	return -1;
127744120aaSJohn Crispin }
128744120aaSJohn Crispin EXPORT_SYMBOL(clk_enable);
129744120aaSJohn Crispin 
clk_disable(struct clk * clk)130744120aaSJohn Crispin void clk_disable(struct clk *clk)
131744120aaSJohn Crispin {
132287e3f3fSJohn Crispin 	if (unlikely(!clk_good(clk)))
133287e3f3fSJohn Crispin 		return;
134287e3f3fSJohn Crispin 
135287e3f3fSJohn Crispin 	if (clk->disable)
136287e3f3fSJohn Crispin 		clk->disable(clk);
137744120aaSJohn Crispin }
138744120aaSJohn Crispin EXPORT_SYMBOL(clk_disable);
139744120aaSJohn Crispin 
clk_activate(struct clk * clk)140287e3f3fSJohn Crispin int clk_activate(struct clk *clk)
141287e3f3fSJohn Crispin {
142287e3f3fSJohn Crispin 	if (unlikely(!clk_good(clk)))
143287e3f3fSJohn Crispin 		return -1;
144287e3f3fSJohn Crispin 
145287e3f3fSJohn Crispin 	if (clk->activate)
146287e3f3fSJohn Crispin 		return clk->activate(clk);
147287e3f3fSJohn Crispin 
148287e3f3fSJohn Crispin 	return -1;
149287e3f3fSJohn Crispin }
150287e3f3fSJohn Crispin EXPORT_SYMBOL(clk_activate);
151287e3f3fSJohn Crispin 
clk_deactivate(struct clk * clk)152287e3f3fSJohn Crispin void clk_deactivate(struct clk *clk)
153287e3f3fSJohn Crispin {
154287e3f3fSJohn Crispin 	if (unlikely(!clk_good(clk)))
155287e3f3fSJohn Crispin 		return;
156287e3f3fSJohn Crispin 
157287e3f3fSJohn Crispin 	if (clk->deactivate)
158287e3f3fSJohn Crispin 		clk->deactivate(clk);
159287e3f3fSJohn Crispin }
160287e3f3fSJohn Crispin EXPORT_SYMBOL(clk_deactivate);
161287e3f3fSJohn Crispin 
clk_get_parent(struct clk * clk)162fc1aabb0SRandy Dunlap struct clk *clk_get_parent(struct clk *clk)
163fc1aabb0SRandy Dunlap {
164fc1aabb0SRandy Dunlap 	return NULL;
165fc1aabb0SRandy Dunlap }
166fc1aabb0SRandy Dunlap EXPORT_SYMBOL(clk_get_parent);
167fc1aabb0SRandy Dunlap 
clk_set_parent(struct clk * clk,struct clk * parent)16876f66dfdSRandy Dunlap int clk_set_parent(struct clk *clk, struct clk *parent)
16976f66dfdSRandy Dunlap {
17076f66dfdSRandy Dunlap 	return 0;
17176f66dfdSRandy Dunlap }
17276f66dfdSRandy Dunlap EXPORT_SYMBOL(clk_set_parent);
17376f66dfdSRandy Dunlap 
get_counter_resolution(void)174287e3f3fSJohn Crispin static inline u32 get_counter_resolution(void)
175171bb2f1SJohn Crispin {
176171bb2f1SJohn Crispin 	u32 res;
177171bb2f1SJohn Crispin 
178171bb2f1SJohn Crispin 	__asm__ __volatile__(
179171bb2f1SJohn Crispin 		".set	push\n"
180171bb2f1SJohn Crispin 		".set	mips32r2\n"
181171bb2f1SJohn Crispin 		"rdhwr	%0, $3\n"
182171bb2f1SJohn Crispin 		".set pop\n"
183171bb2f1SJohn Crispin 		: "=&r" (res)
184171bb2f1SJohn Crispin 		: /* no input */
185171bb2f1SJohn Crispin 		: "memory");
186171bb2f1SJohn Crispin 
187171bb2f1SJohn Crispin 	return res;
188171bb2f1SJohn Crispin }
189171bb2f1SJohn Crispin 
plat_time_init(void)190171bb2f1SJohn Crispin void __init plat_time_init(void)
191171bb2f1SJohn Crispin {
192171bb2f1SJohn Crispin 	struct clk *clk;
193171bb2f1SJohn Crispin 
194287e3f3fSJohn Crispin 	ltq_soc_init();
195171bb2f1SJohn Crispin 
196287e3f3fSJohn Crispin 	clk = clk_get_cpu();
197287e3f3fSJohn Crispin 	mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
198171bb2f1SJohn Crispin 	write_c0_compare(read_c0_count());
199287e3f3fSJohn Crispin 	pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
200171bb2f1SJohn Crispin 	clk_put(clk);
201171bb2f1SJohn Crispin }
202