xref: /openbmc/linux/drivers/clk/microchip/clk-core.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
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