51
51
#define INA226_ALERT_LIMIT 0x07
52
52
#define INA226_DIE_ID 0xFF
53
53
54
- #define INA2XX_MAX_REGISTERS 8
54
+ /* SY24655 register definitions */
55
+ #define SY24655_EIN 0x0A
56
+ #define SY24655_ACCUM_CONFIG 0x0D
57
+ #define INA2XX_MAX_REGISTERS 0x0D
55
58
56
59
/* settings - depend on use case */
57
60
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
58
61
#define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */
59
62
#define INA260_CONFIG_DEFAULT 0x6527 /* averages=16 */
63
+ #define SY24655_CONFIG_DEFAULT 0x4527 /* averages=16 */
64
+
65
+ /* (only for sy24655) */
66
+ #define SY24655_ACCUM_CONFIG_DEFAULT 0x044C /* continuous mode, clear after read*/
60
67
61
68
/* worst case is 68.10 ms (~14.6Hz, ina219) */
62
69
#define INA2XX_CONVERSION_RATE 15
@@ -97,6 +104,7 @@ static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg)
97
104
case INA2XX_CALIBRATION :
98
105
case INA226_MASK_ENABLE :
99
106
case INA226_ALERT_LIMIT :
107
+ case SY24655_ACCUM_CONFIG :
100
108
return true;
101
109
default :
102
110
return false;
@@ -127,12 +135,13 @@ static const struct regmap_config ina2xx_regmap_config = {
127
135
.writeable_reg = ina2xx_writeable_reg ,
128
136
};
129
137
130
- enum ina2xx_ids { ina219 , ina226 , ina260 };
138
+ enum ina2xx_ids { ina219 , ina226 , ina260 , sy24655 };
131
139
132
140
struct ina2xx_config {
133
141
u16 config_default ;
134
142
bool has_alerts ; /* chip supports alerts and limits */
135
143
bool has_ishunt ; /* chip has internal shunt resistor */
144
+ bool has_power_average ; /* chip has internal shunt resistor */
136
145
int calibration_value ;
137
146
int shunt_div ;
138
147
int bus_voltage_shift ;
@@ -149,6 +158,7 @@ struct ina2xx_data {
149
158
long power_lsb_uW ;
150
159
struct mutex config_lock ;
151
160
struct regmap * regmap ;
161
+ struct i2c_client * client ;
152
162
};
153
163
154
164
static const struct ina2xx_config ina2xx_config [] = {
@@ -161,6 +171,7 @@ static const struct ina2xx_config ina2xx_config[] = {
161
171
.power_lsb_factor = 20 ,
162
172
.has_alerts = false,
163
173
.has_ishunt = false,
174
+ .has_power_average = false,
164
175
},
165
176
[ina226 ] = {
166
177
.config_default = INA226_CONFIG_DEFAULT ,
@@ -171,6 +182,7 @@ static const struct ina2xx_config ina2xx_config[] = {
171
182
.power_lsb_factor = 25 ,
172
183
.has_alerts = true,
173
184
.has_ishunt = false,
185
+ .has_power_average = false,
174
186
},
175
187
[ina260 ] = {
176
188
.config_default = INA260_CONFIG_DEFAULT ,
@@ -180,6 +192,18 @@ static const struct ina2xx_config ina2xx_config[] = {
180
192
.power_lsb_factor = 8 ,
181
193
.has_alerts = true,
182
194
.has_ishunt = true,
195
+ .has_power_average = false,
196
+ },
197
+ [sy24655 ] = {
198
+ .config_default = SY24655_CONFIG_DEFAULT ,
199
+ .calibration_value = 4096 ,
200
+ .shunt_div = 400 ,
201
+ .bus_voltage_shift = 0 ,
202
+ .bus_voltage_lsb = 1250 ,
203
+ .power_lsb_factor = 25 ,
204
+ .has_alerts = true,
205
+ .has_ishunt = false,
206
+ .has_power_average = true,
183
207
},
184
208
};
185
209
@@ -485,13 +509,50 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
485
509
return 0 ;
486
510
}
487
511
512
+ /*
513
+ * Configuring the READ_EIN (bit 10) of the ACCUM_CONFIG register to 1
514
+ * can clear accumulator and sample_count after reading the EIN register.
515
+ * This way, the average power between the last read and the current
516
+ * read can be obtained. By combining with accurate time data from
517
+ * outside, the energy consumption during that period can be calculated.
518
+ */
519
+ static int sy24655_average_power_read (struct ina2xx_data * data , u8 reg , long * val )
520
+ {
521
+ u8 template [6 ];
522
+ int ret ;
523
+ long accumulator_24 , sample_count ;
524
+
525
+ /* 48-bit register read */
526
+ ret = i2c_smbus_read_i2c_block_data (data -> client , reg , 6 , template );
527
+ if (ret < 0 )
528
+ return ret ;
529
+ if (ret != 6 )
530
+ return - EIO ;
531
+ accumulator_24 = ((template [3 ] << 16 ) |
532
+ (template [4 ] << 8 ) |
533
+ template [5 ]);
534
+ sample_count = ((template [0 ] << 16 ) |
535
+ (template [1 ] << 8 ) |
536
+ template [2 ]);
537
+ if (sample_count <= 0 ) {
538
+ * val = 0 ;
539
+ return 0 ;
540
+ }
541
+
542
+ * val = DIV_ROUND_CLOSEST (accumulator_24 , sample_count ) * data -> power_lsb_uW ;
543
+
544
+ return 0 ;
545
+ }
546
+
488
547
static int ina2xx_power_read (struct device * dev , u32 attr , long * val )
489
548
{
490
549
struct ina2xx_data * data = dev_get_drvdata (dev );
491
550
492
551
switch (attr ) {
493
552
case hwmon_power_input :
494
553
return ina2xx_read_init (dev , INA2XX_POWER , val );
554
+ case hwmon_power_average :
555
+ return sy24655_average_power_read (data , SY24655_EIN , val );
495
556
case hwmon_power_crit :
496
557
return ina226_alert_limit_read (data , INA226_POWER_OVER_LIMIT_MASK ,
497
558
INA2XX_POWER , val );
@@ -651,6 +712,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
651
712
{
652
713
const struct ina2xx_data * data = _data ;
653
714
bool has_alerts = data -> config -> has_alerts ;
715
+ bool has_power_average = data -> config -> has_power_average ;
654
716
enum ina2xx_ids chip = data -> chip ;
655
717
656
718
switch (type ) {
@@ -702,6 +764,10 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
702
764
if (has_alerts )
703
765
return 0444 ;
704
766
break ;
767
+ case hwmon_power_average :
768
+ if (has_power_average )
769
+ return 0444 ;
770
+ break ;
705
771
default :
706
772
break ;
707
773
}
@@ -734,7 +800,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = {
734
800
HWMON_CHANNEL_INFO (curr , HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM |
735
801
HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM ),
736
802
HWMON_CHANNEL_INFO (power ,
737
- HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM ),
803
+ HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM |
804
+ HWMON_P_AVERAGE ),
738
805
NULL
739
806
};
740
807
@@ -839,6 +906,19 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data)
839
906
INA226_ALERT_LATCH_ENABLE |
840
907
FIELD_PREP (INA226_ALERT_POLARITY , active_high ));
841
908
}
909
+ if (data -> config -> has_power_average ) {
910
+ if (data -> chip == sy24655 ) {
911
+ /*
912
+ * Initialize the power accumulation method to continuous
913
+ * mode and clear the EIN register after each read of the
914
+ * EIN register
915
+ */
916
+ ret = regmap_write (regmap , SY24655_ACCUM_CONFIG ,
917
+ SY24655_ACCUM_CONFIG_DEFAULT );
918
+ if (ret < 0 )
919
+ return ret ;
920
+ }
921
+ }
842
922
843
923
if (data -> config -> has_ishunt )
844
924
return 0 ;
@@ -868,6 +948,7 @@ static int ina2xx_probe(struct i2c_client *client)
868
948
return - ENOMEM ;
869
949
870
950
/* set the device type */
951
+ data -> client = client ;
871
952
data -> config = & ina2xx_config [chip ];
872
953
data -> chip = chip ;
873
954
mutex_init (& data -> config_lock );
@@ -906,11 +987,16 @@ static const struct i2c_device_id ina2xx_id[] = {
906
987
{ "ina230" , ina226 },
907
988
{ "ina231" , ina226 },
908
989
{ "ina260" , ina260 },
990
+ { "sy24655" , sy24655 },
909
991
{ }
910
992
};
911
993
MODULE_DEVICE_TABLE (i2c , ina2xx_id );
912
994
913
995
static const struct of_device_id __maybe_unused ina2xx_of_match [] = {
996
+ {
997
+ .compatible = "silergy,sy24655" ,
998
+ .data = (void * )sy24655
999
+ },
914
1000
{
915
1001
.compatible = "ti,ina219" ,
916
1002
.data = (void * )ina219
@@ -935,7 +1021,7 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = {
935
1021
.compatible = "ti,ina260" ,
936
1022
.data = (void * )ina260
937
1023
},
938
- { },
1024
+ { }
939
1025
};
940
1026
MODULE_DEVICE_TABLE (of , ina2xx_of_match );
941
1027
0 commit comments