Lines Matching +full:rate +full:- +full:a
1 // SPDX-License-Identifier: GPL-2.0
8 * - Root source, usually 12MHz supplied by an external crystal
9 * - 3 PLLs which generate multiples of root rate [AUX, CPU, AUX2]
12 * - 6 clock dividers with:
18 * - up to 6 "internal" (fixed) consumers which:
24 * - sysbus clock: CPU core clock (CPUPLL) divided by 2, 3 or 4.
25 * depends on board design and should be set by bootloader, read-only.
26 * - peripheral clock: half the rate of sysbus clock, source for a lot
27 * of peripheral blocks, read-only.
28 * - memory clock: clk rate to main memory chips, depends on board
29 * design and is read-only,
30 * - lrclk: the static bus clock signal for synchronous operation.
40 #include <linux/clk-provider.h>
45 #include <asm/mach-au1x00/au1000.h>
48 * found any board yet which uses a different rate.
55 * especially which ones are share a clock line.
84 /* aliases for a few on-chip sources which are either shared
124 * On early Au1000, sys_cpupll was write-only. Since these in alchemy_clk_cpu_recalc()
159 return ERR_PTR(-ENOMEM); in alchemy_clk_setup_cpu()
166 h->init = &id; in alchemy_clk_setup_cpu()
189 struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); in alchemy_clk_aux_recalc() local
191 return (alchemy_rdsys(a->reg) & 0xff) * parent_rate; in alchemy_clk_aux_recalc()
195 unsigned long rate, in alchemy_clk_aux_setr() argument
198 struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); in alchemy_clk_aux_setr() local
199 unsigned long d = rate; in alchemy_clk_aux_setr()
201 if (rate) in alchemy_clk_aux_setr()
206 /* minimum is 84MHz, max is 756-1032 depending on variant */ in alchemy_clk_aux_setr()
207 if (((d < 7) && (d != 0)) || (d > a->maxmult)) in alchemy_clk_aux_setr()
208 return -EINVAL; in alchemy_clk_aux_setr()
210 alchemy_wrsys(d, a->reg); in alchemy_clk_aux_setr()
217 struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); in alchemy_clk_aux_determine_rate() local
220 if (!req->rate || !req->best_parent_rate) { in alchemy_clk_aux_determine_rate()
221 req->rate = 0; in alchemy_clk_aux_determine_rate()
226 mult = req->rate / req->best_parent_rate; in alchemy_clk_aux_determine_rate()
230 if (mult > a->maxmult) in alchemy_clk_aux_determine_rate()
231 mult = a->maxmult; in alchemy_clk_aux_determine_rate()
233 req->rate = req->best_parent_rate * mult; in alchemy_clk_aux_determine_rate()
250 struct alchemy_auxpll_clk *a; in alchemy_clk_setup_aux() local
252 a = kzalloc(sizeof(*a), GFP_KERNEL); in alchemy_clk_setup_aux()
253 if (!a) in alchemy_clk_setup_aux()
254 return ERR_PTR(-ENOMEM); in alchemy_clk_setup_aux()
262 a->reg = reg; in alchemy_clk_setup_aux()
263 a->maxmult = maxmult; in alchemy_clk_setup_aux()
264 a->hw.init = &id; in alchemy_clk_setup_aux()
266 c = clk_register(NULL, &a->hw); in alchemy_clk_setup_aux()
270 kfree(a); in alchemy_clk_setup_aux()
293 /* Peripheral clock runs at half the rate of sysbus clk */ in alchemy_clk_setup_periph()
368 /* data for fgen and csrc mux-dividers */
380 static long alchemy_calc_div(unsigned long rate, unsigned long prate, in alchemy_calc_div() argument
385 div1 = prate / rate; in alchemy_calc_div()
386 if ((prate / div1) > rate) in alchemy_calc_div()
389 if (scale == 2) { /* only div-by-multiple-of-2 possible */ in alchemy_calc_div()
394 div2 = (div1 / scale) - 1; /* value to write to register */ in alchemy_calc_div()
416 br = -EINVAL; in alchemy_clk_fgcs_detr()
420 * the one that gets closest to but not over the requested rate. in alchemy_clk_fgcs_detr()
429 * but this is a good-enough approximation for now. in alchemy_clk_fgcs_detr()
437 if (pr < req->rate) in alchemy_clk_fgcs_detr()
441 tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL); in alchemy_clk_fgcs_detr()
443 diff = req->rate - nr; in alchemy_clk_fgcs_detr()
444 if (nr > req->rate) in alchemy_clk_fgcs_detr()
457 /* if we couldn't get the exact rate we wanted from the enabled in alchemy_clk_fgcs_detr()
459 * to give us a rate we can divide down to the requested rate. in alchemy_clk_fgcs_detr()
463 tpr = req->rate * j; in alchemy_clk_fgcs_detr()
468 tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, in alchemy_clk_fgcs_detr()
471 diff = req->rate - nr; in alchemy_clk_fgcs_detr()
472 if (nr > req->rate) in alchemy_clk_fgcs_detr()
488 req->best_parent_rate = bpr; in alchemy_clk_fgcs_detr()
489 req->best_parent_hw = bpc; in alchemy_clk_fgcs_detr()
490 req->rate = br; in alchemy_clk_fgcs_detr()
500 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv1_en()
501 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv1_en()
502 v |= (1 << 1) << c->shift; in alchemy_clk_fgv1_en()
503 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv1_en()
504 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv1_en()
512 unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 1); in alchemy_clk_fgv1_isen()
522 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv1_dis()
523 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv1_dis()
524 v &= ~((1 << 1) << c->shift); in alchemy_clk_fgv1_dis()
525 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv1_dis()
526 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv1_dis()
534 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv1_setp()
535 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv1_setp()
537 v |= (1 << c->shift); in alchemy_clk_fgv1_setp()
539 v &= ~(1 << c->shift); in alchemy_clk_fgv1_setp()
540 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv1_setp()
541 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv1_setp()
550 return (alchemy_rdsys(c->reg) >> c->shift) & 1; in alchemy_clk_fgv1_getp()
553 static int alchemy_clk_fgv1_setr(struct clk_hw *hw, unsigned long rate, in alchemy_clk_fgv1_setr() argument
558 int sh = c->shift + 2; in alchemy_clk_fgv1_setr()
560 if (!rate || !parent_rate || rate > (parent_rate / 2)) in alchemy_clk_fgv1_setr()
561 return -EINVAL; in alchemy_clk_fgv1_setr()
562 ret = alchemy_calc_div(rate, parent_rate, 2, 512, &div); in alchemy_clk_fgv1_setr()
563 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv1_setr()
564 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv1_setr()
567 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv1_setr()
568 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv1_setr()
577 unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 2); in alchemy_clk_fgv1_recalc()
603 unsigned long v = alchemy_rdsys(c->reg); in __alchemy_clk_fgv2_en()
605 v &= ~(3 << c->shift); in __alchemy_clk_fgv2_en()
606 v |= (c->parent & 3) << c->shift; in __alchemy_clk_fgv2_en()
607 alchemy_wrsys(v, c->reg); in __alchemy_clk_fgv2_en()
608 c->isen = 1; in __alchemy_clk_fgv2_en()
617 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv2_en()
619 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv2_en()
628 return ((alchemy_rdsys(c->reg) >> c->shift) & 3) != 0; in alchemy_clk_fgv2_isen()
636 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv2_dis()
637 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv2_dis()
638 v &= ~(3 << c->shift); /* set input mux to "disabled" state */ in alchemy_clk_fgv2_dis()
639 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv2_dis()
640 c->isen = 0; in alchemy_clk_fgv2_dis()
641 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv2_dis()
649 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv2_setp()
650 c->parent = index + 1; /* value to write to register */ in alchemy_clk_fgv2_setp()
651 if (c->isen) in alchemy_clk_fgv2_setp()
653 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv2_setp()
663 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv2_getp()
664 v = c->parent - 1; in alchemy_clk_fgv2_getp()
665 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv2_getp()
669 /* fg0-2 and fg4-6 share a "scale"-bit. With this bit cleared, the
674 static int alchemy_clk_fgv2_setr(struct clk_hw *hw, unsigned long rate, in alchemy_clk_fgv2_setr() argument
678 int sh = c->shift + 2; in alchemy_clk_fgv2_setr()
681 if (!rate || !parent_rate || rate > parent_rate) in alchemy_clk_fgv2_setr()
682 return -EINVAL; in alchemy_clk_fgv2_setr()
684 v = alchemy_rdsys(c->reg) & (1 << 30); /* test "scale" bit */ in alchemy_clk_fgv2_setr()
685 ret = alchemy_calc_div(rate, parent_rate, v ? 1 : 2, in alchemy_clk_fgv2_setr()
688 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_fgv2_setr()
689 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv2_setr()
692 alchemy_wrsys(v, c->reg); in alchemy_clk_fgv2_setr()
693 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_fgv2_setr()
702 int sh = c->shift + 2; in alchemy_clk_fgv2_recalc()
705 v = alchemy_rdsys(c->reg); in alchemy_clk_fgv2_recalc()
719 if (alchemy_rdsys(c->reg) & (1 << 30)) { in alchemy_clk_fgv2_detr()
758 struct alchemy_fgcs_clk *a; in alchemy_clk_init_fgens() local
774 return -ENODEV; in alchemy_clk_init_fgens()
778 a = kcalloc(6, sizeof(*a), GFP_KERNEL); in alchemy_clk_init_fgens()
779 if (!a) in alchemy_clk_init_fgens()
780 return -ENOMEM; in alchemy_clk_init_fgens()
787 a->shift = 10 * (i < 3 ? i : i - 3); in alchemy_clk_init_fgens()
789 a->reg = AU1000_SYS_FREQCTRL1; in alchemy_clk_init_fgens()
790 a->reglock = &alchemy_clk_fg1_lock; in alchemy_clk_init_fgens()
792 a->reg = AU1000_SYS_FREQCTRL0; in alchemy_clk_init_fgens()
793 a->reglock = &alchemy_clk_fg0_lock; in alchemy_clk_init_fgens()
800 v = alchemy_rdsys(a->reg); in alchemy_clk_init_fgens()
801 a->parent = (v >> a->shift) & 3; in alchemy_clk_init_fgens()
802 if (!a->parent) { in alchemy_clk_init_fgens()
803 a->parent = 1; in alchemy_clk_init_fgens()
804 a->isen = 0; in alchemy_clk_init_fgens()
806 a->isen = 1; in alchemy_clk_init_fgens()
809 a->hw.init = &id; in alchemy_clk_init_fgens()
810 c = clk_register(NULL, &a->hw); in alchemy_clk_init_fgens()
815 a++; in alchemy_clk_init_fgens()
826 unsigned long v = alchemy_rdsys(c->reg); in alchemy_clk_csrc_isen()
828 return (((v >> c->shift) >> 2) & 7) != 0; in alchemy_clk_csrc_isen()
833 unsigned long v = alchemy_rdsys(c->reg); in __alchemy_clk_csrc_en()
835 v &= ~((7 << 2) << c->shift); in __alchemy_clk_csrc_en()
836 v |= ((c->parent & 7) << 2) << c->shift; in __alchemy_clk_csrc_en()
837 alchemy_wrsys(v, c->reg); in __alchemy_clk_csrc_en()
838 c->isen = 1; in __alchemy_clk_csrc_en()
847 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_csrc_en()
849 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_csrc_en()
859 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_csrc_dis()
860 v = alchemy_rdsys(c->reg); in alchemy_clk_csrc_dis()
861 v &= ~((3 << 2) << c->shift); /* mux to "disabled" state */ in alchemy_clk_csrc_dis()
862 alchemy_wrsys(v, c->reg); in alchemy_clk_csrc_dis()
863 c->isen = 0; in alchemy_clk_csrc_dis()
864 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_csrc_dis()
872 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_csrc_setp()
873 c->parent = index + 1; /* value to write to register */ in alchemy_clk_csrc_setp()
874 if (c->isen) in alchemy_clk_csrc_setp()
876 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_csrc_setp()
885 return c->parent - 1; in alchemy_clk_csrc_getp()
892 unsigned long v = (alchemy_rdsys(c->reg) >> c->shift) & 3; in alchemy_clk_csrc_recalc()
894 return parent_rate / c->dt[v]; in alchemy_clk_csrc_recalc()
897 static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, in alchemy_clk_csrc_setr() argument
904 if (!rate || !parent_rate || rate > parent_rate) in alchemy_clk_csrc_setr()
905 return -EINVAL; in alchemy_clk_csrc_setr()
907 d = (parent_rate + (rate / 2)) / rate; in alchemy_clk_csrc_setr()
909 return -EINVAL; in alchemy_clk_csrc_setr()
910 if ((d == 3) && (c->dt[2] != 3)) in alchemy_clk_csrc_setr()
914 if (c->dt[i] == d) in alchemy_clk_csrc_setr()
918 return -EINVAL; /* oops */ in alchemy_clk_csrc_setr()
920 spin_lock_irqsave(c->reglock, flags); in alchemy_clk_csrc_setr()
921 v = alchemy_rdsys(c->reg); in alchemy_clk_csrc_setr()
922 v &= ~(3 << c->shift); in alchemy_clk_csrc_setr()
923 v |= (i & 3) << c->shift; in alchemy_clk_csrc_setr()
924 alchemy_wrsys(v, c->reg); in alchemy_clk_csrc_setr()
925 spin_unlock_irqrestore(c->reglock, flags); in alchemy_clk_csrc_setr()
934 int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ in alchemy_clk_csrc_detr()
962 struct alchemy_fgcs_clk *a; in alchemy_clk_setup_imux() local
996 return -ENODEV; in alchemy_clk_setup_imux()
999 a = kcalloc(6, sizeof(*a), GFP_KERNEL); in alchemy_clk_setup_imux()
1000 if (!a) in alchemy_clk_setup_imux()
1001 return -ENOMEM; in alchemy_clk_setup_imux()
1010 a->shift = i * 5; in alchemy_clk_setup_imux()
1011 a->reg = AU1000_SYS_CLKSRC; in alchemy_clk_setup_imux()
1012 a->reglock = &alchemy_clk_csrc_lock; in alchemy_clk_setup_imux()
1013 a->dt = dt; in alchemy_clk_setup_imux()
1018 v = alchemy_rdsys(a->reg); in alchemy_clk_setup_imux()
1019 a->parent = ((v >> a->shift) >> 2) & 7; in alchemy_clk_setup_imux()
1020 if (!a->parent) { in alchemy_clk_setup_imux()
1021 a->parent = 1; in alchemy_clk_setup_imux()
1022 a->isen = 0; in alchemy_clk_setup_imux()
1024 a->isen = 1; in alchemy_clk_setup_imux()
1026 a->hw.init = &id; in alchemy_clk_setup_imux()
1027 c = clk_register(NULL, &a->hw); in alchemy_clk_setup_imux()
1033 a++; in alchemy_clk_setup_imux()
1081 /* peripheral clock: runs at half rate of sysbus clk */ in alchemy_clk_init()
1093 /* Frequency dividers 0-5 */ in alchemy_clk_init()
1096 ret = -ENODEV; in alchemy_clk_init()
1103 ret = -ENODEV; in alchemy_clk_init()
1108 while (t->base) { in alchemy_clk_init()
1109 if (t->cputype == ctype) in alchemy_clk_init()
1110 clk_add_alias(t->alias, NULL, t->base, NULL); in alchemy_clk_init()