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, ¶ms))
40446a57afdSGabriel Fernandez clk_pll3200c32_get_rate(*prate, ¶ms, &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, ¶ms))
43146a57afdSGabriel Fernandez clk_pll3200c32_get_rate(parent_rate, ¶ms, &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, ¶ms, &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, ¶ms)) {
5580829ea5aSGabriel Fernandez clk_pll4600c28_get_rate(*prate, ¶ms, &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, ¶ms)) {
5850829ea5aSGabriel Fernandez clk_pll4600c28_get_rate(parent_rate, ¶ms, &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