Lines Matching +full:divider +full:- +full:clock

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * clk-xgene.c - AppliedMicro X-Gene Clock Interface
13 #include <linux/clk-provider.h>
41 /* PLL Clock */
63 data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); in xgene_clk_pll_is_enabled()
81 pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); in xgene_clk_pll_recalc_rate()
83 if (pllclk->version <= 1) { in xgene_clk_pll_recalc_rate()
84 if (pllclk->type == PLL_TYPE_PCP) { in xgene_clk_pll_recalc_rate()
86 * PLL VCO = Reference clock * NF in xgene_clk_pll_recalc_rate()
93 * Fref = Reference Clock / NREF; in xgene_clk_pll_recalc_rate()
105 * fvco = Reference clock * FBDIVC in xgene_clk_pll_recalc_rate()
113 pllclk->version); in xgene_clk_pll_recalc_rate()
132 /* allocate the APM clock structure */ in xgene_register_clk_pll()
135 return ERR_PTR(-ENOMEM); in xgene_register_clk_pll()
143 apmclk->version = version; in xgene_register_clk_pll()
144 apmclk->reg = reg; in xgene_register_clk_pll()
145 apmclk->lock = lock; in xgene_register_clk_pll()
146 apmclk->pll_offset = pll_offset; in xgene_register_clk_pll()
147 apmclk->type = type; in xgene_register_clk_pll()
148 apmclk->hw.init = &init; in xgene_register_clk_pll()
150 /* Register the clock */ in xgene_register_clk_pll()
151 clk = clk_register(dev, &apmclk->hw); in xgene_register_clk_pll()
162 if (of_device_is_compatible(np, "apm,xgene-socpll-clock")) in xgene_pllclk_version()
164 if (of_device_is_compatible(np, "apm,xgene-pcppll-clock")) in xgene_pllclk_version()
171 const char *clk_name = np->full_name; in xgene_pllclk_init()
181 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_pllclk_init()
189 pr_debug("Add %s clock PLL\n", clk_name); in xgene_pllclk_init()
204 * struct xgene_clk_pmd - PMD clock
206 * @hw: handle between common and hardware-specific interfaces
212 * @flags: XGENE_CLK_PMD_SCALE_INVERTED - By default the scaler is the value read
217 * 0 for (denom - 0) / denom,
218 * 1 for (denom - 1) / denom and etc.
244 if (fd->lock) in xgene_clk_pmd_recalc_rate()
245 spin_lock_irqsave(fd->lock, flags); in xgene_clk_pmd_recalc_rate()
247 __acquire(fd->lock); in xgene_clk_pmd_recalc_rate()
249 val = readl(fd->reg); in xgene_clk_pmd_recalc_rate()
251 if (fd->lock) in xgene_clk_pmd_recalc_rate()
252 spin_unlock_irqrestore(fd->lock, flags); in xgene_clk_pmd_recalc_rate()
254 __release(fd->lock); in xgene_clk_pmd_recalc_rate()
258 scale = (val & fd->mask) >> fd->shift; in xgene_clk_pmd_recalc_rate()
259 if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) in xgene_clk_pmd_recalc_rate()
260 scale = fd->denom - scale; in xgene_clk_pmd_recalc_rate()
265 do_div(ret, fd->denom); in xgene_clk_pmd_recalc_rate()
283 ret = rate * fd->denom; in xgene_clk_pmd_round_rate()
287 do_div(ret, fd->denom); in xgene_clk_pmd_round_rate()
306 ret = rate * fd->denom; in xgene_clk_pmd_set_rate()
310 if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) in xgene_clk_pmd_set_rate()
311 scale = fd->denom - scale; in xgene_clk_pmd_set_rate()
313 scale--; in xgene_clk_pmd_set_rate()
315 if (fd->lock) in xgene_clk_pmd_set_rate()
316 spin_lock_irqsave(fd->lock, flags); in xgene_clk_pmd_set_rate()
318 __acquire(fd->lock); in xgene_clk_pmd_set_rate()
320 val = readl(fd->reg); in xgene_clk_pmd_set_rate()
321 val &= ~fd->mask; in xgene_clk_pmd_set_rate()
322 val |= (scale << fd->shift); in xgene_clk_pmd_set_rate()
323 writel(val, fd->reg); in xgene_clk_pmd_set_rate()
325 if (fd->lock) in xgene_clk_pmd_set_rate()
326 spin_unlock_irqrestore(fd->lock, flags); in xgene_clk_pmd_set_rate()
328 __release(fd->lock); in xgene_clk_pmd_set_rate()
351 return ERR_PTR(-ENOMEM); in xgene_register_clk_pmd()
359 fd->reg = reg; in xgene_register_clk_pmd()
360 fd->shift = shift; in xgene_register_clk_pmd()
361 fd->mask = (BIT(width) - 1) << shift; in xgene_register_clk_pmd()
362 fd->denom = denom; in xgene_register_clk_pmd()
363 fd->flags = clk_flags; in xgene_register_clk_pmd()
364 fd->lock = lock; in xgene_register_clk_pmd()
365 fd->hw.init = &init; in xgene_register_clk_pmd()
367 clk = clk_register(dev, &fd->hw); in xgene_register_clk_pmd()
379 const char *clk_name = np->full_name; in xgene_pmdclk_init()
402 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_pmdclk_init()
415 pr_debug("Add %s clock\n", clk_name); in xgene_pmdclk_init()
422 /* IP Clock */
424 void __iomem *csr_reg; /* CSR for IP clock */
425 u32 reg_clk_offset; /* Offset to clock enable CSR */
426 u32 reg_clk_mask; /* Mask bit for clock enable */
429 void __iomem *divider_reg; /* CSR for divider */
430 u32 reg_divider_offset; /* Offset to divider register */
431 u32 reg_divider_shift; /* Bit shift to divider field */
432 u32 reg_divider_width; /* Width of the bit to divider field */
449 if (pclk->lock) in xgene_clk_enable()
450 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_enable()
452 if (pclk->param.csr_reg) { in xgene_clk_enable()
453 pr_debug("%s clock enabled\n", clk_hw_get_name(hw)); in xgene_clk_enable()
454 /* First enable the clock */ in xgene_clk_enable()
455 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_enable()
456 pclk->param.reg_clk_offset); in xgene_clk_enable()
457 data |= pclk->param.reg_clk_mask; in xgene_clk_enable()
458 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_enable()
459 pclk->param.reg_clk_offset); in xgene_clk_enable()
462 pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, in xgene_clk_enable()
466 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_enable()
467 pclk->param.reg_csr_offset); in xgene_clk_enable()
468 data &= ~pclk->param.reg_csr_mask; in xgene_clk_enable()
469 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_enable()
470 pclk->param.reg_csr_offset); in xgene_clk_enable()
473 pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, in xgene_clk_enable()
477 if (pclk->lock) in xgene_clk_enable()
478 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_enable()
489 if (pclk->lock) in xgene_clk_disable()
490 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_disable()
492 if (pclk->param.csr_reg) { in xgene_clk_disable()
493 pr_debug("%s clock disabled\n", clk_hw_get_name(hw)); in xgene_clk_disable()
495 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_disable()
496 pclk->param.reg_csr_offset); in xgene_clk_disable()
497 data |= pclk->param.reg_csr_mask; in xgene_clk_disable()
498 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_disable()
499 pclk->param.reg_csr_offset); in xgene_clk_disable()
501 /* Second disable the clock */ in xgene_clk_disable()
502 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_disable()
503 pclk->param.reg_clk_offset); in xgene_clk_disable()
504 data &= ~pclk->param.reg_clk_mask; in xgene_clk_disable()
505 xgene_clk_write(data, pclk->param.csr_reg + in xgene_clk_disable()
506 pclk->param.reg_clk_offset); in xgene_clk_disable()
509 if (pclk->lock) in xgene_clk_disable()
510 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_disable()
518 if (pclk->param.csr_reg) { in xgene_clk_is_enabled()
519 pr_debug("%s clock checking\n", clk_hw_get_name(hw)); in xgene_clk_is_enabled()
520 data = xgene_clk_read(pclk->param.csr_reg + in xgene_clk_is_enabled()
521 pclk->param.reg_clk_offset); in xgene_clk_is_enabled()
522 pr_debug("%s clock is %s\n", clk_hw_get_name(hw), in xgene_clk_is_enabled()
523 data & pclk->param.reg_clk_mask ? "enabled" : in xgene_clk_is_enabled()
529 return data & pclk->param.reg_clk_mask ? 1 : 0; in xgene_clk_is_enabled()
538 if (pclk->param.divider_reg) { in xgene_clk_recalc_rate()
539 data = xgene_clk_read(pclk->param.divider_reg + in xgene_clk_recalc_rate()
540 pclk->param.reg_divider_offset); in xgene_clk_recalc_rate()
541 data >>= pclk->param.reg_divider_shift; in xgene_clk_recalc_rate()
542 data &= (1 << pclk->param.reg_divider_width) - 1; in xgene_clk_recalc_rate()
544 pr_debug("%s clock recalc rate %ld parent %ld\n", in xgene_clk_recalc_rate()
550 pr_debug("%s clock recalc rate %ld parent %ld\n", in xgene_clk_recalc_rate()
562 u32 divider; in xgene_clk_set_rate() local
565 if (pclk->lock) in xgene_clk_set_rate()
566 spin_lock_irqsave(pclk->lock, flags); in xgene_clk_set_rate()
568 if (pclk->param.divider_reg) { in xgene_clk_set_rate()
569 /* Let's compute the divider */ in xgene_clk_set_rate()
572 divider_save = divider = parent_rate / rate; /* Rounded down */ in xgene_clk_set_rate()
573 divider &= (1 << pclk->param.reg_divider_width) - 1; in xgene_clk_set_rate()
574 divider <<= pclk->param.reg_divider_shift; in xgene_clk_set_rate()
576 /* Set new divider */ in xgene_clk_set_rate()
577 data = xgene_clk_read(pclk->param.divider_reg + in xgene_clk_set_rate()
578 pclk->param.reg_divider_offset); in xgene_clk_set_rate()
579 data &= ~(((1 << pclk->param.reg_divider_width) - 1) in xgene_clk_set_rate()
580 << pclk->param.reg_divider_shift); in xgene_clk_set_rate()
581 data |= divider; in xgene_clk_set_rate()
582 xgene_clk_write(data, pclk->param.divider_reg + in xgene_clk_set_rate()
583 pclk->param.reg_divider_offset); in xgene_clk_set_rate()
584 pr_debug("%s clock set rate %ld\n", clk_hw_get_name(hw), in xgene_clk_set_rate()
590 if (pclk->lock) in xgene_clk_set_rate()
591 spin_unlock_irqrestore(pclk->lock, flags); in xgene_clk_set_rate()
601 u32 divider; in xgene_clk_round_rate() local
603 if (pclk->param.divider_reg) { in xgene_clk_round_rate()
604 /* Let's compute the divider */ in xgene_clk_round_rate()
607 divider = parent_rate / rate; /* Rounded down */ in xgene_clk_round_rate()
609 divider = 1; in xgene_clk_round_rate()
612 return parent_rate / divider; in xgene_clk_round_rate()
633 /* allocate the APM clock structure */ in xgene_register_clk()
636 return ERR_PTR(-ENOMEM); in xgene_register_clk()
644 apmclk->lock = lock; in xgene_register_clk()
645 apmclk->hw.init = &init; in xgene_register_clk()
646 apmclk->param = *parameters; in xgene_register_clk()
648 /* Register the clock */ in xgene_register_clk()
649 clk = clk_register(dev, &apmclk->hw); in xgene_register_clk()
656 /* Register the clock for lookup */ in xgene_register_clk()
667 const char *clk_name = np->full_name; in xgene_devclk_init()
696 if (strcmp(res.name, "div-reg") == 0) in xgene_devclk_init()
698 else /* if (strcmp(res->name, "csr-reg") == 0) */ in xgene_devclk_init()
701 if (of_property_read_u32(np, "csr-offset", &parameters.reg_csr_offset)) in xgene_devclk_init()
703 if (of_property_read_u32(np, "csr-mask", &parameters.reg_csr_mask)) in xgene_devclk_init()
705 if (of_property_read_u32(np, "enable-offset", in xgene_devclk_init()
708 if (of_property_read_u32(np, "enable-mask", &parameters.reg_clk_mask)) in xgene_devclk_init()
710 if (of_property_read_u32(np, "divider-offset", in xgene_devclk_init()
713 if (of_property_read_u32(np, "divider-width", in xgene_devclk_init()
716 if (of_property_read_u32(np, "divider-shift", in xgene_devclk_init()
719 of_property_read_string(np, "clock-output-names", &clk_name); in xgene_devclk_init()
725 pr_debug("Add %s clock\n", clk_name); in xgene_devclk_init()
739 CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
740 CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
741 CLK_OF_DECLARE(xgene_pmd_clock, "apm,xgene-pmd-clock", xgene_pmdclk_init);
742 CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
744 CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
746 CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);