Add support for PEC by attaching PEC attribute to the i2c device. Add pec_store and pec_show function for accesing the "pec" file. Signed-off-by: Radu Sabau <radu.sabau@xxxxxxxxxx> --- Documentation/hwmon/max31827.rst | 13 ++++- drivers/hwmon/max31827.c | 95 +++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index 44ab9dc064cb..9c11a9518c67 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -131,7 +131,14 @@ The Fault Queue bits select how many consecutive temperature faults must occur before overtemperature or undertemperature faults are indicated in the corresponding status bits. -Notes ------ +PEC Support +----------- + +When reading a register value, the PEC byte is computed and sent by the chip. + +PEC on word data transaction respresents a signifcant increase in bandwitdh +usage (+33% for both write and reads) in normal conditions. -PEC is not implemented. +Since this operation implies there will be an extra delay to each +transaction, PEC can be disabled or enabled through sysfs. +Just write 1 to the "pec" file for enabling PEC and 0 for disabling it. diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index f8a13b30f100..16a1524413db 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -11,19 +11,20 @@ #include <linux/hwmon.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <linux/of_device.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/of_device.h> -#define MAX31827_T_REG 0x0 +#define MAX31827_T_REG 0x0 #define MAX31827_CONFIGURATION_REG 0x2 -#define MAX31827_TH_REG 0x4 -#define MAX31827_TL_REG 0x6 -#define MAX31827_TH_HYST_REG 0x8 -#define MAX31827_TL_HYST_REG 0xA +#define MAX31827_TH_REG 0x4 +#define MAX31827_TL_REG 0x6 +#define MAX31827_TH_HYST_REG 0x8 +#define MAX31827_TL_HYST_REG 0xA #define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0) #define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1) +#define MAX31827_CONFIGURATION_PEC_EN_MASK BIT(4) #define MAX31827_CONFIGURATION_TIMEOUT_MASK BIT(5) #define MAX31827_CONFIGURATION_RESOLUTION_MASK GENMASK(7, 6) #define MAX31827_CONFIGURATION_ALRM_POL_MASK BIT(8) @@ -46,6 +47,8 @@ #define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) #define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0) +#define DEBUG_FS_DATA_MAX 16 + enum chips { max31827 = 1, max31828, max31829 }; enum max31827_cnv { @@ -151,8 +154,8 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, goto unlock; ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_CNV_RATE_MASK, - cnv_rate); + MAX31827_CONFIGURATION_CNV_RATE_MASK, + cnv_rate); unlock: mutex_unlock(&st->lock); @@ -344,7 +347,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_temp_enable: if (val >> 1) - return -EINVAL; + return -EOPNOTSUPP; mutex_lock(&st->lock); /** @@ -384,7 +387,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, case hwmon_chip: if (attr == hwmon_chip_update_interval) { if (!st->enable) - return -EINVAL; + return -EOPNOTSUPP; /* * Convert the desired conversion rate into register @@ -472,11 +475,60 @@ static ssize_t temp1_resolution_store(struct device *dev, return ret ? ret : count; } - static DEVICE_ATTR_RW(temp1_resolution); +static ssize_t pec_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); +} + +static ssize_t pec_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct max31827_state *st = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + unsigned int val, val2; + int err; + + err = kstrtouint(buf, 10, &val); + if (err < 0) + return err; + + val2 = FIELD_PREP(MAX31827_CONFIGURATION_PEC_EN_MASK, !!val); + + switch (val) { + case 0: + err = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_PEC_EN_MASK, + val2); + if (err) + return err; + + client->flags &= ~I2C_CLIENT_PEC; + break; + case 1: + err = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_PEC_EN_MASK, + val2); + if (err) + return err; + + client->flags |= I2C_CLIENT_PEC; + break; + default: + return -EINVAL; + } + + return count; +} +static DEVICE_ATTR_RW(pec); + static struct attribute *max31827_attrs[] = { &dev_attr_temp1_resolution.attr, + &dev_attr_pec.attr, NULL }; ATTRIBUTE_GROUPS(max31827); @@ -493,8 +545,8 @@ static int max31827_init_client(struct max31827_state *st, struct device *dev) { struct fwnode_handle *fwnode; + unsigned int data, lsb_idx; unsigned int res = 0; - u32 data, lsb_idx; enum chips type; bool prop; int ret; @@ -578,6 +630,11 @@ static int max31827_init_client(struct max31827_state *st, return regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, res); } +static void max31827_remove_pec(void *dev) +{ + device_remove_file(dev, &dev_attr_pec); +} + static const struct hwmon_channel_info *max31827_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM | @@ -627,6 +684,16 @@ static int max31827_probe(struct i2c_client *client) if (err) return err; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) { + err = device_create_file(dev, &dev_attr_pec); + if (err) + return err; + + err = devm_add_action_or_reset(dev, max31827_remove_pec, dev); + if (err) + return err; + } + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st, &max31827_chip_info, max31827_groups); @@ -652,15 +719,17 @@ static const struct of_device_id max31827_of_match[] = { MODULE_DEVICE_TABLE(of, max31827_of_match); static struct i2c_driver max31827_driver = { + .class = I2C_CLASS_HWMON, .driver = { .name = "max31827", .of_match_table = max31827_of_match, }, - .probe = max31827_probe, + .probe_new = max31827_probe, .id_table = max31827_i2c_ids, }; module_i2c_driver(max31827_driver); MODULE_AUTHOR("Daniel Matyas <daniel.matyas@xxxxxxxxxx>"); +MODULE_AUTHOR("Radu Sabau <radu.sabau@xxxxxxxxxx>"); MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver"); MODULE_LICENSE("GPL"); -- 2.34.1