| From af9fac9c9a82bc908bec3faed8f6b88d713c8336 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 25 Mar 2021 13:26:38 -0600 |
| Subject: clk: si5341: Check for input clock presence and PLL lock on startup |
| |
| From: Robert Hancock <robert.hancock@calian.com> |
| |
| [ Upstream commit 71dcc4d1f7d2ad97ff7ab831281bc6893ff713a2 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/clk/clk-si5341.c | 26 ++++++++++++++++++++++++++ |
| 1 file changed, 26 insertions(+) |
| |
| 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]); |
| -- |
| 2.30.2 |
| |