On Sun, Apr 14, 2019 at 07:27:47AM -0700, Guenter Roeck wrote: >On 4/13/19 9:03 AM, Adamski, Krzysztof (Nokia - PL/Wroclaw) wrote: >>Those virtual registers can be used to export manufacturer specific >>functionality for controlling the number of samples for average values >>reported by the device. >> >>Signed-off-by: Krzysztof Adamski <krzysztof.adamski@xxxxxxxxx> >>--- >> Documentation/hwmon/sysfs-interface | 18 +++++ >> drivers/hwmon/pmbus/pmbus.h | 15 ++++ >> drivers/hwmon/pmbus/pmbus_core.c | 114 ++++++++++++++++++++++++++++ >> 3 files changed, 147 insertions(+) >> >>diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface >>index 2b9e1005d88b..7b91706d01c8 100644 >>--- a/Documentation/hwmon/sysfs-interface >>+++ b/Documentation/hwmon/sysfs-interface >>@@ -756,6 +756,24 @@ intrusion[0-*]_beep >> 1: enable >> RW >>+******************************** >>+* Average sample configuration * >>+******************************** >>+ >>+Devices allowing for reading {in,power,curr,temp}_average values may export >>+attributes for controlling number of samples used to compute average. >>+ >>+samples Sets number of average samples for all types of measurements. >>+ RW >>+ >>+in_samples >>+power_samples >>+curr_samples >>+temp_samples Sets number of average samples for specific type of measurements. >>+ Note that on some devices it won't be possible to set all of them >>+ to different values so changing one might also change some others. >>+ RW >>+ > >Separate patch for the above, please. Adding the ABI is one subject, adding support >for it into a driver (or driver core) is another. Sure, I'll do that. > >> sysfs attribute writes interpretation >> ------------------------------------- >>diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h >>index 1d24397d36ec..e73289cc867d 100644 >>--- a/drivers/hwmon/pmbus/pmbus.h >>+++ b/drivers/hwmon/pmbus/pmbus.h >>@@ -217,6 +217,20 @@ enum pmbus_regs { >> PMBUS_VIRT_PWM_ENABLE_2, >> PMBUS_VIRT_PWM_ENABLE_3, >> PMBUS_VIRT_PWM_ENABLE_4, >>+ >>+ /* Samples for average >>+ * >>+ * Drivers wanting to expose functionality for changing the number of >>+ * samples used for average values should implement support in >>+ * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it >>+ * applies to all types of measurements, or any number of specific >>+ * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. >>+ */ >>+ PMBUS_VIRT_SAMPLES, >>+ PMBUS_VIRT_IN_SAMPLES, >>+ PMBUS_VIRT_CURR_SAMPLES, >>+ PMBUS_VIRT_POWER_SAMPLES, >>+ PMBUS_VIRT_TEMP_SAMPLES, >> }; >> /* >>@@ -371,6 +385,7 @@ enum pmbus_sensor_classes { >> #define PMBUS_HAVE_STATUS_VMON BIT(19) >> #define PMBUS_HAVE_PWM12 BIT(20) >> #define PMBUS_HAVE_PWM34 BIT(21) >>+#define PMBUS_HAVE_SAMPLES BIT(22) >> #define PMBUS_PAGE_VIRTUAL BIT(31) >>diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c >>index 2e2b5851139c..31b6bf49518c 100644 >>--- a/drivers/hwmon/pmbus/pmbus_core.c >>+++ b/drivers/hwmon/pmbus/pmbus_core.c >>@@ -1901,6 +1901,116 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, >> return 0; >> } >>+struct pmbus_samples_attr { >>+ int reg; >>+ char *name; >>+}; >>+ >>+struct pmbus_samples_reg { >>+ int page; >>+ struct pmbus_samples_attr *attr; >>+ struct device_attribute dev_attr; >>+}; >>+ >>+static struct pmbus_samples_attr pmbus_samples_registers[] = { >>+ { >>+ .reg = PMBUS_VIRT_SAMPLES, >>+ .name = "samples", >>+ }, { >>+ .reg = PMBUS_VIRT_IN_SAMPLES, >>+ .name = "in_samples", >>+ }, { >>+ .reg = PMBUS_VIRT_CURR_SAMPLES, >>+ .name = "curr_samples", >>+ }, { >>+ .reg = PMBUS_VIRT_POWER_SAMPLES, >>+ .name = "power_samples", >>+ }, { >>+ .reg = PMBUS_VIRT_TEMP_SAMPLES, >>+ .name = "temp_samples", >>+ } >>+}; >>+ >>+#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) >>+ >>+static ssize_t pmbus_show_samples(struct device *dev, >>+ struct device_attribute *devattr, char *buf) >>+{ >>+ int val; >>+ struct i2c_client *client = to_i2c_client(dev->parent); >>+ struct pmbus_samples_reg *reg = to_samples_reg(devattr); >>+ >>+ val = _pmbus_read_word_data(client, reg->page, reg->attr->reg); >>+ if (val < 0) >>+ return val; >>+ >>+ return snprintf(buf, PAGE_SIZE, "%d\n", val); >>+} >>+ >>+static ssize_t pmbus_set_samples(struct device *dev, >>+ struct device_attribute *devattr, >>+ const char *buf, size_t count) >>+{ >>+ int ret; >>+ long val; >>+ struct i2c_client *client = to_i2c_client(dev->parent); >>+ struct pmbus_samples_reg *reg = to_samples_reg(devattr); >>+ >>+ if (kstrtol(buf, 0, &val) < 0) >>+ return -EINVAL; >>+ >>+ ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); >>+ >>+ return ret ? : count; >>+} >>+ >>+static int pmbus_add_samples_attr(struct pmbus_data *data, int page, >>+ struct pmbus_samples_attr *attr) >>+{ >>+ struct pmbus_samples_reg *reg; >>+ >>+ reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); >>+ if (!reg) >>+ return -ENOMEM; >>+ >>+ reg->attr = attr; >>+ reg->page = page; >>+ >>+ pmbus_dev_attr_init(®->dev_attr, attr->name, (S_IWUSR | S_IRUGO), > >S_IWUSR ran out of favor and generates a checkpatch warning. >Please use 0644. I wasn't sure if its more important to care about checkpatch warning or to keep convention in the file. I'll change to numerical value as advised. > >>+ pmbus_show_samples, pmbus_set_samples); >>+ >>+ return pmbus_add_attribute(data, ®->dev_attr.attr); >>+} >>+ >>+static int pmbus_add_samples_attributes(struct i2c_client *client, >>+ struct pmbus_data *data) >>+{ >>+ const struct pmbus_driver_info *info = data->info; >>+ int page; >>+ >>+ for (page = 0; page < info->pages; page++) { > >This won't work as intended on multi-page chips. If the driver writer >is not careful, it will try to generate multiple similar attributes, >one per page. I would suggest to only check this for page 0. >At some point we may need to add a separate func pointer for >chip specific attributes, but that should do for now. > Good point. I'll do that. >>+ int s;: >>+ >>+ if (!(info->func[page] & PMBUS_HAVE_SAMPLES)) >>+ continue; >>+ >>+ for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { >>+ int ret; >>+ struct pmbus_samples_attr *attr; >>+ > >Please use reverse christmas tree here > > struct pmbus_samples_attr *attr; > int ret; Ok. >>+ attr = &pmbus_samples_registers[s]; >>+ if (!pmbus_check_word_register(client, page, attr->reg)) >>+ continue; >>+ >>+ ret = pmbus_add_samples_attr(data, page, attr); >>+ if (ret) >>+ return ret; >>+ } >>+ } >>+ >>+ return 0; >>+} >>+ >> static int pmbus_find_attributes(struct i2c_client *client, >> struct pmbus_data *data) >> { >>@@ -1932,6 +2042,10 @@ static int pmbus_find_attributes(struct i2c_client *client, >> /* Fans */ >> ret = pmbus_add_fan_attributes(client, data); >>+ if (ret) >>+ return ret; >>+ >>+ ret = pmbus_add_samples_attributes(client, data); >> return ret; >> } >> > Krzysztof