66 * Copyright (C) 2021 Nathan Rossi <nathan.rossi@digi.com>
77 */
88
9+ #include <linux/bitops.h>
910#include <linux/err.h>
1011#include <linux/hwmon.h>
1112#include <linux/i2c.h>
107108#define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */
108109#define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */
109110#define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
111+ #define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
110112
111113static const struct regmap_config ina238_regmap_config = {
112114 .max_register = INA238_REGISTERS ,
113115 .reg_bits = 8 ,
114116 .val_bits = 16 ,
115117};
116118
117- enum ina238_ids { ina238 , ina237 , sq52206 };
119+ enum ina238_ids { ina238 , ina237 , sq52206 , ina228 };
118120
119121struct ina238_config {
122+ bool has_20bit_voltage_current ; /* vshunt, vbus and current are 20-bit fields */
120123 bool has_power_highest ; /* chip detection power peak */
121124 bool has_energy ; /* chip detection energy */
122125 u8 temp_shift ; /* fixed parameters for temp calculate */
@@ -137,6 +140,7 @@ struct ina238_data {
137140
138141static const struct ina238_config ina238_config [] = {
139142 [ina238 ] = {
143+ .has_20bit_voltage_current = false,
140144 .has_energy = false,
141145 .has_power_highest = false,
142146 .temp_shift = 4 ,
@@ -146,6 +150,7 @@ static const struct ina238_config ina238_config[] = {
146150 .temp_lsb = INA238_DIE_TEMP_LSB ,
147151 },
148152 [ina237 ] = {
153+ .has_20bit_voltage_current = false,
149154 .has_energy = false,
150155 .has_power_highest = false,
151156 .temp_shift = 4 ,
@@ -155,6 +160,7 @@ static const struct ina238_config ina238_config[] = {
155160 .temp_lsb = INA238_DIE_TEMP_LSB ,
156161 },
157162 [sq52206 ] = {
163+ .has_20bit_voltage_current = false,
158164 .has_energy = true,
159165 .has_power_highest = true,
160166 .temp_shift = 0 ,
@@ -163,6 +169,16 @@ static const struct ina238_config ina238_config[] = {
163169 .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB ,
164170 .temp_lsb = SQ52206_DIE_TEMP_LSB ,
165171 },
172+ [ina228 ] = {
173+ .has_20bit_voltage_current = true,
174+ .has_energy = true,
175+ .has_power_highest = false,
176+ .temp_shift = 0 ,
177+ .power_calculate_factor = 20 ,
178+ .config_default = INA238_CONFIG_DEFAULT ,
179+ .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB ,
180+ .temp_lsb = INA228_DIE_TEMP_LSB ,
181+ },
166182};
167183
168184static int ina238_read_reg24 (const struct i2c_client * client , u8 reg , u32 * val )
@@ -199,6 +215,65 @@ static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val)
199215 return 0 ;
200216}
201217
218+ static int ina238_read_field_s20 (const struct i2c_client * client , u8 reg , s32 * val )
219+ {
220+ u32 regval ;
221+ int err ;
222+
223+ err = ina238_read_reg24 (client , reg , & regval );
224+ if (err )
225+ return err ;
226+
227+ /* bits 3-0 Reserved, always zero */
228+ regval >>= 4 ;
229+
230+ * val = sign_extend32 (regval , 19 );
231+
232+ return 0 ;
233+ }
234+
235+ static int ina228_read_shunt_voltage (struct device * dev , u32 attr , int channel ,
236+ long * val )
237+ {
238+ struct ina238_data * data = dev_get_drvdata (dev );
239+ int regval ;
240+ int err ;
241+
242+ err = ina238_read_field_s20 (data -> client , INA238_SHUNT_VOLTAGE , & regval );
243+ if (err )
244+ return err ;
245+
246+ /*
247+ * gain of 1 -> LSB / 4
248+ * This field has 16 bit on ina238. ina228 adds another 4 bits of
249+ * precision. ina238 conversion factors can still be applied when
250+ * dividing by 16.
251+ */
252+ * val = (regval * INA238_SHUNT_VOLTAGE_LSB ) * data -> gain / (1000 * 4 ) / 16 ;
253+ return 0 ;
254+ }
255+
256+ static int ina228_read_bus_voltage (struct device * dev , u32 attr , int channel ,
257+ long * val )
258+ {
259+ struct ina238_data * data = dev_get_drvdata (dev );
260+ int regval ;
261+ int err ;
262+
263+ err = ina238_read_field_s20 (data -> client , INA238_BUS_VOLTAGE , & regval );
264+ if (err )
265+ return err ;
266+
267+ /*
268+ * gain of 1 -> LSB / 4
269+ * This field has 16 bit on ina238. ina228 adds another 4 bits of
270+ * precision. ina238 conversion factors can still be applied when
271+ * dividing by 16.
272+ */
273+ * val = (regval * data -> config -> bus_voltage_lsb ) / 1000 / 16 ;
274+ return 0 ;
275+ }
276+
202277static int ina238_read_in (struct device * dev , u32 attr , int channel ,
203278 long * val )
204279{
@@ -211,6 +286,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
211286 case 0 :
212287 switch (attr ) {
213288 case hwmon_in_input :
289+ if (data -> config -> has_20bit_voltage_current )
290+ return ina228_read_shunt_voltage (dev , attr , channel , val );
214291 reg = INA238_SHUNT_VOLTAGE ;
215292 break ;
216293 case hwmon_in_max :
@@ -234,6 +311,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel,
234311 case 1 :
235312 switch (attr ) {
236313 case hwmon_in_input :
314+ if (data -> config -> has_20bit_voltage_current )
315+ return ina228_read_bus_voltage (dev , attr , channel , val );
237316 reg = INA238_BUS_VOLTAGE ;
238317 break ;
239318 case hwmon_in_max :
@@ -341,13 +420,25 @@ static int ina238_read_current(struct device *dev, u32 attr, long *val)
341420
342421 switch (attr ) {
343422 case hwmon_curr_input :
344- err = regmap_read (data -> regmap , INA238_CURRENT , & regval );
345- if (err < 0 )
346- return err ;
423+ if (data -> config -> has_20bit_voltage_current ) {
424+ err = ina238_read_field_s20 (data -> client , INA238_CURRENT , & regval );
425+ if (err )
426+ return err ;
427+ } else {
428+ err = regmap_read (data -> regmap , INA238_CURRENT , & regval );
429+ if (err < 0 )
430+ return err ;
431+ /* sign-extend */
432+ regval = (s16 )regval ;
433+ }
347434
348435 /* Signed register, fixed 1mA current lsb. result in mA */
349- * val = div_s64 ((s16 )regval * INA238_FIXED_SHUNT * data -> gain ,
436+ * val = div_s64 ((s64 )regval * INA238_FIXED_SHUNT * data -> gain ,
350437 data -> rshunt * 4 );
438+
439+ /* Account for 4 bit offset */
440+ if (data -> config -> has_20bit_voltage_current )
441+ * val /= 16 ;
351442 break ;
352443 default :
353444 return - EOPNOTSUPP ;
@@ -750,6 +841,7 @@ static int ina238_probe(struct i2c_client *client)
750841}
751842
752843static const struct i2c_device_id ina238_id [] = {
844+ { "ina228" , ina228 },
753845 { "ina237" , ina237 },
754846 { "ina238" , ina238 },
755847 { "sq52206" , sq52206 },
@@ -758,6 +850,10 @@ static const struct i2c_device_id ina238_id[] = {
758850MODULE_DEVICE_TABLE (i2c , ina238_id );
759851
760852static const struct of_device_id __maybe_unused ina238_of_match [] = {
853+ {
854+ .compatible = "ti,ina228" ,
855+ .data = (void * )ina228
856+ },
761857 {
762858 .compatible = "ti,ina237" ,
763859 .data = (void * )ina237
0 commit comments