[PATCH 3/4] iio: adc: ade9000: add support for ADE9078
From: Antoniu Miclaus
Date: Mon Jul 20 2026 - 07:41:56 EST
The ADE9078 is a polyphase energy metering device that is register
compatible with the ADE9000. The main differences relevant to the driver
are the absence of the on-chip dip/swell detection and slightly different
full-scale ADC codes.
Add a dedicated channel table that omits the swell/dip voltage events and
a matching chip_info describing the ADE9078 full-scale codes. The RMS
voltage channel macro is split into a shared base and two variants so the
event-less table can reuse the common definition.
Signed-off-by: Antoniu Miclaus <antoniu.miclaus@xxxxxxxxxx>
---
drivers/iio/adc/Kconfig | 14 ++---
drivers/iio/adc/ade9000.c | 121 +++++++++++++++++++++++++-------------
2 files changed, 86 insertions(+), 49 deletions(-)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index d1b198cb8a80..33f2c281b1aa 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -573,20 +573,20 @@ config AD9467
called ad9467.
config ADE9000
- tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Monitoring IC Driver"
+ tristate "Analog Devices ADE9000/ADE9078 Multiphase Energy, and Power Quality Monitoring IC Driver"
depends on SPI
select REGMAP_SPI
select IIO_BUFFER
select IIO_KFIFO_BUF
help
- Say yes here to build support for the Analog Devices ADE9000,
- a highly accurate, multiphase energy and power quality monitoring
- integrated circuit.
+ Say yes here to build support for the Analog Devices ADE9000 and
+ ADE9078, highly accurate, multiphase energy and power quality
+ monitoring integrated circuits.
- The device features high-precision analog-to-digital converters
+ The devices feature high-precision analog-to-digital converters
and digital signal processing to compute RMS values, power factor,
- frequency, and harmonic analysis. It supports SPI communication
- and provides buffered data output through the IIO framework.
+ frequency, and harmonic analysis. They support SPI communication
+ and provide buffered data output through the IIO framework.
To compile this driver as a module, choose M here: the module will
be called ade9000.
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index 38a5c7e043b3..0de55b7ad1ea 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -502,7 +502,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}
-#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num) \
.type = IIO_ALTVOLTAGE, \
.channel = num, \
.address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num), \
@@ -512,9 +512,18 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .scan_index = -1
+
+/* With swell/dip (sag) events - ADE9000 only */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \
+ ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num), \
.event_spec = ade9000_rms_voltage_events, \
.num_event_specs = ARRAY_SIZE(ade9000_rms_voltage_events), \
- .scan_index = -1 \
+}
+
+/* Without swell/dip events - parts lacking DIP_LVL/SWELL_LVL hardware */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS(num) { \
+ ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num), \
}
#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \
@@ -598,48 +607,65 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}
-static const struct iio_chan_spec ade9000_channels[] = {
- /* Phase A channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR),
- /* Phase B channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR),
- /* Phase C channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR),
-};
+/*
+ * Declare a full channel array. @altvoltage_rms picks the RMS voltage channel
+ * variant so parts without dip/swell hardware (e.g. ADE9078) omit those events.
+ */
+#define ADE9000_DECLARE_CHANNELS(_name, altvoltage_rms) \
+ static const struct iio_chan_spec _name[] = { \
+ /* Phase A channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR), \
+ altvoltage_rms(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR), \
+ /* Phase B channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR), \
+ altvoltage_rms(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR), \
+ /* Phase C channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR), \
+ altvoltage_rms(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR), \
+ }
+
+ADE9000_DECLARE_CHANNELS(ade9000_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL);
+ADE9000_DECLARE_CHANNELS(ade9078_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS);
/*
- * Full-scale codes referred from the datasheet. These are the digital codes
- * produced when the ADC inputs are at full scale.
+ * Full-scale codes referred from the respective datasheets. These are the
+ * digital codes produced when the ADC inputs are at full scale.
*/
static const struct ade9000_chip_info ade9000_chip_info = {
.name = "ade9000",
@@ -650,6 +676,15 @@ static const struct ade9000_chip_info ade9000_chip_info = {
.pcf_full_scale_codes = 74770000,
};
+static const struct ade9000_chip_info ade9078_chip_info = {
+ .name = "ade9078",
+ .channels = ade9078_channels,
+ .num_channels = ARRAY_SIZE(ade9078_channels),
+ .rms_full_scale_codes = 52866837,
+ .watt_full_scale_codes = 20823646,
+ .pcf_full_scale_codes = 74680000,
+};
+
static const struct reg_sequence ade9000_initialization_sequence[] = {
{ ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN },
{ ADE9000_REG_CONFIG0, ADE9000_CONFIG0 },
@@ -1800,12 +1835,14 @@ static int ade9000_probe(struct spi_device *spi)
static const struct spi_device_id ade9000_id[] = {
{ .name = "ade9000", .driver_data = (kernel_ulong_t)&ade9000_chip_info },
+ { .name = "ade9078", .driver_data = (kernel_ulong_t)&ade9078_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ade9000_id);
static const struct of_device_id ade9000_of_match[] = {
{ .compatible = "adi,ade9000", .data = &ade9000_chip_info },
+ { .compatible = "adi,ade9078", .data = &ade9078_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ade9000_of_match);
--
2.43.0