xref: /openbmc/linux/drivers/clk/st/clkgen-mux.c (revision 44993d384004fa9ca2dfcca86cddc436a28d6958)
194885fafSGabriel FERNANDEZ /*
294885fafSGabriel FERNANDEZ  * clkgen-mux.c: ST GEN-MUX Clock driver
394885fafSGabriel FERNANDEZ  *
494885fafSGabriel FERNANDEZ  * Copyright (C) 2014 STMicroelectronics (R&D) Limited
594885fafSGabriel FERNANDEZ  *
694885fafSGabriel FERNANDEZ  * Authors: Stephen Gallimore <stephen.gallimore@st.com>
794885fafSGabriel FERNANDEZ  *	    Pankaj Dev <pankaj.dev@st.com>
894885fafSGabriel FERNANDEZ  *
994885fafSGabriel FERNANDEZ  * This program is free software; you can redistribute it and/or modify
1094885fafSGabriel FERNANDEZ  * it under the terms of the GNU General Public License as published by
1194885fafSGabriel FERNANDEZ  * the Free Software Foundation; either version 2 of the License, or
1294885fafSGabriel FERNANDEZ  * (at your option) any later version.
1394885fafSGabriel FERNANDEZ  *
1494885fafSGabriel FERNANDEZ  */
1594885fafSGabriel FERNANDEZ 
1694885fafSGabriel FERNANDEZ #include <linux/slab.h>
1794885fafSGabriel FERNANDEZ #include <linux/of_address.h>
1894885fafSGabriel FERNANDEZ #include <linux/clk-provider.h>
1994885fafSGabriel FERNANDEZ 
2094885fafSGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgena_divmux_lock);
21*44993d38SGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgenf_lock);
2294885fafSGabriel FERNANDEZ 
2394885fafSGabriel FERNANDEZ static const char ** __init clkgen_mux_get_parents(struct device_node *np,
2494885fafSGabriel FERNANDEZ 						       int *num_parents)
2594885fafSGabriel FERNANDEZ {
2694885fafSGabriel FERNANDEZ 	const char **parents;
2794885fafSGabriel FERNANDEZ 	int nparents, i;
2894885fafSGabriel FERNANDEZ 
2994885fafSGabriel FERNANDEZ 	nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
3094885fafSGabriel FERNANDEZ 	if (WARN_ON(nparents <= 0))
3194885fafSGabriel FERNANDEZ 		return ERR_PTR(-EINVAL);
3294885fafSGabriel FERNANDEZ 
3394885fafSGabriel FERNANDEZ 	parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL);
3494885fafSGabriel FERNANDEZ 	if (!parents)
3594885fafSGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
3694885fafSGabriel FERNANDEZ 
3794885fafSGabriel FERNANDEZ 	for (i = 0; i < nparents; i++)
3894885fafSGabriel FERNANDEZ 		parents[i] = of_clk_get_parent_name(np, i);
3994885fafSGabriel FERNANDEZ 
4094885fafSGabriel FERNANDEZ 	*num_parents = nparents;
4194885fafSGabriel FERNANDEZ 	return parents;
4294885fafSGabriel FERNANDEZ }
4394885fafSGabriel FERNANDEZ 
4494885fafSGabriel FERNANDEZ /**
4594885fafSGabriel FERNANDEZ  * DOC: Clock mux with a programmable divider on each of its three inputs.
4694885fafSGabriel FERNANDEZ  *      The mux has an input setting which effectively gates its output.
4794885fafSGabriel FERNANDEZ  *
4894885fafSGabriel FERNANDEZ  * Traits of this clock:
4994885fafSGabriel FERNANDEZ  * prepare - clk_(un)prepare only ensures parent is (un)prepared
5094885fafSGabriel FERNANDEZ  * enable - clk_enable and clk_disable are functional & control gating
5194885fafSGabriel FERNANDEZ  * rate - set rate is supported
5294885fafSGabriel FERNANDEZ  * parent - set/get parent
5394885fafSGabriel FERNANDEZ  */
5494885fafSGabriel FERNANDEZ 
5594885fafSGabriel FERNANDEZ #define NUM_INPUTS 3
5694885fafSGabriel FERNANDEZ 
5794885fafSGabriel FERNANDEZ struct clkgena_divmux {
5894885fafSGabriel FERNANDEZ 	struct clk_hw hw;
5994885fafSGabriel FERNANDEZ 	/* Subclassed mux and divider structures */
6094885fafSGabriel FERNANDEZ 	struct clk_mux mux;
6194885fafSGabriel FERNANDEZ 	struct clk_divider div[NUM_INPUTS];
6294885fafSGabriel FERNANDEZ 	/* Enable/running feedback register bits for each input */
6394885fafSGabriel FERNANDEZ 	void __iomem *feedback_reg[NUM_INPUTS];
6494885fafSGabriel FERNANDEZ 	int feedback_bit_idx;
6594885fafSGabriel FERNANDEZ 
6694885fafSGabriel FERNANDEZ 	u8              muxsel;
6794885fafSGabriel FERNANDEZ };
6894885fafSGabriel FERNANDEZ 
6994885fafSGabriel FERNANDEZ #define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw)
7094885fafSGabriel FERNANDEZ 
7194885fafSGabriel FERNANDEZ struct clkgena_divmux_data {
7294885fafSGabriel FERNANDEZ 	int num_outputs;
7394885fafSGabriel FERNANDEZ 	int mux_offset;
7494885fafSGabriel FERNANDEZ 	int mux_offset2;
7594885fafSGabriel FERNANDEZ 	int mux_start_bit;
7694885fafSGabriel FERNANDEZ 	int div_offsets[NUM_INPUTS];
7794885fafSGabriel FERNANDEZ 	int fb_offsets[NUM_INPUTS];
7894885fafSGabriel FERNANDEZ 	int fb_start_bit_idx;
7994885fafSGabriel FERNANDEZ };
8094885fafSGabriel FERNANDEZ 
8194885fafSGabriel FERNANDEZ #define CKGAX_CLKOPSRC_SWITCH_OFF 0x3
8294885fafSGabriel FERNANDEZ 
8394885fafSGabriel FERNANDEZ static int clkgena_divmux_is_running(struct clkgena_divmux *mux)
8494885fafSGabriel FERNANDEZ {
8594885fafSGabriel FERNANDEZ 	u32 regval = readl(mux->feedback_reg[mux->muxsel]);
8694885fafSGabriel FERNANDEZ 	u32 running = regval & BIT(mux->feedback_bit_idx);
8794885fafSGabriel FERNANDEZ 	return !!running;
8894885fafSGabriel FERNANDEZ }
8994885fafSGabriel FERNANDEZ 
9094885fafSGabriel FERNANDEZ static int clkgena_divmux_enable(struct clk_hw *hw)
9194885fafSGabriel FERNANDEZ {
9294885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
9394885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
9494885fafSGabriel FERNANDEZ 	unsigned long timeout;
9594885fafSGabriel FERNANDEZ 	int ret = 0;
9694885fafSGabriel FERNANDEZ 
9794885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
9894885fafSGabriel FERNANDEZ 
9994885fafSGabriel FERNANDEZ 	ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
10094885fafSGabriel FERNANDEZ 	if (ret)
10194885fafSGabriel FERNANDEZ 		return ret;
10294885fafSGabriel FERNANDEZ 
10394885fafSGabriel FERNANDEZ 	timeout = jiffies + msecs_to_jiffies(10);
10494885fafSGabriel FERNANDEZ 
10594885fafSGabriel FERNANDEZ 	while (!clkgena_divmux_is_running(genamux)) {
10694885fafSGabriel FERNANDEZ 		if (time_after(jiffies, timeout))
10794885fafSGabriel FERNANDEZ 			return -ETIMEDOUT;
10894885fafSGabriel FERNANDEZ 		cpu_relax();
10994885fafSGabriel FERNANDEZ 	}
11094885fafSGabriel FERNANDEZ 
11194885fafSGabriel FERNANDEZ 	return 0;
11294885fafSGabriel FERNANDEZ }
11394885fafSGabriel FERNANDEZ 
11494885fafSGabriel FERNANDEZ static void clkgena_divmux_disable(struct clk_hw *hw)
11594885fafSGabriel FERNANDEZ {
11694885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
11794885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
11894885fafSGabriel FERNANDEZ 
11994885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
12094885fafSGabriel FERNANDEZ 
12194885fafSGabriel FERNANDEZ 	clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
12294885fafSGabriel FERNANDEZ }
12394885fafSGabriel FERNANDEZ 
12494885fafSGabriel FERNANDEZ static int clkgena_divmux_is_enabled(struct clk_hw *hw)
12594885fafSGabriel FERNANDEZ {
12694885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
12794885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
12894885fafSGabriel FERNANDEZ 
12994885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
13094885fafSGabriel FERNANDEZ 
13194885fafSGabriel FERNANDEZ 	return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
13294885fafSGabriel FERNANDEZ }
13394885fafSGabriel FERNANDEZ 
13494885fafSGabriel FERNANDEZ u8 clkgena_divmux_get_parent(struct clk_hw *hw)
13594885fafSGabriel FERNANDEZ {
13694885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
13794885fafSGabriel FERNANDEZ 	struct clk_hw *mux_hw = &genamux->mux.hw;
13894885fafSGabriel FERNANDEZ 
13994885fafSGabriel FERNANDEZ 	mux_hw->clk = hw->clk;
14094885fafSGabriel FERNANDEZ 
14194885fafSGabriel FERNANDEZ 	genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
14294885fafSGabriel FERNANDEZ 	if ((s8)genamux->muxsel < 0) {
14394885fafSGabriel FERNANDEZ 		pr_debug("%s: %s: Invalid parent, setting to default.\n",
14494885fafSGabriel FERNANDEZ 		      __func__, __clk_get_name(hw->clk));
14594885fafSGabriel FERNANDEZ 		genamux->muxsel = 0;
14694885fafSGabriel FERNANDEZ 	}
14794885fafSGabriel FERNANDEZ 
14894885fafSGabriel FERNANDEZ 	return genamux->muxsel;
14994885fafSGabriel FERNANDEZ }
15094885fafSGabriel FERNANDEZ 
15194885fafSGabriel FERNANDEZ static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index)
15294885fafSGabriel FERNANDEZ {
15394885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
15494885fafSGabriel FERNANDEZ 
15594885fafSGabriel FERNANDEZ 	if (index >= CKGAX_CLKOPSRC_SWITCH_OFF)
15694885fafSGabriel FERNANDEZ 		return -EINVAL;
15794885fafSGabriel FERNANDEZ 
15894885fafSGabriel FERNANDEZ 	genamux->muxsel = index;
15994885fafSGabriel FERNANDEZ 
16094885fafSGabriel FERNANDEZ 	/*
16194885fafSGabriel FERNANDEZ 	 * If the mux is already enabled, call enable directly to set the
16294885fafSGabriel FERNANDEZ 	 * new mux position and wait for it to start running again. Otherwise
16394885fafSGabriel FERNANDEZ 	 * do nothing.
16494885fafSGabriel FERNANDEZ 	 */
16594885fafSGabriel FERNANDEZ 	if (clkgena_divmux_is_enabled(hw))
16694885fafSGabriel FERNANDEZ 		clkgena_divmux_enable(hw);
16794885fafSGabriel FERNANDEZ 
16894885fafSGabriel FERNANDEZ 	return 0;
16994885fafSGabriel FERNANDEZ }
17094885fafSGabriel FERNANDEZ 
17194885fafSGabriel FERNANDEZ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
17294885fafSGabriel FERNANDEZ 		unsigned long parent_rate)
17394885fafSGabriel FERNANDEZ {
17494885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
17594885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
17694885fafSGabriel FERNANDEZ 
17794885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
17894885fafSGabriel FERNANDEZ 
17994885fafSGabriel FERNANDEZ 	return clk_divider_ops.recalc_rate(div_hw, parent_rate);
18094885fafSGabriel FERNANDEZ }
18194885fafSGabriel FERNANDEZ 
18294885fafSGabriel FERNANDEZ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate,
18394885fafSGabriel FERNANDEZ 				unsigned long parent_rate)
18494885fafSGabriel FERNANDEZ {
18594885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
18694885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
18794885fafSGabriel FERNANDEZ 
18894885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
18994885fafSGabriel FERNANDEZ 
19094885fafSGabriel FERNANDEZ 	return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
19194885fafSGabriel FERNANDEZ }
19294885fafSGabriel FERNANDEZ 
19394885fafSGabriel FERNANDEZ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate,
19494885fafSGabriel FERNANDEZ 				   unsigned long *prate)
19594885fafSGabriel FERNANDEZ {
19694885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
19794885fafSGabriel FERNANDEZ 	struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
19894885fafSGabriel FERNANDEZ 
19994885fafSGabriel FERNANDEZ 	div_hw->clk = hw->clk;
20094885fafSGabriel FERNANDEZ 
20194885fafSGabriel FERNANDEZ 	return clk_divider_ops.round_rate(div_hw, rate, prate);
20294885fafSGabriel FERNANDEZ }
20394885fafSGabriel FERNANDEZ 
20494885fafSGabriel FERNANDEZ static const struct clk_ops clkgena_divmux_ops = {
20594885fafSGabriel FERNANDEZ 	.enable = clkgena_divmux_enable,
20694885fafSGabriel FERNANDEZ 	.disable = clkgena_divmux_disable,
20794885fafSGabriel FERNANDEZ 	.is_enabled = clkgena_divmux_is_enabled,
20894885fafSGabriel FERNANDEZ 	.get_parent = clkgena_divmux_get_parent,
20994885fafSGabriel FERNANDEZ 	.set_parent = clkgena_divmux_set_parent,
21094885fafSGabriel FERNANDEZ 	.round_rate = clkgena_divmux_round_rate,
21194885fafSGabriel FERNANDEZ 	.recalc_rate = clkgena_divmux_recalc_rate,
21294885fafSGabriel FERNANDEZ 	.set_rate = clkgena_divmux_set_rate,
21394885fafSGabriel FERNANDEZ };
21494885fafSGabriel FERNANDEZ 
21594885fafSGabriel FERNANDEZ /**
21694885fafSGabriel FERNANDEZ  * clk_register_genamux - register a genamux clock with the clock framework
21794885fafSGabriel FERNANDEZ  */
21894885fafSGabriel FERNANDEZ struct clk *clk_register_genamux(const char *name,
21994885fafSGabriel FERNANDEZ 				const char **parent_names, u8 num_parents,
22094885fafSGabriel FERNANDEZ 				void __iomem *reg,
22194885fafSGabriel FERNANDEZ 				const struct clkgena_divmux_data *muxdata,
22294885fafSGabriel FERNANDEZ 				u32 idx)
22394885fafSGabriel FERNANDEZ {
22494885fafSGabriel FERNANDEZ 	/*
22594885fafSGabriel FERNANDEZ 	 * Fixed constants across all ClockgenA variants
22694885fafSGabriel FERNANDEZ 	 */
22794885fafSGabriel FERNANDEZ 	const int mux_width = 2;
22894885fafSGabriel FERNANDEZ 	const int divider_width = 5;
22994885fafSGabriel FERNANDEZ 	struct clkgena_divmux *genamux;
23094885fafSGabriel FERNANDEZ 	struct clk *clk;
23194885fafSGabriel FERNANDEZ 	struct clk_init_data init;
23294885fafSGabriel FERNANDEZ 	int i;
23394885fafSGabriel FERNANDEZ 
23494885fafSGabriel FERNANDEZ 	genamux = kzalloc(sizeof(*genamux), GFP_KERNEL);
23594885fafSGabriel FERNANDEZ 	if (!genamux)
23694885fafSGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
23794885fafSGabriel FERNANDEZ 
23894885fafSGabriel FERNANDEZ 	init.name = name;
23994885fafSGabriel FERNANDEZ 	init.ops = &clkgena_divmux_ops;
24094885fafSGabriel FERNANDEZ 	init.flags = CLK_IS_BASIC;
24194885fafSGabriel FERNANDEZ 	init.parent_names = parent_names;
24294885fafSGabriel FERNANDEZ 	init.num_parents = num_parents;
24394885fafSGabriel FERNANDEZ 
24494885fafSGabriel FERNANDEZ 	genamux->mux.lock  = &clkgena_divmux_lock;
24594885fafSGabriel FERNANDEZ 	genamux->mux.mask = BIT(mux_width) - 1;
24694885fafSGabriel FERNANDEZ 	genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width);
24794885fafSGabriel FERNANDEZ 	if (genamux->mux.shift > 31) {
24894885fafSGabriel FERNANDEZ 		/*
24994885fafSGabriel FERNANDEZ 		 * We have spilled into the second mux register so
25094885fafSGabriel FERNANDEZ 		 * adjust the register address and the bit shift accordingly
25194885fafSGabriel FERNANDEZ 		 */
25294885fafSGabriel FERNANDEZ 		genamux->mux.reg = reg + muxdata->mux_offset2;
25394885fafSGabriel FERNANDEZ 		genamux->mux.shift -= 32;
25494885fafSGabriel FERNANDEZ 	} else {
25594885fafSGabriel FERNANDEZ 		genamux->mux.reg   = reg + muxdata->mux_offset;
25694885fafSGabriel FERNANDEZ 	}
25794885fafSGabriel FERNANDEZ 
25894885fafSGabriel FERNANDEZ 	for (i = 0; i < NUM_INPUTS; i++) {
25994885fafSGabriel FERNANDEZ 		/*
26094885fafSGabriel FERNANDEZ 		 * Divider config for each input
26194885fafSGabriel FERNANDEZ 		 */
26294885fafSGabriel FERNANDEZ 		void __iomem *divbase = reg + muxdata->div_offsets[i];
26394885fafSGabriel FERNANDEZ 		genamux->div[i].width = divider_width;
26494885fafSGabriel FERNANDEZ 		genamux->div[i].reg = divbase + (idx * sizeof(u32));
26594885fafSGabriel FERNANDEZ 
26694885fafSGabriel FERNANDEZ 		/*
26794885fafSGabriel FERNANDEZ 		 * Mux enabled/running feedback register for each input.
26894885fafSGabriel FERNANDEZ 		 */
26994885fafSGabriel FERNANDEZ 		genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i];
27094885fafSGabriel FERNANDEZ 	}
27194885fafSGabriel FERNANDEZ 
27294885fafSGabriel FERNANDEZ 	genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx;
27394885fafSGabriel FERNANDEZ 	genamux->hw.init = &init;
27494885fafSGabriel FERNANDEZ 
27594885fafSGabriel FERNANDEZ 	clk = clk_register(NULL, &genamux->hw);
27694885fafSGabriel FERNANDEZ 	if (IS_ERR(clk)) {
27794885fafSGabriel FERNANDEZ 		kfree(genamux);
27894885fafSGabriel FERNANDEZ 		goto err;
27994885fafSGabriel FERNANDEZ 	}
28094885fafSGabriel FERNANDEZ 
28194885fafSGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %lu\n",
28294885fafSGabriel FERNANDEZ 			__clk_get_name(clk),
28394885fafSGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
28494885fafSGabriel FERNANDEZ 			clk_get_rate(clk));
28594885fafSGabriel FERNANDEZ err:
28694885fafSGabriel FERNANDEZ 	return clk;
28794885fafSGabriel FERNANDEZ }
28894885fafSGabriel FERNANDEZ 
28994885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65hs = {
29094885fafSGabriel FERNANDEZ 	.num_outputs = 4,
29194885fafSGabriel FERNANDEZ 	.mux_offset = 0x14,
29294885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
29394885fafSGabriel FERNANDEZ 	.div_offsets = { 0x800, 0x900, 0xb00 },
29494885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x18, 0x1c, 0x20 },
29594885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 0,
29694885fafSGabriel FERNANDEZ };
29794885fafSGabriel FERNANDEZ 
29894885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c65ls = {
29994885fafSGabriel FERNANDEZ 	.num_outputs = 14,
30094885fafSGabriel FERNANDEZ 	.mux_offset = 0x14,
30194885fafSGabriel FERNANDEZ 	.mux_offset2 = 0x24,
30294885fafSGabriel FERNANDEZ 	.mux_start_bit = 8,
30394885fafSGabriel FERNANDEZ 	.div_offsets = { 0x810, 0xa10, 0xb10 },
30494885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x18, 0x1c, 0x20 },
30594885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 4,
30694885fafSGabriel FERNANDEZ };
30794885fafSGabriel FERNANDEZ 
30894885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf0 = {
30994885fafSGabriel FERNANDEZ 	.num_outputs = 8,
31094885fafSGabriel FERNANDEZ 	.mux_offset = 0x1c,
31194885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
31294885fafSGabriel FERNANDEZ 	.div_offsets = { 0x800, 0x900, 0xa60 },
31394885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
31494885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 0,
31594885fafSGabriel FERNANDEZ };
31694885fafSGabriel FERNANDEZ 
31794885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf1 = {
31894885fafSGabriel FERNANDEZ 	.num_outputs = 8,
31994885fafSGabriel FERNANDEZ 	.mux_offset = 0x1c,
32094885fafSGabriel FERNANDEZ 	.mux_start_bit = 16,
32194885fafSGabriel FERNANDEZ 	.div_offsets = { 0x820, 0x980, 0xa80 },
32294885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
32394885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 8,
32494885fafSGabriel FERNANDEZ };
32594885fafSGabriel FERNANDEZ 
32694885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf2 = {
32794885fafSGabriel FERNANDEZ 	.num_outputs = 8,
32894885fafSGabriel FERNANDEZ 	.mux_offset = 0x20,
32994885fafSGabriel FERNANDEZ 	.mux_start_bit = 0,
33094885fafSGabriel FERNANDEZ 	.div_offsets = { 0x840, 0xa20, 0xb10 },
33194885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
33294885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 16,
33394885fafSGabriel FERNANDEZ };
33494885fafSGabriel FERNANDEZ 
33594885fafSGabriel FERNANDEZ static struct clkgena_divmux_data st_divmux_c32odf3 = {
33694885fafSGabriel FERNANDEZ 	.num_outputs = 8,
33794885fafSGabriel FERNANDEZ 	.mux_offset = 0x20,
33894885fafSGabriel FERNANDEZ 	.mux_start_bit = 16,
33994885fafSGabriel FERNANDEZ 	.div_offsets = { 0x860, 0xa40, 0xb30 },
34094885fafSGabriel FERNANDEZ 	.fb_offsets = { 0x2c, 0x24, 0x28 },
34194885fafSGabriel FERNANDEZ 	.fb_start_bit_idx = 24,
34294885fafSGabriel FERNANDEZ };
34394885fafSGabriel FERNANDEZ 
34494885fafSGabriel FERNANDEZ static struct of_device_id clkgena_divmux_of_match[] = {
34594885fafSGabriel FERNANDEZ 	{
34694885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c65-hs",
34794885fafSGabriel FERNANDEZ 		.data = &st_divmux_c65hs,
34894885fafSGabriel FERNANDEZ 	},
34994885fafSGabriel FERNANDEZ 	{
35094885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c65-ls",
35194885fafSGabriel FERNANDEZ 		.data = &st_divmux_c65ls,
35294885fafSGabriel FERNANDEZ 	},
35394885fafSGabriel FERNANDEZ 	{
35494885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf0",
35594885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf0,
35694885fafSGabriel FERNANDEZ 	},
35794885fafSGabriel FERNANDEZ 	{
35894885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf1",
35994885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf1,
36094885fafSGabriel FERNANDEZ 	},
36194885fafSGabriel FERNANDEZ 	{
36294885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf2",
36394885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf2,
36494885fafSGabriel FERNANDEZ 	},
36594885fafSGabriel FERNANDEZ 	{
36694885fafSGabriel FERNANDEZ 		.compatible = "st,clkgena-divmux-c32-odf3",
36794885fafSGabriel FERNANDEZ 		.data = &st_divmux_c32odf3,
36894885fafSGabriel FERNANDEZ 	},
36994885fafSGabriel FERNANDEZ 	{}
37094885fafSGabriel FERNANDEZ };
37194885fafSGabriel FERNANDEZ 
37294885fafSGabriel FERNANDEZ static void __iomem * __init clkgen_get_register_base(
37394885fafSGabriel FERNANDEZ 				struct device_node *np)
37494885fafSGabriel FERNANDEZ {
37594885fafSGabriel FERNANDEZ 	struct device_node *pnode;
37694885fafSGabriel FERNANDEZ 	void __iomem *reg = NULL;
37794885fafSGabriel FERNANDEZ 
37894885fafSGabriel FERNANDEZ 	pnode = of_get_parent(np);
37994885fafSGabriel FERNANDEZ 	if (!pnode)
38094885fafSGabriel FERNANDEZ 		return NULL;
38194885fafSGabriel FERNANDEZ 
38294885fafSGabriel FERNANDEZ 	reg = of_iomap(pnode, 0);
38394885fafSGabriel FERNANDEZ 
38494885fafSGabriel FERNANDEZ 	of_node_put(pnode);
38594885fafSGabriel FERNANDEZ 	return reg;
38694885fafSGabriel FERNANDEZ }
38794885fafSGabriel FERNANDEZ 
38894885fafSGabriel FERNANDEZ void __init st_of_clkgena_divmux_setup(struct device_node *np)
38994885fafSGabriel FERNANDEZ {
39094885fafSGabriel FERNANDEZ 	const struct of_device_id *match;
39194885fafSGabriel FERNANDEZ 	const struct clkgena_divmux_data *data;
39294885fafSGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
39394885fafSGabriel FERNANDEZ 	void __iomem *reg;
39494885fafSGabriel FERNANDEZ 	const char **parents;
39594885fafSGabriel FERNANDEZ 	int num_parents = 0, i;
39694885fafSGabriel FERNANDEZ 
39794885fafSGabriel FERNANDEZ 	match = of_match_node(clkgena_divmux_of_match, np);
39894885fafSGabriel FERNANDEZ 	if (WARN_ON(!match))
39994885fafSGabriel FERNANDEZ 		return;
40094885fafSGabriel FERNANDEZ 
40194885fafSGabriel FERNANDEZ 	data = (struct clkgena_divmux_data *)match->data;
40294885fafSGabriel FERNANDEZ 
40394885fafSGabriel FERNANDEZ 	reg = clkgen_get_register_base(np);
40494885fafSGabriel FERNANDEZ 	if (!reg)
40594885fafSGabriel FERNANDEZ 		return;
40694885fafSGabriel FERNANDEZ 
40794885fafSGabriel FERNANDEZ 	parents = clkgen_mux_get_parents(np, &num_parents);
40894885fafSGabriel FERNANDEZ 	if (IS_ERR(parents))
40994885fafSGabriel FERNANDEZ 		return;
41094885fafSGabriel FERNANDEZ 
41194885fafSGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
41294885fafSGabriel FERNANDEZ 	if (!clk_data)
41394885fafSGabriel FERNANDEZ 		goto err;
41494885fafSGabriel FERNANDEZ 
41594885fafSGabriel FERNANDEZ 	clk_data->clk_num = data->num_outputs;
41694885fafSGabriel FERNANDEZ 	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
41794885fafSGabriel FERNANDEZ 				 GFP_KERNEL);
41894885fafSGabriel FERNANDEZ 
41994885fafSGabriel FERNANDEZ 	if (!clk_data->clks)
42094885fafSGabriel FERNANDEZ 		goto err;
42194885fafSGabriel FERNANDEZ 
42294885fafSGabriel FERNANDEZ 	for (i = 0; i < clk_data->clk_num; i++) {
42394885fafSGabriel FERNANDEZ 		struct clk *clk;
42494885fafSGabriel FERNANDEZ 		const char *clk_name;
42594885fafSGabriel FERNANDEZ 
42694885fafSGabriel FERNANDEZ 		if (of_property_read_string_index(np, "clock-output-names",
42794885fafSGabriel FERNANDEZ 						  i, &clk_name))
42894885fafSGabriel FERNANDEZ 			break;
42994885fafSGabriel FERNANDEZ 
43094885fafSGabriel FERNANDEZ 		/*
43194885fafSGabriel FERNANDEZ 		 * If we read an empty clock name then the output is unused
43294885fafSGabriel FERNANDEZ 		 */
43394885fafSGabriel FERNANDEZ 		if (*clk_name == '\0')
43494885fafSGabriel FERNANDEZ 			continue;
43594885fafSGabriel FERNANDEZ 
43694885fafSGabriel FERNANDEZ 		clk = clk_register_genamux(clk_name, parents, num_parents,
43794885fafSGabriel FERNANDEZ 					   reg, data, i);
43894885fafSGabriel FERNANDEZ 
43994885fafSGabriel FERNANDEZ 		if (IS_ERR(clk))
44094885fafSGabriel FERNANDEZ 			goto err;
44194885fafSGabriel FERNANDEZ 
44294885fafSGabriel FERNANDEZ 		clk_data->clks[i] = clk;
44394885fafSGabriel FERNANDEZ 	}
44494885fafSGabriel FERNANDEZ 
44594885fafSGabriel FERNANDEZ 	kfree(parents);
44694885fafSGabriel FERNANDEZ 
44794885fafSGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
44894885fafSGabriel FERNANDEZ 	return;
44994885fafSGabriel FERNANDEZ err:
45094885fafSGabriel FERNANDEZ 	if (clk_data)
45194885fafSGabriel FERNANDEZ 		kfree(clk_data->clks);
45294885fafSGabriel FERNANDEZ 
45394885fafSGabriel FERNANDEZ 	kfree(clk_data);
45494885fafSGabriel FERNANDEZ 	kfree(parents);
45594885fafSGabriel FERNANDEZ }
45694885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup);
45794885fafSGabriel FERNANDEZ 
45894885fafSGabriel FERNANDEZ struct clkgena_prediv_data {
45994885fafSGabriel FERNANDEZ 	u32 offset;
46094885fafSGabriel FERNANDEZ 	u8 shift;
46194885fafSGabriel FERNANDEZ 	struct clk_div_table *table;
46294885fafSGabriel FERNANDEZ };
46394885fafSGabriel FERNANDEZ 
46494885fafSGabriel FERNANDEZ static struct clk_div_table prediv_table16[] = {
46594885fafSGabriel FERNANDEZ 	{ .val = 0, .div = 1 },
46694885fafSGabriel FERNANDEZ 	{ .val = 1, .div = 16 },
46794885fafSGabriel FERNANDEZ 	{ .div = 0 },
46894885fafSGabriel FERNANDEZ };
46994885fafSGabriel FERNANDEZ 
47094885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c65_data = {
47194885fafSGabriel FERNANDEZ 	.offset = 0x4c,
47294885fafSGabriel FERNANDEZ 	.shift = 31,
47394885fafSGabriel FERNANDEZ 	.table = prediv_table16,
47494885fafSGabriel FERNANDEZ };
47594885fafSGabriel FERNANDEZ 
47694885fafSGabriel FERNANDEZ static struct clkgena_prediv_data prediv_c32_data = {
47794885fafSGabriel FERNANDEZ 	.offset = 0x50,
47894885fafSGabriel FERNANDEZ 	.shift = 1,
47994885fafSGabriel FERNANDEZ 	.table = prediv_table16,
48094885fafSGabriel FERNANDEZ };
48194885fafSGabriel FERNANDEZ 
48294885fafSGabriel FERNANDEZ static struct of_device_id clkgena_prediv_of_match[] = {
48394885fafSGabriel FERNANDEZ 	{ .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data },
48494885fafSGabriel FERNANDEZ 	{ .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data },
48594885fafSGabriel FERNANDEZ 	{}
48694885fafSGabriel FERNANDEZ };
48794885fafSGabriel FERNANDEZ 
48894885fafSGabriel FERNANDEZ void __init st_of_clkgena_prediv_setup(struct device_node *np)
48994885fafSGabriel FERNANDEZ {
49094885fafSGabriel FERNANDEZ 	const struct of_device_id *match;
49194885fafSGabriel FERNANDEZ 	void __iomem *reg;
49294885fafSGabriel FERNANDEZ 	const char *parent_name, *clk_name;
49394885fafSGabriel FERNANDEZ 	struct clk *clk;
49494885fafSGabriel FERNANDEZ 	struct clkgena_prediv_data *data;
49594885fafSGabriel FERNANDEZ 
49694885fafSGabriel FERNANDEZ 	match = of_match_node(clkgena_prediv_of_match, np);
49794885fafSGabriel FERNANDEZ 	if (!match) {
49894885fafSGabriel FERNANDEZ 		pr_err("%s: No matching data\n", __func__);
49994885fafSGabriel FERNANDEZ 		return;
50094885fafSGabriel FERNANDEZ 	}
50194885fafSGabriel FERNANDEZ 
50294885fafSGabriel FERNANDEZ 	data = (struct clkgena_prediv_data *)match->data;
50394885fafSGabriel FERNANDEZ 
50494885fafSGabriel FERNANDEZ 	reg = clkgen_get_register_base(np);
50594885fafSGabriel FERNANDEZ 	if (!reg)
50694885fafSGabriel FERNANDEZ 		return;
50794885fafSGabriel FERNANDEZ 
50894885fafSGabriel FERNANDEZ 	parent_name = of_clk_get_parent_name(np, 0);
50994885fafSGabriel FERNANDEZ 	if (!parent_name)
51094885fafSGabriel FERNANDEZ 		return;
51194885fafSGabriel FERNANDEZ 
51294885fafSGabriel FERNANDEZ 	if (of_property_read_string_index(np, "clock-output-names",
51394885fafSGabriel FERNANDEZ 					  0, &clk_name))
51494885fafSGabriel FERNANDEZ 		return;
51594885fafSGabriel FERNANDEZ 
51694885fafSGabriel FERNANDEZ 	clk = clk_register_divider_table(NULL, clk_name, parent_name, 0,
51794885fafSGabriel FERNANDEZ 					 reg + data->offset, data->shift, 1,
51894885fafSGabriel FERNANDEZ 					 0, data->table, NULL);
51994885fafSGabriel FERNANDEZ 	if (IS_ERR(clk))
52094885fafSGabriel FERNANDEZ 		return;
52194885fafSGabriel FERNANDEZ 
52294885fafSGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
52394885fafSGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %u\n",
52494885fafSGabriel FERNANDEZ 		__clk_get_name(clk),
52594885fafSGabriel FERNANDEZ 		__clk_get_name(clk_get_parent(clk)),
52694885fafSGabriel FERNANDEZ 		(unsigned int)clk_get_rate(clk));
52794885fafSGabriel FERNANDEZ 
52894885fafSGabriel FERNANDEZ 	return;
52994885fafSGabriel FERNANDEZ }
53094885fafSGabriel FERNANDEZ CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup);
531*44993d38SGabriel FERNANDEZ 
532*44993d38SGabriel FERNANDEZ struct clkgen_mux_data {
533*44993d38SGabriel FERNANDEZ 	u32 offset;
534*44993d38SGabriel FERNANDEZ 	u8 shift;
535*44993d38SGabriel FERNANDEZ 	u8 width;
536*44993d38SGabriel FERNANDEZ 	spinlock_t *lock;
537*44993d38SGabriel FERNANDEZ 	unsigned long clk_flags;
538*44993d38SGabriel FERNANDEZ 	u8 mux_flags;
539*44993d38SGabriel FERNANDEZ };
540*44993d38SGabriel FERNANDEZ 
541*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_c_vcc_hd_416 = {
542*44993d38SGabriel FERNANDEZ 	.offset = 0,
543*44993d38SGabriel FERNANDEZ 	.shift = 0,
544*44993d38SGabriel FERNANDEZ 	.width = 1,
545*44993d38SGabriel FERNANDEZ };
546*44993d38SGabriel FERNANDEZ 
547*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_fvdp_416 = {
548*44993d38SGabriel FERNANDEZ 	.offset = 0,
549*44993d38SGabriel FERNANDEZ 	.shift = 0,
550*44993d38SGabriel FERNANDEZ 	.width = 1,
551*44993d38SGabriel FERNANDEZ };
552*44993d38SGabriel FERNANDEZ 
553*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_hva_416 = {
554*44993d38SGabriel FERNANDEZ 	.offset = 0,
555*44993d38SGabriel FERNANDEZ 	.shift = 0,
556*44993d38SGabriel FERNANDEZ 	.width = 1,
557*44993d38SGabriel FERNANDEZ };
558*44993d38SGabriel FERNANDEZ 
559*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_f_vcc_hd_416 = {
560*44993d38SGabriel FERNANDEZ 	.offset = 0,
561*44993d38SGabriel FERNANDEZ 	.shift = 16,
562*44993d38SGabriel FERNANDEZ 	.width = 1,
563*44993d38SGabriel FERNANDEZ 	.lock = &clkgenf_lock,
564*44993d38SGabriel FERNANDEZ };
565*44993d38SGabriel FERNANDEZ 
566*44993d38SGabriel FERNANDEZ static struct clkgen_mux_data clkgen_mux_c_vcc_sd_416 = {
567*44993d38SGabriel FERNANDEZ 	.offset = 0,
568*44993d38SGabriel FERNANDEZ 	.shift = 17,
569*44993d38SGabriel FERNANDEZ 	.width = 1,
570*44993d38SGabriel FERNANDEZ 	.lock = &clkgenf_lock,
571*44993d38SGabriel FERNANDEZ };
572*44993d38SGabriel FERNANDEZ 
573*44993d38SGabriel FERNANDEZ static struct of_device_id mux_of_match[] = {
574*44993d38SGabriel FERNANDEZ 	{
575*44993d38SGabriel FERNANDEZ 		.compatible = "st,stih416-clkgenc-vcc-hd",
576*44993d38SGabriel FERNANDEZ 		.data = &clkgen_mux_c_vcc_hd_416,
577*44993d38SGabriel FERNANDEZ 	},
578*44993d38SGabriel FERNANDEZ 	{
579*44993d38SGabriel FERNANDEZ 		.compatible = "st,stih416-clkgenf-vcc-fvdp",
580*44993d38SGabriel FERNANDEZ 		.data = &clkgen_mux_f_vcc_fvdp_416,
581*44993d38SGabriel FERNANDEZ 	},
582*44993d38SGabriel FERNANDEZ 	{
583*44993d38SGabriel FERNANDEZ 		.compatible = "st,stih416-clkgenf-vcc-hva",
584*44993d38SGabriel FERNANDEZ 		.data = &clkgen_mux_f_vcc_hva_416,
585*44993d38SGabriel FERNANDEZ 	},
586*44993d38SGabriel FERNANDEZ 	{
587*44993d38SGabriel FERNANDEZ 		.compatible = "st,stih416-clkgenf-vcc-hd",
588*44993d38SGabriel FERNANDEZ 		.data = &clkgen_mux_f_vcc_hd_416,
589*44993d38SGabriel FERNANDEZ 	},
590*44993d38SGabriel FERNANDEZ 	{
591*44993d38SGabriel FERNANDEZ 		.compatible = "st,stih416-clkgenf-vcc-sd",
592*44993d38SGabriel FERNANDEZ 		.data = &clkgen_mux_c_vcc_sd_416,
593*44993d38SGabriel FERNANDEZ 	},
594*44993d38SGabriel FERNANDEZ 	{}
595*44993d38SGabriel FERNANDEZ };
596*44993d38SGabriel FERNANDEZ 
597*44993d38SGabriel FERNANDEZ void __init st_of_clkgen_mux_setup(struct device_node *np)
598*44993d38SGabriel FERNANDEZ {
599*44993d38SGabriel FERNANDEZ 	const struct of_device_id *match;
600*44993d38SGabriel FERNANDEZ 	struct clk *clk;
601*44993d38SGabriel FERNANDEZ 	void __iomem *reg;
602*44993d38SGabriel FERNANDEZ 	const char **parents;
603*44993d38SGabriel FERNANDEZ 	int num_parents;
604*44993d38SGabriel FERNANDEZ 	struct clkgen_mux_data *data;
605*44993d38SGabriel FERNANDEZ 
606*44993d38SGabriel FERNANDEZ 	match = of_match_node(mux_of_match, np);
607*44993d38SGabriel FERNANDEZ 	if (!match) {
608*44993d38SGabriel FERNANDEZ 		pr_err("%s: No matching data\n", __func__);
609*44993d38SGabriel FERNANDEZ 		return;
610*44993d38SGabriel FERNANDEZ 	}
611*44993d38SGabriel FERNANDEZ 
612*44993d38SGabriel FERNANDEZ 	data = (struct clkgen_mux_data *)match->data;
613*44993d38SGabriel FERNANDEZ 
614*44993d38SGabriel FERNANDEZ 	reg = of_iomap(np, 0);
615*44993d38SGabriel FERNANDEZ 	if (!reg) {
616*44993d38SGabriel FERNANDEZ 		pr_err("%s: Failed to get base address\n", __func__);
617*44993d38SGabriel FERNANDEZ 		return;
618*44993d38SGabriel FERNANDEZ 	}
619*44993d38SGabriel FERNANDEZ 
620*44993d38SGabriel FERNANDEZ 	parents = clkgen_mux_get_parents(np, &num_parents);
621*44993d38SGabriel FERNANDEZ 	if (IS_ERR(parents)) {
622*44993d38SGabriel FERNANDEZ 		pr_err("%s: Failed to get parents (%ld)\n",
623*44993d38SGabriel FERNANDEZ 				__func__, PTR_ERR(parents));
624*44993d38SGabriel FERNANDEZ 		return;
625*44993d38SGabriel FERNANDEZ 	}
626*44993d38SGabriel FERNANDEZ 
627*44993d38SGabriel FERNANDEZ 	clk = clk_register_mux(NULL, np->name, parents, num_parents,
628*44993d38SGabriel FERNANDEZ 				data->clk_flags | CLK_SET_RATE_PARENT,
629*44993d38SGabriel FERNANDEZ 				reg + data->offset,
630*44993d38SGabriel FERNANDEZ 				data->shift, data->width, data->mux_flags,
631*44993d38SGabriel FERNANDEZ 				data->lock);
632*44993d38SGabriel FERNANDEZ 	if (IS_ERR(clk))
633*44993d38SGabriel FERNANDEZ 		goto err;
634*44993d38SGabriel FERNANDEZ 
635*44993d38SGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %u\n",
636*44993d38SGabriel FERNANDEZ 			__clk_get_name(clk),
637*44993d38SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
638*44993d38SGabriel FERNANDEZ 			(unsigned int)clk_get_rate(clk));
639*44993d38SGabriel FERNANDEZ 
640*44993d38SGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
641*44993d38SGabriel FERNANDEZ 
642*44993d38SGabriel FERNANDEZ err:
643*44993d38SGabriel FERNANDEZ 	kfree(parents);
644*44993d38SGabriel FERNANDEZ 
645*44993d38SGabriel FERNANDEZ 	return;
646*44993d38SGabriel FERNANDEZ }
647*44993d38SGabriel FERNANDEZ CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup);
648*44993d38SGabriel FERNANDEZ 
649*44993d38SGabriel FERNANDEZ #define VCC_MAX_CHANNELS 16
650*44993d38SGabriel FERNANDEZ 
651*44993d38SGabriel FERNANDEZ #define VCC_GATE_OFFSET 0x0
652*44993d38SGabriel FERNANDEZ #define VCC_MUX_OFFSET 0x4
653*44993d38SGabriel FERNANDEZ #define VCC_DIV_OFFSET 0x8
654*44993d38SGabriel FERNANDEZ 
655*44993d38SGabriel FERNANDEZ struct clkgen_vcc_data {
656*44993d38SGabriel FERNANDEZ 	spinlock_t *lock;
657*44993d38SGabriel FERNANDEZ 	unsigned long clk_flags;
658*44993d38SGabriel FERNANDEZ };
659*44993d38SGabriel FERNANDEZ 
660*44993d38SGabriel FERNANDEZ static struct clkgen_vcc_data st_clkgenc_vcc_416 = {
661*44993d38SGabriel FERNANDEZ 	.clk_flags = CLK_SET_RATE_PARENT,
662*44993d38SGabriel FERNANDEZ };
663*44993d38SGabriel FERNANDEZ 
664*44993d38SGabriel FERNANDEZ static struct clkgen_vcc_data st_clkgenf_vcc_416 = {
665*44993d38SGabriel FERNANDEZ 	.lock = &clkgenf_lock,
666*44993d38SGabriel FERNANDEZ };
667*44993d38SGabriel FERNANDEZ 
668*44993d38SGabriel FERNANDEZ static struct of_device_id vcc_of_match[] = {
669*44993d38SGabriel FERNANDEZ 	{ .compatible = "st,stih416-clkgenc", .data = &st_clkgenc_vcc_416 },
670*44993d38SGabriel FERNANDEZ 	{ .compatible = "st,stih416-clkgenf", .data = &st_clkgenf_vcc_416 },
671*44993d38SGabriel FERNANDEZ 	{}
672*44993d38SGabriel FERNANDEZ };
673*44993d38SGabriel FERNANDEZ 
674*44993d38SGabriel FERNANDEZ void __init st_of_clkgen_vcc_setup(struct device_node *np)
675*44993d38SGabriel FERNANDEZ {
676*44993d38SGabriel FERNANDEZ 	const struct of_device_id *match;
677*44993d38SGabriel FERNANDEZ 	void __iomem *reg;
678*44993d38SGabriel FERNANDEZ 	const char **parents;
679*44993d38SGabriel FERNANDEZ 	int num_parents, i;
680*44993d38SGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
681*44993d38SGabriel FERNANDEZ 	struct clkgen_vcc_data *data;
682*44993d38SGabriel FERNANDEZ 
683*44993d38SGabriel FERNANDEZ 	match = of_match_node(vcc_of_match, np);
684*44993d38SGabriel FERNANDEZ 	if (WARN_ON(!match))
685*44993d38SGabriel FERNANDEZ 		return;
686*44993d38SGabriel FERNANDEZ 	data = (struct clkgen_vcc_data *)match->data;
687*44993d38SGabriel FERNANDEZ 
688*44993d38SGabriel FERNANDEZ 	reg = of_iomap(np, 0);
689*44993d38SGabriel FERNANDEZ 	if (!reg)
690*44993d38SGabriel FERNANDEZ 		return;
691*44993d38SGabriel FERNANDEZ 
692*44993d38SGabriel FERNANDEZ 	parents = clkgen_mux_get_parents(np, &num_parents);
693*44993d38SGabriel FERNANDEZ 	if (IS_ERR(parents))
694*44993d38SGabriel FERNANDEZ 		return;
695*44993d38SGabriel FERNANDEZ 
696*44993d38SGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
697*44993d38SGabriel FERNANDEZ 	if (!clk_data)
698*44993d38SGabriel FERNANDEZ 		goto err;
699*44993d38SGabriel FERNANDEZ 
700*44993d38SGabriel FERNANDEZ 	clk_data->clk_num = VCC_MAX_CHANNELS;
701*44993d38SGabriel FERNANDEZ 	clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *),
702*44993d38SGabriel FERNANDEZ 				 GFP_KERNEL);
703*44993d38SGabriel FERNANDEZ 
704*44993d38SGabriel FERNANDEZ 	if (!clk_data->clks)
705*44993d38SGabriel FERNANDEZ 		goto err;
706*44993d38SGabriel FERNANDEZ 
707*44993d38SGabriel FERNANDEZ 	for (i = 0; i < clk_data->clk_num; i++) {
708*44993d38SGabriel FERNANDEZ 		struct clk *clk;
709*44993d38SGabriel FERNANDEZ 		const char *clk_name;
710*44993d38SGabriel FERNANDEZ 		struct clk_gate *gate;
711*44993d38SGabriel FERNANDEZ 		struct clk_divider *div;
712*44993d38SGabriel FERNANDEZ 		struct clk_mux *mux;
713*44993d38SGabriel FERNANDEZ 
714*44993d38SGabriel FERNANDEZ 		if (of_property_read_string_index(np, "clock-output-names",
715*44993d38SGabriel FERNANDEZ 						  i, &clk_name))
716*44993d38SGabriel FERNANDEZ 			break;
717*44993d38SGabriel FERNANDEZ 
718*44993d38SGabriel FERNANDEZ 		/*
719*44993d38SGabriel FERNANDEZ 		 * If we read an empty clock name then the output is unused
720*44993d38SGabriel FERNANDEZ 		 */
721*44993d38SGabriel FERNANDEZ 		if (*clk_name == '\0')
722*44993d38SGabriel FERNANDEZ 			continue;
723*44993d38SGabriel FERNANDEZ 
724*44993d38SGabriel FERNANDEZ 		gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
725*44993d38SGabriel FERNANDEZ 		if (!gate)
726*44993d38SGabriel FERNANDEZ 			break;
727*44993d38SGabriel FERNANDEZ 
728*44993d38SGabriel FERNANDEZ 		div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
729*44993d38SGabriel FERNANDEZ 		if (!div) {
730*44993d38SGabriel FERNANDEZ 			kfree(gate);
731*44993d38SGabriel FERNANDEZ 			break;
732*44993d38SGabriel FERNANDEZ 		}
733*44993d38SGabriel FERNANDEZ 
734*44993d38SGabriel FERNANDEZ 		mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
735*44993d38SGabriel FERNANDEZ 		if (!mux) {
736*44993d38SGabriel FERNANDEZ 			kfree(gate);
737*44993d38SGabriel FERNANDEZ 			kfree(div);
738*44993d38SGabriel FERNANDEZ 			break;
739*44993d38SGabriel FERNANDEZ 		}
740*44993d38SGabriel FERNANDEZ 
741*44993d38SGabriel FERNANDEZ 		gate->reg = reg + VCC_GATE_OFFSET;
742*44993d38SGabriel FERNANDEZ 		gate->bit_idx = i;
743*44993d38SGabriel FERNANDEZ 		gate->flags = CLK_GATE_SET_TO_DISABLE;
744*44993d38SGabriel FERNANDEZ 		gate->lock = data->lock;
745*44993d38SGabriel FERNANDEZ 
746*44993d38SGabriel FERNANDEZ 		div->reg = reg + VCC_DIV_OFFSET;
747*44993d38SGabriel FERNANDEZ 		div->shift = 2 * i;
748*44993d38SGabriel FERNANDEZ 		div->width = 2;
749*44993d38SGabriel FERNANDEZ 		div->flags = CLK_DIVIDER_POWER_OF_TWO;
750*44993d38SGabriel FERNANDEZ 
751*44993d38SGabriel FERNANDEZ 		mux->reg = reg + VCC_MUX_OFFSET;
752*44993d38SGabriel FERNANDEZ 		mux->shift = 2 * i;
753*44993d38SGabriel FERNANDEZ 		mux->mask = 0x3;
754*44993d38SGabriel FERNANDEZ 
755*44993d38SGabriel FERNANDEZ 		clk = clk_register_composite(NULL, clk_name, parents,
756*44993d38SGabriel FERNANDEZ 					     num_parents,
757*44993d38SGabriel FERNANDEZ 					     &mux->hw, &clk_mux_ops,
758*44993d38SGabriel FERNANDEZ 					     &div->hw, &clk_divider_ops,
759*44993d38SGabriel FERNANDEZ 					     &gate->hw, &clk_gate_ops,
760*44993d38SGabriel FERNANDEZ 					     data->clk_flags);
761*44993d38SGabriel FERNANDEZ 		if (IS_ERR(clk)) {
762*44993d38SGabriel FERNANDEZ 			kfree(gate);
763*44993d38SGabriel FERNANDEZ 			kfree(div);
764*44993d38SGabriel FERNANDEZ 			kfree(mux);
765*44993d38SGabriel FERNANDEZ 			goto err;
766*44993d38SGabriel FERNANDEZ 		}
767*44993d38SGabriel FERNANDEZ 
768*44993d38SGabriel FERNANDEZ 		pr_debug("%s: parent %s rate %u\n",
769*44993d38SGabriel FERNANDEZ 			__clk_get_name(clk),
770*44993d38SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
771*44993d38SGabriel FERNANDEZ 			(unsigned int)clk_get_rate(clk));
772*44993d38SGabriel FERNANDEZ 
773*44993d38SGabriel FERNANDEZ 		clk_data->clks[i] = clk;
774*44993d38SGabriel FERNANDEZ 	}
775*44993d38SGabriel FERNANDEZ 
776*44993d38SGabriel FERNANDEZ 	kfree(parents);
777*44993d38SGabriel FERNANDEZ 
778*44993d38SGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
779*44993d38SGabriel FERNANDEZ 	return;
780*44993d38SGabriel FERNANDEZ 
781*44993d38SGabriel FERNANDEZ err:
782*44993d38SGabriel FERNANDEZ 	for (i = 0; i < clk_data->clk_num; i++) {
783*44993d38SGabriel FERNANDEZ 		struct clk_composite *composite;
784*44993d38SGabriel FERNANDEZ 
785*44993d38SGabriel FERNANDEZ 		if (!clk_data->clks[i])
786*44993d38SGabriel FERNANDEZ 			continue;
787*44993d38SGabriel FERNANDEZ 
788*44993d38SGabriel FERNANDEZ 		composite = container_of(__clk_get_hw(clk_data->clks[i]),
789*44993d38SGabriel FERNANDEZ 					 struct clk_composite, hw);
790*44993d38SGabriel FERNANDEZ 		kfree(container_of(composite->gate_hw, struct clk_gate, hw));
791*44993d38SGabriel FERNANDEZ 		kfree(container_of(composite->rate_hw, struct clk_divider, hw));
792*44993d38SGabriel FERNANDEZ 		kfree(container_of(composite->mux_hw, struct clk_mux, hw));
793*44993d38SGabriel FERNANDEZ 	}
794*44993d38SGabriel FERNANDEZ 
795*44993d38SGabriel FERNANDEZ 	if (clk_data)
796*44993d38SGabriel FERNANDEZ 		kfree(clk_data->clks);
797*44993d38SGabriel FERNANDEZ 
798*44993d38SGabriel FERNANDEZ 	kfree(clk_data);
799*44993d38SGabriel FERNANDEZ 	kfree(parents);
800*44993d38SGabriel FERNANDEZ }
801*44993d38SGabriel FERNANDEZ CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup);
802