xref: /openbmc/linux/drivers/clk/clk-axm5516.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c675a00cSAnders Berg /*
3c675a00cSAnders Berg  * drivers/clk/clk-axm5516.c
4c675a00cSAnders Berg  *
5c675a00cSAnders Berg  * Provides clock implementations for three different types of clock devices on
6c675a00cSAnders Berg  * the Axxia device: PLL clock, a clock divider and a clock mux.
7c675a00cSAnders Berg  *
8c675a00cSAnders Berg  * Copyright (C) 2014 LSI Corporation
9c675a00cSAnders Berg  */
10c675a00cSAnders Berg #include <linux/module.h>
11c675a00cSAnders Berg #include <linux/kernel.h>
12c675a00cSAnders Berg #include <linux/slab.h>
13c675a00cSAnders Berg #include <linux/platform_device.h>
14c675a00cSAnders Berg #include <linux/of.h>
15c675a00cSAnders Berg #include <linux/of_address.h>
16c675a00cSAnders Berg #include <linux/clk-provider.h>
17c675a00cSAnders Berg #include <linux/regmap.h>
18c675a00cSAnders Berg #include <dt-bindings/clock/lsi,axm5516-clks.h>
19c675a00cSAnders Berg 
20c675a00cSAnders Berg 
21c675a00cSAnders Berg /**
22c675a00cSAnders Berg  * struct axxia_clk - Common struct to all Axxia clocks.
23c675a00cSAnders Berg  * @hw: clk_hw for the common clk framework
24c675a00cSAnders Berg  * @regmap: Regmap for the clock control registers
25c675a00cSAnders Berg  */
26c675a00cSAnders Berg struct axxia_clk {
27c675a00cSAnders Berg 	struct clk_hw hw;
28c675a00cSAnders Berg 	struct regmap *regmap;
29c675a00cSAnders Berg };
30c675a00cSAnders Berg #define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
31c675a00cSAnders Berg 
32c675a00cSAnders Berg /**
33c675a00cSAnders Berg  * struct axxia_pllclk - Axxia PLL generated clock.
34c675a00cSAnders Berg  * @aclk: Common struct
35c675a00cSAnders Berg  * @reg: Offset into regmap for PLL control register
36c675a00cSAnders Berg  */
37c675a00cSAnders Berg struct axxia_pllclk {
38c675a00cSAnders Berg 	struct axxia_clk aclk;
39c675a00cSAnders Berg 	u32 reg;
40c675a00cSAnders Berg };
41c675a00cSAnders Berg #define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
42c675a00cSAnders Berg 
43c675a00cSAnders Berg /**
44c675a00cSAnders Berg  * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
45c675a00cSAnders Berg  * parent clock rate.
46c675a00cSAnders Berg  */
47c675a00cSAnders Berg static unsigned long
axxia_pllclk_recalc(struct clk_hw * hw,unsigned long parent_rate)48c675a00cSAnders Berg axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
49c675a00cSAnders Berg {
50c675a00cSAnders Berg 	struct axxia_clk *aclk = to_axxia_clk(hw);
51c675a00cSAnders Berg 	struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
52c675a00cSAnders Berg 	unsigned long rate, fbdiv, refdiv, postdiv;
53c675a00cSAnders Berg 	u32 control;
54c675a00cSAnders Berg 
55c675a00cSAnders Berg 	regmap_read(aclk->regmap, pll->reg, &control);
56c675a00cSAnders Berg 	postdiv = ((control >> 0) & 0xf) + 1;
57c675a00cSAnders Berg 	fbdiv   = ((control >> 4) & 0xfff) + 3;
58c675a00cSAnders Berg 	refdiv  = ((control >> 16) & 0x1f) + 1;
59c675a00cSAnders Berg 	rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
60c675a00cSAnders Berg 
61c675a00cSAnders Berg 	return rate;
62c675a00cSAnders Berg }
63c675a00cSAnders Berg 
64c675a00cSAnders Berg static const struct clk_ops axxia_pllclk_ops = {
65c675a00cSAnders Berg 	.recalc_rate = axxia_pllclk_recalc,
66c675a00cSAnders Berg };
67c675a00cSAnders Berg 
68c675a00cSAnders Berg /**
69c675a00cSAnders Berg  * struct axxia_divclk - Axxia clock divider
70c675a00cSAnders Berg  * @aclk: Common struct
71c675a00cSAnders Berg  * @reg: Offset into regmap for PLL control register
72c675a00cSAnders Berg  * @shift: Bit position for divider value
73c675a00cSAnders Berg  * @width: Number of bits in divider value
74c675a00cSAnders Berg  */
75c675a00cSAnders Berg struct axxia_divclk {
76c675a00cSAnders Berg 	struct axxia_clk aclk;
77c675a00cSAnders Berg 	u32 reg;
78c675a00cSAnders Berg 	u32 shift;
79c675a00cSAnders Berg 	u32 width;
80c675a00cSAnders Berg };
81c675a00cSAnders Berg #define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
82c675a00cSAnders Berg 
83c675a00cSAnders Berg /**
84c675a00cSAnders Berg  * axxia_divclk_recalc_rate - Calculate clock divider output rage
85c675a00cSAnders Berg  */
86c675a00cSAnders Berg static unsigned long
axxia_divclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)87c675a00cSAnders Berg axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
88c675a00cSAnders Berg {
89c675a00cSAnders Berg 	struct axxia_clk *aclk = to_axxia_clk(hw);
90c675a00cSAnders Berg 	struct axxia_divclk *divclk = to_axxia_divclk(aclk);
91c675a00cSAnders Berg 	u32 ctrl, div;
92c675a00cSAnders Berg 
93c675a00cSAnders Berg 	regmap_read(aclk->regmap, divclk->reg, &ctrl);
94c675a00cSAnders Berg 	div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
95c675a00cSAnders Berg 
96c675a00cSAnders Berg 	return parent_rate / div;
97c675a00cSAnders Berg }
98c675a00cSAnders Berg 
99c675a00cSAnders Berg static const struct clk_ops axxia_divclk_ops = {
100c675a00cSAnders Berg 	.recalc_rate = axxia_divclk_recalc_rate,
101c675a00cSAnders Berg };
102c675a00cSAnders Berg 
103c675a00cSAnders Berg /**
104c675a00cSAnders Berg  * struct axxia_clkmux - Axxia clock mux
105c675a00cSAnders Berg  * @aclk: Common struct
106c675a00cSAnders Berg  * @reg: Offset into regmap for PLL control register
107c675a00cSAnders Berg  * @shift: Bit position for selection value
108c675a00cSAnders Berg  * @width: Number of bits in selection value
109c675a00cSAnders Berg  */
110c675a00cSAnders Berg struct axxia_clkmux {
111c675a00cSAnders Berg 	struct axxia_clk aclk;
112c675a00cSAnders Berg 	u32 reg;
113c675a00cSAnders Berg 	u32 shift;
114c675a00cSAnders Berg 	u32 width;
115c675a00cSAnders Berg };
116c675a00cSAnders Berg #define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
117c675a00cSAnders Berg 
118c675a00cSAnders Berg /**
119c675a00cSAnders Berg  * axxia_clkmux_get_parent - Return the index of selected parent clock
120c675a00cSAnders Berg  */
axxia_clkmux_get_parent(struct clk_hw * hw)121c675a00cSAnders Berg static u8 axxia_clkmux_get_parent(struct clk_hw *hw)
122c675a00cSAnders Berg {
123c675a00cSAnders Berg 	struct axxia_clk *aclk = to_axxia_clk(hw);
124c675a00cSAnders Berg 	struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
125c675a00cSAnders Berg 	u32 ctrl, parent;
126c675a00cSAnders Berg 
127c675a00cSAnders Berg 	regmap_read(aclk->regmap, mux->reg, &ctrl);
128c675a00cSAnders Berg 	parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
129c675a00cSAnders Berg 
130c675a00cSAnders Berg 	return (u8) parent;
131c675a00cSAnders Berg }
132c675a00cSAnders Berg 
133c675a00cSAnders Berg static const struct clk_ops axxia_clkmux_ops = {
134c675a00cSAnders Berg 	.get_parent = axxia_clkmux_get_parent,
135c675a00cSAnders Berg };
136c675a00cSAnders Berg 
137c675a00cSAnders Berg 
138c675a00cSAnders Berg /*
139c675a00cSAnders Berg  * PLLs
140c675a00cSAnders Berg  */
141c675a00cSAnders Berg 
142c675a00cSAnders Berg static struct axxia_pllclk clk_fab_pll = {
143c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
144c675a00cSAnders Berg 		.name = "clk_fab_pll",
145c675a00cSAnders Berg 		.parent_names = (const char *[]){
146c675a00cSAnders Berg 			"clk_ref0"
147c675a00cSAnders Berg 		},
148c675a00cSAnders Berg 		.num_parents = 1,
149c675a00cSAnders Berg 		.ops = &axxia_pllclk_ops,
150c675a00cSAnders Berg 	},
151c675a00cSAnders Berg 	.reg   = 0x01800,
152c675a00cSAnders Berg };
153c675a00cSAnders Berg 
154c675a00cSAnders Berg static struct axxia_pllclk clk_cpu_pll = {
155c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
156c675a00cSAnders Berg 		.name = "clk_cpu_pll",
157c675a00cSAnders Berg 		.parent_names = (const char *[]){
158c675a00cSAnders Berg 			"clk_ref0"
159c675a00cSAnders Berg 		},
160c675a00cSAnders Berg 		.num_parents = 1,
161c675a00cSAnders Berg 		.ops = &axxia_pllclk_ops,
162c675a00cSAnders Berg 	},
163c675a00cSAnders Berg 	.reg   = 0x02000,
164c675a00cSAnders Berg };
165c675a00cSAnders Berg 
166c675a00cSAnders Berg static struct axxia_pllclk clk_sys_pll = {
167c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
168c675a00cSAnders Berg 		.name = "clk_sys_pll",
169c675a00cSAnders Berg 		.parent_names = (const char *[]){
170c675a00cSAnders Berg 			"clk_ref0"
171c675a00cSAnders Berg 		},
172c675a00cSAnders Berg 		.num_parents = 1,
173c675a00cSAnders Berg 		.ops = &axxia_pllclk_ops,
174c675a00cSAnders Berg 	},
175c675a00cSAnders Berg 	.reg   = 0x02800,
176c675a00cSAnders Berg };
177c675a00cSAnders Berg 
178c675a00cSAnders Berg static struct axxia_pllclk clk_sm0_pll = {
179c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
180c675a00cSAnders Berg 		.name = "clk_sm0_pll",
181c675a00cSAnders Berg 		.parent_names = (const char *[]){
182c675a00cSAnders Berg 			"clk_ref2"
183c675a00cSAnders Berg 		},
184c675a00cSAnders Berg 		.num_parents = 1,
185c675a00cSAnders Berg 		.ops = &axxia_pllclk_ops,
186c675a00cSAnders Berg 	},
187c675a00cSAnders Berg 	.reg   = 0x03000,
188c675a00cSAnders Berg };
189c675a00cSAnders Berg 
190c675a00cSAnders Berg static struct axxia_pllclk clk_sm1_pll = {
191c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
192c675a00cSAnders Berg 		.name = "clk_sm1_pll",
193c675a00cSAnders Berg 		.parent_names = (const char *[]){
194c675a00cSAnders Berg 			"clk_ref1"
195c675a00cSAnders Berg 		},
196c675a00cSAnders Berg 		.num_parents = 1,
197c675a00cSAnders Berg 		.ops = &axxia_pllclk_ops,
198c675a00cSAnders Berg 	},
199c675a00cSAnders Berg 	.reg   = 0x03800,
200c675a00cSAnders Berg };
201c675a00cSAnders Berg 
202c675a00cSAnders Berg /*
203c675a00cSAnders Berg  * Clock dividers
204c675a00cSAnders Berg  */
205c675a00cSAnders Berg 
206c675a00cSAnders Berg static struct axxia_divclk clk_cpu0_div = {
207c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
208c675a00cSAnders Berg 		.name = "clk_cpu0_div",
209c675a00cSAnders Berg 		.parent_names = (const char *[]){
210c675a00cSAnders Berg 			"clk_cpu_pll"
211c675a00cSAnders Berg 		},
212c675a00cSAnders Berg 		.num_parents = 1,
213c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
214c675a00cSAnders Berg 	},
215c675a00cSAnders Berg 	.reg   = 0x10008,
216c675a00cSAnders Berg 	.shift = 0,
217c675a00cSAnders Berg 	.width = 4,
218c675a00cSAnders Berg };
219c675a00cSAnders Berg 
220c675a00cSAnders Berg static struct axxia_divclk clk_cpu1_div = {
221c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
222c675a00cSAnders Berg 		.name = "clk_cpu1_div",
223c675a00cSAnders Berg 		.parent_names = (const char *[]){
224c675a00cSAnders Berg 			"clk_cpu_pll"
225c675a00cSAnders Berg 		},
226c675a00cSAnders Berg 		.num_parents = 1,
227c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
228c675a00cSAnders Berg 	},
229c675a00cSAnders Berg 	.reg   = 0x10008,
230c675a00cSAnders Berg 	.shift = 4,
231c675a00cSAnders Berg 	.width = 4,
232c675a00cSAnders Berg };
233c675a00cSAnders Berg 
234c675a00cSAnders Berg static struct axxia_divclk clk_cpu2_div = {
235c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
236c675a00cSAnders Berg 		.name = "clk_cpu2_div",
237c675a00cSAnders Berg 		.parent_names = (const char *[]){
238c675a00cSAnders Berg 			"clk_cpu_pll"
239c675a00cSAnders Berg 		},
240c675a00cSAnders Berg 		.num_parents = 1,
241c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
242c675a00cSAnders Berg 	},
243c675a00cSAnders Berg 	.reg   = 0x10008,
244c675a00cSAnders Berg 	.shift = 8,
245c675a00cSAnders Berg 	.width = 4,
246c675a00cSAnders Berg };
247c675a00cSAnders Berg 
248c675a00cSAnders Berg static struct axxia_divclk clk_cpu3_div = {
249c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
250c675a00cSAnders Berg 		.name = "clk_cpu3_div",
251c675a00cSAnders Berg 		.parent_names = (const char *[]){
252c675a00cSAnders Berg 			"clk_cpu_pll"
253c675a00cSAnders Berg 		},
254c675a00cSAnders Berg 		.num_parents = 1,
255c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
256c675a00cSAnders Berg 	},
257c675a00cSAnders Berg 	.reg   = 0x10008,
258c675a00cSAnders Berg 	.shift = 12,
259c675a00cSAnders Berg 	.width = 4,
260c675a00cSAnders Berg };
261c675a00cSAnders Berg 
262c675a00cSAnders Berg static struct axxia_divclk clk_nrcp_div = {
263c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
264c675a00cSAnders Berg 		.name = "clk_nrcp_div",
265c675a00cSAnders Berg 		.parent_names = (const char *[]){
266c675a00cSAnders Berg 			"clk_sys_pll"
267c675a00cSAnders Berg 		},
268c675a00cSAnders Berg 		.num_parents = 1,
269c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
270c675a00cSAnders Berg 	},
271c675a00cSAnders Berg 	.reg   = 0x1000c,
272c675a00cSAnders Berg 	.shift = 0,
273c675a00cSAnders Berg 	.width = 4,
274c675a00cSAnders Berg };
275c675a00cSAnders Berg 
276c675a00cSAnders Berg static struct axxia_divclk clk_sys_div = {
277c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
278c675a00cSAnders Berg 		.name = "clk_sys_div",
279c675a00cSAnders Berg 		.parent_names = (const char *[]){
280c675a00cSAnders Berg 			"clk_sys_pll"
281c675a00cSAnders Berg 		},
282c675a00cSAnders Berg 		.num_parents = 1,
283c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
284c675a00cSAnders Berg 	},
285c675a00cSAnders Berg 	.reg   = 0x1000c,
286c675a00cSAnders Berg 	.shift = 4,
287c675a00cSAnders Berg 	.width = 4,
288c675a00cSAnders Berg };
289c675a00cSAnders Berg 
290c675a00cSAnders Berg static struct axxia_divclk clk_fab_div = {
291c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
292c675a00cSAnders Berg 		.name = "clk_fab_div",
293c675a00cSAnders Berg 		.parent_names = (const char *[]){
294c675a00cSAnders Berg 			"clk_fab_pll"
295c675a00cSAnders Berg 		},
296c675a00cSAnders Berg 		.num_parents = 1,
297c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
298c675a00cSAnders Berg 	},
299c675a00cSAnders Berg 	.reg   = 0x1000c,
300c675a00cSAnders Berg 	.shift = 8,
301c675a00cSAnders Berg 	.width = 4,
302c675a00cSAnders Berg };
303c675a00cSAnders Berg 
304c675a00cSAnders Berg static struct axxia_divclk clk_per_div = {
305c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
306c675a00cSAnders Berg 		.name = "clk_per_div",
307c675a00cSAnders Berg 		.parent_names = (const char *[]){
308c675a00cSAnders Berg 			"clk_sm1_pll"
309c675a00cSAnders Berg 		},
310c675a00cSAnders Berg 		.num_parents = 1,
311c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
312c675a00cSAnders Berg 	},
313c675a00cSAnders Berg 	.reg   = 0x1000c,
314c675a00cSAnders Berg 	.shift = 12,
315c675a00cSAnders Berg 	.width = 4,
316c675a00cSAnders Berg };
317c675a00cSAnders Berg 
318c675a00cSAnders Berg static struct axxia_divclk clk_mmc_div = {
319c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
320c675a00cSAnders Berg 		.name = "clk_mmc_div",
321c675a00cSAnders Berg 		.parent_names = (const char *[]){
322c675a00cSAnders Berg 			"clk_sm1_pll"
323c675a00cSAnders Berg 		},
324c675a00cSAnders Berg 		.num_parents = 1,
325c675a00cSAnders Berg 		.ops = &axxia_divclk_ops,
326c675a00cSAnders Berg 	},
327c675a00cSAnders Berg 	.reg   = 0x1000c,
328c675a00cSAnders Berg 	.shift = 16,
329c675a00cSAnders Berg 	.width = 4,
330c675a00cSAnders Berg };
331c675a00cSAnders Berg 
332c675a00cSAnders Berg /*
333c675a00cSAnders Berg  * Clock MUXes
334c675a00cSAnders Berg  */
335c675a00cSAnders Berg 
336c675a00cSAnders Berg static struct axxia_clkmux clk_cpu0_mux = {
337c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
338c675a00cSAnders Berg 		.name = "clk_cpu0",
339c675a00cSAnders Berg 		.parent_names = (const char *[]){
340c675a00cSAnders Berg 			"clk_ref0",
341c675a00cSAnders Berg 			"clk_cpu_pll",
342c675a00cSAnders Berg 			"clk_cpu0_div",
343c675a00cSAnders Berg 			"clk_cpu0_div"
344c675a00cSAnders Berg 		},
345c675a00cSAnders Berg 		.num_parents = 4,
346c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
347c675a00cSAnders Berg 	},
348c675a00cSAnders Berg 	.reg   = 0x10000,
349c675a00cSAnders Berg 	.shift = 0,
350c675a00cSAnders Berg 	.width = 2,
351c675a00cSAnders Berg };
352c675a00cSAnders Berg 
353c675a00cSAnders Berg static struct axxia_clkmux clk_cpu1_mux = {
354c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
355c675a00cSAnders Berg 		.name = "clk_cpu1",
356c675a00cSAnders Berg 		.parent_names = (const char *[]){
357c675a00cSAnders Berg 			"clk_ref0",
358c675a00cSAnders Berg 			"clk_cpu_pll",
359c675a00cSAnders Berg 			"clk_cpu1_div",
360c675a00cSAnders Berg 			"clk_cpu1_div"
361c675a00cSAnders Berg 		},
362c675a00cSAnders Berg 		.num_parents = 4,
363c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
364c675a00cSAnders Berg 	},
365c675a00cSAnders Berg 	.reg   = 0x10000,
366c675a00cSAnders Berg 	.shift = 2,
367c675a00cSAnders Berg 	.width = 2,
368c675a00cSAnders Berg };
369c675a00cSAnders Berg 
370c675a00cSAnders Berg static struct axxia_clkmux clk_cpu2_mux = {
371c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
372c675a00cSAnders Berg 		.name = "clk_cpu2",
373c675a00cSAnders Berg 		.parent_names = (const char *[]){
374c675a00cSAnders Berg 			"clk_ref0",
375c675a00cSAnders Berg 			"clk_cpu_pll",
376c675a00cSAnders Berg 			"clk_cpu2_div",
377c675a00cSAnders Berg 			"clk_cpu2_div"
378c675a00cSAnders Berg 		},
379c675a00cSAnders Berg 		.num_parents = 4,
380c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
381c675a00cSAnders Berg 	},
382c675a00cSAnders Berg 	.reg   = 0x10000,
383c675a00cSAnders Berg 	.shift = 4,
384c675a00cSAnders Berg 	.width = 2,
385c675a00cSAnders Berg };
386c675a00cSAnders Berg 
387c675a00cSAnders Berg static struct axxia_clkmux clk_cpu3_mux = {
388c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
389c675a00cSAnders Berg 		.name = "clk_cpu3",
390c675a00cSAnders Berg 		.parent_names = (const char *[]){
391c675a00cSAnders Berg 			"clk_ref0",
392c675a00cSAnders Berg 			"clk_cpu_pll",
393c675a00cSAnders Berg 			"clk_cpu3_div",
394c675a00cSAnders Berg 			"clk_cpu3_div"
395c675a00cSAnders Berg 		},
396c675a00cSAnders Berg 		.num_parents = 4,
397c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
398c675a00cSAnders Berg 	},
399c675a00cSAnders Berg 	.reg   = 0x10000,
400c675a00cSAnders Berg 	.shift = 6,
401c675a00cSAnders Berg 	.width = 2,
402c675a00cSAnders Berg };
403c675a00cSAnders Berg 
404c675a00cSAnders Berg static struct axxia_clkmux clk_nrcp_mux = {
405c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
406c675a00cSAnders Berg 		.name = "clk_nrcp",
407c675a00cSAnders Berg 		.parent_names = (const char *[]){
408c675a00cSAnders Berg 			"clk_ref0",
409c675a00cSAnders Berg 			"clk_sys_pll",
410c675a00cSAnders Berg 			"clk_nrcp_div",
411c675a00cSAnders Berg 			"clk_nrcp_div"
412c675a00cSAnders Berg 		},
413c675a00cSAnders Berg 		.num_parents = 4,
414c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
415c675a00cSAnders Berg 	},
416c675a00cSAnders Berg 	.reg   = 0x10004,
417c675a00cSAnders Berg 	.shift = 0,
418c675a00cSAnders Berg 	.width = 2,
419c675a00cSAnders Berg };
420c675a00cSAnders Berg 
421c675a00cSAnders Berg static struct axxia_clkmux clk_sys_mux = {
422c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
423c675a00cSAnders Berg 		.name = "clk_sys",
424c675a00cSAnders Berg 		.parent_names = (const char *[]){
425c675a00cSAnders Berg 			"clk_ref0",
426c675a00cSAnders Berg 			"clk_sys_pll",
427c675a00cSAnders Berg 			"clk_sys_div",
428c675a00cSAnders Berg 			"clk_sys_div"
429c675a00cSAnders Berg 		},
430c675a00cSAnders Berg 		.num_parents = 4,
431c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
432c675a00cSAnders Berg 	},
433c675a00cSAnders Berg 	.reg   = 0x10004,
434c675a00cSAnders Berg 	.shift = 2,
435c675a00cSAnders Berg 	.width = 2,
436c675a00cSAnders Berg };
437c675a00cSAnders Berg 
438c675a00cSAnders Berg static struct axxia_clkmux clk_fab_mux = {
439c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
440c675a00cSAnders Berg 		.name = "clk_fab",
441c675a00cSAnders Berg 		.parent_names = (const char *[]){
442c675a00cSAnders Berg 			"clk_ref0",
443c675a00cSAnders Berg 			"clk_fab_pll",
444c675a00cSAnders Berg 			"clk_fab_div",
445c675a00cSAnders Berg 			"clk_fab_div"
446c675a00cSAnders Berg 		},
447c675a00cSAnders Berg 		.num_parents = 4,
448c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
449c675a00cSAnders Berg 	},
450c675a00cSAnders Berg 	.reg   = 0x10004,
451c675a00cSAnders Berg 	.shift = 4,
452c675a00cSAnders Berg 	.width = 2,
453c675a00cSAnders Berg };
454c675a00cSAnders Berg 
455c675a00cSAnders Berg static struct axxia_clkmux clk_per_mux = {
456c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
457c675a00cSAnders Berg 		.name = "clk_per",
458c675a00cSAnders Berg 		.parent_names = (const char *[]){
459c675a00cSAnders Berg 			"clk_ref1",
460c675a00cSAnders Berg 			"clk_per_div"
461c675a00cSAnders Berg 		},
462c675a00cSAnders Berg 		.num_parents = 2,
463c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
464c675a00cSAnders Berg 	},
465c675a00cSAnders Berg 	.reg   = 0x10004,
466c675a00cSAnders Berg 	.shift = 6,
467c675a00cSAnders Berg 	.width = 1,
468c675a00cSAnders Berg };
469c675a00cSAnders Berg 
470c675a00cSAnders Berg static struct axxia_clkmux clk_mmc_mux = {
471c675a00cSAnders Berg 	.aclk.hw.init = &(struct clk_init_data){
472c675a00cSAnders Berg 		.name = "clk_mmc",
473c675a00cSAnders Berg 		.parent_names = (const char *[]){
474c675a00cSAnders Berg 			"clk_ref1",
475c675a00cSAnders Berg 			"clk_mmc_div"
476c675a00cSAnders Berg 		},
477c675a00cSAnders Berg 		.num_parents = 2,
478c675a00cSAnders Berg 		.ops = &axxia_clkmux_ops,
479c675a00cSAnders Berg 	},
480c675a00cSAnders Berg 	.reg   = 0x10004,
481c675a00cSAnders Berg 	.shift = 9,
482c675a00cSAnders Berg 	.width = 1,
483c675a00cSAnders Berg };
484c675a00cSAnders Berg 
485c675a00cSAnders Berg /* Table of all supported clocks indexed by the clock identifiers from the
486c675a00cSAnders Berg  * device tree binding
487c675a00cSAnders Berg  */
488c675a00cSAnders Berg static struct axxia_clk *axmclk_clocks[] = {
489c675a00cSAnders Berg 	[AXXIA_CLK_FAB_PLL]  = &clk_fab_pll.aclk,
490c675a00cSAnders Berg 	[AXXIA_CLK_CPU_PLL]  = &clk_cpu_pll.aclk,
491c675a00cSAnders Berg 	[AXXIA_CLK_SYS_PLL]  = &clk_sys_pll.aclk,
492c675a00cSAnders Berg 	[AXXIA_CLK_SM0_PLL]  = &clk_sm0_pll.aclk,
493c675a00cSAnders Berg 	[AXXIA_CLK_SM1_PLL]  = &clk_sm1_pll.aclk,
494c675a00cSAnders Berg 	[AXXIA_CLK_FAB_DIV]  = &clk_fab_div.aclk,
495c675a00cSAnders Berg 	[AXXIA_CLK_SYS_DIV]  = &clk_sys_div.aclk,
496c675a00cSAnders Berg 	[AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
497c675a00cSAnders Berg 	[AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
498c675a00cSAnders Berg 	[AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
499c675a00cSAnders Berg 	[AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
500c675a00cSAnders Berg 	[AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
501c675a00cSAnders Berg 	[AXXIA_CLK_PER_DIV]  = &clk_per_div.aclk,
502c675a00cSAnders Berg 	[AXXIA_CLK_MMC_DIV]  = &clk_mmc_div.aclk,
503c675a00cSAnders Berg 	[AXXIA_CLK_FAB]      = &clk_fab_mux.aclk,
504c675a00cSAnders Berg 	[AXXIA_CLK_SYS]      = &clk_sys_mux.aclk,
505c675a00cSAnders Berg 	[AXXIA_CLK_NRCP]     = &clk_nrcp_mux.aclk,
506c675a00cSAnders Berg 	[AXXIA_CLK_CPU0]     = &clk_cpu0_mux.aclk,
507c675a00cSAnders Berg 	[AXXIA_CLK_CPU1]     = &clk_cpu1_mux.aclk,
508c675a00cSAnders Berg 	[AXXIA_CLK_CPU2]     = &clk_cpu2_mux.aclk,
509c675a00cSAnders Berg 	[AXXIA_CLK_CPU3]     = &clk_cpu3_mux.aclk,
510c675a00cSAnders Berg 	[AXXIA_CLK_PER]      = &clk_per_mux.aclk,
511c675a00cSAnders Berg 	[AXXIA_CLK_MMC]      = &clk_mmc_mux.aclk,
512c675a00cSAnders Berg };
513c675a00cSAnders Berg 
514235d2aaaSStephen Boyd static struct clk_hw *
of_clk_axmclk_get(struct of_phandle_args * clkspec,void * unused)515235d2aaaSStephen Boyd of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
516235d2aaaSStephen Boyd {
517235d2aaaSStephen Boyd 	unsigned int idx = clkspec->args[0];
518235d2aaaSStephen Boyd 
519235d2aaaSStephen Boyd 	if (idx >= ARRAY_SIZE(axmclk_clocks)) {
520235d2aaaSStephen Boyd 		pr_err("%s: invalid index %u\n", __func__, idx);
521235d2aaaSStephen Boyd 		return ERR_PTR(-EINVAL);
522235d2aaaSStephen Boyd 	}
523235d2aaaSStephen Boyd 
524235d2aaaSStephen Boyd 	return &axmclk_clocks[idx]->hw;
525235d2aaaSStephen Boyd }
526235d2aaaSStephen Boyd 
527c675a00cSAnders Berg static const struct regmap_config axmclk_regmap_config = {
528c675a00cSAnders Berg 	.reg_bits	= 32,
529c675a00cSAnders Berg 	.reg_stride	= 4,
530c675a00cSAnders Berg 	.val_bits	= 32,
531c675a00cSAnders Berg 	.max_register	= 0x1fffc,
532c675a00cSAnders Berg 	.fast_io	= true,
533c675a00cSAnders Berg };
534c675a00cSAnders Berg 
535c675a00cSAnders Berg static const struct of_device_id axmclk_match_table[] = {
536c675a00cSAnders Berg 	{ .compatible = "lsi,axm5516-clks" },
537c675a00cSAnders Berg 	{ }
538c675a00cSAnders Berg };
539c675a00cSAnders Berg MODULE_DEVICE_TABLE(of, axmclk_match_table);
540c675a00cSAnders Berg 
axmclk_probe(struct platform_device * pdev)541c675a00cSAnders Berg static int axmclk_probe(struct platform_device *pdev)
542c675a00cSAnders Berg {
543c675a00cSAnders Berg 	void __iomem *base;
544c675a00cSAnders Berg 	int i, ret;
545c675a00cSAnders Berg 	struct device *dev = &pdev->dev;
546c675a00cSAnders Berg 	struct regmap *regmap;
547c675a00cSAnders Berg 	size_t num_clks;
548c675a00cSAnders Berg 
549*495093efSYangtao Li 	base = devm_platform_ioremap_resource(pdev, 0);
550c675a00cSAnders Berg 	if (IS_ERR(base))
551c675a00cSAnders Berg 		return PTR_ERR(base);
552c675a00cSAnders Berg 
553c675a00cSAnders Berg 	regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
554c675a00cSAnders Berg 	if (IS_ERR(regmap))
555c675a00cSAnders Berg 		return PTR_ERR(regmap);
556c675a00cSAnders Berg 
557c675a00cSAnders Berg 	num_clks = ARRAY_SIZE(axmclk_clocks);
558beb7a2a9SAlexander Sverdlin 	pr_info("axmclk: supporting %zu clocks\n", num_clks);
559c675a00cSAnders Berg 
560c675a00cSAnders Berg 	/* Update each entry with the allocated regmap and register the clock
561c675a00cSAnders Berg 	 * with the common clock framework
562c675a00cSAnders Berg 	 */
563c675a00cSAnders Berg 	for (i = 0; i < num_clks; i++) {
564c675a00cSAnders Berg 		axmclk_clocks[i]->regmap = regmap;
565235d2aaaSStephen Boyd 		ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
566235d2aaaSStephen Boyd 		if (ret)
567235d2aaaSStephen Boyd 			return ret;
568c675a00cSAnders Berg 	}
569c675a00cSAnders Berg 
570f042ebcfSLars-Peter Clausen 	return devm_of_clk_add_hw_provider(dev, of_clk_axmclk_get, NULL);
571c675a00cSAnders Berg }
572c675a00cSAnders Berg 
573c675a00cSAnders Berg static struct platform_driver axmclk_driver = {
574c675a00cSAnders Berg 	.probe		= axmclk_probe,
575c675a00cSAnders Berg 	.driver		= {
576c675a00cSAnders Berg 		.name	= "clk-axm5516",
577c675a00cSAnders Berg 		.of_match_table = axmclk_match_table,
578c675a00cSAnders Berg 	},
579c675a00cSAnders Berg };
580c675a00cSAnders Berg 
axmclk_init(void)581c675a00cSAnders Berg static int __init axmclk_init(void)
582c675a00cSAnders Berg {
583c675a00cSAnders Berg 	return platform_driver_register(&axmclk_driver);
584c675a00cSAnders Berg }
585c675a00cSAnders Berg core_initcall(axmclk_init);
586c675a00cSAnders Berg 
axmclk_exit(void)587c675a00cSAnders Berg static void __exit axmclk_exit(void)
588c675a00cSAnders Berg {
589c675a00cSAnders Berg 	platform_driver_unregister(&axmclk_driver);
590c675a00cSAnders Berg }
591c675a00cSAnders Berg module_exit(axmclk_exit);
592c675a00cSAnders Berg 
593c675a00cSAnders Berg MODULE_DESCRIPTION("AXM5516 clock driver");
594c675a00cSAnders Berg MODULE_LICENSE("GPL v2");
595c675a00cSAnders Berg MODULE_ALIAS("platform:clk-axm5516");
596