[PATCH 02/14] clk: sunxi: factors: Implement clock min and max frequencies

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




In the A13, the out of reset frequency for the PLL6 is too high to be actually
working.

Hence, we need to be able to lower down its frequency whenever we need to use
the clock to some acceptable frequency.

This patch adds two new properties in the clock-nodes, clk-min-frequency and
clk-max-frequency, to specify acceptable boundaries for proper clock
operations.

It also adds supports in the sunxi factor clocks driver to use these
boundaries, enforce them at prepare time to make sure that the drivers will
have a decent frequency, even though it never called set_rate, but also make
sure we never cross these boundaries.

Signed-off-by: Maxime Ripard <maxime.ripard@xxxxxxxxxxxxxxxxxx>
---
 drivers/clk/sunxi/clk-factors.c | 28 ++++++++++++++++++++++++++++
 drivers/clk/sunxi/clk-factors.h |  2 ++
 2 files changed, 30 insertions(+)

diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 2057c8ac648f..f8f45a7ffcd7 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -39,6 +39,25 @@
 #define FACTOR_SET(bit, len, reg, val) \
 	(((reg) & CLRMASK(len, bit)) | (val << (bit)))
 
+static int clk_factors_prepare(struct clk_hw *hw)
+{
+	struct clk_factors *factors = to_clk_factors(hw);
+	unsigned long rate = __clk_get_rate(hw->clk);
+	unsigned long new_rate;
+
+	if (factors->min_rate && (rate < factors->min_rate))
+		new_rate = factors->min_rate;
+	else if (factors->max_rate && (rate > factors->max_rate))
+		new_rate = factors->max_rate;
+	else
+		return 0;
+
+	pr_info("Initial rate of %s out of boundaries.. Changing rate from %lu to %lu\n",
+		__clk_get_name(hw->clk), rate, new_rate);
+
+	return clk_set_rate(hw->clk, rate);
+}
+
 static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
 					     unsigned long parent_rate)
 {
@@ -74,6 +93,11 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
 	factors->get_factors((u32 *)&rate, (u32)*parent_rate,
 			     NULL, NULL, NULL, NULL);
 
+	if (factors->max_rate && (rate > factors->max_rate))
+		rate = factors->max_rate;
+	else if (factors->min_rate && (rate < factors->min_rate))
+		rate = factors->min_rate;
+
 	return rate;
 }
 
@@ -123,6 +147,9 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
 
 	factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p);
 
+	if ((rate > factors->max_rate) || (rate < factors->min_rate))
+		return -EINVAL;
+
 	if (factors->lock)
 		spin_lock_irqsave(factors->lock, flags);
 
@@ -149,6 +176,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
 
 const struct clk_ops clk_factors_ops = {
 	.determine_rate = clk_factors_determine_rate,
+	.prepare = clk_factors_prepare,
 	.recalc_rate = clk_factors_recalc_rate,
 	.round_rate = clk_factors_round_rate,
 	.set_rate = clk_factors_set_rate,
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index d2d0efa39379..2b8579a24039 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -24,6 +24,8 @@ struct clk_factors {
 	struct clk_factors_config *config;
 	void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p);
 	spinlock_t *lock;
+	unsigned long max_rate;
+	unsigned long min_rate;
 };
 
 extern const struct clk_ops clk_factors_ops;
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux