diff options
Diffstat (limited to 'drivers/clk/qcom/clk-rcg.c')
-rw-r--r-- | drivers/clk/qcom/clk-rcg.c | 115 |
1 files changed, 54 insertions, 61 deletions
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index b638c5846dbf..b6e6959e89aa 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/div64.h> | 21 | #include <asm/div64.h> |
22 | 22 | ||
23 | #include "clk-rcg.h" | 23 | #include "clk-rcg.h" |
24 | #include "common.h" | ||
24 | 25 | ||
25 | static u32 ns_to_src(struct src_sel *s, u32 ns) | 26 | static u32 ns_to_src(struct src_sel *s, u32 ns) |
26 | { | 27 | { |
@@ -67,16 +68,16 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) | |||
67 | { | 68 | { |
68 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 69 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
69 | int num_parents = __clk_get_num_parents(hw->clk); | 70 | int num_parents = __clk_get_num_parents(hw->clk); |
70 | u32 ns, ctl; | 71 | u32 ns, reg; |
71 | int bank; | 72 | int bank; |
72 | int i; | 73 | int i; |
73 | struct src_sel *s; | 74 | struct src_sel *s; |
74 | 75 | ||
75 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 76 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
76 | bank = reg_to_bank(rcg, ctl); | 77 | bank = reg_to_bank(rcg, reg); |
77 | s = &rcg->s[bank]; | 78 | s = &rcg->s[bank]; |
78 | 79 | ||
79 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 80 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); |
80 | ns = ns_to_src(s, ns); | 81 | ns = ns_to_src(s, ns); |
81 | 82 | ||
82 | for (i = 0; i < num_parents; i++) | 83 | for (i = 0; i < num_parents; i++) |
@@ -192,90 +193,93 @@ static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) | |||
192 | 193 | ||
193 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) | 194 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) |
194 | { | 195 | { |
195 | u32 ns, md, ctl, *regp; | 196 | u32 ns, md, reg; |
196 | int bank, new_bank; | 197 | int bank, new_bank; |
197 | struct mn *mn; | 198 | struct mn *mn; |
198 | struct pre_div *p; | 199 | struct pre_div *p; |
199 | struct src_sel *s; | 200 | struct src_sel *s; |
200 | bool enabled; | 201 | bool enabled; |
201 | u32 md_reg; | 202 | u32 md_reg, ns_reg; |
202 | u32 bank_reg; | ||
203 | bool banked_mn = !!rcg->mn[1].width; | 203 | bool banked_mn = !!rcg->mn[1].width; |
204 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
204 | struct clk_hw *hw = &rcg->clkr.hw; | 205 | struct clk_hw *hw = &rcg->clkr.hw; |
205 | 206 | ||
206 | enabled = __clk_is_enabled(hw->clk); | 207 | enabled = __clk_is_enabled(hw->clk); |
207 | 208 | ||
208 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 209 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
209 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 210 | bank = reg_to_bank(rcg, reg); |
210 | |||
211 | if (banked_mn) { | ||
212 | regp = &ctl; | ||
213 | bank_reg = rcg->clkr.enable_reg; | ||
214 | } else { | ||
215 | regp = &ns; | ||
216 | bank_reg = rcg->ns_reg; | ||
217 | } | ||
218 | |||
219 | bank = reg_to_bank(rcg, *regp); | ||
220 | new_bank = enabled ? !bank : bank; | 211 | new_bank = enabled ? !bank : bank; |
221 | 212 | ||
213 | ns_reg = rcg->ns_reg[new_bank]; | ||
214 | regmap_read(rcg->clkr.regmap, ns_reg, &ns); | ||
215 | |||
222 | if (banked_mn) { | 216 | if (banked_mn) { |
223 | mn = &rcg->mn[new_bank]; | 217 | mn = &rcg->mn[new_bank]; |
224 | md_reg = rcg->md_reg[new_bank]; | 218 | md_reg = rcg->md_reg[new_bank]; |
225 | 219 | ||
226 | ns |= BIT(mn->mnctr_reset_bit); | 220 | ns |= BIT(mn->mnctr_reset_bit); |
227 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 221 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
228 | 222 | ||
229 | regmap_read(rcg->clkr.regmap, md_reg, &md); | 223 | regmap_read(rcg->clkr.regmap, md_reg, &md); |
230 | md = mn_to_md(mn, f->m, f->n, md); | 224 | md = mn_to_md(mn, f->m, f->n, md); |
231 | regmap_write(rcg->clkr.regmap, md_reg, md); | 225 | regmap_write(rcg->clkr.regmap, md_reg, md); |
232 | 226 | ||
233 | ns = mn_to_ns(mn, f->m, f->n, ns); | 227 | ns = mn_to_ns(mn, f->m, f->n, ns); |
234 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 228 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
235 | 229 | ||
236 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | 230 | /* Two NS registers means mode control is in NS register */ |
237 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | 231 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) { |
232 | ns = mn_to_reg(mn, f->m, f->n, ns); | ||
233 | regmap_write(rcg->clkr.regmap, ns_reg, ns); | ||
234 | } else { | ||
235 | reg = mn_to_reg(mn, f->m, f->n, reg); | ||
236 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
237 | } | ||
238 | 238 | ||
239 | ns &= ~BIT(mn->mnctr_reset_bit); | 239 | ns &= ~BIT(mn->mnctr_reset_bit); |
240 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 240 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
241 | } else { | 241 | } |
242 | |||
243 | if (banked_p) { | ||
242 | p = &rcg->p[new_bank]; | 244 | p = &rcg->p[new_bank]; |
243 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); | 245 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); |
244 | } | 246 | } |
245 | 247 | ||
246 | s = &rcg->s[new_bank]; | 248 | s = &rcg->s[new_bank]; |
247 | ns = src_to_ns(s, s->parent_map[f->src], ns); | 249 | ns = src_to_ns(s, s->parent_map[f->src], ns); |
248 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 250 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
249 | 251 | ||
250 | if (enabled) { | 252 | if (enabled) { |
251 | *regp ^= BIT(rcg->mux_sel_bit); | 253 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
252 | regmap_write(rcg->clkr.regmap, bank_reg, *regp); | 254 | reg ^= BIT(rcg->mux_sel_bit); |
255 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
253 | } | 256 | } |
254 | } | 257 | } |
255 | 258 | ||
256 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) | 259 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) |
257 | { | 260 | { |
258 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 261 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
259 | u32 ns, ctl, md, reg; | 262 | u32 ns, md, reg; |
260 | int bank; | 263 | int bank; |
261 | struct freq_tbl f = { 0 }; | 264 | struct freq_tbl f = { 0 }; |
262 | bool banked_mn = !!rcg->mn[1].width; | 265 | bool banked_mn = !!rcg->mn[1].width; |
266 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
263 | 267 | ||
264 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 268 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
265 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
266 | reg = banked_mn ? ctl : ns; | ||
267 | |||
268 | bank = reg_to_bank(rcg, reg); | 269 | bank = reg_to_bank(rcg, reg); |
269 | 270 | ||
271 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
272 | |||
270 | if (banked_mn) { | 273 | if (banked_mn) { |
271 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 274 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
272 | f.m = md_to_m(&rcg->mn[bank], md); | 275 | f.m = md_to_m(&rcg->mn[bank], md); |
273 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); | 276 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); |
274 | } else { | ||
275 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
276 | } | 277 | } |
277 | f.src = index; | ||
278 | 278 | ||
279 | if (banked_p) | ||
280 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
281 | |||
282 | f.src = index; | ||
279 | configure_bank(rcg, &f); | 283 | configure_bank(rcg, &f); |
280 | 284 | ||
281 | return 0; | 285 | return 0; |
@@ -336,41 +340,30 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
336 | u32 m, n, pre_div, ns, md, mode, reg; | 340 | u32 m, n, pre_div, ns, md, mode, reg; |
337 | int bank; | 341 | int bank; |
338 | struct mn *mn; | 342 | struct mn *mn; |
343 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
339 | bool banked_mn = !!rcg->mn[1].width; | 344 | bool banked_mn = !!rcg->mn[1].width; |
340 | 345 | ||
341 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 346 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
342 | |||
343 | if (banked_mn) | ||
344 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, ®); | ||
345 | else | ||
346 | reg = ns; | ||
347 | |||
348 | bank = reg_to_bank(rcg, reg); | 347 | bank = reg_to_bank(rcg, reg); |
349 | 348 | ||
349 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
350 | m = n = pre_div = mode = 0; | ||
351 | |||
350 | if (banked_mn) { | 352 | if (banked_mn) { |
351 | mn = &rcg->mn[bank]; | 353 | mn = &rcg->mn[bank]; |
352 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 354 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
353 | m = md_to_m(mn, md); | 355 | m = md_to_m(mn, md); |
354 | n = ns_m_to_n(mn, ns, m); | 356 | n = ns_m_to_n(mn, ns, m); |
357 | /* Two NS registers means mode control is in NS register */ | ||
358 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) | ||
359 | reg = ns; | ||
355 | mode = reg_to_mnctr_mode(mn, reg); | 360 | mode = reg_to_mnctr_mode(mn, reg); |
356 | return calc_rate(parent_rate, m, n, mode, 0); | ||
357 | } else { | ||
358 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
359 | return calc_rate(parent_rate, 0, 0, 0, pre_div); | ||
360 | } | 361 | } |
361 | } | ||
362 | 362 | ||
363 | static const | 363 | if (banked_p) |
364 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | 364 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); |
365 | { | ||
366 | if (!f) | ||
367 | return NULL; | ||
368 | |||
369 | for (; f->freq; f++) | ||
370 | if (rate <= f->freq) | ||
371 | return f; | ||
372 | 365 | ||
373 | return NULL; | 366 | return calc_rate(parent_rate, m, n, mode, pre_div); |
374 | } | 367 | } |
375 | 368 | ||
376 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 369 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
@@ -379,7 +372,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, | |||
379 | { | 372 | { |
380 | unsigned long clk_flags; | 373 | unsigned long clk_flags; |
381 | 374 | ||
382 | f = find_freq(f, rate); | 375 | f = qcom_find_freq(f, rate); |
383 | if (!f) | 376 | if (!f) |
384 | return -EINVAL; | 377 | return -EINVAL; |
385 | 378 | ||
@@ -477,7 +470,7 @@ static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, | |||
477 | struct clk_rcg *rcg = to_clk_rcg(hw); | 470 | struct clk_rcg *rcg = to_clk_rcg(hw); |
478 | const struct freq_tbl *f; | 471 | const struct freq_tbl *f; |
479 | 472 | ||
480 | f = find_freq(rcg->freq_tbl, rate); | 473 | f = qcom_find_freq(rcg->freq_tbl, rate); |
481 | if (!f) | 474 | if (!f) |
482 | return -EINVAL; | 475 | return -EINVAL; |
483 | 476 | ||
@@ -497,7 +490,7 @@ static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) | |||
497 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 490 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
498 | const struct freq_tbl *f; | 491 | const struct freq_tbl *f; |
499 | 492 | ||
500 | f = find_freq(rcg->freq_tbl, rate); | 493 | f = qcom_find_freq(rcg->freq_tbl, rate); |
501 | if (!f) | 494 | if (!f) |
502 | return -EINVAL; | 495 | return -EINVAL; |
503 | 496 | ||