clk: si5341: Check for input clock presence and PLL lock on startup

[ 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>
This commit is contained in:
Robert Hancock
2021-03-25 13:26:38 -06:00
committed by Greg Kroah-Hartman
parent 42ac32d834
commit 55aaba36d7

View File

@@ -92,6 +92,9 @@ struct clk_si5341_output_config {
#define SI5341_PN_BASE 0x0002 #define SI5341_PN_BASE 0x0002
#define SI5341_DEVICE_REV 0x0005 #define SI5341_DEVICE_REV 0x0005
#define SI5341_STATUS 0x000C #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_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021 #define SI5341_IN_SEL 0x0021
#define SI5341_DEVICE_READY 0x00FE #define SI5341_DEVICE_READY 0x00FE
@@ -99,6 +102,12 @@ struct clk_si5341_output_config {
#define SI5341_IN_EN 0x0949 #define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A #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 */ /* Input selection */
#define SI5341_IN_SEL_MASK 0x06 #define SI5341_IN_SEL_MASK 0x06
#define SI5341_IN_SEL_SHIFT 1 #define SI5341_IN_SEL_SHIFT 1
@@ -1416,6 +1425,7 @@ static int si5341_probe(struct i2c_client *client,
unsigned int i; unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS]; struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
bool initialization_required; bool initialization_required;
u32 status;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
@@ -1583,6 +1593,22 @@ static int si5341_probe(struct i2c_client *client,
return err; 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 */ /* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i) for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]); devm_kfree(&client->dev, (void *)synth_clock_names[i]);