aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-si5341.c
diff options
context:
space:
mode:
authorRobert Hancock <robert.hancock@calian.com>2021-03-25 13:26:38 -0600
committerStephen Boyd <sboyd@kernel.org>2021-06-27 19:58:14 -0700
commit71dcc4d1f7d2ad97ff7ab831281bc6893ff713a2 (patch)
treea7e58904df3b046dbbe617fe879b8eaa60291ec7 /drivers/clk/clk-si5341.c
parentclk: si5341: Avoid divide errors due to bogus register contents (diff)
downloadlinux-dev-71dcc4d1f7d2ad97ff7ab831281bc6893ff713a2.tar.xz
linux-dev-71dcc4d1f7d2ad97ff7ab831281bc6893ff713a2.zip
clk: si5341: Check for input clock presence and PLL lock on startup
After initializing the device, wait for it to report that the input clock is present and the PLL has locked before declaring success. Fixes: 3044a860fd ("clk: Add Si5341/Si5340 driver") Signed-off-by: Robert Hancock <robert.hancock@calian.com> Link: https://lore.kernel.org/r/20210325192643.2190069-5-robert.hancock@calian.com Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers/clk/clk-si5341.c')
-rw-r--r--drivers/clk/clk-si5341.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index ac1ccec2b681..da40b90c2aa8 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -92,6 +92,9 @@ struct clk_si5341_output_config {
#define SI5341_PN_BASE 0x0002
#define SI5341_DEVICE_REV 0x0005
#define SI5341_STATUS 0x000C
+#define SI5341_LOS 0x000D
+#define SI5341_STATUS_STICKY 0x0011
+#define SI5341_LOS_STICKY 0x0012
#define SI5341_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021
#define SI5341_DEVICE_READY 0x00FE
@@ -99,6 +102,12 @@ struct clk_si5341_output_config {
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
+/* Status bits */
+#define SI5341_STATUS_SYSINCAL BIT(0)
+#define SI5341_STATUS_LOSXAXB BIT(1)
+#define SI5341_STATUS_LOSREF BIT(2)
+#define SI5341_STATUS_LOL BIT(3)
+
/* Input selection */
#define SI5341_IN_SEL_MASK 0x06
#define SI5341_IN_SEL_SHIFT 1
@@ -1416,6 +1425,7 @@ static int si5341_probe(struct i2c_client *client,
unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
bool initialization_required;
+ u32 status;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1583,6 +1593,22 @@ static int si5341_probe(struct i2c_client *client,
return err;
}
+ /* wait for device to report input clock present and PLL lock */
+ err = regmap_read_poll_timeout(data->regmap, SI5341_STATUS, status,
+ !(status & (SI5341_STATUS_LOSREF | SI5341_STATUS_LOL)),
+ 10000, 250000);
+ if (err) {
+ dev_err(&client->dev, "Error waiting for input clock or PLL lock\n");
+ return err;
+ }
+
+ /* clear sticky alarm bits from initialization */
+ err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
+ if (err) {
+ dev_err(&client->dev, "unable to clear sticky status\n");
+ return err;
+ }
+
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);