summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/88pm886-gpadc.c393
-rw-r--r--drivers/iio/adc/Kconfig56
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/ab8500-gpadc.c1
-rw-r--r--drivers/iio/adc/ad4130.c3
-rw-r--r--drivers/iio/adc/ad7124.c577
-rw-r--r--drivers/iio/adc/ad7173.c304
-rw-r--r--drivers/iio/adc/ad7380.c1
-rw-r--r--drivers/iio/adc/ad7476.c461
-rw-r--r--drivers/iio/adc/ad7768-1.c37
-rw-r--r--drivers/iio/adc/ad7779.c192
-rw-r--r--drivers/iio/adc/ad7949.c4
-rw-r--r--drivers/iio/adc/ad799x.c30
-rw-r--r--drivers/iio/adc/ade9000.c1799
-rw-r--r--drivers/iio/adc/adi-axi-adc.c1
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c13
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c4
-rw-r--r--drivers/iio/adc/cpcap-adc.c6
-rw-r--r--drivers/iio/adc/da9150-gpadc.c5
-rw-r--r--drivers/iio/adc/dln2-adc.c9
-rw-r--r--drivers/iio/adc/exynos_adc.c286
-rw-r--r--drivers/iio/adc/hx711.c2
-rw-r--r--drivers/iio/adc/imx7d_adc.c4
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c6
-rw-r--r--drivers/iio/adc/imx93_adc.c26
-rw-r--r--drivers/iio/adc/intel_dc_ti_adc.c328
-rw-r--r--drivers/iio/adc/mcp3564.c2
-rw-r--r--drivers/iio/adc/meson_saradc.c2
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c3
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c4
-rw-r--r--drivers/iio/adc/pac1921.c3
-rw-r--r--drivers/iio/adc/pac1934.c31
-rw-r--r--drivers/iio/adc/palmas_gpadc.c4
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c8
-rw-r--r--drivers/iio/adc/rn5t618-adc.c4
-rw-r--r--drivers/iio/adc/rockchip_saradc.c6
-rw-r--r--drivers/iio/adc/rohm-bd79112.c556
-rw-r--r--drivers/iio/adc/rzg2l_adc.c35
-rw-r--r--drivers/iio/adc/spear_adc.c12
-rw-r--r--drivers/iio/adc/stm32-adc-core.c1
-rw-r--r--drivers/iio/adc/stm32-adc.c7
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c4
-rw-r--r--drivers/iio/adc/stmpe-adc.c4
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c3
-rw-r--r--drivers/iio/adc/ti-adc081c.c40
-rw-r--r--drivers/iio/adc/ti-adc084s021.c4
-rw-r--r--drivers/iio/adc/ti-adc12138.c30
-rw-r--r--drivers/iio/adc/ti-adc128s052.c132
-rw-r--r--drivers/iio/adc/ti-ads1015.c6
-rw-r--r--drivers/iio/adc/ti-ads1100.c1
-rw-r--r--drivers/iio/adc/ti-ads1119.c11
-rw-r--r--drivers/iio/adc/ti-ads131e08.c8
-rw-r--r--drivers/iio/adc/ti-ads7924.c9
-rw-r--r--drivers/iio/adc/ti-tsc2046.c6
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c5
-rw-r--r--drivers/iio/adc/twl4030-madc.c4
-rw-r--r--drivers/iio/adc/vf610_adc.c2
-rw-r--r--drivers/iio/adc/viperboard_adc.c4
-rw-r--r--drivers/iio/adc/xilinx-ams.c47
59 files changed, 4531 insertions, 1019 deletions
diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c
new file mode 100644
index 000000000000..cffe35136685
--- /dev/null
+++ b/drivers/iio/adc/88pm886-gpadc.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025, Duje Mihanović <duje@dujemihanovic.xyz>
+ */
+
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+#include <linux/mfd/88pm886.h>
+
+struct pm886_gpadc {
+ struct regmap *map;
+};
+
+enum pm886_gpadc_channel {
+ VSC_CHAN,
+ VCHG_PWR_CHAN,
+ VCF_OUT_CHAN,
+ VBAT_CHAN,
+ VBAT_SLP_CHAN,
+ VBUS_CHAN,
+
+ GPADC0_CHAN,
+ GPADC1_CHAN,
+ GPADC2_CHAN,
+ GPADC3_CHAN,
+
+ GND_DET1_CHAN,
+ GND_DET2_CHAN,
+ MIC_DET_CHAN,
+
+ TINT_CHAN,
+};
+
+static const int pm886_gpadc_regs[] = {
+ [VSC_CHAN] = PM886_REG_GPADC_VSC,
+ [VCHG_PWR_CHAN] = PM886_REG_GPADC_VCHG_PWR,
+ [VCF_OUT_CHAN] = PM886_REG_GPADC_VCF_OUT,
+ [VBAT_CHAN] = PM886_REG_GPADC_VBAT,
+ [VBAT_SLP_CHAN] = PM886_REG_GPADC_VBAT_SLP,
+ [VBUS_CHAN] = PM886_REG_GPADC_VBUS,
+
+ [GPADC0_CHAN] = PM886_REG_GPADC_GPADC0,
+ [GPADC1_CHAN] = PM886_REG_GPADC_GPADC1,
+ [GPADC2_CHAN] = PM886_REG_GPADC_GPADC2,
+ [GPADC3_CHAN] = PM886_REG_GPADC_GPADC3,
+
+ [GND_DET1_CHAN] = PM886_REG_GPADC_GND_DET1,
+ [GND_DET2_CHAN] = PM886_REG_GPADC_GND_DET2,
+ [MIC_DET_CHAN] = PM886_REG_GPADC_MIC_DET,
+
+ [TINT_CHAN] = PM886_REG_GPADC_TINT,
+};
+
+#define ADC_CHANNEL_VOLTAGE(index, lsb, name) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .address = lsb, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = name, \
+}
+
+#define ADC_CHANNEL_RESISTANCE(index, lsb, name) \
+{ \
+ .type = IIO_RESISTANCE, \
+ .indexed = 1, \
+ .channel = index, \
+ .address = lsb, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .datasheet_name = name, \
+}
+
+#define ADC_CHANNEL_TEMPERATURE(index, lsb, name) \
+{ \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = index, \
+ .address = lsb, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .datasheet_name = name, \
+}
+
+static const struct iio_chan_spec pm886_gpadc_channels[] = {
+ ADC_CHANNEL_VOLTAGE(VSC_CHAN, 1367, "vsc"),
+ ADC_CHANNEL_VOLTAGE(VCHG_PWR_CHAN, 1709, "vchg_pwr"),
+ ADC_CHANNEL_VOLTAGE(VCF_OUT_CHAN, 1367, "vcf_out"),
+ ADC_CHANNEL_VOLTAGE(VBAT_CHAN, 1367, "vbat"),
+ ADC_CHANNEL_VOLTAGE(VBAT_SLP_CHAN, 1367, "vbat_slp"),
+ ADC_CHANNEL_VOLTAGE(VBUS_CHAN, 1709, "vbus"),
+
+ ADC_CHANNEL_RESISTANCE(GPADC0_CHAN, 342, "gpadc0"),
+ ADC_CHANNEL_RESISTANCE(GPADC1_CHAN, 342, "gpadc1"),
+ ADC_CHANNEL_RESISTANCE(GPADC2_CHAN, 342, "gpadc2"),
+ ADC_CHANNEL_RESISTANCE(GPADC3_CHAN, 342, "gpadc3"),
+
+ ADC_CHANNEL_VOLTAGE(GND_DET1_CHAN, 342, "gnddet1"),
+ ADC_CHANNEL_VOLTAGE(GND_DET2_CHAN, 342, "gnddet2"),
+ ADC_CHANNEL_VOLTAGE(MIC_DET_CHAN, 1367, "mic_det"),
+
+ ADC_CHANNEL_TEMPERATURE(TINT_CHAN, 104, "tint"),
+};
+
+static const struct regmap_config pm886_gpadc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PM886_GPADC_MAX_REGISTER,
+};
+
+static int gpadc_get_raw(struct iio_dev *iio, enum pm886_gpadc_channel chan)
+{
+ struct pm886_gpadc *gpadc = iio_priv(iio);
+ __be16 buf;
+ int ret;
+
+ ret = regmap_bulk_read(gpadc->map, pm886_gpadc_regs[chan], &buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ return be16_to_cpu(buf) >> 4;
+}
+
+static int
+gpadc_set_bias(struct pm886_gpadc *gpadc, enum pm886_gpadc_channel chan, bool on)
+{
+ unsigned int gpadc_num = chan - GPADC0_CHAN;
+ unsigned int bits = BIT(gpadc_num + 4) | BIT(gpadc_num);
+
+ return regmap_assign_bits(gpadc->map, PM886_REG_GPADC_CONFIG(0x14), bits, on);
+}
+
+static int
+gpadc_find_bias_current(struct iio_dev *iio, struct iio_chan_spec const *chan,
+ unsigned int *raw_uV, unsigned int *raw_uA)
+{
+ struct pm886_gpadc *gpadc = iio_priv(iio);
+ unsigned int gpadc_num = chan->channel - GPADC0_CHAN;
+ unsigned int reg = PM886_REG_GPADC_CONFIG(0xb + gpadc_num);
+ unsigned long lsb = chan->address;
+ int ret;
+
+ for (unsigned int i = 0; i < PM886_GPADC_BIAS_LEVELS; i++) {
+ ret = regmap_update_bits(gpadc->map, reg, GENMASK(3, 0), i);
+ if (ret)
+ return ret;
+
+ /* Wait for the new bias level to apply. */
+ fsleep(5 * USEC_PER_MSEC);
+
+ *raw_uA = PM886_GPADC_INDEX_TO_BIAS_uA(i);
+ *raw_uV = gpadc_get_raw(iio, chan->channel) * lsb;
+
+ /*
+ * Vendor kernel errors out above 1.25 V, but testing shows
+ * that the resistance of the battery detection channel (GPADC2
+ * on coreprimevelte) reaches about 1.4 MΩ when the battery is
+ * removed, which can't be measured with such a low upper
+ * limit. Therefore, to be able to detect the battery without
+ * ugly externs as used in the vendor fuel gauge driver,
+ * increase this limit a bit.
+ */
+ if (WARN_ON(*raw_uV > 1500 * (MICRO / MILLI)))
+ return -EIO;
+
+ /*
+ * Vendor kernel errors out under 300 mV, but for the same
+ * reason as above (except the channel hovers around 3.5 kΩ
+ * with battery present) reduce this limit.
+ */
+ if (*raw_uV < 200 * (MICRO / MILLI)) {
+ dev_dbg(&iio->dev, "bad bias for chan %d: %d uA @ %d uV\n",
+ chan->channel, *raw_uA, *raw_uV);
+ continue;
+ }
+
+ dev_dbg(&iio->dev, "good bias for chan %d: %d uA @ %d uV\n",
+ chan->channel, *raw_uA, *raw_uV);
+ return 0;
+ }
+
+ dev_err(&iio->dev, "failed to find good bias for chan %d\n", chan->channel);
+ return -EINVAL;
+}
+
+static int
+gpadc_get_resistance_ohm(struct iio_dev *iio, struct iio_chan_spec const *chan)
+{
+ struct pm886_gpadc *gpadc = iio_priv(iio);
+ unsigned int raw_uV, raw_uA;
+ int ret;
+
+ ret = gpadc_set_bias(gpadc, chan->channel, true);
+ if (ret)
+ goto out;
+
+ ret = gpadc_find_bias_current(iio, chan, &raw_uV, &raw_uA);
+ if (ret)
+ goto out;
+
+ ret = DIV_ROUND_CLOSEST(raw_uV, raw_uA);
+out:
+ gpadc_set_bias(gpadc, chan->channel, false);
+ return ret;
+}
+
+static int
+__pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ unsigned long lsb = chan->address;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ *val = gpadc_get_raw(iio, chan->channel);
+ if (*val < 0)
+ return *val;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = lsb;
+
+ if (chan->type == IIO_VOLTAGE) {
+ *val2 = MILLI;
+ return IIO_VAL_FRACTIONAL;
+ } else {
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ /* Raw value is 104 millikelvin/LSB, convert it to 104 millicelsius/LSB */
+ *val = ABSOLUTE_ZERO_MILLICELSIUS;
+ *val2 = lsb;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_PROCESSED:
+ *val = gpadc_get_resistance_ohm(iio, chan);
+ if (*val < 0)
+ return *val;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct device *dev = iio->dev.parent;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ ret = __pm886_gpadc_read_raw(iio, chan, val, val2, mask);
+
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+}
+
+static int pm886_gpadc_hw_enable(struct regmap *map)
+{
+ const u8 config[] = {
+ PM886_GPADC_CONFIG1_EN_ALL,
+ PM886_GPADC_CONFIG2_EN_ALL,
+ PM886_GPADC_GND_DET2_EN,
+ };
+ int ret;
+
+ /* Enable the ADC block. */
+ ret = regmap_set_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0));
+ if (ret)
+ return ret;
+
+ /* Enable all channels. */
+ return regmap_bulk_write(map, PM886_REG_GPADC_CONFIG(0x1), config, ARRAY_SIZE(config));
+}
+
+static int pm886_gpadc_hw_disable(struct regmap *map)
+{
+ return regmap_clear_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0));
+}
+
+static const struct iio_info pm886_gpadc_iio_info = {
+ .read_raw = pm886_gpadc_read_raw,
+};
+
+static int pm886_gpadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pm886_chip *chip = dev_get_drvdata(dev->parent);
+ struct i2c_client *client = chip->client;
+ struct pm886_gpadc *gpadc;
+ struct i2c_client *page;
+ struct iio_dev *iio;
+ int ret;
+
+ iio = devm_iio_device_alloc(dev, sizeof(*gpadc));
+ if (!iio)
+ return -ENOMEM;
+
+ gpadc = iio_priv(iio);
+ dev_set_drvdata(dev, iio);
+
+ page = devm_i2c_new_dummy_device(dev, client->adapter,
+ client->addr + PM886_PAGE_OFFSET_GPADC);
+ if (IS_ERR(page))
+ return dev_err_probe(dev, PTR_ERR(page), "Failed to initialize GPADC page\n");
+
+ gpadc->map = devm_regmap_init_i2c(page, &pm886_gpadc_regmap_config);
+ if (IS_ERR(gpadc->map))
+ return dev_err_probe(dev, PTR_ERR(gpadc->map),
+ "Failed to initialize GPADC regmap\n");
+
+ iio->name = "88pm886-gpadc";
+ iio->modes = INDIO_DIRECT_MODE;
+ iio->info = &pm886_gpadc_iio_info;
+ iio->channels = pm886_gpadc_channels;
+ iio->num_channels = ARRAY_SIZE(pm886_gpadc_channels);
+ device_set_node(&iio->dev, dev_fwnode(dev->parent));
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_iio_device_register(dev, iio);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register ADC\n");
+
+ return 0;
+}
+
+static int pm886_gpadc_runtime_resume(struct device *dev)
+{
+ struct iio_dev *iio = dev_get_drvdata(dev);
+ struct pm886_gpadc *gpadc = iio_priv(iio);
+
+ return pm886_gpadc_hw_enable(gpadc->map);
+}
+
+static int pm886_gpadc_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *iio = dev_get_drvdata(dev);
+ struct pm886_gpadc *gpadc = iio_priv(iio);
+
+ return pm886_gpadc_hw_disable(gpadc->map);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops,
+ pm886_gpadc_runtime_suspend,
+ pm886_gpadc_runtime_resume, NULL);
+
+static const struct platform_device_id pm886_gpadc_id[] = {
+ { "88pm886-gpadc" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, pm886_gpadc_id);
+
+static struct platform_driver pm886_gpadc_driver = {
+ .driver = {
+ .name = "88pm886-gpadc",
+ .pm = pm_ptr(&pm886_gpadc_pm_ops),
+ },
+ .probe = pm886_gpadc_probe,
+ .id_table = pm886_gpadc_id,
+};
+module_platform_driver(pm886_gpadc_driver);
+
+MODULE_AUTHOR("Duje Mihanović <duje@dujemihanovic.xyz>");
+MODULE_DESCRIPTION("Marvell 88PM886 GPADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 6de2abad0197..58a14e6833f6 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -9,6 +9,19 @@ menu "Analog to digital converters"
config IIO_ADC_HELPER
tristate
+config 88PM886_GPADC
+ tristate "Marvell 88PM886 GPADC driver"
+ depends on MFD_88PM886_PMIC
+ default MFD_88PM886_PMIC
+ help
+ Say Y here to enable support for the GPADC (General Purpose ADC)
+ found on the Marvell 88PM886 PMIC. The GPADC measures various
+ internal voltages and temperatures, including (but not limited to)
+ system, battery and USB Vbus.
+
+ To compile this driver as a module, choose M here: the module will be
+ called 88pm886-gpadc.
+
config AB8500_GPADC
bool "ST-Ericsson AB8500 GPADC driver"
depends on AB8500_CORE && REGULATOR_AB8500
@@ -389,6 +402,7 @@ config AD7779
depends on SPI
select CRC8
select IIO_BUFFER
+ select IIO_BACKEND
help
Say yes here to build support for Analog Devices AD777X family
(AD7770, AD7771, AD7779) analog to digital converter (ADC).
@@ -507,6 +521,25 @@ config AD9467
To compile this driver as a module, choose M here: the module will be
called ad9467.
+config ADE9000
+ tristate "Analog Devices ADE9000 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.
+
+ The device features 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.
+
+ To compile this driver as a module, choose M here: the module will
+ be called ade9000.
+
config ADI_AXI_ADC
tristate "Analog Devices Generic AXI ADC IP core driver"
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST
@@ -766,6 +799,17 @@ config INGENIC_ADC
This driver can also be built as a module. If so, the module will be
called ingenic_adc.
+config INTEL_DC_TI_ADC
+ tristate "Intel Bay Trail / Cherry Trail Dollar Cove TI ADC driver"
+ depends on INTEL_SOC_PMIC_CHTDC_TI
+ help
+ Say yes here to have support for the Dollar Cove TI PMIC ADC device.
+ Depending on platform configuration, this general purpose ADC can be
+ used for sensors such as battery voltage and thermal resistors.
+
+ To compile this driver as a module, choose M here: the module will be
+ called intel_dc_ti_adc.
+
config INTEL_MRFLD_ADC
tristate "Intel Merrifield Basin Cove ADC driver"
depends on INTEL_SOC_PMIC_MRFLD
@@ -1298,9 +1342,19 @@ config RN5T618_ADC
This driver can also be built as a module. If so, the module
will be called rn5t618-adc.
+config ROHM_BD79112
+ tristate "Rohm BD79112 ADC driver"
+ depends on SPI && GPIOLIB
+ select REGMAP_SPI
+ select IIO_ADC_HELPER
+ help
+ Say yes here to build support for the ROHM BD79112 ADC. The
+ ROHM BD79112 is a 12-bit, 32-channel, SAR ADC. Analog inputs
+ can also be used for GPIO.
+
config ROHM_BD79124
tristate "Rohm BD79124 ADC driver"
- depends on I2C
+ depends on I2C && GPIOLIB
select REGMAP_I2C
select IIO_ADC_HELPER
help
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 1c6ca5fd4b6d..d008f78dc010 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_88PM886_GPADC) += 88pm886-gpadc.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD4000) += ad4000.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_AD7944) += ad7944.o
obj-$(CONFIG_AD7949) += ad7949.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AD9467) += ad9467.o
+obj-$(CONFIG_ADE9000) += ade9000.o
obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
@@ -70,6 +72,7 @@ obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o
obj-$(CONFIG_IMX93_ADC) += imx93_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
+obj-$(CONFIG_INTEL_DC_TI_ADC) += intel_dc_ti_adc.o
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
@@ -116,6 +119,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
+obj-$(CONFIG_ROHM_BD79112) += rohm-bd79112.o
obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c
index f3b057f92310..8eaa1dd6a89b 100644
--- a/drivers/iio/adc/ab8500-gpadc.c
+++ b/drivers/iio/adc/ab8500-gpadc.c
@@ -607,7 +607,6 @@ static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc,
}
/* This eventually drops the regulator */
- pm_runtime_mark_last_busy(gpadc->dev);
pm_runtime_put_autosuspend(gpadc->dev);
return (high_data << 8) | low_data;
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index dcdb5778f7d6..5567ae5dee88 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -2035,8 +2035,7 @@ static int ad4130_probe(struct spi_device *spi)
ret = devm_add_action_or_reset(dev, ad4130_disable_regulators, st);
if (ret)
- return dev_err_probe(dev, ret,
- "Failed to add regulators disable action\n");
+ return ret;
ret = ad4130_soft_reset(st);
if (ret)
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 9808df2e9242..910b40393f77 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -3,21 +3,27 @@
* AD7124 SPI ADC driver
*
* Copyright 2018 Analog Devices Inc.
+ * Copyright 2025 BayLibre, SAS
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/sprintf.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/adc/ad_sigma_delta.h>
@@ -44,6 +50,11 @@
#define AD7124_STATUS_POR_FLAG BIT(4)
/* AD7124_ADC_CONTROL */
+#define AD7124_ADC_CONTROL_CLK_SEL GENMASK(1, 0)
+#define AD7124_ADC_CONTROL_CLK_SEL_INT 0
+#define AD7124_ADC_CONTROL_CLK_SEL_INT_OUT 1
+#define AD7124_ADC_CONTROL_CLK_SEL_EXT 2
+#define AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4 3
#define AD7124_ADC_CONTROL_MODE GENMASK(5, 2)
#define AD7124_ADC_CONTROL_MODE_CONTINUOUS 0
#define AD7124_ADC_CONTROL_MODE_SINGLE 1
@@ -84,14 +95,26 @@
#define AD7124_CONFIG_PGA GENMASK(2, 0)
/* AD7124_FILTER_X */
-#define AD7124_FILTER_FS GENMASK(10, 0)
#define AD7124_FILTER_FILTER GENMASK(23, 21)
#define AD7124_FILTER_FILTER_SINC4 0
#define AD7124_FILTER_FILTER_SINC3 2
+#define AD7124_FILTER_FILTER_SINC4_SINC1 4
+#define AD7124_FILTER_FILTER_SINC3_SINC1 5
+#define AD7124_FILTER_FILTER_SINC3_PF 7
+#define AD7124_FILTER_REJ60 BIT(20)
+#define AD7124_FILTER_POST_FILTER GENMASK(19, 17)
+#define AD7124_FILTER_POST_FILTER_47dB 2
+#define AD7124_FILTER_POST_FILTER_62dB 3
+#define AD7124_FILTER_POST_FILTER_86dB 5
+#define AD7124_FILTER_POST_FILTER_92dB 6
+#define AD7124_FILTER_SINGLE_CYCLE BIT(16)
+#define AD7124_FILTER_FS GENMASK(10, 0)
#define AD7124_MAX_CONFIGS 8
#define AD7124_MAX_CHANNELS 16
+#define AD7124_INT_CLK_HZ 614400
+
/* AD7124 input sources */
enum ad7124_ref_sel {
@@ -120,9 +143,9 @@ static const unsigned int ad7124_reg_size[] = {
};
static const int ad7124_master_clk_freq_hz[3] = {
- [AD7124_LOW_POWER] = 76800,
- [AD7124_MID_POWER] = 153600,
- [AD7124_FULL_POWER] = 614400,
+ [AD7124_LOW_POWER] = AD7124_INT_CLK_HZ / 8,
+ [AD7124_MID_POWER] = AD7124_INT_CLK_HZ / 4,
+ [AD7124_FULL_POWER] = AD7124_INT_CLK_HZ,
};
static const char * const ad7124_ref_names[] = {
@@ -138,9 +161,24 @@ struct ad7124_chip_info {
unsigned int num_inputs;
};
+enum ad7124_filter_type {
+ AD7124_FILTER_TYPE_SINC3,
+ AD7124_FILTER_TYPE_SINC3_PF1,
+ AD7124_FILTER_TYPE_SINC3_PF2,
+ AD7124_FILTER_TYPE_SINC3_PF3,
+ AD7124_FILTER_TYPE_SINC3_PF4,
+ AD7124_FILTER_TYPE_SINC3_REJ60,
+ AD7124_FILTER_TYPE_SINC3_SINC1,
+ AD7124_FILTER_TYPE_SINC4,
+ AD7124_FILTER_TYPE_SINC4_REJ60,
+ AD7124_FILTER_TYPE_SINC4_SINC1,
+};
+
struct ad7124_channel_config {
bool live;
unsigned int cfg_slot;
+ unsigned int requested_odr;
+ unsigned int requested_odr_micro;
/*
* Following fields are used to compare for equality. If you
* make adaptations in it, you most likely also have to adapt
@@ -153,9 +191,8 @@ struct ad7124_channel_config {
bool buf_negative;
unsigned int vref_mv;
unsigned int pga_bits;
- unsigned int odr;
unsigned int odr_sel_bits;
- unsigned int filter_type;
+ enum ad7124_filter_type filter_type;
unsigned int calibration_offset;
unsigned int calibration_gain;
);
@@ -174,7 +211,7 @@ struct ad7124_state {
struct ad_sigma_delta sd;
struct ad7124_channel *channels;
struct regulator *vref[4];
- struct clk *mclk;
+ u32 clk_hz;
unsigned int adc_control;
unsigned int num_channels;
struct mutex cfgs_lock; /* lock for configs access */
@@ -250,44 +287,117 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd,
return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
}
-static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr)
+static u32 ad7124_get_fclk_hz(struct ad7124_state *st)
+{
+ enum ad7124_power_mode power_mode;
+ u32 fclk_hz;
+
+ power_mode = FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, st->adc_control);
+ fclk_hz = st->clk_hz;
+
+ switch (power_mode) {
+ case AD7124_LOW_POWER:
+ fclk_hz /= 8;
+ break;
+ case AD7124_MID_POWER:
+ fclk_hz /= 4;
+ break;
+ default:
+ break;
+ }
+
+ return fclk_hz;
+}
+
+static u32 ad7124_get_fs_factor(struct ad7124_state *st, unsigned int channel)
{
- unsigned int fclk, odr_sel_bits;
+ enum ad7124_power_mode power_mode =
+ FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, st->adc_control);
+ u32 avg = power_mode == AD7124_LOW_POWER ? 8 : 16;
- fclk = clk_get_rate(st->mclk);
/*
- * FS[10:0] = fCLK / (fADC x 32) where:
+ * These are the "zero-latency" factors from the data sheet. For the
+ * sinc1 filters, these aren't documented, but derived by taking the
+ * single-channel formula from the sinc1 section of the data sheet and
+ * multiplying that by the sinc3/4 factor from the corresponding zero-
+ * latency sections.
+ */
+ switch (st->channels[channel].cfg.filter_type) {
+ case AD7124_FILTER_TYPE_SINC4:
+ case AD7124_FILTER_TYPE_SINC4_REJ60:
+ return 4 * 32;
+ case AD7124_FILTER_TYPE_SINC4_SINC1:
+ return 4 * avg * 32;
+ case AD7124_FILTER_TYPE_SINC3_SINC1:
+ return 3 * avg * 32;
+ default:
+ return 3 * 32;
+ }
+}
+
+static u32 ad7124_get_fadc_divisor(struct ad7124_state *st, unsigned int channel)
+{
+ u32 factor = ad7124_get_fs_factor(st, channel);
+
+ /*
+ * The output data rate (f_ADC) is f_CLK / divisor. We are returning
+ * the divisor.
+ */
+ return st->channels[channel].cfg.odr_sel_bits * factor;
+}
+
+static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel)
+{
+ struct ad7124_channel_config *cfg = &st->channels[channel].cfg;
+ unsigned int fclk, factor, divisor, odr_sel_bits;
+
+ fclk = ad7124_get_fclk_hz(st);
+ factor = ad7124_get_fs_factor(st, channel);
+
+ /*
+ * FS[10:0] = fCLK / (fADC x 32 * N) where:
* fADC is the output data rate
* fCLK is the master clock frequency
+ * N is number of conversions per sample (depends on filter type)
* FS[10:0] are the bits in the filter register
* FS[10:0] can have a value from 1 to 2047
*/
- odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * 32);
- if (odr_sel_bits < 1)
- odr_sel_bits = 1;
- else if (odr_sel_bits > 2047)
- odr_sel_bits = 2047;
+ divisor = cfg->requested_odr * factor +
+ cfg->requested_odr_micro * factor / MICRO;
+ odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, divisor), 1, 2047);
if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits)
st->channels[channel].cfg.live = false;
- /* fADC = fCLK / (FS[10:0] x 32) */
- st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32);
st->channels[channel].cfg.odr_sel_bits = odr_sel_bits;
}
-static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
- unsigned int channel)
+static int ad7124_get_3db_filter_factor(struct ad7124_state *st,
+ unsigned int channel)
{
- unsigned int fadc;
+ struct ad7124_channel_config *cfg = &st->channels[channel].cfg;
- fadc = st->channels[channel].cfg.odr;
-
- switch (st->channels[channel].cfg.filter_type) {
- case AD7124_FILTER_FILTER_SINC3:
- return DIV_ROUND_CLOSEST(fadc * 272, 1000);
- case AD7124_FILTER_FILTER_SINC4:
- return DIV_ROUND_CLOSEST(fadc * 230, 1000);
+ /*
+ * 3dB point is the f_CLK rate times some factor. This functions returns
+ * the factor times 1000.
+ */
+ switch (cfg->filter_type) {
+ case AD7124_FILTER_TYPE_SINC3:
+ case AD7124_FILTER_TYPE_SINC3_REJ60:
+ case AD7124_FILTER_TYPE_SINC3_SINC1:
+ return 272;
+ case AD7124_FILTER_TYPE_SINC4:
+ case AD7124_FILTER_TYPE_SINC4_REJ60:
+ case AD7124_FILTER_TYPE_SINC4_SINC1:
+ return 230;
+ case AD7124_FILTER_TYPE_SINC3_PF1:
+ return 633;
+ case AD7124_FILTER_TYPE_SINC3_PF2:
+ return 605;
+ case AD7124_FILTER_TYPE_SINC3_PF3:
+ return 669;
+ case AD7124_FILTER_TYPE_SINC3_PF4:
+ return 759;
default:
return -EINVAL;
}
@@ -311,9 +421,8 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
bool buf_negative;
unsigned int vref_mv;
unsigned int pga_bits;
- unsigned int odr;
unsigned int odr_sel_bits;
- unsigned int filter_type;
+ enum ad7124_filter_type filter_type;
unsigned int calibration_offset;
unsigned int calibration_gain;
}));
@@ -328,7 +437,6 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
cfg->buf_negative == cfg_aux->buf_negative &&
cfg->vref_mv == cfg_aux->vref_mv &&
cfg->pga_bits == cfg_aux->pga_bits &&
- cfg->odr == cfg_aux->odr &&
cfg->odr_sel_bits == cfg_aux->odr_sel_bits &&
cfg->filter_type == cfg_aux->filter_type &&
cfg->calibration_offset == cfg_aux->calibration_offset &&
@@ -381,8 +489,9 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg,
unsigned int cfg_slot)
{
- unsigned int tmp;
- unsigned int val;
+ unsigned int val, filter;
+ unsigned int rej60 = 0;
+ unsigned int post = 0;
int ret;
cfg->cfg_slot = cfg_slot;
@@ -405,11 +514,60 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
if (ret < 0)
return ret;
- tmp = FIELD_PREP(AD7124_FILTER_FILTER, cfg->filter_type) |
- FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits);
- return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot),
- AD7124_FILTER_FILTER | AD7124_FILTER_FS,
- tmp, 3);
+ switch (cfg->filter_type) {
+ case AD7124_FILTER_TYPE_SINC3:
+ filter = AD7124_FILTER_FILTER_SINC3;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_PF1:
+ filter = AD7124_FILTER_FILTER_SINC3_PF;
+ post = AD7124_FILTER_POST_FILTER_47dB;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_PF2:
+ filter = AD7124_FILTER_FILTER_SINC3_PF;
+ post = AD7124_FILTER_POST_FILTER_62dB;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_PF3:
+ filter = AD7124_FILTER_FILTER_SINC3_PF;
+ post = AD7124_FILTER_POST_FILTER_86dB;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_PF4:
+ filter = AD7124_FILTER_FILTER_SINC3_PF;
+ post = AD7124_FILTER_POST_FILTER_92dB;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_REJ60:
+ filter = AD7124_FILTER_FILTER_SINC3;
+ rej60 = 1;
+ break;
+ case AD7124_FILTER_TYPE_SINC3_SINC1:
+ filter = AD7124_FILTER_FILTER_SINC3_SINC1;
+ break;
+ case AD7124_FILTER_TYPE_SINC4:
+ filter = AD7124_FILTER_FILTER_SINC4;
+ break;
+ case AD7124_FILTER_TYPE_SINC4_REJ60:
+ filter = AD7124_FILTER_FILTER_SINC4;
+ rej60 = 1;
+ break;
+ case AD7124_FILTER_TYPE_SINC4_SINC1:
+ filter = AD7124_FILTER_FILTER_SINC4_SINC1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * NB: AD7124_FILTER_SINGLE_CYCLE is always set so that we get the same
+ * sampling frequency even when only one channel is enabled in a
+ * buffered read. If it was not set, the N in ad7124_set_channel_odr()
+ * would be 1 and we would get a faster sampling frequency than what
+ * was requested.
+ */
+ return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg->cfg_slot), 3,
+ FIELD_PREP(AD7124_FILTER_FILTER, filter) |
+ FIELD_PREP(AD7124_FILTER_REJ60, rej60) |
+ FIELD_PREP(AD7124_FILTER_POST_FILTER, post) |
+ AD7124_FILTER_SINGLE_CYCLE |
+ FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits));
}
static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st)
@@ -576,6 +734,33 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
.num_resetclks = 64,
};
+static const int ad7124_voltage_scales[][2] = {
+ { 0, 1164 },
+ { 0, 2328 },
+ { 0, 4656 },
+ { 0, 9313 },
+ { 0, 18626 },
+ { 0, 37252 },
+ { 0, 74505 },
+ { 0, 149011 },
+ { 0, 298023 },
+};
+
+static int ad7124_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)ad7124_voltage_scales;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(ad7124_voltage_scales) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ad7124_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
@@ -644,18 +829,59 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
- case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&st->cfgs_lock);
- *val = st->channels[chan->address].cfg.odr;
- mutex_unlock(&st->cfgs_lock);
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- mutex_lock(&st->cfgs_lock);
- *val = ad7124_get_3db_filter_freq(st, chan->scan_index);
- mutex_unlock(&st->cfgs_lock);
+ guard(mutex)(&st->cfgs_lock);
- return IIO_VAL_INT;
+ switch (cfg->filter_type) {
+ case AD7124_FILTER_TYPE_SINC3:
+ case AD7124_FILTER_TYPE_SINC3_REJ60:
+ case AD7124_FILTER_TYPE_SINC3_SINC1:
+ case AD7124_FILTER_TYPE_SINC4:
+ case AD7124_FILTER_TYPE_SINC4_REJ60:
+ case AD7124_FILTER_TYPE_SINC4_SINC1:
+ *val = ad7124_get_fclk_hz(st);
+ *val2 = ad7124_get_fadc_divisor(st, chan->address);
+ return IIO_VAL_FRACTIONAL;
+ /*
+ * Post filters force the chip to a fixed rate. These are the
+ * single-channel rates from the data sheet divided by 3 for
+ * the multi-channel case (data sheet doesn't explicitly state
+ * this but confirmed through testing).
+ */
+ case AD7124_FILTER_TYPE_SINC3_PF1:
+ *val = 300;
+ *val2 = 33;
+ return IIO_VAL_FRACTIONAL;
+ case AD7124_FILTER_TYPE_SINC3_PF2:
+ *val = 25;
+ *val2 = 3;
+ return IIO_VAL_FRACTIONAL;
+ case AD7124_FILTER_TYPE_SINC3_PF3:
+ *val = 20;
+ *val2 = 3;
+ return IIO_VAL_FRACTIONAL;
+ case AD7124_FILTER_TYPE_SINC3_PF4:
+ *val = 50;
+ *val2 = 9;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ }
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: {
+ guard(mutex)(&st->cfgs_lock);
+
+ ret = ad7124_get_3db_filter_factor(st, chan->address);
+ if (ret < 0)
+ return ret;
+
+ /* 3dB point is the f_CLK rate times a fractional value */
+ *val = ret * ad7124_get_fclk_hz(st);
+ *val2 = MILLI * ad7124_get_fadc_divisor(st, chan->address);
+ return IIO_VAL_FRACTIONAL;
+ }
default:
return -EINVAL;
}
@@ -666,25 +892,24 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
int val, int val2, long info)
{
struct ad7124_state *st = iio_priv(indio_dev);
+ struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg;
unsigned int res, gain, full_scale, vref;
- int ret = 0;
- mutex_lock(&st->cfgs_lock);
+ guard(mutex)(&st->cfgs_lock);
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
- if (val2 != 0 || val == 0) {
- ret = -EINVAL;
- break;
- }
+ if (val2 < 0 || val < 0 || (val2 == 0 && val == 0))
+ return -EINVAL;
- ad7124_set_channel_odr(st, chan->address, val);
- break;
+ cfg->requested_odr = val;
+ cfg->requested_odr_micro = val2;
+ ad7124_set_channel_odr(st, chan->address);
+
+ return 0;
case IIO_CHAN_INFO_SCALE:
- if (val != 0) {
- ret = -EINVAL;
- break;
- }
+ if (val != 0)
+ return -EINVAL;
if (st->channels[chan->address].cfg.bipolar)
full_scale = 1 << (chan->scan_type.realbits - 1);
@@ -700,13 +925,10 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
st->channels[chan->address].cfg.live = false;
st->channels[chan->address].cfg.pga_bits = res;
- break;
+ return 0;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&st->cfgs_lock);
- return ret;
}
static int ad7124_reg_access(struct iio_dev *indio_dev,
@@ -730,18 +952,6 @@ static int ad7124_reg_access(struct iio_dev *indio_dev,
return ret;
}
-static IIO_CONST_ATTR(in_voltage_scale_available,
- "0.000001164 0.000002328 0.000004656 0.000009313 0.000018626 0.000037252 0.000074505 0.000149011 0.000298023");
-
-static struct attribute *ad7124_attributes[] = {
- &iio_const_attr_in_voltage_scale_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad7124_attrs_group = {
- .attrs = ad7124_attributes,
-};
-
static int ad7124_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
@@ -750,7 +960,8 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev,
int ret;
int i;
- mutex_lock(&st->cfgs_lock);
+ guard(mutex)(&st->cfgs_lock);
+
for (i = 0; i < st->num_channels; i++) {
bit_set = test_bit(i, scan_mask);
if (bit_set)
@@ -758,25 +969,20 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev,
else
ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE,
0, 2);
- if (ret < 0) {
- mutex_unlock(&st->cfgs_lock);
-
+ if (ret < 0)
return ret;
- }
}
- mutex_unlock(&st->cfgs_lock);
-
return 0;
}
static const struct iio_info ad7124_info = {
+ .read_avail = ad7124_read_avail,
.read_raw = ad7124_read_raw,
.write_raw = ad7124_write_raw,
.debugfs_reg_access = &ad7124_reg_access,
.validate_trigger = ad_sd_validate_trigger,
.update_scan_mode = ad7124_update_scan_mode,
- .attrs = &ad7124_attrs_group,
};
/* Only called during probe, so dev_err_probe() can be used */
@@ -849,7 +1055,7 @@ enum {
static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan_spec *chan)
{
struct device *dev = &st->sd.spi->dev;
- struct ad7124_channel *ch = &st->channels[chan->channel];
+ struct ad7124_channel *ch = &st->channels[chan->address];
int ret;
if (ch->syscalib_mode == AD7124_SYSCALIB_ZERO_SCALE) {
@@ -865,8 +1071,8 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
if (ret < 0)
return ret;
- dev_dbg(dev, "offset for channel %d after zero-scale calibration: 0x%x\n",
- chan->channel, ch->cfg.calibration_offset);
+ dev_dbg(dev, "offset for channel %lu after zero-scale calibration: 0x%x\n",
+ chan->address, ch->cfg.calibration_offset);
} else {
ch->cfg.calibration_gain = st->gain_default;
@@ -880,8 +1086,8 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
if (ret < 0)
return ret;
- dev_dbg(dev, "gain for channel %d after full-scale calibration: 0x%x\n",
- chan->channel, ch->cfg.calibration_gain);
+ dev_dbg(dev, "gain for channel %lu after full-scale calibration: 0x%x\n",
+ chan->address, ch->cfg.calibration_gain);
}
return 0;
@@ -924,7 +1130,7 @@ static int ad7124_set_syscalib_mode(struct iio_dev *indio_dev,
{
struct ad7124_state *st = iio_priv(indio_dev);
- st->channels[chan->channel].syscalib_mode = mode;
+ st->channels[chan->address].syscalib_mode = mode;
return 0;
}
@@ -934,7 +1140,7 @@ static int ad7124_get_syscalib_mode(struct iio_dev *indio_dev,
{
struct ad7124_state *st = iio_priv(indio_dev);
- return st->channels[chan->channel].syscalib_mode;
+ return st->channels[chan->address].syscalib_mode;
}
static const struct iio_enum ad7124_syscalib_mode_enum = {
@@ -944,6 +1150,52 @@ static const struct iio_enum ad7124_syscalib_mode_enum = {
.get = ad7124_get_syscalib_mode
};
+static const char * const ad7124_filter_types[] = {
+ [AD7124_FILTER_TYPE_SINC3] = "sinc3",
+ [AD7124_FILTER_TYPE_SINC3_PF1] = "sinc3+pf1",
+ [AD7124_FILTER_TYPE_SINC3_PF2] = "sinc3+pf2",
+ [AD7124_FILTER_TYPE_SINC3_PF3] = "sinc3+pf3",
+ [AD7124_FILTER_TYPE_SINC3_PF4] = "sinc3+pf4",
+ [AD7124_FILTER_TYPE_SINC3_REJ60] = "sinc3+rej60",
+ [AD7124_FILTER_TYPE_SINC3_SINC1] = "sinc3+sinc1",
+ [AD7124_FILTER_TYPE_SINC4] = "sinc4",
+ [AD7124_FILTER_TYPE_SINC4_REJ60] = "sinc4+rej60",
+ [AD7124_FILTER_TYPE_SINC4_SINC1] = "sinc4+sinc1",
+};
+
+static int ad7124_set_filter_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan,
+ unsigned int value)
+{
+ struct ad7124_state *st = iio_priv(dev);
+ struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg;
+
+ guard(mutex)(&st->cfgs_lock);
+
+ cfg->live = false;
+ cfg->filter_type = value;
+ ad7124_set_channel_odr(st, chan->address);
+
+ return 0;
+}
+
+static int ad7124_get_filter_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7124_state *st = iio_priv(dev);
+
+ guard(mutex)(&st->cfgs_lock);
+
+ return st->channels[chan->address].cfg.filter_type;
+}
+
+static const struct iio_enum ad7124_filter_type_enum = {
+ .items = ad7124_filter_types,
+ .num_items = ARRAY_SIZE(ad7124_filter_types),
+ .set = ad7124_set_filter_type_attr,
+ .get = ad7124_get_filter_type_attr,
+};
+
static const struct iio_chan_spec_ext_info ad7124_calibsys_ext_info[] = {
{
.name = "sys_calibration",
@@ -954,6 +1206,9 @@ static const struct iio_chan_spec_ext_info ad7124_calibsys_ext_info[] = {
&ad7124_syscalib_mode_enum),
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
&ad7124_syscalib_mode_enum),
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad7124_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+ &ad7124_filter_type_enum),
{ }
};
@@ -966,6 +1221,7 @@ static const struct iio_chan_spec ad7124_channel_template = {
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
.scan_type = {
.sign = 'u',
.realbits = 24,
@@ -1111,24 +1367,122 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
static int ad7124_setup(struct ad7124_state *st)
{
struct device *dev = &st->sd.spi->dev;
- unsigned int fclk, power_mode;
+ unsigned int power_mode, clk_sel;
+ struct clk *mclk;
int i, ret;
- fclk = clk_get_rate(st->mclk);
- if (!fclk)
- return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
+ /*
+ * Always use full power mode for max performance. If needed, the driver
+ * could be adapted to use a dynamic power mode based on the requested
+ * output data rate.
+ */
+ power_mode = AD7124_ADC_CONTROL_POWER_MODE_FULL;
+
+ /*
+ * This "mclk" business is needed for backwards compatibility with old
+ * devicetrees that specified a fake clock named "mclk" to select the
+ * power mode.
+ */
+ mclk = devm_clk_get_optional_enabled(dev, "mclk");
+ if (IS_ERR(mclk))
+ return dev_err_probe(dev, PTR_ERR(mclk), "Failed to get mclk\n");
+
+ if (mclk) {
+ unsigned long mclk_hz;
- /* The power mode changes the master clock frequency */
- power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
- ARRAY_SIZE(ad7124_master_clk_freq_hz),
- fclk);
- if (fclk != ad7124_master_clk_freq_hz[power_mode]) {
- ret = clk_set_rate(st->mclk, fclk);
+ mclk_hz = clk_get_rate(mclk);
+ if (!mclk_hz)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to get mclk rate\n");
+
+ /*
+ * This logic is a bit backwards, which is why it is only here
+ * for backwards compatibility. The driver should be able to set
+ * the power mode as it sees fit and the f_clk/mclk rate should
+ * be dynamic accordingly. But here, we are selecting a fixed
+ * power mode based on the given "mclk" rate.
+ */
+ power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
+ ARRAY_SIZE(ad7124_master_clk_freq_hz), mclk_hz);
+
+ if (mclk_hz != ad7124_master_clk_freq_hz[power_mode]) {
+ ret = clk_set_rate(mclk, mclk_hz);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set mclk rate\n");
+ }
+
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT;
+ st->clk_hz = AD7124_INT_CLK_HZ;
+ } else if (!device_property_present(dev, "clocks") &&
+ device_property_present(dev, "#clock-cells")) {
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw *clk_hw;
+
+ const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%pfwP-clk",
+ dev_fwnode(dev));
+ if (!name)
+ return -ENOMEM;
+
+ clk_hw = devm_clk_hw_register_fixed_rate(dev, name, NULL, 0,
+ AD7124_INT_CLK_HZ);
+ if (IS_ERR(clk_hw))
+ return dev_err_probe(dev, PTR_ERR(clk_hw),
+ "Failed to register clock provider\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ clk_hw);
if (ret)
- return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
+ return dev_err_probe(dev, ret,
+ "Failed to add clock provider\n");
+#endif
+
+ /*
+ * Treat the clock as always on. This way we don't have to deal
+ * with someone trying to enable/disable the clock while we are
+ * reading samples.
+ */
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT_OUT;
+ st->clk_hz = AD7124_INT_CLK_HZ;
+ } else {
+ struct clk *clk;
+
+ clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "Failed to get external clock\n");
+
+ if (clk) {
+ unsigned long clk_hz;
+
+ clk_hz = clk_get_rate(clk);
+ if (!clk_hz)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to get external clock rate\n");
+
+ /*
+ * The external clock may be 4x the nominal clock rate,
+ * in which case the ADC needs to be configured to
+ * divide it by 4. Using MEGA is a bit arbitrary, but
+ * the expected clock rates are either 614.4 kHz or
+ * 2.4576 MHz, so this should work.
+ */
+ if (clk_hz > (1 * HZ_PER_MHZ)) {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4;
+ st->clk_hz = clk_hz / 4;
+ } else {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT;
+ st->clk_hz = clk_hz;
+ }
+ } else {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT;
+ st->clk_hz = AD7124_INT_CLK_HZ;
+ }
}
- /* Set the power mode */
+ st->adc_control &= ~AD7124_ADC_CONTROL_CLK_SEL;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_CLK_SEL, clk_sel);
+
st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode);
@@ -1138,17 +1492,22 @@ static int ad7124_setup(struct ad7124_state *st)
mutex_init(&st->cfgs_lock);
INIT_KFIFO(st->live_cfgs_fifo);
for (i = 0; i < st->num_channels; i++) {
+ struct ad7124_channel_config *cfg = &st->channels[i].cfg;
- ret = ad7124_init_config_vref(st, &st->channels[i].cfg);
+ ret = ad7124_init_config_vref(st, cfg);
if (ret < 0)
return ret;
+ /* Default filter type on the ADC after reset. */
+ cfg->filter_type = AD7124_FILTER_TYPE_SINC4;
+
/*
* 9.38 SPS is the minimum output data rate supported
* regardless of the selected power mode. Round it up to 10 and
* set all channels to this default value.
*/
- ad7124_set_channel_odr(st, i, 10);
+ cfg->requested_odr = 10;
+ ad7124_set_channel_odr(st, i);
}
ad7124_disable_all(&st->sd);
@@ -1300,13 +1659,9 @@ static int ad7124_probe(struct spi_device *spi)
ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable,
st->vref[i]);
if (ret)
- return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i);
+ return ret;
}
- st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
- if (IS_ERR(st->mclk))
- return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n");
-
ret = ad7124_soft_reset(st);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index 4413207be28f..d36612352b44 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -8,6 +8,7 @@
* AD7175-8/AD7176-2/AD7177-2
*
* Copyright (C) 2015, 2024 Analog Devices, Inc.
+ * Copyright (C) 2025 BayLibre, SAS
*/
#include <linux/array_size.h>
@@ -149,7 +150,12 @@
(pin2) < st->info->num_voltage_in && \
(pin2) >= st->info->num_voltage_in_div)
-#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
+#define AD7173_FILTER_SINC3_MAP BIT(15)
+#define AD7173_FILTER_SINC3_MAP_DIV GENMASK(14, 0)
+#define AD7173_FILTER_ENHFILTEN BIT(11)
+#define AD7173_FILTER_ENHFILT_MASK GENMASK(10, 8)
+#define AD7173_FILTER_ORDER BIT(6)
+#define AD7173_FILTER_ODR_MASK GENMASK(5, 0)
#define AD7173_MAX_CONFIGS 8
#define AD4111_OW_DET_THRSH_MV 300
@@ -190,6 +196,15 @@ struct ad7173_device_info {
u8 num_gpios;
};
+enum ad7173_filter_type {
+ AD7173_FILTER_SINC3,
+ AD7173_FILTER_SINC5_SINC1,
+ AD7173_FILTER_SINC5_SINC1_PF1,
+ AD7173_FILTER_SINC5_SINC1_PF2,
+ AD7173_FILTER_SINC5_SINC1_PF3,
+ AD7173_FILTER_SINC5_SINC1_PF4,
+};
+
struct ad7173_channel_config {
/* Openwire detection threshold */
unsigned int openwire_thrsh_raw;
@@ -200,13 +215,15 @@ struct ad7173_channel_config {
/*
* Following fields are used to compare equality. If you
* make adaptations in it, you most likely also have to adapt
- * ad7173_find_live_config(), too.
+ * ad7173_is_setup_equal(), too.
*/
struct_group(config_props,
bool bipolar;
bool input_buf;
- u8 odr;
+ u16 sinc3_odr_div;
+ u8 sinc5_odr_index;
u8 ref_sel;
+ enum ad7173_filter_type filter_type;
);
};
@@ -266,6 +283,24 @@ static const unsigned int ad7175_sinc5_data_rates[] = {
5000, /* 20 */
};
+/**
+ * ad7173_sinc3_odr_div_from_odr() - Convert ODR to divider value
+ * @odr_millihz: ODR (sampling_frequency) in milliHz
+ * Returns: Divider value for SINC3 filter to pass.
+ */
+static u16 ad7173_sinc3_odr_div_from_odr(u32 odr_millihz)
+{
+ /*
+ * Divider is f_MOD (1 MHz) / 32 / ODR. ODR freq is in milliHz, so
+ * we need to convert f_MOD to the same units. When SING_CYC=1 or
+ * multiple channels are enabled (currently always the case), there
+ * is an additional factor of 3.
+ */
+ u32 div = DIV_ROUND_CLOSEST(MEGA * MILLI, odr_millihz * 32 * 3);
+ /* Avoid divide by 0 and limit to register field size. */
+ return clamp(div, 1U, AD7173_FILTER_SINC3_MAP_DIV);
+}
+
static unsigned int ad4111_current_channel_config[] = {
/* Ain sel: pos neg */
0x1E8, /* 15:IIN0+ 8:IIN0− */
@@ -369,7 +404,48 @@ static const struct iio_enum ad7173_syscalib_mode_enum = {
.get = ad7173_get_syscalib_mode
};
-static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
+static const char * const ad7173_filter_types_str[] = {
+ [AD7173_FILTER_SINC3] = "sinc3",
+ [AD7173_FILTER_SINC5_SINC1] = "sinc5+sinc1",
+ [AD7173_FILTER_SINC5_SINC1_PF1] = "sinc5+sinc1+pf1",
+ [AD7173_FILTER_SINC5_SINC1_PF2] = "sinc5+sinc1+pf2",
+ [AD7173_FILTER_SINC5_SINC1_PF3] = "sinc5+sinc1+pf3",
+ [AD7173_FILTER_SINC5_SINC1_PF4] = "sinc5+sinc1+pf4",
+};
+
+static int ad7173_set_filter_type(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int val)
+{
+ struct ad7173_state *st = iio_priv(indio_dev);
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ st->channels[chan->address].cfg.filter_type = val;
+ st->channels[chan->address].cfg.live = false;
+
+ iio_device_release_direct(indio_dev);
+
+ return 0;
+}
+
+static int ad7173_get_filter_type(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7173_state *st = iio_priv(indio_dev);
+
+ return st->channels[chan->address].cfg.filter_type;
+}
+
+static const struct iio_enum ad7173_filter_type_enum = {
+ .items = ad7173_filter_types_str,
+ .num_items = ARRAY_SIZE(ad7173_filter_types_str),
+ .set = ad7173_set_filter_type,
+ .get = ad7173_get_filter_type,
+};
+
+static const struct iio_chan_spec_ext_info ad7173_chan_spec_ext_info[] = {
{
.name = "sys_calibration",
.write = ad7173_write_syscalib,
@@ -379,6 +455,16 @@ static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
&ad7173_syscalib_mode_enum),
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
&ad7173_syscalib_mode_enum),
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad7173_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+ &ad7173_filter_type_enum),
+ { }
+};
+
+static const struct iio_chan_spec_ext_info ad7173_temp_chan_spec_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad7173_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+ &ad7173_filter_type_enum),
{ }
};
@@ -561,12 +647,19 @@ static void ad7173_reset_usage_cnts(struct ad7173_state *st)
st->config_usage_counter = 0;
}
-static struct ad7173_channel_config *
-ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *cfg)
+/**
+ * ad7173_is_setup_equal - Compare two channel setups
+ * @cfg1: First channel configuration
+ * @cfg2: Second channel configuration
+ *
+ * Compares all configuration options that affect the registers connected to
+ * SETUP_SEL, namely CONFIGx, FILTERx, GAINx and OFFSETx.
+ *
+ * Returns: true if the setups are identical, false otherwise
+ */
+static bool ad7173_is_setup_equal(const struct ad7173_channel_config *cfg1,
+ const struct ad7173_channel_config *cfg2)
{
- struct ad7173_channel_config *cfg_aux;
- int i;
-
/*
* This is just to make sure that the comparison is adapted after
* struct ad7173_channel_config was changed.
@@ -575,18 +668,30 @@ ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *c
sizeof(struct {
bool bipolar;
bool input_buf;
- u8 odr;
+ u16 sinc3_odr_div;
+ u8 sinc5_odr_index;
u8 ref_sel;
+ enum ad7173_filter_type filter_type;
}));
+ return cfg1->bipolar == cfg2->bipolar &&
+ cfg1->input_buf == cfg2->input_buf &&
+ cfg1->sinc3_odr_div == cfg2->sinc3_odr_div &&
+ cfg1->sinc5_odr_index == cfg2->sinc5_odr_index &&
+ cfg1->ref_sel == cfg2->ref_sel &&
+ cfg1->filter_type == cfg2->filter_type;
+}
+
+static struct ad7173_channel_config *
+ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *cfg)
+{
+ struct ad7173_channel_config *cfg_aux;
+ int i;
+
for (i = 0; i < st->num_channels; i++) {
cfg_aux = &st->channels[i].cfg;
- if (cfg_aux->live &&
- cfg->bipolar == cfg_aux->bipolar &&
- cfg->input_buf == cfg_aux->input_buf &&
- cfg->odr == cfg_aux->odr &&
- cfg->ref_sel == cfg_aux->ref_sel)
+ if (cfg_aux->live && ad7173_is_setup_equal(cfg, cfg_aux))
return cfg_aux;
}
return NULL;
@@ -615,6 +720,7 @@ static int ad7173_load_config(struct ad7173_state *st,
{
unsigned int config;
int free_cfg_slot, ret;
+ u8 post_filter_enable, post_filter_select;
free_cfg_slot = ida_alloc_range(&st->cfg_slots_status, 0,
st->info->num_configs - 1, GFP_KERNEL);
@@ -634,8 +740,49 @@ static int ad7173_load_config(struct ad7173_state *st,
if (ret)
return ret;
+ /*
+ * When SINC3_MAP flag is enabled, the rest of the register has a
+ * different meaning. We are using this option to allow the most
+ * possible sampling frequencies with SINC3 filter.
+ */
+ if (cfg->filter_type == AD7173_FILTER_SINC3)
+ return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2,
+ FIELD_PREP(AD7173_FILTER_SINC3_MAP, 1) |
+ FIELD_PREP(AD7173_FILTER_SINC3_MAP_DIV,
+ cfg->sinc3_odr_div));
+
+ switch (cfg->filter_type) {
+ case AD7173_FILTER_SINC5_SINC1_PF1:
+ post_filter_enable = 1;
+ post_filter_select = 2;
+ break;
+ case AD7173_FILTER_SINC5_SINC1_PF2:
+ post_filter_enable = 1;
+ post_filter_select = 3;
+ break;
+ case AD7173_FILTER_SINC5_SINC1_PF3:
+ post_filter_enable = 1;
+ post_filter_select = 5;
+ break;
+ case AD7173_FILTER_SINC5_SINC1_PF4:
+ post_filter_enable = 1;
+ post_filter_select = 6;
+ break;
+ default:
+ post_filter_enable = 0;
+ post_filter_select = 0;
+ break;
+ }
+
return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2,
- AD7173_FILTER_ODR0_MASK & cfg->odr);
+ FIELD_PREP(AD7173_FILTER_SINC3_MAP, 0) |
+ FIELD_PREP(AD7173_FILTER_ENHFILT_MASK,
+ post_filter_enable) |
+ FIELD_PREP(AD7173_FILTER_ENHFILTEN,
+ post_filter_select) |
+ FIELD_PREP(AD7173_FILTER_ORDER, 0) |
+ FIELD_PREP(AD7173_FILTER_ODR_MASK,
+ cfg->sinc5_odr_index));
}
static int ad7173_config_channel(struct ad7173_state *st, int addr)
@@ -746,6 +893,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_4_slots = {
.set_mode = ad7173_set_mode,
.has_registers = true,
.has_named_irqs = true,
+ .supports_spi_offload = true,
.addr_shift = 0,
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
@@ -762,6 +910,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_8_slots = {
.set_mode = ad7173_set_mode,
.has_registers = true,
.has_named_irqs = true,
+ .supports_spi_offload = true,
.addr_shift = 0,
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
@@ -778,6 +927,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_16_slots = {
.set_mode = ad7173_set_mode,
.has_registers = true,
.has_named_irqs = true,
+ .supports_spi_offload = true,
.addr_shift = 0,
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
@@ -1165,7 +1315,14 @@ static int ad7173_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
- reg = st->channels[chan->address].cfg.odr;
+ if (st->channels[chan->address].cfg.filter_type == AD7173_FILTER_SINC3) {
+ /* Inverse operation of ad7173_sinc3_odr_div_from_odr() */
+ *val = MEGA;
+ *val2 = 3 * 32 * st->channels[chan->address].cfg.sinc3_odr_div;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ reg = st->channels[chan->address].cfg.sinc5_odr_index;
*val = st->info->sinc5_data_rates[reg] / MILLI;
*val2 = (st->info->sinc5_data_rates[reg] % MILLI) * (MICRO / MILLI);
@@ -1203,6 +1360,10 @@ static int ad7173_write_raw(struct iio_dev *indio_dev,
*
* This will cause the reading of CH1 to be actually done once every
* 200.16ms, an effective rate of 4.99sps.
+ *
+ * Both the sinc5 and sinc3 rates are set here so that if the filter
+ * type is changed, the requested rate will still be set (aside from
+ * rounding differences).
*/
case IIO_CHAN_INFO_SAMP_FREQ:
freq = val * MILLI + val2 / MILLI;
@@ -1211,7 +1372,8 @@ static int ad7173_write_raw(struct iio_dev *indio_dev,
break;
cfg = &st->channels[chan->address].cfg;
- cfg->odr = i;
+ cfg->sinc5_odr_index = i;
+ cfg->sinc3_odr_div = ad7173_sinc3_odr_div_from_odr(freq);
cfg->live = false;
break;
@@ -1228,17 +1390,88 @@ static int ad7173_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad7173_state *st = iio_priv(indio_dev);
- int i, ret;
+ u16 sinc3_count = 0;
+ u16 sinc3_div = 0;
+ int i, j, k, ret;
for (i = 0; i < indio_dev->num_channels; i++) {
- if (test_bit(i, scan_mask))
+ const struct ad7173_channel_config *cfg = &st->channels[i].cfg;
+
+ if (test_bit(i, scan_mask)) {
+ if (cfg->filter_type == AD7173_FILTER_SINC3) {
+ sinc3_count++;
+
+ if (sinc3_div == 0) {
+ sinc3_div = cfg->sinc3_odr_div;
+ } else if (sinc3_div != cfg->sinc3_odr_div) {
+ dev_err(&st->sd.spi->dev,
+ "All enabled channels must have the same sampling_frequency for sinc3 filter_type\n");
+ return -EINVAL;
+ }
+ }
+
ret = ad7173_set_channel(&st->sd, i);
- else
+ } else {
ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(i), 2, 0);
+ }
if (ret < 0)
return ret;
}
+ if (sinc3_count && sinc3_count < bitmap_weight(scan_mask, indio_dev->num_channels)) {
+ dev_err(&st->sd.spi->dev,
+ "All enabled channels must have sinc3 filter_type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * On some chips, there are more channels that setups, so if there were
+ * more unique setups requested than the number of available slots,
+ * ad7173_set_channel() will have written over some of the slots. We
+ * can detect this by making sure each assigned cfg_slot matches the
+ * requested configuration. If it doesn't, we know that the slot was
+ * overwritten by a different channel.
+ */
+ for_each_set_bit(i, scan_mask, indio_dev->num_channels) {
+ const struct ad7173_channel_config *cfg1, *cfg2;
+
+ cfg1 = &st->channels[i].cfg;
+
+ for_each_set_bit(j, scan_mask, indio_dev->num_channels) {
+ cfg2 = &st->channels[j].cfg;
+
+ /*
+ * Only compare configs that are assigned to the same
+ * SETUP_SEL slot and don't compare channel to itself.
+ */
+ if (i == j || cfg1->cfg_slot != cfg2->cfg_slot)
+ continue;
+
+ /*
+ * If we find two different configs trying to use the
+ * same SETUP_SEL slot, then we know that the that we
+ * have too many unique configurations requested for
+ * the available slots and at least one was overwritten.
+ */
+ if (!ad7173_is_setup_equal(cfg1, cfg2)) {
+ /*
+ * At this point, there isn't a way to tell
+ * which setups are actually programmed in the
+ * ADC anymore, so we could read them back to
+ * see, but it is simpler to just turn off all
+ * of the live flags so that everything gets
+ * reprogramed on the next attempt read a sample.
+ */
+ for (k = 0; k < st->num_channels; k++)
+ st->channels[k].cfg.live = false;
+
+ dev_err(&st->sd.spi->dev,
+ "Too many unique channel configurations requested for scan\n");
+ return -EINVAL;
+ }
+ }
+ }
+
return 0;
}
@@ -1333,7 +1566,7 @@ static const struct iio_chan_spec ad7173_channel_template = {
.storagebits = 32,
.endianness = IIO_BE,
},
- .ext_info = ad7173_calibsys_ext_info,
+ .ext_info = ad7173_chan_spec_ext_info,
};
static const struct iio_chan_spec ad7173_temp_iio_channel_template = {
@@ -1349,6 +1582,7 @@ static const struct iio_chan_spec ad7173_temp_iio_channel_template = {
.storagebits = 32,
.endianness = IIO_BE,
},
+ .ext_info = ad7173_temp_chan_spec_ext_info,
};
static void ad7173_disable_regulators(void *data)
@@ -1589,12 +1823,21 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
chan_st_priv->cfg.bipolar = false;
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF;
- chan_st_priv->cfg.odr = st->info->odr_start_value;
+ chan_st_priv->cfg.sinc3_odr_div = ad7173_sinc3_odr_div_from_odr(
+ st->info->sinc5_data_rates[st->info->odr_start_value]
+ );
+ chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value;
+ chan_st_priv->cfg.filter_type = AD7173_FILTER_SINC5_SINC1;
chan_st_priv->cfg.openwire_comp_chan = -1;
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
if (st->info->data_reg_only_16bit)
chan_arr[chan_index].scan_type = ad4113_scan_type;
+ if (ad_sigma_delta_has_spi_offload(&st->sd)) {
+ chan_arr[chan_index].scan_type.storagebits = 32;
+ chan_arr[chan_index].scan_type.endianness = IIO_CPU;
+ }
+
chan_index++;
}
@@ -1656,7 +1899,11 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
chan->scan_index = chan_index;
chan->channel = ain[0];
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
- chan_st_priv->cfg.odr = st->info->odr_start_value;
+ chan_st_priv->cfg.sinc3_odr_div = ad7173_sinc3_odr_div_from_odr(
+ st->info->sinc5_data_rates[st->info->odr_start_value]
+ );
+ chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value;
+ chan_st_priv->cfg.filter_type = AD7173_FILTER_SINC5_SINC1;
chan_st_priv->cfg.openwire_comp_chan = -1;
chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar");
@@ -1685,6 +1932,12 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
if (st->info->data_reg_only_16bit)
chan_arr[chan_index].scan_type = ad4113_scan_type;
+ /* Assuming SPI offload is ad411x_ad717x HDL project. */
+ if (ad_sigma_delta_has_spi_offload(&st->sd)) {
+ chan_arr[chan_index].scan_type.storagebits = 32;
+ chan_arr[chan_index].scan_type.endianness = IIO_CPU;
+ }
+
chan_index++;
}
return 0;
@@ -1717,8 +1970,7 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
ret = devm_add_action_or_reset(dev, ad7173_disable_regulators, st);
if (ret)
- return dev_err_probe(dev, ret,
- "Failed to add regulators disable action\n");
+ return ret;
ret = device_property_match_property_string(dev, "clock-names",
ad7173_clk_sel,
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index 6f7034b6c266..fa251dc1aae6 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -873,6 +873,7 @@ static const struct ad7380_chip_info adaq4381_4_chip_info = {
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
+ .max_conversion_rate_hz = 4 * MEGA,
};
static const struct spi_offload_config ad7380_offload_config = {
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index aea734aa06bd..1bec6657394c 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -6,6 +6,7 @@
* Copyright 2010 Analog Devices Inc.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -27,22 +28,24 @@
struct ad7476_state;
struct ad7476_chip_info {
- unsigned int int_vref_uv;
+ unsigned int int_vref_mv;
struct iio_chan_spec channel[2];
- /* channels used when convst gpio is defined */
- struct iio_chan_spec convst_channel[2];
void (*reset)(struct ad7476_state *);
+ void (*conversion_pre_op)(struct ad7476_state *st);
+ void (*conversion_post_op)(struct ad7476_state *st);
bool has_vref;
bool has_vdrive;
+ bool convstart_required;
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
- struct regulator *ref_reg;
struct gpio_desc *convst_gpio;
struct spi_transfer xfer;
struct spi_message msg;
+ struct iio_chan_spec channel[2];
+ int scale_mv;
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
@@ -52,40 +55,29 @@ struct ad7476_state {
unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
};
-enum ad7476_supported_device_ids {
- ID_AD7091,
- ID_AD7091R,
- ID_AD7273,
- ID_AD7274,
- ID_AD7276,
- ID_AD7277,
- ID_AD7278,
- ID_AD7466,
- ID_AD7467,
- ID_AD7468,
- ID_AD7475,
- ID_AD7495,
- ID_AD7940,
- ID_ADC081S,
- ID_ADC101S,
- ID_ADC121S,
- ID_ADS7866,
- ID_ADS7867,
- ID_ADS7868,
- ID_LTC2314_14,
-};
-
static void ad7091_convst(struct ad7476_state *st)
{
if (!st->convst_gpio)
return;
- gpiod_set_value(st->convst_gpio, 0);
+ gpiod_set_value_cansleep(st->convst_gpio, 0);
udelay(1); /* CONVST pulse width: 10 ns min */
- gpiod_set_value(st->convst_gpio, 1);
+ gpiod_set_value_cansleep(st->convst_gpio, 1);
udelay(1); /* Conversion time: 650 ns max */
}
+static void bd79105_convst_disable(struct ad7476_state *st)
+{
+ gpiod_set_value_cansleep(st->convst_gpio, 0);
+}
+
+static void bd79105_convst_enable(struct ad7476_state *st)
+{
+ gpiod_set_value_cansleep(st->convst_gpio, 1);
+ /* Worst case, 2790 ns required for conversion */
+ ndelay(2790);
+}
+
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -93,7 +85,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
struct ad7476_state *st = iio_priv(indio_dev);
int b_sent;
- ad7091_convst(st);
+ if (st->chip_info->conversion_pre_op)
+ st->chip_info->conversion_pre_op(st);
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
@@ -102,6 +95,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
iio_push_to_buffers_with_ts(indio_dev, st->data, sizeof(st->data),
iio_get_time_ns(indio_dev));
done:
+ if (st->chip_info->conversion_post_op)
+ st->chip_info->conversion_post_op(st);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -117,12 +112,16 @@ static int ad7476_scan_direct(struct ad7476_state *st)
{
int ret;
- ad7091_convst(st);
+ if (st->chip_info->conversion_pre_op)
+ st->chip_info->conversion_pre_op(st);
ret = spi_sync(st->spi, &st->msg);
if (ret)
return ret;
+ if (st->chip_info->conversion_post_op)
+ st->chip_info->conversion_post_op(st);
+
return be16_to_cpup((__be16 *)st->data);
}
@@ -134,7 +133,6 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
{
int ret;
struct ad7476_state *st = iio_priv(indio_dev);
- int scale_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
@@ -145,18 +143,11 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- *val = (ret >> st->chip_info->channel[0].scan_type.shift) &
- GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
+ *val = (ret >> chan->scan_type.shift) &
+ GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- if (st->ref_reg) {
- scale_uv = regulator_get_voltage(st->ref_reg);
- if (scale_uv < 0)
- return scale_uv;
- } else {
- scale_uv = st->chip_info->int_vref_uv;
- }
- *val = scale_uv / 1000;
+ *val = st->scale_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -185,125 +176,147 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
-#define AD7091R_CONVST_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), \
- BIT(IIO_CHAN_INFO_RAW))
#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
-static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
- [ID_AD7091] = {
- .channel[0] = AD7091R_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .convst_channel[0] = AD7091R_CONVST_CHAN(12),
- .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .reset = ad7091_reset,
- },
- [ID_AD7091R] = {
- .channel[0] = AD7091R_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .convst_channel[0] = AD7091R_CONVST_CHAN(12),
- .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .int_vref_uv = 2500000,
- .has_vref = true,
- .reset = ad7091_reset,
- },
- [ID_AD7273] = {
- .channel[0] = AD7940_CHAN(10),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .has_vref = true,
- },
- [ID_AD7274] = {
- .channel[0] = AD7940_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .has_vref = true,
- },
- [ID_AD7276] = {
- .channel[0] = AD7940_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7277] = {
- .channel[0] = AD7940_CHAN(10),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7278] = {
- .channel[0] = AD7940_CHAN(8),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7466] = {
- .channel[0] = AD7476_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7467] = {
- .channel[0] = AD7476_CHAN(10),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7468] = {
- .channel[0] = AD7476_CHAN(8),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_AD7475] = {
- .channel[0] = AD7476_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .has_vref = true,
- .has_vdrive = true,
- },
- [ID_AD7495] = {
- .channel[0] = AD7476_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .int_vref_uv = 2500000,
- .has_vdrive = true,
- },
- [ID_AD7940] = {
- .channel[0] = AD7940_CHAN(14),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADC081S] = {
- .channel[0] = ADC081S_CHAN(8),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADC101S] = {
- .channel[0] = ADC081S_CHAN(10),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADC121S] = {
- .channel[0] = ADC081S_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADS7866] = {
- .channel[0] = ADS786X_CHAN(12),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADS7867] = {
- .channel[0] = ADS786X_CHAN(10),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_ADS7868] = {
- .channel[0] = ADS786X_CHAN(8),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- },
- [ID_LTC2314_14] = {
- .channel[0] = AD7940_CHAN(14),
- .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .has_vref = true,
- },
+static const struct ad7476_chip_info ad7091_chip_info = {
+ .channel[0] = AD7091R_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .conversion_pre_op = ad7091_convst,
+ .reset = ad7091_reset,
};
-static const struct iio_info ad7476_info = {
- .read_raw = &ad7476_read_raw,
+static const struct ad7476_chip_info ad7091r_chip_info = {
+ .channel[0] = AD7091R_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .conversion_pre_op = ad7091_convst,
+ .int_vref_mv = 2500,
+ .has_vref = true,
+ .reset = ad7091_reset,
};
-static void ad7476_reg_disable(void *data)
-{
- struct regulator *reg = data;
+static const struct ad7476_chip_info ad7273_chip_info = {
+ .channel[0] = AD7940_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+};
- regulator_disable(reg);
-}
+static const struct ad7476_chip_info ad7274_chip_info = {
+ .channel[0] = AD7940_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+};
+
+static const struct ad7476_chip_info ad7276_chip_info = {
+ .channel[0] = AD7940_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7277_chip_info = {
+ .channel[0] = AD7940_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7278_chip_info = {
+ .channel[0] = AD7940_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7466_chip_info = {
+ .channel[0] = AD7476_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7467_chip_info = {
+ .channel[0] = AD7476_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7468_chip_info = {
+ .channel[0] = AD7476_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ad7475_chip_info = {
+ .channel[0] = AD7476_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+ .has_vdrive = true,
+};
+
+static const struct ad7476_chip_info ad7495_chip_info = {
+ .channel[0] = AD7476_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .int_vref_mv = 2500,
+ .has_vdrive = true,
+};
+
+static const struct ad7476_chip_info ad7940_chip_info = {
+ .channel[0] = AD7940_CHAN(14),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info adc081s_chip_info = {
+ .channel[0] = ADC081S_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info adc101s_chip_info = {
+ .channel[0] = ADC081S_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info adc121s_chip_info = {
+ .channel[0] = ADC081S_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ads7866_chip_info = {
+ .channel[0] = ADS786X_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ads7867_chip_info = {
+ .channel[0] = ADS786X_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ads7868_chip_info = {
+ .channel[0] = ADS786X_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct ad7476_chip_info ltc2314_14_chip_info = {
+ .channel[0] = AD7940_CHAN(14),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+};
+
+static const struct ad7476_chip_info bd79105_chip_info = {
+ .channel[0] = AD7091R_CHAN(16),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ /*
+ * The BD79105 starts ADC data conversion when the CONVSTART line is
+ * set HIGH. The CONVSTART must be kept HIGH until the data has been
+ * read from the ADC.
+ */
+ .conversion_pre_op = bd79105_convst_enable,
+ .conversion_post_op = bd79105_convst_disable,
+ /* BD79105 won't do conversion without convstart */
+ .convstart_required = true,
+ .has_vref = true,
+ .has_vdrive = true,
+};
+
+static const struct iio_info ad7476_info = {
+ .read_raw = &ad7476_read_raw,
+};
static int ad7476_probe(struct spi_device *spi)
{
struct ad7476_state *st;
struct iio_dev *indio_dev;
- struct regulator *reg;
+ unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -311,61 +324,37 @@ static int ad7476_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->chip_info =
- &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- reg = devm_regulator_get(&spi->dev, "vcc");
- if (IS_ERR(reg))
- return PTR_ERR(reg);
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg);
- if (ret)
- return ret;
-
- /* Either vcc or vref (below) as appropriate */
- if (!st->chip_info->int_vref_uv)
- st->ref_reg = reg;
+ /* Use VCC for reference voltage if vref / internal vref aren't used */
+ if (!st->chip_info->int_vref_mv && !st->chip_info->has_vref) {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
+ if (ret < 0)
+ return ret;
+ st->scale_mv = ret / 1000;
+ } else {
+ ret = devm_regulator_get_enable(&spi->dev, "vcc");
+ if (ret < 0)
+ return ret;
+ }
if (st->chip_info->has_vref) {
-
- /* If a device has an internal reference vref is optional */
- if (st->chip_info->int_vref_uv) {
- reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (IS_ERR(reg) && (PTR_ERR(reg) != -ENODEV))
- return PTR_ERR(reg);
- } else {
- reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(reg))
- return PTR_ERR(reg);
- }
-
- if (!IS_ERR(reg)) {
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev,
- ad7476_reg_disable,
- reg);
- if (ret)
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0) {
+ /* Vref is optional if a device has an internal reference */
+ if (!st->chip_info->int_vref_mv || ret != -ENODEV)
return ret;
- st->ref_reg = reg;
} else {
- /*
- * Can only get here if device supports both internal
- * and external reference, but the regulator connected
- * to the external reference is not connected.
- * Set the reference regulator pointer to NULL to
- * indicate this.
- */
- st->ref_reg = NULL;
+ st->scale_mv = ret / 1000;
}
}
+ if (!st->scale_mv)
+ st->scale_mv = st->chip_info->int_vref_mv;
+
if (st->chip_info->has_vdrive) {
ret = devm_regulator_get_enable(&spi->dev, "vdrive");
if (ret)
@@ -378,20 +367,35 @@ static int ad7476_probe(struct spi_device *spi)
if (IS_ERR(st->convst_gpio))
return PTR_ERR(st->convst_gpio);
+ if (st->chip_info->convstart_required && !st->convst_gpio)
+ return dev_err_probe(&spi->dev, -EINVAL, "No convstart GPIO\n");
+
+ /*
+ * This will never happen. Unless someone changes the channel specs
+ * in this driver. And if someone does, without changing the loop
+ * below, then we'd better immediately produce a big fat error, before
+ * the change proceeds from that developer's table.
+ */
+ static_assert(ARRAY_SIZE(st->channel) == ARRAY_SIZE(st->chip_info->channel));
+ for (i = 0; i < ARRAY_SIZE(st->channel); i++) {
+ st->channel[i] = st->chip_info->channel[i];
+ if (st->convst_gpio)
+ __set_bit(IIO_CHAN_INFO_RAW,
+ &st->channel[i].info_mask_separate);
+ }
+
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = st->chip_info->channel;
- indio_dev->num_channels = 2;
+ indio_dev->channels = st->channel;
+ indio_dev->num_channels = ARRAY_SIZE(st->channel);
indio_dev->info = &ad7476_info;
- if (st->convst_gpio)
- indio_dev->channels = st->chip_info->convst_channel;
/* Setup default message */
st->xfer.rx_buf = &st->data;
- st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
+ st->xfer.len = indio_dev->channels[0].scan_type.storagebits / 8;
spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &st->msg);
@@ -408,41 +412,42 @@ static int ad7476_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7476_id[] = {
- { "ad7091", ID_AD7091 },
- { "ad7091r", ID_AD7091R },
- { "ad7273", ID_AD7273 },
- { "ad7274", ID_AD7274 },
- { "ad7276", ID_AD7276},
- { "ad7277", ID_AD7277 },
- { "ad7278", ID_AD7278 },
- { "ad7466", ID_AD7466 },
- { "ad7467", ID_AD7467 },
- { "ad7468", ID_AD7468 },
- { "ad7475", ID_AD7475 },
- { "ad7476", ID_AD7466 },
- { "ad7476a", ID_AD7466 },
- { "ad7477", ID_AD7467 },
- { "ad7477a", ID_AD7467 },
- { "ad7478", ID_AD7468 },
- { "ad7478a", ID_AD7468 },
- { "ad7495", ID_AD7495 },
- { "ad7910", ID_AD7467 },
- { "ad7920", ID_AD7466 },
- { "ad7940", ID_AD7940 },
- { "adc081s", ID_ADC081S },
- { "adc101s", ID_ADC101S },
- { "adc121s", ID_ADC121S },
- { "ads7866", ID_ADS7866 },
- { "ads7867", ID_ADS7867 },
- { "ads7868", ID_ADS7868 },
+ { "ad7091", (kernel_ulong_t)&ad7091_chip_info },
+ { "ad7091r", (kernel_ulong_t)&ad7091r_chip_info },
+ { "ad7273", (kernel_ulong_t)&ad7273_chip_info },
+ { "ad7274", (kernel_ulong_t)&ad7274_chip_info },
+ { "ad7276", (kernel_ulong_t)&ad7276_chip_info },
+ { "ad7277", (kernel_ulong_t)&ad7277_chip_info },
+ { "ad7278", (kernel_ulong_t)&ad7278_chip_info },
+ { "ad7466", (kernel_ulong_t)&ad7466_chip_info },
+ { "ad7467", (kernel_ulong_t)&ad7467_chip_info },
+ { "ad7468", (kernel_ulong_t)&ad7468_chip_info },
+ { "ad7475", (kernel_ulong_t)&ad7475_chip_info },
+ { "ad7476", (kernel_ulong_t)&ad7466_chip_info },
+ { "ad7476a", (kernel_ulong_t)&ad7466_chip_info },
+ { "ad7477", (kernel_ulong_t)&ad7467_chip_info },
+ { "ad7477a", (kernel_ulong_t)&ad7467_chip_info },
+ { "ad7478", (kernel_ulong_t)&ad7468_chip_info },
+ { "ad7478a", (kernel_ulong_t)&ad7468_chip_info },
+ { "ad7495", (kernel_ulong_t)&ad7495_chip_info },
+ { "ad7910", (kernel_ulong_t)&ad7467_chip_info },
+ { "ad7920", (kernel_ulong_t)&ad7466_chip_info },
+ { "ad7940", (kernel_ulong_t)&ad7940_chip_info },
+ { "adc081s", (kernel_ulong_t)&adc081s_chip_info },
+ { "adc101s", (kernel_ulong_t)&adc101s_chip_info },
+ { "adc121s", (kernel_ulong_t)&adc121s_chip_info },
+ { "ads7866", (kernel_ulong_t)&ads7866_chip_info },
+ { "ads7867", (kernel_ulong_t)&ads7867_chip_info },
+ { "ads7868", (kernel_ulong_t)&ads7868_chip_info },
+ { "bd79105", (kernel_ulong_t)&bd79105_chip_info },
/*
* The ROHM BU79100G is identical to the TI's ADS7866 from the software
* point of view. The binding document mandates the ADS7866 to be
* marked as a fallback for the BU79100G, but we still need the SPI ID
* here to make the module loading work.
*/
- { "bu79100g", ID_ADS7866 },
- { "ltc2314-14", ID_LTC2314_14 },
+ { "bu79100g", (kernel_ulong_t)&ads7866_chip_info },
+ { "ltc2314-14", (kernel_ulong_t)&ltc2314_14_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index ca8fa91796ca..872c88d0c86c 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -217,7 +217,7 @@ struct ad7768_state {
struct spi_device *spi;
struct regmap *regmap;
struct regmap *regmap24;
- struct regulator *vref;
+ int vref_uv;
struct regulator_dev *vcm_rdev;
unsigned int vcm_output_sel;
struct clk *mclk;
@@ -687,8 +687,6 @@ static int ad7768_set_freq(struct ad7768_state *st,
int ret;
freq = clamp(freq, 50, 1024000);
- if (freq == 0)
- return -EINVAL;
mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio);
/* Find the closest match for the desired sampling frequency */
@@ -776,7 +774,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
{
struct ad7768_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
- int scale_uv, ret, temp;
+ int ret, temp;
scan_type = iio_get_current_scan_type(indio_dev, chan);
if (IS_ERR(scan_type))
@@ -797,11 +795,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- scale_uv = regulator_get_voltage(st->vref);
- if (scale_uv < 0)
- return scale_uv;
-
- *val = (scale_uv * 2) / 1000;
+ *val = (st->vref_uv * 2) / 1000;
*val2 = scan_type->realbits;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -1134,13 +1128,6 @@ static const struct iio_trigger_ops ad7768_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
-static void ad7768_regulator_disable(void *data)
-{
- struct ad7768_state *st = data;
-
- regulator_disable(st->vref);
-}
-
static int ad7768_set_channel_label(struct iio_dev *indio_dev,
int num_channels)
{
@@ -1372,19 +1359,11 @@ static int ad7768_probe(struct spi_device *spi)
return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24),
"Failed to initialize regmap24");
- st->vref = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->vref))
- return PTR_ERR(st->vref);
-
- ret = regulator_enable(st->vref);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified vref supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&spi->dev, ad7768_regulator_disable, st);
- if (ret)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get VREF voltage\n");
+ st->vref_uv = ret;
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
if (IS_ERR(st->mclk))
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
index 845adc510239..aac5049c9a07 100644
--- a/drivers/iio/adc/ad7779.c
+++ b/drivers/iio/adc/ad7779.c
@@ -25,6 +25,7 @@
#include <linux/units.h>
#include <linux/iio/iio.h>
+#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
@@ -145,6 +146,7 @@ struct ad7779_state {
struct completion completion;
unsigned int sampling_freq;
enum ad7779_filter filter_enabled;
+ struct iio_backend *back;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -630,12 +632,38 @@ static int ad7779_reset(struct iio_dev *indio_dev, struct gpio_desc *reset_gpio)
return ret;
}
+static int ad7779_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ unsigned int c;
+ int ret;
+
+ for (c = 0; c < AD7779_NUM_CHANNELS; c++) {
+ if (test_bit(c, scan_mask))
+ ret = iio_backend_chan_enable(st->back, c);
+ else
+ ret = iio_backend_chan_disable(st->back, c);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct iio_info ad7779_info = {
.read_raw = ad7779_read_raw,
.write_raw = ad7779_write_raw,
.debugfs_reg_access = &ad7779_reg_access,
};
+static const struct iio_info ad7779_info_data = {
+ .read_raw = ad7779_read_raw,
+ .write_raw = ad7779_write_raw,
+ .debugfs_reg_access = &ad7779_reg_access,
+ .update_scan_mode = &ad7779_update_scan_mode,
+};
+
static const struct iio_enum ad7779_filter_enum = {
.items = ad7779_filter_type,
.num_items = ARRAY_SIZE(ad7779_filter_type),
@@ -752,6 +780,125 @@ static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio)
return 0;
}
+static int ad7779_set_data_lines(struct iio_dev *indio_dev, u32 num_lanes)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4)
+ return -EINVAL;
+
+ ret = ad7779_set_sampling_frequency(st, num_lanes * AD7779_DEFAULT_SAMPLING_1LINE);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_num_lanes_set(st->back, num_lanes);
+ if (ret)
+ return ret;
+
+ return ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
+ AD7779_DOUT_FORMAT_MSK,
+ FIELD_PREP(AD7779_DOUT_FORMAT_MSK, 2 - ilog2(num_lanes)));
+}
+
+static int ad7779_setup_channels(struct iio_dev *indio_dev, const struct ad7779_state *st)
+{
+ struct iio_chan_spec *channels;
+ struct device *dev = &st->spi->dev;
+
+ channels = devm_kmemdup_array(dev, st->chip_info->channels,
+ ARRAY_SIZE(ad7779_channels),
+ sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(ad7779_channels); i++)
+ channels[i].scan_type.endianness = IIO_CPU;
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7779_channels);
+
+ return 0;
+}
+
+static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev *indio_dev)
+{
+ int ret;
+ struct device *dev = &st->spi->dev;
+
+ indio_dev->info = &ad7779_info;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7779_channels);
+
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad7779_trigger_ops;
+
+ iio_trigger_set_drvdata(st->trig, st);
+
+ ret = devm_request_irq(dev, st->spi->irq, iio_trigger_generic_data_rdy_poll,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name,
+ st->trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "request IRQ %d failed\n",
+ st->spi->irq);
+
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ init_completion(&st->completion);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7779_trigger_handler,
+ &ad7779_buffer_setup_ops);
+ if (ret)
+ return ret;
+
+ return ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
+ AD7779_DCLK_CLK_DIV_MSK,
+ FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7));
+}
+
+static int ad7779_setup_backend(struct ad7779_state *st, struct iio_dev *indio_dev)
+{
+ struct device *dev = &st->spi->dev;
+ int ret;
+ u32 num_lanes;
+
+ indio_dev->info = &ad7779_info_data;
+
+ ret = ad7779_setup_channels(indio_dev, st);
+ if (ret)
+ return ret;
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return dev_err_probe(dev, PTR_ERR(st->back),
+ "failed to get iio backend");
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ num_lanes = 4;
+ ret = device_property_read_u32(dev, "adi,num-lanes", &num_lanes);
+ if (ret && ret != -EINVAL)
+ return ret;
+
+ return ad7779_set_data_lines(indio_dev, num_lanes);
+}
+
static int ad7779_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -760,9 +907,6 @@ static int ad7779_probe(struct spi_device *spi)
struct device *dev = &spi->dev;
int ret = -EINVAL;
- if (!spi->irq)
- return dev_err_probe(dev, ret, "DRDY irq not present\n");
-
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -804,45 +948,12 @@ static int ad7779_probe(struct spi_device *spi)
return ret;
indio_dev->name = st->chip_info->name;
- indio_dev->info = &ad7779_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = st->chip_info->channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7779_channels);
- st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
- iio_device_id(indio_dev));
- if (!st->trig)
- return -ENOMEM;
-
- st->trig->ops = &ad7779_trigger_ops;
-
- iio_trigger_set_drvdata(st->trig, st);
-
- ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll,
- IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name,
- st->trig);
- if (ret)
- return dev_err_probe(dev, ret, "request IRQ %d failed\n",
- st->spi->irq);
-
- ret = devm_iio_trigger_register(dev, st->trig);
- if (ret)
- return ret;
-
- indio_dev->trig = iio_trigger_get(st->trig);
-
- init_completion(&st->completion);
-
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
- &iio_pollfunc_store_time,
- &ad7779_trigger_handler,
- &ad7779_buffer_setup_ops);
- if (ret)
- return ret;
-
- ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
- AD7779_DCLK_CLK_DIV_MSK,
- FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7));
+ if (device_property_present(dev, "io-backends"))
+ ret = ad7779_setup_backend(st, indio_dev);
+ else
+ ret = ad7779_setup_without_backend(st, indio_dev);
if (ret)
return ret;
@@ -936,3 +1047,4 @@ module_spi_driver(ad7779_driver);
MODULE_AUTHOR("Ramona Alexandra Nechita <ramona.nechita@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7779 ADC");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 202561cad401..b35d299a3977 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -316,10 +316,8 @@ static int ad7949_spi_probe(struct spi_device *spi)
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*ad7949_adc));
- if (!indio_dev) {
- dev_err(dev, "can not allocate iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
indio_dev->info = &ad7949_spi_info;
indio_dev->name = spi_get_device_id(spi)->name;
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 9c02f9199139..108bb22162ef 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -114,11 +114,13 @@ struct ad799x_chip_config {
* @num_channels: number of channels
* @noirq_config: device configuration w/o IRQ
* @irq_config: device configuration w/IRQ
+ * @has_vref: device supports external reference voltage
*/
struct ad799x_chip_info {
int num_channels;
const struct ad799x_chip_config noirq_config;
const struct ad799x_chip_config irq_config;
+ bool has_vref;
};
struct ad799x_state {
@@ -604,6 +606,7 @@ static const struct iio_event_spec ad799x_events[] = {
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
[ad7991] = {
.num_channels = 5,
+ .has_vref = true,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
@@ -617,6 +620,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
[ad7995] = {
.num_channels = 5,
+ .has_vref = true,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
@@ -630,6 +634,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
[ad7999] = {
.num_channels = 5,
+ .has_vref = true,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 8),
@@ -687,6 +692,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
[ad7994] = {
.num_channels = 5,
+ .has_vref = true,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
@@ -809,32 +815,22 @@ static int ad799x_probe(struct i2c_client *client)
return ret;
/* check if an external reference is supplied */
- st->vref = devm_regulator_get_optional(&client->dev, "vref");
-
- if (IS_ERR(st->vref)) {
- if (PTR_ERR(st->vref) == -ENODEV) {
+ if (chip_info->has_vref) {
+ st->vref = devm_regulator_get_optional(&client->dev, "vref");
+ ret = PTR_ERR_OR_ZERO(st->vref);
+ if (ret) {
+ if (ret != -ENODEV)
+ goto error_disable_reg;
st->vref = NULL;
dev_info(&client->dev, "Using VCC reference voltage\n");
- } else {
- ret = PTR_ERR(st->vref);
- goto error_disable_reg;
}
- }
- if (st->vref) {
- /*
- * Use external reference voltage if supported by hardware.
- * This is optional if voltage / regulator present, use VCC otherwise.
- */
- if ((st->id == ad7991) || (st->id == ad7995) || (st->id == ad7999)) {
+ if (st->vref) {
dev_info(&client->dev, "Using external reference voltage\n");
extra_config |= AD7991_REF_SEL;
ret = regulator_enable(st->vref);
if (ret)
goto error_disable_reg;
- } else {
- st->vref = NULL;
- dev_warn(&client->dev, "Supplied reference not supported\n");
}
}
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
new file mode 100644
index 000000000000..94e05e11abd9
--- /dev/null
+++ b/drivers/iio/adc/ade9000.c
@@ -0,0 +1,1799 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/**
+ * ADE9000 driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/events.h>
+#include <linux/interrupt.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+
+/* Address of ADE9000 registers */
+#define ADE9000_REG_AIGAIN 0x000
+#define ADE9000_REG_AVGAIN 0x00B
+#define ADE9000_REG_AIRMSOS 0x00C
+#define ADE9000_REG_AVRMSOS 0x00D
+#define ADE9000_REG_APGAIN 0x00E
+#define ADE9000_REG_AWATTOS 0x00F
+#define ADE9000_REG_AVAROS 0x010
+#define ADE9000_REG_AFVAROS 0x012
+#define ADE9000_REG_CONFIG0 0x060
+#define ADE9000_REG_DICOEFF 0x072
+#define ADE9000_REG_AI_PCF 0x20A
+#define ADE9000_REG_AV_PCF 0x20B
+#define ADE9000_REG_AIRMS 0x20C
+#define ADE9000_REG_AVRMS 0x20D
+#define ADE9000_REG_AWATT 0x210
+#define ADE9000_REG_AVAR 0x211
+#define ADE9000_REG_AVA 0x212
+#define ADE9000_REG_AFVAR 0x214
+#define ADE9000_REG_APF 0x216
+#define ADE9000_REG_BI_PCF 0x22A
+#define ADE9000_REG_BV_PCF 0x22B
+#define ADE9000_REG_BIRMS 0x22C
+#define ADE9000_REG_BVRMS 0x22D
+#define ADE9000_REG_CI_PCF 0x24A
+#define ADE9000_REG_CV_PCF 0x24B
+#define ADE9000_REG_CIRMS 0x24C
+#define ADE9000_REG_CVRMS 0x24D
+#define ADE9000_REG_AWATT_ACC 0x2E5
+#define ADE9000_REG_AWATTHR_LO 0x2E6
+#define ADE9000_REG_AVAHR_LO 0x2FA
+#define ADE9000_REG_AFVARHR_LO 0x30E
+#define ADE9000_REG_BWATTHR_LO 0x322
+#define ADE9000_REG_BVAHR_LO 0x336
+#define ADE9000_REG_BFVARHR_LO 0x34A
+#define ADE9000_REG_CWATTHR_LO 0x35E
+#define ADE9000_REG_CVAHR_LO 0x372
+#define ADE9000_REG_CFVARHR_LO 0x386
+#define ADE9000_REG_STATUS0 0x402
+#define ADE9000_REG_STATUS1 0x403
+#define ADE9000_REG_MASK0 0x405
+#define ADE9000_REG_MASK1 0x406
+#define ADE9000_REG_EVENT_MASK 0x407
+#define ADE9000_REG_VLEVEL 0x40F
+#define ADE9000_REG_DIP_LVL 0x410
+#define ADE9000_REG_DIPA 0x411
+#define ADE9000_REG_DIPB 0x412
+#define ADE9000_REG_DIPC 0x413
+#define ADE9000_REG_SWELL_LVL 0x414
+#define ADE9000_REG_SWELLA 0x415
+#define ADE9000_REG_SWELLB 0x416
+#define ADE9000_REG_SWELLC 0x417
+#define ADE9000_REG_APERIOD 0x418
+#define ADE9000_REG_BPERIOD 0x419
+#define ADE9000_REG_CPERIOD 0x41A
+#define ADE9000_REG_RUN 0x480
+#define ADE9000_REG_CONFIG1 0x481
+#define ADE9000_REG_ACCMODE 0x492
+#define ADE9000_REG_CONFIG3 0x493
+#define ADE9000_REG_ZXTOUT 0x498
+#define ADE9000_REG_ZX_LP_SEL 0x49A
+#define ADE9000_REG_WFB_CFG 0x4A0
+#define ADE9000_REG_WFB_PG_IRQEN 0x4A1
+#define ADE9000_REG_WFB_TRG_CFG 0x4A2
+#define ADE9000_REG_WFB_TRG_STAT 0x4A3
+#define ADE9000_REG_CONFIG2 0x4AF
+#define ADE9000_REG_EP_CFG 0x4B0
+#define ADE9000_REG_EGY_TIME 0x4B2
+#define ADE9000_REG_PGA_GAIN 0x4B9
+#define ADE9000_REG_VERSION 0x4FE
+#define ADE9000_REG_WF_BUFF 0x800
+#define ADE9000_REG_WF_HALF_BUFF 0xC00
+
+#define ADE9000_REG_ADDR_MASK GENMASK(15, 4)
+#define ADE9000_REG_READ_BIT_MASK BIT(3)
+
+#define ADE9000_WF_CAP_EN_MASK BIT(4)
+#define ADE9000_WF_CAP_SEL_MASK BIT(5)
+#define ADE9000_WF_MODE_MASK GENMASK(7, 6)
+#define ADE9000_WF_SRC_MASK GENMASK(9, 8)
+#define ADE9000_WF_IN_EN_MASK BIT(12)
+
+/* External reference selection bit in CONFIG1 */
+#define ADE9000_EXT_REF_MASK BIT(15)
+
+/*
+ * Configuration registers
+ */
+#define ADE9000_PGA_GAIN 0x0000
+
+/* Default configuration */
+
+#define ADE9000_CONFIG0 0x00000000
+
+/* CF3/ZX pin outputs Zero crossing, CF4 = DREADY */
+#define ADE9000_CONFIG1 0x000E
+
+/* Default High pass corner frequency of 1.25Hz */
+#define ADE9000_CONFIG2 0x0A00
+
+/* Peak and overcurrent detection disabled */
+#define ADE9000_CONFIG3 0x0000
+
+/*
+ * 50Hz operation, 3P4W Wye configuration, signed accumulation
+ * 3P4W Wye = 3-Phase 4-Wire star configuration (3 phases + neutral wire)
+ * Clear bit 8 i.e. ACCMODE=0x00xx for 50Hz operation
+ * ACCMODE=0x0x9x for 3Wire delta when phase B is used as reference
+ * 3Wire delta = 3-Phase 3-Wire triangle configuration (3 phases, no neutral)
+ */
+#define ADE9000_ACCMODE 0x0000
+#define ADE9000_ACCMODE_60HZ 0x0100
+
+/*Line period and zero crossing obtained from VA */
+#define ADE9000_ZX_LP_SEL 0x0000
+
+/* Interrupt mask values for initialization */
+#define ADE9000_MASK0_ALL_INT_DIS 0
+#define ADE9000_MASK1_ALL_INT_DIS 0x00000000
+
+/* Events disabled */
+#define ADE9000_EVENT_DISABLE 0x00000000
+
+/*
+ * Assuming Vnom=1/2 of full scale.
+ * Refer to Technical reference manual for detailed calculations.
+ */
+#define ADE9000_VLEVEL 0x0022EA28
+
+/* Set DICOEFF= 0xFFFFE000 when integrator is enabled */
+#define ADE9000_DICOEFF 0x00000000
+
+/* DSP ON */
+#define ADE9000_RUN_ON 0xFFFFFFFF
+
+/*
+ * Energy Accumulation Settings
+ * Enable energy accumulation, accumulate samples at 8ksps
+ * latch energy accumulation after EGYRDY
+ * If accumulation is changed to half line cycle mode, change EGY_TIME
+ */
+#define ADE9000_EP_CFG 0x0011
+
+/* Accumulate 4000 samples */
+#define ADE9000_EGY_TIME 7999
+
+/*
+ * Constant Definitions
+ * ADE9000 FDSP: 8000sps, ADE9000 FDSP: 4000sps
+ */
+#define ADE9000_FDSP 4000
+#define ADE9000_DEFAULT_CLK_FREQ_HZ 24576000
+#define ADE9000_WFB_CFG 0x03E9
+#define ADE9000_WFB_PAGE_SIZE 128
+#define ADE9000_WFB_NR_OF_PAGES 16
+#define ADE9000_WFB_MAX_CHANNELS 8
+#define ADE9000_WFB_BYTES_IN_SAMPLE 4
+#define ADE9000_WFB_SAMPLES_IN_PAGE \
+ (ADE9000_WFB_PAGE_SIZE / ADE9000_WFB_MAX_CHANNELS)
+#define ADE9000_WFB_MAX_SAMPLES_CHAN \
+ (ADE9000_WFB_SAMPLES_IN_PAGE * ADE9000_WFB_NR_OF_PAGES)
+#define ADE9000_WFB_FULL_BUFF_NR_SAMPLES \
+ (ADE9000_WFB_PAGE_SIZE * ADE9000_WFB_NR_OF_PAGES)
+#define ADE9000_WFB_FULL_BUFF_SIZE \
+ (ADE9000_WFB_FULL_BUFF_NR_SAMPLES * ADE9000_WFB_BYTES_IN_SAMPLE)
+
+#define ADE9000_SWRST_BIT BIT(0)
+
+/* Status and Mask register bits*/
+#define ADE9000_ST0_WFB_TRIG_BIT BIT(16)
+#define ADE9000_ST0_PAGE_FULL_BIT BIT(17)
+#define ADE9000_ST0_EGYRDY BIT(0)
+
+#define ADE9000_ST1_ZXTOVA_BIT BIT(6)
+#define ADE9000_ST1_ZXTOVB_BIT BIT(7)
+#define ADE9000_ST1_ZXTOVC_BIT BIT(8)
+#define ADE9000_ST1_ZXVA_BIT BIT(9)
+#define ADE9000_ST1_ZXVB_BIT BIT(10)
+#define ADE9000_ST1_ZXVC_BIT BIT(11)
+#define ADE9000_ST1_ZXIA_BIT BIT(13)
+#define ADE9000_ST1_ZXIB_BIT BIT(14)
+#define ADE9000_ST1_ZXIC_BIT BIT(15)
+#define ADE9000_ST1_RSTDONE_BIT BIT(16)
+#define ADE9000_ST1_SEQERR_BIT BIT(18)
+#define ADE9000_ST1_SWELLA_BIT BIT(20)
+#define ADE9000_ST1_SWELLB_BIT BIT(21)
+#define ADE9000_ST1_SWELLC_BIT BIT(22)
+#define ADE9000_ST1_DIPA_BIT BIT(23)
+#define ADE9000_ST1_DIPB_BIT BIT(24)
+#define ADE9000_ST1_DIPC_BIT BIT(25)
+#define ADE9000_ST1_ERROR0_BIT BIT(28)
+#define ADE9000_ST1_ERROR1_BIT BIT(29)
+#define ADE9000_ST1_ERROR2_BIT BIT(30)
+#define ADE9000_ST1_ERROR3_BIT BIT(31)
+#define ADE9000_ST_ERROR \
+ (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \
+ ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3)
+#define ADE9000_ST1_CROSSING_FIRST 6
+#define ADE9000_ST1_CROSSING_DEPTH 25
+
+#define ADE9000_WFB_TRG_DIP_BIT BIT(0)
+#define ADE9000_WFB_TRG_SWELL_BIT BIT(1)
+#define ADE9000_WFB_TRG_ZXIA_BIT BIT(3)
+#define ADE9000_WFB_TRG_ZXIB_BIT BIT(4)
+#define ADE9000_WFB_TRG_ZXIC_BIT BIT(5)
+#define ADE9000_WFB_TRG_ZXVA_BIT BIT(6)
+#define ADE9000_WFB_TRG_ZXVB_BIT BIT(7)
+#define ADE9000_WFB_TRG_ZXVC_BIT BIT(8)
+
+/* Stop when waveform buffer is full */
+#define ADE9000_WFB_FULL_MODE 0x0
+/* Continuous fill—stop only on enabled trigger events */
+#define ADE9000_WFB_EN_TRIG_MODE 0x1
+/* Continuous filling—center capture around enabled trigger events */
+#define ADE9000_WFB_C_EN_TRIG_MODE 0x2
+/* Continuous fill—used as streaming mode for continuous data output */
+#define ADE9000_WFB_STREAMING_MODE 0x3
+
+#define ADE9000_LAST_PAGE_BIT BIT(15)
+#define ADE9000_MIDDLE_PAGE_BIT BIT(7)
+
+/*
+ * Full scale Codes referred from Datasheet. Respective digital codes are
+ * produced when ADC inputs are at full scale.
+ */
+#define ADE9000_RMS_FULL_SCALE_CODES 52866837
+#define ADE9000_WATT_FULL_SCALE_CODES 20694066
+#define ADE9000_PCF_FULL_SCALE_CODES 74770000
+
+/* Phase and channel definitions */
+#define ADE9000_PHASE_A_NR 0
+#define ADE9000_PHASE_B_NR 1
+#define ADE9000_PHASE_C_NR 2
+
+#define ADE9000_SCAN_POS_IA BIT(0)
+#define ADE9000_SCAN_POS_VA BIT(1)
+#define ADE9000_SCAN_POS_IB BIT(2)
+#define ADE9000_SCAN_POS_VB BIT(3)
+#define ADE9000_SCAN_POS_IC BIT(4)
+#define ADE9000_SCAN_POS_VC BIT(5)
+
+/* Waveform buffer configuration values */
+enum ade9000_wfb_cfg {
+ ADE9000_WFB_CFG_ALL_CHAN = 0x0,
+ ADE9000_WFB_CFG_IA_VA = 0x1,
+ ADE9000_WFB_CFG_IB_VB = 0x2,
+ ADE9000_WFB_CFG_IC_VC = 0x3,
+ ADE9000_WFB_CFG_IA = 0x8,
+ ADE9000_WFB_CFG_VA = 0x9,
+ ADE9000_WFB_CFG_IB = 0xA,
+ ADE9000_WFB_CFG_VB = 0xB,
+ ADE9000_WFB_CFG_IC = 0xC,
+ ADE9000_WFB_CFG_VC = 0xD,
+};
+
+#define ADE9000_PHASE_B_POS_BIT BIT(5)
+#define ADE9000_PHASE_C_POS_BIT BIT(6)
+
+#define ADE9000_MAX_PHASE_NR 3
+#define AD9000_CHANNELS_PER_PHASE 10
+
+/*
+ * Calculate register address for multi-phase device.
+ * Phase A (chan 0): base address + 0x00
+ * Phase B (chan 1): base address + 0x20
+ * Phase C (chan 2): base address + 0x40
+ */
+#define ADE9000_ADDR_ADJUST(addr, chan) \
+ (((chan) == 0 ? 0 : (chan) == 1 ? 2 : 4) << 4 | (addr))
+
+struct ade9000_state {
+ struct completion reset_completion;
+ struct mutex lock; /* Protects SPI transactions */
+ u8 wf_src;
+ u32 wfb_trg;
+ u8 wfb_nr_activ_chan;
+ u32 wfb_nr_samples;
+ struct spi_device *spi;
+ struct clk *clkin;
+ struct spi_transfer xfer[2];
+ struct spi_message spi_msg;
+ struct regmap *regmap;
+ union{
+ u8 byte[ADE9000_WFB_FULL_BUFF_SIZE];
+ __be32 word[ADE9000_WFB_FULL_BUFF_NR_SAMPLES];
+ } rx_buff __aligned(IIO_DMA_MINALIGN);
+ u8 tx_buff[2] __aligned(IIO_DMA_MINALIGN);
+ unsigned int bulk_read_buf[2];
+};
+
+struct ade9000_irq1_event {
+ u32 bit_mask;
+ enum iio_chan_type chan_type;
+ u32 channel;
+ enum iio_event_type event_type;
+ enum iio_event_direction event_dir;
+};
+
+static const struct ade9000_irq1_event ade9000_irq1_events[] = {
+ { ADE9000_ST1_ZXVA_BIT, IIO_VOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_ZXIA_BIT, IIO_CURRENT, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_ZXVB_BIT, IIO_VOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_ZXIB_BIT, IIO_CURRENT, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_ZXVC_BIT, IIO_VOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_ZXIC_BIT, IIO_CURRENT, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER },
+ { ADE9000_ST1_SWELLA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING },
+ { ADE9000_ST1_SWELLB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING },
+ { ADE9000_ST1_SWELLC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING },
+ { ADE9000_ST1_DIPA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING },
+ { ADE9000_ST1_DIPB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING },
+ { ADE9000_ST1_DIPC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING },
+};
+
+/* Voltage events (zero crossing on instantaneous voltage) */
+static const struct iio_event_spec ade9000_voltage_events[] = {
+ {
+ /* Zero crossing detection - datasheet: ZXV interrupts */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+/* Current events (zero crossing on instantaneous current) */
+static const struct iio_event_spec ade9000_current_events[] = {
+ {
+ /* Zero crossing detection - datasheet: ZXI interrupts */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+/* RMS voltage events (swell/sag detection on RMS values) */
+static const struct iio_event_spec ade9000_rms_voltage_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING, /* RMS swell detection */
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING, /* RMS sag/dip detection */
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
+static const char * const ade9000_filter_type_items[] = {
+ "sinc4", "sinc4+lp",
+};
+
+static const int ade9000_filter_type_values[] = {
+ 0, 2,
+};
+
+static int ade9000_filter_type_get(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u32 val;
+ int ret;
+ unsigned int i;
+
+ ret = regmap_read(st->regmap, ADE9000_REG_WFB_CFG, &val);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(ADE9000_WF_SRC_MASK, val);
+
+ for (i = 0; i < ARRAY_SIZE(ade9000_filter_type_values); i++) {
+ if (ade9000_filter_type_values[i] == val)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ade9000_filter_type_set(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int index)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ int ret, val;
+
+ if (index >= ARRAY_SIZE(ade9000_filter_type_values))
+ return -EINVAL;
+
+ val = ade9000_filter_type_values[index];
+
+ /* Update the WFB_CFG register with the new filter type */
+ ret = regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG,
+ ADE9000_WF_SRC_MASK,
+ FIELD_PREP(ADE9000_WF_SRC_MASK, val));
+ if (ret)
+ return ret;
+
+ /* Update cached value */
+ st->wf_src = val;
+
+ return 0;
+}
+
+static const struct iio_enum ade9000_filter_type_enum = {
+ .items = ade9000_filter_type_items,
+ .num_items = ARRAY_SIZE(ade9000_filter_type_items),
+ .get = ade9000_filter_type_get,
+ .set = ade9000_filter_type_set,
+};
+
+static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type_enum),
+ { }
+};
+
+#define ADE9000_CURRENT_CHANNEL(num) { \
+ .type = IIO_CURRENT, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AI_PCF, num), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), \
+ .event_spec = ade9000_current_events, \
+ .num_event_specs = ARRAY_SIZE(ade9000_current_events), \
+ .scan_index = num, \
+ .indexed = 1, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADE9000_VOLTAGE_CHANNEL(num) { \
+ .type = IIO_VOLTAGE, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AV_PCF, num), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_FREQUENCY), \
+ .event_spec = ade9000_voltage_events, \
+ .num_event_specs = ARRAY_SIZE(ade9000_voltage_events), \
+ .scan_index = num + 1, /* interleave with current channels */ \
+ .indexed = 1, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ .endianness = IIO_BE, \
+ }, \
+ .ext_info = ade9000_ext_info, \
+}
+
+#define ADE9000_ALTCURRENT_RMS_CHANNEL(num) { \
+ .type = IIO_ALTCURRENT, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMS, 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_ALTVOLTAGE_RMS_CHANNEL(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), \
+ .event_spec = ade9000_rms_voltage_events, \
+ .num_event_specs = ARRAY_SIZE(ade9000_rms_voltage_events), \
+ .scan_index = -1 \
+}
+
+#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \
+ .type = IIO_POWER, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AWATT, num), \
+ .channel2 = IIO_MOD_ACTIVE, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), \
+ .scan_index = -1 \
+}
+
+#define ADE9000_POWER_REACTIVE_CHANNEL(num) { \
+ .type = IIO_POWER, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVAR, num), \
+ .channel2 = IIO_MOD_REACTIVE, \
+ .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_APPARENT_CHANNEL(num) { \
+ .type = IIO_POWER, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVA, num), \
+ .channel2 = IIO_MOD_APPARENT, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = -1 \
+}
+
+ #define ADE9000_ENERGY_ACTIVE_CHANNEL(num, addr) { \
+ .type = IIO_ENERGY, \
+ .channel = num, \
+ .address = addr, \
+ .channel2 = IIO_MOD_ACTIVE, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .scan_index = -1 \
+}
+
+#define ADE9000_ENERGY_APPARENT_CHANNEL(num, addr) { \
+ .type = IIO_ENERGY, \
+ .channel = num, \
+ .address = addr, \
+ .channel2 = IIO_MOD_APPARENT, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .scan_index = -1 \
+}
+
+#define ADE9000_ENERGY_REACTIVE_CHANNEL(num, addr) { \
+ .type = IIO_ENERGY, \
+ .channel = num, \
+ .address = addr, \
+ .channel2 = IIO_MOD_REACTIVE, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .scan_index = -1 \
+}
+
+#define ADE9000_POWER_FACTOR_CHANNEL(num) { \
+ .type = IIO_POWER, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_APF, num), \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_POWERFACTOR), \
+ .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),
+};
+
+static const struct reg_sequence ade9000_initialization_sequence[] = {
+ { ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN },
+ { ADE9000_REG_CONFIG0, ADE9000_CONFIG0 },
+ { ADE9000_REG_CONFIG1, ADE9000_CONFIG1 },
+ { ADE9000_REG_CONFIG2, ADE9000_CONFIG2 },
+ { ADE9000_REG_CONFIG3, ADE9000_CONFIG3 },
+ { ADE9000_REG_ACCMODE, ADE9000_ACCMODE },
+ { ADE9000_REG_ZX_LP_SEL, ADE9000_ZX_LP_SEL },
+ { ADE9000_REG_MASK0, ADE9000_MASK0_ALL_INT_DIS },
+ { ADE9000_REG_MASK1, ADE9000_MASK1_ALL_INT_DIS },
+ { ADE9000_REG_EVENT_MASK, ADE9000_EVENT_DISABLE },
+ { ADE9000_REG_WFB_CFG, ADE9000_WFB_CFG },
+ { ADE9000_REG_VLEVEL, ADE9000_VLEVEL },
+ { ADE9000_REG_DICOEFF, ADE9000_DICOEFF },
+ { ADE9000_REG_EGY_TIME, ADE9000_EGY_TIME },
+ { ADE9000_REG_EP_CFG, ADE9000_EP_CFG },
+ /* Clear all pending status bits by writing 1s */
+ { ADE9000_REG_STATUS0, GENMASK(31, 0) },
+ { ADE9000_REG_STATUS1, GENMASK(31, 0) },
+ { ADE9000_REG_RUN, ADE9000_RUN_ON }
+};
+
+static int ade9000_spi_write_reg(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ade9000_state *st = context;
+ u8 tx_buf[6];
+ u16 addr;
+ int ret, len;
+
+ guard(mutex)(&st->lock);
+
+ addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, reg);
+ put_unaligned_be16(addr, tx_buf);
+
+ if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) {
+ put_unaligned_be16(val, &tx_buf[2]);
+ len = 4;
+ } else {
+ put_unaligned_be32(val, &tx_buf[2]);
+ len = 6;
+ }
+
+ ret = spi_write_then_read(st->spi, tx_buf, len, NULL, 0);
+ if (ret)
+ dev_err(&st->spi->dev, "problem when writing register 0x%x\n", reg);
+
+ return ret;
+}
+
+static int ade9000_spi_read_reg(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ade9000_state *st = context;
+ u8 tx_buf[2];
+ u8 rx_buf[4];
+ u16 addr;
+ int ret, rx_len;
+
+ guard(mutex)(&st->lock);
+
+ addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, reg) |
+ ADE9000_REG_READ_BIT_MASK;
+
+ put_unaligned_be16(addr, tx_buf);
+
+ /* Skip CRC bytes - only read actual data */
+ if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION)
+ rx_len = 2;
+ else
+ rx_len = 4;
+
+ ret = spi_write_then_read(st->spi, tx_buf, 2, rx_buf, rx_len);
+ if (ret) {
+ dev_err(&st->spi->dev, "error reading register 0x%x\n", reg);
+ return ret;
+ }
+
+ if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION)
+ *val = get_unaligned_be16(rx_buf);
+ else
+ *val = get_unaligned_be32(rx_buf);
+
+ return 0;
+}
+
+static bool ade9000_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ /* Interrupt/error status registers - volatile */
+ case ADE9000_REG_STATUS0:
+ case ADE9000_REG_STATUS1:
+ return true;
+ default:
+ /* All other registers are non-volatile */
+ return false;
+ }
+}
+
+static void ade9000_configure_scan(struct iio_dev *indio_dev, u32 wfb_addr)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u16 addr;
+
+ addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, wfb_addr) |
+ ADE9000_REG_READ_BIT_MASK;
+
+ put_unaligned_be16(addr, st->tx_buff);
+
+ st->xfer[0].tx_buf = &st->tx_buff[0];
+ st->xfer[0].len = 2;
+
+ st->xfer[1].rx_buf = st->rx_buff.byte;
+
+ /* Always use streaming mode */
+ st->xfer[1].len = (st->wfb_nr_samples / 2) * 4;
+
+ spi_message_init_with_transfers(&st->spi_msg, st->xfer, ARRAY_SIZE(st->xfer));
+}
+
+static int ade9000_iio_push_streaming(struct iio_dev *indio_dev)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 current_page, i;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = spi_sync(st->spi, &st->spi_msg);
+ if (ret) {
+ dev_err_ratelimited(dev, "SPI fail in trigger handler\n");
+ return ret;
+ }
+
+ /* In streaming mode, only half the buffer is filled per interrupt */
+ for (i = 0; i < st->wfb_nr_samples / 2; i += st->wfb_nr_activ_chan)
+ iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]);
+
+ ret = regmap_read(st->regmap, ADE9000_REG_WFB_PG_IRQEN, &current_page);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 WFB read fail\n");
+ return ret;
+ }
+
+ if (current_page & ADE9000_MIDDLE_PAGE_BIT) {
+ ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN,
+ ADE9000_LAST_PAGE_BIT);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 WFB write fail\n");
+ return ret;
+ }
+
+ ade9000_configure_scan(indio_dev,
+ ADE9000_REG_WF_HALF_BUFF);
+ } else {
+ ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN,
+ ADE9000_MIDDLE_PAGE_BIT);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 WFB write fail");
+ return IRQ_HANDLED;
+ }
+
+ ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF);
+ }
+
+ return 0;
+}
+
+static int ade9000_iio_push_buffer(struct iio_dev *indio_dev)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ int ret;
+ u32 i;
+
+ guard(mutex)(&st->lock);
+
+ ret = spi_sync(st->spi, &st->spi_msg);
+ if (ret) {
+ dev_err_ratelimited(&st->spi->dev,
+ "SPI fail in trigger handler\n");
+ return ret;
+ }
+
+ for (i = 0; i < st->wfb_nr_samples; i += st->wfb_nr_activ_chan)
+ iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]);
+
+ return 0;
+}
+
+static irqreturn_t ade9000_irq0_thread(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct ade9000_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 handled_irq = 0;
+ u32 interrupts, status;
+ int ret;
+
+ ret = regmap_read(st->regmap, ADE9000_REG_STATUS0, &status);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 read status fail\n");
+ return IRQ_HANDLED;
+ }
+
+ ret = regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 read mask fail\n");
+ return IRQ_HANDLED;
+ }
+
+ if ((status & ADE9000_ST0_PAGE_FULL_BIT) &&
+ (interrupts & ADE9000_ST0_PAGE_FULL_BIT)) {
+ /* Always use streaming mode */
+ ret = ade9000_iio_push_streaming(indio_dev);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 IIO push fail\n");
+ return IRQ_HANDLED;
+ }
+
+ handled_irq |= ADE9000_ST0_PAGE_FULL_BIT;
+ }
+
+ if ((status & ADE9000_ST0_WFB_TRIG_BIT) &&
+ (interrupts & ADE9000_ST0_WFB_TRIG_BIT)) {
+ ret = regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG,
+ ADE9000_WF_CAP_EN_MASK, 0);
+ if (ret) {
+ dev_err_ratelimited(dev, "IRQ0 WFB fail\n");
+ return IRQ_HANDLED;
+ }
+
+ if (iio_buffer_enabled(indio_dev)) {
+ ret = ade9000_iio_push_buffer(indio_dev);
+ if (ret) {
+ dev_err_ratelimited(dev,
+ "IRQ0 IIO push fail @ WFB TRIG\n");
+ return IRQ_HANDLED;
+ }
+ }
+
+ handled_irq |= ADE9000_ST0_WFB_TRIG_BIT;
+ }
+
+ ret = regmap_write(st->regmap, ADE9000_REG_STATUS0, handled_irq);
+ if (ret)
+ dev_err_ratelimited(dev, "IRQ0 write status fail\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ade9000_irq1_thread(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct ade9000_state *st = iio_priv(indio_dev);
+ unsigned int bit = ADE9000_ST1_CROSSING_FIRST;
+ s64 timestamp = iio_get_time_ns(indio_dev);
+ u32 handled_irq = 0;
+ u32 interrupts, result, status, tmp;
+ DECLARE_BITMAP(interrupt_bits, ADE9000_ST1_CROSSING_DEPTH);
+ const struct ade9000_irq1_event *event;
+ int ret, i;
+
+ if (!completion_done(&st->reset_completion)) {
+ ret = regmap_read(st->regmap, ADE9000_REG_STATUS1, &result);
+ if (ret) {
+ dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n");
+ return IRQ_HANDLED;
+ }
+
+ if (result & ADE9000_ST1_RSTDONE_BIT) {
+ complete(&st->reset_completion);
+ /* Clear the reset done status bit */
+ ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, ADE9000_ST1_RSTDONE_BIT);
+ if (ret)
+ dev_err_ratelimited(&st->spi->dev,
+ "IRQ1 clear reset status fail\n");
+ } else {
+ dev_err_ratelimited(&st->spi->dev,
+ "Error testing reset done\n");
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ ret = regmap_read(st->regmap, ADE9000_REG_STATUS1, &status);
+ if (ret) {
+ dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n");
+ return IRQ_HANDLED;
+ }
+
+ ret = regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts);
+ if (ret) {
+ dev_err_ratelimited(&st->spi->dev, "IRQ1 read mask fail\n");
+ return IRQ_HANDLED;
+ }
+
+ bitmap_from_arr32(interrupt_bits, &interrupts, ADE9000_ST1_CROSSING_DEPTH);
+ for_each_set_bit_from(bit, interrupt_bits,
+ ADE9000_ST1_CROSSING_DEPTH) {
+ tmp = status & BIT(bit);
+ if (!tmp)
+ continue;
+
+ event = NULL;
+
+ /* Find corresponding event in lookup table */
+ for (i = 0; i < ARRAY_SIZE(ade9000_irq1_events); i++) {
+ if (ade9000_irq1_events[i].bit_mask == tmp) {
+ event = &ade9000_irq1_events[i];
+ break;
+ }
+ }
+
+ if (event) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(event->chan_type,
+ event->channel,
+ event->event_type,
+ event->event_dir),
+ timestamp);
+ }
+ handled_irq |= tmp;
+ }
+
+ ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, handled_irq);
+ if (ret)
+ dev_err_ratelimited(&st->spi->dev, "IRQ1 write status fail\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ade9000_dready_thread(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+
+ /* Handle data ready interrupt from C4/EVENT/DREADY pin */
+ if (!iio_device_claim_buffer_mode(indio_dev)) {
+ ade9000_iio_push_buffer(indio_dev);
+ iio_device_release_buffer_mode(indio_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ade9000_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ unsigned int measured;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ if (chan->type == IIO_VOLTAGE) {
+ int period_reg;
+ int period;
+
+ switch (chan->channel) {
+ case ADE9000_PHASE_A_NR:
+ period_reg = ADE9000_REG_APERIOD;
+ break;
+ case ADE9000_PHASE_B_NR:
+ period_reg = ADE9000_REG_BPERIOD;
+ break;
+ case ADE9000_PHASE_C_NR:
+ period_reg = ADE9000_REG_CPERIOD;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = regmap_read(st->regmap, period_reg, &period);
+ if (ret)
+ return ret;
+ /*
+ * Frequency = (4MHz * 65536) / (PERIOD + 1)
+ * 4MHz = ADC sample rate, 65536 = 2^16 period register scaling
+ * See ADE9000 datasheet section on period measurement
+ */
+ *val = 4000 * 65536;
+ *val2 = period + 1;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type == IIO_ENERGY) {
+ u16 lo_reg = chan->address;
+
+ ret = regmap_bulk_read(st->regmap, lo_reg,
+ st->bulk_read_buf, 2);
+ if (ret)
+ return ret;
+
+ *val = st->bulk_read_buf[0]; /* Lower 32 bits */
+ *val2 = st->bulk_read_buf[1]; /* Upper 32 bits */
+ return IIO_VAL_INT_64;
+ }
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, chan->address, &measured);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ *val = measured;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_POWERFACTOR:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, chan->address, &measured);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ *val = measured;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_CURRENT:
+ case IIO_VOLTAGE:
+ case IIO_ALTVOLTAGE:
+ case IIO_ALTCURRENT:
+ switch (chan->address) {
+ case ADE9000_REG_AI_PCF:
+ case ADE9000_REG_AV_PCF:
+ case ADE9000_REG_BI_PCF:
+ case ADE9000_REG_BV_PCF:
+ case ADE9000_REG_CI_PCF:
+ case ADE9000_REG_CV_PCF:
+ *val = 1;
+ *val2 = ADE9000_PCF_FULL_SCALE_CODES;
+ return IIO_VAL_FRACTIONAL;
+ case ADE9000_REG_AIRMS:
+ case ADE9000_REG_AVRMS:
+ case ADE9000_REG_BIRMS:
+ case ADE9000_REG_BVRMS:
+ case ADE9000_REG_CIRMS:
+ case ADE9000_REG_CVRMS:
+ *val = 1;
+ *val2 = ADE9000_RMS_FULL_SCALE_CODES;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_POWER:
+ *val = 1;
+ *val2 = ADE9000_WATT_FULL_SCALE_CODES;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ade9000_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u32 tmp;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ switch (chan->type) {
+ case IIO_CURRENT:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMSOS,
+ chan->channel), val);
+ case IIO_VOLTAGE:
+ case IIO_ALTVOLTAGE:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMSOS,
+ chan->channel), val);
+ case IIO_POWER:
+ tmp = chan->address;
+ tmp &= ~ADE9000_PHASE_B_POS_BIT;
+ tmp &= ~ADE9000_PHASE_C_POS_BIT;
+
+ switch (tmp) {
+ case ADE9000_REG_AWATTOS:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS,
+ chan->channel), val);
+ case ADE9000_REG_AVAR:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AVAROS,
+ chan->channel), val);
+ case ADE9000_REG_AFVAR:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AFVAROS,
+ chan->channel), val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBSCALE:
+ /*
+ * Calibration gain registers for fine-tuning measurements.
+ * These are separate from PGA gain and applied in the digital domain.
+ */
+ switch (chan->type) {
+ case IIO_CURRENT:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AIGAIN,
+ chan->channel), val);
+ case IIO_VOLTAGE:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_AVGAIN,
+ chan->channel), val);
+ case IIO_POWER:
+ return regmap_write(st->regmap,
+ ADE9000_ADDR_ADJUST(ADE9000_REG_APGAIN,
+ chan->channel), val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ /* Per-channel scales are read-only */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ade9000_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int tx_val,
+ unsigned int *rx_val)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+
+ if (rx_val)
+ return regmap_read(st->regmap, reg, rx_val);
+
+ return regmap_write(st->regmap, reg, tx_val);
+}
+
+static int ade9000_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u32 interrupts1;
+ int ret;
+
+ /* All events use MASK1 register */
+ ret = regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts1);
+ if (ret)
+ return ret;
+
+ switch (chan->channel) {
+ case ADE9000_PHASE_A_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXVA_BIT);
+ else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXIA_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING)
+ return !!(interrupts1 & ADE9000_ST1_SWELLA_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING)
+ return !!(interrupts1 & ADE9000_ST1_DIPA_BIT);
+ dev_err_ratelimited(&indio_dev->dev,
+ "Invalid channel type %d or direction %d for phase A\n", chan->type, dir);
+ return -EINVAL;
+ case ADE9000_PHASE_B_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXVB_BIT);
+ else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXIB_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING)
+ return !!(interrupts1 & ADE9000_ST1_SWELLB_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING)
+ return !!(interrupts1 & ADE9000_ST1_DIPB_BIT);
+ dev_err_ratelimited(&indio_dev->dev,
+ "Invalid channel type %d or direction %d for phase B\n", chan->type, dir);
+ return -EINVAL;
+ case ADE9000_PHASE_C_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXVC_BIT);
+ else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER)
+ return !!(interrupts1 & ADE9000_ST1_ZXIC_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING)
+ return !!(interrupts1 & ADE9000_ST1_SWELLC_BIT);
+ else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING)
+ return !!(interrupts1 & ADE9000_ST1_DIPC_BIT);
+ dev_err_ratelimited(&indio_dev->dev,
+ "Invalid channel type %d or direction %d for phase C\n", chan->type, dir);
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ade9000_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u32 bit_mask;
+ int ret;
+
+ /* Clear all pending events in STATUS1 register (write 1 to clear) */
+ ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, GENMASK(31, 0));
+ if (ret)
+ return ret;
+
+ /* Determine which interrupt bit to enable/disable */
+ switch (chan->channel) {
+ case ADE9000_PHASE_A_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXVA_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXVA_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVA_BIT;
+ } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXIA_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXIA_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIA_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) {
+ bit_mask = ADE9000_ST1_SWELLA_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) {
+ bit_mask = ADE9000_ST1_DIPA_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT;
+ } else {
+ dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or direction %d for phase A\n",
+ chan->type, dir);
+ return -EINVAL;
+ }
+ break;
+ case ADE9000_PHASE_B_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXVB_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXVB_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVB_BIT;
+ } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXIB_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXIB_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIB_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) {
+ bit_mask = ADE9000_ST1_SWELLB_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) {
+ bit_mask = ADE9000_ST1_DIPB_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT;
+ } else {
+ dev_err_ratelimited(&indio_dev->dev,
+ "Invalid channel type %d or direction %d for phase B\n",
+ chan->type, dir);
+ return -EINVAL;
+ }
+ break;
+ case ADE9000_PHASE_C_NR:
+ if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXVC_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXVC_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVC_BIT;
+ } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) {
+ bit_mask = ADE9000_ST1_ZXIC_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_ZXIC_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIC_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) {
+ bit_mask = ADE9000_ST1_SWELLC_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT;
+ } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) {
+ bit_mask = ADE9000_ST1_DIPC_BIT;
+ if (state)
+ st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT;
+ else
+ st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT;
+ } else {
+ dev_err_ratelimited(&indio_dev->dev,
+ "Invalid channel type %d or direction %d for phase C\n",
+ chan->type, dir);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set bits if enabling event, clear bits if disabling */
+ return regmap_assign_bits(st->regmap, ADE9000_REG_MASK1, bit_mask, state ? bit_mask : 0);
+}
+
+static int ade9000_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ return regmap_write(st->regmap, ADE9000_REG_DIP_LVL, val);
+ case IIO_EV_DIR_RISING:
+ return regmap_write(st->regmap, ADE9000_REG_SWELL_LVL, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ade9000_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ unsigned int data;
+ int ret;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_read(st->regmap, ADE9000_REG_DIP_LVL, &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_RISING:
+ ret = regmap_read(st->regmap, ADE9000_REG_SWELL_LVL, &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ade9000_waveform_buffer_config(struct iio_dev *indio_dev)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ u32 wfb_cfg_val;
+ u32 active_scans;
+
+ bitmap_to_arr32(&active_scans, indio_dev->active_scan_mask,
+ iio_get_masklength(indio_dev));
+
+ switch (active_scans) {
+ case ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA:
+ wfb_cfg_val = ADE9000_WFB_CFG_IA_VA;
+ st->wfb_nr_activ_chan = 2;
+ break;
+ case ADE9000_SCAN_POS_IB | ADE9000_SCAN_POS_VB:
+ wfb_cfg_val = ADE9000_WFB_CFG_IB_VB;
+ st->wfb_nr_activ_chan = 2;
+ break;
+ case ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC:
+ wfb_cfg_val = ADE9000_WFB_CFG_IC_VC;
+ st->wfb_nr_activ_chan = 2;
+ break;
+ case ADE9000_SCAN_POS_IA:
+ wfb_cfg_val = ADE9000_WFB_CFG_IA;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case ADE9000_SCAN_POS_VA:
+ wfb_cfg_val = ADE9000_WFB_CFG_VA;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case ADE9000_SCAN_POS_IB:
+ wfb_cfg_val = ADE9000_WFB_CFG_IB;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case ADE9000_SCAN_POS_VB:
+ wfb_cfg_val = ADE9000_WFB_CFG_VB;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case ADE9000_SCAN_POS_IC:
+ wfb_cfg_val = ADE9000_WFB_CFG_IC;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case ADE9000_SCAN_POS_VC:
+ wfb_cfg_val = ADE9000_WFB_CFG_VC;
+ st->wfb_nr_activ_chan = 1;
+ break;
+ case (ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA | ADE9000_SCAN_POS_IB |
+ ADE9000_SCAN_POS_VB | ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC):
+ wfb_cfg_val = ADE9000_WFB_CFG_ALL_CHAN;
+ st->wfb_nr_activ_chan = 6;
+ break;
+ default:
+ dev_err(&st->spi->dev, "Unsupported combination of scans\n");
+ return -EINVAL;
+ }
+
+ wfb_cfg_val |= FIELD_PREP(ADE9000_WF_SRC_MASK, st->wf_src);
+
+ return regmap_write(st->regmap, ADE9000_REG_WFB_CFG, wfb_cfg_val);
+}
+
+static int ade9000_waveform_buffer_interrupt_setup(struct ade9000_state *st)
+{
+ int ret;
+
+ ret = regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0);
+ if (ret)
+ return ret;
+
+ /* Always use streaming mode setup */
+ ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN,
+ ADE9000_MIDDLE_PAGE_BIT);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0));
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(st->regmap, ADE9000_REG_MASK0,
+ ADE9000_ST0_PAGE_FULL_BIT);
+}
+
+static int ade9000_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ade9000_waveform_buffer_config(indio_dev);
+ if (ret)
+ return ret;
+
+ st->wfb_nr_samples = ADE9000_WFB_MAX_SAMPLES_CHAN * st->wfb_nr_activ_chan;
+
+ ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF);
+
+ ret = ade9000_waveform_buffer_interrupt_setup(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->regmap, ADE9000_REG_WFB_CFG,
+ ADE9000_WF_CAP_EN_MASK);
+ if (ret) {
+ dev_err(&st->spi->dev, "Post-enable waveform buffer enable fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ade9000_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ade9000_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 interrupts;
+ int ret;
+
+ ret = regmap_clear_bits(st->regmap, ADE9000_REG_WFB_CFG,
+ ADE9000_WF_CAP_EN_MASK);
+ if (ret) {
+ dev_err(dev, "Post-disable waveform buffer disable fail\n");
+ return ret;
+ }
+
+ ret = regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0);
+ if (ret)
+ return ret;
+
+ interrupts = ADE9000_ST0_WFB_TRIG_BIT | ADE9000_ST0_PAGE_FULL_BIT;
+
+ ret = regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts);
+ if (ret) {
+ dev_err(dev, "Post-disable update maks0 fail\n");
+ return ret;
+ }
+
+ return regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0));
+}
+
+static const struct iio_buffer_setup_ops ade9000_buffer_ops = {
+ .preenable = &ade9000_buffer_preenable,
+ .postdisable = &ade9000_buffer_postdisable,
+};
+
+static int ade9000_reset(struct ade9000_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct gpio_desc *gpio_reset;
+ int ret;
+
+ gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio_reset))
+ return PTR_ERR(gpio_reset);
+
+ /* Software reset via register if no GPIO available */
+ if (!gpio_reset) {
+ ret = regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1,
+ ADE9000_SWRST_BIT);
+ if (ret)
+ return ret;
+ fsleep(90);
+ return 0;
+ }
+
+ /* Hardware reset via GPIO */
+ fsleep(10);
+ gpiod_set_value_cansleep(gpio_reset, 0);
+ fsleep(50000);
+
+ /* Only wait for completion if IRQ1 is available to signal reset done */
+ if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >= 0) {
+ if (!wait_for_completion_timeout(&st->reset_completion,
+ msecs_to_jiffies(1000))) {
+ dev_err(dev, "Reset timeout after 1s\n");
+ return -ETIMEDOUT;
+ }
+ }
+ /* If no IRQ available, reset is already complete after the 50ms delay above */
+
+ return 0;
+}
+
+static int ade9000_setup(struct ade9000_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ ret = regmap_multi_reg_write(st->regmap, ade9000_initialization_sequence,
+ ARRAY_SIZE(ade9000_initialization_sequence));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write register sequence");
+
+ fsleep(2000);
+
+ return 0;
+}
+
+static const struct iio_info ade9000_info = {
+ .read_raw = ade9000_read_raw,
+ .write_raw = ade9000_write_raw,
+ .debugfs_reg_access = ade9000_reg_access,
+ .write_event_config = ade9000_write_event_config,
+ .read_event_config = ade9000_read_event_config,
+ .write_event_value = ade9000_write_event_value,
+ .read_event_value = ade9000_read_event_value,
+};
+
+static const struct regmap_config ade9000_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 32,
+ .max_register = 0x6bc,
+ .zero_flag_mask = true,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_read = ade9000_spi_read_reg,
+ .reg_write = ade9000_spi_write_reg,
+ .volatile_reg = ade9000_is_volatile_reg,
+};
+
+static int ade9000_setup_clkout(struct device *dev, struct ade9000_state *st)
+{
+ struct clk_hw *clkout_hw;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_COMMON_CLK))
+ return 0;
+
+ /*
+ * Only provide clock output when using external CMOS clock.
+ * When using crystal, CLKOUT is connected to crystal and shouldn't
+ * be used as clock provider for other devices.
+ */
+ if (!device_property_present(dev, "#clock-cells") || !st->clkin)
+ return 0;
+
+ /* CLKOUT passes through CLKIN with divider of 1 */
+ clkout_hw = devm_clk_hw_register_divider(dev, "clkout", __clk_get_name(st->clkin),
+ CLK_SET_RATE_PARENT, NULL, 0, 1, 0, NULL);
+ if (IS_ERR(clkout_hw))
+ return dev_err_probe(dev, PTR_ERR(clkout_hw), "Failed to register clkout");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, clkout_hw);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add clock provider");
+
+ return 0;
+}
+
+static int ade9000_request_irq(struct device *dev, const char *name,
+ irq_handler_t handler, void *dev_id)
+{
+ int irq, ret;
+
+ irq = fwnode_irq_get_byname(dev_fwnode(dev), name);
+ if (irq == -EINVAL)
+ return 0; /* interrupts are optional */
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get %s irq", name);
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request %s irq", name);
+
+ return 0;
+}
+
+static int ade9000_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ade9000_state *st;
+ struct regmap *regmap;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ regmap = devm_regmap_init(dev, NULL, st, &ade9000_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Unable to allocate ADE9000 regmap");
+
+ st->regmap = regmap;
+ st->spi = spi;
+
+ init_completion(&st->reset_completion);
+
+ ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ /* External CMOS clock input (optional - crystal can be used instead) */
+ st->clkin = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(st->clkin))
+ return dev_err_probe(dev, PTR_ERR(st->clkin), "Failed to get and enable clkin");
+
+ ret = ade9000_setup_clkout(dev, st);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "ade9000";
+ indio_dev->info = &ade9000_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->setup_ops = &ade9000_buffer_ops;
+
+ ret = devm_regulator_get_enable(&spi->dev, "vdd");
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get and enable vdd regulator\n");
+
+ indio_dev->channels = ade9000_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ade9000_channels);
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ &ade9000_buffer_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup IIO buffer");
+
+ ret = ade9000_reset(st);
+ if (ret)
+ return ret;
+
+ /* Configure reference selection if vref regulator is available */
+ ret = devm_regulator_get_enable_optional(dev, "vref");
+ if (ret != -ENODEV && ret >= 0) {
+ ret = regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1,
+ ADE9000_EXT_REF_MASK);
+ if (ret)
+ return ret;
+ } else if (ret < 0 && ret != -ENODEV) {
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable vref regulator\n");
+ }
+
+ ret = ade9000_setup(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+};
+
+static const struct spi_device_id ade9000_id[] = {
+ { "ade9000", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ade9000_id);
+
+static const struct of_device_id ade9000_of_match[] = {
+ { .compatible = "adi,ade9000" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ade9000_of_match);
+
+static struct spi_driver ade9000_driver = {
+ .driver = {
+ .name = "ade9000",
+ .of_match_table = ade9000_of_match,
+ },
+ .probe = ade9000_probe,
+ .id_table = ade9000_id,
+};
+module_spi_driver(ade9000_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADE9000");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index eb42e29960e4..14fa4238c2b9 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -618,6 +618,7 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
.chan_status = axi_adc_chan_status,
.interface_type_get = axi_adc_interface_type_get,
.oversampling_ratio_set = axi_adc_oversampling_ratio_set,
+ .num_lanes_set = axi_adc_num_lanes_set,
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
};
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index c3450246730e..b4c36e6a7490 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -896,7 +896,6 @@ static int at91_adc_config_emr(struct at91_adc_state *st,
emr |= osr | AT91_SAMA5D2_TRACKX(trackx);
at91_adc_writel(st, EMR, emr);
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
st->oversampling_ratio = oversampling_ratio;
@@ -971,7 +970,6 @@ static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN);
at91_adc_writel(st, TSMR, 0);
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return 0;
}
@@ -1142,10 +1140,8 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
at91_adc_configure_trigger_registers(st, state);
- if (!state) {
- pm_runtime_mark_last_busy(st->dev);
+ if (!state)
pm_runtime_put_autosuspend(st->dev);
- }
return 0;
}
@@ -1336,7 +1332,6 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
at91_adc_writel(st, IER, AT91_SAMA5D2_IER_DRDY);
pm_runtime_put:
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return ret;
}
@@ -1394,7 +1389,6 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
if (st->dma_st.dma_chan)
dmaengine_terminate_sync(st->dma_st.dma_chan);
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return 0;
@@ -1603,7 +1597,6 @@ static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq,
mr |= AT91_SAMA5D2_MR_TRACKTIM(tracktim);
at91_adc_writel(st, MR, mr);
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u, tracktim=%u\n",
@@ -1809,7 +1802,6 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
at91_adc_readl(st, LCDR);
pm_runtime_put:
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return ret;
}
@@ -1890,7 +1882,6 @@ static int at91_adc_read_temp(struct iio_dev *indio_dev,
restore_config:
/* Revert previous settings. */
at91_adc_temp_sensor_configure(st, false);
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
if (ret < 0)
return ret;
@@ -2465,7 +2456,6 @@ static int at91_adc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "version: %x\n",
readl_relaxed(st->base + st->soc_info.platform->layout->VERSION));
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return 0;
@@ -2567,7 +2557,6 @@ static int at91_adc_resume(struct device *dev)
at91_adc_configure_trigger_registers(st, true);
}
- pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return 0;
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index f258668b0dc7..6426c9e6ccc9 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -511,10 +511,8 @@ static int iproc_adc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(*adc_priv));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed to allocate iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
adc_priv = iio_priv(indio_dev);
platform_set_drvdata(pdev, indio_dev);
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index ba7cbd3b4822..d9ee2ea116a7 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -953,11 +953,9 @@ static int cpcap_adc_probe(struct platform_device *pdev)
int error;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*ddata));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed to allocate iio device\n");
-
+ if (!indio_dev)
return -ENOMEM;
- }
+
ddata = iio_priv(indio_dev);
ddata->ato = device_get_match_data(&pdev->dev);
if (!ddata->ato)
diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
index b99291ce2a45..625e3a8e4d03 100644
--- a/drivers/iio/adc/da9150-gpadc.c
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -308,10 +308,9 @@ static int da9150_gpadc_probe(struct platform_device *pdev)
int irq, ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
- if (!indio_dev) {
- dev_err(&pdev->dev, "Failed to allocate IIO device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
+
gpadc = iio_priv(indio_dev);
gpadc->da9150 = da9150;
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 5aea7644780f..eb902a946efe 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -584,10 +584,8 @@ static int dln2_adc_probe(struct platform_device *pdev)
int i, ret, chans;
indio_dev = devm_iio_device_alloc(dev, sizeof(*dln2));
- if (!indio_dev) {
- dev_err(dev, "failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
dln2 = iio_priv(indio_dev);
dln2->pdev = pdev;
@@ -628,10 +626,9 @@ static int dln2_adc_probe(struct platform_device *pdev)
dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
- if (!dln2->trig) {
- dev_err(dev, "failed to allocate trigger\n");
+ if (!dln2->trig)
return -ENOMEM;
- }
+
iio_trigger_set_drvdata(dln2->trig, dln2);
ret = devm_iio_trigger_register(dev, dln2->trig);
if (ret) {
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 4614cf848535..1484adff00df 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -19,11 +19,9 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/err.h>
-#include <linux/input.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
@@ -31,21 +29,14 @@
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
-#include <linux/platform_data/touchscreen-s3c2410.h>
-
/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
-#define ADC_V1_TSC(x) ((x) + 0x04)
#define ADC_V1_DLY(x) ((x) + 0x08)
#define ADC_V1_DATX(x) ((x) + 0x0C)
#define ADC_V1_DATY(x) ((x) + 0x10)
#define ADC_V1_UPDN(x) ((x) + 0x14)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
-#define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20)
-
-/* S3C2410 ADC registers definitions */
-#define ADC_S3C2410_MUX(x) ((x) + 0x18)
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
@@ -61,13 +52,8 @@
#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY (1u << 2)
-/* Bit definitions for S3C2410 ADC */
+/* Bit definitions for S3C2410 / S3C6410 ADC */
#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3)
-#define ADC_S3C2410_DATX_MASK 0x3FF
-#define ADC_S3C2416_CON_RES_SEL (1u << 3)
-
-/* touch screen always uses channel 0 */
-#define ADC_S3C2410_MUX_TS 0
/* ADCTSC Register Bits */
#define ADC_S3C2443_TSC_UD_SEN (1u << 8)
@@ -75,8 +61,6 @@
#define ADC_S3C2410_TSC_YP_SEN (1u << 6)
#define ADC_S3C2410_TSC_XM_SEN (1u << 5)
#define ADC_S3C2410_TSC_XP_SEN (1u << 4)
-#define ADC_S3C2410_TSC_PULL_UP_DISABLE (1u << 3)
-#define ADC_S3C2410_TSC_AUTO_PST (1u << 2)
#define ADC_S3C2410_TSC_XY_PST(x) (((x) & 0x3) << 0)
#define ADC_TSC_WAIT4INT (ADC_S3C2410_TSC_YM_SEN | \
@@ -84,12 +68,6 @@
ADC_S3C2410_TSC_XP_SEN | \
ADC_S3C2410_TSC_XY_PST(3))
-#define ADC_TSC_AUTOPST (ADC_S3C2410_TSC_YM_SEN | \
- ADC_S3C2410_TSC_YP_SEN | \
- ADC_S3C2410_TSC_XP_SEN | \
- ADC_S3C2410_TSC_AUTO_PST | \
- ADC_S3C2410_TSC_XY_PST(0))
-
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
@@ -121,14 +99,11 @@
struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
- struct input_dev *input;
void __iomem *regs;
struct regmap *pmu_map;
struct clk *clk;
struct clk *sclk;
unsigned int irq;
- unsigned int tsirq;
- unsigned int delay;
struct regulator *vdd;
struct completion completion;
@@ -136,12 +111,6 @@ struct exynos_adc {
u32 value;
unsigned int version;
- bool ts_enabled;
-
- bool read_ts;
- u32 ts_x;
- u32 ts_y;
-
/*
* Lock to protect from potential concurrent access to the
* completion callback during a manual conversion. For this driver
@@ -241,7 +210,7 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
writel(con1, ADC_V1_CON(info->regs));
/* set touchscreen delay */
- writel(info->delay, ADC_V1_DLY(info->regs));
+ writel(10000, ADC_V1_DLY(info->regs));
}
static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
@@ -307,53 +276,6 @@ static const struct exynos_adc_data exynos_adc_s5pv210_data = {
.start_conv = exynos_adc_v1_start_conv,
};
-static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
- unsigned long addr)
-{
- u32 con1;
-
- /* Enable 12 bit ADC resolution */
- con1 = readl(ADC_V1_CON(info->regs));
- con1 |= ADC_S3C2416_CON_RES_SEL;
- writel(con1, ADC_V1_CON(info->regs));
-
- /* Select channel for S3C2416 */
- writel(addr, ADC_S3C2410_MUX(info->regs));
-
- con1 = readl(ADC_V1_CON(info->regs));
- writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
-}
-
-static struct exynos_adc_data const exynos_adc_s3c2416_data = {
- .num_channels = MAX_ADC_V1_CHANNELS,
- .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
-
- .init_hw = exynos_adc_v1_init_hw,
- .exit_hw = exynos_adc_v1_exit_hw,
- .start_conv = exynos_adc_s3c2416_start_conv,
-};
-
-static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info,
- unsigned long addr)
-{
- u32 con1;
-
- /* Select channel for S3C2433 */
- writel(addr, ADC_S3C2410_MUX(info->regs));
-
- con1 = readl(ADC_V1_CON(info->regs));
- writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
-}
-
-static struct exynos_adc_data const exynos_adc_s3c2443_data = {
- .num_channels = MAX_ADC_V1_CHANNELS,
- .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
-
- .init_hw = exynos_adc_v1_init_hw,
- .exit_hw = exynos_adc_v1_exit_hw,
- .start_conv = exynos_adc_s3c2443_start_conv,
-};
-
static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
unsigned long addr)
{
@@ -365,15 +287,6 @@ static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
-static struct exynos_adc_data const exynos_adc_s3c24xx_data = {
- .num_channels = MAX_ADC_V1_CHANNELS,
- .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
-
- .init_hw = exynos_adc_v1_init_hw,
- .exit_hw = exynos_adc_v1_exit_hw,
- .start_conv = exynos_adc_s3c64xx_start_conv,
-};
-
static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
@@ -486,18 +399,6 @@ static const struct exynos_adc_data exynos7_adc_data = {
static const struct of_device_id exynos_adc_match[] = {
{
- .compatible = "samsung,s3c2410-adc",
- .data = &exynos_adc_s3c24xx_data,
- }, {
- .compatible = "samsung,s3c2416-adc",
- .data = &exynos_adc_s3c2416_data,
- }, {
- .compatible = "samsung,s3c2440-adc",
- .data = &exynos_adc_s3c24xx_data,
- }, {
- .compatible = "samsung,s3c2443-adc",
- .data = &exynos_adc_s3c2443_data,
- }, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
@@ -580,55 +481,13 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
return ret;
}
-static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y)
-{
- struct exynos_adc *info = iio_priv(indio_dev);
- unsigned long time_left;
- int ret;
-
- mutex_lock(&info->lock);
- info->read_ts = true;
-
- reinit_completion(&info->completion);
-
- writel(ADC_S3C2410_TSC_PULL_UP_DISABLE | ADC_TSC_AUTOPST,
- ADC_V1_TSC(info->regs));
-
- /* Select the ts channel to be used and Trigger conversion */
- info->data->start_conv(info, ADC_S3C2410_MUX_TS);
-
- time_left = wait_for_completion_timeout(&info->completion,
- EXYNOS_ADC_TIMEOUT);
- if (time_left == 0) {
- dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
- if (info->data->init_hw)
- info->data->init_hw(info);
- ret = -ETIMEDOUT;
- } else {
- *x = info->ts_x;
- *y = info->ts_y;
- ret = 0;
- }
-
- info->read_ts = false;
- mutex_unlock(&info->lock);
-
- return ret;
-}
-
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
{
struct exynos_adc *info = dev_id;
u32 mask = info->data->mask;
/* Read value */
- if (info->read_ts) {
- info->ts_x = readl(ADC_V1_DATX(info->regs));
- info->ts_y = readl(ADC_V1_DATY(info->regs));
- writel(ADC_TSC_WAIT4INT | ADC_S3C2443_TSC_UD_SEN, ADC_V1_TSC(info->regs));
- } else {
- info->value = readl(ADC_V1_DATX(info->regs)) & mask;
- }
+ info->value = readl(ADC_V1_DATX(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
@@ -639,46 +498,6 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/*
- * Here we (ab)use a threaded interrupt handler to stay running
- * for as long as the touchscreen remains pressed, we report
- * a new event with the latest data and then sleep until the
- * next timer tick. This mirrors the behavior of the old
- * driver, with much less code.
- */
-static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
-{
- struct exynos_adc *info = dev_id;
- struct iio_dev *dev = dev_get_drvdata(info->dev);
- u32 x, y;
- bool pressed;
- int ret;
-
- while (READ_ONCE(info->ts_enabled)) {
- ret = exynos_read_s3c64xx_ts(dev, &x, &y);
- if (ret == -ETIMEDOUT)
- break;
-
- pressed = x & y & ADC_DATX_PRESSED;
- if (!pressed) {
- input_report_key(info->input, BTN_TOUCH, 0);
- input_sync(info->input);
- break;
- }
-
- input_report_abs(info->input, ABS_X, x & ADC_DATX_MASK);
- input_report_abs(info->input, ABS_Y, y & ADC_DATY_MASK);
- input_report_key(info->input, BTN_TOUCH, 1);
- input_sync(info->input);
-
- usleep_range(1000, 1100);
- }
-
- writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
-
- return IRQ_HANDLED;
-}
-
static int exynos_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
@@ -730,78 +549,17 @@ static int exynos_adc_remove_devices(struct device *dev, void *c)
return 0;
}
-static int exynos_adc_ts_open(struct input_dev *dev)
-{
- struct exynos_adc *info = input_get_drvdata(dev);
-
- WRITE_ONCE(info->ts_enabled, true);
- enable_irq(info->tsirq);
-
- return 0;
-}
-
-static void exynos_adc_ts_close(struct input_dev *dev)
-{
- struct exynos_adc *info = input_get_drvdata(dev);
-
- WRITE_ONCE(info->ts_enabled, false);
- disable_irq(info->tsirq);
-}
-
-static int exynos_adc_ts_init(struct exynos_adc *info)
-{
- int ret;
-
- if (info->tsirq <= 0)
- return -ENODEV;
-
- info->input = input_allocate_device();
- if (!info->input)
- return -ENOMEM;
-
- info->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- info->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(info->input, ABS_X, 0, 0x3FF, 0, 0);
- input_set_abs_params(info->input, ABS_Y, 0, 0x3FF, 0, 0);
-
- info->input->name = "S3C24xx TouchScreen";
- info->input->id.bustype = BUS_HOST;
- info->input->open = exynos_adc_ts_open;
- info->input->close = exynos_adc_ts_close;
-
- input_set_drvdata(info->input, info);
-
- ret = input_register_device(info->input);
- if (ret) {
- input_free_device(info->input);
- return ret;
- }
-
- ret = request_threaded_irq(info->tsirq, NULL, exynos_ts_isr,
- IRQF_ONESHOT | IRQF_NO_AUTOEN,
- "touchscreen", info);
- if (ret)
- input_unregister_device(info->input);
-
- return ret;
-}
-
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
struct device_node *np = pdev->dev.of_node;
- struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = NULL;
- bool has_ts = false;
int ret;
int irq;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
info = iio_priv(indio_dev);
@@ -826,27 +584,10 @@ static int exynos_adc_probe(struct platform_device *pdev)
}
}
- /* leave out any TS related code if unreachable */
- if (IS_REACHABLE(CONFIG_INPUT)) {
- has_ts = of_property_read_bool(pdev->dev.of_node,
- "has-touchscreen") || pdata;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
info->irq = irq;
-
- if (has_ts) {
- irq = platform_get_irq(pdev, 1);
- if (irq == -EPROBE_DEFER)
- return irq;
-
- info->tsirq = irq;
- } else {
- info->tsirq = -1;
- }
-
info->dev = &pdev->dev;
init_completion(&info->completion);
@@ -910,16 +651,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (info->data->init_hw)
info->data->init_hw(info);
- if (pdata)
- info->delay = pdata->delay;
- else
- info->delay = 10000;
-
- if (has_ts)
- ret = exynos_adc_ts_init(info);
- if (ret)
- goto err_iio;
-
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
@@ -931,11 +662,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
err_of_populate:
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
- if (has_ts) {
- input_unregister_device(info->input);
- free_irq(info->tsirq, info);
- }
-err_iio:
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
@@ -955,10 +681,6 @@ static void exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- if (IS_REACHABLE(CONFIG_INPUT) && info->input) {
- free_irq(info->tsirq, info);
- input_unregister_device(info->input);
- }
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 7235fa9e13d5..1db8b68a8f64 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -465,7 +465,7 @@ static int hx711_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n");
+ return -ENOMEM;
hx711_data = iio_priv(indio_dev);
hx711_data->dev = dev;
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 09ce71f6e941..039c0387da23 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -482,10 +482,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
- if (!indio_dev) {
- dev_err(&pdev->dev, "Failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
info = iio_priv(indio_dev);
info->dev = dev;
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
index be13a6ed7e00..6fc50394ad90 100644
--- a/drivers/iio/adc/imx8qxp-adc.c
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -229,7 +229,6 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
ret = wait_for_completion_interruptible_timeout(&adc->completion,
IMX8QXP_ADC_TIMEOUT);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
if (ret == 0) {
@@ -295,7 +294,6 @@ static int imx8qxp_adc_reg_access(struct iio_dev *indio_dev, unsigned int reg,
*readval = readl(adc->regs + reg);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
return 0;
@@ -315,10 +313,8 @@ static int imx8qxp_adc_probe(struct platform_device *pdev)
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
- if (!indio_dev) {
- dev_err(dev, "Failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
adc = iio_priv(indio_dev);
adc->dev = dev;
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
index 7feaafd2316f..787e80db5de3 100644
--- a/drivers/iio/adc/imx93_adc.c
+++ b/drivers/iio/adc/imx93_adc.c
@@ -32,12 +32,13 @@
#define IMX93_ADC_PCDR0 0x100
#define IMX93_ADC_PCDR1 0x104
#define IMX93_ADC_PCDR2 0x108
-#define IMX93_ADC_PCDR3 0x10c
+#define IMX93_ADC_PCDR3 0x10C
#define IMX93_ADC_PCDR4 0x110
#define IMX93_ADC_PCDR5 0x114
#define IMX93_ADC_PCDR6 0x118
-#define IMX93_ADC_PCDR7 0x11c
+#define IMX93_ADC_PCDR7 0x11C
#define IMX93_ADC_CALSTAT 0x39C
+#define IMX93_ADC_CALCFG0 0x3A0
/* ADC bit shift */
#define IMX93_ADC_MCR_MODE_MASK BIT(29)
@@ -58,6 +59,8 @@
#define IMX93_ADC_IMR_ECH_MASK BIT(0)
#define IMX93_ADC_PCDR_CDATA_MASK GENMASK(11, 0)
+#define IMX93_ADC_CALCFG0_LDFAIL_MASK BIT(4)
+
/* ADC status */
#define IMX93_ADC_MSR_ADCSTATUS_IDLE 0
#define IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN 1
@@ -145,7 +148,7 @@ static void imx93_adc_config_ad_clk(struct imx93_adc *adc)
static int imx93_adc_calibration(struct imx93_adc *adc)
{
- u32 mcr, msr;
+ u32 mcr, msr, calcfg;
int ret;
/* make sure ADC in power down mode */
@@ -158,6 +161,11 @@ static int imx93_adc_calibration(struct imx93_adc *adc)
imx93_adc_power_up(adc);
+ /* Enable loading of calibrated values even in fail condition */
+ calcfg = readl(adc->regs + IMX93_ADC_CALCFG0);
+ calcfg |= IMX93_ADC_CALCFG0_LDFAIL_MASK;
+ writel(calcfg, adc->regs + IMX93_ADC_CALCFG0);
+
/*
* TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR,
* can add the setting of these bit if need in future.
@@ -180,9 +188,13 @@ static int imx93_adc_calibration(struct imx93_adc *adc)
/* check whether calbration is success or not */
msr = readl(adc->regs + IMX93_ADC_MSR);
if (msr & IMX93_ADC_MSR_CALFAIL_MASK) {
+ /*
+ * Only give warning here, this means the noise of the
+ * reference voltage do not meet the requirement:
+ * ADC reference voltage Noise < 1.8V * 1/2^ENOB
+ * And the resault of ADC is not that accurate.
+ */
dev_warn(adc->dev, "ADC calibration failed!\n");
- imx93_adc_power_down(adc);
- return -EAGAIN;
}
return 0;
@@ -248,7 +260,6 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev,
mutex_lock(&adc->lock);
ret = imx93_adc_read_channel_conversion(adc, chan->channel, val);
mutex_unlock(&adc->lock);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
if (ret < 0)
return ret;
@@ -308,8 +319,7 @@ static int imx93_adc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM,
- "Failed allocating iio device\n");
+ return -ENOMEM;
adc = iio_priv(indio_dev);
adc->dev = dev;
diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c
new file mode 100644
index 000000000000..0fe34f1c338e
--- /dev/null
+++ b/drivers/iio/adc/intel_dc_ti_adc.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Dollar Cove TI PMIC GPADC Driver
+ *
+ * Copyright (C) 2014 Intel Corporation (Ramakrishna Pallala <ramakrishna.pallala@intel.com>)
+ * Copyright (C) 2024 - 2025 Hans de Goede <hansg@kernel.org>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/wait.h>
+
+#include <linux/iio/driver.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+
+#define DC_TI_ADC_CNTL_REG 0x50
+#define DC_TI_ADC_START BIT(0)
+#define DC_TI_ADC_CH_SEL GENMASK(2, 1)
+#define DC_TI_ADC_EN BIT(5)
+#define DC_TI_ADC_EN_EXT_BPTH_BIAS BIT(6)
+
+#define DC_TI_VBAT_ZSE_GE_REG 0x53
+#define DC_TI_VBAT_GE GENMASK(3, 0)
+#define DC_TI_VBAT_ZSE GENMASK(7, 4)
+
+/* VBAT GE gain correction is in 0.0015 increments, ZSE is in 1.0 increments */
+#define DC_TI_VBAT_GE_STEP 15
+#define DC_TI_VBAT_GE_DIV 10000
+
+#define DC_TI_ADC_DATA_REG_CH(x) (0x54 + 2 * (x))
+
+enum dc_ti_adc_id {
+ DC_TI_ADC_VBAT,
+ DC_TI_ADC_PMICTEMP,
+ DC_TI_ADC_BATTEMP,
+ DC_TI_ADC_SYSTEMP0,
+};
+
+struct dc_ti_adc_info {
+ struct mutex lock; /* Protects against concurrent accesses to the ADC */
+ wait_queue_head_t wait;
+ struct device *dev;
+ struct regmap *regmap;
+ int vbat_zse;
+ int vbat_ge;
+ bool conversion_done;
+};
+
+static const struct iio_chan_spec dc_ti_adc_channels[] = {
+ {
+ .indexed = 1,
+ .type = IIO_VOLTAGE,
+ .channel = DC_TI_ADC_VBAT,
+ .address = DC_TI_ADC_DATA_REG_CH(0),
+ .datasheet_name = "CH0",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = DC_TI_ADC_PMICTEMP,
+ .address = DC_TI_ADC_DATA_REG_CH(1),
+ .datasheet_name = "CH1",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = DC_TI_ADC_BATTEMP,
+ .address = DC_TI_ADC_DATA_REG_CH(2),
+ .datasheet_name = "CH2",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = DC_TI_ADC_SYSTEMP0,
+ .address = DC_TI_ADC_DATA_REG_CH(3),
+ .datasheet_name = "CH3",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }
+};
+
+static struct iio_map dc_ti_adc_default_maps[] = {
+ IIO_MAP("CH0", "chtdc_ti_battery", "VBAT"),
+ IIO_MAP("CH1", "chtdc_ti_battery", "PMICTEMP"),
+ IIO_MAP("CH2", "chtdc_ti_battery", "BATTEMP"),
+ IIO_MAP("CH3", "chtdc_ti_battery", "SYSTEMP0"),
+ { }
+};
+
+static irqreturn_t dc_ti_adc_isr(int irq, void *data)
+{
+ struct dc_ti_adc_info *info = data;
+
+ info->conversion_done = true;
+ wake_up(&info->wait);
+ return IRQ_HANDLED;
+}
+
+static int dc_ti_adc_scale(struct dc_ti_adc_info *info,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ if (chan->channel != DC_TI_ADC_VBAT)
+ return -EINVAL;
+
+ /* Vbat ADC scale is 4.6875 mV / unit */
+ *val = 4;
+ *val2 = 687500;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int dc_ti_adc_raw_to_processed(struct dc_ti_adc_info *info,
+ struct iio_chan_spec const *chan,
+ int raw, int *val, int *val2)
+{
+ if (chan->channel != DC_TI_ADC_VBAT)
+ return -EINVAL;
+
+ /* Apply calibration */
+ raw -= info->vbat_zse;
+ raw = raw * (DC_TI_VBAT_GE_DIV - info->vbat_ge * DC_TI_VBAT_GE_STEP) /
+ DC_TI_VBAT_GE_DIV;
+ /* Vbat ADC scale is 4.6875 mV / unit */
+ raw *= 46875;
+
+ /* raw is now in 10000 units / mV, convert to milli + milli/1e6 */
+ *val = raw / 10000;
+ *val2 = (raw % 10000) * 100;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int dc_ti_adc_sample(struct dc_ti_adc_info *info,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret, ch = chan->channel;
+ __be16 buf;
+
+ info->conversion_done = false;
+
+ /*
+ * As per TI (PMIC Vendor), the ADC enable and ADC start commands should
+ * not be sent together. Hence send the commands separately.
+ */
+ ret = regmap_set_bits(info->regmap, DC_TI_ADC_CNTL_REG, DC_TI_ADC_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(info->regmap, DC_TI_ADC_CNTL_REG,
+ DC_TI_ADC_CH_SEL,
+ FIELD_PREP(DC_TI_ADC_CH_SEL, ch));
+ if (ret)
+ return ret;
+
+ /*
+ * As per PMIC Vendor, a minimum of 50 ųs delay is required between ADC
+ * Enable and ADC START commands. This is also recommended by Intel
+ * Hardware team after the timing analysis of GPADC signals. Since the
+ * I2C Write transaction to set the channel number also imparts 25 ųs
+ * delay, we need to wait for another 25 ųs before issuing ADC START.
+ */
+ fsleep(25);
+
+ ret = regmap_set_bits(info->regmap, DC_TI_ADC_CNTL_REG,
+ DC_TI_ADC_START);
+ if (ret)
+ return ret;
+
+ /* TI (PMIC Vendor) recommends 5 s timeout for conversion */
+ ret = wait_event_timeout(info->wait, info->conversion_done, 5 * HZ);
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ goto disable_adc;
+ }
+
+ ret = regmap_bulk_read(info->regmap, chan->address, &buf, sizeof(buf));
+ if (ret)
+ goto disable_adc;
+
+ /* The ADC values are 10 bits wide */
+ *val = be16_to_cpu(buf) & GENMASK(9, 0);
+
+disable_adc:
+ regmap_clear_bits(info->regmap, DC_TI_ADC_CNTL_REG,
+ DC_TI_ADC_START | DC_TI_ADC_EN);
+ return ret;
+}
+
+static int dc_ti_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct dc_ti_adc_info *info = iio_priv(indio_dev);
+ int ret;
+
+ if (mask == IIO_CHAN_INFO_SCALE)
+ return dc_ti_adc_scale(info, chan, val, val2);
+
+ guard(mutex)(&info->lock);
+
+ /*
+ * If channel BPTHERM has been selected, first enable the BPTHERM BIAS
+ * which provides the VREF Voltage reference to convert BPTHERM Input
+ * voltage to temperature.
+ */
+ if (chan->channel == DC_TI_ADC_BATTEMP) {
+ ret = regmap_set_bits(info->regmap, DC_TI_ADC_CNTL_REG,
+ DC_TI_ADC_EN_EXT_BPTH_BIAS);
+ if (ret)
+ return ret;
+ /*
+ * As per PMIC Vendor specifications, BPTHERM BIAS should be
+ * enabled 35 ms before ADC_EN command.
+ */
+ msleep(35);
+ }
+
+ ret = dc_ti_adc_sample(info, chan, val);
+
+ if (chan->channel == DC_TI_ADC_BATTEMP)
+ regmap_clear_bits(info->regmap, DC_TI_ADC_CNTL_REG,
+ DC_TI_ADC_EN_EXT_BPTH_BIAS);
+
+ if (ret)
+ return ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_PROCESSED:
+ return dc_ti_adc_raw_to_processed(info, chan, *val, val, val2);
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info dc_ti_adc_iio_info = {
+ .read_raw = dc_ti_adc_read_raw,
+};
+
+static int dc_ti_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
+ struct dc_ti_adc_info *info;
+ struct iio_dev *indio_dev;
+ unsigned int val;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ ret = devm_mutex_init(dev, &info->lock);
+ if (ret)
+ return ret;
+
+ init_waitqueue_head(&info->wait);
+
+ info->dev = dev;
+ info->regmap = pmic->regmap;
+
+ indio_dev->name = "dc_ti_adc";
+ indio_dev->channels = dc_ti_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(dc_ti_adc_channels);
+ indio_dev->info = &dc_ti_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = regmap_read(info->regmap, DC_TI_VBAT_ZSE_GE_REG, &val);
+ if (ret)
+ return ret;
+
+ info->vbat_zse = sign_extend32(FIELD_GET(DC_TI_VBAT_ZSE, val), 3);
+ info->vbat_ge = sign_extend32(FIELD_GET(DC_TI_VBAT_GE, val), 3);
+
+ dev_dbg(dev, "vbat-zse %d vbat-ge %d\n", info->vbat_zse, info->vbat_ge);
+
+ ret = devm_iio_map_array_register(dev, indio_dev, dc_ti_adc_default_maps);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, dc_ti_adc_isr,
+ IRQF_ONESHOT, indio_dev->name, info);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id dc_ti_adc_ids[] = {
+ { .name = "chtdc_ti_adc" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, dc_ti_adc_ids);
+
+static struct platform_driver dc_ti_adc_driver = {
+ .driver = {
+ .name = "dc_ti_adc",
+ },
+ .probe = dc_ti_adc_probe,
+ .id_table = dc_ti_adc_ids,
+};
+module_platform_driver(dc_ti_adc_driver);
+
+MODULE_AUTHOR("Ramakrishna Pallala (Intel)");
+MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
+MODULE_DESCRIPTION("Intel Dollar Cove (TI) GPADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
index a68f1cd6883e..cd679ff10a97 100644
--- a/drivers/iio/adc/mcp3564.c
+++ b/drivers/iio/adc/mcp3564.c
@@ -1019,7 +1019,7 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
if (!channels)
- return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n");
+ return -ENOMEM;
device_for_each_child_node_scoped(dev, child) {
node_name = fwnode_get_name(child);
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 4ff88603e4fc..f7e7172ef4f6 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1357,7 +1357,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM, "failed allocating iio device\n");
+ return -ENOMEM;
priv = iio_priv(indio_dev);
init_completion(&priv->done);
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index 3343b54e8e44..fe9e3ece3fda 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -297,8 +297,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "Failed to add action to managed power off\n");
+ return ret;
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0)
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index 92baf3f5f560..dda5182a5076 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -697,10 +697,8 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
/* Allocate the IIO device. */
iio = devm_iio_device_alloc(dev, sizeof(*adc));
- if (!iio) {
- dev_err(dev, "Failed to allocate IIO device\n");
+ if (!iio)
return -ENOMEM;
- }
adc = iio_priv(iio);
adc->lradc = lradc;
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index 72aa4ca2e5a4..35433250b008 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -1279,8 +1279,7 @@ static int pac1921_probe(struct i2c_client *client)
ret = devm_add_action_or_reset(dev, pac1921_regulator_disable,
priv->vdd);
if (ret)
- return dev_err_probe(dev, ret,
- "Cannot add action for vdd regulator disposal\n");
+ return ret;
msleep(PAC1921_POWERUP_TIME_MS);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 09fe88eb3fb0..48df16509260 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -88,6 +88,7 @@
#define PAC1934_VPOWER_3_ADDR 0x19
#define PAC1934_VPOWER_4_ADDR 0x1A
#define PAC1934_REFRESH_V_REG_ADDR 0x1F
+#define PAC1934_SLOW_REG_ADDR 0x20
#define PAC1934_CTRL_STAT_REGS_ADDR 0x1C
#define PAC1934_PID_REG_ADDR 0xFD
#define PAC1934_MID_REG_ADDR 0xFE
@@ -1265,8 +1266,23 @@ static int pac1934_chip_configure(struct pac1934_chip_info *info)
/* no SLOW triggered REFRESH, clear POR */
regs[PAC1934_SLOW_REG_OFF] = 0;
- ret = i2c_smbus_write_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
- ARRAY_SIZE(regs), (u8 *)regs);
+ /*
+ * Write the three bytes sequentially, as the device does not support
+ * block write.
+ */
+ ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+ regs[PAC1934_CHANNEL_DIS_REG_OFF]);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client,
+ PAC1934_CTRL_STAT_REGS_ADDR + PAC1934_NEG_PWR_REG_OFF,
+ regs[PAC1934_NEG_PWR_REG_OFF]);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, PAC1934_SLOW_REG_ADDR,
+ regs[PAC1934_SLOW_REG_OFF]);
if (ret)
return ret;
@@ -1455,13 +1471,6 @@ static int pac1934_prep_custom_attributes(struct pac1934_chip_info *info,
return 0;
}
-static void pac1934_mutex_destroy(void *data)
-{
- struct mutex *lock = data;
-
- mutex_destroy(lock);
-}
-
static const struct iio_info pac1934_info = {
.read_raw = pac1934_read_raw,
.write_raw = pac1934_write_raw,
@@ -1520,9 +1529,7 @@ static int pac1934_probe(struct i2c_client *client)
return dev_err_probe(dev, ret,
"parameter parsing returned an error\n");
- mutex_init(&info->lock);
- ret = devm_add_action_or_reset(dev, pac1934_mutex_destroy,
- &info->lock);
+ ret = devm_mutex_init(dev, &info->lock);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index 7c01e33be04c..3f433064618e 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -885,10 +885,8 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
return -EINVAL;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
- if (!indio_dev) {
- dev_err(&pdev->dev, "iio_device_alloc failed\n");
+ if (!indio_dev)
return -ENOMEM;
- }
adc = iio_priv(indio_dev);
adc->dev = &pdev->dev;
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index cc326f21d398..3a17b3898bf6 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -163,12 +163,10 @@ static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on)
{
struct device *dev = priv->dev;
- if (on) {
+ if (on)
return pm_runtime_resume_and_get(dev);
- } else {
- pm_runtime_mark_last_busy(dev);
- return pm_runtime_put_autosuspend(dev);
- }
+
+ return pm_runtime_put_autosuspend(dev);
}
static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c
index d6f6b351f2af..f78fc795b69a 100644
--- a/drivers/iio/adc/rn5t618-adc.c
+++ b/drivers/iio/adc/rn5t618-adc.c
@@ -199,10 +199,8 @@ static int rn5t618_adc_probe(struct platform_device *pdev)
struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
- if (!iio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ if (!iio_dev)
return -ENOMEM;
- }
adc = iio_priv(iio_dev);
adc->dev = &pdev->dev;
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index bd62daea0a3e..6721da0ed7bb 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -466,8 +466,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
if (!indio_dev)
- return dev_err_probe(&pdev->dev, -ENOMEM,
- "failed allocating iio device\n");
+ return -ENOMEM;
info = iio_priv(indio_dev);
@@ -527,8 +526,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
ret = devm_add_action_or_reset(&pdev->dev,
rockchip_saradc_regulator_disable, info);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to register devm action\n");
+ return ret;
ret = regulator_get_voltage(info->vref);
if (ret < 0)
diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c
new file mode 100644
index 000000000000..d15e06c8b94d
--- /dev/null
+++ b/drivers/iio/adc/rohm-bd79112.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ROHM ADC driver for BD79112 signal monitoring hub.
+ * Copyright (C) 2025, ROHM Semiconductor.
+ *
+ * SPI communication derived from ad7923.c and ti-ads7950.c
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include <linux/iio/adc-helpers.h>
+#include <linux/iio/iio.h>
+
+#define BD79112_MAX_NUM_CHANNELS 32
+
+struct bd79112_data {
+ struct spi_device *spi;
+ struct regmap *map;
+ struct device *dev;
+ struct gpio_chip gc;
+ unsigned long gpio_valid_mask;
+ unsigned int vref_mv;
+ struct spi_transfer read_xfer[2];
+ struct spi_transfer write_xfer;
+ struct spi_message read_msg;
+ struct spi_message write_msg;
+ /* 16-bit TX, valid data in high byte */
+ u8 read_tx[2] __aligned(IIO_DMA_MINALIGN);
+ /* 8-bit address followed by 8-bit data */
+ u8 reg_write_tx[2];
+ /* 12-bit of ADC data or 8 bit of reg data */
+ __be16 read_rx;
+};
+
+/*
+ * The ADC data is read issuing SPI-command matching the channel number.
+ * We treat this as a register address.
+ */
+#define BD79112_REG_AGIO0A 0x00
+#define BD79112_REG_AGIO15B 0x1f
+
+/*
+ * ADC STATUS_FLAG appended to ADC data will be set, if the ADC result is being
+ * read for a channel, which input pin is muxed to be a GPIO.
+ */
+#define BD79112_ADC_STATUS_FLAG BIT(14)
+
+/*
+ * The BD79112 requires "R/W bit" to be set for SPI register (not ADC data)
+ * reads and an "IOSET bit" to be set for read/write operations (which aren't
+ * reading the ADC data).
+ */
+#define BD79112_BIT_RW BIT(4)
+#define BD79112_BIT_IO BIT(5)
+
+#define BD79112_REG_GPI_VALUE_B8_15 (BD79112_BIT_IO | 0x0)
+#define BD79112_REG_GPI_VALUE_B0_B7 (BD79112_BIT_IO | 0x1)
+#define BD79112_REG_GPI_VALUE_A8_15 (BD79112_BIT_IO | 0x2)
+#define BD79112_REG_GPI_VALUE_A0_A7 (BD79112_BIT_IO | 0x3)
+
+#define BD79112_REG_GPI_EN_B7_B15 (BD79112_BIT_IO | 0x4)
+#define BD79112_REG_GPI_EN_B0_B7 (BD79112_BIT_IO | 0x5)
+#define BD79112_REG_GPI_EN_A8_A15 (BD79112_BIT_IO | 0x6)
+#define BD79112_REG_GPI_EN_A0_A7 (BD79112_BIT_IO | 0x7)
+
+#define BD79112_REG_GPO_EN_B7_B15 (BD79112_BIT_IO | 0x8)
+#define BD79112_REG_GPO_EN_B0_B7 (BD79112_BIT_IO | 0x9)
+#define BD79112_REG_GPO_EN_A8_A15 (BD79112_BIT_IO | 0xa)
+#define BD79112_REG_GPO_EN_A0_A7 (BD79112_BIT_IO | 0xb)
+
+#define BD79112_NUM_GPIO_EN_REGS 8
+#define BD79112_FIRST_GPIO_EN_REG BD79112_REG_GPI_EN_B7_B15
+
+#define BD79112_REG_GPO_VALUE_B8_15 (BD79112_BIT_IO | 0xc)
+#define BD79112_REG_GPO_VALUE_B0_B7 (BD79112_BIT_IO | 0xd)
+#define BD79112_REG_GPO_VALUE_A8_15 (BD79112_BIT_IO | 0xe)
+#define BD79112_REG_GPO_VALUE_A0_A7 (BD79112_BIT_IO | 0xf)
+
+#define BD79112_REG_MAX BD79112_REG_GPO_VALUE_A0_A7
+
+/*
+ * Read transaction consists of two 16-bit sequences separated by CSB.
+ * For register read, 'IOSET' bit must be set. For ADC read, IOSET is cleared
+ * and ADDR equals the channel number (0 ... 31).
+ *
+ * First 16-bit sequence, MOSI as below, MISO data ignored:
+ * - SCK: | 1 | 2 | 3 | 4 | 5 .. 8 | 9 .. 16 |
+ * - MOSI:| 0 | 0 | IOSET | RW (1) | ADDR | 8'b0 |
+ *
+ * CSB released and re-acquired between these sequences
+ *
+ * Second 16-bit sequence, MISO as below, MOSI data ignored:
+ * For Register read data is 8 bits:
+ * - SCK: | 1 .. 8 | 9 .. 16 |
+ * - MISO:| 8'b0 | 8-bit data |
+ *
+ * For ADC read data is 12 bits:
+ * - SCK: | 1 | 2 | 3 4 | 4 .. 16 |
+ * - MISO:| 0 | STATUS_FLAG | 2'b0 | 12-bit data |
+ * The 'STATUS_FLAG' is set if the read input pin was configured as a GPIO.
+ */
+static int bd79112_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct bd79112_data *data = context;
+ int ret;
+
+ if (reg & BD79112_BIT_IO)
+ reg |= BD79112_BIT_RW;
+
+ data->read_tx[0] = reg;
+
+ ret = spi_sync(data->spi, &data->read_msg);
+ if (!ret)
+ *val = be16_to_cpu(data->read_rx);
+
+ return ret;
+}
+
+/*
+ * Write, single 16-bit sequence (broken down below):
+ *
+ * First 8-bit, MOSI as below, MISO data ignored:
+ * - SCK: | 1 | 2 | 3 | 4 | 5 .. 8 |
+ * - MOSI:| 0 | 0 |IOSET| RW(0) | ADDR |
+ *
+ * Last 8 SCK cycles (b8 ... b15), MISO contains register data, MOSI ignored.
+ * - SCK: | 9 .. 16 |
+ * - MISO:| data |
+ */
+static int bd79112_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct bd79112_data *data = context;
+
+ data->reg_write_tx[0] = reg;
+ data->reg_write_tx[1] = val;
+
+ return spi_sync(data->spi, &data->write_msg);
+}
+
+static int _get_gpio_reg(unsigned int offset, unsigned int base)
+{
+ int regoffset = offset / 8;
+
+ if (offset > 31)
+ return -EINVAL;
+
+ return base - regoffset;
+}
+
+#define GET_GPIO_BIT(offset) BIT((offset) % 8)
+#define GET_GPO_EN_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPO_EN_A0_A7)
+#define GET_GPI_EN_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_EN_A0_A7)
+#define GET_GPO_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPO_VALUE_A0_A7)
+#define GET_GPI_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_VALUE_A0_A7)
+
+static const struct regmap_range bd71815_volatile_ro_ranges[] = {
+ {
+ /* Read ADC data */
+ .range_min = BD79112_REG_AGIO0A,
+ .range_max = BD79112_REG_AGIO15B,
+ }, {
+ /* GPI state */
+ .range_min = BD79112_REG_GPI_VALUE_B8_15,
+ .range_max = BD79112_REG_GPI_VALUE_A0_A7,
+ },
+};
+
+static const struct regmap_access_table bd79112_volatile_regs = {
+ .yes_ranges = &bd71815_volatile_ro_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ro_ranges),
+};
+
+static const struct regmap_access_table bd79112_ro_regs = {
+ .no_ranges = &bd71815_volatile_ro_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(bd71815_volatile_ro_ranges),
+};
+
+static const struct regmap_config bd79112_regmap = {
+ .reg_read = bd79112_reg_read,
+ .reg_write = bd79112_reg_write,
+ .volatile_table = &bd79112_volatile_regs,
+ .wr_table = &bd79112_ro_regs,
+ .cache_type = REGCACHE_MAPLE,
+ .max_register = BD79112_REG_MAX,
+};
+
+static int bd79112_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long m)
+{
+ struct bd79112_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(data->map, chan->channel, val);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = data->vref_mv;
+ *val2 = 12;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info bd79112_info = {
+ .read_raw = bd79112_read_raw,
+};
+
+static const struct iio_chan_spec bd79112_chan_template = {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+};
+
+static int bd79112_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+
+ *valid_mask = data->gpio_valid_mask;
+
+ return 0;
+}
+
+static int bd79112_gpio_dir_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+ unsigned int reg, bit, val;
+ int ret;
+
+ bit = GET_GPIO_BIT(offset);
+ reg = GET_GPO_EN_REG(offset);
+
+ ret = regmap_read(data->map, reg, &val);
+ if (ret)
+ return ret;
+
+ if (bit & val)
+ return GPIO_LINE_DIRECTION_OUT;
+
+ reg = GET_GPI_EN_REG(offset);
+ ret = regmap_read(data->map, reg, &val);
+ if (ret)
+ return ret;
+
+ if (bit & val)
+ return GPIO_LINE_DIRECTION_IN;
+
+ /*
+ * Ouch. Seems the pin is ADC input - shouldn't happen as changing mux
+ * at runtime is not supported and non GPIO pins should be invalidated
+ * by the valid_mask at probe. Maybe someone wrote a register bypassing
+ * the driver?
+ */
+ dev_err(data->dev, "Pin not a GPIO\n");
+
+ return -EINVAL;
+}
+
+static int bd79112_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+ unsigned int reg, bit, val;
+ int ret;
+
+ bit = GET_GPIO_BIT(offset);
+ reg = GET_GPI_VAL_REG(offset);
+
+ ret = regmap_read(data->map, reg, &val);
+ if (ret)
+ return ret;
+
+ return !!(val & bit);
+}
+
+static int bd79112_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+ unsigned int reg, bit;
+
+ bit = GET_GPIO_BIT(offset);
+ reg = GET_GPO_VAL_REG(offset);
+
+ return regmap_assign_bits(data->map, reg, bit, value);
+}
+
+static int bd79112_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+ unsigned long i, bank_mask;
+
+ for_each_set_clump8(i, bank_mask, mask, gc->ngpio) {
+ unsigned long bank_bits;
+ unsigned int reg;
+ int ret;
+
+ bank_bits = bitmap_get_value8(bits, i);
+ reg = BD79112_REG_GPO_VALUE_A0_A7 - i / 8;
+ ret = regmap_update_bits(data->map, reg, bank_mask, bank_bits);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bd79112_gpio_dir_set(struct bd79112_data *data, unsigned int offset,
+ int dir)
+{
+ unsigned int gpi_reg, gpo_reg, bit;
+ int ret;
+
+ bit = GET_GPIO_BIT(offset);
+ gpi_reg = GET_GPI_EN_REG(offset);
+ gpo_reg = GET_GPO_EN_REG(offset);
+
+ if (dir == GPIO_LINE_DIRECTION_OUT) {
+ ret = regmap_clear_bits(data->map, gpi_reg, bit);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(data->map, gpo_reg, bit);
+ }
+
+ ret = regmap_set_bits(data->map, gpi_reg, bit);
+ if (ret)
+ return ret;
+
+ return regmap_clear_bits(data->map, gpo_reg, bit);
+}
+
+static int bd79112_gpio_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+
+ return bd79112_gpio_dir_set(data, offset, GPIO_LINE_DIRECTION_IN);
+}
+
+static int bd79112_gpio_output(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct bd79112_data *data = gpiochip_get_data(gc);
+ int ret;
+
+ ret = bd79112_gpio_set(gc, offset, value);
+ if (ret)
+ return ret;
+
+ return bd79112_gpio_dir_set(data, offset, GPIO_LINE_DIRECTION_OUT);
+}
+
+static const struct gpio_chip bd79112_gpio_chip = {
+ .label = "bd79112-gpio",
+ .get_direction = bd79112_gpio_dir_get,
+ .direction_input = bd79112_gpio_input,
+ .direction_output = bd79112_gpio_output,
+ .get = bd79112_gpio_get,
+ .set = bd79112_gpio_set,
+ .set_multiple = bd79112_gpio_set_multiple,
+ .init_valid_mask = bd79112_gpio_init_valid_mask,
+ .can_sleep = true,
+ .ngpio = 32,
+ .base = -1,
+};
+
+static unsigned int bd79112_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels)
+{
+ unsigned int i, gpio_channels;
+
+ /*
+ * Let's initialize the mux config to say that all 32 channels are
+ * GPIOs. Then we can just loop through the iio_chan_spec and clear the
+ * bits for found ADC channels.
+ */
+ gpio_channels = GENMASK(31, 0);
+ for (i = 0; i < num_channels; i++)
+ gpio_channels &= ~BIT(cs[i].channel);
+
+ return gpio_channels;
+}
+
+/* ADC channels as named in the data-sheet */
+static const char * const bd79112_chan_names[] = {
+ "AGIO0A", "AGIO1A", "AGIO2A", "AGIO3A", /* 0 - 3 */
+ "AGIO4A", "AGIO5A", "AGIO6A", "AGIO7A", /* 4 - 7 */
+ "AGIO8A", "AGIO9A", "AGIO10A", "AGIO11A", /* 8 - 11 */
+ "AGIO12A", "AGIO13A", "AGIO14A", "AGIO15A", /* 12 - 15 */
+ "AGIO0B", "AGIO1B", "AGIO2B", "AGIO3B", /* 16 - 19 */
+ "AGIO4B", "AGIO5B", "AGIO6B", "AGIO7B", /* 20 - 23 */
+ "AGIO8B", "AGIO9B", "AGIO10B", "AGIO11B", /* 24 - 27 */
+ "AGIO12B", "AGIO13B", "AGIO14B", "AGIO15B", /* 28 - 31 */
+};
+
+static int bd79112_probe(struct spi_device *spi)
+{
+ struct bd79112_data *data;
+ struct iio_dev *iio_dev;
+ struct iio_chan_spec *cs;
+ struct device *dev = &spi->dev;
+ unsigned long gpio_pins, pin;
+ unsigned int i;
+ int ret;
+
+ iio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(iio_dev);
+ data->spi = spi;
+ data->dev = dev;
+ data->map = devm_regmap_init(dev, NULL, data, &bd79112_regmap);
+ if (IS_ERR(data->map))
+ return dev_err_probe(dev, PTR_ERR(data->map),
+ "Failed to initialize Regmap\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "vdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get the Vdd\n");
+
+ data->vref_mv = ret / 1000;
+
+ ret = devm_regulator_get_enable(dev, "iovdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to enable I/O voltage\n");
+
+ data->read_xfer[0].tx_buf = &data->read_tx[0];
+ data->read_xfer[0].len = sizeof(data->read_tx);
+ data->read_xfer[0].cs_change = 1;
+ data->read_xfer[1].rx_buf = &data->read_rx;
+ data->read_xfer[1].len = sizeof(data->read_rx);
+ spi_message_init_with_transfers(&data->read_msg, data->read_xfer, 2);
+ ret = devm_spi_optimize_message(dev, spi, &data->read_msg);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI read message\n");
+
+ data->write_xfer.tx_buf = &data->reg_write_tx[0];
+ data->write_xfer.len = sizeof(data->reg_write_tx);
+ spi_message_init_with_transfers(&data->write_msg, &data->write_xfer, 1);
+ ret = devm_spi_optimize_message(dev, spi, &data->write_msg);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI write message\n");
+
+ ret = devm_iio_adc_device_alloc_chaninfo_se(dev, &bd79112_chan_template,
+ BD79112_MAX_NUM_CHANNELS - 1,
+ &cs);
+
+ /* Register all pins as GPIOs if there are no ADC channels */
+ if (ret == -ENOENT)
+ goto register_gpios;
+
+ if (ret < 0)
+ return ret;
+
+ iio_dev->num_channels = ret;
+ iio_dev->channels = cs;
+
+ for (i = 0; i < iio_dev->num_channels; i++)
+ cs[i].datasheet_name = bd79112_chan_names[cs[i].channel];
+
+ iio_dev->info = &bd79112_info;
+ iio_dev->name = "bd79112";
+ iio_dev->modes = INDIO_DIRECT_MODE;
+
+ /*
+ * Ensure all channels are ADCs. This allows us to register the IIO
+ * device early (before checking which pins are to be used for GPIO)
+ * without having to worry about some pins being initially used for
+ * GPIO.
+ */
+ for (i = 0; i < BD79112_NUM_GPIO_EN_REGS; i++) {
+ ret = regmap_write(data->map, BD79112_FIRST_GPIO_EN_REG + i, 0);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize channels\n");
+ }
+
+ ret = devm_iio_device_register(data->dev, iio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Failed to register ADC\n");
+
+register_gpios:
+ gpio_pins = bd79112_get_gpio_pins(iio_dev->channels,
+ iio_dev->num_channels);
+
+ /* If all channels are reserved for ADC, then we're done. */
+ if (!gpio_pins)
+ return 0;
+
+ /* Default all the GPIO pins to GPI */
+ for_each_set_bit(pin, &gpio_pins, BD79112_MAX_NUM_CHANNELS) {
+ ret = bd79112_gpio_dir_set(data, pin, GPIO_LINE_DIRECTION_IN);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to mark pin as GPI\n");
+ }
+
+ data->gpio_valid_mask = gpio_pins;
+ data->gc = bd79112_gpio_chip;
+ data->gc.parent = dev;
+
+ return devm_gpiochip_add_data(dev, &data->gc, data);
+}
+
+static const struct of_device_id bd79112_of_match[] = {
+ { .compatible = "rohm,bd79112" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bd79112_of_match);
+
+static const struct spi_device_id bd79112_id[] = {
+ { "bd79112" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, bd79112_id);
+
+static struct spi_driver bd79112_driver = {
+ .driver = {
+ .name = "bd79112",
+ .of_match_table = bd79112_of_match,
+ },
+ .probe = bd79112_probe,
+ .id_table = bd79112_id,
+};
+module_spi_driver(bd79112_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Driver for ROHM BD79112 ADC/GPIO");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DRIVER");
diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
index 9674d48074c9..1010e0511b3e 100644
--- a/drivers/iio/adc/rzg2l_adc.c
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -89,7 +89,6 @@ struct rzg2l_adc {
struct completion completion;
struct mutex lock;
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
- bool was_rpm_active;
};
/**
@@ -249,7 +248,6 @@ static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc
rzg2l_adc_start_stop(adc, false);
rpm_put:
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@@ -411,7 +409,6 @@ static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc)
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
exit_hw_init:
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@@ -428,6 +425,8 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
if (!indio_dev)
return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
adc = iio_priv(indio_dev);
adc->hw_params = device_get_match_data(dev);
@@ -460,8 +459,6 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- platform_set_drvdata(pdev, indio_dev);
-
ret = rzg2l_adc_hw_init(dev, adc);
if (ret)
return dev_err_probe(&pdev->dev, ret,
@@ -541,14 +538,9 @@ static int rzg2l_adc_suspend(struct device *dev)
};
int ret;
- if (pm_runtime_suspended(dev)) {
- adc->was_rpm_active = false;
- } else {
- ret = pm_runtime_force_suspend(dev);
- if (ret)
- return ret;
- adc->was_rpm_active = true;
- }
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
if (ret)
@@ -557,9 +549,7 @@ static int rzg2l_adc_suspend(struct device *dev)
return 0;
rpm_restore:
- if (adc->was_rpm_active)
- pm_runtime_force_resume(dev);
-
+ pm_runtime_force_resume(dev);
return ret;
}
@@ -577,11 +567,9 @@ static int rzg2l_adc_resume(struct device *dev)
if (ret)
return ret;
- if (adc->was_rpm_active) {
- ret = pm_runtime_force_resume(dev);
- if (ret)
- goto resets_restore;
- }
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ goto resets_restore;
ret = rzg2l_adc_hw_init(dev, adc);
if (ret)
@@ -590,10 +578,7 @@ static int rzg2l_adc_resume(struct device *dev)
return 0;
rpm_restore:
- if (adc->was_rpm_active) {
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
- }
+ pm_runtime_force_suspend(dev);
resets_restore:
reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
return ret;
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index e3a865c79686..50b0a607baeb 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h>
@@ -29,9 +30,9 @@
/* Bit definitions for SPEAR_ADC_STATUS */
#define SPEAR_ADC_STATUS_START_CONVERSION BIT(0)
-#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1)
+#define SPEAR_ADC_STATUS_CHANNEL_NUM_MASK GENMASK(3, 1)
#define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4)
-#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5)
+#define SPEAR_ADC_STATUS_AVG_SAMPLE_MASK GENMASK(8, 5)
#define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9)
#define SPEAR_ADC_DATA_MASK 0x03ff
@@ -157,8 +158,8 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
- status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) |
- SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) |
+ status = FIELD_PREP(SPEAR_ADC_STATUS_CHANNEL_NUM_MASK, chan->channel) |
+ FIELD_PREP(SPEAR_ADC_STATUS_AVG_SAMPLE_MASK, st->avg_samples) |
SPEAR_ADC_STATUS_START_CONVERSION |
SPEAR_ADC_STATUS_ADC_ENABLE;
if (st->vref_external == 0)
@@ -274,8 +275,7 @@ static int spear_adc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM,
- "failed allocating iio device\n");
+ return -ENOMEM;
st = iio_priv(indio_dev);
st->dev = dev;
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 3d800762c5fc..e39a4c0db25e 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -794,7 +794,6 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_irq_remove;
}
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index b9f93116e114..2d7f88459c7c 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -1528,7 +1528,6 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
stm32_adc_conv_irq_disable(adc);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
@@ -1564,7 +1563,6 @@ static int stm32_adc_write_raw(struct iio_dev *indio_dev,
adc->cfg->set_ovs(indio_dev, idx);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
adc->ovs_idx = idx;
@@ -1759,7 +1757,6 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
adc->num_conv = bitmap_weight(scan_mask, iio_get_masklength(indio_dev));
ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
@@ -1808,7 +1805,6 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev,
else
*readval = stm32_adc_readl(adc, reg);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -1954,7 +1950,6 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
err_clr_trig:
stm32_adc_set_trig(indio_dev, NULL);
err_pm_put:
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
@@ -1977,7 +1972,6 @@ static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
if (stm32_adc_set_trig(indio_dev, NULL))
dev_err(&indio_dev->dev, "Can't clear trigger\n");
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -2614,7 +2608,6 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_hw_stop;
}
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (IS_ENABLED(CONFIG_DEBUG_FS))
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index c2d21eecafe7..74b1b4dc6e81 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1764,10 +1764,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
dev_data = of_device_get_match_data(dev);
iio = devm_iio_device_alloc(dev, sizeof(*adc));
- if (!iio) {
- dev_err(dev, "%s: Failed to allocate IIO\n", __func__);
+ if (!iio)
return -ENOMEM;
- }
adc = iio_priv(iio);
adc->dfsdm = dev_get_drvdata(dev->parent);
diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c
index b0add5a2eab5..8e26c47edc08 100644
--- a/drivers/iio/adc/stmpe-adc.c
+++ b/drivers/iio/adc/stmpe-adc.c
@@ -267,10 +267,8 @@ static int stmpe_adc_probe(struct platform_device *pdev)
return irq_adc;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct stmpe_adc));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
info = iio_priv(indio_dev);
mutex_init(&info->lock);
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 6b8d6bee1873..479115ea50bf 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -154,7 +154,6 @@ static const struct regmap_config sun4i_gpadc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
- .fast_io = true,
};
static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
@@ -245,7 +244,6 @@ static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val,
*val = info->temp_data;
ret = 0;
- pm_runtime_mark_last_busy(indio_dev->dev.parent);
err:
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -272,7 +270,6 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
- pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
return 0;
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 4f514db5c26e..8ef51c57912d 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -102,27 +102,23 @@ struct adcxx1c_model {
int bits;
};
-#define ADCxx1C_MODEL(_name, _bits) \
- { \
- .channels = _name ## _channels, \
- .bits = (_bits), \
- }
-
DEFINE_ADCxx1C_CHANNELS(adc081c, 8);
DEFINE_ADCxx1C_CHANNELS(adc101c, 10);
DEFINE_ADCxx1C_CHANNELS(adc121c, 12);
-/* Model ids are indexes in _models array */
-enum adcxx1c_model_id {
- ADC081C = 0,
- ADC101C = 1,
- ADC121C = 2,
+static const struct adcxx1c_model adc081c_model = {
+ .channels = adc081c_channels,
+ .bits = 8,
+};
+
+static const struct adcxx1c_model adc101c_model = {
+ .channels = adc101c_channels,
+ .bits = 10,
};
-static struct adcxx1c_model adcxx1c_models[] = {
- ADCxx1C_MODEL(adc081c, 8),
- ADCxx1C_MODEL(adc101c, 10),
- ADCxx1C_MODEL(adc121c, 12),
+static const struct adcxx1c_model adc121c_model = {
+ .channels = adc121c_channels,
+ .bits = 12,
};
static const struct iio_info adc081c_info = {
@@ -203,24 +199,24 @@ static int adc081c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adc081c_id[] = {
- { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] },
- { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] },
- { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] },
+ { "adc081c", (kernel_ulong_t)&adc081c_model },
+ { "adc101c", (kernel_ulong_t)&adc101c_model },
+ { "adc121c", (kernel_ulong_t)&adc121c_model },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
static const struct acpi_device_id adc081c_acpi_match[] = {
/* Used on some AAEON boards */
- { "ADC081C", (kernel_ulong_t)&adcxx1c_models[ADC081C] },
+ { "ADC081C", (kernel_ulong_t)&adc081c_model },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);
static const struct of_device_id adc081c_of_match[] = {
- { .compatible = "ti,adc081c", .data = &adcxx1c_models[ADC081C] },
- { .compatible = "ti,adc101c", .data = &adcxx1c_models[ADC101C] },
- { .compatible = "ti,adc121c", .data = &adcxx1c_models[ADC121C] },
+ { .compatible = "ti,adc081c", .data = &adc081c_model },
+ { .compatible = "ti,adc101c", .data = &adc101c_model },
+ { .compatible = "ti,adc121c", .data = &adc121c_model },
{ }
};
MODULE_DEVICE_TABLE(of, adc081c_of_match);
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index 50a474f4d9f5..a100f770fa1c 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -200,10 +200,8 @@ static int adc084s021_probe(struct spi_device *spi)
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
- if (!indio_dev) {
- dev_err(&spi->dev, "Failed to allocate IIO device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
adc = iio_priv(indio_dev);
adc->spi = spi;
diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c
index 9dc465a10ffc..e5ec4b073daa 100644
--- a/drivers/iio/adc/ti-adc12138.c
+++ b/drivers/iio/adc/ti-adc12138.c
@@ -38,15 +38,13 @@ enum {
struct adc12138 {
struct spi_device *spi;
unsigned int id;
- /* conversion clock */
- struct clk *cclk;
/* positive analog voltage reference */
struct regulator *vref_p;
/* negative analog voltage reference */
struct regulator *vref_n;
struct mutex lock;
struct completion complete;
- /* The number of cclk periods for the S/H's acquisition time */
+ /* The number of conversion clock periods for the S/H's acquisition time */
unsigned int acquisition_time;
/*
* Maximum size needed: 16x 2 bytes ADC data + 8 bytes timestamp.
@@ -400,6 +398,7 @@ static int adc12138_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc12138 *adc;
+ struct clk *cclk;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
@@ -435,9 +434,14 @@ static int adc12138_probe(struct spi_device *spi)
if (ret)
adc->acquisition_time = 10;
- adc->cclk = devm_clk_get(&spi->dev, NULL);
- if (IS_ERR(adc->cclk))
- return PTR_ERR(adc->cclk);
+ ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler,
+ IRQF_TRIGGER_RISING, indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ cclk = devm_clk_get_enabled(&spi->dev, NULL);
+ if (IS_ERR(cclk))
+ return PTR_ERR(cclk);
adc->vref_p = devm_regulator_get(&spi->dev, "vref-p");
if (IS_ERR(adc->vref_p))
@@ -454,18 +458,9 @@ static int adc12138_probe(struct spi_device *spi)
return ret;
}
- ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler,
- IRQF_TRIGGER_RISING, indio_dev->name, indio_dev);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(adc->cclk);
- if (ret)
- return ret;
-
ret = regulator_enable(adc->vref_p);
if (ret)
- goto err_clk_disable;
+ return ret;
if (!IS_ERR(adc->vref_n)) {
ret = regulator_enable(adc->vref_n);
@@ -496,8 +491,6 @@ err_vref_n_disable:
regulator_disable(adc->vref_n);
err_vref_p_disable:
regulator_disable(adc->vref_p);
-err_clk_disable:
- clk_disable_unprepare(adc->cclk);
return ret;
}
@@ -512,7 +505,6 @@ static void adc12138_remove(struct spi_device *spi)
if (!IS_ERR(adc->vref_n))
regulator_disable(adc->vref_n);
regulator_disable(adc->vref_p);
- clk_disable_unprepare(adc->cclk);
}
static const struct of_device_id adc12138_dt_ids[] = {
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 1b46a8155803..4ae65793ad9b 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -99,51 +99,83 @@ static int adc128_read_raw(struct iio_dev *indio_dev,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
-static const struct iio_chan_spec adc128s052_channels[] = {
+static const struct iio_chan_spec simple_1chan_adc_channels[] = {
+ ADC128_VOLTAGE_CHANNEL(0),
+};
+
+static const struct iio_chan_spec simple_2chan_adc_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
- ADC128_VOLTAGE_CHANNEL(2),
- ADC128_VOLTAGE_CHANNEL(3),
- ADC128_VOLTAGE_CHANNEL(4),
- ADC128_VOLTAGE_CHANNEL(5),
- ADC128_VOLTAGE_CHANNEL(6),
- ADC128_VOLTAGE_CHANNEL(7),
};
-static const struct iio_chan_spec adc122s021_channels[] = {
+static const struct iio_chan_spec simple_4chan_adc_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
+ ADC128_VOLTAGE_CHANNEL(2),
+ ADC128_VOLTAGE_CHANNEL(3),
};
-static const struct iio_chan_spec adc124s021_channels[] = {
+static const struct iio_chan_spec simple_8chan_adc_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
ADC128_VOLTAGE_CHANNEL(2),
ADC128_VOLTAGE_CHANNEL(3),
+ ADC128_VOLTAGE_CHANNEL(4),
+ ADC128_VOLTAGE_CHANNEL(5),
+ ADC128_VOLTAGE_CHANNEL(6),
+ ADC128_VOLTAGE_CHANNEL(7),
};
static const char * const bd79104_regulators[] = { "iovdd" };
-static const struct adc128_configuration adc128_config[] = {
- {
- .channels = adc128s052_channels,
- .num_channels = ARRAY_SIZE(adc128s052_channels),
- .refname = "vref",
- }, {
- .channels = adc122s021_channels,
- .num_channels = ARRAY_SIZE(adc122s021_channels),
- .refname = "vref",
- }, {
- .channels = adc124s021_channels,
- .num_channels = ARRAY_SIZE(adc124s021_channels),
- .refname = "vref",
- }, {
- .channels = adc128s052_channels,
- .num_channels = ARRAY_SIZE(adc128s052_channels),
- .refname = "vdd",
- .other_regulators = &bd79104_regulators,
- .num_other_regulators = 1,
- },
+static const struct adc128_configuration adc122s_config = {
+ .channels = simple_2chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_2chan_adc_channels),
+ .refname = "vref",
+};
+
+static const struct adc128_configuration adc124s_config = {
+ .channels = simple_4chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_4chan_adc_channels),
+ .refname = "vref",
+};
+
+static const struct adc128_configuration adc128s_config = {
+ .channels = simple_8chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_8chan_adc_channels),
+ .refname = "vref",
+};
+
+static const struct adc128_configuration bd79100_config = {
+ .channels = simple_1chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_1chan_adc_channels),
+ .refname = "vdd",
+ .other_regulators = &bd79104_regulators,
+ .num_other_regulators = 1,
+};
+
+static const struct adc128_configuration bd79101_config = {
+ .channels = simple_2chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_2chan_adc_channels),
+ .refname = "vdd",
+ .other_regulators = &bd79104_regulators,
+ .num_other_regulators = 1,
+};
+
+static const struct adc128_configuration bd79102_config = {
+ .channels = simple_4chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_4chan_adc_channels),
+ .refname = "vdd",
+ .other_regulators = &bd79104_regulators,
+ .num_other_regulators = 1,
+};
+
+static const struct adc128_configuration bd79104_config = {
+ .channels = simple_8chan_adc_channels,
+ .num_channels = ARRAY_SIZE(simple_8chan_adc_channels),
+ .refname = "vdd",
+ .other_regulators = &bd79104_regulators,
+ .num_other_regulators = 1,
};
static const struct iio_info adc128_info = {
@@ -199,33 +231,41 @@ static int adc128_probe(struct spi_device *spi)
}
static const struct of_device_id adc128_of_match[] = {
- { .compatible = "ti,adc128s052", .data = &adc128_config[0] },
- { .compatible = "ti,adc122s021", .data = &adc128_config[1] },
- { .compatible = "ti,adc122s051", .data = &adc128_config[1] },
- { .compatible = "ti,adc122s101", .data = &adc128_config[1] },
- { .compatible = "ti,adc124s021", .data = &adc128_config[2] },
- { .compatible = "ti,adc124s051", .data = &adc128_config[2] },
- { .compatible = "ti,adc124s101", .data = &adc128_config[2] },
- { .compatible = "rohm,bd79104", .data = &adc128_config[3] },
+ { .compatible = "ti,adc128s052", .data = &adc128s_config },
+ { .compatible = "ti,adc122s021", .data = &adc122s_config },
+ { .compatible = "ti,adc122s051", .data = &adc122s_config },
+ { .compatible = "ti,adc122s101", .data = &adc122s_config },
+ { .compatible = "ti,adc124s021", .data = &adc124s_config },
+ { .compatible = "ti,adc124s051", .data = &adc124s_config },
+ { .compatible = "ti,adc124s101", .data = &adc124s_config },
+ { .compatible = "rohm,bd79100", .data = &bd79100_config },
+ { .compatible = "rohm,bd79101", .data = &bd79101_config },
+ { .compatible = "rohm,bd79102", .data = &bd79102_config },
+ { .compatible = "rohm,bd79103", .data = &bd79104_config },
+ { .compatible = "rohm,bd79104", .data = &bd79104_config },
{ }
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
- { "adc128s052", (kernel_ulong_t)&adc128_config[0] },
- { "adc122s021", (kernel_ulong_t)&adc128_config[1] },
- { "adc122s051", (kernel_ulong_t)&adc128_config[1] },
- { "adc122s101", (kernel_ulong_t)&adc128_config[1] },
- { "adc124s021", (kernel_ulong_t)&adc128_config[2] },
- { "adc124s051", (kernel_ulong_t)&adc128_config[2] },
- { "adc124s101", (kernel_ulong_t)&adc128_config[2] },
- { "bd79104", (kernel_ulong_t)&adc128_config[3] },
+ { "adc128s052", (kernel_ulong_t)&adc128s_config },
+ { "adc122s021", (kernel_ulong_t)&adc122s_config },
+ { "adc122s051", (kernel_ulong_t)&adc122s_config },
+ { "adc122s101", (kernel_ulong_t)&adc122s_config },
+ { "adc124s021", (kernel_ulong_t)&adc124s_config },
+ { "adc124s051", (kernel_ulong_t)&adc124s_config },
+ { "adc124s101", (kernel_ulong_t)&adc124s_config },
+ { "bd79100", (kernel_ulong_t)&bd79100_config },
+ { "bd79101", (kernel_ulong_t)&bd79101_config },
+ { "bd79102", (kernel_ulong_t)&bd79102_config },
+ { "bd79103", (kernel_ulong_t)&bd79104_config },
+ { "bd79104", (kernel_ulong_t)&bd79104_config },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
static const struct acpi_device_id adc128_acpi_match[] = {
- { "AANT1280", (kernel_ulong_t)&adc128_config[2] },
+ { "AANT1280", (kernel_ulong_t)&adc124s_config },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 48549d617e5f..f2a93c63ca14 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -374,12 +374,10 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on)
int ret;
struct device *dev = regmap_get_device(data->regmap);
- if (on) {
+ if (on)
ret = pm_runtime_resume_and_get(dev);
- } else {
- pm_runtime_mark_last_busy(dev);
+ else
ret = pm_runtime_put_autosuspend(dev);
- }
return ret < 0 ? ret : 0;
}
diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
index b0790e300b18..aa8946063c7d 100644
--- a/drivers/iio/adc/ti-ads1100.c
+++ b/drivers/iio/adc/ti-ads1100.c
@@ -105,7 +105,6 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val)
ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
- pm_runtime_mark_last_busy(&data->client->dev);
pm_runtime_put_autosuspend(&data->client->dev);
if (ret < 0) {
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index d2f86e1ec656..c9cedc59cdcd 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -291,7 +291,6 @@ static int ads1119_single_conversion(struct ads1119_state *st,
*val = sign_extend32(sample, chan->scan_type.realbits - 1);
ret = IIO_VAL_INT;
pdown:
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@@ -470,7 +469,6 @@ static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)
if (ret)
return ret;
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -693,8 +691,7 @@ static int ads1119_probe(struct i2c_client *client)
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM,
- "Failed to allocate IIO device\n");
+ return -ENOMEM;
st = iio_priv(indio_dev);
st->client = client;
@@ -750,8 +747,7 @@ static int ads1119_probe(struct i2c_client *client)
indio_dev->name,
iio_device_id(indio_dev));
if (!st->trig)
- return dev_err_probe(dev, -ENOMEM,
- "Failed to allocate IIO trigger\n");
+ return -ENOMEM;
st->trig->ops = &ads1119_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
@@ -778,8 +774,7 @@ static int ads1119_probe(struct i2c_client *client)
ret = devm_add_action_or_reset(dev, ads1119_powerdown, st);
if (ret)
- return dev_err_probe(dev, ret,
- "Failed to add powerdown action\n");
+ return ret;
return devm_iio_device_register(dev, indio_dev);
}
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index b18f30d3fdbe..742acc6d8cf9 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -807,10 +807,8 @@ static int ads131e08_probe(struct spi_device *spi)
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (!indio_dev) {
- dev_err(&spi->dev, "failed to allocate IIO device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
st = iio_priv(indio_dev);
st->info = info;
@@ -841,10 +839,8 @@ static int ads131e08_probe(struct spi_device *spi)
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
indio_dev->name, iio_device_id(indio_dev));
- if (!st->trig) {
- dev_err(&spi->dev, "failed to allocate IIO trigger\n");
+ if (!st->trig)
return -ENOMEM;
- }
st->trig->ops = &ads131e08_trigger_ops;
st->trig->dev.parent = &spi->dev;
diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c
index b1f745f75dbe..bbcc4fc22b6e 100644
--- a/drivers/iio/adc/ti-ads7924.c
+++ b/drivers/iio/adc/ti-ads7924.c
@@ -355,8 +355,7 @@ static int ads7924_probe(struct i2c_client *client)
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM,
- "failed to allocate iio device\n");
+ return -ENOMEM;
data = iio_priv(indio_dev);
@@ -399,8 +398,7 @@ static int ads7924_probe(struct i2c_client *client)
ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg);
if (ret)
- return dev_err_probe(dev, ret,
- "failed to add regulator disable action\n");
+ return ret;
ret = ads7924_reset(indio_dev);
if (ret < 0)
@@ -414,8 +412,7 @@ static int ads7924_probe(struct i2c_client *client)
ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data);
if (ret)
- return dev_err_probe(dev, ret,
- "failed to add idle mode action\n");
+ return ret;
/* Use minimum signal acquire time. */
ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG,
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
index 74471f08662e..8eb717b11cff 100644
--- a/drivers/iio/adc/ti-tsc2046.c
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -535,8 +535,7 @@ static enum hrtimer_restart tsc2046_adc_timer(struct hrtimer *hrtimer)
if (priv->poll_cnt < TI_TSC2046_POLL_CNT) {
priv->poll_cnt++;
hrtimer_start(&priv->trig_timer,
- ns_to_ktime(priv->scan_interval_us *
- NSEC_PER_USEC),
+ us_to_ktime(priv->scan_interval_us),
HRTIMER_MODE_REL_SOFT);
if (priv->poll_cnt >= TI_TSC2046_MIN_POLL_CNT) {
@@ -605,8 +604,7 @@ static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig)
* many samples. Reduce the sample rate for default (touchscreen) use
* case.
*/
- tim = ns_to_ktime((priv->scan_interval_us - priv->time_per_scan_us) *
- NSEC_PER_USEC);
+ tim = us_to_ktime(priv->scan_interval_us - priv->time_per_scan_us);
hrtimer_start(&priv->trig_timer, tim, HRTIMER_MODE_REL_SOFT);
}
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index fe1509d3b1e7..99f274adc870 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -631,10 +631,9 @@ static int tiadc_probe(struct platform_device *pdev)
}
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed to allocate iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
+
adc_dev = iio_priv(indio_dev);
adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
index 0ea51ddeaa0a..fe3b31ec976e 100644
--- a/drivers/iio/adc/twl4030-madc.c
+++ b/drivers/iio/adc/twl4030-madc.c
@@ -758,10 +758,8 @@ static int twl4030_madc_probe(struct platform_device *pdev)
}
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
- if (!iio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ if (!iio_dev)
return -ENOMEM;
- }
madc = iio_priv(iio_dev);
madc->dev = &pdev->dev;
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 1b3b1843a801..d7182ed0d2a7 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -832,7 +832,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
if (!indio_dev)
- return dev_err_probe(&pdev->dev, -ENOMEM, "Failed allocating iio device\n");
+ return -ENOMEM;
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index 1028b101cf56..9bb0b83c8f67 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -113,10 +113,8 @@ static int vprbrd_adc_probe(struct platform_device *pdev)
/* registering iio */
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ if (!indio_dev)
return -ENOMEM;
- }
adc = iio_priv(indio_dev);
adc->vb = vb;
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index 76dd0343f5f7..124470c92529 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -118,7 +118,7 @@
#define AMS_ALARM_THRESHOLD_OFF_10 0x10
#define AMS_ALARM_THRESHOLD_OFF_20 0x20
-#define AMS_ALARM_THR_DIRECT_MASK BIT(1)
+#define AMS_ALARM_THR_DIRECT_MASK BIT(0)
#define AMS_ALARM_THR_MIN 0x0000
#define AMS_ALARM_THR_MAX (BIT(16) - 1)
@@ -389,6 +389,29 @@ static void ams_update_pl_alarm(struct ams *ams, unsigned long alarm_mask)
ams_pl_update_reg(ams, AMS_REG_CONFIG3, AMS_REGCFG3_ALARM_MASK, cfg);
}
+static void ams_unmask(struct ams *ams)
+{
+ unsigned int status, unmask;
+
+ status = readl(ams->base + AMS_ISR_0);
+
+ /* Clear those bits which are not active anymore */
+ unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm;
+
+ /* Clear status of disabled alarm */
+ unmask |= ams->intr_mask;
+
+ ams->current_masked_alarm &= status;
+
+ /* Also clear those which are masked out anyway */
+ ams->current_masked_alarm &= ~ams->intr_mask;
+
+ /* Clear the interrupts before we unmask them */
+ writel(unmask, ams->base + AMS_ISR_0);
+
+ ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK);
+}
+
static void ams_update_alarm(struct ams *ams, unsigned long alarm_mask)
{
unsigned long flags;
@@ -401,6 +424,7 @@ static void ams_update_alarm(struct ams *ams, unsigned long alarm_mask)
spin_lock_irqsave(&ams->intr_lock, flags);
ams_update_intrmask(ams, AMS_ISR0_ALARM_MASK, ~alarm_mask);
+ ams_unmask(ams);
spin_unlock_irqrestore(&ams->intr_lock, flags);
}
@@ -1035,28 +1059,9 @@ static void ams_handle_events(struct iio_dev *indio_dev, unsigned long events)
static void ams_unmask_worker(struct work_struct *work)
{
struct ams *ams = container_of(work, struct ams, ams_unmask_work.work);
- unsigned int status, unmask;
spin_lock_irq(&ams->intr_lock);
-
- status = readl(ams->base + AMS_ISR_0);
-
- /* Clear those bits which are not active anymore */
- unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm;
-
- /* Clear status of disabled alarm */
- unmask |= ams->intr_mask;
-
- ams->current_masked_alarm &= status;
-
- /* Also clear those which are masked out anyway */
- ams->current_masked_alarm &= ~ams->intr_mask;
-
- /* Clear the interrupts before we unmask them */
- writel(unmask, ams->base + AMS_ISR_0);
-
- ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK);
-
+ ams_unmask(ams);
spin_unlock_irq(&ams->intr_lock);
/* If still pending some alarm re-trigger the timer */