Commit 71dcc4d1 authored by Robert Hancock's avatar Robert Hancock Committed by Stephen Boyd
Browse files

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: 3044a860 ("clk: Add Si5341/Si5340 driver")
Signed-off-by: default avatarRobert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-5-robert.hancock@calian.com


Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 78f6f406
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -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]);