clk: si5341: Add sysfs properties to allow checking/resetting device faults

[ Upstream commit 9b13ff4340dff30f361462999a6a122fcc4e473f ]

Add sysfs property files to allow viewing the current and latched states of
the input present and PLL lock bits, and allow resetting the latched fault
state. This allows manual checks or automated userspace polling for faults
occurring after initialization.

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-10-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Stable-dep-of: 2560114c06d7 ("clk: si5341: return error if one synth clock registration fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Robert Hancock 2021-03-25 13:26:43 -06:00 committed by Greg Kroah-Hartman
parent fc813d0573
commit 0401139800

View File

@ -1450,6 +1450,94 @@ static int si5341_clk_select_active_input(struct clk_si5341 *data)
return res;
}
static ssize_t input_present_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct clk_si5341 *data = dev_get_drvdata(dev);
u32 status;
int res = regmap_read(data->regmap, SI5341_STATUS, &status);
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present);
static ssize_t input_present_sticky_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct clk_si5341 *data = dev_get_drvdata(dev);
u32 status;
int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present_sticky);
static ssize_t pll_locked_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct clk_si5341 *data = dev_get_drvdata(dev);
u32 status;
int res = regmap_read(data->regmap, SI5341_STATUS, &status);
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked);
static ssize_t pll_locked_sticky_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct clk_si5341 *data = dev_get_drvdata(dev);
u32 status;
int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked_sticky);
static ssize_t clear_sticky_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct clk_si5341 *data = dev_get_drvdata(dev);
long val;
if (kstrtol(buf, 10, &val))
return -EINVAL;
if (val) {
int res = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
if (res < 0)
return res;
}
return count;
}
static DEVICE_ATTR_WO(clear_sticky);
static const struct attribute *si5341_attributes[] = {
&dev_attr_input_present.attr,
&dev_attr_input_present_sticky.attr,
&dev_attr_pll_locked.attr,
&dev_attr_pll_locked_sticky.attr,
&dev_attr_clear_sticky.attr,
NULL
};
static int si5341_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -1676,6 +1764,12 @@ static int si5341_probe(struct i2c_client *client,
goto cleanup;
}
err = sysfs_create_files(&client->dev.kobj, si5341_attributes);
if (err) {
dev_err(&client->dev, "unable to create sysfs files\n");
goto cleanup;
}
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
@ -1695,6 +1789,8 @@ static int si5341_remove(struct i2c_client *client)
struct clk_si5341 *data = i2c_get_clientdata(client);
int i;
sysfs_remove_files(&client->dev.kobj, si5341_attributes);
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
if (data->clk[i].vddo_reg)
regulator_disable(data->clk[i].vddo_reg);