xref: /openbmc/linux/drivers/clk/st/clkgen-mux.c (revision 94885faf9dbcc2ca704d60e7db2f2b87e0b0fe6e)
1*94885fafSGabriel FERNANDEZ /*
2*94885fafSGabriel FERNANDEZ  * clkgen-mux.c: ST GEN-MUX Clock driver
3*94885fafSGabriel FERNANDEZ  *
4*94885fafSGabriel FERNANDEZ  * Copyright (C) 2014 STMicroelectronics (R&D) Limited
5*94885fafSGabriel FERNANDEZ  *
6*94885fafSGabriel FERNANDEZ  * Authors: Stephen Gallimore <stephen.gallimore@st.com>
7*94885fafSGabriel FERNANDEZ  *	    Pankaj Dev <pankaj.dev@st.com>
8*94885fafSGabriel FERNANDEZ  *
9*94885fafSGabriel FERNANDEZ  * This program is free software; you can redistribute it and/or modify
10*94885fafSGabriel FERNANDEZ  * it under the terms of the GNU General Public License as published by
11*94885fafSGabriel FERNANDEZ  * the Free Software Foundation; either version 2 of the License, or
12*94885fafSGabriel FERNANDEZ  * (at your option) any later version.
13*94885fafSGabriel FERNANDEZ  *
14*94885fafSGabriel FERNANDEZ  */
15*94885fafSGabriel FERNANDEZ 
16*94885fafSGabriel FERNANDEZ #include <linux/slab.h>
17*94885fafSGabriel FERNANDEZ #include <linux/of_address.h>
18*94885fafSGabriel FERNANDEZ #include <linux/clk-provider.h>
19*94885fafSGabriel FERNANDEZ 
20*94885fafSGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgena_divmux_lock);
21*94885fafSGabriel FERNANDEZ 
22*94885fafSGabriel FERNANDEZ static const char ** __init clkgen_mux_get_parents(struct device_node *np,
23*94885fafSGabriel FERNANDEZ 						       int *num_parents)
24*94885fafSGabriel FERNANDEZ {
25*94885fafSGabriel FERNANDEZ 	const char **parents;
26*94885fafSGabriel FERNANDEZ 	int nparents, i;
27*94885fafSGabriel FERNANDEZ 
28*94885fafSGabriel FERNANDEZ 	nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
29*94885fafSGabriel FERNANDEZ 	if (WARN_ON(nparents <= 0))
30*94885fafSGabriel FERNANDEZ 		return ERR_PTR(-EINVAL);
31*94885fafSGabriel FERNANDEZ 
32*94885fafSGabriel FERNANDEZ 	parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL);
33*94885fafSGabriel FERNANDEZ 	if (!parents)
34*94885fafSGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
35*94885fafSGabriel FERNANDEZ 
36*94885fafSGabriel FERNANDEZ 	for (i = 0; i < nparents; i++)
37*94885fafSGabriel FERNANDEZ 		parents[i] = of_clk_get_parent_name(np, i);
38*94885fafSGabriel FERNANDEZ 
39*94885fafSGabriel FERNANDEZ 	*num_parents = nparents;
40*94885fafSGabriel FERNANDEZ 	return parents;
41*94885fafSGabriel FERNANDEZ }
42*94885fafSGabriel FERNANDEZ 
43*94885fafSGabriel FERNANDEZ /**
44*94885fafSGabriel FERNANDEZ  * DOC: Clock mux with a programmable divider on each of its three inputs.
45*94885fafSGabriel FERNANDEZ  *      The mux has an input setting which effectively gates its output.
46*94885fafSGabriel FERNANDEZ  *
47*94885fafSGabriel FERNANDEZ  * Traits of this clock:
48*94885fafSGabriel FERNANDEZ  * prepare - clk_(un)prepare only ensures parent is (un)prepared
49*94885fafSGabriel FERNANDEZ  * enable - clk_enable and clk_disable are functional & control gating
50*94885fafSGabriel FERNANDEZ  * rate - set rate is supported
51*94885fafSGabriel FERNANDEZ  * parent - set/get parent
52*94885fafSGabriel FERNANDEZ  */
53*94885fafSGabriel FERNANDEZ 
54*94885fafSGabriel FERNANDEZ #define NUM_INPUTS 3
55*94885fafSGabriel FERNANDEZ 
56*94885fafSGabriel FERNANDEZ struct clkgena_divmux {
57*94885fafSGabriel FERNANDEZ 	struct clk_hw hw;
58*94885fafSGabriel FERNANDEZ 	/* Subclassed mux and divider structures */
59*94885fafSGabriel FERNANDEZ 	struct clk_mux mux;
60*94885fafSGabriel FERNANDEZ 	struct clk_divider div[NUM_INPUTS];
61*94885fafSGabriel FERNANDEZ 	/* Enable/running feedback register bits for each input */
62*94885fafSGabriel FERNANDEZ 	void __iomem *feedback_reg[NUM_INPUTS];
63*94885fafSGabriel FERNANDEZ 	int feedback_bit_idx;
64*94885fafSGabriel FERNANDEZ 
65*94885fafSGabriel FERNANDEZ 	u8              muxsel;
66*94885fafSGabriel FERNANDEZ };
67*94885fafSGabriel FERNANDEZ 
68*94885fafSGabriel FERNANDEZ #define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw)
69*94885fafSGabriel FERNANDEZ 
70*94885fafSGabriel FERNANDEZ struct clkgena_divmux_data {
71*94885fafSGabriel FERNANDEZ 	int num_outputs;
72*94885fafSGabriel FERNANDEZ 	int mux_offset;
73*94885fafSGabriel FERNANDEZ 	int mux_offset2;
74*94885fafSGabriel FERNANDEZ 	int mux_start_bit;
75*94885fafSGabriel FERNANDEZ 	int div_offsets[NUM_INPUTS];
76*94885fafSGabriel FERNANDEZ 	int fb_offsets[NUM_INPUTS];
77*94885fafSGabriel FERNANDEZ 	int fb_start_bit_idx;
78*94885fafSGabriel FERNANDEZ };
79*94885fafSGabriel FERNANDEZ 
80*94885fafSGabriel FERNANDEZ #define CKGAX_CLKOPSRC_SWITCH_OFF 0x3
81*94885fafSGabriel FERNANDEZ 
82*94885fafSGabriel FERNANDEZ static int clkgena_divmux_is_running(struct clkgena_divmux *mux)
83*94885fafSGabriel FERNANDEZ {
84*94885fafSGabriel FERNANDEZ 	u32 regval = readl(mux->feedback_reg[mux->muxsel]);
85*94885fafSGabriel FERNANDEZ 	u32 running = regval & BIT(mux->feedback_bit_idx);
86*94885fafSGabriel FERNANDEZ 	return !!running;
87*94885fafSGabriel FERNANDEZ }
88*94885fafSGabriel FERNANDEZ 
89*94885fafSGabriel FERNANDEZ static int clkgena_divmux_enable(struct clk_hw *hw)
90*94885fafSGabriel FERNANDEZ {
91*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
92*94885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
93*94885fafSGabriel FERNANDEZ 	unsigned long timeout;
94*94885fafSGabriel FERNANDEZ 	int ret = 0;
95*94885fafSGabriel FERNANDEZ 
96*94885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
97*94885fafSGabriel FERNANDEZ 
98*94885fafSGabriel FERNANDEZ 	ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
99*94885fafSGabriel FERNANDEZ 	if (ret)
100*94885fafSGabriel FERNANDEZ 		return ret;
101*94885fafSGabriel FERNANDEZ 
102*94885fafSGabriel FERNANDEZ 	timeout = jiffies + msecs_to_jiffies(10);
103*94885fafSGabriel FERNANDEZ 
104*94885fafSGabriel FERNANDEZ 	while (!clkgena_divmux_is_running(genamux)) {
105*94885fafSGabriel FERNANDEZ 		if (time_after(jiffies, timeout))
106*94885fafSGabriel FERNANDEZ 			return -ETIMEDOUT;
107*94885fafSGabriel FERNANDEZ 		cpu_relax();
108*94885fafSGabriel FERNANDEZ 	}
109*94885fafSGabriel FERNANDEZ 
110*94885fafSGabriel FERNANDEZ 	return 0;
111*94885fafSGabriel FERNANDEZ }
112*94885fafSGabriel FERNANDEZ 
113*94885fafSGabriel FERNANDEZ static void clkgena_divmux_disable(struct clk_hw *hw)
114*94885fafSGabriel FERNANDEZ {
115*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
116*94885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
117*94885fafSGabriel FERNANDEZ 
118*94885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
119*94885fafSGabriel FERNANDEZ 
120*94885fafSGabriel FERNANDEZ 	clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
121*94885fafSGabriel FERNANDEZ }
122*94885fafSGabriel FERNANDEZ 
123*94885fafSGabriel FERNANDEZ static int clkgena_divmux_is_enabled(struct clk_hw *hw)
124*94885fafSGabriel FERNANDEZ {
125*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
126*94885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
127*94885fafSGabriel FERNANDEZ 
128*94885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
129*94885fafSGabriel FERNANDEZ 
130*94885fafSGabriel FERNANDEZ 	return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
131*94885fafSGabriel FERNANDEZ }
132*94885fafSGabriel FERNANDEZ 
133*94885fafSGabriel FERNANDEZ u8 clkgena_divmux_get_parent(struct clk_hw *hw)
134*94885fafSGabriel FERNANDEZ {
135*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
136*94885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
137*94885fafSGabriel FERNANDEZ 
138*94885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
139*94885fafSGabriel FERNANDEZ 
140*94885fafSGabriel FERNANDEZ 	genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
141*94885fafSGabriel FERNANDEZ 	if ((s8)genamux->muxsel < 0) {
142*94885fafSGabriel FERNANDEZ 		pr_debug("%s: %s: Invalid parent, setting to default.\n",
143*94885fafSGabriel FERNANDEZ 		      __func__, __clk_get_name(hw->clk));
144*94885fafSGabriel FERNANDEZ 		genamux->muxsel = 0;
145*94885fafSGabriel FERNANDEZ 	}
146*94885fafSGabriel FERNANDEZ 
147*94885fafSGabriel FERNANDEZ 	return genamux->muxsel;
148*94885fafSGabriel FERNANDEZ }
149*94885fafSGabriel FERNANDEZ 
150*94885fafSGabriel FERNANDEZ static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index)
151*94885fafSGabriel FERNANDEZ {
152*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
153*94885fafSGabriel FERNANDEZ 
154*94885fafSGabriel FERNANDEZ 	if (index >= CKGAX_CLKOPSRC_SWITCH_OFF)
155*94885fafSGabriel FERNANDEZ 		return -EINVAL;
156*94885fafSGabriel FERNANDEZ 
157*94885fafSGabriel FERNANDEZ 	genamux->muxsel = index;
158*94885fafSGabriel FERNANDEZ 
159*94885fafSGabriel FERNANDEZ 	/*
160*94885fafSGabriel FERNANDEZ 	 * If the mux is already enabled, call enable directly to set the
161*94885fafSGabriel FERNANDEZ 	 * new mux position and wait for it to start running again. Otherwise
162*94885fafSGabriel FERNANDEZ 	 * do nothing.
163*94885fafSGabriel FERNANDEZ 	 */
164*94885fafSGabriel FERNANDEZ 	if (clkgena_divmux_is_enabled(hw))
165*94885fafSGabriel FERNANDEZ 		clkgena_divmux_enable(hw);
166*94885fafSGabriel FERNANDEZ 
167*94885fafSGabriel FERNANDEZ 	return 0;
168*94885fafSGabriel FERNANDEZ }
169*94885fafSGabriel FERNANDEZ 
170*94885fafSGabriel FERNANDEZ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
171*94885fafSGabriel FERNANDEZ 		unsigned long parent_rate)
172*94885fafSGabriel FERNANDEZ {
173*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
174*94885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
175*94885fafSGabriel FERNANDEZ 
176*94885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
177*94885fafSGabriel FERNANDEZ 
178*94885fafSGabriel FERNANDEZ 	return clk_divider_ops.recalc_rate(div_hw, parent_rate);
179*94885fafSGabriel FERNANDEZ }
180*94885fafSGabriel FERNANDEZ 
181*94885fafSGabriel FERNANDEZ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate,
182*94885fafSGabriel FERNANDEZ 				unsigned long parent_rate)
183*94885fafSGabriel FERNANDEZ {
184*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
185*94885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
186*94885fafSGabriel FERNANDEZ 
187*94885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
188*94885fafSGabriel FERNANDEZ 
189*94885fafSGabriel FERNANDEZ 	return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
190*94885fafSGabriel FERNANDEZ }
191*94885fafSGabriel FERNANDEZ 
192*94885fafSGabriel FERNANDEZ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate,
193*94885fafSGabriel FERNANDEZ 				   unsigned long *prate)
194*94885fafSGabriel FERNANDEZ {
195*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
196*94885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
197*94885fafSGabriel FERNANDEZ 
198*94885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
199*94885fafSGabriel FERNANDEZ 
200*94885fafSGabriel FERNANDEZ 	return clk_divider_ops.round_rate(div_hw, rate, prate);
201*94885fafSGabriel FERNANDEZ }
202*94885fafSGabriel FERNANDEZ 
203*94885fafSGabriel FERNANDEZ static const struct clk_ops clkgena_divmux_ops = {
204*94885fafSGabriel FERNANDEZ 	.enable = clkgena_divmux_enable,
205*94885fafSGabriel FERNANDEZ 	.disable = clkgena_divmux_disable,
206*94885fafSGabriel FERNANDEZ 	.is_enabled = clkgena_divmux_is_enabled,
207*94885fafSGabriel FERNANDEZ 	.get_parent = clkgena_divmux_get_parent,
208*94885fafSGabriel FERNANDEZ 	.set_parent = clkgena_divmux_set_parent,
209*94885fafSGabriel FERNANDEZ 	.round_rate = clkgena_divmux_round_rate,
210*94885fafSGabriel FERNANDEZ 	.recalc_rate = clkgena_divmux_recalc_rate,
211*94885fafSGabriel FERNANDEZ 	.set_rate = clkgena_divmux_set_rate,
212*94885fafSGabriel FERNANDEZ };
213*94885fafSGabriel FERNANDEZ 
214*94885fafSGabriel FERNANDEZ /**
215*94885fafSGabriel FERNANDEZ  * clk_register_genamux - register a genamux clock with the clock framework
216*94885fafSGabriel FERNANDEZ  */
217*94885fafSGabriel FERNANDEZ struct clk *clk_register_genamux(const char *name,
218*94885fafSGabriel FERNANDEZ 				const char **parent_names, u8 num_parents,
219*94885fafSGabriel FERNANDEZ 				void __iomem *reg,
220*94885fafSGabriel FERNANDEZ 				const struct clkgena_divmux_data *muxdata,
221*94885fafSGabriel FERNANDEZ 				u32 idx)
222*94885fafSGabriel FERNANDEZ {
223*94885fafSGabriel FERNANDEZ 	/*
224*94885fafSGabriel FERNANDEZ 	 * Fixed constants across all ClockgenA variants
225*94885fafSGabriel FERNANDEZ 	 */
226*94885fafSGabriel FERNANDEZ 	const int mux_width = 2;
227*94885fafSGabriel FERNANDEZ 	const int divider_width = 5;
228*94885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux;
229*94885fafSGabriel FERNANDEZ 	struct clk *clk;
230*94885fafSGabriel FERNANDEZ 	struct clk_init_data init;
231*94885fafSGabriel FERNANDEZ 	int i;
232*94885fafSGabriel FERNANDEZ 
233*94885fafSGabriel FERNANDEZ 	genamux = kzalloc(sizeof(*genamux), GFP_KERNEL);
234*94885fafSGabriel FERNANDEZ 	if (!genamux)
235*94885fafSGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
236*94885fafSGabriel FERNANDEZ 
237*94885fafSGabriel FERNANDEZ 	init.name = name;
238*94885fafSGabriel FERNANDEZ 	init.ops = &clkgena_divmux_ops;
239*94885fafSGabriel FERNANDEZ 	init.flags = CLK_IS_BASIC;
240*94885fafSGabriel FERNANDEZ 	init.parent_names = parent_names;
241*94885fafSGabriel FERNANDEZ 	init.num_parents = num_parents;
242*94885fafSGabriel FERNANDEZ 
243*94885fafSGabriel FERNANDEZ 	genamux->mux.lock  = &clkgena_divmux_lock;
244*94885fafSGabriel FERNANDEZ 	genamux->mux.mask = BIT(mux_width) - 1;
245*94885fafSGabriel FERNANDEZ 	genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width);
246*94885fafSGabriel FERNANDEZ 	if (genamux->mux.shift > 31) {
247*94885fafSGabriel FERNANDEZ 		/*
248*94885fafSGabriel FERNANDEZ 		 * We have spilled into the second mux register so
249*94885fafSGabriel FERNANDEZ 		 * adjust the register address and the bit shift accordingly
250*94885fafSGabriel FERNANDEZ 		 */
251*94885fafSGabriel FERNANDEZ 		genamux->mux.reg = reg + muxdata->mux_offset2;
252*94885fafSGabriel FERNANDEZ 		genamux->mux.shift -= 32;
253*94885fafSGabriel FERNANDEZ 	} else {
254*94885fafSGabriel FERNANDEZ 		genamux->mux.reg   = reg + muxdata->mux_offset;
255*94885fafSGabriel FERNANDEZ 	}
256*94885fafSGabriel FERNANDEZ 
257*94885fafSGabriel FERNANDEZ 	for (i = 0; i < NUM_INPUTS; i++) {
258*94885fafSGabriel FERNANDEZ 		/*
259*94885fafSGabriel FERNANDEZ 		 * Divider config for each input
260*94885fafSGabriel FERNANDEZ 		 */
261*94885fafSGabriel FERNANDEZ 		void __iomem *divbase = reg + muxdata->div_offsets[i];
262*94885fafSGabriel FERNANDEZ 		genamux->div[i].width = divider_width;
263*94885fafSGabriel FERNANDEZ 		genamux->div[i].reg = divbase + (idx * sizeof(u32));
264*94885fafSGabriel FERNANDEZ 
265*94885fafSGabriel FERNANDEZ 		/*
266*94885fafSGabriel FERNANDEZ 		 * Mux enabled/running feedback register for each input.
267*94885fafSGabriel FERNANDEZ 		 */
268*94885fafSGabriel FERNANDEZ 		genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i];
269*94885fafSGabriel FERNANDEZ 	}
270*94885fafSGabriel FERNANDEZ 
271*94885fafSGabriel FERNANDEZ 	genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx;
272*94885fafSGabriel FERNANDEZ 	genamux->hw.init = &init;
273*94885fafSGabriel FERNANDEZ 
274*94885fafSGabriel FERNANDEZ 	clk = clk_register(NULL, &genamux->hw);
275*94885fafSGabriel FERNANDEZ 	if (IS_ERR(clk)) {
276*94885fafSGabriel FERNANDEZ 		kfree(genamux);
277*94885fafSGabriel FERNANDEZ 		goto err;
278*94885fafSGabriel FERNANDEZ 	}
279*94885fafSGabriel FERNANDEZ 
280*94885fafSGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %lu\n",
281*94885fafSGabriel FERNANDEZ 			__clk_get_name(clk),
282*94885fafSGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
283*94885fafSGabriel FERNANDEZ 			clk_get_rate(clk));
284*94885fafSGabriel FERNANDEZ err:
285*94885fafSGabriel FERNANDEZ 	return clk;
286*94885fafSGabriel FERNANDEZ }
287*94885fafSGabriel FERNANDEZ 
288*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65hs = {
289*94885fafSGabriel FERNANDEZ 	.num_outputs = 4,
290*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x14,
291*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
292*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x800, 0x900, 0xb00 },
293*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x18, 0x1c, 0x20 },
294*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 0,
295*94885fafSGabriel FERNANDEZ };
296*94885fafSGabriel FERNANDEZ 
297*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65ls = {
298*94885fafSGabriel FERNANDEZ 	.num_outputs = 14,
299*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x14,
300*94885fafSGabriel FERNANDEZ 	.mux_offset2 = 0x24,
301*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 8,
302*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x810, 0xa10, 0xb10 },
303*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x18, 0x1c, 0x20 },
304*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 4,
305*94885fafSGabriel FERNANDEZ };
306*94885fafSGabriel FERNANDEZ 
307*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf0 = {
308*94885fafSGabriel FERNANDEZ 	.num_outputs = 8,
309*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x1c,
310*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
311*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x800, 0x900, 0xa60 },
312*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
313*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 0,
314*94885fafSGabriel FERNANDEZ };
315*94885fafSGabriel FERNANDEZ 
316*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf1 = {
317*94885fafSGabriel FERNANDEZ 	.num_outputs = 8,
318*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x1c,
319*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 16,
320*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x820, 0x980, 0xa80 },
321*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
322*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 8,
323*94885fafSGabriel FERNANDEZ };
324*94885fafSGabriel FERNANDEZ 
325*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf2 = {
326*94885fafSGabriel FERNANDEZ 	.num_outputs = 8,
327*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x20,
328*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
329*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x840, 0xa20, 0xb10 },
330*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
331*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 16,
332*94885fafSGabriel FERNANDEZ };
333*94885fafSGabriel FERNANDEZ 
334*94885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf3 = {
335*94885fafSGabriel FERNANDEZ 	.num_outputs = 8,
336*94885fafSGabriel FERNANDEZ 	.mux_offset = 0x20,
337*94885fafSGabriel FERNANDEZ 	.mux_start_bit = 16,
338*94885fafSGabriel FERNANDEZ 	.div_offsets = { 0x860, 0xa40, 0xb30 },
339*94885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
340*94885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 24,
341*94885fafSGabriel FERNANDEZ };
342*94885fafSGabriel FERNANDEZ 
343*94885fafSGabriel FERNANDEZ static struct of_device_id clkgena_divmux_of_match[] = {
344*94885fafSGabriel FERNANDEZ 	{
345*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c65-hs",
346*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c65hs,
347*94885fafSGabriel FERNANDEZ 	},
348*94885fafSGabriel FERNANDEZ 	{
349*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c65-ls",
350*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c65ls,
351*94885fafSGabriel FERNANDEZ 	},
352*94885fafSGabriel FERNANDEZ 	{
353*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf0",
354*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf0,
355*94885fafSGabriel FERNANDEZ 	},
356*94885fafSGabriel FERNANDEZ 	{
357*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf1",
358*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf1,
359*94885fafSGabriel FERNANDEZ 	},
360*94885fafSGabriel FERNANDEZ 	{
361*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf2",
362*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf2,
363*94885fafSGabriel FERNANDEZ 	},
364*94885fafSGabriel FERNANDEZ 	{
365*94885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf3",
366*94885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf3,
367*94885fafSGabriel FERNANDEZ 	},
368*94885fafSGabriel FERNANDEZ 	{}
369*94885fafSGabriel FERNANDEZ };
370*94885fafSGabriel FERNANDEZ 
371*94885fafSGabriel FERNANDEZ static void __iomem * __init clkgen_get_register_base(
372*94885fafSGabriel FERNANDEZ 				struct device_node *np)
373*94885fafSGabriel FERNANDEZ {
374*94885fafSGabriel FERNANDEZ 	struct device_node *pnode;
375*94885fafSGabriel FERNANDEZ 	void __iomem *reg = NULL;
376*94885fafSGabriel FERNANDEZ 
377*94885fafSGabriel FERNANDEZ 	pnode = of_get_parent(np);
378*94885fafSGabriel FERNANDEZ 	if (!pnode)
379*94885fafSGabriel FERNANDEZ 		return NULL;
380*94885fafSGabriel FERNANDEZ 
381*94885fafSGabriel FERNANDEZ 	reg = of_iomap(pnode, 0);
382*94885fafSGabriel FERNANDEZ 
383*94885fafSGabriel FERNANDEZ 	of_node_put(pnode);
384*94885fafSGabriel FERNANDEZ 	return reg;
385*94885fafSGabriel FERNANDEZ }
386*94885fafSGabriel FERNANDEZ 
387*94885fafSGabriel FERNANDEZ void __init st_of_clkgena_divmux_setup(struct device_node *np)
388*94885fafSGabriel FERNANDEZ {
389*94885fafSGabriel FERNANDEZ 	const struct of_device_id *match;
390*94885fafSGabriel FERNANDEZ 	const struct clkgena_divmux_data *data;
391*94885fafSGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
392*94885fafSGabriel FERNANDEZ 	void __iomem *reg;
393*94885fafSGabriel FERNANDEZ 	const char **parents;
394*94885fafSGabriel FERNANDEZ 	int num_parents = 0, i;
395*94885fafSGabriel FERNANDEZ 
396*94885fafSGabriel FERNANDEZ 	match = of_match_node(clkgena_divmux_of_match, np);
397*94885fafSGabriel FERNANDEZ 	if (WARN_ON(!match))
398*94885fafSGabriel FERNANDEZ 		return;
399*94885fafSGabriel FERNANDEZ 
400*94885fafSGabriel FERNANDEZ 	data = (struct clkgena_divmux_data *)match->data;
401*94885fafSGabriel FERNANDEZ 
402*94885fafSGabriel FERNANDEZ 	reg = clkgen_get_register_base(np);
403*94885fafSGabriel FERNANDEZ 	if (!reg)
404*94885fafSGabriel FERNANDEZ 		return;
405*94885fafSGabriel FERNANDEZ 
406*94885fafSGabriel FERNANDEZ 	parents = clkgen_mux_get_parents(np, &num_parents);
407*94885fafSGabriel FERNANDEZ 	if (IS_ERR(parents))
408*94885fafSGabriel FERNANDEZ 		return;
409*94885fafSGabriel FERNANDEZ 
410*94885fafSGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
411*94885fafSGabriel FERNANDEZ 	if (!clk_data)
412*94885fafSGabriel FERNANDEZ 		goto err;
413*94885fafSGabriel FERNANDEZ 
414*94885fafSGabriel FERNANDEZ 	clk_data->clk_num = data->num_outputs;
415*94885fafSGabriel FERNANDEZ 	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
416*94885fafSGabriel FERNANDEZ 				 GFP_KERNEL);
417*94885fafSGabriel FERNANDEZ 
418*94885fafSGabriel FERNANDEZ 	if (!clk_data->clks)
419*94885fafSGabriel FERNANDEZ 		goto err;
420*94885fafSGabriel FERNANDEZ 
421*94885fafSGabriel FERNANDEZ 	for (i = 0; i < clk_data->clk_num; i++) {
422*94885fafSGabriel FERNANDEZ 		struct clk *clk;
423*94885fafSGabriel FERNANDEZ 		const char *clk_name;
424*94885fafSGabriel FERNANDEZ 
425*94885fafSGabriel FERNANDEZ 		if (of_property_read_string_index(np, "clock-output-names",
426*94885fafSGabriel FERNANDEZ 						  i, &clk_name))
427*94885fafSGabriel FERNANDEZ 			break;
428*94885fafSGabriel FERNANDEZ 
429*94885fafSGabriel FERNANDEZ 		/*
430*94885fafSGabriel FERNANDEZ 		 * If we read an empty clock name then the output is unused
431*94885fafSGabriel FERNANDEZ 		 */
432*94885fafSGabriel FERNANDEZ 		if (*clk_name == '\0')
433*94885fafSGabriel FERNANDEZ 			continue;
434*94885fafSGabriel FERNANDEZ 
435*94885fafSGabriel FERNANDEZ 		clk = clk_register_genamux(clk_name, parents, num_parents,
436*94885fafSGabriel FERNANDEZ 					   reg, data, i);
437*94885fafSGabriel FERNANDEZ 
438*94885fafSGabriel FERNANDEZ 		if (IS_ERR(clk))
439*94885fafSGabriel FERNANDEZ 			goto err;
440*94885fafSGabriel FERNANDEZ 
441*94885fafSGabriel FERNANDEZ 		clk_data->clks[i] = clk;
442*94885fafSGabriel FERNANDEZ 	}
443*94885fafSGabriel FERNANDEZ 
444*94885fafSGabriel FERNANDEZ 	kfree(parents);
445*94885fafSGabriel FERNANDEZ 
446*94885fafSGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
447*94885fafSGabriel FERNANDEZ 	return;
448*94885fafSGabriel FERNANDEZ err:
449*94885fafSGabriel FERNANDEZ 	if (clk_data)
450*94885fafSGabriel FERNANDEZ 		kfree(clk_data->clks);
451*94885fafSGabriel FERNANDEZ 
452*94885fafSGabriel FERNANDEZ 	kfree(clk_data);
453*94885fafSGabriel FERNANDEZ 	kfree(parents);
454*94885fafSGabriel FERNANDEZ }
455*94885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup);
456*94885fafSGabriel FERNANDEZ 
457*94885fafSGabriel FERNANDEZ struct clkgena_prediv_data {
458*94885fafSGabriel FERNANDEZ 	u32 offset;
459*94885fafSGabriel FERNANDEZ 	u8 shift;
460*94885fafSGabriel FERNANDEZ 	struct clk_div_table *table;
461*94885fafSGabriel FERNANDEZ };
462*94885fafSGabriel FERNANDEZ 
463*94885fafSGabriel FERNANDEZ static struct clk_div_table prediv_table16[] = {
464*94885fafSGabriel FERNANDEZ 	{ .val = 0, .div = 1 },
465*94885fafSGabriel FERNANDEZ 	{ .val = 1, .div = 16 },
466*94885fafSGabriel FERNANDEZ 	{ .div = 0 },
467*94885fafSGabriel FERNANDEZ };
468*94885fafSGabriel FERNANDEZ 
469*94885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c65_data = {
470*94885fafSGabriel FERNANDEZ 	.offset = 0x4c,
471*94885fafSGabriel FERNANDEZ 	.shift = 31,
472*94885fafSGabriel FERNANDEZ 	.table = prediv_table16,
473*94885fafSGabriel FERNANDEZ };
474*94885fafSGabriel FERNANDEZ 
475*94885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c32_data = {
476*94885fafSGabriel FERNANDEZ 	.offset = 0x50,
477*94885fafSGabriel FERNANDEZ 	.shift = 1,
478*94885fafSGabriel FERNANDEZ 	.table = prediv_table16,
479*94885fafSGabriel FERNANDEZ };
480*94885fafSGabriel FERNANDEZ 
481*94885fafSGabriel FERNANDEZ static struct of_device_id clkgena_prediv_of_match[] = {
482*94885fafSGabriel FERNANDEZ 	{ .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data },
483*94885fafSGabriel FERNANDEZ 	{ .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data },
484*94885fafSGabriel FERNANDEZ 	{}
485*94885fafSGabriel FERNANDEZ };
486*94885fafSGabriel FERNANDEZ 
487*94885fafSGabriel FERNANDEZ void __init st_of_clkgena_prediv_setup(struct device_node *np)
488*94885fafSGabriel FERNANDEZ {
489*94885fafSGabriel FERNANDEZ 	const struct of_device_id *match;
490*94885fafSGabriel FERNANDEZ 	void __iomem *reg;
491*94885fafSGabriel FERNANDEZ 	const char *parent_name, *clk_name;
492*94885fafSGabriel FERNANDEZ 	struct clk *clk;
493*94885fafSGabriel FERNANDEZ 	struct clkgena_prediv_data *data;
494*94885fafSGabriel FERNANDEZ 
495*94885fafSGabriel FERNANDEZ 	match = of_match_node(clkgena_prediv_of_match, np);
496*94885fafSGabriel FERNANDEZ 	if (!match) {
497*94885fafSGabriel FERNANDEZ 		pr_err("%s: No matching data\n", __func__);
498*94885fafSGabriel FERNANDEZ 		return;
499*94885fafSGabriel FERNANDEZ 	}
500*94885fafSGabriel FERNANDEZ 
501*94885fafSGabriel FERNANDEZ 	data = (struct clkgena_prediv_data *)match->data;
502*94885fafSGabriel FERNANDEZ 
503*94885fafSGabriel FERNANDEZ 	reg = clkgen_get_register_base(np);
504*94885fafSGabriel FERNANDEZ 	if (!reg)
505*94885fafSGabriel FERNANDEZ 		return;
506*94885fafSGabriel FERNANDEZ 
507*94885fafSGabriel FERNANDEZ 	parent_name = of_clk_get_parent_name(np, 0);
508*94885fafSGabriel FERNANDEZ 	if (!parent_name)
509*94885fafSGabriel FERNANDEZ 		return;
510*94885fafSGabriel FERNANDEZ 
511*94885fafSGabriel FERNANDEZ 	if (of_property_read_string_index(np, "clock-output-names",
512*94885fafSGabriel FERNANDEZ 					  0, &clk_name))
513*94885fafSGabriel FERNANDEZ 		return;
514*94885fafSGabriel FERNANDEZ 
515*94885fafSGabriel FERNANDEZ 	clk = clk_register_divider_table(NULL, clk_name, parent_name, 0,
516*94885fafSGabriel FERNANDEZ 					 reg + data->offset, data->shift, 1,
517*94885fafSGabriel FERNANDEZ 					 0, data->table, NULL);
518*94885fafSGabriel FERNANDEZ 	if (IS_ERR(clk))
519*94885fafSGabriel FERNANDEZ 		return;
520*94885fafSGabriel FERNANDEZ 
521*94885fafSGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
522*94885fafSGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %u\n",
523*94885fafSGabriel FERNANDEZ 		__clk_get_name(clk),
524*94885fafSGabriel FERNANDEZ 		__clk_get_name(clk_get_parent(clk)),
525*94885fafSGabriel FERNANDEZ 		(unsigned int)clk_get_rate(clk));
526*94885fafSGabriel FERNANDEZ 
527*94885fafSGabriel FERNANDEZ 	return;
528*94885fafSGabriel FERNANDEZ }
529*94885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup);
530