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:

committed by
Greg Kroah-Hartman

parent
42ac32d834
commit
55aaba36d7
@@ -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]);
|
||||||
|
Reference in New Issue
Block a user