Skip to content

Commit

Permalink
hwmon: (pmbus) Move pec attribute to I2C device
Browse files Browse the repository at this point in the history
Enabling and disabling PEC for PMBus devices is currently only supported
with a debugfs attribute, which requires debugfs to be enabled and is
thus less than perfect. Take the lm90 driver as example and add a 'pec'
attribute to the I2C device if both the I2C adapter and the PMBus device
support it. Remove the now obsolete 'pec' attribute from debugfs.

Cc: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  • Loading branch information
Guenter Roeck committed Jul 13, 2022
1 parent 88084a3 commit f30ce04
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 39 deletions.
9 changes: 9 additions & 0 deletions Documentation/ABI/testing/sysfs-class-hwmon
Original file line number Diff line number Diff line change
Expand Up @@ -938,3 +938,12 @@ Description:
- 1: enable

RW

What: /sys/class/hwmon/hwmonX/device/pec
Description:
PEC support on I2C devices

- 0, off, n: disable
- 1, on, y: enable

RW
9 changes: 9 additions & 0 deletions Documentation/hwmon/pmbus-core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ Specifically, it provides the following information.
non-standard PMBus commands to standard commands, or to augment standard
command return values with device specific information.

PEC Support
===========

Many PMBus devices support SMBus PEC (Packet Error Checking). If supported
by both the I2C adapter and by the PMBus chip, it is by default enabled.
If PEC is supported, the PMBus core driver adds an attribute named 'pec' to
the I2C device. This attribute can be used to control PEC support in the
communication with the PMBus chip.

API functions
=============

Expand Down
89 changes: 50 additions & 39 deletions drivers/hwmon/pmbus/pmbus_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,42 @@ static int pmbus_read_status_word(struct i2c_client *client, int page)
return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD);
}

/* PEC attribute support */

static ssize_t pec_show(struct device *dev, struct device_attribute *dummy,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);

return sysfs_emit(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
}

static ssize_t pec_store(struct device *dev, struct device_attribute *dummy,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
bool enable;
int err;

err = kstrtobool(buf, &enable);
if (err < 0)
return err;

if (enable)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;

return count;
}

static DEVICE_ATTR_RW(pec);

static void pmbus_remove_pec(void *dev)
{
device_remove_file(dev, &dev_attr_pec);
}

static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
struct pmbus_driver_info *info)
{
Expand Down Expand Up @@ -2474,6 +2510,20 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return ret;
}

if (client->flags & I2C_CLIENT_PEC) {
/*
* If I2C_CLIENT_PEC is set here, both the I2C adapter and the
* chip support PEC. Add 'pec' attribute to client device to let
* the user control it.
*/
ret = device_create_file(dev, &dev_attr_pec);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, pmbus_remove_pec, dev);
if (ret)
return ret;
}

return 0;
}

Expand Down Expand Up @@ -2782,42 +2832,6 @@ static int pmbus_debugfs_get_status(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status,
NULL, "0x%04llx\n");

static int pmbus_debugfs_get_pec(void *data, u64 *val)
{
struct i2c_client *client = data;

*val = !!(client->flags & I2C_CLIENT_PEC);

return 0;
}

static int pmbus_debugfs_set_pec(void *data, u64 val)
{
int rc;
struct i2c_client *client = data;

if (!val) {
client->flags &= ~I2C_CLIENT_PEC;
return 0;
}

if (val != 1)
return -EINVAL;

rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
if (rc < 0)
return rc;

if (!(rc & PB_CAPABILITY_ERROR_CHECK))
return -EOPNOTSUPP;

client->flags |= I2C_CLIENT_PEC;

return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec,
pmbus_debugfs_set_pec, "%llu\n");

static void pmbus_remove_debugfs(void *data)
{
struct dentry *entry = data;
Expand Down Expand Up @@ -2853,9 +2867,6 @@ static int pmbus_init_debugfs(struct i2c_client *client,
if (!entries)
return -ENOMEM;

debugfs_create_file("pec", 0664, data->debugfs, client,
&pmbus_debugfs_ops_pec);

for (i = 0; i < data->info->pages; ++i) {
/* Check accessibility of status register if it's not page 0 */
if (!i || pmbus_check_status_register(client, i)) {
Expand Down

0 comments on commit f30ce04

Please sign in to comment.