Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Robert Hancock and committed by
Stephen Boyd
9b13ff43 2f02c5e4

+96
+96
drivers/clk/clk-si5341.c
··· 1457 1457 return res; 1458 1458 } 1459 1459 1460 + static ssize_t input_present_show(struct device *dev, 1461 + struct device_attribute *attr, 1462 + char *buf) 1463 + { 1464 + struct clk_si5341 *data = dev_get_drvdata(dev); 1465 + u32 status; 1466 + int res = regmap_read(data->regmap, SI5341_STATUS, &status); 1467 + 1468 + if (res < 0) 1469 + return res; 1470 + res = !(status & SI5341_STATUS_LOSREF); 1471 + return snprintf(buf, PAGE_SIZE, "%d\n", res); 1472 + } 1473 + static DEVICE_ATTR_RO(input_present); 1474 + 1475 + static ssize_t input_present_sticky_show(struct device *dev, 1476 + struct device_attribute *attr, 1477 + char *buf) 1478 + { 1479 + struct clk_si5341 *data = dev_get_drvdata(dev); 1480 + u32 status; 1481 + int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status); 1482 + 1483 + if (res < 0) 1484 + return res; 1485 + res = !(status & SI5341_STATUS_LOSREF); 1486 + return snprintf(buf, PAGE_SIZE, "%d\n", res); 1487 + } 1488 + static DEVICE_ATTR_RO(input_present_sticky); 1489 + 1490 + static ssize_t pll_locked_show(struct device *dev, 1491 + struct device_attribute *attr, 1492 + char *buf) 1493 + { 1494 + struct clk_si5341 *data = dev_get_drvdata(dev); 1495 + u32 status; 1496 + int res = regmap_read(data->regmap, SI5341_STATUS, &status); 1497 + 1498 + if (res < 0) 1499 + return res; 1500 + res = !(status & SI5341_STATUS_LOL); 1501 + return snprintf(buf, PAGE_SIZE, "%d\n", res); 1502 + } 1503 + static DEVICE_ATTR_RO(pll_locked); 1504 + 1505 + static ssize_t pll_locked_sticky_show(struct device *dev, 1506 + struct device_attribute *attr, 1507 + char *buf) 1508 + { 1509 + struct clk_si5341 *data = dev_get_drvdata(dev); 1510 + u32 status; 1511 + int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status); 1512 + 1513 + if (res < 0) 1514 + return res; 1515 + res = !(status & SI5341_STATUS_LOL); 1516 + return snprintf(buf, PAGE_SIZE, "%d\n", res); 1517 + } 1518 + static DEVICE_ATTR_RO(pll_locked_sticky); 1519 + 1520 + static ssize_t clear_sticky_store(struct device *dev, 1521 + struct device_attribute *attr, 1522 + const char *buf, size_t count) 1523 + { 1524 + struct clk_si5341 *data = dev_get_drvdata(dev); 1525 + long val; 1526 + 1527 + if (kstrtol(buf, 10, &val)) 1528 + return -EINVAL; 1529 + if (val) { 1530 + int res = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0); 1531 + 1532 + if (res < 0) 1533 + return res; 1534 + } 1535 + return count; 1536 + } 1537 + static DEVICE_ATTR_WO(clear_sticky); 1538 + 1539 + static const struct attribute *si5341_attributes[] = { 1540 + &dev_attr_input_present.attr, 1541 + &dev_attr_input_present_sticky.attr, 1542 + &dev_attr_pll_locked.attr, 1543 + &dev_attr_pll_locked_sticky.attr, 1544 + &dev_attr_clear_sticky.attr, 1545 + NULL 1546 + }; 1547 + 1460 1548 static int si5341_probe(struct i2c_client *client, 1461 1549 const struct i2c_device_id *id) 1462 1550 { ··· 1775 1687 goto cleanup; 1776 1688 } 1777 1689 1690 + err = sysfs_create_files(&client->dev.kobj, si5341_attributes); 1691 + if (err) { 1692 + dev_err(&client->dev, "unable to create sysfs files\n"); 1693 + goto cleanup; 1694 + } 1695 + 1778 1696 /* Free the names, clk framework makes copies */ 1779 1697 for (i = 0; i < data->num_synth; ++i) 1780 1698 devm_kfree(&client->dev, (void *)synth_clock_names[i]); ··· 1799 1705 { 1800 1706 struct clk_si5341 *data = i2c_get_clientdata(client); 1801 1707 int i; 1708 + 1709 + sysfs_remove_files(&client->dev.kobj, si5341_attributes); 1802 1710 1803 1711 for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) { 1804 1712 if (data->clk[i].vddo_reg)