Message ID | 20180926064245.4091-3-nicoleotsuka@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | hwmon: ina3221: Add power and enable sysfs nodes | expand |
Hi Nicolin, On 09/25/2018 11:42 PM, Nicolin Chen wrote: > The inX_enable interface allows user space to enable or disable > the corresponding channel. Meanwhile, according to hwmon ABI, a > disabled channel/sensor should return -ENODATA as a read result. > > However, there're configurable nodes sharing the same __show() > functions. So this change also adds to check if the attribute is > read-only to make sure it's not reading a configuration but the > sensor data. > One necessary high level change I don't see below: With this change, we should no longer drop a channel entirely if it is disabled from devicetree. All channels should be visible but report -ENODATA if disabled. In other words, it should be possible for the 'enable' flag to override settings in DT. > Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com> > --- > Documentation/hwmon/ina3221 | 1 + > drivers/hwmon/ina3221.c | 85 +++++++++++++++++++++++++++++++++++++ > 2 files changed, 86 insertions(+) > > diff --git a/Documentation/hwmon/ina3221 b/Documentation/hwmon/ina3221 > index 6be64b553cd0..1aa32366d8aa 100644 > --- a/Documentation/hwmon/ina3221 > +++ b/Documentation/hwmon/ina3221 > @@ -23,6 +23,7 @@ Sysfs entries > > in[123]_input Bus voltage(mV) channels > in[123]_label Voltage channel labels > +in[123]_enable Voltage channel enable controls > curr[123]_input Current(mA) measurement channels > shunt[123]_resistor Shunt resistance(uOhm) channels > curr[123]_crit Critical alert current(mA) setting, activates the > diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c > index 5890a2da3bfe..1be2d062a19e 100644 > --- a/drivers/hwmon/ina3221.c > +++ b/drivers/hwmon/ina3221.c > @@ -78,6 +78,9 @@ enum ina3221_channels { > }; > > static const unsigned int register_channel[] = { > + [INA3221_BUS1] = INA3221_CHANNEL1, > + [INA3221_BUS2] = INA3221_CHANNEL2, > + [INA3221_BUS3] = INA3221_CHANNEL3, > [INA3221_SHUNT1] = INA3221_CHANNEL1, > [INA3221_SHUNT2] = INA3221_CHANNEL2, > [INA3221_SHUNT3] = INA3221_CHANNEL3, > @@ -113,6 +116,19 @@ struct ina3221_data { > struct ina3221_input inputs[INA3221_NUM_CHANNELS]; > }; > > +static inline bool ina3221_is_enable(struct ina3221_data *ina, int channel) s/is_enable/is_enabled/, maybe ? > +{ > + unsigned int config; > + int ret; > + > + /* Return false to reject further read */ > + ret = regmap_read(ina->regmap, INA3221_CONFIG, &config); > + if (ret) > + return false; > + > + return (config & INA3221_CONFIG_CHx_EN(channel)) > 0; The "> 0" is unnecessary. Conversion to bool is automatic. If you want to make it explicit, please use return !!(config & INA3221_CONFIG_CHx_EN(channel)); It should not be necessary to re-read the value from the chip all the time. I would suggest to cache the value in the 'disabled' variable. > +} > + > static ssize_t ina3221_show_label(struct device *dev, > struct device_attribute *attr, char *buf) > { > @@ -124,6 +140,45 @@ static ssize_t ina3221_show_label(struct device *dev, > return snprintf(buf, PAGE_SIZE, "%s\n", input->label); > } > > +static ssize_t ina3221_show_enable(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); > + struct ina3221_data *ina = dev_get_drvdata(dev); > + unsigned int channel = sd_attr->index; > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + ina3221_is_enable(ina, channel)); > +} > + > +static ssize_t ina3221_set_enable(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); > + struct ina3221_data *ina = dev_get_drvdata(dev); > + unsigned int channel = sd_attr->index; > + unsigned int mask = INA3221_CONFIG_CHx_EN(channel); > + unsigned int config; > + int val, ret; > + > + ret = kstrtoint(buf, 0, &val); > + if (ret) > + return ret; > + > + /* inX_enable only accepts 1 for enabling or 0 for disabling */ > + if (val != 0 && val != 1) > + return -EINVAL; > + Just use kstrtobool(). > + config = val ? mask : 0; > + > + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); > + if (ret) > + return ret; > + > + return count; > +} > + > static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, > int *val) > { > @@ -146,8 +201,13 @@ static ssize_t ina3221_show_bus_voltage(struct device *dev, > struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); > struct ina3221_data *ina = dev_get_drvdata(dev); > unsigned int reg = sd_attr->index; > + unsigned int channel = register_channel[reg]; > int val, voltage_mv, ret; > > + /* No data for read-only attribute if channel is disabled */ > + if (!attr->store && !ina3221_is_enable(ina, channel)) > + return -ENODATA; > + > ret = ina3221_read_value(ina, reg, &val); > if (ret) > return ret; > @@ -164,8 +224,13 @@ static ssize_t ina3221_show_shunt_voltage(struct device *dev, > struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); > struct ina3221_data *ina = dev_get_drvdata(dev); > unsigned int reg = sd_attr->index; > + unsigned int channel = register_channel[reg]; > int val, voltage_uv, ret; > > + /* No data for read-only attribute if channel is disabled */ > + if (!attr->store && !ina3221_is_enable(ina, channel)) > + return -ENODATA; > + > ret = ina3221_read_value(ina, reg, &val); > if (ret) > return ret; > @@ -201,8 +266,13 @@ static ssize_t ina3221_show_current(struct device *dev, > struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); > struct ina3221_data *ina = dev_get_drvdata(dev); > unsigned int reg = sd_attr->index; > + unsigned int channel = register_channel[reg]; > int current_ma, ret; > > + /* No data for read-only attribute if channel is disabled */ > + if (!attr->store && !ina3221_is_enable(ina, channel)) > + return -ENODATA; > + > ret = __ina3221_show_current(ina, reg, ¤t_ma); > if (ret) > return ret; > @@ -318,6 +388,10 @@ static ssize_t ina3221_show_power(struct device *dev, > int val, current_ma, voltage_mv, ret; > s64 power_uw; > > + /* No data for read-only attribute if channel is disabled */ > + if (!attr->store && !ina3221_is_enable(ina, channel)) > + return -ENODATA; > + > /* Read bus voltage */ > ret = ina3221_read_value(ina, reg_bus, &val); > if (ret) > @@ -377,6 +451,14 @@ static SENSOR_DEVICE_ATTR(in2_label, 0444, > static SENSOR_DEVICE_ATTR(in3_label, 0444, > ina3221_show_label, NULL, INA3221_CHANNEL3); > > +/* voltage channel enable */ > +static SENSOR_DEVICE_ATTR(in1_enable, 0644, > + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL1); > +static SENSOR_DEVICE_ATTR(in2_enable, 0644, > + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL2); > +static SENSOR_DEVICE_ATTR(in3_enable, 0644, > + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL3); > + > /* bus voltage */ > static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, > ina3221_show_bus_voltage, NULL, INA3221_BUS1); > @@ -460,6 +542,7 @@ static SENSOR_DEVICE_ATTR(power3_crit, 0644, > static struct attribute *ina3221_attrs[] = { > /* channel 1 -- make sure label at first */ > &sensor_dev_attr_in1_label.dev_attr.attr, > + &sensor_dev_attr_in1_enable.dev_attr.attr, > &sensor_dev_attr_in1_input.dev_attr.attr, > &sensor_dev_attr_curr1_input.dev_attr.attr, > &sensor_dev_attr_shunt1_resistor.dev_attr.attr, > @@ -473,6 +556,7 @@ static struct attribute *ina3221_attrs[] = { > > /* channel 2 -- make sure label at first */ > &sensor_dev_attr_in2_label.dev_attr.attr, > + &sensor_dev_attr_in2_enable.dev_attr.attr, > &sensor_dev_attr_in2_input.dev_attr.attr, > &sensor_dev_attr_curr2_input.dev_attr.attr, > &sensor_dev_attr_shunt2_resistor.dev_attr.attr, > @@ -486,6 +570,7 @@ static struct attribute *ina3221_attrs[] = { > > /* channel 3 -- make sure label at first */ > &sensor_dev_attr_in3_label.dev_attr.attr, > + &sensor_dev_attr_in3_enable.dev_attr.attr, > &sensor_dev_attr_in3_input.dev_attr.attr, > &sensor_dev_attr_curr3_input.dev_attr.attr, > &sensor_dev_attr_shunt3_resistor.dev_attr.attr, >
On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > The inX_enable interface allows user space to enable or disable > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > disabled channel/sensor should return -ENODATA as a read result. > > > > However, there're configurable nodes sharing the same __show() > > functions. So this change also adds to check if the attribute is > > read-only to make sure it's not reading a configuration but the > > sensor data. > One necessary high level change I don't see below: With this change, > we should no longer drop a channel entirely if it is disabled from > devicetree. All channels should be visible but report -ENODATA if > disabled. In other words, it should be possible for the 'enable' flag > to override settings in DT. Hmm...I don't feel so convinced here. The status in DT binding isn't exactly a setting but a physical status: if a hardware design leaves a channel to be disconnected, I don't really see a point in enabling it in the runtime. Or maybe you can shed some light on it? Meanwhile, I believe the enable nodes are necessary in either way as users could decide to disable the connected channels, based on their use cases, to save power. Thanks Nicolin
Nicolin, On Wed, Sep 26, 2018 at 11:02:44AM -0700, Nicolin Chen wrote: > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > > The inX_enable interface allows user space to enable or disable > > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > > disabled channel/sensor should return -ENODATA as a read result. > > > > > > However, there're configurable nodes sharing the same __show() > > > functions. So this change also adds to check if the attribute is > > > read-only to make sure it's not reading a configuration but the > > > sensor data. > > > One necessary high level change I don't see below: With this change, > > we should no longer drop a channel entirely if it is disabled from > > devicetree. All channels should be visible but report -ENODATA if > > disabled. In other words, it should be possible for the 'enable' flag > > to override settings in DT. > > Hmm...I don't feel so convinced here. The status in DT binding isn't > exactly a setting but a physical status: if a hardware design leaves > a channel to be disconnected, I don't really see a point in enabling > it in the runtime. Or maybe you can shed some light on it? > You are making an assumption from your use case. It might as well be that some or all channels are disabled in DT by default to conserve power, not because they are disconnected. > Meanwhile, I believe the enable nodes are necessary in either way as > users could decide to disable the connected channels, based on their > use cases, to save power. > Agreed, though I would not say "necessary". "Useful" seems to be more appropriate. Thanks, Guenter
Hello, On Wed, Sep 26, 2018 at 12:58:17PM -0700, Guenter Roeck wrote: > On Wed, Sep 26, 2018 at 11:02:44AM -0700, Nicolin Chen wrote: > > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > > > The inX_enable interface allows user space to enable or disable > > > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > > > disabled channel/sensor should return -ENODATA as a read result. > > > > > > > > However, there're configurable nodes sharing the same __show() > > > > functions. So this change also adds to check if the attribute is > > > > read-only to make sure it's not reading a configuration but the > > > > sensor data. > > > > > One necessary high level change I don't see below: With this change, > > > we should no longer drop a channel entirely if it is disabled from > > > devicetree. All channels should be visible but report -ENODATA if > > > disabled. In other words, it should be possible for the 'enable' flag > > > to override settings in DT. > > > > Hmm...I don't feel so convinced here. The status in DT binding isn't > > exactly a setting but a physical status: if a hardware design leaves > > a channel to be disconnected, I don't really see a point in enabling > > it in the runtime. Or maybe you can shed some light on it? > > > > You are making an assumption from your use case. It might as well be that > some or all channels are disabled in DT by default to conserve power, > not because they are disconnected. I think I probably should update my DT binding somehow to say it explicitly that the property should be only used in cases of the physical disconnections, although I feel the current binding "no input source" already has the same meaning. In my opinion, disabling channels in DT to save power isn't very plausible, because it sounds more likely a user decision, while, as we know, DT merely describes the hardware design. Otherwise, if we want something like a setting for this purpose, we should probably use a different property for DT binding, bool type "disable-on-boot" for example. > > Meanwhile, I believe the enable nodes are necessary in either way as > > users could decide to disable the connected channels, based on their > > use cases, to save power. > > > Agreed, though I would not say "necessary". "Useful" seems to be more > appropriate. Yea..
On Wed, Sep 26, 2018 at 01:25:20PM -0700, Nicolin Chen wrote: > Hello, > > On Wed, Sep 26, 2018 at 12:58:17PM -0700, Guenter Roeck wrote: > > On Wed, Sep 26, 2018 at 11:02:44AM -0700, Nicolin Chen wrote: > > > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > > > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > > > > The inX_enable interface allows user space to enable or disable > > > > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > > > > disabled channel/sensor should return -ENODATA as a read result. > > > > > > > > > > However, there're configurable nodes sharing the same __show() > > > > > functions. So this change also adds to check if the attribute is > > > > > read-only to make sure it's not reading a configuration but the > > > > > sensor data. > > > > > > > One necessary high level change I don't see below: With this change, > > > > we should no longer drop a channel entirely if it is disabled from > > > > devicetree. All channels should be visible but report -ENODATA if > > > > disabled. In other words, it should be possible for the 'enable' flag > > > > to override settings in DT. > > > > > > Hmm...I don't feel so convinced here. The status in DT binding isn't > > > exactly a setting but a physical status: if a hardware design leaves > > > a channel to be disconnected, I don't really see a point in enabling > > > it in the runtime. Or maybe you can shed some light on it? > > > > > > > You are making an assumption from your use case. It might as well be that > > some or all channels are disabled in DT by default to conserve power, > > not because they are disconnected. > > I think I probably should update my DT binding somehow to say it > explicitly that the property should be only used in cases of the > physical disconnections, although I feel the current binding "no > input source" already has the same meaning. > > In my opinion, disabling channels in DT to save power isn't very > plausible, because it sounds more likely a user decision, while, > as we know, DT merely describes the hardware design. > I try to avoid making such assumptions. All I know is that I'll have to deal with the fallout if a single person wants to use the property differently. This is similar to disabling an entire subsystem in DT because it isn't used in a specific system - say, a SPI or I2C bus which has nothing connected on some shipping hardware, even though the board has a connector for it. Your argument is that one shall not use the status property do disable loading the driver, and that one must not remove a set of properties for unused hardware either. That doesn't sound very realistic to me. Point is that I don't _know_ how this is going to be used, so I'd rather keep it flexible. Guenter > Otherwise, if we want something like a setting for this purpose, > we should probably use a different property for DT binding, bool > type "disable-on-boot" for example. > > > > Meanwhile, I believe the enable nodes are necessary in either way as > > > users could decide to disable the connected channels, based on their > > > use cases, to save power. > > > > > Agreed, though I would not say "necessary". "Useful" seems to be more > > appropriate. > > Yea..
On Wed, Sep 26, 2018 at 01:44:55PM -0700, Guenter Roeck wrote: > On Wed, Sep 26, 2018 at 01:25:20PM -0700, Nicolin Chen wrote: > > Hello, > > > > On Wed, Sep 26, 2018 at 12:58:17PM -0700, Guenter Roeck wrote: > > > On Wed, Sep 26, 2018 at 11:02:44AM -0700, Nicolin Chen wrote: > > > > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > > > > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > > > > > The inX_enable interface allows user space to enable or disable > > > > > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > > > > > disabled channel/sensor should return -ENODATA as a read result. > > > > > > > > > > > > However, there're configurable nodes sharing the same __show() > > > > > > functions. So this change also adds to check if the attribute is > > > > > > read-only to make sure it's not reading a configuration but the > > > > > > sensor data. > > > > > > > > > One necessary high level change I don't see below: With this change, > > > > > we should no longer drop a channel entirely if it is disabled from > > > > > devicetree. All channels should be visible but report -ENODATA if > > > > > disabled. In other words, it should be possible for the 'enable' flag > > > > > to override settings in DT. > > > > > > > > Hmm...I don't feel so convinced here. The status in DT binding isn't > > > > exactly a setting but a physical status: if a hardware design leaves > > > > a channel to be disconnected, I don't really see a point in enabling > > > > it in the runtime. Or maybe you can shed some light on it? > > > > > > > > > > You are making an assumption from your use case. It might as well be that > > > some or all channels are disabled in DT by default to conserve power, > > > not because they are disconnected. > > > > I think I probably should update my DT binding somehow to say it > > explicitly that the property should be only used in cases of the > > physical disconnections, although I feel the current binding "no > > input source" already has the same meaning. > > > > In my opinion, disabling channels in DT to save power isn't very > > plausible, because it sounds more likely a user decision, while, > > as we know, DT merely describes the hardware design. > > > > I try to avoid making such assumptions. All I know is that I'll have > to deal with the fallout if a single person wants to use the property > differently. I can understand your point (or pain lol). But I believe in such a case, DT maintainers should reject such a DT change. Let's say if this kinda "default setting" in DT is allowable, other things such as having a default mode setting between polling or one-shot modes, and as default critical current settings would be able to put into DT. But we know that these would be rejected as a reason of "not being hardware design but a user decision". > This is similar to disabling an entire subsystem in DT > because it isn't used in a specific system - say, a SPI or I2C bus > which has nothing connected on some shipping hardware, even though > the board has a connector for it. Your argument is that one shall > not use the status property do disable loading the driver, and that > one must not remove a set of properties for unused hardware either. > That doesn't sound very realistic to me. SPI/I2C is a good example comparing to my case. And you do make a point. In that case, I think DT overlay is designed for it -- one shall overlay the status property from "disable" (defined in the DTS of the shipping hardware -- the main board) to "okay" in the overlay DTS where a connection actually happens. And even in this case, it makes sense to me to disable both the status and the driver of SPI/I2C for the main board. Otherwise, memory could be wasted for standalone main board users at those unused SPI/I2C buses -- and the memory might be larger than one could expect depending on where drivers allocate data buffers. > Point is that I don't _know_ how this is going to be used, so I'd > rather keep it flexible. Well, taking one step back, I am okay to follow your way if you are really firm about it. Just please give me a more reply and I will merge this change to that v5, dropping the is_visible(). Actually neither the is_visible nor inX_enable is that essential for me. I am just trying to do what I feel right. Thank you Nicolin
Hi Nicolin, On Wed, Sep 26, 2018 at 02:55:06PM -0700, Nicolin Chen wrote: > On Wed, Sep 26, 2018 at 01:44:55PM -0700, Guenter Roeck wrote: > > On Wed, Sep 26, 2018 at 01:25:20PM -0700, Nicolin Chen wrote: > > > Hello, > > > > > > On Wed, Sep 26, 2018 at 12:58:17PM -0700, Guenter Roeck wrote: > > > > On Wed, Sep 26, 2018 at 11:02:44AM -0700, Nicolin Chen wrote: > > > > > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > > > > > On 09/25/2018 11:42 PM, Nicolin Chen wrote: > > > > > > > The inX_enable interface allows user space to enable or disable > > > > > > > the corresponding channel. Meanwhile, according to hwmon ABI, a > > > > > > > disabled channel/sensor should return -ENODATA as a read result. > > > > > > > > > > > > > > However, there're configurable nodes sharing the same __show() > > > > > > > functions. So this change also adds to check if the attribute is > > > > > > > read-only to make sure it's not reading a configuration but the > > > > > > > sensor data. > > > > > > > > > > > One necessary high level change I don't see below: With this change, > > > > > > we should no longer drop a channel entirely if it is disabled from > > > > > > devicetree. All channels should be visible but report -ENODATA if > > > > > > disabled. In other words, it should be possible for the 'enable' flag > > > > > > to override settings in DT. > > > > > > > > > > Hmm...I don't feel so convinced here. The status in DT binding isn't > > > > > exactly a setting but a physical status: if a hardware design leaves > > > > > a channel to be disconnected, I don't really see a point in enabling > > > > > it in the runtime. Or maybe you can shed some light on it? > > > > > > > > > > > > > You are making an assumption from your use case. It might as well be that > > > > some or all channels are disabled in DT by default to conserve power, > > > > not because they are disconnected. > > > > > > I think I probably should update my DT binding somehow to say it > > > explicitly that the property should be only used in cases of the > > > physical disconnections, although I feel the current binding "no > > > input source" already has the same meaning. > > > > > > In my opinion, disabling channels in DT to save power isn't very > > > plausible, because it sounds more likely a user decision, while, > > > as we know, DT merely describes the hardware design. > > > > > > > I try to avoid making such assumptions. All I know is that I'll have > > to deal with the fallout if a single person wants to use the property > > differently. > > I can understand your point (or pain lol). But I believe in such > a case, DT maintainers should reject such a DT change. Let's say > if this kinda "default setting" in DT is allowable, other things > such as having a default mode setting between polling or one-shot > modes, and as default critical current settings would be able to > put into DT. But we know that these would be rejected as a reason > of "not being hardware design but a user decision". > > > This is similar to disabling an entire subsystem in DT > > because it isn't used in a specific system - say, a SPI or I2C bus > > which has nothing connected on some shipping hardware, even though > > the board has a connector for it. Your argument is that one shall > > not use the status property do disable loading the driver, and that > > one must not remove a set of properties for unused hardware either. > > That doesn't sound very realistic to me. > > SPI/I2C is a good example comparing to my case. And you do make > a point. In that case, I think DT overlay is designed for it -- > one shall overlay the status property from "disable" (defined in > the DTS of the shipping hardware -- the main board) to "okay" in > the overlay DTS where a connection actually happens. > > And even in this case, it makes sense to me to disable both the > status and the driver of SPI/I2C for the main board. Otherwise, > memory could be wasted for standalone main board users at those > unused SPI/I2C buses -- and the memory might be larger than one > could expect depending on where drivers allocate data buffers. > > > Point is that I don't _know_ how this is going to be used, so I'd > > rather keep it flexible. > > Well, taking one step back, I am okay to follow your way if you > are really firm about it. Just please give me a more reply and > I will merge this change to that v5, dropping the is_visible(). Quite obviously we are not converging. Given that, I think it would be better to shelve the new attributes for now and to wait for an actual user who actually needs the new attributes. Thanks, Guenter
Hello Guenter, On Thu, Sep 27, 2018 at 09:05:09AM -0700, Guenter Roeck wrote: > > > Point is that I don't _know_ how this is going to be used, so I'd > > > rather keep it flexible. > > > > Well, taking one step back, I am okay to follow your way if you > > are really firm about it. Just please give me a more reply and > > I will merge this change to that v5, dropping the is_visible(). > > Quite obviously we are not converging. Given that, I think it > would be better to shelve the new attributes for now and to wait > for an actual user who actually needs the new attributes. I would rather remove the hiding code, if we have to sacrifice one of them. We both agreed that in[123]_enable is more useful. And actually we will still keep is_visible() for empty labels. So even if one day we somehow feel safe to hide a disconnected channel one day, it'd only need a couple of lines of changes. I will squash this change into v6, and will send it after I fix things that Rob pointed out at DT binding. Thank you Nicolin
On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > +static inline bool ina3221_is_enable(struct ina3221_data *ina, int channel) > > s/is_enable/is_enabled/, maybe ? Fixing. > > + return (config & INA3221_CONFIG_CHx_EN(channel)) > 0; > > The "> 0" is unnecessary. Conversion to bool is automatic. If you want to make > it explicit, please use > > return !!(config & INA3221_CONFIG_CHx_EN(channel)); Removing "> 0". > It should not be necessary to re-read the value from the chip all the time. > I would suggest to cache the value in the 'disabled' variable. Regarding this part, I added a cache before sending this one. But I realized if the chip got powered off and rebooted during system suspend/resume, the cache would not reflect the actual status. As I mentioned earlier, this was enlightened by your comments about the BIOS. So I feel it'd be safer to read the register every time at this point, until I add the suspend/resume feature by syncing with regcache. What do you think about it? > > + ret = kstrtoint(buf, 0, &val); > > + if (ret) > > + return ret; > > + > > + /* inX_enable only accepts 1 for enabling or 0 for disabling */ > > + if (val != 0 && val != 1) > > + return -EINVAL; > > + > Just use kstrtobool(). Fixing. Thanks Nicolin
On Thu, Sep 27, 2018 at 03:26:14PM -0700, Nicolin Chen wrote: > On Wed, Sep 26, 2018 at 06:06:32AM -0700, Guenter Roeck wrote: > > > +static inline bool ina3221_is_enable(struct ina3221_data *ina, int channel) > > > > s/is_enable/is_enabled/, maybe ? > > Fixing. > > > > + return (config & INA3221_CONFIG_CHx_EN(channel)) > 0; > > > > The "> 0" is unnecessary. Conversion to bool is automatic. If you want to make > > it explicit, please use > > > > return !!(config & INA3221_CONFIG_CHx_EN(channel)); > > Removing "> 0". > > > It should not be necessary to re-read the value from the chip all the time. > > I would suggest to cache the value in the 'disabled' variable. > > Regarding this part, I added a cache before sending this one. But > I realized if the chip got powered off and rebooted during system > suspend/resume, the cache would not reflect the actual status. As > I mentioned earlier, this was enlightened by your comments about > the BIOS. So I feel it'd be safer to read the register every time > at this point, until I add the suspend/resume feature by syncing > with regcache. What do you think about it? > The proper fix for this problem would be to add support for suspend / resume to the driver. At resume time, all channels will have been re-enabled if the chip was powered off, even if they were explicitly disabled by devicetree (or via explicit configuration). This means the driver just behaves badly across suspend/resume, period. Displaying a raw value instead of a cached one doesn't solve that problem. By using a cached value, at least the user would not notice that the chip no longer does what it is supposed to be doing. I guess we just have different priorities. If I think suspend/resume is a problem for my use case, I would just go ahead and fix it. I would not try to write code that doesn't fix the problem causing it, much less argue for it. Having said that, I didn't mention that part in my other reply, meaning I'll accept the code as is. Thanks, Guenter
On Thu, Sep 27, 2018 at 03:52:00PM -0700, Guenter Roeck wrote: > The proper fix for this problem would be to add support for suspend / > resume to the driver. At resume time, all channels will have been > re-enabled if the chip was powered off, even if they were explicitly > disabled by devicetree (or via explicit configuration). This means > the driver just behaves badly across suspend/resume, period. > Displaying a raw value instead of a cached one doesn't solve that > problem. By using a cached value, at least the user would not notice > that the chip no longer does what it is supposed to be doing. > > I guess we just have different priorities. If I think suspend/resume > is a problem for my use case, I would just go ahead and fix it. > I would not try to write code that doesn't fix the problem causing it, > much less argue for it. I agree. > Having said that, I didn't mention that part in my other reply, > meaning I'll accept the code as is. Thanks for the generosity. But, since Rob hasn't acked yet, let me write the patch for suspend and resume first, which shouldn't take long. Thanks Nicolin
diff --git a/Documentation/hwmon/ina3221 b/Documentation/hwmon/ina3221 index 6be64b553cd0..1aa32366d8aa 100644 --- a/Documentation/hwmon/ina3221 +++ b/Documentation/hwmon/ina3221 @@ -23,6 +23,7 @@ Sysfs entries in[123]_input Bus voltage(mV) channels in[123]_label Voltage channel labels +in[123]_enable Voltage channel enable controls curr[123]_input Current(mA) measurement channels shunt[123]_resistor Shunt resistance(uOhm) channels curr[123]_crit Critical alert current(mA) setting, activates the diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 5890a2da3bfe..1be2d062a19e 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -78,6 +78,9 @@ enum ina3221_channels { }; static const unsigned int register_channel[] = { + [INA3221_BUS1] = INA3221_CHANNEL1, + [INA3221_BUS2] = INA3221_CHANNEL2, + [INA3221_BUS3] = INA3221_CHANNEL3, [INA3221_SHUNT1] = INA3221_CHANNEL1, [INA3221_SHUNT2] = INA3221_CHANNEL2, [INA3221_SHUNT3] = INA3221_CHANNEL3, @@ -113,6 +116,19 @@ struct ina3221_data { struct ina3221_input inputs[INA3221_NUM_CHANNELS]; }; +static inline bool ina3221_is_enable(struct ina3221_data *ina, int channel) +{ + unsigned int config; + int ret; + + /* Return false to reject further read */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &config); + if (ret) + return false; + + return (config & INA3221_CONFIG_CHx_EN(channel)) > 0; +} + static ssize_t ina3221_show_label(struct device *dev, struct device_attribute *attr, char *buf) { @@ -124,6 +140,45 @@ static ssize_t ina3221_show_label(struct device *dev, return snprintf(buf, PAGE_SIZE, "%s\n", input->label); } +static ssize_t ina3221_show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + + return snprintf(buf, PAGE_SIZE, "%d\n", + ina3221_is_enable(ina, channel)); +} + +static ssize_t ina3221_set_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + unsigned int mask = INA3221_CONFIG_CHx_EN(channel); + unsigned int config; + int val, ret; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + /* inX_enable only accepts 1 for enabling or 0 for disabling */ + if (val != 0 && val != 1) + return -EINVAL; + + config = val ? mask : 0; + + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); + if (ret) + return ret; + + return count; +} + static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, int *val) { @@ -146,8 +201,13 @@ static ssize_t ina3221_show_bus_voltage(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; int val, voltage_mv, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = ina3221_read_value(ina, reg, &val); if (ret) return ret; @@ -164,8 +224,13 @@ static ssize_t ina3221_show_shunt_voltage(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; int val, voltage_uv, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = ina3221_read_value(ina, reg, &val); if (ret) return ret; @@ -201,8 +266,13 @@ static ssize_t ina3221_show_current(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; int current_ma, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = __ina3221_show_current(ina, reg, ¤t_ma); if (ret) return ret; @@ -318,6 +388,10 @@ static ssize_t ina3221_show_power(struct device *dev, int val, current_ma, voltage_mv, ret; s64 power_uw; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + /* Read bus voltage */ ret = ina3221_read_value(ina, reg_bus, &val); if (ret) @@ -377,6 +451,14 @@ static SENSOR_DEVICE_ATTR(in2_label, 0444, static SENSOR_DEVICE_ATTR(in3_label, 0444, ina3221_show_label, NULL, INA3221_CHANNEL3); +/* voltage channel enable */ +static SENSOR_DEVICE_ATTR(in1_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR(in2_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR(in3_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL3); + /* bus voltage */ static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina3221_show_bus_voltage, NULL, INA3221_BUS1); @@ -460,6 +542,7 @@ static SENSOR_DEVICE_ATTR(power3_crit, 0644, static struct attribute *ina3221_attrs[] = { /* channel 1 -- make sure label at first */ &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in1_enable.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_shunt1_resistor.dev_attr.attr, @@ -473,6 +556,7 @@ static struct attribute *ina3221_attrs[] = { /* channel 2 -- make sure label at first */ &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_in2_enable.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_shunt2_resistor.dev_attr.attr, @@ -486,6 +570,7 @@ static struct attribute *ina3221_attrs[] = { /* channel 3 -- make sure label at first */ &sensor_dev_attr_in3_label.dev_attr.attr, + &sensor_dev_attr_in3_enable.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_curr3_input.dev_attr.attr, &sensor_dev_attr_shunt3_resistor.dev_attr.attr,
The inX_enable interface allows user space to enable or disable the corresponding channel. Meanwhile, according to hwmon ABI, a disabled channel/sensor should return -ENODATA as a read result. However, there're configurable nodes sharing the same __show() functions. So this change also adds to check if the attribute is read-only to make sure it's not reading a configuration but the sensor data. Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com> --- Documentation/hwmon/ina3221 | 1 + drivers/hwmon/ina3221.c | 85 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+)