From 3e7a1a8e1f3e472e473e5ab47329bb44a9ec24ba Mon Sep 17 00:00:00 2001
From: Daniel Mack <zonque@gmail.com>
Date: Sun, 17 Feb 2013 18:01:08 +0100
Subject: [PATCH] si5351: cache 'prepared' bits of clocks

---
 drivers/clk/clk-si5351.c | 47 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index b526742..528f88a 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -54,6 +54,7 @@ struct si5351_hw_data {
 	struct si5351_driver_data	*drvdata;
 	struct si5351_parameters	params;
 	unsigned char			num;
+	bool				prepared;
 };
 
 struct si5351_driver_data {
@@ -70,6 +71,9 @@ struct si5351_driver_data {
 	struct si5351_hw_data	pll[2];
 	struct si5351_hw_data	*msynth;
 	struct si5351_hw_data	*clkout;
+
+	bool			xtal_prepared;
+	bool			clkin_prepared;
 };
 
 static const char const *si5351_input_names[] = {
@@ -223,6 +227,8 @@ static int si5351_xtal_prepare(struct clk_hw *hw)
 		container_of(hw, struct si5351_driver_data, xtal);
 	si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
 			SI5351_XTAL_ENABLE, SI5351_XTAL_ENABLE);
+	drvdata->xtal_prepared  = true;
+
 	return 0;
 }
 
@@ -232,15 +238,14 @@ static void si5351_xtal_unprepare(struct clk_hw *hw)
 		container_of(hw, struct si5351_driver_data, xtal);
 	si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
 			SI5351_XTAL_ENABLE, 0);
+	drvdata->xtal_prepared  = false;
 }
 
 static int si5351_xtal_is_enabled(struct clk_hw *hw)
 {
 	struct si5351_driver_data *drvdata =
 		container_of(hw, struct si5351_driver_data, xtal);
-	unsigned char reg;
-	reg = si5351_reg_read(drvdata, SI5351_FANOUT_ENABLE);
-	return (reg & SI5351_XTAL_ENABLE) ? 1 : 0;
+	return drvdata->xtal_prepared;
 }
 
 static const struct clk_ops si5351_xtal_ops = {
@@ -258,7 +263,8 @@ static int si5351_clkin_prepare(struct clk_hw *hw)
 		container_of(hw, struct si5351_driver_data, clkin);
 	si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
 			SI5351_CLKIN_ENABLE, SI5351_CLKIN_ENABLE);
-	return 0;
+	drvdata->clkin_prepared  = true;
+	return 1;
 }
 
 static void si5351_clkin_unprepare(struct clk_hw *hw)
@@ -267,15 +273,14 @@ static void si5351_clkin_unprepare(struct clk_hw *hw)
 		container_of(hw, struct si5351_driver_data, clkin);
 	si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
 			SI5351_CLKIN_ENABLE, 0);
+	drvdata->clkin_prepared  = false;
 }
 
 static int si5351_clkin_is_enabled(struct clk_hw *hw)
 {
 	struct si5351_driver_data *drvdata =
 		container_of(hw, struct si5351_driver_data, clkin);
-	unsigned char reg;
-	reg = si5351_reg_read(drvdata, SI5351_FANOUT_ENABLE);
-	return (reg & SI5351_CLKIN_ENABLE) ? 1 : 0;
+	return drvdata->clkin_prepared;
 }
 
 /*
@@ -660,6 +665,7 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
 		m += hwdata->params.p2;
 		m += 512 * hwdata->params.p3;
 	}
+printk(" XXXX m %d (%d)\n", m, hwdata->num);
 	do_div(rate, m);
 
 	dev_dbg(&hwdata->drvdata->client->dev,
@@ -887,6 +893,8 @@ static int si5351_clkout_prepare(struct clk_hw *hw)
 			SI5351_CLK_POWERDOWN, 0);
 	si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
 			(1 << hwdata->num), 0);
+	hwdata->prepared = true;
+
 	return 0;
 }
 
@@ -899,21 +907,28 @@ static void si5351_clkout_unprepare(struct clk_hw *hw)
 			SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN);
 	si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
 			(1 << hwdata->num), (1 << hwdata->num));
+	hwdata->prepared = false;
 }
 
-static int si5351_clkout_is_enabled(struct clk_hw *hw)
+static void __si5351_read_clkout_prepared(struct si5351_hw_data *hwdata)
 {
-	struct si5351_hw_data *hwdata =
-		container_of(hw, struct si5351_hw_data, hw);
 	unsigned char val;
 
 	val = si5351_reg_read(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num);
 	if (val & SI5351_CLK_POWERDOWN)
-		return 0;
+		hwdata->prepared = false;
 	val = si5351_reg_read(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL);
 	if (val & (1 << hwdata->num))
-		return 0;
-	return 1;
+		hwdata->prepared = false;
+	hwdata->prepared = true;
+}
+
+static int si5351_clkout_is_enabled(struct clk_hw *hw)
+{
+	struct si5351_hw_data *hwdata =
+		container_of(hw, struct si5351_hw_data, hw);
+
+	return hwdata->prepared;
 }
 
 static u8 si5351_clkout_get_parent(struct clk_hw *hw)
@@ -1306,6 +1321,11 @@ static int si5351_i2c_probe(
 		return -EINVAL;
 	}
 
+	/* read current clock enable bits */
+	ret = si5351_reg_read(drvdata, SI5351_FANOUT_ENABLE);
+	drvdata->xtal_prepared = !!(ret & SI5351_XTAL_ENABLE);
+	drvdata->clkin_prepared  = !!(ret & SI5351_CLKIN_ENABLE);
+
 	/* register PLLB or VXCO (Si5351B) */
 	drvdata->pll[1].num = 1;
 	drvdata->pll[1].drvdata = drvdata;
@@ -1394,6 +1414,7 @@ static int si5351_i2c_probe(
 			return -EINVAL;
 		}
 		drvdata->onecell.clks[n] = clk;
+		__si5351_read_clkout_prepared(&drvdata->clkout[n]);
 	}
 
 	/* setup clock setup from DT */
-- 
1.8.1.2

