xref: /openbmc/linux/drivers/clk/st/clk-flexgen.c (revision 36f8a30c)
1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b1165170SGabriel FERNANDEZ /*
3b1165170SGabriel FERNANDEZ  * clk-flexgen.c
4b1165170SGabriel FERNANDEZ  *
5b1165170SGabriel FERNANDEZ  * Copyright (C) ST-Microelectronics SA 2013
6b1165170SGabriel FERNANDEZ  * Author:  Maxime Coquelin <maxime.coquelin@st.com> for ST-Microelectronics.
7af873fceSThomas Gleixner  */
8b1165170SGabriel FERNANDEZ 
9d5f728acSStephen Boyd #include <linux/clk.h>
10b1165170SGabriel FERNANDEZ #include <linux/clk-provider.h>
11b1165170SGabriel FERNANDEZ #include <linux/module.h>
12b1165170SGabriel FERNANDEZ #include <linux/slab.h>
13b1165170SGabriel FERNANDEZ #include <linux/io.h>
14b1165170SGabriel FERNANDEZ #include <linux/err.h>
15b1165170SGabriel FERNANDEZ #include <linux/string.h>
16b1165170SGabriel FERNANDEZ #include <linux/of.h>
17b1165170SGabriel FERNANDEZ #include <linux/of_address.h>
18b1165170SGabriel FERNANDEZ 
19574dffc2SAlain Volmat struct clkgen_clk_out {
20574dffc2SAlain Volmat 	const char *name;
21574dffc2SAlain Volmat 	unsigned long flags;
22574dffc2SAlain Volmat };
23574dffc2SAlain Volmat 
2426bd0a57SGabriel Fernandez struct clkgen_data {
2526bd0a57SGabriel Fernandez 	unsigned long flags;
26cb80ec76SGabriel Fernandez 	bool mode;
27574dffc2SAlain Volmat 	const struct clkgen_clk_out *outputs;
28574dffc2SAlain Volmat 	const unsigned int outputs_nb;
2926bd0a57SGabriel Fernandez };
3026bd0a57SGabriel Fernandez 
31b1165170SGabriel FERNANDEZ struct flexgen {
32b1165170SGabriel FERNANDEZ 	struct clk_hw hw;
33b1165170SGabriel FERNANDEZ 
34b1165170SGabriel FERNANDEZ 	/* Crossbar */
35b1165170SGabriel FERNANDEZ 	struct clk_mux mux;
36b1165170SGabriel FERNANDEZ 	/* Pre-divisor's gate */
37b1165170SGabriel FERNANDEZ 	struct clk_gate pgate;
38b1165170SGabriel FERNANDEZ 	/* Pre-divisor */
39b1165170SGabriel FERNANDEZ 	struct clk_divider pdiv;
40b1165170SGabriel FERNANDEZ 	/* Final divisor's gate */
41b1165170SGabriel FERNANDEZ 	struct clk_gate fgate;
42b1165170SGabriel FERNANDEZ 	/* Final divisor */
43b1165170SGabriel FERNANDEZ 	struct clk_divider fdiv;
44cb80ec76SGabriel Fernandez 	/* Asynchronous mode control */
45cb80ec76SGabriel Fernandez 	struct clk_gate sync;
46cb80ec76SGabriel Fernandez 	/* hw control flags */
47cb80ec76SGabriel Fernandez 	bool control_mode;
48b1165170SGabriel FERNANDEZ };
49b1165170SGabriel FERNANDEZ 
50b1165170SGabriel FERNANDEZ #define to_flexgen(_hw) container_of(_hw, struct flexgen, hw)
51cb80ec76SGabriel Fernandez #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
52b1165170SGabriel FERNANDEZ 
flexgen_enable(struct clk_hw * hw)53b1165170SGabriel FERNANDEZ static int flexgen_enable(struct clk_hw *hw)
54b1165170SGabriel FERNANDEZ {
55b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
56b1165170SGabriel FERNANDEZ 	struct clk_hw *pgate_hw = &flexgen->pgate.hw;
57b1165170SGabriel FERNANDEZ 	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
58b1165170SGabriel FERNANDEZ 
594e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(pgate_hw, hw);
604e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(fgate_hw, hw);
61b1165170SGabriel FERNANDEZ 
62b1165170SGabriel FERNANDEZ 	clk_gate_ops.enable(pgate_hw);
63b1165170SGabriel FERNANDEZ 
64b1165170SGabriel FERNANDEZ 	clk_gate_ops.enable(fgate_hw);
65b1165170SGabriel FERNANDEZ 
66836ee0f7SStephen Boyd 	pr_debug("%s: flexgen output enabled\n", clk_hw_get_name(hw));
67b1165170SGabriel FERNANDEZ 	return 0;
68b1165170SGabriel FERNANDEZ }
69b1165170SGabriel FERNANDEZ 
flexgen_disable(struct clk_hw * hw)70b1165170SGabriel FERNANDEZ static void flexgen_disable(struct clk_hw *hw)
71b1165170SGabriel FERNANDEZ {
72b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
73b1165170SGabriel FERNANDEZ 	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
74b1165170SGabriel FERNANDEZ 
75b1165170SGabriel FERNANDEZ 	/* disable only the final gate */
764e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(fgate_hw, hw);
77b1165170SGabriel FERNANDEZ 
78b1165170SGabriel FERNANDEZ 	clk_gate_ops.disable(fgate_hw);
79b1165170SGabriel FERNANDEZ 
80836ee0f7SStephen Boyd 	pr_debug("%s: flexgen output disabled\n", clk_hw_get_name(hw));
81b1165170SGabriel FERNANDEZ }
82b1165170SGabriel FERNANDEZ 
flexgen_is_enabled(struct clk_hw * hw)83b1165170SGabriel FERNANDEZ static int flexgen_is_enabled(struct clk_hw *hw)
84b1165170SGabriel FERNANDEZ {
85b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
86b1165170SGabriel FERNANDEZ 	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
87b1165170SGabriel FERNANDEZ 
884e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(fgate_hw, hw);
89b1165170SGabriel FERNANDEZ 
90b1165170SGabriel FERNANDEZ 	if (!clk_gate_ops.is_enabled(fgate_hw))
91b1165170SGabriel FERNANDEZ 		return 0;
92b1165170SGabriel FERNANDEZ 
93b1165170SGabriel FERNANDEZ 	return 1;
94b1165170SGabriel FERNANDEZ }
95b1165170SGabriel FERNANDEZ 
flexgen_get_parent(struct clk_hw * hw)96b1165170SGabriel FERNANDEZ static u8 flexgen_get_parent(struct clk_hw *hw)
97b1165170SGabriel FERNANDEZ {
98b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
99b1165170SGabriel FERNANDEZ 	struct clk_hw *mux_hw = &flexgen->mux.hw;
100b1165170SGabriel FERNANDEZ 
1014e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(mux_hw, hw);
102b1165170SGabriel FERNANDEZ 
103b1165170SGabriel FERNANDEZ 	return clk_mux_ops.get_parent(mux_hw);
104b1165170SGabriel FERNANDEZ }
105b1165170SGabriel FERNANDEZ 
flexgen_set_parent(struct clk_hw * hw,u8 index)106b1165170SGabriel FERNANDEZ static int flexgen_set_parent(struct clk_hw *hw, u8 index)
107b1165170SGabriel FERNANDEZ {
108b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
109b1165170SGabriel FERNANDEZ 	struct clk_hw *mux_hw = &flexgen->mux.hw;
110b1165170SGabriel FERNANDEZ 
1114e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(mux_hw, hw);
112b1165170SGabriel FERNANDEZ 
113b1165170SGabriel FERNANDEZ 	return clk_mux_ops.set_parent(mux_hw, index);
114b1165170SGabriel FERNANDEZ }
115b1165170SGabriel FERNANDEZ 
116b1165170SGabriel FERNANDEZ static inline unsigned long
clk_best_div(unsigned long parent_rate,unsigned long rate)117b1165170SGabriel FERNANDEZ clk_best_div(unsigned long parent_rate, unsigned long rate)
118b1165170SGabriel FERNANDEZ {
119b1165170SGabriel FERNANDEZ 	return parent_rate / rate + ((rate > (2*(parent_rate % rate))) ? 0 : 1);
120b1165170SGabriel FERNANDEZ }
121b1165170SGabriel FERNANDEZ 
flexgen_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)122*36f8a30cSMaxime Ripard static int flexgen_determine_rate(struct clk_hw *hw,
123*36f8a30cSMaxime Ripard 				  struct clk_rate_request *req)
124b1165170SGabriel FERNANDEZ {
125b1165170SGabriel FERNANDEZ 	unsigned long div;
126b1165170SGabriel FERNANDEZ 
127b1165170SGabriel FERNANDEZ 	/* Round div according to exact prate and wished rate */
128*36f8a30cSMaxime Ripard 	div = clk_best_div(req->best_parent_rate, req->rate);
129b1165170SGabriel FERNANDEZ 
13098d8a60eSStephen Boyd 	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
131*36f8a30cSMaxime Ripard 		req->best_parent_rate = req->rate * div;
132*36f8a30cSMaxime Ripard 		return 0;
133b1165170SGabriel FERNANDEZ 	}
134b1165170SGabriel FERNANDEZ 
135*36f8a30cSMaxime Ripard 	req->rate = req->best_parent_rate / div;
136*36f8a30cSMaxime Ripard 	return 0;
137b1165170SGabriel FERNANDEZ }
138b1165170SGabriel FERNANDEZ 
flexgen_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)1398e6dd77cSStephen Boyd static unsigned long flexgen_recalc_rate(struct clk_hw *hw,
140b1165170SGabriel FERNANDEZ 		unsigned long parent_rate)
141b1165170SGabriel FERNANDEZ {
142b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
143b1165170SGabriel FERNANDEZ 	struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
144b1165170SGabriel FERNANDEZ 	struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
145b1165170SGabriel FERNANDEZ 	unsigned long mid_rate;
146b1165170SGabriel FERNANDEZ 
1474e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(pdiv_hw, hw);
1484e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(fdiv_hw, hw);
149b1165170SGabriel FERNANDEZ 
150b1165170SGabriel FERNANDEZ 	mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate);
151b1165170SGabriel FERNANDEZ 
152b1165170SGabriel FERNANDEZ 	return clk_divider_ops.recalc_rate(fdiv_hw, mid_rate);
153b1165170SGabriel FERNANDEZ }
154b1165170SGabriel FERNANDEZ 
flexgen_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)155b1165170SGabriel FERNANDEZ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
156b1165170SGabriel FERNANDEZ 				unsigned long parent_rate)
157b1165170SGabriel FERNANDEZ {
158b1165170SGabriel FERNANDEZ 	struct flexgen *flexgen = to_flexgen(hw);
159b1165170SGabriel FERNANDEZ 	struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
160b1165170SGabriel FERNANDEZ 	struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
161cb80ec76SGabriel Fernandez 	struct clk_hw *sync_hw = &flexgen->sync.hw;
162cb80ec76SGabriel Fernandez 	struct clk_gate *config = to_clk_gate(sync_hw);
163edc30077SPeter Griffin 	unsigned long div = 0;
164b1165170SGabriel FERNANDEZ 	int ret = 0;
165cb80ec76SGabriel Fernandez 	u32 reg;
166b1165170SGabriel FERNANDEZ 
1674e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(pdiv_hw, hw);
1684e907ef6SJavier Martinez Canillas 	__clk_hw_set_clk(fdiv_hw, hw);
169b1165170SGabriel FERNANDEZ 
170cb80ec76SGabriel Fernandez 	if (flexgen->control_mode) {
171cb80ec76SGabriel Fernandez 		reg = readl(config->reg);
172cb80ec76SGabriel Fernandez 		reg &= ~BIT(config->bit_idx);
173cb80ec76SGabriel Fernandez 		writel(reg, config->reg);
174cb80ec76SGabriel Fernandez 	}
175cb80ec76SGabriel Fernandez 
176edc30077SPeter Griffin 	div = clk_best_div(parent_rate, rate);
177b1165170SGabriel FERNANDEZ 
178edc30077SPeter Griffin 	/*
179edc30077SPeter Griffin 	* pdiv is mainly targeted for low freq results, while fdiv
180edc30077SPeter Griffin 	* should be used for div <= 64. The other way round can
181edc30077SPeter Griffin 	* lead to 'duty cycle' issues.
182edc30077SPeter Griffin 	*/
183edc30077SPeter Griffin 
184edc30077SPeter Griffin 	if (div <= 64) {
185edc30077SPeter Griffin 		clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
186edc30077SPeter Griffin 		ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
187edc30077SPeter Griffin 	} else {
188b1165170SGabriel FERNANDEZ 		clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
189edc30077SPeter Griffin 		ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
190edc30077SPeter Griffin 	}
191b1165170SGabriel FERNANDEZ 
192b1165170SGabriel FERNANDEZ 	return ret;
193b1165170SGabriel FERNANDEZ }
194b1165170SGabriel FERNANDEZ 
195b1165170SGabriel FERNANDEZ static const struct clk_ops flexgen_ops = {
196b1165170SGabriel FERNANDEZ 	.enable = flexgen_enable,
197b1165170SGabriel FERNANDEZ 	.disable = flexgen_disable,
198b1165170SGabriel FERNANDEZ 	.is_enabled = flexgen_is_enabled,
199b1165170SGabriel FERNANDEZ 	.get_parent = flexgen_get_parent,
200b1165170SGabriel FERNANDEZ 	.set_parent = flexgen_set_parent,
201*36f8a30cSMaxime Ripard 	.determine_rate = flexgen_determine_rate,
202b1165170SGabriel FERNANDEZ 	.recalc_rate = flexgen_recalc_rate,
203b1165170SGabriel FERNANDEZ 	.set_rate = flexgen_set_rate,
204b1165170SGabriel FERNANDEZ };
205b1165170SGabriel FERNANDEZ 
clk_register_flexgen(const char * name,const char ** parent_names,u8 num_parents,void __iomem * reg,spinlock_t * lock,u32 idx,unsigned long flexgen_flags,bool mode)2068e6dd77cSStephen Boyd static struct clk *clk_register_flexgen(const char *name,
207b1165170SGabriel FERNANDEZ 				const char **parent_names, u8 num_parents,
208b1165170SGabriel FERNANDEZ 				void __iomem *reg, spinlock_t *lock, u32 idx,
209cb80ec76SGabriel Fernandez 				unsigned long flexgen_flags, bool mode) {
210b1165170SGabriel FERNANDEZ 	struct flexgen *fgxbar;
211b1165170SGabriel FERNANDEZ 	struct clk *clk;
212b1165170SGabriel FERNANDEZ 	struct clk_init_data init;
213b1165170SGabriel FERNANDEZ 	u32  xbar_shift;
214b1165170SGabriel FERNANDEZ 	void __iomem *xbar_reg, *fdiv_reg;
215b1165170SGabriel FERNANDEZ 
216b1165170SGabriel FERNANDEZ 	fgxbar = kzalloc(sizeof(struct flexgen), GFP_KERNEL);
217b1165170SGabriel FERNANDEZ 	if (!fgxbar)
218b1165170SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
219b1165170SGabriel FERNANDEZ 
220b1165170SGabriel FERNANDEZ 	init.name = name;
221b1165170SGabriel FERNANDEZ 	init.ops = &flexgen_ops;
222c179c21eSStephen Boyd 	init.flags = CLK_GET_RATE_NOCACHE | flexgen_flags;
223b1165170SGabriel FERNANDEZ 	init.parent_names = parent_names;
224b1165170SGabriel FERNANDEZ 	init.num_parents = num_parents;
225b1165170SGabriel FERNANDEZ 
226b1165170SGabriel FERNANDEZ 	xbar_reg = reg + 0x18 + (idx & ~0x3);
227b1165170SGabriel FERNANDEZ 	xbar_shift = (idx % 4) * 0x8;
228b1165170SGabriel FERNANDEZ 	fdiv_reg = reg + 0x164 + idx * 4;
229b1165170SGabriel FERNANDEZ 
230b1165170SGabriel FERNANDEZ 	/* Crossbar element config */
231b1165170SGabriel FERNANDEZ 	fgxbar->mux.lock = lock;
232b1165170SGabriel FERNANDEZ 	fgxbar->mux.mask = BIT(6) - 1;
233b1165170SGabriel FERNANDEZ 	fgxbar->mux.reg = xbar_reg;
234b1165170SGabriel FERNANDEZ 	fgxbar->mux.shift = xbar_shift;
235b1165170SGabriel FERNANDEZ 	fgxbar->mux.table = NULL;
236b1165170SGabriel FERNANDEZ 
237b1165170SGabriel FERNANDEZ 
238b1165170SGabriel FERNANDEZ 	/* Pre-divider's gate config (in xbar register)*/
239b1165170SGabriel FERNANDEZ 	fgxbar->pgate.lock = lock;
240b1165170SGabriel FERNANDEZ 	fgxbar->pgate.reg = xbar_reg;
241b1165170SGabriel FERNANDEZ 	fgxbar->pgate.bit_idx = xbar_shift + 6;
242b1165170SGabriel FERNANDEZ 
243b1165170SGabriel FERNANDEZ 	/* Pre-divider config */
244b1165170SGabriel FERNANDEZ 	fgxbar->pdiv.lock = lock;
245b1165170SGabriel FERNANDEZ 	fgxbar->pdiv.reg = reg + 0x58 + idx * 4;
246b1165170SGabriel FERNANDEZ 	fgxbar->pdiv.width = 10;
247b1165170SGabriel FERNANDEZ 
248b1165170SGabriel FERNANDEZ 	/* Final divider's gate config */
249b1165170SGabriel FERNANDEZ 	fgxbar->fgate.lock = lock;
250b1165170SGabriel FERNANDEZ 	fgxbar->fgate.reg = fdiv_reg;
251b1165170SGabriel FERNANDEZ 	fgxbar->fgate.bit_idx = 6;
252b1165170SGabriel FERNANDEZ 
253b1165170SGabriel FERNANDEZ 	/* Final divider config */
254b1165170SGabriel FERNANDEZ 	fgxbar->fdiv.lock = lock;
255b1165170SGabriel FERNANDEZ 	fgxbar->fdiv.reg = fdiv_reg;
256b1165170SGabriel FERNANDEZ 	fgxbar->fdiv.width = 6;
257b1165170SGabriel FERNANDEZ 
258cb80ec76SGabriel Fernandez 	/* Final divider sync config */
259cb80ec76SGabriel Fernandez 	fgxbar->sync.lock = lock;
260cb80ec76SGabriel Fernandez 	fgxbar->sync.reg = fdiv_reg;
261cb80ec76SGabriel Fernandez 	fgxbar->sync.bit_idx = 7;
262cb80ec76SGabriel Fernandez 
263cb80ec76SGabriel Fernandez 	fgxbar->control_mode = mode;
264cb80ec76SGabriel Fernandez 
265b1165170SGabriel FERNANDEZ 	fgxbar->hw.init = &init;
266b1165170SGabriel FERNANDEZ 
267b1165170SGabriel FERNANDEZ 	clk = clk_register(NULL, &fgxbar->hw);
268b1165170SGabriel FERNANDEZ 	if (IS_ERR(clk))
269b1165170SGabriel FERNANDEZ 		kfree(fgxbar);
270b1165170SGabriel FERNANDEZ 	else
271b1165170SGabriel FERNANDEZ 		pr_debug("%s: parent %s rate %u\n",
272b1165170SGabriel FERNANDEZ 			__clk_get_name(clk),
273b1165170SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
274b1165170SGabriel FERNANDEZ 			(unsigned int)clk_get_rate(clk));
275b1165170SGabriel FERNANDEZ 	return clk;
276b1165170SGabriel FERNANDEZ }
277b1165170SGabriel FERNANDEZ 
flexgen_get_parents(struct device_node * np,int * num_parents)278b1165170SGabriel FERNANDEZ static const char ** __init flexgen_get_parents(struct device_node *np,
279b1165170SGabriel FERNANDEZ 						       int *num_parents)
280b1165170SGabriel FERNANDEZ {
281b1165170SGabriel FERNANDEZ 	const char **parents;
282caeb057cSStephen Boyd 	unsigned int nparents;
283b1165170SGabriel FERNANDEZ 
2840a65239cSGeert Uytterhoeven 	nparents = of_clk_get_parent_count(np);
285caeb057cSStephen Boyd 	if (WARN_ON(!nparents))
286b1165170SGabriel FERNANDEZ 		return NULL;
287b1165170SGabriel FERNANDEZ 
288b1165170SGabriel FERNANDEZ 	parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
289b1165170SGabriel FERNANDEZ 	if (!parents)
290b1165170SGabriel FERNANDEZ 		return NULL;
291b1165170SGabriel FERNANDEZ 
2920b4e7f08SDinh Nguyen 	*num_parents = of_clk_parent_fill(np, parents, nparents);
293b1165170SGabriel FERNANDEZ 
294b1165170SGabriel FERNANDEZ 	return parents;
295b1165170SGabriel FERNANDEZ }
296b1165170SGabriel FERNANDEZ 
29726bd0a57SGabriel Fernandez static const struct clkgen_data clkgen_audio = {
29826bd0a57SGabriel Fernandez 	.flags = CLK_SET_RATE_PARENT,
29926bd0a57SGabriel Fernandez };
30026bd0a57SGabriel Fernandez 
301cb80ec76SGabriel Fernandez static const struct clkgen_data clkgen_video = {
302cb80ec76SGabriel Fernandez 	.flags = CLK_SET_RATE_PARENT,
303cb80ec76SGabriel Fernandez 	.mode = 1,
304cb80ec76SGabriel Fernandez };
305cb80ec76SGabriel Fernandez 
306574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih407_a0_clk_out[] = {
307574dffc2SAlain Volmat 	/* This clk needs to be on so that memory interface is accessible */
308574dffc2SAlain Volmat 	{ .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
309574dffc2SAlain Volmat };
310574dffc2SAlain Volmat 
311574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih407_a0 = {
312574dffc2SAlain Volmat 	.outputs = clkgen_stih407_a0_clk_out,
313574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih407_a0_clk_out),
314574dffc2SAlain Volmat };
315574dffc2SAlain Volmat 
316574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih410_a0_clk_out[] = {
317574dffc2SAlain Volmat 	/* Those clks need to be on so that memory interface is accessible */
318574dffc2SAlain Volmat 	{ .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
319574dffc2SAlain Volmat 	{ .name = "clk-ic-lmi1", .flags = CLK_IS_CRITICAL },
320574dffc2SAlain Volmat };
321574dffc2SAlain Volmat 
322574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih410_a0 = {
323574dffc2SAlain Volmat 	.outputs = clkgen_stih410_a0_clk_out,
324574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih410_a0_clk_out),
325574dffc2SAlain Volmat };
326574dffc2SAlain Volmat 
327574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih407_c0_clk_out[] = {
328574dffc2SAlain Volmat 	{ .name = "clk-icn-gpu", },
329574dffc2SAlain Volmat 	{ .name = "clk-fdma", },
330574dffc2SAlain Volmat 	{ .name = "clk-nand", },
331574dffc2SAlain Volmat 	{ .name = "clk-hva", },
332574dffc2SAlain Volmat 	{ .name = "clk-proc-stfe", },
333574dffc2SAlain Volmat 	{ .name = "clk-proc-tp", },
334574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-dmu", },
335574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-hva", },
336574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
337574dffc2SAlain Volmat 	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
338574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
339574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
340574dffc2SAlain Volmat 	{ .name = "clk-mmc-0", },
341574dffc2SAlain Volmat 	{ .name = "clk-mmc-1", },
342574dffc2SAlain Volmat 	{ .name = "clk-jpegdec", },
343574dffc2SAlain Volmat 	/* This clk needs to be on to keep A9 running */
344574dffc2SAlain Volmat 	{ .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
345574dffc2SAlain Volmat 	{ .name = "clk-ic-bdisp-0", },
346574dffc2SAlain Volmat 	{ .name = "clk-ic-bdisp-1", },
347574dffc2SAlain Volmat 	{ .name = "clk-pp-dmu", },
348574dffc2SAlain Volmat 	{ .name = "clk-vid-dmu", },
349574dffc2SAlain Volmat 	{ .name = "clk-dss-lpc", },
350574dffc2SAlain Volmat 	{ .name = "clk-st231-aud-0", },
351574dffc2SAlain Volmat 	{ .name = "clk-st231-gp-1", },
352574dffc2SAlain Volmat 	{ .name = "clk-st231-dmu", },
353574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
354574dffc2SAlain Volmat 	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
355574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-disp-1", },
356574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
357574dffc2SAlain Volmat 	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
358574dffc2SAlain Volmat 	{ .name = "clk-stfe-frc2", },
359574dffc2SAlain Volmat 	{ .name = "clk-eth-phy", },
360574dffc2SAlain Volmat 	{ .name = "clk-eth-ref-phyclk", },
361574dffc2SAlain Volmat 	{ .name = "clk-flash-promip", },
362574dffc2SAlain Volmat 	{ .name = "clk-main-disp", },
363574dffc2SAlain Volmat 	{ .name = "clk-aux-disp", },
364574dffc2SAlain Volmat 	{ .name = "clk-compo-dvp", },
365574dffc2SAlain Volmat };
366574dffc2SAlain Volmat 
367574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih407_c0 = {
368574dffc2SAlain Volmat 	.outputs = clkgen_stih407_c0_clk_out,
369574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih407_c0_clk_out),
370574dffc2SAlain Volmat };
371574dffc2SAlain Volmat 
372574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih410_c0_clk_out[] = {
373574dffc2SAlain Volmat 	{ .name = "clk-icn-gpu", },
374574dffc2SAlain Volmat 	{ .name = "clk-fdma", },
375574dffc2SAlain Volmat 	{ .name = "clk-nand", },
376574dffc2SAlain Volmat 	{ .name = "clk-hva", },
377574dffc2SAlain Volmat 	{ .name = "clk-proc-stfe", },
378574dffc2SAlain Volmat 	{ .name = "clk-proc-tp", },
379574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-dmu", },
380574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-hva", },
381574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
382574dffc2SAlain Volmat 	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
383574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
384574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
385574dffc2SAlain Volmat 	{ .name = "clk-mmc-0", },
386574dffc2SAlain Volmat 	{ .name = "clk-mmc-1", },
387574dffc2SAlain Volmat 	{ .name = "clk-jpegdec", },
388574dffc2SAlain Volmat 	/* This clk needs to be on to keep A9 running */
389574dffc2SAlain Volmat 	{ .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
390574dffc2SAlain Volmat 	{ .name = "clk-ic-bdisp-0", },
391574dffc2SAlain Volmat 	{ .name = "clk-ic-bdisp-1", },
392574dffc2SAlain Volmat 	{ .name = "clk-pp-dmu", },
393574dffc2SAlain Volmat 	{ .name = "clk-vid-dmu", },
394574dffc2SAlain Volmat 	{ .name = "clk-dss-lpc", },
395574dffc2SAlain Volmat 	{ .name = "clk-st231-aud-0", },
396574dffc2SAlain Volmat 	{ .name = "clk-st231-gp-1", },
397574dffc2SAlain Volmat 	{ .name = "clk-st231-dmu", },
398574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
399574dffc2SAlain Volmat 	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
400574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-disp-1", },
401574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
402574dffc2SAlain Volmat 	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
403574dffc2SAlain Volmat 	{ .name = "clk-stfe-frc2", },
404574dffc2SAlain Volmat 	{ .name = "clk-eth-phy", },
405574dffc2SAlain Volmat 	{ .name = "clk-eth-ref-phyclk", },
406574dffc2SAlain Volmat 	{ .name = "clk-flash-promip", },
407574dffc2SAlain Volmat 	{ .name = "clk-main-disp", },
408574dffc2SAlain Volmat 	{ .name = "clk-aux-disp", },
409574dffc2SAlain Volmat 	{ .name = "clk-compo-dvp", },
410574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-hades", },
411574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-hades", },
412574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
413574dffc2SAlain Volmat 	{ .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
414574dffc2SAlain Volmat 	{ .name = "clk-pp-hades", },
415574dffc2SAlain Volmat 	{ .name = "clk-clust-hades", },
416574dffc2SAlain Volmat 	{ .name = "clk-hwpe-hades", },
417574dffc2SAlain Volmat 	{ .name = "clk-fc-hades", },
418574dffc2SAlain Volmat };
419574dffc2SAlain Volmat 
420574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih410_c0 = {
421574dffc2SAlain Volmat 	.outputs = clkgen_stih410_c0_clk_out,
422574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih410_c0_clk_out),
423574dffc2SAlain Volmat };
424574dffc2SAlain Volmat 
425574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih418_c0_clk_out[] = {
426574dffc2SAlain Volmat 	{ .name = "clk-icn-gpu", },
427574dffc2SAlain Volmat 	{ .name = "clk-fdma", },
428574dffc2SAlain Volmat 	{ .name = "clk-nand", },
429574dffc2SAlain Volmat 	{ .name = "clk-hva", },
430574dffc2SAlain Volmat 	{ .name = "clk-proc-stfe", },
431574dffc2SAlain Volmat 	{ .name = "clk-tp", },
432574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
433574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-dmu", .flags = CLK_IS_CRITICAL },
434574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
435574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-hva", .flags = CLK_IS_CRITICAL },
436574dffc2SAlain Volmat 	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
437574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
438574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
439574dffc2SAlain Volmat 	{ .name = "clk-mmc-0", },
440574dffc2SAlain Volmat 	{ .name = "clk-mmc-1", },
441574dffc2SAlain Volmat 	{ .name = "clk-jpegdec", },
442574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
443574dffc2SAlain Volmat 	{ .name = "clk-icn-reg", .flags = CLK_IS_CRITICAL },
444574dffc2SAlain Volmat 	{ .name = "clk-proc-bdisp-0", },
445574dffc2SAlain Volmat 	{ .name = "clk-proc-bdisp-1", },
446574dffc2SAlain Volmat 	{ .name = "clk-pp-dmu", },
447574dffc2SAlain Volmat 	{ .name = "clk-vid-dmu", },
448574dffc2SAlain Volmat 	{ .name = "clk-dss-lpc", },
449574dffc2SAlain Volmat 	{ .name = "clk-st231-aud-0", },
450574dffc2SAlain Volmat 	{ .name = "clk-st231-gp-1", },
451574dffc2SAlain Volmat 	{ .name = "clk-st231-dmu", },
452574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
453574dffc2SAlain Volmat 	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
454574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
455574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-1", .flags = CLK_IS_CRITICAL },
456574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
457574dffc2SAlain Volmat 	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
458574dffc2SAlain Volmat 	{ .name = "clk-stfe-frc2", },
459574dffc2SAlain Volmat 	{ .name = "clk-eth-phyref", },
460574dffc2SAlain Volmat 	{ .name = "clk-eth-ref-phyclk", },
461574dffc2SAlain Volmat 	{ .name = "clk-flash-promip", },
462574dffc2SAlain Volmat 	{ .name = "clk-main-disp", },
463574dffc2SAlain Volmat 	{ .name = "clk-aux-disp", },
464574dffc2SAlain Volmat 	{ .name = "clk-compo-dvp", },
465574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
466574dffc2SAlain Volmat 	{ .name = "clk-tx-icn-hades", .flags = CLK_IS_CRITICAL },
467574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
468574dffc2SAlain Volmat 	{ .name = "clk-rx-icn-hades", .flags = CLK_IS_CRITICAL },
469574dffc2SAlain Volmat 	/* This clk needs to be on to keep bus interconnect alive */
470574dffc2SAlain Volmat 	{ .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
471574dffc2SAlain Volmat 	{ .name = "clk-pp-hevc", },
472574dffc2SAlain Volmat 	{ .name = "clk-clust-hevc", },
473574dffc2SAlain Volmat 	{ .name = "clk-hwpe-hevc", },
474574dffc2SAlain Volmat 	{ .name = "clk-fc-hevc", },
475574dffc2SAlain Volmat 	{ .name = "clk-proc-mixer", },
476574dffc2SAlain Volmat 	{ .name = "clk-proc-sc", },
477574dffc2SAlain Volmat 	{ .name = "clk-avsp-hevc", },
478574dffc2SAlain Volmat };
479574dffc2SAlain Volmat 
480574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih418_c0 = {
481574dffc2SAlain Volmat 	.outputs = clkgen_stih418_c0_clk_out,
482574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih418_c0_clk_out),
483574dffc2SAlain Volmat };
484574dffc2SAlain Volmat 
485574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih407_d0_clk_out[] = {
486574dffc2SAlain Volmat 	{ .name = "clk-pcm-0", },
487574dffc2SAlain Volmat 	{ .name = "clk-pcm-1", },
488574dffc2SAlain Volmat 	{ .name = "clk-pcm-2", },
489574dffc2SAlain Volmat 	{ .name = "clk-spdiff", },
490574dffc2SAlain Volmat };
491574dffc2SAlain Volmat 
492574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih407_d0 = {
493574dffc2SAlain Volmat 	.flags = CLK_SET_RATE_PARENT,
494574dffc2SAlain Volmat 	.outputs = clkgen_stih407_d0_clk_out,
495574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d0_clk_out),
496574dffc2SAlain Volmat };
497574dffc2SAlain Volmat 
498574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih410_d0_clk_out[] = {
499574dffc2SAlain Volmat 	{ .name = "clk-pcm-0", },
500574dffc2SAlain Volmat 	{ .name = "clk-pcm-1", },
501574dffc2SAlain Volmat 	{ .name = "clk-pcm-2", },
502574dffc2SAlain Volmat 	{ .name = "clk-spdiff", },
503574dffc2SAlain Volmat 	{ .name = "clk-pcmr10-master", },
504574dffc2SAlain Volmat 	{ .name = "clk-usb2-phy", },
505574dffc2SAlain Volmat };
506574dffc2SAlain Volmat 
507574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih410_d0 = {
508574dffc2SAlain Volmat 	.flags = CLK_SET_RATE_PARENT,
509574dffc2SAlain Volmat 	.outputs = clkgen_stih410_d0_clk_out,
510574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih410_d0_clk_out),
511574dffc2SAlain Volmat };
512574dffc2SAlain Volmat 
513574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih407_d2_clk_out[] = {
514574dffc2SAlain Volmat 	{ .name = "clk-pix-main-disp", },
515574dffc2SAlain Volmat 	{ .name = "clk-pix-pip", },
516574dffc2SAlain Volmat 	{ .name = "clk-pix-gdp1", },
517574dffc2SAlain Volmat 	{ .name = "clk-pix-gdp2", },
518574dffc2SAlain Volmat 	{ .name = "clk-pix-gdp3", },
519574dffc2SAlain Volmat 	{ .name = "clk-pix-gdp4", },
520574dffc2SAlain Volmat 	{ .name = "clk-pix-aux-disp", },
521574dffc2SAlain Volmat 	{ .name = "clk-denc", },
522574dffc2SAlain Volmat 	{ .name = "clk-pix-hddac", },
523574dffc2SAlain Volmat 	{ .name = "clk-hddac", },
524574dffc2SAlain Volmat 	{ .name = "clk-sddac", },
525574dffc2SAlain Volmat 	{ .name = "clk-pix-dvo", },
526574dffc2SAlain Volmat 	{ .name = "clk-dvo", },
527574dffc2SAlain Volmat 	{ .name = "clk-pix-hdmi", },
528574dffc2SAlain Volmat 	{ .name = "clk-tmds-hdmi", },
529574dffc2SAlain Volmat 	{ .name = "clk-ref-hdmiphy", },
530574dffc2SAlain Volmat };
531574dffc2SAlain Volmat 
532574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih407_d2 = {
533574dffc2SAlain Volmat 	.outputs = clkgen_stih407_d2_clk_out,
534574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d2_clk_out),
535574dffc2SAlain Volmat 	.flags = CLK_SET_RATE_PARENT,
536574dffc2SAlain Volmat 	.mode = 1,
537574dffc2SAlain Volmat };
538574dffc2SAlain Volmat 
539574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih418_d2_clk_out[] = {
540574dffc2SAlain Volmat 	{ .name = "clk-pix-main-disp", },
541574dffc2SAlain Volmat 	{ .name = "", },
542574dffc2SAlain Volmat 	{ .name = "", },
543574dffc2SAlain Volmat 	{ .name = "", },
544574dffc2SAlain Volmat 	{ .name = "", },
545574dffc2SAlain Volmat 	{ .name = "clk-tmds-hdmi-div2", },
546574dffc2SAlain Volmat 	{ .name = "clk-pix-aux-disp", },
547574dffc2SAlain Volmat 	{ .name = "clk-denc", },
548574dffc2SAlain Volmat 	{ .name = "clk-pix-hddac", },
549574dffc2SAlain Volmat 	{ .name = "clk-hddac", },
550574dffc2SAlain Volmat 	{ .name = "clk-sddac", },
551574dffc2SAlain Volmat 	{ .name = "clk-pix-dvo", },
552574dffc2SAlain Volmat 	{ .name = "clk-dvo", },
553574dffc2SAlain Volmat 	{ .name = "clk-pix-hdmi", },
554574dffc2SAlain Volmat 	{ .name = "clk-tmds-hdmi", },
555574dffc2SAlain Volmat 	{ .name = "clk-ref-hdmiphy", },
556574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
557574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
558574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
559574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
560574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
561574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
562574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
563574dffc2SAlain Volmat 	{ .name = "", }, { .name = "", }, { .name = "", },
564574dffc2SAlain Volmat 	{ .name = "clk-vp9", },
565574dffc2SAlain Volmat };
566574dffc2SAlain Volmat 
567574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih418_d2 = {
568574dffc2SAlain Volmat 	.outputs = clkgen_stih418_d2_clk_out,
569574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih418_d2_clk_out),
570574dffc2SAlain Volmat 	.flags = CLK_SET_RATE_PARENT,
571574dffc2SAlain Volmat 	.mode = 1,
572574dffc2SAlain Volmat };
573574dffc2SAlain Volmat 
574574dffc2SAlain Volmat static const struct clkgen_clk_out clkgen_stih407_d3_clk_out[] = {
575574dffc2SAlain Volmat 	{ .name = "clk-stfe-frc1", },
576574dffc2SAlain Volmat 	{ .name = "clk-tsout-0", },
577574dffc2SAlain Volmat 	{ .name = "clk-tsout-1", },
578574dffc2SAlain Volmat 	{ .name = "clk-mchi", },
579574dffc2SAlain Volmat 	{ .name = "clk-vsens-compo", },
580574dffc2SAlain Volmat 	{ .name = "clk-frc1-remote", },
581574dffc2SAlain Volmat 	{ .name = "clk-lpc-0", },
582574dffc2SAlain Volmat 	{ .name = "clk-lpc-1", },
583574dffc2SAlain Volmat };
584574dffc2SAlain Volmat 
585574dffc2SAlain Volmat static const struct clkgen_data clkgen_stih407_d3 = {
586574dffc2SAlain Volmat 	.outputs = clkgen_stih407_d3_clk_out,
587574dffc2SAlain Volmat 	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d3_clk_out),
588574dffc2SAlain Volmat };
589574dffc2SAlain Volmat 
59026bd0a57SGabriel Fernandez static const struct of_device_id flexgen_of_match[] = {
59126bd0a57SGabriel Fernandez 	{
59226bd0a57SGabriel Fernandez 		.compatible = "st,flexgen-audio",
59326bd0a57SGabriel Fernandez 		.data = &clkgen_audio,
59426bd0a57SGabriel Fernandez 	},
595cb80ec76SGabriel Fernandez 	{
596cb80ec76SGabriel Fernandez 		.compatible = "st,flexgen-video",
597cb80ec76SGabriel Fernandez 		.data = &clkgen_video,
598cb80ec76SGabriel Fernandez 	},
599574dffc2SAlain Volmat 	{
600574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih407-a0",
601574dffc2SAlain Volmat 		.data = &clkgen_stih407_a0,
602574dffc2SAlain Volmat 	},
603574dffc2SAlain Volmat 	{
604574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih410-a0",
605574dffc2SAlain Volmat 		.data = &clkgen_stih410_a0,
606574dffc2SAlain Volmat 	},
607574dffc2SAlain Volmat 	{
608574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih407-c0",
609574dffc2SAlain Volmat 		.data = &clkgen_stih407_c0,
610574dffc2SAlain Volmat 	},
611574dffc2SAlain Volmat 	{
612574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih410-c0",
613574dffc2SAlain Volmat 		.data = &clkgen_stih410_c0,
614574dffc2SAlain Volmat 	},
615574dffc2SAlain Volmat 	{
616574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih418-c0",
617574dffc2SAlain Volmat 		.data = &clkgen_stih418_c0,
618574dffc2SAlain Volmat 	},
619574dffc2SAlain Volmat 	{
620574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih407-d0",
621574dffc2SAlain Volmat 		.data = &clkgen_stih407_d0,
622574dffc2SAlain Volmat 	},
623574dffc2SAlain Volmat 	{
624574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih410-d0",
625574dffc2SAlain Volmat 		.data = &clkgen_stih410_d0,
626574dffc2SAlain Volmat 	},
627574dffc2SAlain Volmat 	{
628574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih407-d2",
629574dffc2SAlain Volmat 		.data = &clkgen_stih407_d2,
630574dffc2SAlain Volmat 	},
631574dffc2SAlain Volmat 	{
632574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih418-d2",
633574dffc2SAlain Volmat 		.data = &clkgen_stih418_d2,
634574dffc2SAlain Volmat 	},
635574dffc2SAlain Volmat 	{
636574dffc2SAlain Volmat 		.compatible = "st,flexgen-stih407-d3",
637574dffc2SAlain Volmat 		.data = &clkgen_stih407_d3,
638574dffc2SAlain Volmat 	},
63926bd0a57SGabriel Fernandez 	{}
64026bd0a57SGabriel Fernandez };
64126bd0a57SGabriel Fernandez 
st_of_flexgen_setup(struct device_node * np)6428e6dd77cSStephen Boyd static void __init st_of_flexgen_setup(struct device_node *np)
643b1165170SGabriel FERNANDEZ {
644b1165170SGabriel FERNANDEZ 	struct device_node *pnode;
645b1165170SGabriel FERNANDEZ 	void __iomem *reg;
646b1165170SGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
647b1165170SGabriel FERNANDEZ 	const char **parents;
648b1165170SGabriel FERNANDEZ 	int num_parents, i;
649b1165170SGabriel FERNANDEZ 	spinlock_t *rlock = NULL;
65026bd0a57SGabriel Fernandez 	const struct of_device_id *match;
65126bd0a57SGabriel Fernandez 	struct clkgen_data *data = NULL;
65226bd0a57SGabriel Fernandez 	unsigned long flex_flags = 0;
653a1c22a4bSAndrzej Hajda 	int ret;
654cb80ec76SGabriel Fernandez 	bool clk_mode = 0;
655574dffc2SAlain Volmat 	const char *clk_name;
656b1165170SGabriel FERNANDEZ 
657b1165170SGabriel FERNANDEZ 	pnode = of_get_parent(np);
658b1165170SGabriel FERNANDEZ 	if (!pnode)
659b1165170SGabriel FERNANDEZ 		return;
660b1165170SGabriel FERNANDEZ 
661b1165170SGabriel FERNANDEZ 	reg = of_iomap(pnode, 0);
662d432d045SNishka Dasgupta 	of_node_put(pnode);
663b1165170SGabriel FERNANDEZ 	if (!reg)
664b1165170SGabriel FERNANDEZ 		return;
665b1165170SGabriel FERNANDEZ 
666b1165170SGabriel FERNANDEZ 	parents = flexgen_get_parents(np, &num_parents);
66716cd7764SArvind Yadav 	if (!parents) {
66816cd7764SArvind Yadav 		iounmap(reg);
669b1165170SGabriel FERNANDEZ 		return;
67016cd7764SArvind Yadav 	}
671b1165170SGabriel FERNANDEZ 
67226bd0a57SGabriel Fernandez 	match = of_match_node(flexgen_of_match, np);
67326bd0a57SGabriel Fernandez 	if (match) {
67426bd0a57SGabriel Fernandez 		data = (struct clkgen_data *)match->data;
67526bd0a57SGabriel Fernandez 		flex_flags = data->flags;
676cb80ec76SGabriel Fernandez 		clk_mode = data->mode;
67726bd0a57SGabriel Fernandez 	}
67826bd0a57SGabriel Fernandez 
679b1165170SGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
680b1165170SGabriel FERNANDEZ 	if (!clk_data)
681b1165170SGabriel FERNANDEZ 		goto err;
682b1165170SGabriel FERNANDEZ 
683574dffc2SAlain Volmat 	/* First try to get output information from the compatible data */
684574dffc2SAlain Volmat 	if (!data || !data->outputs_nb || !data->outputs) {
685a1c22a4bSAndrzej Hajda 		ret = of_property_count_strings(np, "clock-output-names");
686a1c22a4bSAndrzej Hajda 		if (ret <= 0) {
687b1165170SGabriel FERNANDEZ 			pr_err("%s: Failed to get number of output clocks (%d)",
688b1165170SGabriel FERNANDEZ 					__func__, clk_data->clk_num);
689b1165170SGabriel FERNANDEZ 			goto err;
690b1165170SGabriel FERNANDEZ 		}
691a1c22a4bSAndrzej Hajda 		clk_data->clk_num = ret;
692574dffc2SAlain Volmat 	} else
693574dffc2SAlain Volmat 		clk_data->clk_num = data->outputs_nb;
694b1165170SGabriel FERNANDEZ 
695b1165170SGabriel FERNANDEZ 	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
696b1165170SGabriel FERNANDEZ 			GFP_KERNEL);
697b1165170SGabriel FERNANDEZ 	if (!clk_data->clks)
698b1165170SGabriel FERNANDEZ 		goto err;
699b1165170SGabriel FERNANDEZ 
700b1165170SGabriel FERNANDEZ 	rlock = kzalloc(sizeof(spinlock_t), GFP_KERNEL);
701b1165170SGabriel FERNANDEZ 	if (!rlock)
702b1165170SGabriel FERNANDEZ 		goto err;
703b1165170SGabriel FERNANDEZ 
7040f4f2afdSGiuseppe Cavallaro 	spin_lock_init(rlock);
7050f4f2afdSGiuseppe Cavallaro 
706b1165170SGabriel FERNANDEZ 	for (i = 0; i < clk_data->clk_num; i++) {
707b1165170SGabriel FERNANDEZ 		struct clk *clk;
708b1165170SGabriel FERNANDEZ 
709574dffc2SAlain Volmat 		if (!data || !data->outputs_nb || !data->outputs) {
710574dffc2SAlain Volmat 			if (of_property_read_string_index(np,
711574dffc2SAlain Volmat 							  "clock-output-names",
712574dffc2SAlain Volmat 							  i, &clk_name))
713b1165170SGabriel FERNANDEZ 				break;
714a403bbabSAlain Volmat 			flex_flags &= ~CLK_IS_CRITICAL;
715fa6415afSLee Jones 			of_clk_detect_critical(np, i, &flex_flags);
716574dffc2SAlain Volmat 		} else {
717574dffc2SAlain Volmat 			clk_name = data->outputs[i].name;
718574dffc2SAlain Volmat 			flex_flags = data->flags | data->outputs[i].flags;
719574dffc2SAlain Volmat 		}
720fa6415afSLee Jones 
721b1165170SGabriel FERNANDEZ 		/*
722b1165170SGabriel FERNANDEZ 		 * If we read an empty clock name then the output is unused
723b1165170SGabriel FERNANDEZ 		 */
724b1165170SGabriel FERNANDEZ 		if (*clk_name == '\0')
725b1165170SGabriel FERNANDEZ 			continue;
726b1165170SGabriel FERNANDEZ 
727b1165170SGabriel FERNANDEZ 		clk = clk_register_flexgen(clk_name, parents, num_parents,
728cb80ec76SGabriel Fernandez 					   reg, rlock, i, flex_flags, clk_mode);
729b1165170SGabriel FERNANDEZ 
730b1165170SGabriel FERNANDEZ 		if (IS_ERR(clk))
731b1165170SGabriel FERNANDEZ 			goto err;
732b1165170SGabriel FERNANDEZ 
733b1165170SGabriel FERNANDEZ 		clk_data->clks[i] = clk;
734b1165170SGabriel FERNANDEZ 	}
735b1165170SGabriel FERNANDEZ 
736b1165170SGabriel FERNANDEZ 	kfree(parents);
737b1165170SGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
738b1165170SGabriel FERNANDEZ 
739b1165170SGabriel FERNANDEZ 	return;
740b1165170SGabriel FERNANDEZ 
741b1165170SGabriel FERNANDEZ err:
74216cd7764SArvind Yadav 	iounmap(reg);
743b1165170SGabriel FERNANDEZ 	if (clk_data)
744b1165170SGabriel FERNANDEZ 		kfree(clk_data->clks);
745b1165170SGabriel FERNANDEZ 	kfree(clk_data);
746b1165170SGabriel FERNANDEZ 	kfree(parents);
747b1165170SGabriel FERNANDEZ 	kfree(rlock);
748b1165170SGabriel FERNANDEZ }
749b1165170SGabriel FERNANDEZ CLK_OF_DECLARE(flexgen, "st,flexgen", st_of_flexgen_setup);
750