[PATCH 1/2] clk: sunxi-ng: Support fixed post-dividers on MP style clocks

Chen-Yu Tsai wens at csie.org
Sun Dec 3 21:19:11 PST 2017


On the A64, the MMC module clocks are fixed in the new timing mode,
i.e. they do not have a bit to select the mode. These clocks have
a 2x divider somewhere between the clock and the MMC module.

To be consistent with other SoCs supporting the new timing mode,
we model the 2x divider as a fixed post-divider on the MMC module
clocks.

To do this, we first add fixed post-divider to the MP style clocks,
which the MMC module clocks are.

Signed-off-by: Chen-Yu Tsai <wens at csie.org>
---
 drivers/clk/sunxi-ng/ccu_mp.c | 20 ++++++++++++++++++--
 drivers/clk/sunxi-ng/ccu_mp.h | 24 ++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index 688855e7dc8c..5d0af4051737 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
 	unsigned int max_m, max_p;
 	unsigned int m, p;
 
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate *= cmp->fixed_post_div;
+
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
 	ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
+	rate = *parent_rate / p / m;
+
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= cmp->fixed_post_div;
 
-	return *parent_rate / p / m;
+	return rate;
 }
 
 static void ccu_mp_disable(struct clk_hw *hw)
@@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
 					unsigned long parent_rate)
 {
 	struct ccu_mp *cmp = hw_to_ccu_mp(hw);
+	unsigned long rate;
 	unsigned int m, p;
 	u32 reg;
 
@@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
 	p = reg >> cmp->p.shift;
 	p &= (1 << cmp->p.width) - 1;
 
-	return (parent_rate >> p) / m;
+	rate = (parent_rate >> p) / m;
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate /= cmp->fixed_post_div;
+
+	return rate;
 }
 
 static int ccu_mp_determine_rate(struct clk_hw *hw,
@@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
+	/* Adjust target rate according to post-dividers */
+	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+		rate = rate * cmp->fixed_post_div;
+
 	ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p);
 
 	spin_lock_irqsave(cmp->common.lock, flags);
diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h
index aaef11d747ea..5107635e61de 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.h
+++ b/drivers/clk/sunxi-ng/ccu_mp.h
@@ -33,9 +33,33 @@ struct ccu_mp {
 	struct ccu_div_internal		m;
 	struct ccu_div_internal		p;
 	struct ccu_mux_internal	mux;
+
+	unsigned int		fixed_post_div;
+
 	struct ccu_common	common;
 };
 
+#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
+					   _mshift, _mwidth,		\
+					   _pshift, _pwidth,		\
+					   _muxshift, _muxwidth,	\
+					   _gate, _postdiv, _flags)	\
+	struct ccu_mp _struct = {					\
+		.enable	= _gate,					\
+		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
+		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
+		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
+		.fixed_post_div	= _postdiv,				\
+		.common	= {						\
+			.reg		= _reg,				\
+			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
+			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
+							      _parents, \
+							      &ccu_mp_ops, \
+							      _flags),	\
+		}							\
+	}
+
 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
 				   _mshift, _mwidth,			\
 				   _pshift, _pwidth,			\
-- 
2.15.0




More information about the linux-arm-kernel mailing list