2121#define INA238_CONFIG 0x0
2222#define INA238_ADC_CONFIG 0x1
2323#define INA238_SHUNT_CALIBRATION 0x2
24+ #define SQ52206_SHUNT_TEMPCO 0x3
2425#define INA238_SHUNT_VOLTAGE 0x4
2526#define INA238_BUS_VOLTAGE 0x5
2627#define INA238_DIE_TEMP 0x6
2728#define INA238_CURRENT 0x7
2829#define INA238_POWER 0x8
30+ #define SQ52206_ENERGY 0x9
31+ #define SQ52206_CHARGE 0xa
2932#define INA238_DIAG_ALERT 0xb
3033#define INA238_SHUNT_OVER_VOLTAGE 0xc
3134#define INA238_SHUNT_UNDER_VOLTAGE 0xd
3235#define INA238_BUS_OVER_VOLTAGE 0xe
3336#define INA238_BUS_UNDER_VOLTAGE 0xf
3437#define INA238_TEMP_LIMIT 0x10
3538#define INA238_POWER_LIMIT 0x11
39+ #define SQ52206_POWER_PEAK 0x20
3640#define INA238_DEVICE_ID 0x3f /* not available on INA237 */
3741
3842#define INA238_CONFIG_ADCRANGE BIT(4)
43+ #define SQ52206_CONFIG_ADCRANGE_HIGH BIT(4)
44+ #define SQ52206_CONFIG_ADCRANGE_LOW BIT(3)
3945
4046#define INA238_DIAG_ALERT_TMPOL BIT(7)
4147#define INA238_DIAG_ALERT_SHNTOL BIT(6)
4450#define INA238_DIAG_ALERT_BUSUL BIT(3)
4551#define INA238_DIAG_ALERT_POL BIT(2)
4652
47- #define INA238_REGISTERS 0x11
53+ #define INA238_REGISTERS 0x20
4854
4955#define INA238_RSHUNT_DEFAULT 10000 /* uOhm */
5056
5157/* Default configuration of device on reset. */
5258#define INA238_CONFIG_DEFAULT 0
59+ #define SQ52206_CONFIG_DEFAULT 0x0005
5360/* 16 sample averaging, 1052us conversion time, continuous mode */
5461#define INA238_ADC_CONFIG_DEFAULT 0xfb6a
5562/* Configure alerts to be based on averaged value (SLOWALERT) */
8794 * shunt = 0x4000 / (819.2 * 10^6) / 0.001 = 20000 uOhms (with 1mA/lsb)
8895 *
8996 * Current (mA) = register value * 20000 / rshunt / 4 * gain
90- * Power (W) = 0.2 * register value * 20000 / rshunt / 4 * gain
97+ * Power (mW) = 0.2 * register value * 20000 / rshunt / 4 * gain
98+ * (Specific for SQ52206)
99+ * Power (mW) = 0.24 * register value * 20000 / rshunt / 4 * gain
100+ * Energy (mJ) = 16 * 0.24 * register value * 20000 / rshunt / 4 * gain
91101 */
92102#define INA238_CALIBRATION_VALUE 16384
93103#define INA238_FIXED_SHUNT 20000
94104
95105#define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */
96106#define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */
97- #define INA238_DIE_TEMP_LSB 125 /* 125 mC/lsb */
107+ #define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */
108+ #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */
109+ #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
98110
99111static const struct regmap_config ina238_regmap_config = {
100112 .max_register = INA238_REGISTERS ,
101113 .reg_bits = 8 ,
102114 .val_bits = 16 ,
103115};
104116
105- enum ina238_ids { ina238 , ina237 };
117+ enum ina238_ids { ina238 , ina237 , sq52206 };
106118
107119struct ina238_config {
108120 bool has_power_highest ; /* chip detection power peak */
@@ -142,6 +154,15 @@ static const struct ina238_config ina238_config[] = {
142154 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB ,
143155 .temp_lsb = INA238_DIE_TEMP_LSB ,
144156 },
157+ [sq52206 ] = {
158+ .has_energy = true,
159+ .has_power_highest = true,
160+ .temp_shift = 0 ,
161+ .power_calculate_factor = 24 ,
162+ .config_default = SQ52206_CONFIG_DEFAULT ,
163+ .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB ,
164+ .temp_lsb = SQ52206_DIE_TEMP_LSB ,
165+ },
145166};
146167
147168static int ina238_read_reg24 (const struct i2c_client * client , u8 reg , u32 * val )
@@ -160,6 +181,24 @@ static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
160181 return 0 ;
161182}
162183
184+ static int ina238_read_reg40 (const struct i2c_client * client , u8 reg , u64 * val )
185+ {
186+ u8 data [5 ];
187+ u32 low ;
188+ int err ;
189+
190+ /* 40-bit register read */
191+ err = i2c_smbus_read_i2c_block_data (client , reg , 5 , data );
192+ if (err < 0 )
193+ return err ;
194+ if (err != 5 )
195+ return - EIO ;
196+ low = (data [1 ] << 24 ) | (data [2 ] << 16 ) | (data [3 ] << 8 ) | data [4 ];
197+ * val = ((long long )data [0 ] << 32 ) | low ;
198+
199+ return 0 ;
200+ }
201+
163202static int ina238_read_in (struct device * dev , u32 attr , int channel ,
164203 long * val )
165204{
@@ -330,6 +369,17 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val)
330369 if (err )
331370 return err ;
332371
372+ /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
373+ power = div_u64 (regval * 1000ULL * INA238_FIXED_SHUNT *
374+ data -> gain , 20 * data -> rshunt );
375+ /* Clamp value to maximum value of long */
376+ * val = clamp_val (power , 0 , LONG_MAX );
377+ break ;
378+ case hwmon_power_input_highest :
379+ err = ina238_read_reg24 (data -> client , SQ52206_POWER_PEAK , & regval );
380+ if (err )
381+ return err ;
382+
333383 /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
334384 power = div_u64 (regval * 1000ULL * INA238_FIXED_SHUNT *
335385 data -> gain , 20 * data -> rshunt );
@@ -437,6 +487,25 @@ static int ina238_write_temp(struct device *dev, u32 attr, long val)
437487 return regmap_write (data -> regmap , INA238_TEMP_LIMIT , regval );
438488}
439489
490+ static ssize_t energy1_input_show (struct device * dev ,
491+ struct device_attribute * da , char * buf )
492+ {
493+ struct ina238_data * data = dev_get_drvdata (dev );
494+ int ret ;
495+ u64 regval ;
496+ u64 energy ;
497+
498+ ret = ina238_read_reg40 (data -> client , SQ52206_ENERGY , & regval );
499+ if (ret )
500+ return ret ;
501+
502+ /* result in mJ */
503+ energy = div_u64 (regval * INA238_FIXED_SHUNT * data -> gain * 16 *
504+ data -> config -> power_calculate_factor , 4 * 100 * data -> rshunt );
505+
506+ return sysfs_emit (buf , "%llu\n" , energy );
507+ }
508+
440509static int ina238_read (struct device * dev , enum hwmon_sensor_types type ,
441510 u32 attr , int channel , long * val )
442511{
@@ -456,7 +525,7 @@ static int ina238_read(struct device *dev, enum hwmon_sensor_types type,
456525}
457526
458527static int ina238_write (struct device * dev , enum hwmon_sensor_types type ,
459- u32 attr , int channel , long val )
528+ u32 attr , int channel , long val )
460529{
461530 struct ina238_data * data = dev_get_drvdata (dev );
462531 int err ;
@@ -486,6 +555,9 @@ static umode_t ina238_is_visible(const void *drvdata,
486555 enum hwmon_sensor_types type ,
487556 u32 attr , int channel )
488557{
558+ const struct ina238_data * data = drvdata ;
559+ bool has_power_highest = data -> config -> has_power_highest ;
560+
489561 switch (type ) {
490562 case hwmon_in :
491563 switch (attr ) {
@@ -513,6 +585,10 @@ static umode_t ina238_is_visible(const void *drvdata,
513585 return 0444 ;
514586 case hwmon_power_max :
515587 return 0644 ;
588+ case hwmon_power_input_highest :
589+ if (has_power_highest )
590+ return 0444 ;
591+ return 0 ;
516592 default :
517593 return 0 ;
518594 }
@@ -546,7 +622,8 @@ static const struct hwmon_channel_info * const ina238_info[] = {
546622 HWMON_C_INPUT ),
547623 HWMON_CHANNEL_INFO (power ,
548624 /* 0: power */
549- HWMON_P_INPUT | HWMON_P_MAX | HWMON_P_MAX_ALARM ),
625+ HWMON_P_INPUT | HWMON_P_MAX |
626+ HWMON_P_MAX_ALARM | HWMON_P_INPUT_HIGHEST ),
550627 HWMON_CHANNEL_INFO (temp ,
551628 /* 0: die temperature */
552629 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_ALARM ),
@@ -564,6 +641,15 @@ static const struct hwmon_chip_info ina238_chip_info = {
564641 .info = ina238_info ,
565642};
566643
644+ /* energy attributes are 5 bytes wide so we need u64 */
645+ static DEVICE_ATTR_RO (energy1_input );
646+
647+ static struct attribute * ina238_attrs [] = {
648+ & dev_attr_energy1_input .attr ,
649+ NULL ,
650+ };
651+ ATTRIBUTE_GROUPS (ina238 );
652+
567653static int ina238_probe (struct i2c_client * client )
568654{
569655 struct ina2xx_platform_data * pdata = dev_get_platdata (& client -> dev );
@@ -604,15 +690,21 @@ static int ina238_probe(struct i2c_client *client)
604690 /* load shunt gain value */
605691 if (device_property_read_u32 (dev , "ti,shunt-gain" , & data -> gain ) < 0 )
606692 data -> gain = 4 ; /* Default of ADCRANGE = 0 */
607- if (data -> gain != 1 && data -> gain != 4 ) {
693+ if (data -> gain != 1 && data -> gain != 2 && data -> gain != 4 ) {
608694 dev_err (dev , "invalid shunt gain value %u\n" , data -> gain );
609695 return - EINVAL ;
610696 }
611697
612698 /* Setup CONFIG register */
613699 config = data -> config -> config_default ;
614- if (data -> gain == 1 )
700+ if (chip == sq52206 ) {
701+ if (data -> gain == 1 )
702+ config |= SQ52206_CONFIG_ADCRANGE_HIGH ; /* ADCRANGE = 10/11 is /1 */
703+ else if (data -> gain == 2 )
704+ config |= SQ52206_CONFIG_ADCRANGE_LOW ; /* ADCRANGE = 01 is /2 */
705+ } else if (data -> gain == 1 ) {
615706 config |= INA238_CONFIG_ADCRANGE ; /* ADCRANGE = 1 is /1 */
707+ }
616708 ret = regmap_write (data -> regmap , INA238_CONFIG , config );
617709 if (ret < 0 ) {
618710 dev_err (dev , "error configuring the device: %d\n" , ret );
@@ -645,7 +737,8 @@ static int ina238_probe(struct i2c_client *client)
645737
646738 hwmon_dev = devm_hwmon_device_register_with_info (dev , client -> name , data ,
647739 & ina238_chip_info ,
648- NULL );
740+ data -> config -> has_energy ?
741+ ina238_groups : NULL );
649742 if (IS_ERR (hwmon_dev ))
650743 return PTR_ERR (hwmon_dev );
651744
@@ -658,6 +751,7 @@ static int ina238_probe(struct i2c_client *client)
658751static const struct i2c_device_id ina238_id [] = {
659752 { "ina237" , ina237 },
660753 { "ina238" , ina238 },
754+ { "sq52206" , sq52206 },
661755 { }
662756};
663757MODULE_DEVICE_TABLE (i2c , ina238_id );
@@ -671,6 +765,10 @@ static const struct of_device_id __maybe_unused ina238_of_match[] = {
671765 .compatible = "ti,ina238" ,
672766 .data = (void * )ina238
673767 },
768+ {
769+ .compatible = "silergy,sq52206" ,
770+ .data = (void * )sq52206
771+ },
674772 { }
675773};
676774MODULE_DEVICE_TABLE (of , ina238_of_match );
0 commit comments