devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] ina238: Improvements and INA228 support
@ 2025-07-15 20:48 Jonas Rebmann
  2025-07-15 20:49 ` [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace Jonas Rebmann
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-15 20:48 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel, Jonas Rebmann

This series includes:
 - Whitespace fixes
 - Add labels to voltage inputs
 - Support INA228 ultra-precise power monitor

Tested on the INA228 chips on a TI TMDS62LEVM.

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
Jonas Rebmann (4):
      hwmon: ina238: Fix inconsistent whitespace
      hwmon: ina238: Add label support for voltage inputs
      dt-bindings: Add INA228 to ina2xx devicetree bindings
      hwmon: ina238: Add support for INA228

 .../devicetree/bindings/hwmon/ti,ina2xx.yaml       |   2 +
 drivers/hwmon/ina238.c                             | 155 ++++++++++++++++++---
 2 files changed, 135 insertions(+), 22 deletions(-)
---
base-commit: 27b297ca04813623d8df2f79d141d51e0856810c
change-id: 20250715-ina228-ddb5550dcb23

Best regards,
-- 
Jonas Rebmann <jre@pengutronix.de>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace
  2025-07-15 20:48 [PATCH 0/4] ina238: Improvements and INA228 support Jonas Rebmann
@ 2025-07-15 20:49 ` Jonas Rebmann
  2025-07-16 15:52   ` Guenter Roeck
  2025-07-15 20:49 ` [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs Jonas Rebmann
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-15 20:49 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel, Jonas Rebmann

Some purely cosmetic changes in ina238.c:

 - When aligning definitions, do so consistently with tab stop of 8.
 - Use spaces instead of tabs around operators.
 - Align wrapped lines.

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
 drivers/hwmon/ina238.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c
index 9a5fd16a4ec2a6d5a6cd5e8070d0442e1ef0135a..d603d4990c928984350c1f414431219b1489a546 100644
--- a/drivers/hwmon/ina238.c
+++ b/drivers/hwmon/ina238.c
@@ -41,7 +41,7 @@
 
 #define INA238_CONFIG_ADCRANGE		BIT(4)
 #define SQ52206_CONFIG_ADCRANGE_HIGH	BIT(4)
-#define SQ52206_CONFIG_ADCRANGE_LOW		BIT(3)
+#define SQ52206_CONFIG_ADCRANGE_LOW	BIT(3)
 
 #define INA238_DIAG_ALERT_TMPOL		BIT(7)
 #define INA238_DIAG_ALERT_SHNTOL	BIT(6)
@@ -104,7 +104,7 @@
 
 #define INA238_SHUNT_VOLTAGE_LSB	5 /* 5 uV/lsb */
 #define INA238_BUS_VOLTAGE_LSB		3125 /* 3.125 mV/lsb */
-#define INA238_DIE_TEMP_LSB			1250000 /* 125.0000 mC/lsb */
+#define INA238_DIE_TEMP_LSB		1250000 /* 125.0000 mC/lsb */
 #define SQ52206_BUS_VOLTAGE_LSB		3750 /* 3.75 mV/lsb */
 #define SQ52206_DIE_TEMP_LSB		78125 /* 7.8125 mC/lsb */
 
@@ -118,12 +118,12 @@ enum ina238_ids { ina238, ina237, sq52206 };
 
 struct ina238_config {
 	bool has_power_highest;		/* chip detection power peak */
-	bool has_energy;			/* chip detection energy */
-	u8 temp_shift;				/* fixed parameters for temp calculate */
+	bool has_energy;		/* chip detection energy */
+	u8 temp_shift;			/* fixed parameters for temp calculate */
 	u32 power_calculate_factor;	/* fixed parameters for power calculate */
-	u16 config_default;			/* Power-on default state */
+	u16 config_default;		/* Power-on default state */
 	int bus_voltage_lsb;		/* use for temperature calculate, uV/lsb */
-	int temp_lsb;				/* use for temperature calculate */
+	int temp_lsb;			/* use for temperature calculate */
 };
 
 struct ina238_data {
@@ -271,7 +271,7 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
 		if (channel == 0)
 			/* gain of 1 -> LSB / 4 */
 			*val = (regval * INA238_SHUNT_VOLTAGE_LSB) *
-					data->gain / (1000 * 4);
+				data->gain / (1000 * 4);
 		else
 			*val = (regval * data->config->bus_voltage_lsb) / 1000;
 		break;
@@ -370,7 +370,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
 			return err;
 
 		/* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
-		power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT *	data->gain *
+		power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
 				data->config->power_calculate_factor, 4 * 100 * data->rshunt);
 		/* Clamp value to maximum value of long */
 		*val = clamp_val(power, 0, LONG_MAX);
@@ -381,7 +381,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
 			return err;
 
 		/* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
-		power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT *	data->gain *
+		power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
 				data->config->power_calculate_factor, 4 * 100 * data->rshunt);
 		/* Clamp value to maximum value of long */
 		*val = clamp_val(power, 0, LONG_MAX);
@@ -395,7 +395,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
 		 * Truncated 24-bit compare register, lower 8-bits are
 		 * truncated. Same conversion to/from uW as POWER register.
 		 */
-		power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT *	data->gain *
+		power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain *
 				data->config->power_calculate_factor, 4 * 100 * data->rshunt);
 		/* Clamp value to maximum value of long */
 		*val = clamp_val(power, 0, LONG_MAX);
@@ -448,7 +448,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val)
 			return err;
 		/* Signed, result in mC */
 		*val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
-						(s64)data->config->temp_lsb, 10000);
+			       (s64)data->config->temp_lsb, 10000);
 		break;
 	case hwmon_temp_max:
 		err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval);
@@ -456,7 +456,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val)
 			return err;
 		/* Signed, result in mC */
 		*val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
-						(s64)data->config->temp_lsb, 10000);
+			       (s64)data->config->temp_lsb, 10000);
 		break;
 	case hwmon_temp_max_alarm:
 		err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval);
@@ -501,8 +501,8 @@ static ssize_t energy1_input_show(struct device *dev,
 		return ret;
 
 	/* result in uJ */
-	energy = div_u64(regval * INA238_FIXED_SHUNT *	data->gain * 16 * 10 *
-				data->config->power_calculate_factor, 4 * data->rshunt);
+	energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 *
+			 data->config->power_calculate_factor, 4 * data->rshunt);
 
 	return sysfs_emit(buf, "%llu\n", energy);
 }
@@ -776,7 +776,7 @@ MODULE_DEVICE_TABLE(of, ina238_of_match);
 
 static struct i2c_driver ina238_driver = {
 	.driver = {
-		.name	= "ina238",
+		.name = "ina238",
 		.of_match_table = of_match_ptr(ina238_of_match),
 	},
 	.probe		= ina238_probe,

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs
  2025-07-15 20:48 [PATCH 0/4] ina238: Improvements and INA228 support Jonas Rebmann
  2025-07-15 20:49 ` [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace Jonas Rebmann
@ 2025-07-15 20:49 ` Jonas Rebmann
  2025-07-16 15:04   ` Guenter Roeck
  2025-07-15 20:49 ` [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings Jonas Rebmann
  2025-07-15 20:49 ` [PATCH 4/4] hwmon: ina238: Add support for INA228 Jonas Rebmann
  3 siblings, 1 reply; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-15 20:49 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel, Jonas Rebmann

The INA family of power monitors estimate power consumption based on
two voltage measurements: across a shunt resistor and across the bus.

Conveniently label them "Shunt Voltage" and "Bus Voltage".

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
 drivers/hwmon/ina238.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c
index d603d4990c928984350c1f414431219b1489a546..44f7ce3c1d7b5a91f67d12c1d29e1e560024a04c 100644
--- a/drivers/hwmon/ina238.c
+++ b/drivers/hwmon/ina238.c
@@ -507,6 +507,27 @@ static ssize_t energy1_input_show(struct device *dev,
 	return sysfs_emit(buf, "%llu\n", energy);
 }
 
+static int ina238_read_string(struct device *dev, enum hwmon_sensor_types type,
+			       u32 attr, int channel, const char **str)
+{
+	switch (type) {
+	case hwmon_in:
+		switch (channel) {
+		case 0:
+			*str = "Shunt Voltage";
+			return 0;
+		case 1:
+			*str = "Bus Voltage";
+			return 0;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+	return -EOPNOTSUPP;
+}
+
 static int ina238_read(struct device *dev, enum hwmon_sensor_types type,
 		       u32 attr, int channel, long *val)
 {
@@ -565,6 +586,7 @@ static umode_t ina238_is_visible(const void *drvdata,
 		case hwmon_in_input:
 		case hwmon_in_max_alarm:
 		case hwmon_in_min_alarm:
+		case hwmon_in_label:
 			return 0444;
 		case hwmon_in_max:
 		case hwmon_in_min:
@@ -615,9 +637,9 @@ static umode_t ina238_is_visible(const void *drvdata,
 static const struct hwmon_channel_info * const ina238_info[] = {
 	HWMON_CHANNEL_INFO(in,
 			   /* 0: shunt voltage */
-			   INA238_HWMON_IN_CONFIG,
+			   INA238_HWMON_IN_CONFIG | HWMON_I_LABEL,
 			   /* 1: bus voltage */
-			   INA238_HWMON_IN_CONFIG),
+			   INA238_HWMON_IN_CONFIG | HWMON_I_LABEL),
 	HWMON_CHANNEL_INFO(curr,
 			   /* 0: current through shunt */
 			   HWMON_C_INPUT),
@@ -633,6 +655,7 @@ static const struct hwmon_channel_info * const ina238_info[] = {
 
 static const struct hwmon_ops ina238_hwmon_ops = {
 	.is_visible = ina238_is_visible,
+	.read_string = ina238_read_string,
 	.read = ina238_read,
 	.write = ina238_write,
 };

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings
  2025-07-15 20:48 [PATCH 0/4] ina238: Improvements and INA228 support Jonas Rebmann
  2025-07-15 20:49 ` [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace Jonas Rebmann
  2025-07-15 20:49 ` [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs Jonas Rebmann
@ 2025-07-15 20:49 ` Jonas Rebmann
  2025-07-16  6:30   ` Krzysztof Kozlowski
  2025-07-15 20:49 ` [PATCH 4/4] hwmon: ina238: Add support for INA228 Jonas Rebmann
  3 siblings, 1 reply; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-15 20:49 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel, Jonas Rebmann

Add the ina228 to ina2xx bindings.

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
 Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
index d1fb7b9abda081113ac28ed999d9c28da9d4daf9..fa68b99ef2e292c0b7d618c14819fa2bd64db7b8 100644
--- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
+++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
@@ -25,6 +25,7 @@ properties:
       - ti,ina219
       - ti,ina220
       - ti,ina226
+      - ti,ina228
       - ti,ina230
       - ti,ina231
       - ti,ina233
@@ -107,6 +108,7 @@ allOf:
               - ti,ina219
               - ti,ina220
               - ti,ina226
+              - ti,ina228
               - ti,ina230
               - ti,ina231
               - ti,ina237

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/4] hwmon: ina238: Add support for INA228
  2025-07-15 20:48 [PATCH 0/4] ina238: Improvements and INA228 support Jonas Rebmann
                   ` (2 preceding siblings ...)
  2025-07-15 20:49 ` [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings Jonas Rebmann
@ 2025-07-15 20:49 ` Jonas Rebmann
  2025-07-16 15:50   ` Guenter Roeck
  3 siblings, 1 reply; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-15 20:49 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel, Jonas Rebmann

Add support for the Texas Instruments INA228 Ultra-Precise
Power/Energy/Charge Monitor.

The INA228 is very similar to the INA238 but offers four bits of extra
precision in the temperature, voltage and current measurement fields.
It also supports energy and charge monitoring, the latter of which is
not supported through this patch.

While it seems in the datasheet that some constants such as LSB values
differ between the 228 and the 238, they differ only for those registers
where four bits of precision have been added and they differ by a factor
of 16 (VBUS, VSHUNT, DIETEMP, CURRENT).

Therefore, the INA238 constants are still applicable with regard
to the bit of the same significance.

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
 drivers/hwmon/ina238.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 93 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c
index 44f7ce3c1d7b5a91f67d12c1d29e1e560024a04c..f8c74317344a5bbdf933a32b8c7e5aba13beda30 100644
--- a/drivers/hwmon/ina238.c
+++ b/drivers/hwmon/ina238.c
@@ -107,6 +107,7 @@
 #define INA238_DIE_TEMP_LSB		1250000 /* 125.0000 mC/lsb */
 #define SQ52206_BUS_VOLTAGE_LSB		3750 /* 3.75 mV/lsb */
 #define SQ52206_DIE_TEMP_LSB		78125 /* 7.8125 mC/lsb */
+#define INA228_DIE_TEMP_LSB		78125 /* 7.8125 mC/lsb */
 
 static const struct regmap_config ina238_regmap_config = {
 	.max_register = INA238_REGISTERS,
@@ -114,9 +115,10 @@ static const struct regmap_config ina238_regmap_config = {
 	.val_bits = 16,
 };
 
-enum ina238_ids { ina238, ina237, sq52206 };
+enum ina238_ids { ina238, ina237, sq52206, ina228 };
 
 struct ina238_config {
+	bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */
 	bool has_power_highest;		/* chip detection power peak */
 	bool has_energy;		/* chip detection energy */
 	u8 temp_shift;			/* fixed parameters for temp calculate */
@@ -137,6 +139,7 @@ struct ina238_data {
 
 static const struct ina238_config ina238_config[] = {
 	[ina238] = {
+		.has_20bit_voltage_current = false,
 		.has_energy = false,
 		.has_power_highest = false,
 		.temp_shift = 4,
@@ -146,6 +149,7 @@ static const struct ina238_config ina238_config[] = {
 		.temp_lsb = INA238_DIE_TEMP_LSB,
 	},
 	[ina237] = {
+		.has_20bit_voltage_current = false,
 		.has_energy = false,
 		.has_power_highest = false,
 		.temp_shift = 4,
@@ -155,6 +159,7 @@ static const struct ina238_config ina238_config[] = {
 		.temp_lsb = INA238_DIE_TEMP_LSB,
 	},
 	[sq52206] = {
+		.has_20bit_voltage_current = false,
 		.has_energy = true,
 		.has_power_highest = true,
 		.temp_shift = 0,
@@ -163,6 +168,16 @@ static const struct ina238_config ina238_config[] = {
 		.bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB,
 		.temp_lsb = SQ52206_DIE_TEMP_LSB,
 	},
+	[ina228] = {
+		.has_20bit_voltage_current = true,
+		.has_energy = true,
+		.has_power_highest = false,
+		.temp_shift = 0,
+		.power_calculate_factor = 20,
+		.config_default = INA238_CONFIG_DEFAULT,
+		.bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
+		.temp_lsb = INA228_DIE_TEMP_LSB,
+	},
 };
 
 static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
@@ -199,6 +214,56 @@ static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val)
 	return 0;
 }
 
+static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel,
+				     long *val)
+{
+	struct ina238_data *data = dev_get_drvdata(dev);
+	int regval;
+	int field;
+	int err;
+
+	err = ina238_read_reg24(data->client, INA238_SHUNT_VOLTAGE, &regval);
+	if (err)
+		return err;
+
+	/* bits 3-0 Reserved, always zero */
+	field = regval >> 4;
+
+	/*
+	 * gain of 1 -> LSB / 4
+	 * This field has 16 bit on ina238. ina228 adds another 4 bits of
+	 * precision. ina238 conversion factors can still be applied when
+	 * dividing by 16.
+	 */
+	*val = (field * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16;
+	return 0;
+}
+
+static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel,
+				   long *val)
+{
+	struct ina238_data *data = dev_get_drvdata(dev);
+	int regval;
+	int field;
+	int err;
+
+	err = ina238_read_reg24(data->client, INA238_BUS_VOLTAGE, &regval);
+	if (err)
+		return err;
+
+	/* bits 3-0 Reserved, always zero */
+	field = regval >> 4;
+
+	/*
+	 * gain of 1 -> LSB / 4
+	 * This field has 16 bit on ina238. ina228 adds another 4 bits of
+	 * precision. ina238 conversion factors can still be applied when
+	 * dividing by 16.
+	 */
+	*val = (field * data->config->bus_voltage_lsb) / 1000 / 16;
+	return 0;
+}
+
 static int ina238_read_in(struct device *dev, u32 attr, int channel,
 			  long *val)
 {
@@ -211,6 +276,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
 	case 0:
 		switch (attr) {
 		case hwmon_in_input:
+			if (data->config->has_20bit_voltage_current)
+				return ina228_read_shunt_voltage(dev, attr, channel, val);
 			reg = INA238_SHUNT_VOLTAGE;
 			break;
 		case hwmon_in_max:
@@ -234,6 +301,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
 	case 1:
 		switch (attr) {
 		case hwmon_in_input:
+			if (data->config->has_20bit_voltage_current)
+				return ina228_read_bus_voltage(dev, attr, channel, val);
 			reg = INA238_BUS_VOLTAGE;
 			break;
 		case hwmon_in_max:
@@ -341,13 +410,27 @@ static int ina238_read_current(struct device *dev, u32 attr, long *val)
 
 	switch (attr) {
 	case hwmon_curr_input:
-		err = regmap_read(data->regmap, INA238_CURRENT, &regval);
-		if (err < 0)
-			return err;
+		if (data->config->has_20bit_voltage_current) {
+			err = ina238_read_reg24(data->client, INA238_CURRENT, &regval);
+			if (err)
+				return err;
+			/* 4 Lowest 4 bits reserved zero */
+			regval >>= 4;
+		} else {
+			err = regmap_read(data->regmap, INA238_CURRENT, &regval);
+			if (err < 0)
+				return err;
+			/* sign-extend */
+			regval = (s16)regval;
+		}
 
 		/* Signed register, fixed 1mA current lsb. result in mA */
-		*val = div_s64((s16)regval * INA238_FIXED_SHUNT * data->gain,
+		*val = div_s64(regval * INA238_FIXED_SHUNT * data->gain,
 			       data->rshunt * 4);
+
+		/* Account for 4 bit offset */
+		if (data->config->has_20bit_voltage_current)
+			*val /= 16;
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -773,6 +856,7 @@ static int ina238_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ina238_id[] = {
+	{ "ina228", ina228 },
 	{ "ina237", ina237 },
 	{ "ina238", ina238 },
 	{ "sq52206", sq52206 },
@@ -781,6 +865,10 @@ static const struct i2c_device_id ina238_id[] = {
 MODULE_DEVICE_TABLE(i2c, ina238_id);
 
 static const struct of_device_id __maybe_unused ina238_of_match[] = {
+	{
+		.compatible = "ti,ina228",
+		.data = (void *)ina228
+	},
 	{
 		.compatible = "ti,ina237",
 		.data = (void *)ina237

-- 
2.39.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings
  2025-07-15 20:49 ` [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings Jonas Rebmann
@ 2025-07-16  6:30   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 11+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-16  6:30 UTC (permalink / raw)
  To: Jonas Rebmann, Jean Delvare, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-hwmon, linux-kernel, devicetree, kernel

On 15/07/2025 22:49, Jonas Rebmann wrote:
> Add the ina228 to ina2xx bindings.
> 
> Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
> ---
>  Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs
  2025-07-15 20:49 ` [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs Jonas Rebmann
@ 2025-07-16 15:04   ` Guenter Roeck
  2025-07-17  7:30     ` Jonas Rebmann
  0 siblings, 1 reply; 11+ messages in thread
From: Guenter Roeck @ 2025-07-16 15:04 UTC (permalink / raw)
  To: Jonas Rebmann, Jean Delvare, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel

On 7/15/25 13:49, Jonas Rebmann wrote:
> The INA family of power monitors estimate power consumption based on
> two voltage measurements: across a shunt resistor and across the bus.
> 
> Conveniently label them "Shunt Voltage" and "Bus Voltage".
> 

Labels are supposed to show the sensor's association with the system, not
the chip labeling. So this is a no-go. And, yes, apparently I have been too
complacent with people (mis-)using the label attributes. That doesn't make
it better, so don't use it as argument to support this one.

Guenter


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] hwmon: ina238: Add support for INA228
  2025-07-15 20:49 ` [PATCH 4/4] hwmon: ina238: Add support for INA228 Jonas Rebmann
@ 2025-07-16 15:50   ` Guenter Roeck
  0 siblings, 0 replies; 11+ messages in thread
From: Guenter Roeck @ 2025-07-16 15:50 UTC (permalink / raw)
  To: Jonas Rebmann, Jean Delvare, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel

On 7/15/25 13:49, Jonas Rebmann wrote:
> Add support for the Texas Instruments INA228 Ultra-Precise
> Power/Energy/Charge Monitor.
> 
> The INA228 is very similar to the INA238 but offers four bits of extra
> precision in the temperature, voltage and current measurement fields.
> It also supports energy and charge monitoring, the latter of which is
> not supported through this patch.
> 
> While it seems in the datasheet that some constants such as LSB values
> differ between the 228 and the 238, they differ only for those registers
> where four bits of precision have been added and they differ by a factor
> of 16 (VBUS, VSHUNT, DIETEMP, CURRENT).
> 
> Therefore, the INA238 constants are still applicable with regard
> to the bit of the same significance.
> 
> Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
> ---
>   drivers/hwmon/ina238.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 93 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c
> index 44f7ce3c1d7b5a91f67d12c1d29e1e560024a04c..f8c74317344a5bbdf933a32b8c7e5aba13beda30 100644
> --- a/drivers/hwmon/ina238.c
> +++ b/drivers/hwmon/ina238.c
> @@ -107,6 +107,7 @@
>   #define INA238_DIE_TEMP_LSB		1250000 /* 125.0000 mC/lsb */
>   #define SQ52206_BUS_VOLTAGE_LSB		3750 /* 3.75 mV/lsb */
>   #define SQ52206_DIE_TEMP_LSB		78125 /* 7.8125 mC/lsb */
> +#define INA228_DIE_TEMP_LSB		78125 /* 7.8125 mC/lsb */
>   
>   static const struct regmap_config ina238_regmap_config = {
>   	.max_register = INA238_REGISTERS,
> @@ -114,9 +115,10 @@ static const struct regmap_config ina238_regmap_config = {
>   	.val_bits = 16,
>   };
>   
> -enum ina238_ids { ina238, ina237, sq52206 };
> +enum ina238_ids { ina238, ina237, sq52206, ina228 };
>   
>   struct ina238_config {
> +	bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */
>   	bool has_power_highest;		/* chip detection power peak */
>   	bool has_energy;		/* chip detection energy */
>   	u8 temp_shift;			/* fixed parameters for temp calculate */
> @@ -137,6 +139,7 @@ struct ina238_data {
>   
>   static const struct ina238_config ina238_config[] = {
>   	[ina238] = {
> +		.has_20bit_voltage_current = false,
>   		.has_energy = false,
>   		.has_power_highest = false,
>   		.temp_shift = 4,
> @@ -146,6 +149,7 @@ static const struct ina238_config ina238_config[] = {
>   		.temp_lsb = INA238_DIE_TEMP_LSB,
>   	},
>   	[ina237] = {
> +		.has_20bit_voltage_current = false,
>   		.has_energy = false,
>   		.has_power_highest = false,
>   		.temp_shift = 4,
> @@ -155,6 +159,7 @@ static const struct ina238_config ina238_config[] = {
>   		.temp_lsb = INA238_DIE_TEMP_LSB,
>   	},
>   	[sq52206] = {
> +		.has_20bit_voltage_current = false,
>   		.has_energy = true,
>   		.has_power_highest = true,
>   		.temp_shift = 0,
> @@ -163,6 +168,16 @@ static const struct ina238_config ina238_config[] = {
>   		.bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB,
>   		.temp_lsb = SQ52206_DIE_TEMP_LSB,
>   	},
> +	[ina228] = {
> +		.has_20bit_voltage_current = true,
> +		.has_energy = true,
> +		.has_power_highest = false,
> +		.temp_shift = 0,
> +		.power_calculate_factor = 20,
> +		.config_default = INA238_CONFIG_DEFAULT,
> +		.bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
> +		.temp_lsb = INA228_DIE_TEMP_LSB,
> +	},
>   };
>   
>   static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
> @@ -199,6 +214,56 @@ static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val)
>   	return 0;
>   }
>   
> +static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel,
> +				     long *val)
> +{
> +	struct ina238_data *data = dev_get_drvdata(dev);
> +	int regval;
> +	int field;
> +	int err;
> +
> +	err = ina238_read_reg24(data->client, INA238_SHUNT_VOLTAGE, &regval);
> +	if (err)
> +		return err;
> +
> +	/* bits 3-0 Reserved, always zero */
> +	field = regval >> 4;
> +
> +	/*
> +	 * gain of 1 -> LSB / 4
> +	 * This field has 16 bit on ina238. ina228 adds another 4 bits of
> +	 * precision. ina238 conversion factors can still be applied when
> +	 * dividing by 16.
> +	 */
> +	*val = (field * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16;
> +	return 0;
> +}
> +
> +static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel,
> +				   long *val)
> +{
> +	struct ina238_data *data = dev_get_drvdata(dev);
> +	int regval;
> +	int field;
> +	int err;
> +
> +	err = ina238_read_reg24(data->client, INA238_BUS_VOLTAGE, &regval);
> +	if (err)
> +		return err;
> +
> +	/* bits 3-0 Reserved, always zero */
> +	field = regval >> 4;
> +
> +	/*
> +	 * gain of 1 -> LSB / 4
> +	 * This field has 16 bit on ina238. ina228 adds another 4 bits of
> +	 * precision. ina238 conversion factors can still be applied when
> +	 * dividing by 16.
> +	 */
> +	*val = (field * data->config->bus_voltage_lsb) / 1000 / 16;
> +	return 0;
> +}

Sign extension missing for both. Yes, I understand, the bus voltage is always positive,
but the shunt voltage isn't.

> +
>   static int ina238_read_in(struct device *dev, u32 attr, int channel,
>   			  long *val)
>   {
> @@ -211,6 +276,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
>   	case 0:
>   		switch (attr) {
>   		case hwmon_in_input:
> +			if (data->config->has_20bit_voltage_current)
> +				return ina228_read_shunt_voltage(dev, attr, channel, val);
>   			reg = INA238_SHUNT_VOLTAGE;
>   			break;
>   		case hwmon_in_max:
> @@ -234,6 +301,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
>   	case 1:
>   		switch (attr) {
>   		case hwmon_in_input:
> +			if (data->config->has_20bit_voltage_current)
> +				return ina228_read_bus_voltage(dev, attr, channel, val);
>   			reg = INA238_BUS_VOLTAGE;
>   			break;
>   		case hwmon_in_max:
> @@ -341,13 +410,27 @@ static int ina238_read_current(struct device *dev, u32 attr, long *val)
>   
>   	switch (attr) {
>   	case hwmon_curr_input:
> -		err = regmap_read(data->regmap, INA238_CURRENT, &regval);
> -		if (err < 0)
> -			return err;
> +		if (data->config->has_20bit_voltage_current) {
> +			err = ina238_read_reg24(data->client, INA238_CURRENT, &regval);
> +			if (err)
> +				return err;
> +			/* 4 Lowest 4 bits reserved zero */
> +			regval >>= 4;

It is still a signed register and thus needs sign extension.

> +		} else {
> +			err = regmap_read(data->regmap, INA238_CURRENT, &regval);
> +			if (err < 0)
> +				return err;
> +			/* sign-extend */
> +			regval = (s16)regval;
> +		}
>   
>   		/* Signed register, fixed 1mA current lsb. result in mA */
> -		*val = div_s64((s16)regval * INA238_FIXED_SHUNT * data->gain,
> +		*val = div_s64(regval * INA238_FIXED_SHUNT * data->gain,
>   			       data->rshunt * 4);

Reading this again, I suspect that "regval * INA238_FIXED_SHUNT * data->gain"
is a 32-bit value (it is never extended to 64 bit) which may overflow. That probably
never happened with the old chips, but regval is now a 20-bit value so overflows
are more likely than before. The code needs to make sure that the expression
has a 64-bit result.

> +
> +		/* Account for 4 bit offset */
> +		if (data->config->has_20bit_voltage_current)
> +			*val /= 16;
>   		break;
>   	default:
>   		return -EOPNOTSUPP;
> @@ -773,6 +856,7 @@ static int ina238_probe(struct i2c_client *client)
>   }
>   
>   static const struct i2c_device_id ina238_id[] = {
> +	{ "ina228", ina228 },
>   	{ "ina237", ina237 },
>   	{ "ina238", ina238 },
>   	{ "sq52206", sq52206 },
> @@ -781,6 +865,10 @@ static const struct i2c_device_id ina238_id[] = {
>   MODULE_DEVICE_TABLE(i2c, ina238_id);
>   
>   static const struct of_device_id __maybe_unused ina238_of_match[] = {
> +	{
> +		.compatible = "ti,ina228",
> +		.data = (void *)ina228
> +	},
>   	{
>   		.compatible = "ti,ina237",
>   		.data = (void *)ina237
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace
  2025-07-15 20:49 ` [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace Jonas Rebmann
@ 2025-07-16 15:52   ` Guenter Roeck
  0 siblings, 0 replies; 11+ messages in thread
From: Guenter Roeck @ 2025-07-16 15:52 UTC (permalink / raw)
  To: Jonas Rebmann, Jean Delvare, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel

On 7/15/25 13:49, Jonas Rebmann wrote:
> Some purely cosmetic changes in ina238.c:
> 
>   - When aligning definitions, do so consistently with tab stop of 8.
>   - Use spaces instead of tabs around operators.
>   - Align wrapped lines.
> 
> Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
> ---
>   drivers/hwmon/ina238.c | 30 +++++++++++++++---------------
>   1 file changed, 15 insertions(+), 15 deletions(-)
...
>   static struct i2c_driver ina238_driver = {
>   	.driver = {
> -		.name	= "ina238",
> +		.name = "ina238",

This was aligned with ".probe" below. Either leave it alone or change the tabs below as well.

Thanks,
Guenter


>   		.of_match_table = of_match_ptr(ina238_of_match),
>   	},
>   	.probe		= ina238_probe,
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs
  2025-07-16 15:04   ` Guenter Roeck
@ 2025-07-17  7:30     ` Jonas Rebmann
  2025-07-17 15:24       ` Guenter Roeck
  0 siblings, 1 reply; 11+ messages in thread
From: Jonas Rebmann @ 2025-07-17  7:30 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel

Hi Guenter,

Thanks for the review!

On 16/07/2025 17.04, Guenter Roeck wrote:
> On 7/15/25 13:49, Jonas Rebmann wrote:
>> The INA family of power monitors estimate power consumption based on
>> two voltage measurements: across a shunt resistor and across the bus.
>>
>> Conveniently label them "Shunt Voltage" and "Bus Voltage".
>>
> 
> Labels are supposed to show the sensor's association with the system, not
> the chip labeling. So this is a no-go. And, yes, apparently I have been too
> complacent with people (mis-)using the label attributes. That doesn't make
> it better, so don't use it as argument to support this one.

As this chip measures power based on two voltage measurements, the
measured voltage inputs must always be associated with the system in
that way, that in1 measures the voltage on a bus and in0 over a shunt
resistor on that bus.

Otherwise the Power/Energy/Charge-Measurements will be incorrect.

Do you have a suggestion on how to use the labels correctly or should I
just drop the patch for v2?

Regards,
Jonas


-- 
Pengutronix e.K.                          | Jonas Rebmann               |
Steuerwalder Str. 21                      | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                 | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686          | Fax:   +49-5121-206917-9    |

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs
  2025-07-17  7:30     ` Jonas Rebmann
@ 2025-07-17 15:24       ` Guenter Roeck
  0 siblings, 0 replies; 11+ messages in thread
From: Guenter Roeck @ 2025-07-17 15:24 UTC (permalink / raw)
  To: Jonas Rebmann
  Cc: Jean Delvare, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-hwmon, linux-kernel, Krzysztof Kozlowski, devicetree,
	kernel

On Thu, Jul 17, 2025 at 09:30:33AM +0200, Jonas Rebmann wrote:
> Hi Guenter,
> 
> Thanks for the review!
> 
> On 16/07/2025 17.04, Guenter Roeck wrote:
> > On 7/15/25 13:49, Jonas Rebmann wrote:
> > > The INA family of power monitors estimate power consumption based on
> > > two voltage measurements: across a shunt resistor and across the bus.
> > > 
> > > Conveniently label them "Shunt Voltage" and "Bus Voltage".
> > > 
> > 
> > Labels are supposed to show the sensor's association with the system, not
> > the chip labeling. So this is a no-go. And, yes, apparently I have been too
> > complacent with people (mis-)using the label attributes. That doesn't make
> > it better, so don't use it as argument to support this one.
> 
> As this chip measures power based on two voltage measurements, the
> measured voltage inputs must always be associated with the system in
> that way, that in1 measures the voltage on a bus and in0 over a shunt
> resistor on that bus.
> 
> Otherwise the Power/Energy/Charge-Measurements will be incorrect.
> 
> Do you have a suggestion on how to use the labels correctly or should I
> just drop the patch for v2?
> 
Please drop it.

Guenter

> Regards,
> Jonas
> 
> 
> -- 
> Pengutronix e.K.                          | Jonas Rebmann               |
> Steuerwalder Str. 21                      | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                 | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686          | Fax:   +49-5121-206917-9    |
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-07-17 15:24 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-15 20:48 [PATCH 0/4] ina238: Improvements and INA228 support Jonas Rebmann
2025-07-15 20:49 ` [PATCH 1/4] hwmon: ina238: Fix inconsistent whitespace Jonas Rebmann
2025-07-16 15:52   ` Guenter Roeck
2025-07-15 20:49 ` [PATCH 2/4] hwmon: ina238: Add label support for voltage inputs Jonas Rebmann
2025-07-16 15:04   ` Guenter Roeck
2025-07-17  7:30     ` Jonas Rebmann
2025-07-17 15:24       ` Guenter Roeck
2025-07-15 20:49 ` [PATCH 3/4] dt-bindings: Add INA228 to ina2xx devicetree bindings Jonas Rebmann
2025-07-16  6:30   ` Krzysztof Kozlowski
2025-07-15 20:49 ` [PATCH 4/4] hwmon: ina238: Add support for INA228 Jonas Rebmann
2025-07-16 15:50   ` Guenter Roeck

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).