Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: meson: fractional pll support

Fractional MPLLs are a superset of the existing AmLogic MPLLs. They add
in a couple of new bitfields for further dividing the clock rate to
achieve rates with fractional hertz.

Tested-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>

+45 -2
+30 -2
drivers/clk/meson/clk-pll.c
··· 53 53 struct parm *p; 54 54 unsigned long parent_rate_mhz = parent_rate / 1000000; 55 55 unsigned long rate_mhz; 56 - u16 n, m, od; 56 + u16 n, m, frac = 0, od, od2 = 0; 57 57 u32 reg; 58 58 59 59 p = &pll->n; ··· 68 68 reg = readl(pll->base + p->reg_off); 69 69 od = PARM_GET(p->width, p->shift, reg); 70 70 71 - rate_mhz = (parent_rate_mhz * m / n) >> od; 71 + p = &pll->od2; 72 + if (p->width) { 73 + reg = readl(pll->base + p->reg_off); 74 + od2 = PARM_GET(p->width, p->shift, reg); 75 + } 76 + 77 + p = &pll->frac; 78 + if (p->width) { 79 + reg = readl(pll->base + p->reg_off); 80 + frac = PARM_GET(p->width, p->shift, reg); 81 + rate_mhz = (parent_rate_mhz * m + \ 82 + (parent_rate_mhz * frac >> 12)) * 2 / n; 83 + rate_mhz = rate_mhz >> od >> od2; 84 + } else 85 + rate_mhz = (parent_rate_mhz * m / n) >> od >> od2; 72 86 73 87 return rate_mhz * 1000000; 74 88 } ··· 168 154 reg = readl(pll->base + p->reg_off); 169 155 reg = PARM_SET(p->width, p->shift, reg, rate_set->od); 170 156 writel(reg, pll->base + p->reg_off); 157 + 158 + p = &pll->od2; 159 + if (p->width) { 160 + reg = readl(pll->base + p->reg_off); 161 + reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); 162 + writel(reg, pll->base + p->reg_off); 163 + } 164 + 165 + p = &pll->frac; 166 + if (p->width) { 167 + reg = readl(pll->base + p->reg_off); 168 + reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); 169 + writel(reg, pll->base + p->reg_off); 170 + } 171 171 172 172 p = &pll->n; 173 173 ret = meson_clk_pll_wait_lock(pll, p);
+15
drivers/clk/meson/clkc.h
··· 40 40 u16 m; 41 41 u16 n; 42 42 u16 od; 43 + u16 od2; 44 + u16 frac; 43 45 }; 46 + 44 47 #define PLL_RATE(_r, _m, _n, _od) \ 45 48 { \ 46 49 .rate = (_r), \ ··· 52 49 .od = (_od), \ 53 50 } \ 54 51 52 + #define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \ 53 + { \ 54 + .rate = (_r), \ 55 + .m = (_m), \ 56 + .n = (_n), \ 57 + .od = (_od), \ 58 + .od2 = (_od2), \ 59 + .frac = (_frac), \ 60 + } \ 61 + 55 62 struct meson_clk_pll { 56 63 struct clk_hw hw; 57 64 void __iomem *base; 58 65 struct parm m; 59 66 struct parm n; 67 + struct parm frac; 60 68 struct parm od; 69 + struct parm od2; 61 70 const struct pll_rate_table *rate_table; 62 71 unsigned int rate_count; 63 72 spinlock_t *lock;