162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * clk-flexgen.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) ST-Microelectronics SA 2013
662306a36Sopenharmony_ci * Author:  Maxime Coquelin <maxime.coquelin@st.com> for ST-Microelectronics.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/err.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/of_address.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct clkgen_clk_out {
2062306a36Sopenharmony_ci	const char *name;
2162306a36Sopenharmony_ci	unsigned long flags;
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct clkgen_data {
2562306a36Sopenharmony_ci	unsigned long flags;
2662306a36Sopenharmony_ci	bool mode;
2762306a36Sopenharmony_ci	const struct clkgen_clk_out *outputs;
2862306a36Sopenharmony_ci	const unsigned int outputs_nb;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct flexgen {
3262306a36Sopenharmony_ci	struct clk_hw hw;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* Crossbar */
3562306a36Sopenharmony_ci	struct clk_mux mux;
3662306a36Sopenharmony_ci	/* Pre-divisor's gate */
3762306a36Sopenharmony_ci	struct clk_gate pgate;
3862306a36Sopenharmony_ci	/* Pre-divisor */
3962306a36Sopenharmony_ci	struct clk_divider pdiv;
4062306a36Sopenharmony_ci	/* Final divisor's gate */
4162306a36Sopenharmony_ci	struct clk_gate fgate;
4262306a36Sopenharmony_ci	/* Final divisor */
4362306a36Sopenharmony_ci	struct clk_divider fdiv;
4462306a36Sopenharmony_ci	/* Asynchronous mode control */
4562306a36Sopenharmony_ci	struct clk_gate sync;
4662306a36Sopenharmony_ci	/* hw control flags */
4762306a36Sopenharmony_ci	bool control_mode;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define to_flexgen(_hw) container_of(_hw, struct flexgen, hw)
5162306a36Sopenharmony_ci#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int flexgen_enable(struct clk_hw *hw)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
5662306a36Sopenharmony_ci	struct clk_hw *pgate_hw = &flexgen->pgate.hw;
5762306a36Sopenharmony_ci	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	__clk_hw_set_clk(pgate_hw, hw);
6062306a36Sopenharmony_ci	__clk_hw_set_clk(fgate_hw, hw);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	clk_gate_ops.enable(pgate_hw);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	clk_gate_ops.enable(fgate_hw);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	pr_debug("%s: flexgen output enabled\n", clk_hw_get_name(hw));
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void flexgen_disable(struct clk_hw *hw)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
7362306a36Sopenharmony_ci	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* disable only the final gate */
7662306a36Sopenharmony_ci	__clk_hw_set_clk(fgate_hw, hw);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	clk_gate_ops.disable(fgate_hw);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	pr_debug("%s: flexgen output disabled\n", clk_hw_get_name(hw));
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int flexgen_is_enabled(struct clk_hw *hw)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
8662306a36Sopenharmony_ci	struct clk_hw *fgate_hw = &flexgen->fgate.hw;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	__clk_hw_set_clk(fgate_hw, hw);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (!clk_gate_ops.is_enabled(fgate_hw))
9162306a36Sopenharmony_ci		return 0;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return 1;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic u8 flexgen_get_parent(struct clk_hw *hw)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
9962306a36Sopenharmony_ci	struct clk_hw *mux_hw = &flexgen->mux.hw;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	__clk_hw_set_clk(mux_hw, hw);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return clk_mux_ops.get_parent(mux_hw);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int flexgen_set_parent(struct clk_hw *hw, u8 index)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
10962306a36Sopenharmony_ci	struct clk_hw *mux_hw = &flexgen->mux.hw;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	__clk_hw_set_clk(mux_hw, hw);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return clk_mux_ops.set_parent(mux_hw, index);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic inline unsigned long
11762306a36Sopenharmony_ciclk_best_div(unsigned long parent_rate, unsigned long rate)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return parent_rate / rate + ((rate > (2*(parent_rate % rate))) ? 0 : 1);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int flexgen_determine_rate(struct clk_hw *hw,
12362306a36Sopenharmony_ci				  struct clk_rate_request *req)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	unsigned long div;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Round div according to exact prate and wished rate */
12862306a36Sopenharmony_ci	div = clk_best_div(req->best_parent_rate, req->rate);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
13162306a36Sopenharmony_ci		req->best_parent_rate = req->rate * div;
13262306a36Sopenharmony_ci		return 0;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	req->rate = req->best_parent_rate / div;
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic unsigned long flexgen_recalc_rate(struct clk_hw *hw,
14062306a36Sopenharmony_ci		unsigned long parent_rate)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
14362306a36Sopenharmony_ci	struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
14462306a36Sopenharmony_ci	struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
14562306a36Sopenharmony_ci	unsigned long mid_rate;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	__clk_hw_set_clk(pdiv_hw, hw);
14862306a36Sopenharmony_ci	__clk_hw_set_clk(fdiv_hw, hw);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return clk_divider_ops.recalc_rate(fdiv_hw, mid_rate);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
15662306a36Sopenharmony_ci				unsigned long parent_rate)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct flexgen *flexgen = to_flexgen(hw);
15962306a36Sopenharmony_ci	struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
16062306a36Sopenharmony_ci	struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
16162306a36Sopenharmony_ci	struct clk_hw *sync_hw = &flexgen->sync.hw;
16262306a36Sopenharmony_ci	struct clk_gate *config = to_clk_gate(sync_hw);
16362306a36Sopenharmony_ci	unsigned long div = 0;
16462306a36Sopenharmony_ci	int ret = 0;
16562306a36Sopenharmony_ci	u32 reg;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	__clk_hw_set_clk(pdiv_hw, hw);
16862306a36Sopenharmony_ci	__clk_hw_set_clk(fdiv_hw, hw);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (flexgen->control_mode) {
17162306a36Sopenharmony_ci		reg = readl(config->reg);
17262306a36Sopenharmony_ci		reg &= ~BIT(config->bit_idx);
17362306a36Sopenharmony_ci		writel(reg, config->reg);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	div = clk_best_div(parent_rate, rate);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/*
17962306a36Sopenharmony_ci	* pdiv is mainly targeted for low freq results, while fdiv
18062306a36Sopenharmony_ci	* should be used for div <= 64. The other way round can
18162306a36Sopenharmony_ci	* lead to 'duty cycle' issues.
18262306a36Sopenharmony_ci	*/
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (div <= 64) {
18562306a36Sopenharmony_ci		clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
18662306a36Sopenharmony_ci		ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
18762306a36Sopenharmony_ci	} else {
18862306a36Sopenharmony_ci		clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
18962306a36Sopenharmony_ci		ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return ret;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const struct clk_ops flexgen_ops = {
19662306a36Sopenharmony_ci	.enable = flexgen_enable,
19762306a36Sopenharmony_ci	.disable = flexgen_disable,
19862306a36Sopenharmony_ci	.is_enabled = flexgen_is_enabled,
19962306a36Sopenharmony_ci	.get_parent = flexgen_get_parent,
20062306a36Sopenharmony_ci	.set_parent = flexgen_set_parent,
20162306a36Sopenharmony_ci	.determine_rate = flexgen_determine_rate,
20262306a36Sopenharmony_ci	.recalc_rate = flexgen_recalc_rate,
20362306a36Sopenharmony_ci	.set_rate = flexgen_set_rate,
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic struct clk *clk_register_flexgen(const char *name,
20762306a36Sopenharmony_ci				const char **parent_names, u8 num_parents,
20862306a36Sopenharmony_ci				void __iomem *reg, spinlock_t *lock, u32 idx,
20962306a36Sopenharmony_ci				unsigned long flexgen_flags, bool mode) {
21062306a36Sopenharmony_ci	struct flexgen *fgxbar;
21162306a36Sopenharmony_ci	struct clk *clk;
21262306a36Sopenharmony_ci	struct clk_init_data init;
21362306a36Sopenharmony_ci	u32  xbar_shift;
21462306a36Sopenharmony_ci	void __iomem *xbar_reg, *fdiv_reg;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	fgxbar = kzalloc(sizeof(struct flexgen), GFP_KERNEL);
21762306a36Sopenharmony_ci	if (!fgxbar)
21862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	init.name = name;
22162306a36Sopenharmony_ci	init.ops = &flexgen_ops;
22262306a36Sopenharmony_ci	init.flags = CLK_GET_RATE_NOCACHE | flexgen_flags;
22362306a36Sopenharmony_ci	init.parent_names = parent_names;
22462306a36Sopenharmony_ci	init.num_parents = num_parents;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	xbar_reg = reg + 0x18 + (idx & ~0x3);
22762306a36Sopenharmony_ci	xbar_shift = (idx % 4) * 0x8;
22862306a36Sopenharmony_ci	fdiv_reg = reg + 0x164 + idx * 4;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* Crossbar element config */
23162306a36Sopenharmony_ci	fgxbar->mux.lock = lock;
23262306a36Sopenharmony_ci	fgxbar->mux.mask = BIT(6) - 1;
23362306a36Sopenharmony_ci	fgxbar->mux.reg = xbar_reg;
23462306a36Sopenharmony_ci	fgxbar->mux.shift = xbar_shift;
23562306a36Sopenharmony_ci	fgxbar->mux.table = NULL;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* Pre-divider's gate config (in xbar register)*/
23962306a36Sopenharmony_ci	fgxbar->pgate.lock = lock;
24062306a36Sopenharmony_ci	fgxbar->pgate.reg = xbar_reg;
24162306a36Sopenharmony_ci	fgxbar->pgate.bit_idx = xbar_shift + 6;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* Pre-divider config */
24462306a36Sopenharmony_ci	fgxbar->pdiv.lock = lock;
24562306a36Sopenharmony_ci	fgxbar->pdiv.reg = reg + 0x58 + idx * 4;
24662306a36Sopenharmony_ci	fgxbar->pdiv.width = 10;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Final divider's gate config */
24962306a36Sopenharmony_ci	fgxbar->fgate.lock = lock;
25062306a36Sopenharmony_ci	fgxbar->fgate.reg = fdiv_reg;
25162306a36Sopenharmony_ci	fgxbar->fgate.bit_idx = 6;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Final divider config */
25462306a36Sopenharmony_ci	fgxbar->fdiv.lock = lock;
25562306a36Sopenharmony_ci	fgxbar->fdiv.reg = fdiv_reg;
25662306a36Sopenharmony_ci	fgxbar->fdiv.width = 6;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* Final divider sync config */
25962306a36Sopenharmony_ci	fgxbar->sync.lock = lock;
26062306a36Sopenharmony_ci	fgxbar->sync.reg = fdiv_reg;
26162306a36Sopenharmony_ci	fgxbar->sync.bit_idx = 7;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	fgxbar->control_mode = mode;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	fgxbar->hw.init = &init;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	clk = clk_register(NULL, &fgxbar->hw);
26862306a36Sopenharmony_ci	if (IS_ERR(clk))
26962306a36Sopenharmony_ci		kfree(fgxbar);
27062306a36Sopenharmony_ci	else
27162306a36Sopenharmony_ci		pr_debug("%s: parent %s rate %u\n",
27262306a36Sopenharmony_ci			__clk_get_name(clk),
27362306a36Sopenharmony_ci			__clk_get_name(clk_get_parent(clk)),
27462306a36Sopenharmony_ci			(unsigned int)clk_get_rate(clk));
27562306a36Sopenharmony_ci	return clk;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic const char ** __init flexgen_get_parents(struct device_node *np,
27962306a36Sopenharmony_ci						       int *num_parents)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	const char **parents;
28262306a36Sopenharmony_ci	unsigned int nparents;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	nparents = of_clk_get_parent_count(np);
28562306a36Sopenharmony_ci	if (WARN_ON(!nparents))
28662306a36Sopenharmony_ci		return NULL;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
28962306a36Sopenharmony_ci	if (!parents)
29062306a36Sopenharmony_ci		return NULL;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	*num_parents = of_clk_parent_fill(np, parents, nparents);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return parents;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic const struct clkgen_data clkgen_audio = {
29862306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
29962306a36Sopenharmony_ci};
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct clkgen_data clkgen_video = {
30262306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
30362306a36Sopenharmony_ci	.mode = 1,
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih407_a0_clk_out[] = {
30762306a36Sopenharmony_ci	/* This clk needs to be on so that memory interface is accessible */
30862306a36Sopenharmony_ci	{ .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
30962306a36Sopenharmony_ci};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih407_a0 = {
31262306a36Sopenharmony_ci	.outputs = clkgen_stih407_a0_clk_out,
31362306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih407_a0_clk_out),
31462306a36Sopenharmony_ci};
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih410_a0_clk_out[] = {
31762306a36Sopenharmony_ci	/* Those clks need to be on so that memory interface is accessible */
31862306a36Sopenharmony_ci	{ .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
31962306a36Sopenharmony_ci	{ .name = "clk-ic-lmi1", .flags = CLK_IS_CRITICAL },
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih410_a0 = {
32362306a36Sopenharmony_ci	.outputs = clkgen_stih410_a0_clk_out,
32462306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih410_a0_clk_out),
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih407_c0_clk_out[] = {
32862306a36Sopenharmony_ci	{ .name = "clk-icn-gpu", },
32962306a36Sopenharmony_ci	{ .name = "clk-fdma", },
33062306a36Sopenharmony_ci	{ .name = "clk-nand", },
33162306a36Sopenharmony_ci	{ .name = "clk-hva", },
33262306a36Sopenharmony_ci	{ .name = "clk-proc-stfe", },
33362306a36Sopenharmony_ci	{ .name = "clk-proc-tp", },
33462306a36Sopenharmony_ci	{ .name = "clk-rx-icn-dmu", },
33562306a36Sopenharmony_ci	{ .name = "clk-rx-icn-hva", },
33662306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
33762306a36Sopenharmony_ci	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
33862306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
33962306a36Sopenharmony_ci	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
34062306a36Sopenharmony_ci	{ .name = "clk-mmc-0", },
34162306a36Sopenharmony_ci	{ .name = "clk-mmc-1", },
34262306a36Sopenharmony_ci	{ .name = "clk-jpegdec", },
34362306a36Sopenharmony_ci	/* This clk needs to be on to keep A9 running */
34462306a36Sopenharmony_ci	{ .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
34562306a36Sopenharmony_ci	{ .name = "clk-ic-bdisp-0", },
34662306a36Sopenharmony_ci	{ .name = "clk-ic-bdisp-1", },
34762306a36Sopenharmony_ci	{ .name = "clk-pp-dmu", },
34862306a36Sopenharmony_ci	{ .name = "clk-vid-dmu", },
34962306a36Sopenharmony_ci	{ .name = "clk-dss-lpc", },
35062306a36Sopenharmony_ci	{ .name = "clk-st231-aud-0", },
35162306a36Sopenharmony_ci	{ .name = "clk-st231-gp-1", },
35262306a36Sopenharmony_ci	{ .name = "clk-st231-dmu", },
35362306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
35462306a36Sopenharmony_ci	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
35562306a36Sopenharmony_ci	{ .name = "clk-tx-icn-disp-1", },
35662306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
35762306a36Sopenharmony_ci	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
35862306a36Sopenharmony_ci	{ .name = "clk-stfe-frc2", },
35962306a36Sopenharmony_ci	{ .name = "clk-eth-phy", },
36062306a36Sopenharmony_ci	{ .name = "clk-eth-ref-phyclk", },
36162306a36Sopenharmony_ci	{ .name = "clk-flash-promip", },
36262306a36Sopenharmony_ci	{ .name = "clk-main-disp", },
36362306a36Sopenharmony_ci	{ .name = "clk-aux-disp", },
36462306a36Sopenharmony_ci	{ .name = "clk-compo-dvp", },
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih407_c0 = {
36862306a36Sopenharmony_ci	.outputs = clkgen_stih407_c0_clk_out,
36962306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih407_c0_clk_out),
37062306a36Sopenharmony_ci};
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih410_c0_clk_out[] = {
37362306a36Sopenharmony_ci	{ .name = "clk-icn-gpu", },
37462306a36Sopenharmony_ci	{ .name = "clk-fdma", },
37562306a36Sopenharmony_ci	{ .name = "clk-nand", },
37662306a36Sopenharmony_ci	{ .name = "clk-hva", },
37762306a36Sopenharmony_ci	{ .name = "clk-proc-stfe", },
37862306a36Sopenharmony_ci	{ .name = "clk-proc-tp", },
37962306a36Sopenharmony_ci	{ .name = "clk-rx-icn-dmu", },
38062306a36Sopenharmony_ci	{ .name = "clk-rx-icn-hva", },
38162306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
38262306a36Sopenharmony_ci	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
38362306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
38462306a36Sopenharmony_ci	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
38562306a36Sopenharmony_ci	{ .name = "clk-mmc-0", },
38662306a36Sopenharmony_ci	{ .name = "clk-mmc-1", },
38762306a36Sopenharmony_ci	{ .name = "clk-jpegdec", },
38862306a36Sopenharmony_ci	/* This clk needs to be on to keep A9 running */
38962306a36Sopenharmony_ci	{ .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
39062306a36Sopenharmony_ci	{ .name = "clk-ic-bdisp-0", },
39162306a36Sopenharmony_ci	{ .name = "clk-ic-bdisp-1", },
39262306a36Sopenharmony_ci	{ .name = "clk-pp-dmu", },
39362306a36Sopenharmony_ci	{ .name = "clk-vid-dmu", },
39462306a36Sopenharmony_ci	{ .name = "clk-dss-lpc", },
39562306a36Sopenharmony_ci	{ .name = "clk-st231-aud-0", },
39662306a36Sopenharmony_ci	{ .name = "clk-st231-gp-1", },
39762306a36Sopenharmony_ci	{ .name = "clk-st231-dmu", },
39862306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
39962306a36Sopenharmony_ci	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
40062306a36Sopenharmony_ci	{ .name = "clk-tx-icn-disp-1", },
40162306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
40262306a36Sopenharmony_ci	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
40362306a36Sopenharmony_ci	{ .name = "clk-stfe-frc2", },
40462306a36Sopenharmony_ci	{ .name = "clk-eth-phy", },
40562306a36Sopenharmony_ci	{ .name = "clk-eth-ref-phyclk", },
40662306a36Sopenharmony_ci	{ .name = "clk-flash-promip", },
40762306a36Sopenharmony_ci	{ .name = "clk-main-disp", },
40862306a36Sopenharmony_ci	{ .name = "clk-aux-disp", },
40962306a36Sopenharmony_ci	{ .name = "clk-compo-dvp", },
41062306a36Sopenharmony_ci	{ .name = "clk-tx-icn-hades", },
41162306a36Sopenharmony_ci	{ .name = "clk-rx-icn-hades", },
41262306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
41362306a36Sopenharmony_ci	{ .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
41462306a36Sopenharmony_ci	{ .name = "clk-pp-hades", },
41562306a36Sopenharmony_ci	{ .name = "clk-clust-hades", },
41662306a36Sopenharmony_ci	{ .name = "clk-hwpe-hades", },
41762306a36Sopenharmony_ci	{ .name = "clk-fc-hades", },
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih410_c0 = {
42162306a36Sopenharmony_ci	.outputs = clkgen_stih410_c0_clk_out,
42262306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih410_c0_clk_out),
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih418_c0_clk_out[] = {
42662306a36Sopenharmony_ci	{ .name = "clk-icn-gpu", },
42762306a36Sopenharmony_ci	{ .name = "clk-fdma", },
42862306a36Sopenharmony_ci	{ .name = "clk-nand", },
42962306a36Sopenharmony_ci	{ .name = "clk-hva", },
43062306a36Sopenharmony_ci	{ .name = "clk-proc-stfe", },
43162306a36Sopenharmony_ci	{ .name = "clk-tp", },
43262306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
43362306a36Sopenharmony_ci	{ .name = "clk-rx-icn-dmu", .flags = CLK_IS_CRITICAL },
43462306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
43562306a36Sopenharmony_ci	{ .name = "clk-rx-icn-hva", .flags = CLK_IS_CRITICAL },
43662306a36Sopenharmony_ci	{ .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
43762306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
43862306a36Sopenharmony_ci	{ .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
43962306a36Sopenharmony_ci	{ .name = "clk-mmc-0", },
44062306a36Sopenharmony_ci	{ .name = "clk-mmc-1", },
44162306a36Sopenharmony_ci	{ .name = "clk-jpegdec", },
44262306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
44362306a36Sopenharmony_ci	{ .name = "clk-icn-reg", .flags = CLK_IS_CRITICAL },
44462306a36Sopenharmony_ci	{ .name = "clk-proc-bdisp-0", },
44562306a36Sopenharmony_ci	{ .name = "clk-proc-bdisp-1", },
44662306a36Sopenharmony_ci	{ .name = "clk-pp-dmu", },
44762306a36Sopenharmony_ci	{ .name = "clk-vid-dmu", },
44862306a36Sopenharmony_ci	{ .name = "clk-dss-lpc", },
44962306a36Sopenharmony_ci	{ .name = "clk-st231-aud-0", },
45062306a36Sopenharmony_ci	{ .name = "clk-st231-gp-1", },
45162306a36Sopenharmony_ci	{ .name = "clk-st231-dmu", },
45262306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
45362306a36Sopenharmony_ci	{ .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
45462306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
45562306a36Sopenharmony_ci	{ .name = "clk-tx-icn-1", .flags = CLK_IS_CRITICAL },
45662306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
45762306a36Sopenharmony_ci	{ .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
45862306a36Sopenharmony_ci	{ .name = "clk-stfe-frc2", },
45962306a36Sopenharmony_ci	{ .name = "clk-eth-phyref", },
46062306a36Sopenharmony_ci	{ .name = "clk-eth-ref-phyclk", },
46162306a36Sopenharmony_ci	{ .name = "clk-flash-promip", },
46262306a36Sopenharmony_ci	{ .name = "clk-main-disp", },
46362306a36Sopenharmony_ci	{ .name = "clk-aux-disp", },
46462306a36Sopenharmony_ci	{ .name = "clk-compo-dvp", },
46562306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
46662306a36Sopenharmony_ci	{ .name = "clk-tx-icn-hades", .flags = CLK_IS_CRITICAL },
46762306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
46862306a36Sopenharmony_ci	{ .name = "clk-rx-icn-hades", .flags = CLK_IS_CRITICAL },
46962306a36Sopenharmony_ci	/* This clk needs to be on to keep bus interconnect alive */
47062306a36Sopenharmony_ci	{ .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
47162306a36Sopenharmony_ci	{ .name = "clk-pp-hevc", },
47262306a36Sopenharmony_ci	{ .name = "clk-clust-hevc", },
47362306a36Sopenharmony_ci	{ .name = "clk-hwpe-hevc", },
47462306a36Sopenharmony_ci	{ .name = "clk-fc-hevc", },
47562306a36Sopenharmony_ci	{ .name = "clk-proc-mixer", },
47662306a36Sopenharmony_ci	{ .name = "clk-proc-sc", },
47762306a36Sopenharmony_ci	{ .name = "clk-avsp-hevc", },
47862306a36Sopenharmony_ci};
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih418_c0 = {
48162306a36Sopenharmony_ci	.outputs = clkgen_stih418_c0_clk_out,
48262306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih418_c0_clk_out),
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih407_d0_clk_out[] = {
48662306a36Sopenharmony_ci	{ .name = "clk-pcm-0", },
48762306a36Sopenharmony_ci	{ .name = "clk-pcm-1", },
48862306a36Sopenharmony_ci	{ .name = "clk-pcm-2", },
48962306a36Sopenharmony_ci	{ .name = "clk-spdiff", },
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih407_d0 = {
49362306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
49462306a36Sopenharmony_ci	.outputs = clkgen_stih407_d0_clk_out,
49562306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d0_clk_out),
49662306a36Sopenharmony_ci};
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih410_d0_clk_out[] = {
49962306a36Sopenharmony_ci	{ .name = "clk-pcm-0", },
50062306a36Sopenharmony_ci	{ .name = "clk-pcm-1", },
50162306a36Sopenharmony_ci	{ .name = "clk-pcm-2", },
50262306a36Sopenharmony_ci	{ .name = "clk-spdiff", },
50362306a36Sopenharmony_ci	{ .name = "clk-pcmr10-master", },
50462306a36Sopenharmony_ci	{ .name = "clk-usb2-phy", },
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih410_d0 = {
50862306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
50962306a36Sopenharmony_ci	.outputs = clkgen_stih410_d0_clk_out,
51062306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih410_d0_clk_out),
51162306a36Sopenharmony_ci};
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih407_d2_clk_out[] = {
51462306a36Sopenharmony_ci	{ .name = "clk-pix-main-disp", },
51562306a36Sopenharmony_ci	{ .name = "clk-pix-pip", },
51662306a36Sopenharmony_ci	{ .name = "clk-pix-gdp1", },
51762306a36Sopenharmony_ci	{ .name = "clk-pix-gdp2", },
51862306a36Sopenharmony_ci	{ .name = "clk-pix-gdp3", },
51962306a36Sopenharmony_ci	{ .name = "clk-pix-gdp4", },
52062306a36Sopenharmony_ci	{ .name = "clk-pix-aux-disp", },
52162306a36Sopenharmony_ci	{ .name = "clk-denc", },
52262306a36Sopenharmony_ci	{ .name = "clk-pix-hddac", },
52362306a36Sopenharmony_ci	{ .name = "clk-hddac", },
52462306a36Sopenharmony_ci	{ .name = "clk-sddac", },
52562306a36Sopenharmony_ci	{ .name = "clk-pix-dvo", },
52662306a36Sopenharmony_ci	{ .name = "clk-dvo", },
52762306a36Sopenharmony_ci	{ .name = "clk-pix-hdmi", },
52862306a36Sopenharmony_ci	{ .name = "clk-tmds-hdmi", },
52962306a36Sopenharmony_ci	{ .name = "clk-ref-hdmiphy", },
53062306a36Sopenharmony_ci};
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih407_d2 = {
53362306a36Sopenharmony_ci	.outputs = clkgen_stih407_d2_clk_out,
53462306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d2_clk_out),
53562306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
53662306a36Sopenharmony_ci	.mode = 1,
53762306a36Sopenharmony_ci};
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih418_d2_clk_out[] = {
54062306a36Sopenharmony_ci	{ .name = "clk-pix-main-disp", },
54162306a36Sopenharmony_ci	{ .name = "", },
54262306a36Sopenharmony_ci	{ .name = "", },
54362306a36Sopenharmony_ci	{ .name = "", },
54462306a36Sopenharmony_ci	{ .name = "", },
54562306a36Sopenharmony_ci	{ .name = "clk-tmds-hdmi-div2", },
54662306a36Sopenharmony_ci	{ .name = "clk-pix-aux-disp", },
54762306a36Sopenharmony_ci	{ .name = "clk-denc", },
54862306a36Sopenharmony_ci	{ .name = "clk-pix-hddac", },
54962306a36Sopenharmony_ci	{ .name = "clk-hddac", },
55062306a36Sopenharmony_ci	{ .name = "clk-sddac", },
55162306a36Sopenharmony_ci	{ .name = "clk-pix-dvo", },
55262306a36Sopenharmony_ci	{ .name = "clk-dvo", },
55362306a36Sopenharmony_ci	{ .name = "clk-pix-hdmi", },
55462306a36Sopenharmony_ci	{ .name = "clk-tmds-hdmi", },
55562306a36Sopenharmony_ci	{ .name = "clk-ref-hdmiphy", },
55662306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
55762306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
55862306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
55962306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
56062306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
56162306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
56262306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
56362306a36Sopenharmony_ci	{ .name = "", }, { .name = "", }, { .name = "", },
56462306a36Sopenharmony_ci	{ .name = "clk-vp9", },
56562306a36Sopenharmony_ci};
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih418_d2 = {
56862306a36Sopenharmony_ci	.outputs = clkgen_stih418_d2_clk_out,
56962306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih418_d2_clk_out),
57062306a36Sopenharmony_ci	.flags = CLK_SET_RATE_PARENT,
57162306a36Sopenharmony_ci	.mode = 1,
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic const struct clkgen_clk_out clkgen_stih407_d3_clk_out[] = {
57562306a36Sopenharmony_ci	{ .name = "clk-stfe-frc1", },
57662306a36Sopenharmony_ci	{ .name = "clk-tsout-0", },
57762306a36Sopenharmony_ci	{ .name = "clk-tsout-1", },
57862306a36Sopenharmony_ci	{ .name = "clk-mchi", },
57962306a36Sopenharmony_ci	{ .name = "clk-vsens-compo", },
58062306a36Sopenharmony_ci	{ .name = "clk-frc1-remote", },
58162306a36Sopenharmony_ci	{ .name = "clk-lpc-0", },
58262306a36Sopenharmony_ci	{ .name = "clk-lpc-1", },
58362306a36Sopenharmony_ci};
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic const struct clkgen_data clkgen_stih407_d3 = {
58662306a36Sopenharmony_ci	.outputs = clkgen_stih407_d3_clk_out,
58762306a36Sopenharmony_ci	.outputs_nb = ARRAY_SIZE(clkgen_stih407_d3_clk_out),
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic const struct of_device_id flexgen_of_match[] = {
59162306a36Sopenharmony_ci	{
59262306a36Sopenharmony_ci		.compatible = "st,flexgen-audio",
59362306a36Sopenharmony_ci		.data = &clkgen_audio,
59462306a36Sopenharmony_ci	},
59562306a36Sopenharmony_ci	{
59662306a36Sopenharmony_ci		.compatible = "st,flexgen-video",
59762306a36Sopenharmony_ci		.data = &clkgen_video,
59862306a36Sopenharmony_ci	},
59962306a36Sopenharmony_ci	{
60062306a36Sopenharmony_ci		.compatible = "st,flexgen-stih407-a0",
60162306a36Sopenharmony_ci		.data = &clkgen_stih407_a0,
60262306a36Sopenharmony_ci	},
60362306a36Sopenharmony_ci	{
60462306a36Sopenharmony_ci		.compatible = "st,flexgen-stih410-a0",
60562306a36Sopenharmony_ci		.data = &clkgen_stih410_a0,
60662306a36Sopenharmony_ci	},
60762306a36Sopenharmony_ci	{
60862306a36Sopenharmony_ci		.compatible = "st,flexgen-stih407-c0",
60962306a36Sopenharmony_ci		.data = &clkgen_stih407_c0,
61062306a36Sopenharmony_ci	},
61162306a36Sopenharmony_ci	{
61262306a36Sopenharmony_ci		.compatible = "st,flexgen-stih410-c0",
61362306a36Sopenharmony_ci		.data = &clkgen_stih410_c0,
61462306a36Sopenharmony_ci	},
61562306a36Sopenharmony_ci	{
61662306a36Sopenharmony_ci		.compatible = "st,flexgen-stih418-c0",
61762306a36Sopenharmony_ci		.data = &clkgen_stih418_c0,
61862306a36Sopenharmony_ci	},
61962306a36Sopenharmony_ci	{
62062306a36Sopenharmony_ci		.compatible = "st,flexgen-stih407-d0",
62162306a36Sopenharmony_ci		.data = &clkgen_stih407_d0,
62262306a36Sopenharmony_ci	},
62362306a36Sopenharmony_ci	{
62462306a36Sopenharmony_ci		.compatible = "st,flexgen-stih410-d0",
62562306a36Sopenharmony_ci		.data = &clkgen_stih410_d0,
62662306a36Sopenharmony_ci	},
62762306a36Sopenharmony_ci	{
62862306a36Sopenharmony_ci		.compatible = "st,flexgen-stih407-d2",
62962306a36Sopenharmony_ci		.data = &clkgen_stih407_d2,
63062306a36Sopenharmony_ci	},
63162306a36Sopenharmony_ci	{
63262306a36Sopenharmony_ci		.compatible = "st,flexgen-stih418-d2",
63362306a36Sopenharmony_ci		.data = &clkgen_stih418_d2,
63462306a36Sopenharmony_ci	},
63562306a36Sopenharmony_ci	{
63662306a36Sopenharmony_ci		.compatible = "st,flexgen-stih407-d3",
63762306a36Sopenharmony_ci		.data = &clkgen_stih407_d3,
63862306a36Sopenharmony_ci	},
63962306a36Sopenharmony_ci	{}
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic void __init st_of_flexgen_setup(struct device_node *np)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct device_node *pnode;
64562306a36Sopenharmony_ci	void __iomem *reg;
64662306a36Sopenharmony_ci	struct clk_onecell_data *clk_data;
64762306a36Sopenharmony_ci	const char **parents;
64862306a36Sopenharmony_ci	int num_parents, i;
64962306a36Sopenharmony_ci	spinlock_t *rlock = NULL;
65062306a36Sopenharmony_ci	const struct of_device_id *match;
65162306a36Sopenharmony_ci	struct clkgen_data *data = NULL;
65262306a36Sopenharmony_ci	unsigned long flex_flags = 0;
65362306a36Sopenharmony_ci	int ret;
65462306a36Sopenharmony_ci	bool clk_mode = 0;
65562306a36Sopenharmony_ci	const char *clk_name;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	pnode = of_get_parent(np);
65862306a36Sopenharmony_ci	if (!pnode)
65962306a36Sopenharmony_ci		return;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	reg = of_iomap(pnode, 0);
66262306a36Sopenharmony_ci	of_node_put(pnode);
66362306a36Sopenharmony_ci	if (!reg)
66462306a36Sopenharmony_ci		return;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	parents = flexgen_get_parents(np, &num_parents);
66762306a36Sopenharmony_ci	if (!parents) {
66862306a36Sopenharmony_ci		iounmap(reg);
66962306a36Sopenharmony_ci		return;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	match = of_match_node(flexgen_of_match, np);
67362306a36Sopenharmony_ci	if (match) {
67462306a36Sopenharmony_ci		data = (struct clkgen_data *)match->data;
67562306a36Sopenharmony_ci		flex_flags = data->flags;
67662306a36Sopenharmony_ci		clk_mode = data->mode;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
68062306a36Sopenharmony_ci	if (!clk_data)
68162306a36Sopenharmony_ci		goto err;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/* First try to get output information from the compatible data */
68462306a36Sopenharmony_ci	if (!data || !data->outputs_nb || !data->outputs) {
68562306a36Sopenharmony_ci		ret = of_property_count_strings(np, "clock-output-names");
68662306a36Sopenharmony_ci		if (ret <= 0) {
68762306a36Sopenharmony_ci			pr_err("%s: Failed to get number of output clocks (%d)",
68862306a36Sopenharmony_ci					__func__, clk_data->clk_num);
68962306a36Sopenharmony_ci			goto err;
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci		clk_data->clk_num = ret;
69262306a36Sopenharmony_ci	} else
69362306a36Sopenharmony_ci		clk_data->clk_num = data->outputs_nb;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
69662306a36Sopenharmony_ci			GFP_KERNEL);
69762306a36Sopenharmony_ci	if (!clk_data->clks)
69862306a36Sopenharmony_ci		goto err;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	rlock = kzalloc(sizeof(spinlock_t), GFP_KERNEL);
70162306a36Sopenharmony_ci	if (!rlock)
70262306a36Sopenharmony_ci		goto err;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	spin_lock_init(rlock);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	for (i = 0; i < clk_data->clk_num; i++) {
70762306a36Sopenharmony_ci		struct clk *clk;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		if (!data || !data->outputs_nb || !data->outputs) {
71062306a36Sopenharmony_ci			if (of_property_read_string_index(np,
71162306a36Sopenharmony_ci							  "clock-output-names",
71262306a36Sopenharmony_ci							  i, &clk_name))
71362306a36Sopenharmony_ci				break;
71462306a36Sopenharmony_ci			flex_flags &= ~CLK_IS_CRITICAL;
71562306a36Sopenharmony_ci			of_clk_detect_critical(np, i, &flex_flags);
71662306a36Sopenharmony_ci		} else {
71762306a36Sopenharmony_ci			clk_name = data->outputs[i].name;
71862306a36Sopenharmony_ci			flex_flags = data->flags | data->outputs[i].flags;
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		/*
72262306a36Sopenharmony_ci		 * If we read an empty clock name then the output is unused
72362306a36Sopenharmony_ci		 */
72462306a36Sopenharmony_ci		if (*clk_name == '\0')
72562306a36Sopenharmony_ci			continue;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		clk = clk_register_flexgen(clk_name, parents, num_parents,
72862306a36Sopenharmony_ci					   reg, rlock, i, flex_flags, clk_mode);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		if (IS_ERR(clk))
73162306a36Sopenharmony_ci			goto err;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		clk_data->clks[i] = clk;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	kfree(parents);
73762306a36Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	return;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cierr:
74262306a36Sopenharmony_ci	iounmap(reg);
74362306a36Sopenharmony_ci	if (clk_data)
74462306a36Sopenharmony_ci		kfree(clk_data->clks);
74562306a36Sopenharmony_ci	kfree(clk_data);
74662306a36Sopenharmony_ci	kfree(parents);
74762306a36Sopenharmony_ci	kfree(rlock);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ciCLK_OF_DECLARE(flexgen, "st,flexgen", st_of_flexgen_setup);
750