Lines Matching +full:no +full:- +full:divider
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * clk-xgene.c - AppliedMicro X-Gene Clock Interface
14 #include <linux/clk-provider.h>
64 data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); in xgene_clk_pll_is_enabled()
82 pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); in xgene_clk_pll_recalc_rate()
84 if (pllclk->version <= 1) { in xgene_clk_pll_recalc_rate()
85 if (pllclk->type == PLL_TYPE_PCP) { in xgene_clk_pll_recalc_rate()
114 pllclk->version); in xgene_clk_pll_recalc_rate()
136 return ERR_PTR(-ENOMEM); in xgene_register_clk_pll()
144 apmclk->version = version; in xgene_register_clk_pll()
145 apmclk->reg = reg; in xgene_register_clk_pll()
146 apmclk->lock = lock; in xgene_register_clk_pll()
147 apmclk->pll_offset = pll_offset; in xgene_register_clk_pll()
148 apmclk->type = type; in xgene_register_clk_pll()
149 apmclk->hw.init = &init; in xgene_register_clk_pll()
152 clk = clk_register(dev, &apmclk->hw); in xgene_register_clk_pll()
163 if (of_device_is_compatible(np, "apm,xgene-socpll-clock")) in xgene_pllclk_version()
165 if (of_device_is_compatible(np, "apm,xgene-pcppll-clock")) in xgene_pllclk_version()
172 const char *clk_name = np->full_name; in xgene_pllclk_init()
182 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_pllclk_init()
205 * struct xgene_clk_pmd - PMD clock
207 * @hw: handle between common and hardware-specific interfaces
213 * @flags: XGENE_CLK_PMD_SCALE_INVERTED - By default the scaler is the value read
218 * 0 for (denom - 0) / denom,
219 * 1 for (denom - 1) / denom and etc.
245 if (fd->lock) in xgene_clk_pmd_recalc_rate()
246 spin_lock_irqsave(fd->lock, flags); in xgene_clk_pmd_recalc_rate()
248 __acquire(fd->lock); in xgene_clk_pmd_recalc_rate()
250 val = readl(fd->reg); in xgene_clk_pmd_recalc_rate()
252 if (fd->lock) in xgene_clk_pmd_recalc_rate()
253 spin_unlock_irqrestore(fd->lock, flags); in xgene_clk_pmd_recalc_rate()
255 __release(fd->lock); in xgene_clk_pmd_recalc_rate()
259 scale = (val & fd->mask) >> fd->shift; in xgene_clk_pmd_recalc_rate()
260 if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) in xgene_clk_pmd_recalc_rate()
261 scale = fd->denom - scale; in xgene_clk_pmd_recalc_rate()
266 do_div(ret, fd->denom); in xgene_clk_pmd_recalc_rate()
280 if (!req->rate || req->rate >= req->best_parent_rate) { in xgene_clk_pmd_determine_rate()
281 req->rate = req->best_parent_rate; in xgene_clk_pmd_determine_rate()
287 ret = req->rate * fd->denom; in xgene_clk_pmd_determine_rate()
288 scale = DIV_ROUND_UP_ULL(ret, req->best_parent_rate); in xgene_clk_pmd_determine_rate()
290 ret = (u64)req->best_parent_rate * scale; in xgene_clk_pmd_determine_rate()
291 do_div(ret, fd->denom); in xgene_clk_pmd_determine_rate()
293 req->rate = ret; in xgene_clk_pmd_determine_rate()
312 ret = rate * fd->denom; in xgene_clk_pmd_set_rate()
316 if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) in xgene_clk_pmd_set_rate()
317 scale = fd->denom - scale; in xgene_clk_pmd_set_rate()
319 scale--; in xgene_clk_pmd_set_rate()
321 if (fd->lock) in xgene_clk_pmd_set_rate()
322 spin_lock_irqsave(fd->lock, flags); in xgene_clk_pmd_set_rate()
324 __acquire(fd->lock); in xgene_clk_pmd_set_rate()
326 val = readl(fd->reg); in xgene_clk_pmd_set_rate()
327 val &= ~fd->mask; in xgene_clk_pmd_set_rate()
328 val |= (scale << fd->shift); in xgene_clk_pmd_set_rate()
329 writel(val, fd->reg); in xgene_clk_pmd_set_rate()
331 if (fd->lock) in xgene_clk_pmd_set_rate()
332 spin_unlock_irqrestore(fd->lock, flags); in xgene_clk_pmd_set_rate()
334 __release(fd->lock); in xgene_clk_pmd_set_rate()
357 return ERR_PTR(-ENOMEM); in xgene_register_clk_pmd()
365 fd->reg = reg; in xgene_register_clk_pmd()
366 fd->shift = shift; in xgene_register_clk_pmd()
367 fd->mask = (BIT(width) - 1) << shift; in xgene_register_clk_pmd()
368 fd->denom = denom; in xgene_register_clk_pmd()
369 fd->flags = clk_flags; in xgene_register_clk_pmd()
370 fd->lock = lock; in xgene_register_clk_pmd()
371 fd->hw.init = &init; in xgene_register_clk_pmd()
373 clk = clk_register(dev, &fd->hw); in xgene_register_clk_pmd()
385 const char *clk_name = np->full_name; in xgene_pmdclk_init()
400 pr_err("no DTS register for %pOF\n", np); in xgene_pmdclk_init()
408 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_pmdclk_init()
435 void __iomem *divider_reg; /* CSR for divider */
436 u32 reg_divider_offset; /* Offset to divider register */
437 u32 reg_divider_shift; /* Bit shift to divider field */
438 u32 reg_divider_width; /* Width of the bit to divider field */
455 if (pclk->lock) in xgene_clk_enable()
456 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_enable()
458 if (pclk->param.csr_reg) { in xgene_clk_enable()
461 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_enable()
462 pclk->param.reg_clk_offset); in xgene_clk_enable()
463 data |= pclk->param.reg_clk_mask; in xgene_clk_enable()
464 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_enable()
465 pclk->param.reg_clk_offset); in xgene_clk_enable()
468 pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, in xgene_clk_enable()
472 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_enable()
473 pclk->param.reg_csr_offset); in xgene_clk_enable()
474 data &= ~pclk->param.reg_csr_mask; in xgene_clk_enable()
475 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_enable()
476 pclk->param.reg_csr_offset); in xgene_clk_enable()
479 pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, in xgene_clk_enable()
483 if (pclk->lock) in xgene_clk_enable()
484 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_enable()
495 if (pclk->lock) in xgene_clk_disable()
496 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_disable()
498 if (pclk->param.csr_reg) { in xgene_clk_disable()
501 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_disable()
502 pclk->param.reg_csr_offset); in xgene_clk_disable()
503 data |= pclk->param.reg_csr_mask; in xgene_clk_disable()
504 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_disable()
505 pclk->param.reg_csr_offset); in xgene_clk_disable()
508 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_disable()
509 pclk->param.reg_clk_offset); in xgene_clk_disable()
510 data &= ~pclk->param.reg_clk_mask; in xgene_clk_disable()
511 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_disable()
512 pclk->param.reg_clk_offset); in xgene_clk_disable()
515 if (pclk->lock) in xgene_clk_disable()
516 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_disable()
524 if (pclk->param.csr_reg) { in xgene_clk_is_enabled()
526 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_is_enabled()
527 pclk->param.reg_clk_offset); in xgene_clk_is_enabled()
529 str_enabled_disabled(data & pclk->param.reg_clk_mask)); in xgene_clk_is_enabled()
534 return data & pclk->param.reg_clk_mask ? 1 : 0; in xgene_clk_is_enabled()
543 if (pclk->param.divider_reg) { in xgene_clk_recalc_rate()
544 data = xgene_clk_read(pclk->param.divider_reg + in xgene_clk_recalc_rate()
545 pclk->param.reg_divider_offset); in xgene_clk_recalc_rate()
546 data >>= pclk->param.reg_divider_shift; in xgene_clk_recalc_rate()
547 data &= (1 << pclk->param.reg_divider_width) - 1; in xgene_clk_recalc_rate()
567 u32 divider; in xgene_clk_set_rate() local
570 if (pclk->lock) in xgene_clk_set_rate()
571 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_set_rate()
573 if (pclk->param.divider_reg) { in xgene_clk_set_rate()
574 /* Let's compute the divider */ in xgene_clk_set_rate()
577 divider_save = divider = parent_rate / rate; /* Rounded down */ in xgene_clk_set_rate()
578 divider &= (1 << pclk->param.reg_divider_width) - 1; in xgene_clk_set_rate()
579 divider <<= pclk->param.reg_divider_shift; in xgene_clk_set_rate()
581 /* Set new divider */ in xgene_clk_set_rate()
582 data = xgene_clk_read(pclk->param.divider_reg + in xgene_clk_set_rate()
583 pclk->param.reg_divider_offset); in xgene_clk_set_rate()
584 data &= ~(((1 << pclk->param.reg_divider_width) - 1) in xgene_clk_set_rate()
585 << pclk->param.reg_divider_shift); in xgene_clk_set_rate()
586 data |= divider; in xgene_clk_set_rate()
587 xgene_clk_write(data, pclk->param.divider_reg + in xgene_clk_set_rate()
588 pclk->param.reg_divider_offset); in xgene_clk_set_rate()
595 if (pclk->lock) in xgene_clk_set_rate()
596 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_set_rate()
605 unsigned long parent_rate = req->best_parent_rate; in xgene_clk_determine_rate()
606 u32 divider; in xgene_clk_determine_rate() local
608 if (pclk->param.divider_reg) { in xgene_clk_determine_rate()
609 /* Let's compute the divider */ in xgene_clk_determine_rate()
610 if (req->rate > parent_rate) in xgene_clk_determine_rate()
611 req->rate = parent_rate; in xgene_clk_determine_rate()
612 divider = parent_rate / req->rate; /* Rounded down */ in xgene_clk_determine_rate()
614 divider = 1; in xgene_clk_determine_rate()
617 req->rate = parent_rate / divider; in xgene_clk_determine_rate()
643 return ERR_PTR(-ENOMEM); in xgene_register_clk()
651 apmclk->lock = lock; in xgene_register_clk()
652 apmclk->hw.init = &init; in xgene_register_clk()
653 apmclk->param = *parameters; in xgene_register_clk()
656 clk = clk_register(dev, &apmclk->hw); in xgene_register_clk()
674 const char *clk_name = np->full_name; in xgene_devclk_init()
693 pr_err("no DTS register for %pOF\n", np); in xgene_devclk_init()
703 if (strcmp(res.name, "div-reg") == 0) in xgene_devclk_init()
705 else /* if (strcmp(res->name, "csr-reg") == 0) */ in xgene_devclk_init()
708 if (of_property_read_u32(np, "csr-offset", ¶meters.reg_csr_offset)) in xgene_devclk_init()
710 if (of_property_read_u32(np, "csr-mask", ¶meters.reg_csr_mask)) in xgene_devclk_init()
712 if (of_property_read_u32(np, "enable-offset", in xgene_devclk_init()
715 if (of_property_read_u32(np, "enable-mask", ¶meters.reg_clk_mask)) in xgene_devclk_init()
717 if (of_property_read_u32(np, "divider-offset", in xgene_devclk_init()
720 if (of_property_read_u32(np, "divider-width", in xgene_devclk_init()
723 if (of_property_read_u32(np, "divider-shift", in xgene_devclk_init()
726 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_devclk_init()
746 CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
747 CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
748 CLK_OF_DECLARE(xgene_pmd_clock, "apm,xgene-pmd-clock", xgene_pmdclk_init);
749 CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
751 CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
753 CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);