diff mbox

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

Message ID 1405588134-2396-3-git-send-email-maxime.ripard@free-electrons.com (mailing list archive)
State New, archived
Headers show

Commit Message

Maxime Ripard July 17, 2014, 9:08 a.m. UTC
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@free-electrons.com>
---
 drivers/clk/sunxi/clk-factors.c | 28 ++++++++++++++++++++++++++++
 drivers/clk/sunxi/clk-factors.h |  2 ++
 2 files changed, 30 insertions(+)

Comments

Emilio López July 17, 2014, 4:09 p.m. UTC | #1
Hi Maxime,

El 17/07/14 06:08, Maxime Ripard escribió:
> 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.

This paragraph looks out of place

>
> 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@free-electrons.com>
> ---
(...)
>
> @@ -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;

Printing an error message here may come in handy in the future, what do 
you think?

Thanks for working on this!

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

Patch

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;