xref: /openbmc/linux/drivers/clk/qcom/clk-rcg.c (revision 229fd4a5)
1bcd61c0fSStephen Boyd /*
2bcd61c0fSStephen Boyd  * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3bcd61c0fSStephen Boyd  *
4bcd61c0fSStephen Boyd  * This software is licensed under the terms of the GNU General Public
5bcd61c0fSStephen Boyd  * License version 2, as published by the Free Software Foundation, and
6bcd61c0fSStephen Boyd  * may be copied, distributed, and modified under those terms.
7bcd61c0fSStephen Boyd  *
8bcd61c0fSStephen Boyd  * This program is distributed in the hope that it will be useful,
9bcd61c0fSStephen Boyd  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10bcd61c0fSStephen Boyd  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11bcd61c0fSStephen Boyd  * GNU General Public License for more details.
12bcd61c0fSStephen Boyd  */
13bcd61c0fSStephen Boyd 
14bcd61c0fSStephen Boyd #include <linux/kernel.h>
15bcd61c0fSStephen Boyd #include <linux/bitops.h>
16bcd61c0fSStephen Boyd #include <linux/err.h>
17bcd61c0fSStephen Boyd #include <linux/export.h>
18bcd61c0fSStephen Boyd #include <linux/clk-provider.h>
19bcd61c0fSStephen Boyd #include <linux/regmap.h>
20bcd61c0fSStephen Boyd 
21bcd61c0fSStephen Boyd #include <asm/div64.h>
22bcd61c0fSStephen Boyd 
23bcd61c0fSStephen Boyd #include "clk-rcg.h"
2450c6a503SStephen Boyd #include "common.h"
25bcd61c0fSStephen Boyd 
26bcd61c0fSStephen Boyd static u32 ns_to_src(struct src_sel *s, u32 ns)
27bcd61c0fSStephen Boyd {
28bcd61c0fSStephen Boyd 	ns >>= s->src_sel_shift;
29bcd61c0fSStephen Boyd 	ns &= SRC_SEL_MASK;
30bcd61c0fSStephen Boyd 	return ns;
31bcd61c0fSStephen Boyd }
32bcd61c0fSStephen Boyd 
33bcd61c0fSStephen Boyd static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)
34bcd61c0fSStephen Boyd {
35bcd61c0fSStephen Boyd 	u32 mask;
36bcd61c0fSStephen Boyd 
37bcd61c0fSStephen Boyd 	mask = SRC_SEL_MASK;
38bcd61c0fSStephen Boyd 	mask <<= s->src_sel_shift;
39bcd61c0fSStephen Boyd 	ns &= ~mask;
40bcd61c0fSStephen Boyd 
41bcd61c0fSStephen Boyd 	ns |= src << s->src_sel_shift;
42bcd61c0fSStephen Boyd 	return ns;
43bcd61c0fSStephen Boyd }
44bcd61c0fSStephen Boyd 
45bcd61c0fSStephen Boyd static u8 clk_rcg_get_parent(struct clk_hw *hw)
46bcd61c0fSStephen Boyd {
47bcd61c0fSStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
48bcd61c0fSStephen Boyd 	int num_parents = __clk_get_num_parents(hw->clk);
49bcd61c0fSStephen Boyd 	u32 ns;
50bcd61c0fSStephen Boyd 	int i;
51bcd61c0fSStephen Boyd 
52bcd61c0fSStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
53bcd61c0fSStephen Boyd 	ns = ns_to_src(&rcg->s, ns);
54bcd61c0fSStephen Boyd 	for (i = 0; i < num_parents; i++)
55bcd61c0fSStephen Boyd 		if (ns == rcg->s.parent_map[i])
56bcd61c0fSStephen Boyd 			return i;
57bcd61c0fSStephen Boyd 
58bcd61c0fSStephen Boyd 	return -EINVAL;
59bcd61c0fSStephen Boyd }
60bcd61c0fSStephen Boyd 
61bcd61c0fSStephen Boyd static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
62bcd61c0fSStephen Boyd {
63bcd61c0fSStephen Boyd 	bank &= BIT(rcg->mux_sel_bit);
64bcd61c0fSStephen Boyd 	return !!bank;
65bcd61c0fSStephen Boyd }
66bcd61c0fSStephen Boyd 
67bcd61c0fSStephen Boyd static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
68bcd61c0fSStephen Boyd {
69bcd61c0fSStephen Boyd 	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
70bcd61c0fSStephen Boyd 	int num_parents = __clk_get_num_parents(hw->clk);
71229fd4a5SStephen Boyd 	u32 ns, reg;
72bcd61c0fSStephen Boyd 	int bank;
73bcd61c0fSStephen Boyd 	int i;
74bcd61c0fSStephen Boyd 	struct src_sel *s;
75bcd61c0fSStephen Boyd 
76229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
77229fd4a5SStephen Boyd 	bank = reg_to_bank(rcg, reg);
78bcd61c0fSStephen Boyd 	s = &rcg->s[bank];
79bcd61c0fSStephen Boyd 
80229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
81bcd61c0fSStephen Boyd 	ns = ns_to_src(s, ns);
82bcd61c0fSStephen Boyd 
83bcd61c0fSStephen Boyd 	for (i = 0; i < num_parents; i++)
84bcd61c0fSStephen Boyd 		if (ns == s->parent_map[i])
85bcd61c0fSStephen Boyd 			return i;
86bcd61c0fSStephen Boyd 
87bcd61c0fSStephen Boyd 	return -EINVAL;
88bcd61c0fSStephen Boyd }
89bcd61c0fSStephen Boyd 
90bcd61c0fSStephen Boyd static int clk_rcg_set_parent(struct clk_hw *hw, u8 index)
91bcd61c0fSStephen Boyd {
92bcd61c0fSStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
93bcd61c0fSStephen Boyd 	u32 ns;
94bcd61c0fSStephen Boyd 
95bcd61c0fSStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
96bcd61c0fSStephen Boyd 	ns = src_to_ns(&rcg->s, rcg->s.parent_map[index], ns);
97bcd61c0fSStephen Boyd 	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);
98bcd61c0fSStephen Boyd 
99bcd61c0fSStephen Boyd 	return 0;
100bcd61c0fSStephen Boyd }
101bcd61c0fSStephen Boyd 
102bcd61c0fSStephen Boyd static u32 md_to_m(struct mn *mn, u32 md)
103bcd61c0fSStephen Boyd {
104bcd61c0fSStephen Boyd 	md >>= mn->m_val_shift;
105bcd61c0fSStephen Boyd 	md &= BIT(mn->width) - 1;
106bcd61c0fSStephen Boyd 	return md;
107bcd61c0fSStephen Boyd }
108bcd61c0fSStephen Boyd 
109bcd61c0fSStephen Boyd static u32 ns_to_pre_div(struct pre_div *p, u32 ns)
110bcd61c0fSStephen Boyd {
111bcd61c0fSStephen Boyd 	ns >>= p->pre_div_shift;
112bcd61c0fSStephen Boyd 	ns &= BIT(p->pre_div_width) - 1;
113bcd61c0fSStephen Boyd 	return ns;
114bcd61c0fSStephen Boyd }
115bcd61c0fSStephen Boyd 
116bcd61c0fSStephen Boyd static u32 pre_div_to_ns(struct pre_div *p, u8 pre_div, u32 ns)
117bcd61c0fSStephen Boyd {
118bcd61c0fSStephen Boyd 	u32 mask;
119bcd61c0fSStephen Boyd 
120bcd61c0fSStephen Boyd 	mask = BIT(p->pre_div_width) - 1;
121bcd61c0fSStephen Boyd 	mask <<= p->pre_div_shift;
122bcd61c0fSStephen Boyd 	ns &= ~mask;
123bcd61c0fSStephen Boyd 
124bcd61c0fSStephen Boyd 	ns |= pre_div << p->pre_div_shift;
125bcd61c0fSStephen Boyd 	return ns;
126bcd61c0fSStephen Boyd }
127bcd61c0fSStephen Boyd 
128bcd61c0fSStephen Boyd static u32 mn_to_md(struct mn *mn, u32 m, u32 n, u32 md)
129bcd61c0fSStephen Boyd {
130bcd61c0fSStephen Boyd 	u32 mask, mask_w;
131bcd61c0fSStephen Boyd 
132bcd61c0fSStephen Boyd 	mask_w = BIT(mn->width) - 1;
133bcd61c0fSStephen Boyd 	mask = (mask_w << mn->m_val_shift) | mask_w;
134bcd61c0fSStephen Boyd 	md &= ~mask;
135bcd61c0fSStephen Boyd 
136bcd61c0fSStephen Boyd 	if (n) {
137bcd61c0fSStephen Boyd 		m <<= mn->m_val_shift;
138bcd61c0fSStephen Boyd 		md |= m;
139bcd61c0fSStephen Boyd 		md |= ~n & mask_w;
140bcd61c0fSStephen Boyd 	}
141bcd61c0fSStephen Boyd 
142bcd61c0fSStephen Boyd 	return md;
143bcd61c0fSStephen Boyd }
144bcd61c0fSStephen Boyd 
145bcd61c0fSStephen Boyd static u32 ns_m_to_n(struct mn *mn, u32 ns, u32 m)
146bcd61c0fSStephen Boyd {
147bcd61c0fSStephen Boyd 	ns = ~ns >> mn->n_val_shift;
148bcd61c0fSStephen Boyd 	ns &= BIT(mn->width) - 1;
149bcd61c0fSStephen Boyd 	return ns + m;
150bcd61c0fSStephen Boyd }
151bcd61c0fSStephen Boyd 
152bcd61c0fSStephen Boyd static u32 reg_to_mnctr_mode(struct mn *mn, u32 val)
153bcd61c0fSStephen Boyd {
154bcd61c0fSStephen Boyd 	val >>= mn->mnctr_mode_shift;
155bcd61c0fSStephen Boyd 	val &= MNCTR_MODE_MASK;
156bcd61c0fSStephen Boyd 	return val;
157bcd61c0fSStephen Boyd }
158bcd61c0fSStephen Boyd 
159bcd61c0fSStephen Boyd static u32 mn_to_ns(struct mn *mn, u32 m, u32 n, u32 ns)
160bcd61c0fSStephen Boyd {
161bcd61c0fSStephen Boyd 	u32 mask;
162bcd61c0fSStephen Boyd 
163bcd61c0fSStephen Boyd 	mask = BIT(mn->width) - 1;
164bcd61c0fSStephen Boyd 	mask <<= mn->n_val_shift;
165bcd61c0fSStephen Boyd 	ns &= ~mask;
166bcd61c0fSStephen Boyd 
167bcd61c0fSStephen Boyd 	if (n) {
168bcd61c0fSStephen Boyd 		n = n - m;
169bcd61c0fSStephen Boyd 		n = ~n;
170bcd61c0fSStephen Boyd 		n &= BIT(mn->width) - 1;
171bcd61c0fSStephen Boyd 		n <<= mn->n_val_shift;
172bcd61c0fSStephen Boyd 		ns |= n;
173bcd61c0fSStephen Boyd 	}
174bcd61c0fSStephen Boyd 
175bcd61c0fSStephen Boyd 	return ns;
176bcd61c0fSStephen Boyd }
177bcd61c0fSStephen Boyd 
178bcd61c0fSStephen Boyd static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val)
179bcd61c0fSStephen Boyd {
180bcd61c0fSStephen Boyd 	u32 mask;
181bcd61c0fSStephen Boyd 
182bcd61c0fSStephen Boyd 	mask = MNCTR_MODE_MASK << mn->mnctr_mode_shift;
183bcd61c0fSStephen Boyd 	mask |= BIT(mn->mnctr_en_bit);
184bcd61c0fSStephen Boyd 	val &= ~mask;
185bcd61c0fSStephen Boyd 
186bcd61c0fSStephen Boyd 	if (n) {
187bcd61c0fSStephen Boyd 		val |= BIT(mn->mnctr_en_bit);
188bcd61c0fSStephen Boyd 		val |= MNCTR_MODE_DUAL << mn->mnctr_mode_shift;
189bcd61c0fSStephen Boyd 	}
190bcd61c0fSStephen Boyd 
191bcd61c0fSStephen Boyd 	return val;
192bcd61c0fSStephen Boyd }
193bcd61c0fSStephen Boyd 
194bcd61c0fSStephen Boyd static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f)
195bcd61c0fSStephen Boyd {
196229fd4a5SStephen Boyd 	u32 ns, md, reg;
197bcd61c0fSStephen Boyd 	int bank, new_bank;
198bcd61c0fSStephen Boyd 	struct mn *mn;
199bcd61c0fSStephen Boyd 	struct pre_div *p;
200bcd61c0fSStephen Boyd 	struct src_sel *s;
201bcd61c0fSStephen Boyd 	bool enabled;
202229fd4a5SStephen Boyd 	u32 md_reg, ns_reg;
203bcd61c0fSStephen Boyd 	bool banked_mn = !!rcg->mn[1].width;
204229fd4a5SStephen Boyd 	bool banked_p = !!rcg->p[1].pre_div_width;
205bcd61c0fSStephen Boyd 	struct clk_hw *hw = &rcg->clkr.hw;
206bcd61c0fSStephen Boyd 
207bcd61c0fSStephen Boyd 	enabled = __clk_is_enabled(hw->clk);
208bcd61c0fSStephen Boyd 
209229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
210229fd4a5SStephen Boyd 	bank = reg_to_bank(rcg, reg);
211bcd61c0fSStephen Boyd 	new_bank = enabled ? !bank : bank;
212bcd61c0fSStephen Boyd 
213229fd4a5SStephen Boyd 	ns_reg = rcg->ns_reg[new_bank];
214229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, ns_reg, &ns);
215229fd4a5SStephen Boyd 
216bcd61c0fSStephen Boyd 	if (banked_mn) {
217bcd61c0fSStephen Boyd 		mn = &rcg->mn[new_bank];
218bcd61c0fSStephen Boyd 		md_reg = rcg->md_reg[new_bank];
219bcd61c0fSStephen Boyd 
220bcd61c0fSStephen Boyd 		ns |= BIT(mn->mnctr_reset_bit);
221229fd4a5SStephen Boyd 		regmap_write(rcg->clkr.regmap, ns_reg, ns);
222bcd61c0fSStephen Boyd 
223bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, md_reg, &md);
224bcd61c0fSStephen Boyd 		md = mn_to_md(mn, f->m, f->n, md);
225bcd61c0fSStephen Boyd 		regmap_write(rcg->clkr.regmap, md_reg, md);
226bcd61c0fSStephen Boyd 
227bcd61c0fSStephen Boyd 		ns = mn_to_ns(mn, f->m, f->n, ns);
228229fd4a5SStephen Boyd 		regmap_write(rcg->clkr.regmap, ns_reg, ns);
229bcd61c0fSStephen Boyd 
230229fd4a5SStephen Boyd 		/* Two NS registers means mode control is in NS register */
231229fd4a5SStephen Boyd 		if (rcg->ns_reg[0] != rcg->ns_reg[1]) {
232229fd4a5SStephen Boyd 			ns = mn_to_reg(mn, f->m, f->n, ns);
233229fd4a5SStephen Boyd 			regmap_write(rcg->clkr.regmap, ns_reg, ns);
234229fd4a5SStephen Boyd 		} else {
235229fd4a5SStephen Boyd 			reg = mn_to_reg(mn, f->m, f->n, reg);
236229fd4a5SStephen Boyd 			regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg);
237229fd4a5SStephen Boyd 		}
238bcd61c0fSStephen Boyd 
239bcd61c0fSStephen Boyd 		ns &= ~BIT(mn->mnctr_reset_bit);
240229fd4a5SStephen Boyd 		regmap_write(rcg->clkr.regmap, ns_reg, ns);
241229fd4a5SStephen Boyd 	}
242229fd4a5SStephen Boyd 
243229fd4a5SStephen Boyd 	if (banked_p) {
244bcd61c0fSStephen Boyd 		p = &rcg->p[new_bank];
245bcd61c0fSStephen Boyd 		ns = pre_div_to_ns(p, f->pre_div - 1, ns);
246bcd61c0fSStephen Boyd 	}
247bcd61c0fSStephen Boyd 
248bcd61c0fSStephen Boyd 	s = &rcg->s[new_bank];
249bcd61c0fSStephen Boyd 	ns = src_to_ns(s, s->parent_map[f->src], ns);
250229fd4a5SStephen Boyd 	regmap_write(rcg->clkr.regmap, ns_reg, ns);
251bcd61c0fSStephen Boyd 
252bcd61c0fSStephen Boyd 	if (enabled) {
253229fd4a5SStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
254229fd4a5SStephen Boyd 		reg ^= BIT(rcg->mux_sel_bit);
255229fd4a5SStephen Boyd 		regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg);
256bcd61c0fSStephen Boyd 	}
257bcd61c0fSStephen Boyd }
258bcd61c0fSStephen Boyd 
259bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index)
260bcd61c0fSStephen Boyd {
261bcd61c0fSStephen Boyd 	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
262229fd4a5SStephen Boyd 	u32 ns, md, reg;
263bcd61c0fSStephen Boyd 	int bank;
264bcd61c0fSStephen Boyd 	struct freq_tbl f = { 0 };
265bcd61c0fSStephen Boyd 	bool banked_mn = !!rcg->mn[1].width;
266229fd4a5SStephen Boyd 	bool banked_p = !!rcg->p[1].pre_div_width;
267bcd61c0fSStephen Boyd 
268229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
269bcd61c0fSStephen Boyd 	bank = reg_to_bank(rcg, reg);
270bcd61c0fSStephen Boyd 
271229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
272229fd4a5SStephen Boyd 
273bcd61c0fSStephen Boyd 	if (banked_mn) {
274bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);
275bcd61c0fSStephen Boyd 		f.m = md_to_m(&rcg->mn[bank], md);
276bcd61c0fSStephen Boyd 		f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m);
277bcd61c0fSStephen Boyd 	}
278bcd61c0fSStephen Boyd 
279229fd4a5SStephen Boyd 	if (banked_p)
280229fd4a5SStephen Boyd 		f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1;
281229fd4a5SStephen Boyd 
282229fd4a5SStephen Boyd 	f.src = index;
283bcd61c0fSStephen Boyd 	configure_bank(rcg, &f);
284bcd61c0fSStephen Boyd 
285bcd61c0fSStephen Boyd 	return 0;
286bcd61c0fSStephen Boyd }
287bcd61c0fSStephen Boyd 
288bcd61c0fSStephen Boyd /*
289bcd61c0fSStephen Boyd  * Calculate m/n:d rate
290bcd61c0fSStephen Boyd  *
291bcd61c0fSStephen Boyd  *          parent_rate     m
292bcd61c0fSStephen Boyd  *   rate = ----------- x  ---
293bcd61c0fSStephen Boyd  *            pre_div       n
294bcd61c0fSStephen Boyd  */
295bcd61c0fSStephen Boyd static unsigned long
296bcd61c0fSStephen Boyd calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 pre_div)
297bcd61c0fSStephen Boyd {
298bcd61c0fSStephen Boyd 	if (pre_div)
299bcd61c0fSStephen Boyd 		rate /= pre_div + 1;
300bcd61c0fSStephen Boyd 
301bcd61c0fSStephen Boyd 	if (mode) {
302bcd61c0fSStephen Boyd 		u64 tmp = rate;
303bcd61c0fSStephen Boyd 		tmp *= m;
304bcd61c0fSStephen Boyd 		do_div(tmp, n);
305bcd61c0fSStephen Boyd 		rate = tmp;
306bcd61c0fSStephen Boyd 	}
307bcd61c0fSStephen Boyd 
308bcd61c0fSStephen Boyd 	return rate;
309bcd61c0fSStephen Boyd }
310bcd61c0fSStephen Boyd 
311bcd61c0fSStephen Boyd static unsigned long
312bcd61c0fSStephen Boyd clk_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
313bcd61c0fSStephen Boyd {
314bcd61c0fSStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
315bcd61c0fSStephen Boyd 	u32 pre_div, m = 0, n = 0, ns, md, mode = 0;
316bcd61c0fSStephen Boyd 	struct mn *mn = &rcg->mn;
317bcd61c0fSStephen Boyd 
318bcd61c0fSStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
319bcd61c0fSStephen Boyd 	pre_div = ns_to_pre_div(&rcg->p, ns);
320bcd61c0fSStephen Boyd 
321bcd61c0fSStephen Boyd 	if (rcg->mn.width) {
322bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);
323bcd61c0fSStephen Boyd 		m = md_to_m(mn, md);
324bcd61c0fSStephen Boyd 		n = ns_m_to_n(mn, ns, m);
325bcd61c0fSStephen Boyd 		/* MN counter mode is in hw.enable_reg sometimes */
326bcd61c0fSStephen Boyd 		if (rcg->clkr.enable_reg != rcg->ns_reg)
327bcd61c0fSStephen Boyd 			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &mode);
328bcd61c0fSStephen Boyd 		else
329bcd61c0fSStephen Boyd 			mode = ns;
330bcd61c0fSStephen Boyd 		mode = reg_to_mnctr_mode(mn, mode);
331bcd61c0fSStephen Boyd 	}
332bcd61c0fSStephen Boyd 
333bcd61c0fSStephen Boyd 	return calc_rate(parent_rate, m, n, mode, pre_div);
334bcd61c0fSStephen Boyd }
335bcd61c0fSStephen Boyd 
336bcd61c0fSStephen Boyd static unsigned long
337bcd61c0fSStephen Boyd clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
338bcd61c0fSStephen Boyd {
339bcd61c0fSStephen Boyd 	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
340bcd61c0fSStephen Boyd 	u32 m, n, pre_div, ns, md, mode, reg;
341bcd61c0fSStephen Boyd 	int bank;
342bcd61c0fSStephen Boyd 	struct mn *mn;
343229fd4a5SStephen Boyd 	bool banked_p = !!rcg->p[1].pre_div_width;
344bcd61c0fSStephen Boyd 	bool banked_mn = !!rcg->mn[1].width;
345bcd61c0fSStephen Boyd 
346229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
347bcd61c0fSStephen Boyd 	bank = reg_to_bank(rcg, reg);
348bcd61c0fSStephen Boyd 
349229fd4a5SStephen Boyd 	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
350229fd4a5SStephen Boyd 	m = n = pre_div = mode = 0;
351229fd4a5SStephen Boyd 
352bcd61c0fSStephen Boyd 	if (banked_mn) {
353bcd61c0fSStephen Boyd 		mn = &rcg->mn[bank];
354bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);
355bcd61c0fSStephen Boyd 		m = md_to_m(mn, md);
356bcd61c0fSStephen Boyd 		n = ns_m_to_n(mn, ns, m);
357229fd4a5SStephen Boyd 		/* Two NS registers means mode control is in NS register */
358229fd4a5SStephen Boyd 		if (rcg->ns_reg[0] != rcg->ns_reg[1])
359229fd4a5SStephen Boyd 			reg = ns;
360bcd61c0fSStephen Boyd 		mode = reg_to_mnctr_mode(mn, reg);
361bcd61c0fSStephen Boyd 	}
362229fd4a5SStephen Boyd 
363229fd4a5SStephen Boyd 	if (banked_p)
364229fd4a5SStephen Boyd 		pre_div = ns_to_pre_div(&rcg->p[bank], ns);
365229fd4a5SStephen Boyd 
366229fd4a5SStephen Boyd 	return calc_rate(parent_rate, m, n, mode, pre_div);
367bcd61c0fSStephen Boyd }
368bcd61c0fSStephen Boyd 
369bcd61c0fSStephen Boyd static long _freq_tbl_determine_rate(struct clk_hw *hw,
370bcd61c0fSStephen Boyd 		const struct freq_tbl *f, unsigned long rate,
371bcd61c0fSStephen Boyd 		unsigned long *p_rate, struct clk **p)
372bcd61c0fSStephen Boyd {
373bcd61c0fSStephen Boyd 	unsigned long clk_flags;
374bcd61c0fSStephen Boyd 
37550c6a503SStephen Boyd 	f = qcom_find_freq(f, rate);
376bcd61c0fSStephen Boyd 	if (!f)
377bcd61c0fSStephen Boyd 		return -EINVAL;
378bcd61c0fSStephen Boyd 
379bcd61c0fSStephen Boyd 	clk_flags = __clk_get_flags(hw->clk);
380bcd61c0fSStephen Boyd 	*p = clk_get_parent_by_index(hw->clk, f->src);
381bcd61c0fSStephen Boyd 	if (clk_flags & CLK_SET_RATE_PARENT) {
382bcd61c0fSStephen Boyd 		rate = rate * f->pre_div;
383bcd61c0fSStephen Boyd 		if (f->n) {
384bcd61c0fSStephen Boyd 			u64 tmp = rate;
385bcd61c0fSStephen Boyd 			tmp = tmp * f->n;
386bcd61c0fSStephen Boyd 			do_div(tmp, f->m);
387bcd61c0fSStephen Boyd 			rate = tmp;
388bcd61c0fSStephen Boyd 		}
389bcd61c0fSStephen Boyd 	} else {
390bcd61c0fSStephen Boyd 		rate =  __clk_get_rate(*p);
391bcd61c0fSStephen Boyd 	}
392bcd61c0fSStephen Boyd 	*p_rate = rate;
393bcd61c0fSStephen Boyd 
394bcd61c0fSStephen Boyd 	return f->freq;
395bcd61c0fSStephen Boyd }
396bcd61c0fSStephen Boyd 
397bcd61c0fSStephen Boyd static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
398bcd61c0fSStephen Boyd 		unsigned long *p_rate, struct clk **p)
399bcd61c0fSStephen Boyd {
400bcd61c0fSStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
401bcd61c0fSStephen Boyd 
402bcd61c0fSStephen Boyd 	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
403bcd61c0fSStephen Boyd }
404bcd61c0fSStephen Boyd 
405bcd61c0fSStephen Boyd static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
406bcd61c0fSStephen Boyd 		unsigned long *p_rate, struct clk **p)
407bcd61c0fSStephen Boyd {
408bcd61c0fSStephen Boyd 	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
409bcd61c0fSStephen Boyd 
410bcd61c0fSStephen Boyd 	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
411bcd61c0fSStephen Boyd }
412bcd61c0fSStephen Boyd 
413404c1ff6SStephen Boyd static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
414404c1ff6SStephen Boyd 		unsigned long *p_rate, struct clk **p)
415bcd61c0fSStephen Boyd {
416bcd61c0fSStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
417404c1ff6SStephen Boyd 	const struct freq_tbl *f = rcg->freq_tbl;
418404c1ff6SStephen Boyd 
419404c1ff6SStephen Boyd 	*p = clk_get_parent_by_index(hw->clk, f->src);
420404c1ff6SStephen Boyd 	*p_rate = __clk_round_rate(*p, rate);
421404c1ff6SStephen Boyd 
422404c1ff6SStephen Boyd 	return *p_rate;
423404c1ff6SStephen Boyd }
424404c1ff6SStephen Boyd 
425404c1ff6SStephen Boyd static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
426404c1ff6SStephen Boyd {
427bcd61c0fSStephen Boyd 	u32 ns, md, ctl;
428bcd61c0fSStephen Boyd 	struct mn *mn = &rcg->mn;
429bcd61c0fSStephen Boyd 	u32 mask = 0;
430bcd61c0fSStephen Boyd 	unsigned int reset_reg;
431bcd61c0fSStephen Boyd 
432bcd61c0fSStephen Boyd 	if (rcg->mn.reset_in_cc)
433bcd61c0fSStephen Boyd 		reset_reg = rcg->clkr.enable_reg;
434bcd61c0fSStephen Boyd 	else
435bcd61c0fSStephen Boyd 		reset_reg = rcg->ns_reg;
436bcd61c0fSStephen Boyd 
437bcd61c0fSStephen Boyd 	if (rcg->mn.width) {
438bcd61c0fSStephen Boyd 		mask = BIT(mn->mnctr_reset_bit);
439bcd61c0fSStephen Boyd 		regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, mask);
440bcd61c0fSStephen Boyd 
441bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);
442bcd61c0fSStephen Boyd 		md = mn_to_md(mn, f->m, f->n, md);
443bcd61c0fSStephen Boyd 		regmap_write(rcg->clkr.regmap, rcg->md_reg, md);
444bcd61c0fSStephen Boyd 
445bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
446bcd61c0fSStephen Boyd 		/* MN counter mode is in hw.enable_reg sometimes */
447bcd61c0fSStephen Boyd 		if (rcg->clkr.enable_reg != rcg->ns_reg) {
448bcd61c0fSStephen Boyd 			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl);
449bcd61c0fSStephen Boyd 			ctl = mn_to_reg(mn, f->m, f->n, ctl);
450bcd61c0fSStephen Boyd 			regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl);
451bcd61c0fSStephen Boyd 		} else {
452bcd61c0fSStephen Boyd 			ns = mn_to_reg(mn, f->m, f->n, ns);
453bcd61c0fSStephen Boyd 		}
454bcd61c0fSStephen Boyd 		ns = mn_to_ns(mn, f->m, f->n, ns);
455bcd61c0fSStephen Boyd 	} else {
456bcd61c0fSStephen Boyd 		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
457bcd61c0fSStephen Boyd 	}
458bcd61c0fSStephen Boyd 
459bcd61c0fSStephen Boyd 	ns = pre_div_to_ns(&rcg->p, f->pre_div - 1, ns);
460bcd61c0fSStephen Boyd 	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);
461bcd61c0fSStephen Boyd 
462bcd61c0fSStephen Boyd 	regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, 0);
463bcd61c0fSStephen Boyd 
464bcd61c0fSStephen Boyd 	return 0;
465bcd61c0fSStephen Boyd }
466bcd61c0fSStephen Boyd 
467404c1ff6SStephen Boyd static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
468404c1ff6SStephen Boyd 			    unsigned long parent_rate)
469404c1ff6SStephen Boyd {
470404c1ff6SStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
471404c1ff6SStephen Boyd 	const struct freq_tbl *f;
472404c1ff6SStephen Boyd 
47350c6a503SStephen Boyd 	f = qcom_find_freq(rcg->freq_tbl, rate);
474404c1ff6SStephen Boyd 	if (!f)
475404c1ff6SStephen Boyd 		return -EINVAL;
476404c1ff6SStephen Boyd 
477404c1ff6SStephen Boyd 	return __clk_rcg_set_rate(rcg, f);
478404c1ff6SStephen Boyd }
479404c1ff6SStephen Boyd 
480404c1ff6SStephen Boyd static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,
481404c1ff6SStephen Boyd 				unsigned long parent_rate)
482404c1ff6SStephen Boyd {
483404c1ff6SStephen Boyd 	struct clk_rcg *rcg = to_clk_rcg(hw);
484404c1ff6SStephen Boyd 
485404c1ff6SStephen Boyd 	return __clk_rcg_set_rate(rcg, rcg->freq_tbl);
486404c1ff6SStephen Boyd }
487404c1ff6SStephen Boyd 
488bcd61c0fSStephen Boyd static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate)
489bcd61c0fSStephen Boyd {
490bcd61c0fSStephen Boyd 	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
491bcd61c0fSStephen Boyd 	const struct freq_tbl *f;
492bcd61c0fSStephen Boyd 
49350c6a503SStephen Boyd 	f = qcom_find_freq(rcg->freq_tbl, rate);
494bcd61c0fSStephen Boyd 	if (!f)
495bcd61c0fSStephen Boyd 		return -EINVAL;
496bcd61c0fSStephen Boyd 
497bcd61c0fSStephen Boyd 	configure_bank(rcg, f);
498bcd61c0fSStephen Boyd 
499bcd61c0fSStephen Boyd 	return 0;
500bcd61c0fSStephen Boyd }
501bcd61c0fSStephen Boyd 
502bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
503bcd61c0fSStephen Boyd 			    unsigned long parent_rate)
504bcd61c0fSStephen Boyd {
505bcd61c0fSStephen Boyd 	return __clk_dyn_rcg_set_rate(hw, rate);
506bcd61c0fSStephen Boyd }
507bcd61c0fSStephen Boyd 
508bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_rate_and_parent(struct clk_hw *hw,
509bcd61c0fSStephen Boyd 		unsigned long rate, unsigned long parent_rate, u8 index)
510bcd61c0fSStephen Boyd {
511bcd61c0fSStephen Boyd 	return __clk_dyn_rcg_set_rate(hw, rate);
512bcd61c0fSStephen Boyd }
513bcd61c0fSStephen Boyd 
514bcd61c0fSStephen Boyd const struct clk_ops clk_rcg_ops = {
515bcd61c0fSStephen Boyd 	.enable = clk_enable_regmap,
516bcd61c0fSStephen Boyd 	.disable = clk_disable_regmap,
517bcd61c0fSStephen Boyd 	.get_parent = clk_rcg_get_parent,
518bcd61c0fSStephen Boyd 	.set_parent = clk_rcg_set_parent,
519bcd61c0fSStephen Boyd 	.recalc_rate = clk_rcg_recalc_rate,
520bcd61c0fSStephen Boyd 	.determine_rate = clk_rcg_determine_rate,
521bcd61c0fSStephen Boyd 	.set_rate = clk_rcg_set_rate,
522bcd61c0fSStephen Boyd };
523bcd61c0fSStephen Boyd EXPORT_SYMBOL_GPL(clk_rcg_ops);
524bcd61c0fSStephen Boyd 
525404c1ff6SStephen Boyd const struct clk_ops clk_rcg_bypass_ops = {
526404c1ff6SStephen Boyd 	.enable = clk_enable_regmap,
527404c1ff6SStephen Boyd 	.disable = clk_disable_regmap,
528404c1ff6SStephen Boyd 	.get_parent = clk_rcg_get_parent,
529404c1ff6SStephen Boyd 	.set_parent = clk_rcg_set_parent,
530404c1ff6SStephen Boyd 	.recalc_rate = clk_rcg_recalc_rate,
531404c1ff6SStephen Boyd 	.determine_rate = clk_rcg_bypass_determine_rate,
532404c1ff6SStephen Boyd 	.set_rate = clk_rcg_bypass_set_rate,
533404c1ff6SStephen Boyd };
534404c1ff6SStephen Boyd EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);
535404c1ff6SStephen Boyd 
536bcd61c0fSStephen Boyd const struct clk_ops clk_dyn_rcg_ops = {
537bcd61c0fSStephen Boyd 	.enable = clk_enable_regmap,
538bcd61c0fSStephen Boyd 	.is_enabled = clk_is_enabled_regmap,
539bcd61c0fSStephen Boyd 	.disable = clk_disable_regmap,
540bcd61c0fSStephen Boyd 	.get_parent = clk_dyn_rcg_get_parent,
541bcd61c0fSStephen Boyd 	.set_parent = clk_dyn_rcg_set_parent,
542bcd61c0fSStephen Boyd 	.recalc_rate = clk_dyn_rcg_recalc_rate,
543bcd61c0fSStephen Boyd 	.determine_rate = clk_dyn_rcg_determine_rate,
544bcd61c0fSStephen Boyd 	.set_rate = clk_dyn_rcg_set_rate,
545bcd61c0fSStephen Boyd 	.set_rate_and_parent = clk_dyn_rcg_set_rate_and_parent,
546bcd61c0fSStephen Boyd };
547bcd61c0fSStephen Boyd EXPORT_SYMBOL_GPL(clk_dyn_rcg_ops);
548