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(-)
@@ -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