Skip to content

Commit 52172ad

Browse files
Wenliang Yangroeck
authored andcommitted
hwmon: (ina226) Add support for SY24655
SY24655: Support for current and voltage detection as well as power calculation. Signed-off-by: Wenliang Yan <[email protected]> Message-ID: <[email protected]> [groeck: Changed order of compatible entries; dropped spurious extra return statement in is_visible(); fixed code problems] Signed-off-by: Guenter Roeck <[email protected]>
1 parent 0196d07 commit 52172ad

File tree

3 files changed

+116
-7
lines changed

3 files changed

+116
-7
lines changed

Documentation/hwmon/ina2xx.rst

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ Supported chips:
6363

6464
https://www.ti.com/
6565

66+
* Silergy SY24655
67+
68+
Prefix: 'sy24655'
69+
70+
Addresses: I2C 0x40 - 0x4f
71+
72+
Datasheet: Publicly available at the Silergy website
73+
74+
https://us1.silergy.com/
75+
76+
6677
Author: Lothar Felten <[email protected]>
6778

6879
Description
@@ -85,6 +96,11 @@ bus supply voltage.
8596
INA260 is a high or low side current and power monitor with integrated shunt
8697
resistor.
8798

99+
The SY24655 is a high- and low-side current shunt and power monitor with an I2C
100+
interface. The SY24655 supports both shunt drop and supply voltage, with
101+
programmable calibration value and conversion times. The SY24655 can also
102+
calculate average power for use in energy conversion.
103+
88104
The shunt value in micro-ohms can be set via platform data or device tree at
89105
compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
90106
refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings
@@ -108,8 +124,8 @@ power1_input Power(uW) measurement channel
108124
shunt_resistor Shunt resistance(uOhm) channel (not for ina260)
109125
======================= ===============================================
110126

111-
Additional sysfs entries for ina226, ina230, ina231, and ina260
112-
---------------------------------------------------------------
127+
Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655
128+
------------------------------------------------------------------------
113129

114130
======================= ====================================================
115131
curr1_lcrit Critical low current
@@ -130,6 +146,13 @@ update_interval data conversion time; affects number of samples used
130146
to average results for shunt and bus voltages.
131147
======================= ====================================================
132148

149+
Sysfs entries for sy24655 only
150+
------------------------------
151+
152+
======================= ====================================================
153+
power1_average average power from last reading to the present.
154+
======================= ====================================================
155+
133156
.. note::
134157

135158
- Configure `shunt_resistor` before configure `power1_crit`, because power

drivers/hwmon/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2189,7 +2189,7 @@ config SENSORS_INA2XX
21892189
select REGMAP_I2C
21902190
help
21912191
If you say yes here you get support for INA219, INA220, INA226,
2192-
INA230, INA231, and INA260 power monitor chips.
2192+
INA230, INA231, INA260, and SY24655 power monitor chips.
21932193

21942194
The INA2xx driver is configured for the default configuration of
21952195
the part as described in the datasheet.

drivers/hwmon/ina2xx.c

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,19 @@
5151
#define INA226_ALERT_LIMIT 0x07
5252
#define INA226_DIE_ID 0xFF
5353

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
5558

5659
/* settings - depend on use case */
5760
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
5861
#define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */
5962
#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*/
6067

6168
/* worst case is 68.10 ms (~14.6Hz, ina219) */
6269
#define INA2XX_CONVERSION_RATE 15
@@ -97,6 +104,7 @@ static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg)
97104
case INA2XX_CALIBRATION:
98105
case INA226_MASK_ENABLE:
99106
case INA226_ALERT_LIMIT:
107+
case SY24655_ACCUM_CONFIG:
100108
return true;
101109
default:
102110
return false;
@@ -127,12 +135,13 @@ static const struct regmap_config ina2xx_regmap_config = {
127135
.writeable_reg = ina2xx_writeable_reg,
128136
};
129137

130-
enum ina2xx_ids { ina219, ina226, ina260 };
138+
enum ina2xx_ids { ina219, ina226, ina260, sy24655 };
131139

132140
struct ina2xx_config {
133141
u16 config_default;
134142
bool has_alerts; /* chip supports alerts and limits */
135143
bool has_ishunt; /* chip has internal shunt resistor */
144+
bool has_power_average; /* chip has internal shunt resistor */
136145
int calibration_value;
137146
int shunt_div;
138147
int bus_voltage_shift;
@@ -149,6 +158,7 @@ struct ina2xx_data {
149158
long power_lsb_uW;
150159
struct mutex config_lock;
151160
struct regmap *regmap;
161+
struct i2c_client *client;
152162
};
153163

154164
static const struct ina2xx_config ina2xx_config[] = {
@@ -161,6 +171,7 @@ static const struct ina2xx_config ina2xx_config[] = {
161171
.power_lsb_factor = 20,
162172
.has_alerts = false,
163173
.has_ishunt = false,
174+
.has_power_average = false,
164175
},
165176
[ina226] = {
166177
.config_default = INA226_CONFIG_DEFAULT,
@@ -171,6 +182,7 @@ static const struct ina2xx_config ina2xx_config[] = {
171182
.power_lsb_factor = 25,
172183
.has_alerts = true,
173184
.has_ishunt = false,
185+
.has_power_average = false,
174186
},
175187
[ina260] = {
176188
.config_default = INA260_CONFIG_DEFAULT,
@@ -180,6 +192,18 @@ static const struct ina2xx_config ina2xx_config[] = {
180192
.power_lsb_factor = 8,
181193
.has_alerts = true,
182194
.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,
183207
},
184208
};
185209

@@ -485,13 +509,50 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
485509
return 0;
486510
}
487511

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+
488547
static int ina2xx_power_read(struct device *dev, u32 attr, long *val)
489548
{
490549
struct ina2xx_data *data = dev_get_drvdata(dev);
491550

492551
switch (attr) {
493552
case hwmon_power_input:
494553
return ina2xx_read_init(dev, INA2XX_POWER, val);
554+
case hwmon_power_average:
555+
return sy24655_average_power_read(data, SY24655_EIN, val);
495556
case hwmon_power_crit:
496557
return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK,
497558
INA2XX_POWER, val);
@@ -651,6 +712,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
651712
{
652713
const struct ina2xx_data *data = _data;
653714
bool has_alerts = data->config->has_alerts;
715+
bool has_power_average = data->config->has_power_average;
654716
enum ina2xx_ids chip = data->chip;
655717

656718
switch (type) {
@@ -702,6 +764,10 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
702764
if (has_alerts)
703765
return 0444;
704766
break;
767+
case hwmon_power_average:
768+
if (has_power_average)
769+
return 0444;
770+
break;
705771
default:
706772
break;
707773
}
@@ -734,7 +800,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = {
734800
HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM |
735801
HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM),
736802
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),
738805
NULL
739806
};
740807

@@ -839,6 +906,19 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data)
839906
INA226_ALERT_LATCH_ENABLE |
840907
FIELD_PREP(INA226_ALERT_POLARITY, active_high));
841908
}
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+
}
842922

843923
if (data->config->has_ishunt)
844924
return 0;
@@ -868,6 +948,7 @@ static int ina2xx_probe(struct i2c_client *client)
868948
return -ENOMEM;
869949

870950
/* set the device type */
951+
data->client = client;
871952
data->config = &ina2xx_config[chip];
872953
data->chip = chip;
873954
mutex_init(&data->config_lock);
@@ -906,11 +987,16 @@ static const struct i2c_device_id ina2xx_id[] = {
906987
{ "ina230", ina226 },
907988
{ "ina231", ina226 },
908989
{ "ina260", ina260 },
990+
{ "sy24655", sy24655 },
909991
{ }
910992
};
911993
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
912994

913995
static const struct of_device_id __maybe_unused ina2xx_of_match[] = {
996+
{
997+
.compatible = "silergy,sy24655",
998+
.data = (void *)sy24655
999+
},
9141000
{
9151001
.compatible = "ti,ina219",
9161002
.data = (void *)ina219
@@ -935,7 +1021,7 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = {
9351021
.compatible = "ti,ina260",
9361022
.data = (void *)ina260
9371023
},
938-
{ },
1024+
{ }
9391025
};
9401026
MODULE_DEVICE_TABLE(of, ina2xx_of_match);
9411027

0 commit comments

Comments
 (0)