104dc82e1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ce6e1188SPurna Chandra Mandal /*
3ce6e1188SPurna Chandra Mandal * Purna Chandra Mandal,<purna.mandal@microchip.com>
4ce6e1188SPurna Chandra Mandal * Copyright (C) 2015 Microchip Technology Inc. All rights reserved.
5ce6e1188SPurna Chandra Mandal */
6ce6e1188SPurna Chandra Mandal #include <linux/clk-provider.h>
7ce6e1188SPurna Chandra Mandal #include <linux/delay.h>
8ce6e1188SPurna Chandra Mandal #include <linux/device.h>
9ce6e1188SPurna Chandra Mandal #include <linux/interrupt.h>
1062e59c4eSStephen Boyd #include <linux/io.h>
11ce6e1188SPurna Chandra Mandal #include <linux/iopoll.h>
12ce6e1188SPurna Chandra Mandal #include <asm/mach-pic32/pic32.h>
13ce6e1188SPurna Chandra Mandal #include <asm/traps.h>
14ce6e1188SPurna Chandra Mandal
15ce6e1188SPurna Chandra Mandal #include "clk-core.h"
16ce6e1188SPurna Chandra Mandal
17ce6e1188SPurna Chandra Mandal /* OSCCON Reg fields */
18ce6e1188SPurna Chandra Mandal #define OSC_CUR_MASK 0x07
19ce6e1188SPurna Chandra Mandal #define OSC_CUR_SHIFT 12
20ce6e1188SPurna Chandra Mandal #define OSC_NEW_MASK 0x07
21ce6e1188SPurna Chandra Mandal #define OSC_NEW_SHIFT 8
22ce6e1188SPurna Chandra Mandal #define OSC_SWEN BIT(0)
23ce6e1188SPurna Chandra Mandal
24ce6e1188SPurna Chandra Mandal /* SPLLCON Reg fields */
25ce6e1188SPurna Chandra Mandal #define PLL_RANGE_MASK 0x07
26ce6e1188SPurna Chandra Mandal #define PLL_RANGE_SHIFT 0
27ce6e1188SPurna Chandra Mandal #define PLL_ICLK_MASK 0x01
28ce6e1188SPurna Chandra Mandal #define PLL_ICLK_SHIFT 7
29ce6e1188SPurna Chandra Mandal #define PLL_IDIV_MASK 0x07
30ce6e1188SPurna Chandra Mandal #define PLL_IDIV_SHIFT 8
31ce6e1188SPurna Chandra Mandal #define PLL_ODIV_MASK 0x07
32ce6e1188SPurna Chandra Mandal #define PLL_ODIV_SHIFT 24
33ce6e1188SPurna Chandra Mandal #define PLL_MULT_MASK 0x7F
34ce6e1188SPurna Chandra Mandal #define PLL_MULT_SHIFT 16
35ce6e1188SPurna Chandra Mandal #define PLL_MULT_MAX 128
36ce6e1188SPurna Chandra Mandal #define PLL_ODIV_MIN 1
37ce6e1188SPurna Chandra Mandal #define PLL_ODIV_MAX 5
38ce6e1188SPurna Chandra Mandal
39ce6e1188SPurna Chandra Mandal /* Peripheral Bus Clock Reg Fields */
40ce6e1188SPurna Chandra Mandal #define PB_DIV_MASK 0x7f
41ce6e1188SPurna Chandra Mandal #define PB_DIV_SHIFT 0
42ce6e1188SPurna Chandra Mandal #define PB_DIV_READY BIT(11)
43ce6e1188SPurna Chandra Mandal #define PB_DIV_ENABLE BIT(15)
44ce6e1188SPurna Chandra Mandal #define PB_DIV_MAX 128
45ce6e1188SPurna Chandra Mandal #define PB_DIV_MIN 0
46ce6e1188SPurna Chandra Mandal
47ce6e1188SPurna Chandra Mandal /* Reference Oscillator Control Reg fields */
48ce6e1188SPurna Chandra Mandal #define REFO_SEL_MASK 0x0f
49ce6e1188SPurna Chandra Mandal #define REFO_SEL_SHIFT 0
50ce6e1188SPurna Chandra Mandal #define REFO_ACTIVE BIT(8)
51ce6e1188SPurna Chandra Mandal #define REFO_DIVSW_EN BIT(9)
52ce6e1188SPurna Chandra Mandal #define REFO_OE BIT(12)
53ce6e1188SPurna Chandra Mandal #define REFO_ON BIT(15)
54ce6e1188SPurna Chandra Mandal #define REFO_DIV_SHIFT 16
55ce6e1188SPurna Chandra Mandal #define REFO_DIV_MASK 0x7fff
56ce6e1188SPurna Chandra Mandal
57ce6e1188SPurna Chandra Mandal /* Reference Oscillator Trim Register Fields */
58ce6e1188SPurna Chandra Mandal #define REFO_TRIM_REG 0x10
59ce6e1188SPurna Chandra Mandal #define REFO_TRIM_MASK 0x1ff
60ce6e1188SPurna Chandra Mandal #define REFO_TRIM_SHIFT 23
61ce6e1188SPurna Chandra Mandal #define REFO_TRIM_MAX 511
62ce6e1188SPurna Chandra Mandal
63ce6e1188SPurna Chandra Mandal /* Mux Slew Control Register fields */
64ce6e1188SPurna Chandra Mandal #define SLEW_BUSY BIT(0)
65ce6e1188SPurna Chandra Mandal #define SLEW_DOWNEN BIT(1)
66ce6e1188SPurna Chandra Mandal #define SLEW_UPEN BIT(2)
67ce6e1188SPurna Chandra Mandal #define SLEW_DIV 0x07
68ce6e1188SPurna Chandra Mandal #define SLEW_DIV_SHIFT 8
69ce6e1188SPurna Chandra Mandal #define SLEW_SYSDIV 0x0f
70ce6e1188SPurna Chandra Mandal #define SLEW_SYSDIV_SHIFT 20
71ce6e1188SPurna Chandra Mandal
72ce6e1188SPurna Chandra Mandal /* Clock Poll Timeout */
73ce6e1188SPurna Chandra Mandal #define LOCK_TIMEOUT_US USEC_PER_MSEC
74ce6e1188SPurna Chandra Mandal
75ce6e1188SPurna Chandra Mandal /* SoC specific clock needed during SPLL clock rate switch */
76ce6e1188SPurna Chandra Mandal static struct clk_hw *pic32_sclk_hw;
77ce6e1188SPurna Chandra Mandal
78ce6e1188SPurna Chandra Mandal /* add instruction pipeline delay while CPU clock is in-transition. */
79ce6e1188SPurna Chandra Mandal #define cpu_nop5() \
80ce6e1188SPurna Chandra Mandal do { \
81ce6e1188SPurna Chandra Mandal __asm__ __volatile__("nop"); \
82ce6e1188SPurna Chandra Mandal __asm__ __volatile__("nop"); \
83ce6e1188SPurna Chandra Mandal __asm__ __volatile__("nop"); \
84ce6e1188SPurna Chandra Mandal __asm__ __volatile__("nop"); \
85ce6e1188SPurna Chandra Mandal __asm__ __volatile__("nop"); \
86ce6e1188SPurna Chandra Mandal } while (0)
87ce6e1188SPurna Chandra Mandal
88ce6e1188SPurna Chandra Mandal /* Perpheral bus clocks */
89ce6e1188SPurna Chandra Mandal struct pic32_periph_clk {
90ce6e1188SPurna Chandra Mandal struct clk_hw hw;
91ce6e1188SPurna Chandra Mandal void __iomem *ctrl_reg;
92ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core;
93ce6e1188SPurna Chandra Mandal };
94ce6e1188SPurna Chandra Mandal
95ce6e1188SPurna Chandra Mandal #define clkhw_to_pbclk(_hw) container_of(_hw, struct pic32_periph_clk, hw)
96ce6e1188SPurna Chandra Mandal
pbclk_is_enabled(struct clk_hw * hw)97ce6e1188SPurna Chandra Mandal static int pbclk_is_enabled(struct clk_hw *hw)
98ce6e1188SPurna Chandra Mandal {
99ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pb = clkhw_to_pbclk(hw);
100ce6e1188SPurna Chandra Mandal
101ce6e1188SPurna Chandra Mandal return readl(pb->ctrl_reg) & PB_DIV_ENABLE;
102ce6e1188SPurna Chandra Mandal }
103ce6e1188SPurna Chandra Mandal
pbclk_enable(struct clk_hw * hw)104ce6e1188SPurna Chandra Mandal static int pbclk_enable(struct clk_hw *hw)
105ce6e1188SPurna Chandra Mandal {
106ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pb = clkhw_to_pbclk(hw);
107ce6e1188SPurna Chandra Mandal
108ce6e1188SPurna Chandra Mandal writel(PB_DIV_ENABLE, PIC32_SET(pb->ctrl_reg));
109ce6e1188SPurna Chandra Mandal return 0;
110ce6e1188SPurna Chandra Mandal }
111ce6e1188SPurna Chandra Mandal
pbclk_disable(struct clk_hw * hw)112ce6e1188SPurna Chandra Mandal static void pbclk_disable(struct clk_hw *hw)
113ce6e1188SPurna Chandra Mandal {
114ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pb = clkhw_to_pbclk(hw);
115ce6e1188SPurna Chandra Mandal
116ce6e1188SPurna Chandra Mandal writel(PB_DIV_ENABLE, PIC32_CLR(pb->ctrl_reg));
117ce6e1188SPurna Chandra Mandal }
118ce6e1188SPurna Chandra Mandal
calc_best_divided_rate(unsigned long rate,unsigned long parent_rate,u32 divider_max,u32 divider_min)119ce6e1188SPurna Chandra Mandal static unsigned long calc_best_divided_rate(unsigned long rate,
120ce6e1188SPurna Chandra Mandal unsigned long parent_rate,
121ce6e1188SPurna Chandra Mandal u32 divider_max,
122ce6e1188SPurna Chandra Mandal u32 divider_min)
123ce6e1188SPurna Chandra Mandal {
124ce6e1188SPurna Chandra Mandal unsigned long divided_rate, divided_rate_down, best_rate;
125ce6e1188SPurna Chandra Mandal unsigned long div, div_up;
126ce6e1188SPurna Chandra Mandal
127ce6e1188SPurna Chandra Mandal /* eq. clk_rate = parent_rate / divider.
128ce6e1188SPurna Chandra Mandal *
129ce6e1188SPurna Chandra Mandal * Find best divider to produce closest of target divided rate.
130ce6e1188SPurna Chandra Mandal */
131ce6e1188SPurna Chandra Mandal div = parent_rate / rate;
132ce6e1188SPurna Chandra Mandal div = clamp_val(div, divider_min, divider_max);
133ce6e1188SPurna Chandra Mandal div_up = clamp_val(div + 1, divider_min, divider_max);
134ce6e1188SPurna Chandra Mandal
135ce6e1188SPurna Chandra Mandal divided_rate = parent_rate / div;
136ce6e1188SPurna Chandra Mandal divided_rate_down = parent_rate / div_up;
137ce6e1188SPurna Chandra Mandal if (abs(rate - divided_rate_down) < abs(rate - divided_rate))
138ce6e1188SPurna Chandra Mandal best_rate = divided_rate_down;
139ce6e1188SPurna Chandra Mandal else
140ce6e1188SPurna Chandra Mandal best_rate = divided_rate;
141ce6e1188SPurna Chandra Mandal
142ce6e1188SPurna Chandra Mandal return best_rate;
143ce6e1188SPurna Chandra Mandal }
144ce6e1188SPurna Chandra Mandal
pbclk_read_pbdiv(struct pic32_periph_clk * pb)145ce6e1188SPurna Chandra Mandal static inline u32 pbclk_read_pbdiv(struct pic32_periph_clk *pb)
146ce6e1188SPurna Chandra Mandal {
147ce6e1188SPurna Chandra Mandal return ((readl(pb->ctrl_reg) >> PB_DIV_SHIFT) & PB_DIV_MASK) + 1;
148ce6e1188SPurna Chandra Mandal }
149ce6e1188SPurna Chandra Mandal
pbclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)150ce6e1188SPurna Chandra Mandal static unsigned long pbclk_recalc_rate(struct clk_hw *hw,
151ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
152ce6e1188SPurna Chandra Mandal {
153ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pb = clkhw_to_pbclk(hw);
154ce6e1188SPurna Chandra Mandal
155ce6e1188SPurna Chandra Mandal return parent_rate / pbclk_read_pbdiv(pb);
156ce6e1188SPurna Chandra Mandal }
157ce6e1188SPurna Chandra Mandal
pbclk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)158ce6e1188SPurna Chandra Mandal static long pbclk_round_rate(struct clk_hw *hw, unsigned long rate,
159ce6e1188SPurna Chandra Mandal unsigned long *parent_rate)
160ce6e1188SPurna Chandra Mandal {
161ce6e1188SPurna Chandra Mandal return calc_best_divided_rate(rate, *parent_rate,
162ce6e1188SPurna Chandra Mandal PB_DIV_MAX, PB_DIV_MIN);
163ce6e1188SPurna Chandra Mandal }
164ce6e1188SPurna Chandra Mandal
pbclk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)165ce6e1188SPurna Chandra Mandal static int pbclk_set_rate(struct clk_hw *hw, unsigned long rate,
166ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
167ce6e1188SPurna Chandra Mandal {
168ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pb = clkhw_to_pbclk(hw);
169ce6e1188SPurna Chandra Mandal unsigned long flags;
170ce6e1188SPurna Chandra Mandal u32 v, div;
171ce6e1188SPurna Chandra Mandal int err;
172ce6e1188SPurna Chandra Mandal
173ce6e1188SPurna Chandra Mandal /* check & wait for DIV_READY */
174ce6e1188SPurna Chandra Mandal err = readl_poll_timeout(pb->ctrl_reg, v, v & PB_DIV_READY,
175ce6e1188SPurna Chandra Mandal 1, LOCK_TIMEOUT_US);
176ce6e1188SPurna Chandra Mandal if (err)
177ce6e1188SPurna Chandra Mandal return err;
178ce6e1188SPurna Chandra Mandal
179ce6e1188SPurna Chandra Mandal /* calculate clkdiv and best rate */
180ce6e1188SPurna Chandra Mandal div = DIV_ROUND_CLOSEST(parent_rate, rate);
181ce6e1188SPurna Chandra Mandal
182ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&pb->core->reg_lock, flags);
183ce6e1188SPurna Chandra Mandal
184ce6e1188SPurna Chandra Mandal /* apply new div */
185ce6e1188SPurna Chandra Mandal v = readl(pb->ctrl_reg);
186ce6e1188SPurna Chandra Mandal v &= ~PB_DIV_MASK;
187ce6e1188SPurna Chandra Mandal v |= (div - 1);
188ce6e1188SPurna Chandra Mandal
189ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
190ce6e1188SPurna Chandra Mandal
191ce6e1188SPurna Chandra Mandal writel(v, pb->ctrl_reg);
192ce6e1188SPurna Chandra Mandal
193ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&pb->core->reg_lock, flags);
194ce6e1188SPurna Chandra Mandal
19512f53b24SPurna Chandra Mandal /* wait again for DIV_READY */
19612f53b24SPurna Chandra Mandal err = readl_poll_timeout(pb->ctrl_reg, v, v & PB_DIV_READY,
197ce6e1188SPurna Chandra Mandal 1, LOCK_TIMEOUT_US);
198ce6e1188SPurna Chandra Mandal if (err)
199ce6e1188SPurna Chandra Mandal return err;
200ce6e1188SPurna Chandra Mandal
201ce6e1188SPurna Chandra Mandal /* confirm that new div is applied correctly */
202ce6e1188SPurna Chandra Mandal return (pbclk_read_pbdiv(pb) == div) ? 0 : -EBUSY;
203ce6e1188SPurna Chandra Mandal }
204ce6e1188SPurna Chandra Mandal
205ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_pbclk_ops = {
206ce6e1188SPurna Chandra Mandal .enable = pbclk_enable,
207ce6e1188SPurna Chandra Mandal .disable = pbclk_disable,
208ce6e1188SPurna Chandra Mandal .is_enabled = pbclk_is_enabled,
209ce6e1188SPurna Chandra Mandal .recalc_rate = pbclk_recalc_rate,
210ce6e1188SPurna Chandra Mandal .round_rate = pbclk_round_rate,
211ce6e1188SPurna Chandra Mandal .set_rate = pbclk_set_rate,
212ce6e1188SPurna Chandra Mandal };
213ce6e1188SPurna Chandra Mandal
pic32_periph_clk_register(const struct pic32_periph_clk_data * desc,struct pic32_clk_common * core)214ce6e1188SPurna Chandra Mandal struct clk *pic32_periph_clk_register(const struct pic32_periph_clk_data *desc,
215ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core)
216ce6e1188SPurna Chandra Mandal {
217ce6e1188SPurna Chandra Mandal struct pic32_periph_clk *pbclk;
218ce6e1188SPurna Chandra Mandal struct clk *clk;
219ce6e1188SPurna Chandra Mandal
220ce6e1188SPurna Chandra Mandal pbclk = devm_kzalloc(core->dev, sizeof(*pbclk), GFP_KERNEL);
221ce6e1188SPurna Chandra Mandal if (!pbclk)
222ce6e1188SPurna Chandra Mandal return ERR_PTR(-ENOMEM);
223ce6e1188SPurna Chandra Mandal
224ce6e1188SPurna Chandra Mandal pbclk->hw.init = &desc->init_data;
225ce6e1188SPurna Chandra Mandal pbclk->core = core;
226ce6e1188SPurna Chandra Mandal pbclk->ctrl_reg = desc->ctrl_reg + core->iobase;
227ce6e1188SPurna Chandra Mandal
228ce6e1188SPurna Chandra Mandal clk = devm_clk_register(core->dev, &pbclk->hw);
229ce6e1188SPurna Chandra Mandal if (IS_ERR(clk)) {
230ce6e1188SPurna Chandra Mandal dev_err(core->dev, "%s: clk_register() failed\n", __func__);
231ce6e1188SPurna Chandra Mandal devm_kfree(core->dev, pbclk);
232ce6e1188SPurna Chandra Mandal }
233ce6e1188SPurna Chandra Mandal
234ce6e1188SPurna Chandra Mandal return clk;
235ce6e1188SPurna Chandra Mandal }
236ce6e1188SPurna Chandra Mandal
237ce6e1188SPurna Chandra Mandal /* Reference oscillator operations */
238ce6e1188SPurna Chandra Mandal struct pic32_ref_osc {
239ce6e1188SPurna Chandra Mandal struct clk_hw hw;
240ce6e1188SPurna Chandra Mandal void __iomem *ctrl_reg;
241ce6e1188SPurna Chandra Mandal const u32 *parent_map;
242ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core;
243ce6e1188SPurna Chandra Mandal };
244ce6e1188SPurna Chandra Mandal
245ce6e1188SPurna Chandra Mandal #define clkhw_to_refosc(_hw) container_of(_hw, struct pic32_ref_osc, hw)
246ce6e1188SPurna Chandra Mandal
roclk_is_enabled(struct clk_hw * hw)247ce6e1188SPurna Chandra Mandal static int roclk_is_enabled(struct clk_hw *hw)
248ce6e1188SPurna Chandra Mandal {
249ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
250ce6e1188SPurna Chandra Mandal
251ce6e1188SPurna Chandra Mandal return readl(refo->ctrl_reg) & REFO_ON;
252ce6e1188SPurna Chandra Mandal }
253ce6e1188SPurna Chandra Mandal
roclk_enable(struct clk_hw * hw)254ce6e1188SPurna Chandra Mandal static int roclk_enable(struct clk_hw *hw)
255ce6e1188SPurna Chandra Mandal {
256ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
257ce6e1188SPurna Chandra Mandal
258ce6e1188SPurna Chandra Mandal writel(REFO_ON | REFO_OE, PIC32_SET(refo->ctrl_reg));
259ce6e1188SPurna Chandra Mandal return 0;
260ce6e1188SPurna Chandra Mandal }
261ce6e1188SPurna Chandra Mandal
roclk_disable(struct clk_hw * hw)262ce6e1188SPurna Chandra Mandal static void roclk_disable(struct clk_hw *hw)
263ce6e1188SPurna Chandra Mandal {
264ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
265ce6e1188SPurna Chandra Mandal
266ce6e1188SPurna Chandra Mandal writel(REFO_ON | REFO_OE, PIC32_CLR(refo->ctrl_reg));
267ce6e1188SPurna Chandra Mandal }
268ce6e1188SPurna Chandra Mandal
roclk_init(struct clk_hw * hw)269*89d079dcSJerome Brunet static int roclk_init(struct clk_hw *hw)
270ce6e1188SPurna Chandra Mandal {
271ce6e1188SPurna Chandra Mandal /* initialize clock in disabled state */
272ce6e1188SPurna Chandra Mandal roclk_disable(hw);
273*89d079dcSJerome Brunet
274*89d079dcSJerome Brunet return 0;
275ce6e1188SPurna Chandra Mandal }
276ce6e1188SPurna Chandra Mandal
roclk_get_parent(struct clk_hw * hw)277ce6e1188SPurna Chandra Mandal static u8 roclk_get_parent(struct clk_hw *hw)
278ce6e1188SPurna Chandra Mandal {
279ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
280ce6e1188SPurna Chandra Mandal u32 v, i;
281ce6e1188SPurna Chandra Mandal
282ce6e1188SPurna Chandra Mandal v = (readl(refo->ctrl_reg) >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
283ce6e1188SPurna Chandra Mandal
284ce6e1188SPurna Chandra Mandal if (!refo->parent_map)
285ce6e1188SPurna Chandra Mandal return v;
286ce6e1188SPurna Chandra Mandal
287ce6e1188SPurna Chandra Mandal for (i = 0; i < clk_hw_get_num_parents(hw); i++)
288ce6e1188SPurna Chandra Mandal if (refo->parent_map[i] == v)
289ce6e1188SPurna Chandra Mandal return i;
290ce6e1188SPurna Chandra Mandal
291ce6e1188SPurna Chandra Mandal return -EINVAL;
292ce6e1188SPurna Chandra Mandal }
293ce6e1188SPurna Chandra Mandal
roclk_calc_rate(unsigned long parent_rate,u32 rodiv,u32 rotrim)294ce6e1188SPurna Chandra Mandal static unsigned long roclk_calc_rate(unsigned long parent_rate,
295ce6e1188SPurna Chandra Mandal u32 rodiv, u32 rotrim)
296ce6e1188SPurna Chandra Mandal {
297ce6e1188SPurna Chandra Mandal u64 rate64;
298ce6e1188SPurna Chandra Mandal
299ce6e1188SPurna Chandra Mandal /* fout = fin / [2 * {div + (trim / 512)}]
300ce6e1188SPurna Chandra Mandal * = fin * 512 / [1024 * div + 2 * trim]
301ce6e1188SPurna Chandra Mandal * = fin * 256 / (512 * div + trim)
302ce6e1188SPurna Chandra Mandal * = (fin << 8) / ((div << 9) + trim)
303ce6e1188SPurna Chandra Mandal */
304ce6e1188SPurna Chandra Mandal if (rotrim) {
305ce6e1188SPurna Chandra Mandal rodiv = (rodiv << 9) + rotrim;
306ce6e1188SPurna Chandra Mandal rate64 = parent_rate;
307ce6e1188SPurna Chandra Mandal rate64 <<= 8;
308ce6e1188SPurna Chandra Mandal do_div(rate64, rodiv);
309ce6e1188SPurna Chandra Mandal } else if (rodiv) {
310ce6e1188SPurna Chandra Mandal rate64 = parent_rate / (rodiv << 1);
311ce6e1188SPurna Chandra Mandal } else {
312ce6e1188SPurna Chandra Mandal rate64 = parent_rate;
313ce6e1188SPurna Chandra Mandal }
314ce6e1188SPurna Chandra Mandal return rate64;
315ce6e1188SPurna Chandra Mandal }
316ce6e1188SPurna Chandra Mandal
roclk_calc_div_trim(unsigned long rate,unsigned long parent_rate,u32 * rodiv_p,u32 * rotrim_p)317ce6e1188SPurna Chandra Mandal static void roclk_calc_div_trim(unsigned long rate,
318ce6e1188SPurna Chandra Mandal unsigned long parent_rate,
319ce6e1188SPurna Chandra Mandal u32 *rodiv_p, u32 *rotrim_p)
320ce6e1188SPurna Chandra Mandal {
321ce6e1188SPurna Chandra Mandal u32 div, rotrim, rodiv;
322ce6e1188SPurna Chandra Mandal u64 frac;
323ce6e1188SPurna Chandra Mandal
324ce6e1188SPurna Chandra Mandal /* Find integer approximation of floating-point arithmetic.
325ce6e1188SPurna Chandra Mandal * fout = fin / [2 * {rodiv + (rotrim / 512)}] ... (1)
326ce6e1188SPurna Chandra Mandal * i.e. fout = fin / 2 * DIV
327ce6e1188SPurna Chandra Mandal * whereas DIV = rodiv + (rotrim / 512)
328ce6e1188SPurna Chandra Mandal *
329ce6e1188SPurna Chandra Mandal * Since kernel does not perform floating-point arithmatic so
330ce6e1188SPurna Chandra Mandal * (rotrim/512) will be zero. And DIV & rodiv will result same.
331ce6e1188SPurna Chandra Mandal *
332ce6e1188SPurna Chandra Mandal * ie. fout = (fin * 256) / [(512 * rodiv) + rotrim] ... from (1)
333ce6e1188SPurna Chandra Mandal * ie. rotrim = ((fin * 256) / fout) - (512 * DIV)
334ce6e1188SPurna Chandra Mandal */
335ce6e1188SPurna Chandra Mandal if (parent_rate <= rate) {
336ce6e1188SPurna Chandra Mandal div = 0;
337ce6e1188SPurna Chandra Mandal frac = 0;
338ce6e1188SPurna Chandra Mandal rodiv = 0;
339ce6e1188SPurna Chandra Mandal rotrim = 0;
340ce6e1188SPurna Chandra Mandal } else {
341ce6e1188SPurna Chandra Mandal div = parent_rate / (rate << 1);
342ce6e1188SPurna Chandra Mandal frac = parent_rate;
343ce6e1188SPurna Chandra Mandal frac <<= 8;
344ce6e1188SPurna Chandra Mandal do_div(frac, rate);
345ce6e1188SPurna Chandra Mandal frac -= (u64)(div << 9);
346ce6e1188SPurna Chandra Mandal
347ce6e1188SPurna Chandra Mandal rodiv = (div > REFO_DIV_MASK) ? REFO_DIV_MASK : div;
348ce6e1188SPurna Chandra Mandal rotrim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : frac;
349ce6e1188SPurna Chandra Mandal }
350ce6e1188SPurna Chandra Mandal
351ce6e1188SPurna Chandra Mandal if (rodiv_p)
352ce6e1188SPurna Chandra Mandal *rodiv_p = rodiv;
353ce6e1188SPurna Chandra Mandal
354ce6e1188SPurna Chandra Mandal if (rotrim_p)
355ce6e1188SPurna Chandra Mandal *rotrim_p = rotrim;
356ce6e1188SPurna Chandra Mandal }
357ce6e1188SPurna Chandra Mandal
roclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)358ce6e1188SPurna Chandra Mandal static unsigned long roclk_recalc_rate(struct clk_hw *hw,
359ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
360ce6e1188SPurna Chandra Mandal {
361ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
362ce6e1188SPurna Chandra Mandal u32 v, rodiv, rotrim;
363ce6e1188SPurna Chandra Mandal
364ce6e1188SPurna Chandra Mandal /* get rodiv */
365ce6e1188SPurna Chandra Mandal v = readl(refo->ctrl_reg);
366ce6e1188SPurna Chandra Mandal rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
367ce6e1188SPurna Chandra Mandal
368ce6e1188SPurna Chandra Mandal /* get trim */
369ce6e1188SPurna Chandra Mandal v = readl(refo->ctrl_reg + REFO_TRIM_REG);
370ce6e1188SPurna Chandra Mandal rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
371ce6e1188SPurna Chandra Mandal
372ce6e1188SPurna Chandra Mandal return roclk_calc_rate(parent_rate, rodiv, rotrim);
373ce6e1188SPurna Chandra Mandal }
374ce6e1188SPurna Chandra Mandal
roclk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)375ce6e1188SPurna Chandra Mandal static long roclk_round_rate(struct clk_hw *hw, unsigned long rate,
376ce6e1188SPurna Chandra Mandal unsigned long *parent_rate)
377ce6e1188SPurna Chandra Mandal {
378ce6e1188SPurna Chandra Mandal u32 rotrim, rodiv;
379ce6e1188SPurna Chandra Mandal
380ce6e1188SPurna Chandra Mandal /* calculate dividers for new rate */
381ce6e1188SPurna Chandra Mandal roclk_calc_div_trim(rate, *parent_rate, &rodiv, &rotrim);
382ce6e1188SPurna Chandra Mandal
383ce6e1188SPurna Chandra Mandal /* caclulate new rate (rounding) based on new rodiv & rotrim */
384ce6e1188SPurna Chandra Mandal return roclk_calc_rate(*parent_rate, rodiv, rotrim);
385ce6e1188SPurna Chandra Mandal }
386ce6e1188SPurna Chandra Mandal
roclk_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)387ce6e1188SPurna Chandra Mandal static int roclk_determine_rate(struct clk_hw *hw,
388ce6e1188SPurna Chandra Mandal struct clk_rate_request *req)
389ce6e1188SPurna Chandra Mandal {
390ce6e1188SPurna Chandra Mandal struct clk_hw *parent_clk, *best_parent_clk = NULL;
391ce6e1188SPurna Chandra Mandal unsigned int i, delta, best_delta = -1;
392ce6e1188SPurna Chandra Mandal unsigned long parent_rate, best_parent_rate = 0;
393ce6e1188SPurna Chandra Mandal unsigned long best = 0, nearest_rate;
394ce6e1188SPurna Chandra Mandal
395ce6e1188SPurna Chandra Mandal /* find a parent which can generate nearest clkrate >= rate */
396ce6e1188SPurna Chandra Mandal for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
397ce6e1188SPurna Chandra Mandal /* get parent */
398ce6e1188SPurna Chandra Mandal parent_clk = clk_hw_get_parent_by_index(hw, i);
399ce6e1188SPurna Chandra Mandal if (!parent_clk)
400ce6e1188SPurna Chandra Mandal continue;
401ce6e1188SPurna Chandra Mandal
402ce6e1188SPurna Chandra Mandal /* skip if parent runs slower than target rate */
403ce6e1188SPurna Chandra Mandal parent_rate = clk_hw_get_rate(parent_clk);
404ce6e1188SPurna Chandra Mandal if (req->rate > parent_rate)
405ce6e1188SPurna Chandra Mandal continue;
406ce6e1188SPurna Chandra Mandal
407ce6e1188SPurna Chandra Mandal nearest_rate = roclk_round_rate(hw, req->rate, &parent_rate);
408ce6e1188SPurna Chandra Mandal delta = abs(nearest_rate - req->rate);
409ce6e1188SPurna Chandra Mandal if ((nearest_rate >= req->rate) && (delta < best_delta)) {
410ce6e1188SPurna Chandra Mandal best_parent_clk = parent_clk;
411ce6e1188SPurna Chandra Mandal best_parent_rate = parent_rate;
412ce6e1188SPurna Chandra Mandal best = nearest_rate;
413ce6e1188SPurna Chandra Mandal best_delta = delta;
414ce6e1188SPurna Chandra Mandal
415ce6e1188SPurna Chandra Mandal if (delta == 0)
416ce6e1188SPurna Chandra Mandal break;
417ce6e1188SPurna Chandra Mandal }
418ce6e1188SPurna Chandra Mandal }
419ce6e1188SPurna Chandra Mandal
420ce6e1188SPurna Chandra Mandal /* if no match found, retain old rate */
421ce6e1188SPurna Chandra Mandal if (!best_parent_clk) {
422ce6e1188SPurna Chandra Mandal pr_err("%s:%s, no parent found for rate %lu.\n",
423ce6e1188SPurna Chandra Mandal __func__, clk_hw_get_name(hw), req->rate);
424ce6e1188SPurna Chandra Mandal return clk_hw_get_rate(hw);
425ce6e1188SPurna Chandra Mandal }
426ce6e1188SPurna Chandra Mandal
427ce6e1188SPurna Chandra Mandal pr_debug("%s,rate %lu, best_parent(%s, %lu), best %lu, delta %d\n",
428ce6e1188SPurna Chandra Mandal clk_hw_get_name(hw), req->rate,
429ce6e1188SPurna Chandra Mandal clk_hw_get_name(best_parent_clk), best_parent_rate,
430ce6e1188SPurna Chandra Mandal best, best_delta);
431ce6e1188SPurna Chandra Mandal
432ce6e1188SPurna Chandra Mandal if (req->best_parent_rate)
433ce6e1188SPurna Chandra Mandal req->best_parent_rate = best_parent_rate;
434ce6e1188SPurna Chandra Mandal
435ce6e1188SPurna Chandra Mandal if (req->best_parent_hw)
436ce6e1188SPurna Chandra Mandal req->best_parent_hw = best_parent_clk;
437ce6e1188SPurna Chandra Mandal
438ce6e1188SPurna Chandra Mandal return best;
439ce6e1188SPurna Chandra Mandal }
440ce6e1188SPurna Chandra Mandal
roclk_set_parent(struct clk_hw * hw,u8 index)441ce6e1188SPurna Chandra Mandal static int roclk_set_parent(struct clk_hw *hw, u8 index)
442ce6e1188SPurna Chandra Mandal {
443ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
444ce6e1188SPurna Chandra Mandal unsigned long flags;
445ce6e1188SPurna Chandra Mandal u32 v;
446ce6e1188SPurna Chandra Mandal int err;
447ce6e1188SPurna Chandra Mandal
448ce6e1188SPurna Chandra Mandal if (refo->parent_map)
449ce6e1188SPurna Chandra Mandal index = refo->parent_map[index];
450ce6e1188SPurna Chandra Mandal
451ce6e1188SPurna Chandra Mandal /* wait until ACTIVE bit is zero or timeout */
452ce6e1188SPurna Chandra Mandal err = readl_poll_timeout(refo->ctrl_reg, v, !(v & REFO_ACTIVE),
453ce6e1188SPurna Chandra Mandal 1, LOCK_TIMEOUT_US);
454ce6e1188SPurna Chandra Mandal if (err) {
455ce6e1188SPurna Chandra Mandal pr_err("%s: poll failed, clk active\n", clk_hw_get_name(hw));
456ce6e1188SPurna Chandra Mandal return err;
457ce6e1188SPurna Chandra Mandal }
458ce6e1188SPurna Chandra Mandal
459ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&refo->core->reg_lock, flags);
460ce6e1188SPurna Chandra Mandal
461ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
462ce6e1188SPurna Chandra Mandal
463ce6e1188SPurna Chandra Mandal /* calculate & apply new */
464ce6e1188SPurna Chandra Mandal v = readl(refo->ctrl_reg);
465ce6e1188SPurna Chandra Mandal v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
466ce6e1188SPurna Chandra Mandal v |= index << REFO_SEL_SHIFT;
467ce6e1188SPurna Chandra Mandal
468ce6e1188SPurna Chandra Mandal writel(v, refo->ctrl_reg);
469ce6e1188SPurna Chandra Mandal
470ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&refo->core->reg_lock, flags);
471ce6e1188SPurna Chandra Mandal
472ce6e1188SPurna Chandra Mandal return 0;
473ce6e1188SPurna Chandra Mandal }
474ce6e1188SPurna Chandra Mandal
roclk_set_rate_and_parent(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate,u8 index)475ce6e1188SPurna Chandra Mandal static int roclk_set_rate_and_parent(struct clk_hw *hw,
476ce6e1188SPurna Chandra Mandal unsigned long rate,
477ce6e1188SPurna Chandra Mandal unsigned long parent_rate,
478ce6e1188SPurna Chandra Mandal u8 index)
479ce6e1188SPurna Chandra Mandal {
480ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo = clkhw_to_refosc(hw);
481ce6e1188SPurna Chandra Mandal unsigned long flags;
482ce6e1188SPurna Chandra Mandal u32 trim, rodiv, v;
483ce6e1188SPurna Chandra Mandal int err;
484ce6e1188SPurna Chandra Mandal
485ce6e1188SPurna Chandra Mandal /* calculate new rodiv & rotrim for new rate */
486ce6e1188SPurna Chandra Mandal roclk_calc_div_trim(rate, parent_rate, &rodiv, &trim);
487ce6e1188SPurna Chandra Mandal
488ce6e1188SPurna Chandra Mandal pr_debug("parent_rate = %lu, rate = %lu, div = %d, trim = %d\n",
489ce6e1188SPurna Chandra Mandal parent_rate, rate, rodiv, trim);
490ce6e1188SPurna Chandra Mandal
491ce6e1188SPurna Chandra Mandal /* wait till source change is active */
492ce6e1188SPurna Chandra Mandal err = readl_poll_timeout(refo->ctrl_reg, v,
493ce6e1188SPurna Chandra Mandal !(v & (REFO_ACTIVE | REFO_DIVSW_EN)),
494ce6e1188SPurna Chandra Mandal 1, LOCK_TIMEOUT_US);
495ce6e1188SPurna Chandra Mandal if (err) {
496ce6e1188SPurna Chandra Mandal pr_err("%s: poll timedout, clock is still active\n", __func__);
497ce6e1188SPurna Chandra Mandal return err;
498ce6e1188SPurna Chandra Mandal }
499ce6e1188SPurna Chandra Mandal
500ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&refo->core->reg_lock, flags);
501ce6e1188SPurna Chandra Mandal v = readl(refo->ctrl_reg);
502ce6e1188SPurna Chandra Mandal
503ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
504ce6e1188SPurna Chandra Mandal
505ce6e1188SPurna Chandra Mandal /* apply parent, if required */
506ce6e1188SPurna Chandra Mandal if (refo->parent_map)
507ce6e1188SPurna Chandra Mandal index = refo->parent_map[index];
508ce6e1188SPurna Chandra Mandal
509ce6e1188SPurna Chandra Mandal v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
510ce6e1188SPurna Chandra Mandal v |= index << REFO_SEL_SHIFT;
511ce6e1188SPurna Chandra Mandal
512ce6e1188SPurna Chandra Mandal /* apply RODIV */
513ce6e1188SPurna Chandra Mandal v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
514ce6e1188SPurna Chandra Mandal v |= rodiv << REFO_DIV_SHIFT;
515ce6e1188SPurna Chandra Mandal writel(v, refo->ctrl_reg);
516ce6e1188SPurna Chandra Mandal
517ce6e1188SPurna Chandra Mandal /* apply ROTRIM */
518ce6e1188SPurna Chandra Mandal v = readl(refo->ctrl_reg + REFO_TRIM_REG);
519ce6e1188SPurna Chandra Mandal v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
520ce6e1188SPurna Chandra Mandal v |= trim << REFO_TRIM_SHIFT;
521ce6e1188SPurna Chandra Mandal writel(v, refo->ctrl_reg + REFO_TRIM_REG);
522ce6e1188SPurna Chandra Mandal
523ce6e1188SPurna Chandra Mandal /* enable & activate divider switching */
524ce6e1188SPurna Chandra Mandal writel(REFO_ON | REFO_DIVSW_EN, PIC32_SET(refo->ctrl_reg));
525ce6e1188SPurna Chandra Mandal
526ce6e1188SPurna Chandra Mandal /* wait till divswen is in-progress */
527ce6e1188SPurna Chandra Mandal err = readl_poll_timeout_atomic(refo->ctrl_reg, v, !(v & REFO_DIVSW_EN),
528ce6e1188SPurna Chandra Mandal 1, LOCK_TIMEOUT_US);
529ce6e1188SPurna Chandra Mandal /* leave the clk gated as it was */
530ce6e1188SPurna Chandra Mandal writel(REFO_ON, PIC32_CLR(refo->ctrl_reg));
531ce6e1188SPurna Chandra Mandal
532ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&refo->core->reg_lock, flags);
533ce6e1188SPurna Chandra Mandal
534ce6e1188SPurna Chandra Mandal return err;
535ce6e1188SPurna Chandra Mandal }
536ce6e1188SPurna Chandra Mandal
roclk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)537ce6e1188SPurna Chandra Mandal static int roclk_set_rate(struct clk_hw *hw, unsigned long rate,
538ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
539ce6e1188SPurna Chandra Mandal {
540ce6e1188SPurna Chandra Mandal u8 index = roclk_get_parent(hw);
541ce6e1188SPurna Chandra Mandal
542ce6e1188SPurna Chandra Mandal return roclk_set_rate_and_parent(hw, rate, parent_rate, index);
543ce6e1188SPurna Chandra Mandal }
544ce6e1188SPurna Chandra Mandal
545ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_roclk_ops = {
546ce6e1188SPurna Chandra Mandal .enable = roclk_enable,
547ce6e1188SPurna Chandra Mandal .disable = roclk_disable,
548ce6e1188SPurna Chandra Mandal .is_enabled = roclk_is_enabled,
549ce6e1188SPurna Chandra Mandal .get_parent = roclk_get_parent,
550ce6e1188SPurna Chandra Mandal .set_parent = roclk_set_parent,
551ce6e1188SPurna Chandra Mandal .determine_rate = roclk_determine_rate,
552ce6e1188SPurna Chandra Mandal .recalc_rate = roclk_recalc_rate,
553ce6e1188SPurna Chandra Mandal .set_rate_and_parent = roclk_set_rate_and_parent,
554ce6e1188SPurna Chandra Mandal .set_rate = roclk_set_rate,
555ce6e1188SPurna Chandra Mandal .init = roclk_init,
556ce6e1188SPurna Chandra Mandal };
557ce6e1188SPurna Chandra Mandal
pic32_refo_clk_register(const struct pic32_ref_osc_data * data,struct pic32_clk_common * core)558ce6e1188SPurna Chandra Mandal struct clk *pic32_refo_clk_register(const struct pic32_ref_osc_data *data,
559ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core)
560ce6e1188SPurna Chandra Mandal {
561ce6e1188SPurna Chandra Mandal struct pic32_ref_osc *refo;
562ce6e1188SPurna Chandra Mandal struct clk *clk;
563ce6e1188SPurna Chandra Mandal
564ce6e1188SPurna Chandra Mandal refo = devm_kzalloc(core->dev, sizeof(*refo), GFP_KERNEL);
565ce6e1188SPurna Chandra Mandal if (!refo)
566ce6e1188SPurna Chandra Mandal return ERR_PTR(-ENOMEM);
567ce6e1188SPurna Chandra Mandal
568ce6e1188SPurna Chandra Mandal refo->core = core;
569ce6e1188SPurna Chandra Mandal refo->hw.init = &data->init_data;
570ce6e1188SPurna Chandra Mandal refo->ctrl_reg = data->ctrl_reg + core->iobase;
571ce6e1188SPurna Chandra Mandal refo->parent_map = data->parent_map;
572ce6e1188SPurna Chandra Mandal
573ce6e1188SPurna Chandra Mandal clk = devm_clk_register(core->dev, &refo->hw);
574ce6e1188SPurna Chandra Mandal if (IS_ERR(clk))
575ce6e1188SPurna Chandra Mandal dev_err(core->dev, "%s: clk_register() failed\n", __func__);
576ce6e1188SPurna Chandra Mandal
577ce6e1188SPurna Chandra Mandal return clk;
578ce6e1188SPurna Chandra Mandal }
579ce6e1188SPurna Chandra Mandal
580ce6e1188SPurna Chandra Mandal struct pic32_sys_pll {
581ce6e1188SPurna Chandra Mandal struct clk_hw hw;
582ce6e1188SPurna Chandra Mandal void __iomem *ctrl_reg;
583ce6e1188SPurna Chandra Mandal void __iomem *status_reg;
584ce6e1188SPurna Chandra Mandal u32 lock_mask;
585ce6e1188SPurna Chandra Mandal u32 idiv; /* PLL iclk divider, treated fixed */
586ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core;
587ce6e1188SPurna Chandra Mandal };
588ce6e1188SPurna Chandra Mandal
589ce6e1188SPurna Chandra Mandal #define clkhw_to_spll(_hw) container_of(_hw, struct pic32_sys_pll, hw)
590ce6e1188SPurna Chandra Mandal
spll_odiv_to_divider(u32 odiv)591ce6e1188SPurna Chandra Mandal static inline u32 spll_odiv_to_divider(u32 odiv)
592ce6e1188SPurna Chandra Mandal {
593ce6e1188SPurna Chandra Mandal odiv = clamp_val(odiv, PLL_ODIV_MIN, PLL_ODIV_MAX);
594ce6e1188SPurna Chandra Mandal
595ce6e1188SPurna Chandra Mandal return 1 << odiv;
596ce6e1188SPurna Chandra Mandal }
597ce6e1188SPurna Chandra Mandal
spll_calc_mult_div(struct pic32_sys_pll * pll,unsigned long rate,unsigned long parent_rate,u32 * mult_p,u32 * odiv_p)598ce6e1188SPurna Chandra Mandal static unsigned long spll_calc_mult_div(struct pic32_sys_pll *pll,
599ce6e1188SPurna Chandra Mandal unsigned long rate,
600ce6e1188SPurna Chandra Mandal unsigned long parent_rate,
601ce6e1188SPurna Chandra Mandal u32 *mult_p, u32 *odiv_p)
602ce6e1188SPurna Chandra Mandal {
603ce6e1188SPurna Chandra Mandal u32 mul, div, best_mul = 1, best_div = 1;
604ce6e1188SPurna Chandra Mandal unsigned long new_rate, best_rate = rate;
605ce6e1188SPurna Chandra Mandal unsigned int best_delta = -1, delta, match_found = 0;
606ce6e1188SPurna Chandra Mandal u64 rate64;
607ce6e1188SPurna Chandra Mandal
608ce6e1188SPurna Chandra Mandal parent_rate /= pll->idiv;
609ce6e1188SPurna Chandra Mandal
610ce6e1188SPurna Chandra Mandal for (mul = 1; mul <= PLL_MULT_MAX; mul++) {
611ce6e1188SPurna Chandra Mandal for (div = PLL_ODIV_MIN; div <= PLL_ODIV_MAX; div++) {
612ce6e1188SPurna Chandra Mandal rate64 = parent_rate;
613ce6e1188SPurna Chandra Mandal rate64 *= mul;
614ce6e1188SPurna Chandra Mandal do_div(rate64, 1 << div);
615ce6e1188SPurna Chandra Mandal new_rate = rate64;
616ce6e1188SPurna Chandra Mandal delta = abs(rate - new_rate);
617ce6e1188SPurna Chandra Mandal if ((new_rate >= rate) && (delta < best_delta)) {
618ce6e1188SPurna Chandra Mandal best_delta = delta;
619ce6e1188SPurna Chandra Mandal best_rate = new_rate;
620ce6e1188SPurna Chandra Mandal best_mul = mul;
621ce6e1188SPurna Chandra Mandal best_div = div;
622ce6e1188SPurna Chandra Mandal match_found = 1;
623ce6e1188SPurna Chandra Mandal }
624ce6e1188SPurna Chandra Mandal }
625ce6e1188SPurna Chandra Mandal }
626ce6e1188SPurna Chandra Mandal
627ce6e1188SPurna Chandra Mandal if (!match_found) {
628ce6e1188SPurna Chandra Mandal pr_warn("spll: no match found\n");
629ce6e1188SPurna Chandra Mandal return 0;
630ce6e1188SPurna Chandra Mandal }
631ce6e1188SPurna Chandra Mandal
632ce6e1188SPurna Chandra Mandal pr_debug("rate %lu, par_rate %lu/mult %u, div %u, best_rate %lu\n",
633ce6e1188SPurna Chandra Mandal rate, parent_rate, best_mul, best_div, best_rate);
634ce6e1188SPurna Chandra Mandal
635ce6e1188SPurna Chandra Mandal if (mult_p)
636ce6e1188SPurna Chandra Mandal *mult_p = best_mul - 1;
637ce6e1188SPurna Chandra Mandal
638ce6e1188SPurna Chandra Mandal if (odiv_p)
639ce6e1188SPurna Chandra Mandal *odiv_p = best_div;
640ce6e1188SPurna Chandra Mandal
641ce6e1188SPurna Chandra Mandal return best_rate;
642ce6e1188SPurna Chandra Mandal }
643ce6e1188SPurna Chandra Mandal
spll_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)644ce6e1188SPurna Chandra Mandal static unsigned long spll_clk_recalc_rate(struct clk_hw *hw,
645ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
646ce6e1188SPurna Chandra Mandal {
647ce6e1188SPurna Chandra Mandal struct pic32_sys_pll *pll = clkhw_to_spll(hw);
648ce6e1188SPurna Chandra Mandal unsigned long pll_in_rate;
649ce6e1188SPurna Chandra Mandal u32 mult, odiv, div, v;
650ce6e1188SPurna Chandra Mandal u64 rate64;
651ce6e1188SPurna Chandra Mandal
652ce6e1188SPurna Chandra Mandal v = readl(pll->ctrl_reg);
653ce6e1188SPurna Chandra Mandal odiv = ((v >> PLL_ODIV_SHIFT) & PLL_ODIV_MASK);
654ce6e1188SPurna Chandra Mandal mult = ((v >> PLL_MULT_SHIFT) & PLL_MULT_MASK) + 1;
655ce6e1188SPurna Chandra Mandal div = spll_odiv_to_divider(odiv);
656ce6e1188SPurna Chandra Mandal
657ce6e1188SPurna Chandra Mandal /* pll_in_rate = parent_rate / idiv
658ce6e1188SPurna Chandra Mandal * pll_out_rate = pll_in_rate * mult / div;
659ce6e1188SPurna Chandra Mandal */
660ce6e1188SPurna Chandra Mandal pll_in_rate = parent_rate / pll->idiv;
661ce6e1188SPurna Chandra Mandal rate64 = pll_in_rate;
662ce6e1188SPurna Chandra Mandal rate64 *= mult;
663ce6e1188SPurna Chandra Mandal do_div(rate64, div);
664ce6e1188SPurna Chandra Mandal
665ce6e1188SPurna Chandra Mandal return rate64;
666ce6e1188SPurna Chandra Mandal }
667ce6e1188SPurna Chandra Mandal
spll_clk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)668ce6e1188SPurna Chandra Mandal static long spll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
669ce6e1188SPurna Chandra Mandal unsigned long *parent_rate)
670ce6e1188SPurna Chandra Mandal {
671ce6e1188SPurna Chandra Mandal struct pic32_sys_pll *pll = clkhw_to_spll(hw);
672ce6e1188SPurna Chandra Mandal
673ce6e1188SPurna Chandra Mandal return spll_calc_mult_div(pll, rate, *parent_rate, NULL, NULL);
674ce6e1188SPurna Chandra Mandal }
675ce6e1188SPurna Chandra Mandal
spll_clk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)676ce6e1188SPurna Chandra Mandal static int spll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
677ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
678ce6e1188SPurna Chandra Mandal {
679ce6e1188SPurna Chandra Mandal struct pic32_sys_pll *pll = clkhw_to_spll(hw);
680ce6e1188SPurna Chandra Mandal unsigned long ret, flags;
681ce6e1188SPurna Chandra Mandal u32 mult, odiv, v;
682ce6e1188SPurna Chandra Mandal int err;
683ce6e1188SPurna Chandra Mandal
684ce6e1188SPurna Chandra Mandal ret = spll_calc_mult_div(pll, rate, parent_rate, &mult, &odiv);
685ce6e1188SPurna Chandra Mandal if (!ret)
686ce6e1188SPurna Chandra Mandal return -EINVAL;
687ce6e1188SPurna Chandra Mandal
688ce6e1188SPurna Chandra Mandal /*
689ce6e1188SPurna Chandra Mandal * We can't change SPLL counters when it is in-active use
690ce6e1188SPurna Chandra Mandal * by SYSCLK. So check before applying new counters/rate.
691ce6e1188SPurna Chandra Mandal */
692ce6e1188SPurna Chandra Mandal
693ce6e1188SPurna Chandra Mandal /* Is spll_clk active parent of sys_clk ? */
694ce6e1188SPurna Chandra Mandal if (unlikely(clk_hw_get_parent(pic32_sclk_hw) == hw)) {
695ce6e1188SPurna Chandra Mandal pr_err("%s: failed, clk in-use\n", __func__);
696ce6e1188SPurna Chandra Mandal return -EBUSY;
697ce6e1188SPurna Chandra Mandal }
698ce6e1188SPurna Chandra Mandal
699ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&pll->core->reg_lock, flags);
700ce6e1188SPurna Chandra Mandal
701ce6e1188SPurna Chandra Mandal /* apply new multiplier & divisor */
702ce6e1188SPurna Chandra Mandal v = readl(pll->ctrl_reg);
703ce6e1188SPurna Chandra Mandal v &= ~(PLL_MULT_MASK << PLL_MULT_SHIFT);
704ce6e1188SPurna Chandra Mandal v &= ~(PLL_ODIV_MASK << PLL_ODIV_SHIFT);
705ce6e1188SPurna Chandra Mandal v |= (mult << PLL_MULT_SHIFT) | (odiv << PLL_ODIV_SHIFT);
706ce6e1188SPurna Chandra Mandal
707ce6e1188SPurna Chandra Mandal /* sys unlock before write */
708ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
709ce6e1188SPurna Chandra Mandal
710ce6e1188SPurna Chandra Mandal writel(v, pll->ctrl_reg);
711ce6e1188SPurna Chandra Mandal cpu_relax();
712ce6e1188SPurna Chandra Mandal
713ce6e1188SPurna Chandra Mandal /* insert few nops (5-stage) to ensure CPU does not hang */
714ce6e1188SPurna Chandra Mandal cpu_nop5();
715ce6e1188SPurna Chandra Mandal cpu_nop5();
716ce6e1188SPurna Chandra Mandal
717ce6e1188SPurna Chandra Mandal /* Wait until PLL is locked (maximum 100 usecs). */
718ce6e1188SPurna Chandra Mandal err = readl_poll_timeout_atomic(pll->status_reg, v,
719ce6e1188SPurna Chandra Mandal v & pll->lock_mask, 1, 100);
720ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&pll->core->reg_lock, flags);
721ce6e1188SPurna Chandra Mandal
722ce6e1188SPurna Chandra Mandal return err;
723ce6e1188SPurna Chandra Mandal }
724ce6e1188SPurna Chandra Mandal
725ce6e1188SPurna Chandra Mandal /* SPLL clock operation */
726ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_spll_ops = {
727ce6e1188SPurna Chandra Mandal .recalc_rate = spll_clk_recalc_rate,
728ce6e1188SPurna Chandra Mandal .round_rate = spll_clk_round_rate,
729ce6e1188SPurna Chandra Mandal .set_rate = spll_clk_set_rate,
730ce6e1188SPurna Chandra Mandal };
731ce6e1188SPurna Chandra Mandal
pic32_spll_clk_register(const struct pic32_sys_pll_data * data,struct pic32_clk_common * core)732ce6e1188SPurna Chandra Mandal struct clk *pic32_spll_clk_register(const struct pic32_sys_pll_data *data,
733ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core)
734ce6e1188SPurna Chandra Mandal {
735ce6e1188SPurna Chandra Mandal struct pic32_sys_pll *spll;
736ce6e1188SPurna Chandra Mandal struct clk *clk;
737ce6e1188SPurna Chandra Mandal
738ce6e1188SPurna Chandra Mandal spll = devm_kzalloc(core->dev, sizeof(*spll), GFP_KERNEL);
739ce6e1188SPurna Chandra Mandal if (!spll)
740ce6e1188SPurna Chandra Mandal return ERR_PTR(-ENOMEM);
741ce6e1188SPurna Chandra Mandal
742ce6e1188SPurna Chandra Mandal spll->core = core;
743ce6e1188SPurna Chandra Mandal spll->hw.init = &data->init_data;
744ce6e1188SPurna Chandra Mandal spll->ctrl_reg = data->ctrl_reg + core->iobase;
745ce6e1188SPurna Chandra Mandal spll->status_reg = data->status_reg + core->iobase;
746ce6e1188SPurna Chandra Mandal spll->lock_mask = data->lock_mask;
747ce6e1188SPurna Chandra Mandal
748ce6e1188SPurna Chandra Mandal /* cache PLL idiv; PLL driver uses it as constant.*/
749ce6e1188SPurna Chandra Mandal spll->idiv = (readl(spll->ctrl_reg) >> PLL_IDIV_SHIFT) & PLL_IDIV_MASK;
750ce6e1188SPurna Chandra Mandal spll->idiv += 1;
751ce6e1188SPurna Chandra Mandal
752ce6e1188SPurna Chandra Mandal clk = devm_clk_register(core->dev, &spll->hw);
753ce6e1188SPurna Chandra Mandal if (IS_ERR(clk))
754ce6e1188SPurna Chandra Mandal dev_err(core->dev, "sys_pll: clk_register() failed\n");
755ce6e1188SPurna Chandra Mandal
756ce6e1188SPurna Chandra Mandal return clk;
757ce6e1188SPurna Chandra Mandal }
758ce6e1188SPurna Chandra Mandal
759ce6e1188SPurna Chandra Mandal /* System mux clock(aka SCLK) */
760ce6e1188SPurna Chandra Mandal
761ce6e1188SPurna Chandra Mandal struct pic32_sys_clk {
762ce6e1188SPurna Chandra Mandal struct clk_hw hw;
763ce6e1188SPurna Chandra Mandal void __iomem *mux_reg;
764ce6e1188SPurna Chandra Mandal void __iomem *slew_reg;
765ce6e1188SPurna Chandra Mandal u32 slew_div;
766ce6e1188SPurna Chandra Mandal const u32 *parent_map;
767ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core;
768ce6e1188SPurna Chandra Mandal };
769ce6e1188SPurna Chandra Mandal
770ce6e1188SPurna Chandra Mandal #define clkhw_to_sys_clk(_hw) container_of(_hw, struct pic32_sys_clk, hw)
771ce6e1188SPurna Chandra Mandal
sclk_get_rate(struct clk_hw * hw,unsigned long parent_rate)772ce6e1188SPurna Chandra Mandal static unsigned long sclk_get_rate(struct clk_hw *hw, unsigned long parent_rate)
773ce6e1188SPurna Chandra Mandal {
774ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw);
775ce6e1188SPurna Chandra Mandal u32 div;
776ce6e1188SPurna Chandra Mandal
777ce6e1188SPurna Chandra Mandal div = (readl(sclk->slew_reg) >> SLEW_SYSDIV_SHIFT) & SLEW_SYSDIV;
778ce6e1188SPurna Chandra Mandal div += 1; /* sys-div to divider */
779ce6e1188SPurna Chandra Mandal
780ce6e1188SPurna Chandra Mandal return parent_rate / div;
781ce6e1188SPurna Chandra Mandal }
782ce6e1188SPurna Chandra Mandal
sclk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)783ce6e1188SPurna Chandra Mandal static long sclk_round_rate(struct clk_hw *hw, unsigned long rate,
784ce6e1188SPurna Chandra Mandal unsigned long *parent_rate)
785ce6e1188SPurna Chandra Mandal {
786ce6e1188SPurna Chandra Mandal return calc_best_divided_rate(rate, *parent_rate, SLEW_SYSDIV, 1);
787ce6e1188SPurna Chandra Mandal }
788ce6e1188SPurna Chandra Mandal
sclk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)789ce6e1188SPurna Chandra Mandal static int sclk_set_rate(struct clk_hw *hw,
790ce6e1188SPurna Chandra Mandal unsigned long rate, unsigned long parent_rate)
791ce6e1188SPurna Chandra Mandal {
792ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw);
793ce6e1188SPurna Chandra Mandal unsigned long flags;
794ce6e1188SPurna Chandra Mandal u32 v, div;
795ce6e1188SPurna Chandra Mandal int err;
796ce6e1188SPurna Chandra Mandal
797ce6e1188SPurna Chandra Mandal div = parent_rate / rate;
798ce6e1188SPurna Chandra Mandal
799ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&sclk->core->reg_lock, flags);
800ce6e1188SPurna Chandra Mandal
801ce6e1188SPurna Chandra Mandal /* apply new div */
802ce6e1188SPurna Chandra Mandal v = readl(sclk->slew_reg);
803ce6e1188SPurna Chandra Mandal v &= ~(SLEW_SYSDIV << SLEW_SYSDIV_SHIFT);
804ce6e1188SPurna Chandra Mandal v |= (div - 1) << SLEW_SYSDIV_SHIFT;
805ce6e1188SPurna Chandra Mandal
806ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
807ce6e1188SPurna Chandra Mandal
808ce6e1188SPurna Chandra Mandal writel(v, sclk->slew_reg);
809ce6e1188SPurna Chandra Mandal
810ce6e1188SPurna Chandra Mandal /* wait until BUSY is cleared */
811ce6e1188SPurna Chandra Mandal err = readl_poll_timeout_atomic(sclk->slew_reg, v,
812ce6e1188SPurna Chandra Mandal !(v & SLEW_BUSY), 1, LOCK_TIMEOUT_US);
813ce6e1188SPurna Chandra Mandal
814ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&sclk->core->reg_lock, flags);
815ce6e1188SPurna Chandra Mandal
816ce6e1188SPurna Chandra Mandal return err;
817ce6e1188SPurna Chandra Mandal }
818ce6e1188SPurna Chandra Mandal
sclk_get_parent(struct clk_hw * hw)819ce6e1188SPurna Chandra Mandal static u8 sclk_get_parent(struct clk_hw *hw)
820ce6e1188SPurna Chandra Mandal {
821ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw);
822ce6e1188SPurna Chandra Mandal u32 i, v;
823ce6e1188SPurna Chandra Mandal
824ce6e1188SPurna Chandra Mandal v = (readl(sclk->mux_reg) >> OSC_CUR_SHIFT) & OSC_CUR_MASK;
825ce6e1188SPurna Chandra Mandal
826ce6e1188SPurna Chandra Mandal if (!sclk->parent_map)
827ce6e1188SPurna Chandra Mandal return v;
828ce6e1188SPurna Chandra Mandal
829ce6e1188SPurna Chandra Mandal for (i = 0; i < clk_hw_get_num_parents(hw); i++)
830ce6e1188SPurna Chandra Mandal if (sclk->parent_map[i] == v)
831ce6e1188SPurna Chandra Mandal return i;
832ce6e1188SPurna Chandra Mandal return -EINVAL;
833ce6e1188SPurna Chandra Mandal }
834ce6e1188SPurna Chandra Mandal
sclk_set_parent(struct clk_hw * hw,u8 index)835ce6e1188SPurna Chandra Mandal static int sclk_set_parent(struct clk_hw *hw, u8 index)
836ce6e1188SPurna Chandra Mandal {
837ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw);
838ce6e1188SPurna Chandra Mandal unsigned long flags;
839ce6e1188SPurna Chandra Mandal u32 nosc, cosc, v;
840ce6e1188SPurna Chandra Mandal int err;
841ce6e1188SPurna Chandra Mandal
842ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&sclk->core->reg_lock, flags);
843ce6e1188SPurna Chandra Mandal
844ce6e1188SPurna Chandra Mandal /* find new_osc */
845ce6e1188SPurna Chandra Mandal nosc = sclk->parent_map ? sclk->parent_map[index] : index;
846ce6e1188SPurna Chandra Mandal
847ce6e1188SPurna Chandra Mandal /* set new parent */
848ce6e1188SPurna Chandra Mandal v = readl(sclk->mux_reg);
849ce6e1188SPurna Chandra Mandal v &= ~(OSC_NEW_MASK << OSC_NEW_SHIFT);
850ce6e1188SPurna Chandra Mandal v |= nosc << OSC_NEW_SHIFT;
851ce6e1188SPurna Chandra Mandal
852ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
853ce6e1188SPurna Chandra Mandal
854ce6e1188SPurna Chandra Mandal writel(v, sclk->mux_reg);
855ce6e1188SPurna Chandra Mandal
856ce6e1188SPurna Chandra Mandal /* initate switch */
857ce6e1188SPurna Chandra Mandal writel(OSC_SWEN, PIC32_SET(sclk->mux_reg));
858ce6e1188SPurna Chandra Mandal cpu_relax();
859ce6e1188SPurna Chandra Mandal
860ce6e1188SPurna Chandra Mandal /* add nop to flush pipeline (as cpu_clk is in-flux) */
861ce6e1188SPurna Chandra Mandal cpu_nop5();
862ce6e1188SPurna Chandra Mandal
863ce6e1188SPurna Chandra Mandal /* wait for SWEN bit to clear */
864ce6e1188SPurna Chandra Mandal err = readl_poll_timeout_atomic(sclk->slew_reg, v,
865ce6e1188SPurna Chandra Mandal !(v & OSC_SWEN), 1, LOCK_TIMEOUT_US);
866ce6e1188SPurna Chandra Mandal
867ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&sclk->core->reg_lock, flags);
868ce6e1188SPurna Chandra Mandal
869ce6e1188SPurna Chandra Mandal /*
870ce6e1188SPurna Chandra Mandal * SCLK clock-switching logic might reject a clock switching request
871ce6e1188SPurna Chandra Mandal * if pre-requisites (like new clk_src not present or unstable) are
872ce6e1188SPurna Chandra Mandal * not met.
873ce6e1188SPurna Chandra Mandal * So confirm before claiming success.
874ce6e1188SPurna Chandra Mandal */
875ce6e1188SPurna Chandra Mandal cosc = (readl(sclk->mux_reg) >> OSC_CUR_SHIFT) & OSC_CUR_MASK;
876ce6e1188SPurna Chandra Mandal if (cosc != nosc) {
877ce6e1188SPurna Chandra Mandal pr_err("%s: err, failed to set_parent() to %d, current %d\n",
878ce6e1188SPurna Chandra Mandal clk_hw_get_name(hw), nosc, cosc);
879ce6e1188SPurna Chandra Mandal err = -EBUSY;
880ce6e1188SPurna Chandra Mandal }
881ce6e1188SPurna Chandra Mandal
882ce6e1188SPurna Chandra Mandal return err;
883ce6e1188SPurna Chandra Mandal }
884ce6e1188SPurna Chandra Mandal
sclk_init(struct clk_hw * hw)885*89d079dcSJerome Brunet static int sclk_init(struct clk_hw *hw)
886ce6e1188SPurna Chandra Mandal {
887ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw);
888ce6e1188SPurna Chandra Mandal unsigned long flags;
889ce6e1188SPurna Chandra Mandal u32 v;
890ce6e1188SPurna Chandra Mandal
891ce6e1188SPurna Chandra Mandal /* Maintain reference to this clk, required in spll_clk_set_rate() */
892ce6e1188SPurna Chandra Mandal pic32_sclk_hw = hw;
893ce6e1188SPurna Chandra Mandal
894ce6e1188SPurna Chandra Mandal /* apply slew divider on both up and down scaling */
895ce6e1188SPurna Chandra Mandal if (sclk->slew_div) {
896ce6e1188SPurna Chandra Mandal spin_lock_irqsave(&sclk->core->reg_lock, flags);
897ce6e1188SPurna Chandra Mandal v = readl(sclk->slew_reg);
898ce6e1188SPurna Chandra Mandal v &= ~(SLEW_DIV << SLEW_DIV_SHIFT);
899ce6e1188SPurna Chandra Mandal v |= sclk->slew_div << SLEW_DIV_SHIFT;
900ce6e1188SPurna Chandra Mandal v |= SLEW_DOWNEN | SLEW_UPEN;
901ce6e1188SPurna Chandra Mandal writel(v, sclk->slew_reg);
902ce6e1188SPurna Chandra Mandal spin_unlock_irqrestore(&sclk->core->reg_lock, flags);
903ce6e1188SPurna Chandra Mandal }
904*89d079dcSJerome Brunet
905*89d079dcSJerome Brunet return 0;
906ce6e1188SPurna Chandra Mandal }
907ce6e1188SPurna Chandra Mandal
908ce6e1188SPurna Chandra Mandal /* sclk with post-divider */
909ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_sclk_ops = {
910ce6e1188SPurna Chandra Mandal .get_parent = sclk_get_parent,
911ce6e1188SPurna Chandra Mandal .set_parent = sclk_set_parent,
912ce6e1188SPurna Chandra Mandal .round_rate = sclk_round_rate,
913ce6e1188SPurna Chandra Mandal .set_rate = sclk_set_rate,
914ce6e1188SPurna Chandra Mandal .recalc_rate = sclk_get_rate,
915ce6e1188SPurna Chandra Mandal .init = sclk_init,
916ce6e1188SPurna Chandra Mandal .determine_rate = __clk_mux_determine_rate,
917ce6e1188SPurna Chandra Mandal };
918ce6e1188SPurna Chandra Mandal
919ce6e1188SPurna Chandra Mandal /* sclk with no slew and no post-divider */
920ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_sclk_no_div_ops = {
921ce6e1188SPurna Chandra Mandal .get_parent = sclk_get_parent,
922ce6e1188SPurna Chandra Mandal .set_parent = sclk_set_parent,
923ce6e1188SPurna Chandra Mandal .init = sclk_init,
924ce6e1188SPurna Chandra Mandal .determine_rate = __clk_mux_determine_rate,
925ce6e1188SPurna Chandra Mandal };
926ce6e1188SPurna Chandra Mandal
pic32_sys_clk_register(const struct pic32_sys_clk_data * data,struct pic32_clk_common * core)927ce6e1188SPurna Chandra Mandal struct clk *pic32_sys_clk_register(const struct pic32_sys_clk_data *data,
928ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core)
929ce6e1188SPurna Chandra Mandal {
930ce6e1188SPurna Chandra Mandal struct pic32_sys_clk *sclk;
931ce6e1188SPurna Chandra Mandal struct clk *clk;
932ce6e1188SPurna Chandra Mandal
933ce6e1188SPurna Chandra Mandal sclk = devm_kzalloc(core->dev, sizeof(*sclk), GFP_KERNEL);
934ce6e1188SPurna Chandra Mandal if (!sclk)
935ce6e1188SPurna Chandra Mandal return ERR_PTR(-ENOMEM);
936ce6e1188SPurna Chandra Mandal
937ce6e1188SPurna Chandra Mandal sclk->core = core;
938ce6e1188SPurna Chandra Mandal sclk->hw.init = &data->init_data;
939ce6e1188SPurna Chandra Mandal sclk->mux_reg = data->mux_reg + core->iobase;
940ce6e1188SPurna Chandra Mandal sclk->slew_reg = data->slew_reg + core->iobase;
941ce6e1188SPurna Chandra Mandal sclk->slew_div = data->slew_div;
942ce6e1188SPurna Chandra Mandal sclk->parent_map = data->parent_map;
943ce6e1188SPurna Chandra Mandal
944ce6e1188SPurna Chandra Mandal clk = devm_clk_register(core->dev, &sclk->hw);
945ce6e1188SPurna Chandra Mandal if (IS_ERR(clk))
946ce6e1188SPurna Chandra Mandal dev_err(core->dev, "%s: clk register failed\n", __func__);
947ce6e1188SPurna Chandra Mandal
948ce6e1188SPurna Chandra Mandal return clk;
949ce6e1188SPurna Chandra Mandal }
950ce6e1188SPurna Chandra Mandal
951ce6e1188SPurna Chandra Mandal /* secondary oscillator */
952ce6e1188SPurna Chandra Mandal struct pic32_sec_osc {
953ce6e1188SPurna Chandra Mandal struct clk_hw hw;
954ce6e1188SPurna Chandra Mandal void __iomem *enable_reg;
955ce6e1188SPurna Chandra Mandal void __iomem *status_reg;
956ce6e1188SPurna Chandra Mandal u32 enable_mask;
957ce6e1188SPurna Chandra Mandal u32 status_mask;
958ce6e1188SPurna Chandra Mandal unsigned long fixed_rate;
959ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core;
960ce6e1188SPurna Chandra Mandal };
961ce6e1188SPurna Chandra Mandal
962ce6e1188SPurna Chandra Mandal #define clkhw_to_sosc(_hw) container_of(_hw, struct pic32_sec_osc, hw)
sosc_clk_enable(struct clk_hw * hw)963ce6e1188SPurna Chandra Mandal static int sosc_clk_enable(struct clk_hw *hw)
964ce6e1188SPurna Chandra Mandal {
965ce6e1188SPurna Chandra Mandal struct pic32_sec_osc *sosc = clkhw_to_sosc(hw);
966ce6e1188SPurna Chandra Mandal u32 v;
967ce6e1188SPurna Chandra Mandal
968ce6e1188SPurna Chandra Mandal /* enable SOSC */
969ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
970ce6e1188SPurna Chandra Mandal writel(sosc->enable_mask, PIC32_SET(sosc->enable_reg));
971ce6e1188SPurna Chandra Mandal
972ce6e1188SPurna Chandra Mandal /* wait till warm-up period expires or ready-status is updated */
973ce6e1188SPurna Chandra Mandal return readl_poll_timeout_atomic(sosc->status_reg, v,
974ce6e1188SPurna Chandra Mandal v & sosc->status_mask, 1, 100);
975ce6e1188SPurna Chandra Mandal }
976ce6e1188SPurna Chandra Mandal
sosc_clk_disable(struct clk_hw * hw)977ce6e1188SPurna Chandra Mandal static void sosc_clk_disable(struct clk_hw *hw)
978ce6e1188SPurna Chandra Mandal {
979ce6e1188SPurna Chandra Mandal struct pic32_sec_osc *sosc = clkhw_to_sosc(hw);
980ce6e1188SPurna Chandra Mandal
981ce6e1188SPurna Chandra Mandal pic32_syskey_unlock();
982ce6e1188SPurna Chandra Mandal writel(sosc->enable_mask, PIC32_CLR(sosc->enable_reg));
983ce6e1188SPurna Chandra Mandal }
984ce6e1188SPurna Chandra Mandal
sosc_clk_is_enabled(struct clk_hw * hw)985ce6e1188SPurna Chandra Mandal static int sosc_clk_is_enabled(struct clk_hw *hw)
986ce6e1188SPurna Chandra Mandal {
987ce6e1188SPurna Chandra Mandal struct pic32_sec_osc *sosc = clkhw_to_sosc(hw);
988ce6e1188SPurna Chandra Mandal u32 enabled, ready;
989ce6e1188SPurna Chandra Mandal
990ce6e1188SPurna Chandra Mandal /* check enabled and ready status */
991ce6e1188SPurna Chandra Mandal enabled = readl(sosc->enable_reg) & sosc->enable_mask;
992ce6e1188SPurna Chandra Mandal ready = readl(sosc->status_reg) & sosc->status_mask;
993ce6e1188SPurna Chandra Mandal
994ce6e1188SPurna Chandra Mandal return enabled && ready;
995ce6e1188SPurna Chandra Mandal }
996ce6e1188SPurna Chandra Mandal
sosc_clk_calc_rate(struct clk_hw * hw,unsigned long parent_rate)997ce6e1188SPurna Chandra Mandal static unsigned long sosc_clk_calc_rate(struct clk_hw *hw,
998ce6e1188SPurna Chandra Mandal unsigned long parent_rate)
999ce6e1188SPurna Chandra Mandal {
1000ce6e1188SPurna Chandra Mandal return clkhw_to_sosc(hw)->fixed_rate;
1001ce6e1188SPurna Chandra Mandal }
1002ce6e1188SPurna Chandra Mandal
1003ce6e1188SPurna Chandra Mandal const struct clk_ops pic32_sosc_ops = {
1004ce6e1188SPurna Chandra Mandal .enable = sosc_clk_enable,
1005ce6e1188SPurna Chandra Mandal .disable = sosc_clk_disable,
1006ce6e1188SPurna Chandra Mandal .is_enabled = sosc_clk_is_enabled,
1007ce6e1188SPurna Chandra Mandal .recalc_rate = sosc_clk_calc_rate,
1008ce6e1188SPurna Chandra Mandal };
1009ce6e1188SPurna Chandra Mandal
pic32_sosc_clk_register(const struct pic32_sec_osc_data * data,struct pic32_clk_common * core)1010ce6e1188SPurna Chandra Mandal struct clk *pic32_sosc_clk_register(const struct pic32_sec_osc_data *data,
1011ce6e1188SPurna Chandra Mandal struct pic32_clk_common *core)
1012ce6e1188SPurna Chandra Mandal {
1013ce6e1188SPurna Chandra Mandal struct pic32_sec_osc *sosc;
1014ce6e1188SPurna Chandra Mandal
1015ce6e1188SPurna Chandra Mandal sosc = devm_kzalloc(core->dev, sizeof(*sosc), GFP_KERNEL);
1016ce6e1188SPurna Chandra Mandal if (!sosc)
1017ce6e1188SPurna Chandra Mandal return ERR_PTR(-ENOMEM);
1018ce6e1188SPurna Chandra Mandal
1019ce6e1188SPurna Chandra Mandal sosc->core = core;
1020ce6e1188SPurna Chandra Mandal sosc->hw.init = &data->init_data;
1021ce6e1188SPurna Chandra Mandal sosc->fixed_rate = data->fixed_rate;
1022ce6e1188SPurna Chandra Mandal sosc->enable_mask = data->enable_mask;
1023ce6e1188SPurna Chandra Mandal sosc->status_mask = data->status_mask;
1024ce6e1188SPurna Chandra Mandal sosc->enable_reg = data->enable_reg + core->iobase;
1025ce6e1188SPurna Chandra Mandal sosc->status_reg = data->status_reg + core->iobase;
1026ce6e1188SPurna Chandra Mandal
1027ce6e1188SPurna Chandra Mandal return devm_clk_register(core->dev, &sosc->hw);
1028ce6e1188SPurna Chandra Mandal }
1029