On the new Allwinner H6 SoC, multiple PLL's are NMP style clocks
(modelled as NKMP with no K) and have fixed post-dividers.

Add fixed post divider support to the NKMP style clocks.

Signed-off-by: Icenowy Zheng <icen...@aosc.io>
---
Changes in v3:
- Rebased on newest linux-next/master.

No changes in v2.

 drivers/clk/sunxi-ng/ccu_nkmp.c | 20 +++++++++++++++++---
 drivers/clk/sunxi-ng/ccu_nkmp.h |  2 ++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index c3f6fe7be565..ebd9436d2c7c 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -95,7 +95,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
                                        unsigned long parent_rate)
 {
        struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
-       unsigned long n, m, k, p;
+       unsigned long n, m, k, p, rate;
        u32 reg;
 
        reg = readl(nkmp->common.base + nkmp->common.reg);
@@ -121,7 +121,11 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw 
*hw,
        p = reg >> nkmp->p.shift;
        p &= (1 << nkmp->p.width) - 1;
 
-       return ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p);
+       rate = ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p);
+       if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+               rate /= nkmp->fixed_post_div;
+
+       return rate;
 }
 
 static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -130,6 +134,9 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned 
long rate,
        struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
        struct _ccu_nkmp _nkmp;
 
+       if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+               rate *= nkmp->fixed_post_div;
+
        _nkmp.min_n = nkmp->n.min ?: 1;
        _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width;
        _nkmp.min_k = nkmp->k.min ?: 1;
@@ -141,8 +148,12 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, 
unsigned long rate,
 
        ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
 
-       return ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k,
+       rate = ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k,
                                  _nkmp.m, _nkmp.p);
+       if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+               rate = rate / nkmp->fixed_post_div;
+
+       return rate;
 }
 
 static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -154,6 +165,9 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned 
long rate,
        unsigned long flags;
        u32 reg;
 
+       if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+               rate = rate * nkmp->fixed_post_div;
+
        _nkmp.min_n = nkmp->n.min ?: 1;
        _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width;
        _nkmp.min_k = nkmp->k.min ?: 1;
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h
index a82facbc6144..6940503e7fc4 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.h
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.h
@@ -34,6 +34,8 @@ struct ccu_nkmp {
        struct ccu_div_internal         m;
        struct ccu_div_internal         p;
 
+       unsigned int            fixed_post_div;
+
        struct ccu_common       common;
 };
 
-- 
2.15.1

Reply via email to