Re: [PATCH 2/4] hwmon: (ina2xx) Make max expected current configurable

2017-09-28 Thread Guenter Roeck

On 09/28/2017 05:50 AM, Maciej Purski wrote:

Max expected current is used for calculating calibration register value,
Current LSB and Power LSB according to equations found in ina datasheet.
Max expected current is now implicitly set to default value,
which is 2^15, thanks to which Current LSB is equal to 1 mA and
Power LSB is equal to 2 uW or 25000 uW depending on ina model.

Make max expected current configurable, just like it's already done
with shunt resistance: from device tree, platform_data or later
from sysfs. On each max_expected_current change, calculate new values
for Current LSB and Power LSB. According to datasheet Current LSB should
be calculated by dividing max expected current by 2^15, as values read
from device registers are in this case 16-bit integers. Power LSB
is calculated by multiplying Current LSB by a factor, which is defined
in ina documentation.

Signed-off-by: Maciej Purski 
---
  drivers/hwmon/ina2xx.c | 105 +++--
  1 file changed, 93 insertions(+), 12 deletions(-)

diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 62e38fa..d956013 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -80,6 +80,8 @@
  /* common attrs, ina226 attrs and NULL */
  #define INA2XX_MAX_ATTRIBUTE_GROUPS   3
  
+#define INA2XX_MAX_EXPECTED_A_DEFAULT  (1 << 15)   /* current_lsb = 1 mA */

+
  /*
   * Both bus voltage and shunt voltage conversion times for ina226 are set
   * to 0b0100 on POR, which translates to 2200 microseconds in total.
@@ -100,13 +102,16 @@ struct ina2xx_config {
int shunt_div;
int bus_voltage_shift;
int bus_voltage_lsb;/* uV */
-   int power_lsb;  /* uW */
+   int power_lsb_factor;
  };
  
  struct ina2xx_data {

const struct ina2xx_config *config;
  
-	long rshunt;

+   long rshunt;/* uOhms */
+   unsigned int max_expected_current;  /* mA */
+   int current_lsb;/* uA */
+   int power_lsb;  /* uW */
struct mutex config_lock;
struct regmap *regmap;
  
@@ -121,7 +126,7 @@ static const struct ina2xx_config ina2xx_config[] = {

.shunt_div = 100,
.bus_voltage_shift = 3,
.bus_voltage_lsb = 4000,
-   .power_lsb = 2,
+   .power_lsb_factor = 20,
},
[ina226] = {
.config_default = INA226_CONFIG_DEFAULT,
@@ -130,7 +135,7 @@ static const struct ina2xx_config ina2xx_config[] = {
.shunt_div = 400,
.bus_voltage_shift = 0,
.bus_voltage_lsb = 1250,
-   .power_lsb = 25000,
+   .power_lsb_factor = 25,
},
  };
  
@@ -169,10 +174,17 @@ static u16 ina226_interval_to_reg(int interval)

return INA226_SHIFT_AVG(avg_bits);
  }
  
+/*

+ * Calculate calibration value according to equation 1 in ina226 datasheet
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ * Current LSB is in uA and RShunt is in uOhms, so in order to keep
+ * calibration value scaled RShunt must be converted to mOhms.
+ */
  static int ina2xx_calibrate(struct ina2xx_data *data)
  {
+   int r_shunt = DIV_ROUND_CLOSEST(data->rshunt, 1000);
u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-   data->rshunt);
+   data->current_lsb * r_shunt);
  
  	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);

  }
@@ -187,13 +199,28 @@ static int ina2xx_init(struct ina2xx_data *data)
if (ret < 0)
return ret;
  
-	/*

-* Set current LSB to 1mA, shunt is in uOhms
-* (equation 13 in datasheet).
-*/
return ina2xx_calibrate(data);
  }
  
+/*

+ * Set max_expected_current (mA) and calculate current_lsb (uA),
+ * according to equation 2 in ina226 datasheet. Power LSB is calculated
+ * by multiplying Current LSB by a given factor, which may vary depending
+ * on ina version.
+ */
+static int set_max_expected_current(struct ina2xx_data *data, unsigned int val)
+{
+   if (val <= 0 || val > data->config->calibration_factor)
+   return -EINVAL;
+
+   data->max_expected_current = val;
+   data->current_lsb = DIV_ROUND_CLOSEST(data->max_expected_current * 1000,
+ 1 << 15);
+   data->power_lsb = data->current_lsb * data->config->power_lsb_factor;
+
+   return 0;
+}
+
  static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval)
  {
struct ina2xx_data *data = dev_get_drvdata(dev);
@@ -268,11 +295,11 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 
reg,
val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_POWER:
-   val = regval * data->config->power_lsb;
+   val = regval * data->power_lsb;

[PATCH 2/4] hwmon: (ina2xx) Make max expected current configurable

2017-09-28 Thread Maciej Purski
Max expected current is used for calculating calibration register value,
Current LSB and Power LSB according to equations found in ina datasheet.
Max expected current is now implicitly set to default value,
which is 2^15, thanks to which Current LSB is equal to 1 mA and
Power LSB is equal to 2 uW or 25000 uW depending on ina model.

Make max expected current configurable, just like it's already done
with shunt resistance: from device tree, platform_data or later
from sysfs. On each max_expected_current change, calculate new values
for Current LSB and Power LSB. According to datasheet Current LSB should
be calculated by dividing max expected current by 2^15, as values read
from device registers are in this case 16-bit integers. Power LSB
is calculated by multiplying Current LSB by a factor, which is defined
in ina documentation.

Signed-off-by: Maciej Purski 
---
 drivers/hwmon/ina2xx.c | 105 +++--
 1 file changed, 93 insertions(+), 12 deletions(-)

diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 62e38fa..d956013 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -80,6 +80,8 @@
 /* common attrs, ina226 attrs and NULL */
 #define INA2XX_MAX_ATTRIBUTE_GROUPS3
 
+#define INA2XX_MAX_EXPECTED_A_DEFAULT  (1 << 15)   /* current_lsb = 1 mA */
+
 /*
  * Both bus voltage and shunt voltage conversion times for ina226 are set
  * to 0b0100 on POR, which translates to 2200 microseconds in total.
@@ -100,13 +102,16 @@ struct ina2xx_config {
int shunt_div;
int bus_voltage_shift;
int bus_voltage_lsb;/* uV */
-   int power_lsb;  /* uW */
+   int power_lsb_factor;
 };
 
 struct ina2xx_data {
const struct ina2xx_config *config;
 
-   long rshunt;
+   long rshunt;/* uOhms */
+   unsigned int max_expected_current;  /* mA */
+   int current_lsb;/* uA */
+   int power_lsb;  /* uW */
struct mutex config_lock;
struct regmap *regmap;
 
@@ -121,7 +126,7 @@ static const struct ina2xx_config ina2xx_config[] = {
.shunt_div = 100,
.bus_voltage_shift = 3,
.bus_voltage_lsb = 4000,
-   .power_lsb = 2,
+   .power_lsb_factor = 20,
},
[ina226] = {
.config_default = INA226_CONFIG_DEFAULT,
@@ -130,7 +135,7 @@ static const struct ina2xx_config ina2xx_config[] = {
.shunt_div = 400,
.bus_voltage_shift = 0,
.bus_voltage_lsb = 1250,
-   .power_lsb = 25000,
+   .power_lsb_factor = 25,
},
 };
 
@@ -169,10 +174,17 @@ static u16 ina226_interval_to_reg(int interval)
return INA226_SHIFT_AVG(avg_bits);
 }
 
+/*
+ * Calculate calibration value according to equation 1 in ina226 datasheet
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ * Current LSB is in uA and RShunt is in uOhms, so in order to keep
+ * calibration value scaled RShunt must be converted to mOhms.
+ */
 static int ina2xx_calibrate(struct ina2xx_data *data)
 {
+   int r_shunt = DIV_ROUND_CLOSEST(data->rshunt, 1000);
u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-   data->rshunt);
+   data->current_lsb * r_shunt);
 
return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
 }
@@ -187,13 +199,28 @@ static int ina2xx_init(struct ina2xx_data *data)
if (ret < 0)
return ret;
 
-   /*
-* Set current LSB to 1mA, shunt is in uOhms
-* (equation 13 in datasheet).
-*/
return ina2xx_calibrate(data);
 }
 
+/*
+ * Set max_expected_current (mA) and calculate current_lsb (uA),
+ * according to equation 2 in ina226 datasheet. Power LSB is calculated
+ * by multiplying Current LSB by a given factor, which may vary depending
+ * on ina version.
+ */
+static int set_max_expected_current(struct ina2xx_data *data, unsigned int val)
+{
+   if (val <= 0 || val > data->config->calibration_factor)
+   return -EINVAL;
+
+   data->max_expected_current = val;
+   data->current_lsb = DIV_ROUND_CLOSEST(data->max_expected_current * 1000,
+ 1 << 15);
+   data->power_lsb = data->current_lsb * data->config->power_lsb_factor;
+
+   return 0;
+}
+
 static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval)
 {
struct ina2xx_data *data = dev_get_drvdata(dev);
@@ -268,11 +295,11 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 
reg,
val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_POWER:
-   val = regval * data->config->power_lsb;
+   val = regval * data->power_lsb;
break;
case INA2XX_CURRENT:
-   /* signed re