[PATCH v2 3/4] iio: adc: ade9000: add support for ADE9078

From: Antoniu Miclaus

Date: Fri Jul 31 2026 - 04:32:23 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. A separate
RMS voltage channel macro variant is added that drops the swell/dip event
spec so the ADE9078 channel table can omit those events.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@xxxxxxxxxx>
---
Changes in v2:
- use a generic Kconfig title and list the supported parts.
- duplicate the RMS voltage macro instead of a shared base macro.
- drop the full-scale codes comment change and reword the commit message.

drivers/iio/adc/Kconfig | 16 ++---
drivers/iio/adc/ade9000.c | 119 ++++++++++++++++++++++++++------------
2 files changed, 90 insertions(+), 45 deletions(-)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 642c42b1fae7..daebffa93a83 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -573,20 +573,22 @@ config AD9467
called ad9467.

config ADE9000
- tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Monitoring IC Driver"
+ tristate "Analog Devices 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 following Analog Devices
+ highly accurate, multiphase energy and power quality monitoring
+ integrated circuits:
+ - ADE9000
+ - ADE9078

- 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 030bb9109ab6..fd1362a98052 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -502,6 +502,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}

+/* With swell/dip (sag) events - ADE9000 only */
#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \
.type = IIO_ALTVOLTAGE, \
.channel = num, \
@@ -517,6 +518,20 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}

+/* Without swell/dip events - parts lacking DIP_LVL/SWELL_LVL hardware */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS(num) { \
+ .type = IIO_ALTVOLTAGE, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num), \
+ .channel2 = IIO_MOD_RMS, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .scan_index = -1 \
+}
+
#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \
.type = IIO_POWER, \
.channel = num, \
@@ -598,44 +613,61 @@ 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 respective datasheets. These are the
@@ -650,6 +682,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 +1841,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