xref: /openbmc/linux/drivers/clk/st/clkgen-pll.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b9b8e614SGabriel FERNANDEZ /*
3b9b8e614SGabriel FERNANDEZ  * Copyright (C) 2014 STMicroelectronics (R&D) Limited
4b9b8e614SGabriel FERNANDEZ  */
5b9b8e614SGabriel FERNANDEZ 
6b9b8e614SGabriel FERNANDEZ /*
7b9b8e614SGabriel FERNANDEZ  * Authors:
8b9b8e614SGabriel FERNANDEZ  * Stephen Gallimore <stephen.gallimore@st.com>,
9b9b8e614SGabriel FERNANDEZ  * Pankaj Dev <pankaj.dev@st.com>.
10b9b8e614SGabriel FERNANDEZ  */
11b9b8e614SGabriel FERNANDEZ 
12b9b8e614SGabriel FERNANDEZ #include <linux/slab.h>
13b9b8e614SGabriel FERNANDEZ #include <linux/of_address.h>
14d5f728acSStephen Boyd #include <linux/clk.h>
15b9b8e614SGabriel FERNANDEZ #include <linux/clk-provider.h>
16fb473862SGabriel Fernandez #include <linux/iopoll.h>
17b9b8e614SGabriel FERNANDEZ 
18b9b8e614SGabriel FERNANDEZ #include "clkgen.h"
19b9b8e614SGabriel FERNANDEZ 
20b9b8e614SGabriel FERNANDEZ static DEFINE_SPINLOCK(clkgena_c32_odf_lock);
2146a57afdSGabriel Fernandez DEFINE_SPINLOCK(clkgen_a9_lock);
22b9b8e614SGabriel FERNANDEZ 
23b9b8e614SGabriel FERNANDEZ /*
24b9b8e614SGabriel FERNANDEZ  * PLL configuration register bits for PLL3200 C32
25b9b8e614SGabriel FERNANDEZ  */
26b9b8e614SGabriel FERNANDEZ #define C32_NDIV_MASK (0xff)
27b9b8e614SGabriel FERNANDEZ #define C32_IDF_MASK (0x7)
28b9b8e614SGabriel FERNANDEZ #define C32_ODF_MASK (0x3f)
29b9b8e614SGabriel FERNANDEZ #define C32_LDF_MASK (0x7f)
3046a57afdSGabriel Fernandez #define C32_CP_MASK (0x1f)
31b9b8e614SGabriel FERNANDEZ 
32b9b8e614SGabriel FERNANDEZ #define C32_MAX_ODFS (4)
33b9b8e614SGabriel FERNANDEZ 
340829ea5aSGabriel Fernandez /*
350829ea5aSGabriel Fernandez  * PLL configuration register bits for PLL4600 C28
360829ea5aSGabriel Fernandez  */
370829ea5aSGabriel Fernandez #define C28_NDIV_MASK (0xff)
380829ea5aSGabriel Fernandez #define C28_IDF_MASK (0x7)
390829ea5aSGabriel Fernandez #define C28_ODF_MASK (0x3f)
400829ea5aSGabriel Fernandez 
41b9b8e614SGabriel FERNANDEZ struct clkgen_pll_data {
42b9b8e614SGabriel FERNANDEZ 	struct clkgen_field pdn_status;
43fb473862SGabriel Fernandez 	struct clkgen_field pdn_ctrl;
44b9b8e614SGabriel FERNANDEZ 	struct clkgen_field locked_status;
45b9b8e614SGabriel FERNANDEZ 	struct clkgen_field mdiv;
46b9b8e614SGabriel FERNANDEZ 	struct clkgen_field ndiv;
47b9b8e614SGabriel FERNANDEZ 	struct clkgen_field pdiv;
48b9b8e614SGabriel FERNANDEZ 	struct clkgen_field idf;
49b9b8e614SGabriel FERNANDEZ 	struct clkgen_field ldf;
5046a57afdSGabriel Fernandez 	struct clkgen_field cp;
51b9b8e614SGabriel FERNANDEZ 	unsigned int num_odfs;
52b9b8e614SGabriel FERNANDEZ 	struct clkgen_field odf[C32_MAX_ODFS];
53b9b8e614SGabriel FERNANDEZ 	struct clkgen_field odf_gate[C32_MAX_ODFS];
5446a57afdSGabriel Fernandez 	bool switch2pll_en;
5546a57afdSGabriel Fernandez 	struct clkgen_field switch2pll;
5646a57afdSGabriel Fernandez 	spinlock_t *lock;
57b9b8e614SGabriel FERNANDEZ 	const struct clk_ops *ops;
58b9b8e614SGabriel FERNANDEZ };
59b9b8e614SGabriel FERNANDEZ 
60*92ef1b2bSAlain Volmat struct clkgen_clk_out {
61*92ef1b2bSAlain Volmat 	const char *name;
62*92ef1b2bSAlain Volmat 	unsigned long flags;
63*92ef1b2bSAlain Volmat };
64*92ef1b2bSAlain Volmat 
65*92ef1b2bSAlain Volmat struct clkgen_pll_data_clks {
66*92ef1b2bSAlain Volmat 	struct clkgen_pll_data *data;
67*92ef1b2bSAlain Volmat 	const struct clkgen_clk_out *outputs;
68*92ef1b2bSAlain Volmat };
69*92ef1b2bSAlain Volmat 
70*92ef1b2bSAlain Volmat 
71b9b8e614SGabriel FERNANDEZ static const struct clk_ops stm_pll3200c32_ops;
7246a57afdSGabriel Fernandez static const struct clk_ops stm_pll3200c32_a9_ops;
730829ea5aSGabriel Fernandez static const struct clk_ops stm_pll4600c28_ops;
74b9b8e614SGabriel FERNANDEZ 
75d34e210eSGabriel Fernandez static const struct clkgen_pll_data st_pll3200c32_cx_0 = {
7651306d56SGabriel FERNANDEZ 	/* 407 C0 PLL0 */
7751306d56SGabriel FERNANDEZ 	.pdn_status	= CLKGEN_FIELD(0x2a0,	0x1,			8),
78fb473862SGabriel Fernandez 	.pdn_ctrl	= CLKGEN_FIELD(0x2a0,	0x1,			8),
7951306d56SGabriel FERNANDEZ 	.locked_status	= CLKGEN_FIELD(0x2a0,	0x1,			24),
8051306d56SGabriel FERNANDEZ 	.ndiv		= CLKGEN_FIELD(0x2a4,	C32_NDIV_MASK,		16),
8151306d56SGabriel FERNANDEZ 	.idf		= CLKGEN_FIELD(0x2a4,	C32_IDF_MASK,		0x0),
8251306d56SGabriel FERNANDEZ 	.num_odfs = 1,
8351306d56SGabriel FERNANDEZ 	.odf		= { CLKGEN_FIELD(0x2b4, C32_ODF_MASK,		0) },
8451306d56SGabriel FERNANDEZ 	.odf_gate	= { CLKGEN_FIELD(0x2b4, 0x1,			6) },
8551306d56SGabriel FERNANDEZ 	.ops		= &stm_pll3200c32_ops,
8651306d56SGabriel FERNANDEZ };
8751306d56SGabriel FERNANDEZ 
88*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_cx_0_legacy_data = {
89*92ef1b2bSAlain Volmat 	.data	= (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
90*92ef1b2bSAlain Volmat };
91*92ef1b2bSAlain Volmat 
92*92ef1b2bSAlain Volmat static const struct clkgen_clk_out st_pll3200c32_ax_0_clks[] = {
93*92ef1b2bSAlain Volmat 	{ .name = "clk-s-a0-pll-odf-0", },
94*92ef1b2bSAlain Volmat };
95*92ef1b2bSAlain Volmat 
96*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_a0_data = {
97*92ef1b2bSAlain Volmat 	.data		= (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
98*92ef1b2bSAlain Volmat 	.outputs	= st_pll3200c32_ax_0_clks,
99*92ef1b2bSAlain Volmat };
100*92ef1b2bSAlain Volmat 
101*92ef1b2bSAlain Volmat static const struct clkgen_clk_out st_pll3200c32_cx_0_clks[] = {
102*92ef1b2bSAlain Volmat 	{ .name = "clk-s-c0-pll0-odf-0", },
103*92ef1b2bSAlain Volmat };
104*92ef1b2bSAlain Volmat 
105*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_c0_data = {
106*92ef1b2bSAlain Volmat 	.data		= (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
107*92ef1b2bSAlain Volmat 	.outputs	= st_pll3200c32_cx_0_clks,
108*92ef1b2bSAlain Volmat };
109*92ef1b2bSAlain Volmat 
110d34e210eSGabriel Fernandez static const struct clkgen_pll_data st_pll3200c32_cx_1 = {
11151306d56SGabriel FERNANDEZ 	/* 407 C0 PLL1 */
11251306d56SGabriel FERNANDEZ 	.pdn_status	= CLKGEN_FIELD(0x2c8,	0x1,			8),
113fb473862SGabriel Fernandez 	.pdn_ctrl	= CLKGEN_FIELD(0x2c8,	0x1,			8),
11451306d56SGabriel FERNANDEZ 	.locked_status	= CLKGEN_FIELD(0x2c8,	0x1,			24),
11551306d56SGabriel FERNANDEZ 	.ndiv		= CLKGEN_FIELD(0x2cc,	C32_NDIV_MASK,		16),
11651306d56SGabriel FERNANDEZ 	.idf		= CLKGEN_FIELD(0x2cc,	C32_IDF_MASK,		0x0),
11751306d56SGabriel FERNANDEZ 	.num_odfs = 1,
11851306d56SGabriel FERNANDEZ 	.odf		= { CLKGEN_FIELD(0x2dc, C32_ODF_MASK,		0) },
11951306d56SGabriel FERNANDEZ 	.odf_gate	= { CLKGEN_FIELD(0x2dc, 0x1,			6) },
12051306d56SGabriel FERNANDEZ 	.ops		= &stm_pll3200c32_ops,
12151306d56SGabriel FERNANDEZ };
12251306d56SGabriel FERNANDEZ 
123*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_cx_1_legacy_data = {
124*92ef1b2bSAlain Volmat 	.data	= (struct clkgen_pll_data *)&st_pll3200c32_cx_1,
125*92ef1b2bSAlain Volmat };
126*92ef1b2bSAlain Volmat 
127*92ef1b2bSAlain Volmat static const struct clkgen_clk_out st_pll3200c32_cx_1_clks[] = {
128*92ef1b2bSAlain Volmat 	{ .name = "clk-s-c0-pll1-odf-0", },
129*92ef1b2bSAlain Volmat };
130*92ef1b2bSAlain Volmat 
131*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_c1_data = {
132*92ef1b2bSAlain Volmat 	.data		= (struct clkgen_pll_data *)&st_pll3200c32_cx_1,
133*92ef1b2bSAlain Volmat 	.outputs	= st_pll3200c32_cx_1_clks,
134*92ef1b2bSAlain Volmat };
135*92ef1b2bSAlain Volmat 
136aaa65d77SGabriel FERNANDEZ static const struct clkgen_pll_data st_pll3200c32_407_a9 = {
137aaa65d77SGabriel FERNANDEZ 	/* 407 A9 */
138aaa65d77SGabriel FERNANDEZ 	.pdn_status	= CLKGEN_FIELD(0x1a8,	0x1,			0),
139fb473862SGabriel Fernandez 	.pdn_ctrl	= CLKGEN_FIELD(0x1a8,	0x1,			0),
140aaa65d77SGabriel FERNANDEZ 	.locked_status	= CLKGEN_FIELD(0x87c,	0x1,			0),
141aaa65d77SGabriel FERNANDEZ 	.ndiv		= CLKGEN_FIELD(0x1b0,	C32_NDIV_MASK,		0),
142aaa65d77SGabriel FERNANDEZ 	.idf		= CLKGEN_FIELD(0x1a8,	C32_IDF_MASK,		25),
143aaa65d77SGabriel FERNANDEZ 	.num_odfs = 1,
144aaa65d77SGabriel FERNANDEZ 	.odf		= { CLKGEN_FIELD(0x1b0, C32_ODF_MASK,		8) },
145aaa65d77SGabriel FERNANDEZ 	.odf_gate	= { CLKGEN_FIELD(0x1ac, 0x1,			28) },
14646a57afdSGabriel Fernandez 	.switch2pll_en	= true,
14746a57afdSGabriel Fernandez 	.cp		= CLKGEN_FIELD(0x1a8,	C32_CP_MASK,		1),
14846a57afdSGabriel Fernandez 	.switch2pll	= CLKGEN_FIELD(0x1a4,	0x1,			1),
14946a57afdSGabriel Fernandez 	.lock = &clkgen_a9_lock,
15046a57afdSGabriel Fernandez 	.ops		= &stm_pll3200c32_a9_ops,
151aaa65d77SGabriel FERNANDEZ };
152aaa65d77SGabriel FERNANDEZ 
153*92ef1b2bSAlain Volmat static const struct clkgen_clk_out st_pll3200c32_407_a9_clks[] = {
154*92ef1b2bSAlain Volmat 	{ .name = "clockgen-a9-pll-odf", },
155*92ef1b2bSAlain Volmat };
156*92ef1b2bSAlain Volmat 
157*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll3200c32_407_a9_data = {
158*92ef1b2bSAlain Volmat 	.data		= (struct clkgen_pll_data *)&st_pll3200c32_407_a9,
159*92ef1b2bSAlain Volmat 	.outputs	= st_pll3200c32_407_a9_clks,
160*92ef1b2bSAlain Volmat };
161*92ef1b2bSAlain Volmat 
1620829ea5aSGabriel Fernandez static struct clkgen_pll_data st_pll4600c28_418_a9 = {
1630829ea5aSGabriel Fernandez 	/* 418 A9 */
1640829ea5aSGabriel Fernandez 	.pdn_status	= CLKGEN_FIELD(0x1a8,	0x1,			0),
1650829ea5aSGabriel Fernandez 	.pdn_ctrl	= CLKGEN_FIELD(0x1a8,	0x1,			0),
1660829ea5aSGabriel Fernandez 	.locked_status	= CLKGEN_FIELD(0x87c,	0x1,			0),
1670829ea5aSGabriel Fernandez 	.ndiv		= CLKGEN_FIELD(0x1b0,	C28_NDIV_MASK,		0),
1680829ea5aSGabriel Fernandez 	.idf		= CLKGEN_FIELD(0x1a8,	C28_IDF_MASK,		25),
1690829ea5aSGabriel Fernandez 	.num_odfs = 1,
1700829ea5aSGabriel Fernandez 	.odf		= { CLKGEN_FIELD(0x1b0, C28_ODF_MASK,		8) },
1710829ea5aSGabriel Fernandez 	.odf_gate	= { CLKGEN_FIELD(0x1ac, 0x1,			28) },
1720829ea5aSGabriel Fernandez 	.switch2pll_en	= true,
1730829ea5aSGabriel Fernandez 	.switch2pll	= CLKGEN_FIELD(0x1a4,	0x1,			1),
1740829ea5aSGabriel Fernandez 	.lock		= &clkgen_a9_lock,
1750829ea5aSGabriel Fernandez 	.ops		= &stm_pll4600c28_ops,
1760829ea5aSGabriel Fernandez };
1770829ea5aSGabriel Fernandez 
178*92ef1b2bSAlain Volmat static const struct clkgen_clk_out st_pll4600c28_418_a9_clks[] = {
179*92ef1b2bSAlain Volmat 	{ .name = "clockgen-a9-pll-odf", },
180*92ef1b2bSAlain Volmat };
181*92ef1b2bSAlain Volmat 
182*92ef1b2bSAlain Volmat static const struct clkgen_pll_data_clks st_pll4600c28_418_a9_data = {
183*92ef1b2bSAlain Volmat 	.data		= (struct clkgen_pll_data *)&st_pll4600c28_418_a9,
184*92ef1b2bSAlain Volmat 	.outputs	= st_pll4600c28_418_a9_clks,
185*92ef1b2bSAlain Volmat };
186*92ef1b2bSAlain Volmat 
187b9b8e614SGabriel FERNANDEZ /**
188b9b8e614SGabriel FERNANDEZ  * DOC: Clock Generated by PLL, rate set and enabled by bootloader
189b9b8e614SGabriel FERNANDEZ  *
190b9b8e614SGabriel FERNANDEZ  * Traits of this clock:
191b9b8e614SGabriel FERNANDEZ  * prepare - clk_(un)prepare only ensures parent is (un)prepared
192b9b8e614SGabriel FERNANDEZ  * enable - clk_enable/disable only ensures parent is enabled
193b9b8e614SGabriel FERNANDEZ  * rate - rate is fixed. No clk_set_rate support
194b9b8e614SGabriel FERNANDEZ  * parent - fixed parent.  No clk_set_parent support
195b9b8e614SGabriel FERNANDEZ  */
196b9b8e614SGabriel FERNANDEZ 
197c1372617SLee Jones /*
198b9b8e614SGabriel FERNANDEZ  * PLL clock that is integrated in the ClockGenA instances on the STiH415
199b9b8e614SGabriel FERNANDEZ  * and STiH416.
200b9b8e614SGabriel FERNANDEZ  *
201b9b8e614SGabriel FERNANDEZ  * @hw: handle between common and hardware-specific interfaces.
202b9b8e614SGabriel FERNANDEZ  * @regs_base: base of the PLL configuration register(s).
203b9b8e614SGabriel FERNANDEZ  *
204b9b8e614SGabriel FERNANDEZ  */
205b9b8e614SGabriel FERNANDEZ struct clkgen_pll {
206b9b8e614SGabriel FERNANDEZ 	struct clk_hw		hw;
207b9b8e614SGabriel FERNANDEZ 	struct clkgen_pll_data	*data;
208b9b8e614SGabriel FERNANDEZ 	void __iomem		*regs_base;
20946a57afdSGabriel Fernandez 	spinlock_t	*lock;
21046a57afdSGabriel Fernandez 
21146a57afdSGabriel Fernandez 	u32 ndiv;
21246a57afdSGabriel Fernandez 	u32 idf;
21346a57afdSGabriel Fernandez 	u32 cp;
214b9b8e614SGabriel FERNANDEZ };
215b9b8e614SGabriel FERNANDEZ 
216b9b8e614SGabriel FERNANDEZ #define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw)
217b9b8e614SGabriel FERNANDEZ 
21846a57afdSGabriel Fernandez struct stm_pll {
21946a57afdSGabriel Fernandez 	unsigned long mdiv;
22046a57afdSGabriel Fernandez 	unsigned long ndiv;
22146a57afdSGabriel Fernandez 	unsigned long pdiv;
22246a57afdSGabriel Fernandez 	unsigned long odf;
22346a57afdSGabriel Fernandez 	unsigned long idf;
22446a57afdSGabriel Fernandez 	unsigned long ldf;
22546a57afdSGabriel Fernandez 	unsigned long cp;
22646a57afdSGabriel Fernandez };
22746a57afdSGabriel Fernandez 
clkgen_pll_is_locked(struct clk_hw * hw)228b9b8e614SGabriel FERNANDEZ static int clkgen_pll_is_locked(struct clk_hw *hw)
229b9b8e614SGabriel FERNANDEZ {
230b9b8e614SGabriel FERNANDEZ 	struct clkgen_pll *pll = to_clkgen_pll(hw);
231b9b8e614SGabriel FERNANDEZ 	u32 locked = CLKGEN_READ(pll, locked_status);
232b9b8e614SGabriel FERNANDEZ 
233b9b8e614SGabriel FERNANDEZ 	return !!locked;
234b9b8e614SGabriel FERNANDEZ }
235b9b8e614SGabriel FERNANDEZ 
clkgen_pll_is_enabled(struct clk_hw * hw)236b9b8e614SGabriel FERNANDEZ static int clkgen_pll_is_enabled(struct clk_hw *hw)
237b9b8e614SGabriel FERNANDEZ {
238b9b8e614SGabriel FERNANDEZ 	struct clkgen_pll *pll = to_clkgen_pll(hw);
239b9b8e614SGabriel FERNANDEZ 	u32 poweroff = CLKGEN_READ(pll, pdn_status);
240b9b8e614SGabriel FERNANDEZ 	return !poweroff;
241b9b8e614SGabriel FERNANDEZ }
242b9b8e614SGabriel FERNANDEZ 
__clkgen_pll_enable(struct clk_hw * hw)24346a57afdSGabriel Fernandez static int __clkgen_pll_enable(struct clk_hw *hw)
244fb473862SGabriel Fernandez {
245fb473862SGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
246fb473862SGabriel Fernandez 	void __iomem *base =  pll->regs_base;
247fb473862SGabriel Fernandez 	struct clkgen_field *field = &pll->data->locked_status;
248fb473862SGabriel Fernandez 	int ret = 0;
249fb473862SGabriel Fernandez 	u32 reg;
250fb473862SGabriel Fernandez 
251fb473862SGabriel Fernandez 	if (clkgen_pll_is_enabled(hw))
252fb473862SGabriel Fernandez 		return 0;
253fb473862SGabriel Fernandez 
254fb473862SGabriel Fernandez 	CLKGEN_WRITE(pll, pdn_ctrl, 0);
255fb473862SGabriel Fernandez 
256fb473862SGabriel Fernandez 	ret = readl_relaxed_poll_timeout(base + field->offset, reg,
257fb473862SGabriel Fernandez 			!!((reg >> field->shift) & field->mask),  0, 10000);
258fb473862SGabriel Fernandez 
25946a57afdSGabriel Fernandez 	if (!ret) {
26046a57afdSGabriel Fernandez 		if (pll->data->switch2pll_en)
26146a57afdSGabriel Fernandez 			CLKGEN_WRITE(pll, switch2pll, 0);
26246a57afdSGabriel Fernandez 
263fb473862SGabriel Fernandez 		pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__);
26446a57afdSGabriel Fernandez 	}
265fb473862SGabriel Fernandez 
266fb473862SGabriel Fernandez 	return ret;
267fb473862SGabriel Fernandez }
268fb473862SGabriel Fernandez 
clkgen_pll_enable(struct clk_hw * hw)26946a57afdSGabriel Fernandez static int clkgen_pll_enable(struct clk_hw *hw)
27046a57afdSGabriel Fernandez {
27146a57afdSGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
27246a57afdSGabriel Fernandez 	unsigned long flags = 0;
27346a57afdSGabriel Fernandez 	int ret = 0;
27446a57afdSGabriel Fernandez 
27546a57afdSGabriel Fernandez 	if (pll->lock)
27646a57afdSGabriel Fernandez 		spin_lock_irqsave(pll->lock, flags);
27746a57afdSGabriel Fernandez 
27846a57afdSGabriel Fernandez 	ret = __clkgen_pll_enable(hw);
27946a57afdSGabriel Fernandez 
28046a57afdSGabriel Fernandez 	if (pll->lock)
28146a57afdSGabriel Fernandez 		spin_unlock_irqrestore(pll->lock, flags);
28246a57afdSGabriel Fernandez 
28346a57afdSGabriel Fernandez 	return ret;
28446a57afdSGabriel Fernandez }
28546a57afdSGabriel Fernandez 
__clkgen_pll_disable(struct clk_hw * hw)28646a57afdSGabriel Fernandez static void __clkgen_pll_disable(struct clk_hw *hw)
287fb473862SGabriel Fernandez {
288fb473862SGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
289fb473862SGabriel Fernandez 
290fb473862SGabriel Fernandez 	if (!clkgen_pll_is_enabled(hw))
291fb473862SGabriel Fernandez 		return;
292fb473862SGabriel Fernandez 
29346a57afdSGabriel Fernandez 	if (pll->data->switch2pll_en)
29446a57afdSGabriel Fernandez 		CLKGEN_WRITE(pll, switch2pll, 1);
29546a57afdSGabriel Fernandez 
296fb473862SGabriel Fernandez 	CLKGEN_WRITE(pll, pdn_ctrl, 1);
297fb473862SGabriel Fernandez 
298fb473862SGabriel Fernandez 	pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__);
299fb473862SGabriel Fernandez }
300fb473862SGabriel Fernandez 
clkgen_pll_disable(struct clk_hw * hw)30146a57afdSGabriel Fernandez static void clkgen_pll_disable(struct clk_hw *hw)
30246a57afdSGabriel Fernandez {
30346a57afdSGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
30446a57afdSGabriel Fernandez 	unsigned long flags = 0;
30546a57afdSGabriel Fernandez 
30646a57afdSGabriel Fernandez 	if (pll->lock)
30746a57afdSGabriel Fernandez 		spin_lock_irqsave(pll->lock, flags);
30846a57afdSGabriel Fernandez 
30946a57afdSGabriel Fernandez 	__clkgen_pll_disable(hw);
31046a57afdSGabriel Fernandez 
31146a57afdSGabriel Fernandez 	if (pll->lock)
31246a57afdSGabriel Fernandez 		spin_unlock_irqrestore(pll->lock, flags);
31346a57afdSGabriel Fernandez }
31446a57afdSGabriel Fernandez 
clk_pll3200c32_get_params(unsigned long input,unsigned long output,struct stm_pll * pll)31546a57afdSGabriel Fernandez static int clk_pll3200c32_get_params(unsigned long input, unsigned long output,
31646a57afdSGabriel Fernandez 			  struct stm_pll *pll)
31746a57afdSGabriel Fernandez {
31846a57afdSGabriel Fernandez 	unsigned long i, n;
31946a57afdSGabriel Fernandez 	unsigned long deviation = ~0;
32046a57afdSGabriel Fernandez 	unsigned long new_freq;
32146a57afdSGabriel Fernandez 	long new_deviation;
32246a57afdSGabriel Fernandez 	/* Charge pump table: highest ndiv value for cp=6 to 25 */
32346a57afdSGabriel Fernandez 	static const unsigned char cp_table[] = {
32446a57afdSGabriel Fernandez 		48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
32546a57afdSGabriel Fernandez 		128, 136, 144, 152, 160, 168, 176, 184, 192
32646a57afdSGabriel Fernandez 	};
32746a57afdSGabriel Fernandez 
32846a57afdSGabriel Fernandez 	/* Output clock range: 800Mhz to 1600Mhz */
32946a57afdSGabriel Fernandez 	if (output < 800000000 || output > 1600000000)
33046a57afdSGabriel Fernandez 		return -EINVAL;
33146a57afdSGabriel Fernandez 
33246a57afdSGabriel Fernandez 	input /= 1000;
33346a57afdSGabriel Fernandez 	output /= 1000;
33446a57afdSGabriel Fernandez 
33546a57afdSGabriel Fernandez 	for (i = 1; i <= 7 && deviation; i++) {
33646a57afdSGabriel Fernandez 		n = i * output / (2 * input);
33746a57afdSGabriel Fernandez 
33846a57afdSGabriel Fernandez 		/* Checks */
33946a57afdSGabriel Fernandez 		if (n < 8)
34046a57afdSGabriel Fernandez 			continue;
34146a57afdSGabriel Fernandez 		if (n > 200)
34246a57afdSGabriel Fernandez 			break;
34346a57afdSGabriel Fernandez 
34446a57afdSGabriel Fernandez 		new_freq = (input * 2 * n) / i;
34546a57afdSGabriel Fernandez 
34646a57afdSGabriel Fernandez 		new_deviation = abs(new_freq - output);
34746a57afdSGabriel Fernandez 
34846a57afdSGabriel Fernandez 		if (!new_deviation || new_deviation < deviation) {
34946a57afdSGabriel Fernandez 			pll->idf  = i;
35046a57afdSGabriel Fernandez 			pll->ndiv = n;
35146a57afdSGabriel Fernandez 			deviation = new_deviation;
35246a57afdSGabriel Fernandez 		}
35346a57afdSGabriel Fernandez 	}
35446a57afdSGabriel Fernandez 
35546a57afdSGabriel Fernandez 	if (deviation == ~0) /* No solution found */
35646a57afdSGabriel Fernandez 		return -EINVAL;
35746a57afdSGabriel Fernandez 
35846a57afdSGabriel Fernandez 	/* Computing recommended charge pump value */
35946a57afdSGabriel Fernandez 	for (pll->cp = 6; pll->ndiv > cp_table[pll->cp-6]; (pll->cp)++)
36046a57afdSGabriel Fernandez 		;
36146a57afdSGabriel Fernandez 
36246a57afdSGabriel Fernandez 	return 0;
36346a57afdSGabriel Fernandez }
36446a57afdSGabriel Fernandez 
clk_pll3200c32_get_rate(unsigned long input,struct stm_pll * pll,unsigned long * rate)36546a57afdSGabriel Fernandez static int clk_pll3200c32_get_rate(unsigned long input, struct stm_pll *pll,
36646a57afdSGabriel Fernandez 			unsigned long *rate)
36746a57afdSGabriel Fernandez {
36846a57afdSGabriel Fernandez 	if (!pll->idf)
36946a57afdSGabriel Fernandez 		pll->idf = 1;
37046a57afdSGabriel Fernandez 
37146a57afdSGabriel Fernandez 	*rate = ((2 * (input / 1000) * pll->ndiv) / pll->idf) * 1000;
37246a57afdSGabriel Fernandez 
37346a57afdSGabriel Fernandez 	return 0;
37446a57afdSGabriel Fernandez }
37546a57afdSGabriel Fernandez 
recalc_stm_pll3200c32(struct clk_hw * hw,unsigned long parent_rate)3768e6dd77cSStephen Boyd static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
377b9b8e614SGabriel FERNANDEZ 		unsigned long parent_rate)
378b9b8e614SGabriel FERNANDEZ {
379b9b8e614SGabriel FERNANDEZ 	struct clkgen_pll *pll = to_clkgen_pll(hw);
380b9b8e614SGabriel FERNANDEZ 	unsigned long ndiv, idf;
381b9b8e614SGabriel FERNANDEZ 	unsigned long rate = 0;
382b9b8e614SGabriel FERNANDEZ 
383b9b8e614SGabriel FERNANDEZ 	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
384b9b8e614SGabriel FERNANDEZ 		return 0;
385b9b8e614SGabriel FERNANDEZ 
386b9b8e614SGabriel FERNANDEZ 	ndiv = CLKGEN_READ(pll, ndiv);
387b9b8e614SGabriel FERNANDEZ 	idf = CLKGEN_READ(pll, idf);
388b9b8e614SGabriel FERNANDEZ 
389b9b8e614SGabriel FERNANDEZ 	if (idf)
390b9b8e614SGabriel FERNANDEZ 		/* Note: input is divided to avoid overflow */
391b9b8e614SGabriel FERNANDEZ 		rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000;
392b9b8e614SGabriel FERNANDEZ 
393836ee0f7SStephen Boyd 	pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
394b9b8e614SGabriel FERNANDEZ 
395b9b8e614SGabriel FERNANDEZ 	return rate;
396b9b8e614SGabriel FERNANDEZ }
397b9b8e614SGabriel FERNANDEZ 
round_rate_stm_pll3200c32(struct clk_hw * hw,unsigned long rate,unsigned long * prate)39846a57afdSGabriel Fernandez static long round_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate,
39946a57afdSGabriel Fernandez 		unsigned long *prate)
40046a57afdSGabriel Fernandez {
40146a57afdSGabriel Fernandez 	struct stm_pll params;
40246a57afdSGabriel Fernandez 
40346a57afdSGabriel Fernandez 	if (!clk_pll3200c32_get_params(*prate, rate, &params))
40446a57afdSGabriel Fernandez 		clk_pll3200c32_get_rate(*prate, &params, &rate);
40546a57afdSGabriel Fernandez 	else {
40646a57afdSGabriel Fernandez 		pr_debug("%s: %s rate %ld Invalid\n", __func__,
40746a57afdSGabriel Fernandez 			 __clk_get_name(hw->clk), rate);
40846a57afdSGabriel Fernandez 		return 0;
40946a57afdSGabriel Fernandez 	}
41046a57afdSGabriel Fernandez 
41146a57afdSGabriel Fernandez 	pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
41246a57afdSGabriel Fernandez 		 __func__, __clk_get_name(hw->clk),
41346a57afdSGabriel Fernandez 		 rate, (unsigned int)params.ndiv,
41446a57afdSGabriel Fernandez 		 (unsigned int)params.idf);
41546a57afdSGabriel Fernandez 
41646a57afdSGabriel Fernandez 	return rate;
41746a57afdSGabriel Fernandez }
41846a57afdSGabriel Fernandez 
set_rate_stm_pll3200c32(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)41946a57afdSGabriel Fernandez static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate,
42046a57afdSGabriel Fernandez 				unsigned long parent_rate)
42146a57afdSGabriel Fernandez {
42246a57afdSGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
42346a57afdSGabriel Fernandez 	struct stm_pll params;
42446a57afdSGabriel Fernandez 	long hwrate = 0;
42546a57afdSGabriel Fernandez 	unsigned long flags = 0;
42646a57afdSGabriel Fernandez 
42746a57afdSGabriel Fernandez 	if (!rate || !parent_rate)
42846a57afdSGabriel Fernandez 		return -EINVAL;
42946a57afdSGabriel Fernandez 
43046a57afdSGabriel Fernandez 	if (!clk_pll3200c32_get_params(parent_rate, rate, &params))
43146a57afdSGabriel Fernandez 		clk_pll3200c32_get_rate(parent_rate, &params, &hwrate);
43246a57afdSGabriel Fernandez 
43346a57afdSGabriel Fernandez 	pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
43446a57afdSGabriel Fernandez 		 __func__, __clk_get_name(hw->clk),
43546a57afdSGabriel Fernandez 		 hwrate, (unsigned int)params.ndiv,
43646a57afdSGabriel Fernandez 		 (unsigned int)params.idf);
43746a57afdSGabriel Fernandez 
43846a57afdSGabriel Fernandez 	if (!hwrate)
43946a57afdSGabriel Fernandez 		return -EINVAL;
44046a57afdSGabriel Fernandez 
44146a57afdSGabriel Fernandez 	pll->ndiv = params.ndiv;
44246a57afdSGabriel Fernandez 	pll->idf = params.idf;
44346a57afdSGabriel Fernandez 	pll->cp = params.cp;
44446a57afdSGabriel Fernandez 
44546a57afdSGabriel Fernandez 	__clkgen_pll_disable(hw);
44646a57afdSGabriel Fernandez 
44746a57afdSGabriel Fernandez 	if (pll->lock)
44846a57afdSGabriel Fernandez 		spin_lock_irqsave(pll->lock, flags);
44946a57afdSGabriel Fernandez 
45046a57afdSGabriel Fernandez 	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
45146a57afdSGabriel Fernandez 	CLKGEN_WRITE(pll, idf, pll->idf);
45246a57afdSGabriel Fernandez 	CLKGEN_WRITE(pll, cp, pll->cp);
45346a57afdSGabriel Fernandez 
45446a57afdSGabriel Fernandez 	if (pll->lock)
45546a57afdSGabriel Fernandez 		spin_unlock_irqrestore(pll->lock, flags);
45646a57afdSGabriel Fernandez 
45746a57afdSGabriel Fernandez 	__clkgen_pll_enable(hw);
45846a57afdSGabriel Fernandez 
45946a57afdSGabriel Fernandez 	return 0;
46046a57afdSGabriel Fernandez }
46146a57afdSGabriel Fernandez 
4620829ea5aSGabriel Fernandez /* PLL output structure
4630829ea5aSGabriel Fernandez  * FVCO >> /2 >> FVCOBY2 (no output)
4640829ea5aSGabriel Fernandez  *                 |> Divider (ODF) >> PHI
4650829ea5aSGabriel Fernandez  *
4660829ea5aSGabriel Fernandez  * FVCOby2 output = (input * 2 * NDIV) / IDF (assuming FRAC_CONTROL==L)
4670829ea5aSGabriel Fernandez  *
4680829ea5aSGabriel Fernandez  * Rules:
4690829ea5aSGabriel Fernandez  *   4Mhz <= INFF input <= 350Mhz
4700829ea5aSGabriel Fernandez  *   4Mhz <= INFIN (INFF / IDF) <= 50Mhz
4710829ea5aSGabriel Fernandez  *   19.05Mhz <= FVCOby2 output (PHI w ODF=1) <= 3000Mhz
4720829ea5aSGabriel Fernandez  *   1 <= i (register/dec value for IDF) <= 7
4730829ea5aSGabriel Fernandez  *   8 <= n (register/dec value for NDIV) <= 246
4740829ea5aSGabriel Fernandez  */
4750829ea5aSGabriel Fernandez 
clk_pll4600c28_get_params(unsigned long input,unsigned long output,struct stm_pll * pll)4760829ea5aSGabriel Fernandez static int clk_pll4600c28_get_params(unsigned long input, unsigned long output,
4770829ea5aSGabriel Fernandez 			  struct stm_pll *pll)
4780829ea5aSGabriel Fernandez {
4790829ea5aSGabriel Fernandez 
4800829ea5aSGabriel Fernandez 	unsigned long i, infin, n;
4810829ea5aSGabriel Fernandez 	unsigned long deviation = ~0;
4820829ea5aSGabriel Fernandez 	unsigned long new_freq, new_deviation;
4830829ea5aSGabriel Fernandez 
4840829ea5aSGabriel Fernandez 	/* Output clock range: 19Mhz to 3000Mhz */
4850829ea5aSGabriel Fernandez 	if (output < 19000000 || output > 3000000000u)
4860829ea5aSGabriel Fernandez 		return -EINVAL;
4870829ea5aSGabriel Fernandez 
4880829ea5aSGabriel Fernandez 	/* For better jitter, IDF should be smallest and NDIV must be maximum */
4890829ea5aSGabriel Fernandez 	for (i = 1; i <= 7 && deviation; i++) {
4900829ea5aSGabriel Fernandez 		/* INFIN checks */
4910829ea5aSGabriel Fernandez 		infin = input / i;
4920829ea5aSGabriel Fernandez 		if (infin < 4000000 || infin > 50000000)
4930829ea5aSGabriel Fernandez 			continue;	/* Invalid case */
4940829ea5aSGabriel Fernandez 
4950829ea5aSGabriel Fernandez 		n = output / (infin * 2);
4960829ea5aSGabriel Fernandez 		if (n < 8 || n > 246)
4970829ea5aSGabriel Fernandez 			continue;	/* Invalid case */
4980829ea5aSGabriel Fernandez 		if (n < 246)
4990829ea5aSGabriel Fernandez 			n++;	/* To work around 'y' when n=x.y */
5000829ea5aSGabriel Fernandez 
5010829ea5aSGabriel Fernandez 		for (; n >= 8 && deviation; n--) {
5020829ea5aSGabriel Fernandez 			new_freq = infin * 2 * n;
5030829ea5aSGabriel Fernandez 			if (new_freq < output)
5040829ea5aSGabriel Fernandez 				break;	/* Optimization: shorting loop */
5050829ea5aSGabriel Fernandez 
5060829ea5aSGabriel Fernandez 			new_deviation = new_freq - output;
5070829ea5aSGabriel Fernandez 			if (!new_deviation || new_deviation < deviation) {
5080829ea5aSGabriel Fernandez 				pll->idf  = i;
5090829ea5aSGabriel Fernandez 				pll->ndiv = n;
5100829ea5aSGabriel Fernandez 				deviation = new_deviation;
5110829ea5aSGabriel Fernandez 			}
5120829ea5aSGabriel Fernandez 		}
5130829ea5aSGabriel Fernandez 	}
5140829ea5aSGabriel Fernandez 
5150829ea5aSGabriel Fernandez 	if (deviation == ~0) /* No solution found */
5160829ea5aSGabriel Fernandez 		return -EINVAL;
5170829ea5aSGabriel Fernandez 
5180829ea5aSGabriel Fernandez 	return 0;
5190829ea5aSGabriel Fernandez }
5200829ea5aSGabriel Fernandez 
clk_pll4600c28_get_rate(unsigned long input,struct stm_pll * pll,unsigned long * rate)5210829ea5aSGabriel Fernandez static int clk_pll4600c28_get_rate(unsigned long input, struct stm_pll *pll,
5220829ea5aSGabriel Fernandez 			unsigned long *rate)
5230829ea5aSGabriel Fernandez {
5240829ea5aSGabriel Fernandez 	if (!pll->idf)
5250829ea5aSGabriel Fernandez 		pll->idf = 1;
5260829ea5aSGabriel Fernandez 
5270829ea5aSGabriel Fernandez 	*rate = (input / pll->idf) * 2 * pll->ndiv;
5280829ea5aSGabriel Fernandez 
5290829ea5aSGabriel Fernandez 	return 0;
5300829ea5aSGabriel Fernandez }
5310829ea5aSGabriel Fernandez 
recalc_stm_pll4600c28(struct clk_hw * hw,unsigned long parent_rate)5320829ea5aSGabriel Fernandez static unsigned long recalc_stm_pll4600c28(struct clk_hw *hw,
5330829ea5aSGabriel Fernandez 				    unsigned long parent_rate)
5340829ea5aSGabriel Fernandez {
5350829ea5aSGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
5360829ea5aSGabriel Fernandez 	struct stm_pll params;
5370829ea5aSGabriel Fernandez 	unsigned long rate;
5380829ea5aSGabriel Fernandez 
5390829ea5aSGabriel Fernandez 	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
5400829ea5aSGabriel Fernandez 		return 0;
5410829ea5aSGabriel Fernandez 
5420829ea5aSGabriel Fernandez 	params.ndiv = CLKGEN_READ(pll, ndiv);
5430829ea5aSGabriel Fernandez 	params.idf = CLKGEN_READ(pll, idf);
5440829ea5aSGabriel Fernandez 
5450829ea5aSGabriel Fernandez 	clk_pll4600c28_get_rate(parent_rate, &params, &rate);
5460829ea5aSGabriel Fernandez 
5470829ea5aSGabriel Fernandez 	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
5480829ea5aSGabriel Fernandez 
5490829ea5aSGabriel Fernandez 	return rate;
5500829ea5aSGabriel Fernandez }
5510829ea5aSGabriel Fernandez 
round_rate_stm_pll4600c28(struct clk_hw * hw,unsigned long rate,unsigned long * prate)5520829ea5aSGabriel Fernandez static long round_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate,
5530829ea5aSGabriel Fernandez 				      unsigned long *prate)
5540829ea5aSGabriel Fernandez {
5550829ea5aSGabriel Fernandez 	struct stm_pll params;
5560829ea5aSGabriel Fernandez 
5570829ea5aSGabriel Fernandez 	if (!clk_pll4600c28_get_params(*prate, rate, &params)) {
5580829ea5aSGabriel Fernandez 		clk_pll4600c28_get_rate(*prate, &params, &rate);
5590829ea5aSGabriel Fernandez 	} else {
5600829ea5aSGabriel Fernandez 		pr_debug("%s: %s rate %ld Invalid\n", __func__,
5610829ea5aSGabriel Fernandez 			 __clk_get_name(hw->clk), rate);
5620829ea5aSGabriel Fernandez 		return 0;
5630829ea5aSGabriel Fernandez 	}
5640829ea5aSGabriel Fernandez 
5650829ea5aSGabriel Fernandez 	pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
5660829ea5aSGabriel Fernandez 		 __func__, __clk_get_name(hw->clk),
5670829ea5aSGabriel Fernandez 		 rate, (unsigned int)params.ndiv,
5680829ea5aSGabriel Fernandez 		 (unsigned int)params.idf);
5690829ea5aSGabriel Fernandez 
5700829ea5aSGabriel Fernandez 	return rate;
5710829ea5aSGabriel Fernandez }
5720829ea5aSGabriel Fernandez 
set_rate_stm_pll4600c28(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)5730829ea5aSGabriel Fernandez static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate,
5740829ea5aSGabriel Fernandez 				   unsigned long parent_rate)
5750829ea5aSGabriel Fernandez {
5760829ea5aSGabriel Fernandez 	struct clkgen_pll *pll = to_clkgen_pll(hw);
5770829ea5aSGabriel Fernandez 	struct stm_pll params;
5780829ea5aSGabriel Fernandez 	long hwrate;
5790829ea5aSGabriel Fernandez 	unsigned long flags = 0;
5800829ea5aSGabriel Fernandez 
5810829ea5aSGabriel Fernandez 	if (!rate || !parent_rate)
5820829ea5aSGabriel Fernandez 		return -EINVAL;
5830829ea5aSGabriel Fernandez 
5840829ea5aSGabriel Fernandez 	if (!clk_pll4600c28_get_params(parent_rate, rate, &params)) {
5850829ea5aSGabriel Fernandez 		clk_pll4600c28_get_rate(parent_rate, &params, &hwrate);
5860829ea5aSGabriel Fernandez 	} else {
5870829ea5aSGabriel Fernandez 		pr_debug("%s: %s rate %ld Invalid\n", __func__,
5880829ea5aSGabriel Fernandez 			 __clk_get_name(hw->clk), rate);
5890829ea5aSGabriel Fernandez 		return -EINVAL;
5900829ea5aSGabriel Fernandez 	}
5910829ea5aSGabriel Fernandez 
5920829ea5aSGabriel Fernandez 	pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
5930829ea5aSGabriel Fernandez 		 __func__, __clk_get_name(hw->clk),
5940829ea5aSGabriel Fernandez 		 hwrate, (unsigned int)params.ndiv,
5950829ea5aSGabriel Fernandez 		 (unsigned int)params.idf);
5960829ea5aSGabriel Fernandez 
5970829ea5aSGabriel Fernandez 	if (!hwrate)
5980829ea5aSGabriel Fernandez 		return -EINVAL;
5990829ea5aSGabriel Fernandez 
6000829ea5aSGabriel Fernandez 	pll->ndiv = params.ndiv;
6010829ea5aSGabriel Fernandez 	pll->idf = params.idf;
6020829ea5aSGabriel Fernandez 
6030829ea5aSGabriel Fernandez 	__clkgen_pll_disable(hw);
6040829ea5aSGabriel Fernandez 
6050829ea5aSGabriel Fernandez 	if (pll->lock)
6060829ea5aSGabriel Fernandez 		spin_lock_irqsave(pll->lock, flags);
6070829ea5aSGabriel Fernandez 
6080829ea5aSGabriel Fernandez 	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
6090829ea5aSGabriel Fernandez 	CLKGEN_WRITE(pll, idf, pll->idf);
6100829ea5aSGabriel Fernandez 
6110829ea5aSGabriel Fernandez 	if (pll->lock)
6120829ea5aSGabriel Fernandez 		spin_unlock_irqrestore(pll->lock, flags);
6130829ea5aSGabriel Fernandez 
6140829ea5aSGabriel Fernandez 	__clkgen_pll_enable(hw);
6150829ea5aSGabriel Fernandez 
6160829ea5aSGabriel Fernandez 	return 0;
6170829ea5aSGabriel Fernandez }
6180829ea5aSGabriel Fernandez 
619b9b8e614SGabriel FERNANDEZ static const struct clk_ops stm_pll3200c32_ops = {
620fb473862SGabriel Fernandez 	.enable		= clkgen_pll_enable,
621fb473862SGabriel Fernandez 	.disable	= clkgen_pll_disable,
622b9b8e614SGabriel FERNANDEZ 	.is_enabled	= clkgen_pll_is_enabled,
623b9b8e614SGabriel FERNANDEZ 	.recalc_rate	= recalc_stm_pll3200c32,
624b9b8e614SGabriel FERNANDEZ };
625b9b8e614SGabriel FERNANDEZ 
62646a57afdSGabriel Fernandez static const struct clk_ops stm_pll3200c32_a9_ops = {
62746a57afdSGabriel Fernandez 	.enable		= clkgen_pll_enable,
62846a57afdSGabriel Fernandez 	.disable	= clkgen_pll_disable,
62946a57afdSGabriel Fernandez 	.is_enabled	= clkgen_pll_is_enabled,
63046a57afdSGabriel Fernandez 	.recalc_rate	= recalc_stm_pll3200c32,
63146a57afdSGabriel Fernandez 	.round_rate	= round_rate_stm_pll3200c32,
63246a57afdSGabriel Fernandez 	.set_rate	= set_rate_stm_pll3200c32,
63346a57afdSGabriel Fernandez };
63446a57afdSGabriel Fernandez 
6350829ea5aSGabriel Fernandez static const struct clk_ops stm_pll4600c28_ops = {
6360829ea5aSGabriel Fernandez 	.enable		= clkgen_pll_enable,
6370829ea5aSGabriel Fernandez 	.disable	= clkgen_pll_disable,
6380829ea5aSGabriel Fernandez 	.is_enabled	= clkgen_pll_is_enabled,
6390829ea5aSGabriel Fernandez 	.recalc_rate	= recalc_stm_pll4600c28,
6400829ea5aSGabriel Fernandez 	.round_rate	= round_rate_stm_pll4600c28,
6410829ea5aSGabriel Fernandez 	.set_rate	= set_rate_stm_pll4600c28,
6420829ea5aSGabriel Fernandez };
6430829ea5aSGabriel Fernandez 
clkgen_pll_register(const char * parent_name,struct clkgen_pll_data * pll_data,void __iomem * reg,unsigned long pll_flags,const char * clk_name,spinlock_t * lock)644b9b8e614SGabriel FERNANDEZ static struct clk * __init clkgen_pll_register(const char *parent_name,
645b9b8e614SGabriel FERNANDEZ 				struct clkgen_pll_data	*pll_data,
6466ca59e6eSLee Jones 				void __iomem *reg, unsigned long pll_flags,
64746a57afdSGabriel Fernandez 				const char *clk_name, spinlock_t *lock)
648b9b8e614SGabriel FERNANDEZ {
649b9b8e614SGabriel FERNANDEZ 	struct clkgen_pll *pll;
650b9b8e614SGabriel FERNANDEZ 	struct clk *clk;
651b9b8e614SGabriel FERNANDEZ 	struct clk_init_data init;
652b9b8e614SGabriel FERNANDEZ 
653b9b8e614SGabriel FERNANDEZ 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
654b9b8e614SGabriel FERNANDEZ 	if (!pll)
655b9b8e614SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
656b9b8e614SGabriel FERNANDEZ 
657b9b8e614SGabriel FERNANDEZ 	init.name = clk_name;
658b9b8e614SGabriel FERNANDEZ 	init.ops = pll_data->ops;
659b9b8e614SGabriel FERNANDEZ 
660c179c21eSStephen Boyd 	init.flags = pll_flags | CLK_GET_RATE_NOCACHE;
661b9b8e614SGabriel FERNANDEZ 	init.parent_names = &parent_name;
662b9b8e614SGabriel FERNANDEZ 	init.num_parents  = 1;
663b9b8e614SGabriel FERNANDEZ 
664b9b8e614SGabriel FERNANDEZ 	pll->data = pll_data;
665b9b8e614SGabriel FERNANDEZ 	pll->regs_base = reg;
666b9b8e614SGabriel FERNANDEZ 	pll->hw.init = &init;
66746a57afdSGabriel Fernandez 	pll->lock = lock;
668b9b8e614SGabriel FERNANDEZ 
669b9b8e614SGabriel FERNANDEZ 	clk = clk_register(NULL, &pll->hw);
670b9b8e614SGabriel FERNANDEZ 	if (IS_ERR(clk)) {
671b9b8e614SGabriel FERNANDEZ 		kfree(pll);
672b9b8e614SGabriel FERNANDEZ 		return clk;
673b9b8e614SGabriel FERNANDEZ 	}
674b9b8e614SGabriel FERNANDEZ 
675b9b8e614SGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %lu\n",
676b9b8e614SGabriel FERNANDEZ 			__clk_get_name(clk),
677b9b8e614SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
678b9b8e614SGabriel FERNANDEZ 			clk_get_rate(clk));
679b9b8e614SGabriel FERNANDEZ 
680b9b8e614SGabriel FERNANDEZ 	return clk;
681b9b8e614SGabriel FERNANDEZ }
682b9b8e614SGabriel FERNANDEZ 
clkgen_get_register_base(struct device_node * np)683b9b8e614SGabriel FERNANDEZ static void __iomem * __init clkgen_get_register_base(
684b9b8e614SGabriel FERNANDEZ 				struct device_node *np)
685b9b8e614SGabriel FERNANDEZ {
686b9b8e614SGabriel FERNANDEZ 	struct device_node *pnode;
687b9b8e614SGabriel FERNANDEZ 	void __iomem *reg = NULL;
688b9b8e614SGabriel FERNANDEZ 
689b9b8e614SGabriel FERNANDEZ 	pnode = of_get_parent(np);
690b9b8e614SGabriel FERNANDEZ 	if (!pnode)
691b9b8e614SGabriel FERNANDEZ 		return NULL;
692b9b8e614SGabriel FERNANDEZ 
693b9b8e614SGabriel FERNANDEZ 	reg = of_iomap(pnode, 0);
694b9b8e614SGabriel FERNANDEZ 
695b9b8e614SGabriel FERNANDEZ 	of_node_put(pnode);
696b9b8e614SGabriel FERNANDEZ 	return reg;
697b9b8e614SGabriel FERNANDEZ }
698b9b8e614SGabriel FERNANDEZ 
clkgen_odf_register(const char * parent_name,void __iomem * reg,struct clkgen_pll_data * pll_data,unsigned long pll_flags,int odf,spinlock_t * odf_lock,const char * odf_name)699b9b8e614SGabriel FERNANDEZ static struct clk * __init clkgen_odf_register(const char *parent_name,
7008e6dd77cSStephen Boyd 					       void __iomem *reg,
701b9b8e614SGabriel FERNANDEZ 					       struct clkgen_pll_data *pll_data,
7026ca59e6eSLee Jones 					       unsigned long pll_flags, int odf,
703b9b8e614SGabriel FERNANDEZ 					       spinlock_t *odf_lock,
704b9b8e614SGabriel FERNANDEZ 					       const char *odf_name)
705b9b8e614SGabriel FERNANDEZ {
706b9b8e614SGabriel FERNANDEZ 	struct clk *clk;
707b9b8e614SGabriel FERNANDEZ 	unsigned long flags;
708b9b8e614SGabriel FERNANDEZ 	struct clk_gate *gate;
709b9b8e614SGabriel FERNANDEZ 	struct clk_divider *div;
710b9b8e614SGabriel FERNANDEZ 
7116ca59e6eSLee Jones 	flags = pll_flags | CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
712b9b8e614SGabriel FERNANDEZ 
713b9b8e614SGabriel FERNANDEZ 	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
714b9b8e614SGabriel FERNANDEZ 	if (!gate)
715b9b8e614SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
716b9b8e614SGabriel FERNANDEZ 
717b9b8e614SGabriel FERNANDEZ 	gate->flags = CLK_GATE_SET_TO_DISABLE;
718b9b8e614SGabriel FERNANDEZ 	gate->reg = reg + pll_data->odf_gate[odf].offset;
719b9b8e614SGabriel FERNANDEZ 	gate->bit_idx = pll_data->odf_gate[odf].shift;
720b9b8e614SGabriel FERNANDEZ 	gate->lock = odf_lock;
721b9b8e614SGabriel FERNANDEZ 
722b9b8e614SGabriel FERNANDEZ 	div = kzalloc(sizeof(*div), GFP_KERNEL);
72372b1c2c3SValentin Ilie 	if (!div) {
72472b1c2c3SValentin Ilie 		kfree(gate);
725b9b8e614SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
72672b1c2c3SValentin Ilie 	}
727b9b8e614SGabriel FERNANDEZ 
728b9b8e614SGabriel FERNANDEZ 	div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
729b9b8e614SGabriel FERNANDEZ 	div->reg = reg + pll_data->odf[odf].offset;
730b9b8e614SGabriel FERNANDEZ 	div->shift = pll_data->odf[odf].shift;
731b9b8e614SGabriel FERNANDEZ 	div->width = fls(pll_data->odf[odf].mask);
732b9b8e614SGabriel FERNANDEZ 	div->lock = odf_lock;
733b9b8e614SGabriel FERNANDEZ 
734b9b8e614SGabriel FERNANDEZ 	clk = clk_register_composite(NULL, odf_name, &parent_name, 1,
735b9b8e614SGabriel FERNANDEZ 				     NULL, NULL,
736b9b8e614SGabriel FERNANDEZ 				     &div->hw, &clk_divider_ops,
737b9b8e614SGabriel FERNANDEZ 				     &gate->hw, &clk_gate_ops,
738b9b8e614SGabriel FERNANDEZ 				     flags);
739b9b8e614SGabriel FERNANDEZ 	if (IS_ERR(clk))
740b9b8e614SGabriel FERNANDEZ 		return clk;
741b9b8e614SGabriel FERNANDEZ 
742b9b8e614SGabriel FERNANDEZ 	pr_debug("%s: parent %s rate %lu\n",
743b9b8e614SGabriel FERNANDEZ 			__clk_get_name(clk),
744b9b8e614SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
745b9b8e614SGabriel FERNANDEZ 			clk_get_rate(clk));
746b9b8e614SGabriel FERNANDEZ 	return clk;
747b9b8e614SGabriel FERNANDEZ }
748b9b8e614SGabriel FERNANDEZ 
749b9b8e614SGabriel FERNANDEZ 
clkgen_c32_pll_setup(struct device_node * np,struct clkgen_pll_data_clks * datac)750880d54ffSGabriel Fernandez static void __init clkgen_c32_pll_setup(struct device_node *np,
751*92ef1b2bSAlain Volmat 		struct clkgen_pll_data_clks *datac)
752b9b8e614SGabriel FERNANDEZ {
753b9b8e614SGabriel FERNANDEZ 	struct clk *clk;
754b9b8e614SGabriel FERNANDEZ 	const char *parent_name, *pll_name;
755b9b8e614SGabriel FERNANDEZ 	void __iomem *pll_base;
756b9b8e614SGabriel FERNANDEZ 	int num_odfs, odf;
757b9b8e614SGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
7586ca59e6eSLee Jones 	unsigned long pll_flags = 0;
759b9b8e614SGabriel FERNANDEZ 
760b9b8e614SGabriel FERNANDEZ 
761b9b8e614SGabriel FERNANDEZ 	parent_name = of_clk_get_parent_name(np, 0);
762b9b8e614SGabriel FERNANDEZ 	if (!parent_name)
763b9b8e614SGabriel FERNANDEZ 		return;
764b9b8e614SGabriel FERNANDEZ 
765b9b8e614SGabriel FERNANDEZ 	pll_base = clkgen_get_register_base(np);
766b9b8e614SGabriel FERNANDEZ 	if (!pll_base)
767b9b8e614SGabriel FERNANDEZ 		return;
768b9b8e614SGabriel FERNANDEZ 
7696ca59e6eSLee Jones 	of_clk_detect_critical(np, 0, &pll_flags);
7706ca59e6eSLee Jones 
771*92ef1b2bSAlain Volmat 	clk = clkgen_pll_register(parent_name, datac->data, pll_base, pll_flags,
772*92ef1b2bSAlain Volmat 				  np->name, datac->data->lock);
773b9b8e614SGabriel FERNANDEZ 	if (IS_ERR(clk))
774b9b8e614SGabriel FERNANDEZ 		return;
775b9b8e614SGabriel FERNANDEZ 
776b9b8e614SGabriel FERNANDEZ 	pll_name = __clk_get_name(clk);
777b9b8e614SGabriel FERNANDEZ 
778*92ef1b2bSAlain Volmat 	num_odfs = datac->data->num_odfs;
779b9b8e614SGabriel FERNANDEZ 
780b9b8e614SGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
781b9b8e614SGabriel FERNANDEZ 	if (!clk_data)
782b9b8e614SGabriel FERNANDEZ 		return;
783b9b8e614SGabriel FERNANDEZ 
784b9b8e614SGabriel FERNANDEZ 	clk_data->clk_num = num_odfs;
7856396bb22SKees Cook 	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
786b9b8e614SGabriel FERNANDEZ 				 GFP_KERNEL);
787b9b8e614SGabriel FERNANDEZ 
788b9b8e614SGabriel FERNANDEZ 	if (!clk_data->clks)
789b9b8e614SGabriel FERNANDEZ 		goto err;
790b9b8e614SGabriel FERNANDEZ 
791b9b8e614SGabriel FERNANDEZ 	for (odf = 0; odf < num_odfs; odf++) {
792b9b8e614SGabriel FERNANDEZ 		struct clk *clk;
793b9b8e614SGabriel FERNANDEZ 		const char *clk_name;
7946ca59e6eSLee Jones 		unsigned long odf_flags = 0;
795b9b8e614SGabriel FERNANDEZ 
796*92ef1b2bSAlain Volmat 		if (datac->outputs) {
797*92ef1b2bSAlain Volmat 			clk_name = datac->outputs[odf].name;
798*92ef1b2bSAlain Volmat 			odf_flags = datac->outputs[odf].flags;
799*92ef1b2bSAlain Volmat 		} else {
800*92ef1b2bSAlain Volmat 			if (of_property_read_string_index(np,
801*92ef1b2bSAlain Volmat 							  "clock-output-names",
802b9b8e614SGabriel FERNANDEZ 							  odf, &clk_name))
803b9b8e614SGabriel FERNANDEZ 				return;
804b9b8e614SGabriel FERNANDEZ 
8056ca59e6eSLee Jones 			of_clk_detect_critical(np, odf, &odf_flags);
806*92ef1b2bSAlain Volmat 		}
8076ca59e6eSLee Jones 
808*92ef1b2bSAlain Volmat 		clk = clkgen_odf_register(pll_name, pll_base, datac->data,
809*92ef1b2bSAlain Volmat 				odf_flags, odf, &clkgena_c32_odf_lock,
810*92ef1b2bSAlain Volmat 				clk_name);
811b9b8e614SGabriel FERNANDEZ 		if (IS_ERR(clk))
812b9b8e614SGabriel FERNANDEZ 			goto err;
813b9b8e614SGabriel FERNANDEZ 
814b9b8e614SGabriel FERNANDEZ 		clk_data->clks[odf] = clk;
815b9b8e614SGabriel FERNANDEZ 	}
816b9b8e614SGabriel FERNANDEZ 
817b9b8e614SGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
818b9b8e614SGabriel FERNANDEZ 	return;
819b9b8e614SGabriel FERNANDEZ 
820b9b8e614SGabriel FERNANDEZ err:
821b9b8e614SGabriel FERNANDEZ 	kfree(pll_name);
822b9b8e614SGabriel FERNANDEZ 	kfree(clk_data->clks);
823b9b8e614SGabriel FERNANDEZ 	kfree(clk_data);
824b9b8e614SGabriel FERNANDEZ }
clkgen_c32_pll0_setup(struct device_node * np)825880d54ffSGabriel Fernandez static void __init clkgen_c32_pll0_setup(struct device_node *np)
826880d54ffSGabriel Fernandez {
827880d54ffSGabriel Fernandez 	clkgen_c32_pll_setup(np,
828*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_cx_0_legacy_data);
829880d54ffSGabriel Fernandez }
830880d54ffSGabriel Fernandez CLK_OF_DECLARE(c32_pll0, "st,clkgen-pll0", clkgen_c32_pll0_setup);
831880d54ffSGabriel Fernandez 
clkgen_c32_pll0_a0_setup(struct device_node * np)832*92ef1b2bSAlain Volmat static void __init clkgen_c32_pll0_a0_setup(struct device_node *np)
833*92ef1b2bSAlain Volmat {
834*92ef1b2bSAlain Volmat 	clkgen_c32_pll_setup(np,
835*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_a0_data);
836*92ef1b2bSAlain Volmat }
837*92ef1b2bSAlain Volmat CLK_OF_DECLARE(c32_pll0_a0, "st,clkgen-pll0-a0", clkgen_c32_pll0_a0_setup);
838*92ef1b2bSAlain Volmat 
clkgen_c32_pll0_c0_setup(struct device_node * np)839*92ef1b2bSAlain Volmat static void __init clkgen_c32_pll0_c0_setup(struct device_node *np)
840*92ef1b2bSAlain Volmat {
841*92ef1b2bSAlain Volmat 	clkgen_c32_pll_setup(np,
842*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_c0_data);
843*92ef1b2bSAlain Volmat }
844*92ef1b2bSAlain Volmat CLK_OF_DECLARE(c32_pll0_c0, "st,clkgen-pll0-c0", clkgen_c32_pll0_c0_setup);
845*92ef1b2bSAlain Volmat 
clkgen_c32_pll1_setup(struct device_node * np)846880d54ffSGabriel Fernandez static void __init clkgen_c32_pll1_setup(struct device_node *np)
847880d54ffSGabriel Fernandez {
848880d54ffSGabriel Fernandez 	clkgen_c32_pll_setup(np,
849*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_cx_1_legacy_data);
850880d54ffSGabriel Fernandez }
851880d54ffSGabriel Fernandez CLK_OF_DECLARE(c32_pll1, "st,clkgen-pll1", clkgen_c32_pll1_setup);
852880d54ffSGabriel Fernandez 
clkgen_c32_pll1_c0_setup(struct device_node * np)853*92ef1b2bSAlain Volmat static void __init clkgen_c32_pll1_c0_setup(struct device_node *np)
854*92ef1b2bSAlain Volmat {
855*92ef1b2bSAlain Volmat 	clkgen_c32_pll_setup(np,
856*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_c1_data);
857*92ef1b2bSAlain Volmat }
858*92ef1b2bSAlain Volmat CLK_OF_DECLARE(c32_pll1_c0, "st,clkgen-pll1-c0", clkgen_c32_pll1_c0_setup);
859*92ef1b2bSAlain Volmat 
clkgen_c32_plla9_setup(struct device_node * np)860880d54ffSGabriel Fernandez static void __init clkgen_c32_plla9_setup(struct device_node *np)
861880d54ffSGabriel Fernandez {
862880d54ffSGabriel Fernandez 	clkgen_c32_pll_setup(np,
863*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll3200c32_407_a9_data);
864880d54ffSGabriel Fernandez }
865880d54ffSGabriel Fernandez CLK_OF_DECLARE(c32_plla9, "st,stih407-clkgen-plla9", clkgen_c32_plla9_setup);
866880d54ffSGabriel Fernandez 
clkgen_c28_plla9_setup(struct device_node * np)867880d54ffSGabriel Fernandez static void __init clkgen_c28_plla9_setup(struct device_node *np)
868880d54ffSGabriel Fernandez {
869880d54ffSGabriel Fernandez 	clkgen_c32_pll_setup(np,
870*92ef1b2bSAlain Volmat 		(struct clkgen_pll_data_clks *) &st_pll4600c28_418_a9_data);
871880d54ffSGabriel Fernandez }
872880d54ffSGabriel Fernandez CLK_OF_DECLARE(c28_plla9, "st,stih418-clkgen-plla9", clkgen_c28_plla9_setup);
873