linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Nicolin Chen <nicoleotsuka@gmail.com>, jdelvare@suse.com, corbet@lwn.net
Cc: afd@ti.com, linux-hwmon@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Subject: Re: [PATCH 1/2] hwmon: ina3221: Add power sysfs nodes
Date: Wed, 26 Sep 2018 05:34:53 -0700	[thread overview]
Message-ID: <dbf77a33-ae5c-1ac7-c94f-fa5505074adb@roeck-us.net> (raw)
In-Reply-To: <20180926064245.4091-2-nicoleotsuka@gmail.com>

Hi Nicolin,

On 09/25/2018 11:42 PM, Nicolin Chen wrote:
> The hwmon sysfs ABI supports powerX_input and powerX_crit. This
> can ease user space programs who care more about power in total
> than voltage or current individually.
> 
> So this patch adds these two sysfs nodes for INA3221 driver.
> 

Ah, sorry, we can't do that. The sysfs nodes are for chips providing power
registers, not for kernel drivers to provide calculations based on voltage
and current measurements. Basic guideline is that we report what is there,
not some  calculation based on it.

This is even more true for power limits: We can not assume that the power limit
is (max voltage * max current). or (current voltage * max_current), or anything
else. We simply don't have the knowledge to make that assumption.

Thanks,
Guenter

> Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
> ---
>   Documentation/hwmon/ina3221 |   4 +
>   drivers/hwmon/ina3221.c     | 145 ++++++++++++++++++++++++++++++++----
>   2 files changed, 133 insertions(+), 16 deletions(-)
> 
> diff --git a/Documentation/hwmon/ina3221 b/Documentation/hwmon/ina3221
> index 2726038be5bd..6be64b553cd0 100644
> --- a/Documentation/hwmon/ina3221
> +++ b/Documentation/hwmon/ina3221
> @@ -34,3 +34,7 @@ curr[123]_max           Warning alert current(mA) setting, activates the
>                             average is above this value.
>   curr[123]_max_alarm     Warning alert current limit exceeded
>   in[456]_input           Shunt voltage(uV) for channels 1, 2, and 3 respectively
> +power[123]_input        Power(uW) measurement channels
> +power[123]_crit         Critical alert power(uW) setting, activates the
> +                          corresponding alarm when the respective power
> +                          is above this value
> diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
> index ce4d1f55e9cd..5890a2da3bfe 100644
> --- a/drivers/hwmon/ina3221.c
> +++ b/drivers/hwmon/ina3221.c
> @@ -38,6 +38,8 @@
>   #define INA3221_WARN3			0x0c
>   #define INA3221_MASK_ENABLE		0x0f
>   
> +#define INA3221_BUS(x)			(INA3221_BUS1 + ((x) << 1))
> +
>   #define INA3221_CONFIG_MODE_SHUNT	BIT(1)
>   #define INA3221_CONFIG_MODE_BUS		BIT(2)
>   #define INA3221_CONFIG_MODE_CONTINUOUS	BIT(3)
> @@ -172,43 +174,50 @@ static ssize_t ina3221_show_shunt_voltage(struct device *dev,
>   	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
>   }
>   
> -static ssize_t ina3221_show_current(struct device *dev,
> -				    struct device_attribute *attr, char *buf)
> +static int __ina3221_show_current(struct ina3221_data *ina,
> +				  unsigned int reg, int *current_ma)
>   {
> -	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];
>   	struct ina3221_input *input = &ina->inputs[channel];
>   	int resistance_uo = input->shunt_resistor;
> -	int val, current_ma, voltage_nv, ret;
> +	int val, voltage_nv, ret;
>   
> +	/* Read bus shunt voltage */
>   	ret = ina3221_read_value(ina, reg, &val);
>   	if (ret)
>   		return ret;
> +
> +	/* LSB (4th bit) is 40 uV (40000 nV) */
>   	voltage_nv = val * 40000;
>   
> -	current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
> +	*current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
>   
> -	return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
> +	return 0;
>   }
>   
> -static ssize_t ina3221_set_current(struct device *dev,
> -				   struct device_attribute *attr,
> -				   const char *buf, size_t count)
> +static ssize_t ina3221_show_current(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 reg = sd_attr->index;
> -	unsigned int channel = register_channel[reg];
> -	struct ina3221_input *input = &ina->inputs[channel];
> -	int resistance_uo = input->shunt_resistor;
> -	int val, current_ma, voltage_uv, ret;
> +	int current_ma, ret;
>   
> -	ret = kstrtoint(buf, 0, &current_ma);
> +	ret = __ina3221_show_current(ina, reg, &current_ma);
>   	if (ret)
>   		return ret;
>   
> +	return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
> +}
> +
> +static int __ina3221_set_current(struct ina3221_data *ina,
> +				 unsigned int reg, int current_ma)
> +{
> +	unsigned int channel = register_channel[reg];
> +	struct ina3221_input *input = &ina->inputs[channel];
> +	int resistance_uo = input->shunt_resistor;
> +	int val, voltage_uv, ret;
> +
>   	/* clamp current */
>   	current_ma = clamp_val(current_ma,
>   			       INT_MIN / resistance_uo,
> @@ -226,6 +235,26 @@ static ssize_t ina3221_set_current(struct device *dev,
>   	if (ret)
>   		return ret;
>   
> +	return 0;
> +}
> +
> +static ssize_t ina3221_set_current(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 reg = sd_attr->index;
> +	int current_ma, ret;
> +
> +	ret = kstrtoint(buf, 0, &current_ma);
> +	if (ret)
> +		return ret;
> +
> +	ret = __ina3221_set_current(ina, reg, current_ma);
> +	if (ret)
> +		return ret;
> +
>   	return count;
>   }
>   
> @@ -278,6 +307,68 @@ static ssize_t ina3221_show_alert(struct device *dev,
>   	return snprintf(buf, PAGE_SIZE, "%d\n", regval);
>   }
>   
> +static ssize_t ina3221_show_power(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 reg = sd_attr->index;
> +	unsigned int channel = register_channel[reg];
> +	unsigned int reg_bus = INA3221_BUS(channel);
> +	int val, current_ma, voltage_mv, ret;
> +	s64 power_uw;
> +
> +	/* Read bus voltage */
> +	ret = ina3221_read_value(ina, reg_bus, &val);
> +	if (ret)
> +		return ret;
> +
> +	/* LSB (4th bit) is 8 mV */
> +	voltage_mv = val * 8;
> +
> +	/* Read calculated current */
> +	ret = __ina3221_show_current(ina, reg, &current_ma);
> +	if (ret)
> +		return ret;
> +
> +	power_uw = (s64)voltage_mv * current_ma;
> +
> +	return snprintf(buf, PAGE_SIZE, "%lld\n", power_uw);
> +}
> +
> +static ssize_t ina3221_set_power(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 reg = sd_attr->index;
> +	unsigned int channel = register_channel[reg];
> +	unsigned int reg_bus = INA3221_BUS(channel);
> +	int val, current_ma, voltage_mv, ret;
> +	s64 power_uw;
> +
> +	ret = kstrtos64(buf, 0, &power_uw);
> +	if (ret)
> +		return ret;
> +
> +	/* Read bus voltage */
> +	ret = ina3221_read_value(ina, reg_bus, &val);
> +	if (ret)
> +		return ret;
> +
> +	/* LSB (4th bit) is 8 mV */
> +	voltage_mv = val * 8;
> +
> +	current_ma = DIV_ROUND_CLOSEST(power_uw, voltage_mv);
> +
> +	ret = __ina3221_set_current(ina, reg, current_ma);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
>   /* input channel label */
>   static SENSOR_DEVICE_ATTR(in1_label, 0444,
>   		ina3221_show_label, NULL, INA3221_CHANNEL1);
> @@ -350,6 +441,22 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
>   static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
>   		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
>   
> +/* calculated power */
> +static SENSOR_DEVICE_ATTR(power1_input, 0444,
> +		ina3221_show_power, NULL, INA3221_SHUNT1);
> +static SENSOR_DEVICE_ATTR(power2_input, 0444,
> +		ina3221_show_power, NULL, INA3221_SHUNT2);
> +static SENSOR_DEVICE_ATTR(power3_input, 0444,
> +		ina3221_show_power, NULL, INA3221_SHUNT3);
> +
> +/* critical power */
> +static SENSOR_DEVICE_ATTR(power1_crit, 0644,
> +		ina3221_show_power, ina3221_set_power, INA3221_CRIT1);
> +static SENSOR_DEVICE_ATTR(power2_crit, 0644,
> +		ina3221_show_power, ina3221_set_power, INA3221_CRIT2);
> +static SENSOR_DEVICE_ATTR(power3_crit, 0644,
> +		ina3221_show_power, ina3221_set_power, INA3221_CRIT3);
> +
>   static struct attribute *ina3221_attrs[] = {
>   	/* channel 1 -- make sure label at first */
>   	&sensor_dev_attr_in1_label.dev_attr.attr,
> @@ -361,6 +468,8 @@ static struct attribute *ina3221_attrs[] = {
>   	&sensor_dev_attr_curr1_max.dev_attr.attr,
>   	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
>   	&sensor_dev_attr_in4_input.dev_attr.attr,
> +	&sensor_dev_attr_power1_input.dev_attr.attr,
> +	&sensor_dev_attr_power1_crit.dev_attr.attr,
>   
>   	/* channel 2 -- make sure label at first */
>   	&sensor_dev_attr_in2_label.dev_attr.attr,
> @@ -372,6 +481,8 @@ static struct attribute *ina3221_attrs[] = {
>   	&sensor_dev_attr_curr2_max.dev_attr.attr,
>   	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
>   	&sensor_dev_attr_in5_input.dev_attr.attr,
> +	&sensor_dev_attr_power2_input.dev_attr.attr,
> +	&sensor_dev_attr_power2_crit.dev_attr.attr,
>   
>   	/* channel 3 -- make sure label at first */
>   	&sensor_dev_attr_in3_label.dev_attr.attr,
> @@ -383,6 +494,8 @@ static struct attribute *ina3221_attrs[] = {
>   	&sensor_dev_attr_curr3_max.dev_attr.attr,
>   	&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
>   	&sensor_dev_attr_in6_input.dev_attr.attr,
> +	&sensor_dev_attr_power3_input.dev_attr.attr,
> +	&sensor_dev_attr_power3_crit.dev_attr.attr,
>   
>   	NULL,
>   };
> 


  reply	other threads:[~2018-09-26 12:34 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-26  6:42 [PATCH 0/2] hwmon: ina3221: Add power and enable sysfs nodes Nicolin Chen
2018-09-26  6:42 ` [PATCH 1/2] hwmon: ina3221: Add power " Nicolin Chen
2018-09-26 12:34   ` Guenter Roeck [this message]
2018-09-26 18:20     ` Nicolin Chen
2018-09-26 19:45       ` Guenter Roeck
2018-09-26 19:49         ` Nicolin Chen
2018-09-26  6:42 ` [PATCH 2/2] hwmon: ina3221: Add enable " Nicolin Chen
2018-09-26 13:06   ` Guenter Roeck
2018-09-26 18:02     ` Nicolin Chen
2018-09-26 19:58       ` Guenter Roeck
2018-09-26 20:25         ` Nicolin Chen
2018-09-26 20:44           ` Guenter Roeck
2018-09-26 21:55             ` Nicolin Chen
2018-09-27 16:05               ` Guenter Roeck
2018-09-27 18:39                 ` Nicolin Chen
2018-09-27 22:26     ` Nicolin Chen
2018-09-27 22:52       ` Guenter Roeck
2018-09-27 23:14         ` Nicolin Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dbf77a33-ae5c-1ac7-c94f-fa5505074adb@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=afd@ti.com \
    --cc=corbet@lwn.net \
    --cc=jdelvare@suse.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicoleotsuka@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).