clk: meson: fractional pll support
authorMichael Turquette <mturquette@baylibre.com>
Tue, 7 Jun 2016 01:08:15 +0000 (18:08 -0700)
committerMichael Turquette <mturquette@baylibre.com>
Thu, 23 Jun 2016 01:05:47 +0000 (18:05 -0700)
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>
drivers/clk/meson/clk-pll.c
drivers/clk/meson/clkc.h

index 60c6b94..4adc1e8 100644 (file)
@@ -53,7 +53,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
        struct parm *p;
        unsigned long parent_rate_mhz = parent_rate / 1000000;
        unsigned long rate_mhz;
-       u16 n, m, od;
+       u16 n, m, frac = 0, od, od2 = 0;
        u32 reg;
 
        p = &pll->n;
@@ -68,7 +68,21 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
        reg = readl(pll->base + p->reg_off);
        od = PARM_GET(p->width, p->shift, reg);
 
-       rate_mhz = (parent_rate_mhz * m / n) >> od;
+       p = &pll->od2;
+       if (p->width) {
+               reg = readl(pll->base + p->reg_off);
+               od2 = PARM_GET(p->width, p->shift, reg);
+       }
+
+       p = &pll->frac;
+       if (p->width) {
+               reg = readl(pll->base + p->reg_off);
+               frac = PARM_GET(p->width, p->shift, reg);
+               rate_mhz = (parent_rate_mhz * m + \
+                               (parent_rate_mhz * frac >> 12)) * 2 / n;
+               rate_mhz = rate_mhz >> od >> od2;
+       } else
+               rate_mhz = (parent_rate_mhz * m / n) >> od >> od2;
 
        return rate_mhz * 1000000;
 }
@@ -155,6 +169,20 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
        writel(reg, pll->base + p->reg_off);
 
+       p = &pll->od2;
+       if (p->width) {
+               reg = readl(pll->base + p->reg_off);
+               reg = PARM_SET(p->width, p->shift, reg, rate_set->od2);
+               writel(reg, pll->base + p->reg_off);
+       }
+
+       p = &pll->frac;
+       if (p->width) {
+               reg = readl(pll->base + p->reg_off);
+               reg = PARM_SET(p->width, p->shift, reg, rate_set->frac);
+               writel(reg, pll->base + p->reg_off);
+       }
+
        p = &pll->n;
        ret = meson_clk_pll_wait_lock(pll, p);
        if (ret) {
index 73f0146..53326c3 100644 (file)
@@ -40,7 +40,10 @@ struct pll_rate_table {
        u16             m;
        u16             n;
        u16             od;
+       u16             od2;
+       u16             frac;
 };
+
 #define PLL_RATE(_r, _m, _n, _od)                                      \
        {                                                               \
                .rate           = (_r),                                 \
@@ -49,12 +52,24 @@ struct pll_rate_table {
                .od             = (_od),                                \
        }                                                               \
 
+#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac)                    \
+       {                                                               \
+               .rate           = (_r),                                 \
+               .m              = (_m),                                 \
+               .n              = (_n),                                 \
+               .od             = (_od),                                \
+               .od2            = (_od2),                               \
+               .frac           = (_frac),                              \
+       }                                                               \
+
 struct meson_clk_pll {
        struct clk_hw hw;
        void __iomem *base;
        struct parm m;
        struct parm n;
+       struct parm frac;
        struct parm od;
+       struct parm od2;
        const struct pll_rate_table *rate_table;
        unsigned int rate_count;
        spinlock_t *lock;