[PATCH 6.18 168/309] hwmon: (pmbus) Introduce the concept of "write-only" attributes

Greg Kroah-Hartman
2026-03-31T17:05:19Z

From: Guenter Roeck <linux@roeck-us.net>

[ Upstream commit cd658475e7694d58e1c40dabc1dacf8431ccedb2 ]

Attributes intended to clear sensor history are intended to be writeable
only. Reading those attributes today results in reporting more or less
random values. To avoid ABI surprises, have those attributes explicitly
return 0 when reading.

Fixes: 787c095edaa9d ("hwmon: (pmbus/core) Add support for rated attributes")
Reviewed-by: Sanman Pradhan <psanman@juniper.net>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/pmbus/pmbus_core.c | 32 ++++++++++++++++++++++++--------
1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index ecd1dddcbe0ff..cbc36f0ba4bf9 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1209,6 +1209,12 @@ static ssize_t pmbus_show_boolean(struct device *dev,
return sysfs_emit(buf, "%d\n", val);
}

+static ssize_t pmbus_show_zero(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sysfs_emit(buf, "0\n");
+}
+
static ssize_t pmbus_show_sensor(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -1407,7 +1413,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
int reg,
enum pmbus_sensor_classes class,
bool update, bool readonly,
- bool convert)
+ bool writeonly, bool convert)
{
struct pmbus_sensor *sensor;
struct device_attribute *a;
@@ -1436,7 +1442,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
sensor->data = -ENODATA;
pmbus_dev_attr_init(a, sensor->name,
readonly ? 0444 : 0644,
- pmbus_show_sensor, pmbus_set_sensor);
+ writeonly ? pmbus_show_zero : pmbus_show_sensor,
+ pmbus_set_sensor);

if (pmbus_add_attribute(data, &a->attr))
return NULL;
@@ -1496,6 +1503,7 @@ struct pmbus_limit_attr {
u16 reg; /* Limit register */
u16 sbit; /* Alarm attribute status bit */
bool readonly:1; /* True if the attribute is read-only */
+ bool writeonly:1; /* True if the attribute is write-only */
bool update:1; /* True if register needs updates */
bool low:1; /* True if low limit; for limits with compare functions only */
const char *attr; /* Attribute name */
@@ -1545,7 +1553,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
curr = pmbus_add_sensor(data, name, l->attr, index,
page, 0xff, l->reg, attr->class,
attr->update || l->update,
- l->readonly, true);
+ l->readonly, l->writeonly, true);
if (!curr)
return -ENOMEM;
if (l->sbit && (info->func[page] & attr->sfunc)) {
@@ -1585,7 +1593,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
return ret;
}
base = pmbus_add_sensor(data, name, "input", index, page, phase,
- attr->reg, attr->class, true, true, true);
+ attr->reg, attr->class, true, true, false, true);
if (!base)
return -ENOMEM;
/* No limit and alarm attributes for phase specific sensors */
@@ -1722,6 +1730,7 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VIN_MIN,
@@ -1796,6 +1805,7 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VOUT_MIN,
@@ -1877,6 +1887,7 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IIN_MAX,
@@ -1918,6 +1929,7 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IOUT_MAX,
@@ -1976,6 +1988,7 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = {
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_PIN_MAX,
@@ -2017,6 +2030,7 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = {
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_POUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_POUT_MAX,
@@ -2088,6 +2102,7 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_1,
@@ -2133,6 +2148,7 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = {
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_2,
@@ -2250,7 +2266,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,

sensor = pmbus_add_sensor(data, "fan", "target", index, page,
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
- false, false, true);
+ false, false, false, true);

if (!sensor)
return -ENOMEM;
@@ -2261,14 +2277,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,

sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
- false, false, true);
+ false, false, false, true);

if (!sensor)
return -ENOMEM;

sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
- true, false, false);
+ true, false, false, false);

if (!sensor)
return -ENOMEM;
@@ -2310,7 +2326,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,

if (pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
- PSC_FAN, true, true, true) == NULL)
+ PSC_FAN, true, true, false, true) == NULL)
return -ENOMEM;

/* Fan control */
--
2.53.0