mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
clk: si5341: Add sysfs properties to allow checking/resetting device faults
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>
This commit is contained in:
parent
2f02c5e42a
commit
9b13ff4340
1 changed files with 96 additions and 0 deletions
|
@ -1457,6 +1457,94 @@ static int si5341_clk_select_active_input(struct clk_si5341 *data)
|
||||||
return res;
|
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,
|
static int si5341_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -1687,6 +1775,12 @@ static int si5341_probe(struct i2c_client *client,
|
||||||
goto cleanup;
|
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 */
|
/* 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]);
|
||||||
|
@ -1706,6 +1800,8 @@ static int si5341_remove(struct i2c_client *client)
|
||||||
struct clk_si5341 *data = i2c_get_clientdata(client);
|
struct clk_si5341 *data = i2c_get_clientdata(client);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
sysfs_remove_files(&client->dev.kobj, si5341_attributes);
|
||||||
|
|
||||||
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
|
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
|
||||||
if (data->clk[i].vddo_reg)
|
if (data->clk[i].vddo_reg)
|
||||||
regulator_disable(data->clk[i].vddo_reg);
|
regulator_disable(data->clk[i].vddo_reg);
|
||||||
|
|
Loading…
Reference in a new issue