Lines Matching +full:clk +full:- +full:div
1 // SPDX-License-Identifier: GPL-2.0
3 * R-Car Gen3 Clock Pulse Generator
5 * Copyright (C) 2015-2018 Glider bvba
8 * Based on clk-rcar-gen3.c
15 #include <linux/clk.h>
16 #include <linux/clk-provider.h>
25 #include "renesas-cpg-mssr.h"
26 #include "rcar-gen3-cpg.h"
63 csn->saved = readl(csn->reg); in cpg_simple_notifier_call()
67 writel(csn->saved, csn->reg); in cpg_simple_notifier_call()
76 csn->nb.notifier_call = cpg_simple_notifier_call; in cpg_simple_notifier_register()
77 raw_notifier_chain_register(notifiers, &csn->nb); in cpg_simple_notifier_register()
84 * prepare - clk_prepare only ensures that parents are prepared
85 * enable - clk_enable only ensures that parents are enabled
86 * rate - rate is adjustable. clk->rate = (parent->rate * mult / 32 ) / 2
87 * parent - fixed parent. No clk_set_parent support
110 val = readl(zclk->reg) & zclk->mask; in cpg_z_clk_recalc_rate()
111 mult = 32 - (val >> __ffs(zclk->mask)); in cpg_z_clk_recalc_rate()
114 32 * zclk->fixed_div); in cpg_z_clk_recalc_rate()
124 prate = req->best_parent_rate / zclk->fixed_div; in cpg_z_clk_determine_rate()
125 min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL); in cpg_z_clk_determine_rate()
126 max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL); in cpg_z_clk_determine_rate()
128 return -EINVAL; in cpg_z_clk_determine_rate()
130 mult = div64_ul(req->rate * 32ULL, prate); in cpg_z_clk_determine_rate()
133 req->rate = div_u64((u64)prate * mult, 32); in cpg_z_clk_determine_rate()
144 mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div, in cpg_z_clk_set_rate()
148 if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) in cpg_z_clk_set_rate()
149 return -EBUSY; in cpg_z_clk_set_rate()
151 cpg_reg_modify(zclk->reg, zclk->mask, in cpg_z_clk_set_rate()
152 ((32 - mult) << __ffs(zclk->mask)) & zclk->mask); in cpg_z_clk_set_rate()
158 cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK); in cpg_z_clk_set_rate()
169 for (i = 1000; i; i--) { in cpg_z_clk_set_rate()
170 if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) in cpg_z_clk_set_rate()
176 return -ETIMEDOUT; in cpg_z_clk_set_rate()
185 static struct clk * __init cpg_z_clk_register(const char *name, in cpg_z_clk_register()
188 unsigned int div, in cpg_z_clk_register() argument
193 struct clk *clk; in cpg_z_clk_register() local
197 return ERR_PTR(-ENOMEM); in cpg_z_clk_register()
205 zclk->reg = reg + CPG_FRQCRC; in cpg_z_clk_register()
206 zclk->kick_reg = reg + CPG_FRQCRB; in cpg_z_clk_register()
207 zclk->hw.init = &init; in cpg_z_clk_register()
208 zclk->mask = GENMASK(offset + 4, offset); in cpg_z_clk_register()
209 zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */ in cpg_z_clk_register()
211 clk = clk_register(NULL, &zclk->hw); in cpg_z_clk_register()
212 if (IS_ERR(clk)) in cpg_z_clk_register()
215 return clk; in cpg_z_clk_register()
233 .div = (sd_div), \
238 unsigned int div; member
250 * sd_srcfc sd_fc div
251 * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
252 *-------------------------------------------------------------------
266 * early ES versions of H3 and M3-W requires a specific setting to work.
288 cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, in cpg_sd_clock_enable()
289 clock->div_table[clock->cur_div_idx].val & in cpg_sd_clock_enable()
299 cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); in cpg_sd_clock_disable()
306 return !(readl(clock->csn.reg) & CPG_SD_STP_MASK); in cpg_sd_clock_is_enabled()
315 clock->div_table[clock->cur_div_idx].div); in cpg_sd_clock_recalc_rate()
326 for (i = 0; i < clock->div_num; i++) { in cpg_sd_clock_determine_rate()
327 calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, in cpg_sd_clock_determine_rate()
328 clock->div_table[i].div); in cpg_sd_clock_determine_rate()
329 if (calc_rate < req->min_rate || calc_rate > req->max_rate) in cpg_sd_clock_determine_rate()
332 diff = calc_rate > req->rate ? calc_rate - req->rate in cpg_sd_clock_determine_rate()
333 : req->rate - calc_rate; in cpg_sd_clock_determine_rate()
341 return -EINVAL; in cpg_sd_clock_determine_rate()
343 req->rate = best_rate; in cpg_sd_clock_determine_rate()
353 for (i = 0; i < clock->div_num; i++) in cpg_sd_clock_set_rate()
355 clock->div_table[i].div)) in cpg_sd_clock_set_rate()
358 if (i >= clock->div_num) in cpg_sd_clock_set_rate()
359 return -EINVAL; in cpg_sd_clock_set_rate()
361 clock->cur_div_idx = i; in cpg_sd_clock_set_rate()
363 cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, in cpg_sd_clock_set_rate()
364 clock->div_table[i].val & in cpg_sd_clock_set_rate()
381 #define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */
385 static struct clk * __init cpg_sd_clk_register(const char *name, in cpg_sd_clk_register()
391 struct clk *clk; in cpg_sd_clk_register() local
396 return ERR_PTR(-ENOMEM); in cpg_sd_clk_register()
404 clock->csn.reg = base + offset; in cpg_sd_clk_register()
405 clock->hw.init = &init; in cpg_sd_clk_register()
406 clock->div_table = cpg_sd_div_table; in cpg_sd_clk_register()
407 clock->div_num = ARRAY_SIZE(cpg_sd_div_table); in cpg_sd_clk_register()
410 clock->div_table++; in cpg_sd_clk_register()
411 clock->div_num--; in cpg_sd_clk_register()
414 val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK; in cpg_sd_clk_register()
415 val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); in cpg_sd_clk_register()
416 writel(val, clock->csn.reg); in cpg_sd_clk_register()
418 clk = clk_register(NULL, &clock->hw); in cpg_sd_clk_register()
419 if (IS_ERR(clk)) in cpg_sd_clk_register()
422 cpg_simple_notifier_register(notifiers, &clock->csn); in cpg_sd_clk_register()
423 return clk; in cpg_sd_clk_register()
427 return clk; in cpg_sd_clk_register()
431 struct clk_divider div; member
448 static struct clk * __init cpg_rpc_clk_register(const char *name, in cpg_rpc_clk_register()
453 struct clk *clk; in cpg_rpc_clk_register() local
457 return ERR_PTR(-ENOMEM); in cpg_rpc_clk_register()
459 rpc->div.reg = base + CPG_RPCCKCR; in cpg_rpc_clk_register()
460 rpc->div.width = 3; in cpg_rpc_clk_register()
461 rpc->div.table = cpg_rpc_div_table; in cpg_rpc_clk_register()
462 rpc->div.lock = &cpg_lock; in cpg_rpc_clk_register()
464 rpc->gate.reg = base + CPG_RPCCKCR; in cpg_rpc_clk_register()
465 rpc->gate.bit_idx = 8; in cpg_rpc_clk_register()
466 rpc->gate.flags = CLK_GATE_SET_TO_DISABLE; in cpg_rpc_clk_register()
467 rpc->gate.lock = &cpg_lock; in cpg_rpc_clk_register()
469 rpc->csn.reg = base + CPG_RPCCKCR; in cpg_rpc_clk_register()
471 clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, in cpg_rpc_clk_register()
472 &rpc->div.hw, &clk_divider_ops, in cpg_rpc_clk_register()
473 &rpc->gate.hw, &clk_gate_ops, in cpg_rpc_clk_register()
475 if (IS_ERR(clk)) { in cpg_rpc_clk_register()
477 return clk; in cpg_rpc_clk_register()
480 cpg_simple_notifier_register(notifiers, &rpc->csn); in cpg_rpc_clk_register()
481 return clk; in cpg_rpc_clk_register()
489 static struct clk * __init cpg_rpcd2_clk_register(const char *name, in cpg_rpcd2_clk_register()
494 struct clk *clk; in cpg_rpcd2_clk_register() local
498 return ERR_PTR(-ENOMEM); in cpg_rpcd2_clk_register()
500 rpcd2->fixed.mult = 1; in cpg_rpcd2_clk_register()
501 rpcd2->fixed.div = 2; in cpg_rpcd2_clk_register()
503 rpcd2->gate.reg = base + CPG_RPCCKCR; in cpg_rpcd2_clk_register()
504 rpcd2->gate.bit_idx = 9; in cpg_rpcd2_clk_register()
505 rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE; in cpg_rpcd2_clk_register()
506 rpcd2->gate.lock = &cpg_lock; in cpg_rpcd2_clk_register()
508 clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, in cpg_rpcd2_clk_register()
509 &rpcd2->fixed.hw, &clk_fixed_factor_ops, in cpg_rpcd2_clk_register()
510 &rpcd2->gate.hw, &clk_gate_ops, in cpg_rpcd2_clk_register()
512 if (IS_ERR(clk)) in cpg_rpcd2_clk_register()
515 return clk; in cpg_rpcd2_clk_register()
547 struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, in rcar_gen3_cpg_clk_register()
549 struct clk **clks, void __iomem *base, in rcar_gen3_cpg_clk_register()
552 const struct clk *parent; in rcar_gen3_cpg_clk_register()
554 unsigned int div = 1; in rcar_gen3_cpg_clk_register() local
557 parent = clks[core->parent & 0xffff]; /* some types use high bits */ in rcar_gen3_cpg_clk_register()
561 switch (core->type) { in rcar_gen3_cpg_clk_register()
563 div = cpg_pll_config->extal_div; in rcar_gen3_cpg_clk_register()
580 mult = cpg_pll_config->pll1_mult; in rcar_gen3_cpg_clk_register()
581 div = cpg_pll_config->pll1_div; in rcar_gen3_cpg_clk_register()
598 mult = cpg_pll_config->pll3_mult; in rcar_gen3_cpg_clk_register()
599 div = cpg_pll_config->pll3_div; in rcar_gen3_cpg_clk_register()
616 return cpg_sd_clk_register(core->name, base, core->offset, in rcar_gen3_cpg_clk_register()
625 return ERR_PTR(-ENOMEM); in rcar_gen3_cpg_clk_register()
627 csn->reg = base + CPG_RCKCR; in rcar_gen3_cpg_clk_register()
633 value = readl(csn->reg) & 0x3f; in rcar_gen3_cpg_clk_register()
640 writel(value, csn->reg); in rcar_gen3_cpg_clk_register()
655 if (cpg_mode & BIT(core->offset)) { in rcar_gen3_cpg_clk_register()
656 div = core->div & 0xffff; in rcar_gen3_cpg_clk_register()
658 parent = clks[core->parent >> 16]; in rcar_gen3_cpg_clk_register()
661 div = core->div >> 16; in rcar_gen3_cpg_clk_register()
667 return cpg_z_clk_register(core->name, __clk_get_name(parent), in rcar_gen3_cpg_clk_register()
668 base, core->div, core->offset); in rcar_gen3_cpg_clk_register()
674 div = cpg_pll_config->osc_prediv * core->div; in rcar_gen3_cpg_clk_register()
683 div = core->div & 0xffff; in rcar_gen3_cpg_clk_register()
685 parent = clks[core->parent >> 16]; in rcar_gen3_cpg_clk_register()
688 div = core->div >> 16; in rcar_gen3_cpg_clk_register()
693 return clk_register_divider_table(NULL, core->name, in rcar_gen3_cpg_clk_register()
700 return cpg_rpc_clk_register(core->name, base, in rcar_gen3_cpg_clk_register()
704 return cpg_rpcd2_clk_register(core->name, base, in rcar_gen3_cpg_clk_register()
708 return ERR_PTR(-EINVAL); in rcar_gen3_cpg_clk_register()
711 return clk_register_fixed_factor(NULL, core->name, in rcar_gen3_cpg_clk_register()
712 __clk_get_name(parent), 0, mult, div); in rcar_gen3_cpg_clk_register()
725 cpg_quirks = (uintptr_t)attr->data; in rcar_gen3_cpg_init()