diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-10-04 16:26:32 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-10-04 16:26:32 -0700 |
| commit | 6093a688a07da07808f0122f9aa2a3eed250d853 (patch) | |
| tree | 83b189258a392eb2212a8a5a01ebc64fe1985e60 /drivers/iio/adc | |
| parent | 59697e061f6aec86d5738cd4752e16520f1d60dc (diff) | |
| parent | 22d693e45d4a4513bd99489a4e50b81cc0175b21 (diff) | |
Merge tag 'char-misc-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull Char/Misc/IIO/Binder updates from Greg KH:
"Here is the big set of char/misc/iio and other driver subsystem
changes for 6.18-rc1.
Loads of different stuff in here, it was a busy development cycle in
lots of different subsystems, with over 27k new lines added to the
tree.
Included in here are:
- IIO updates including new drivers, reworking of existing apis, and
other goodness in the sensor subsystems
- MEI driver updates and additions
- NVMEM driver updates
- slimbus removal for an unused driver and some other minor updates
- coresight driver updates and additions
- MHI driver updates
- comedi driver updates and fixes
- extcon driver updates
- interconnect driver additions
- eeprom driver updates and fixes
- minor UIO driver updates
- tiny W1 driver updates
But the majority of new code is in the rust bindings and additions,
which includes:
- misc driver rust binding updates for read/write support, we can now
write "normal" misc drivers in rust fully, and the sample driver
shows how this can be done.
- Initial framework for USB driver rust bindings, which are disabled
for now in the build, due to limited support, but coming in through
this tree due to dependencies on other rust binding changes that
were in here. I'll be enabling these back on in the build in the
usb.git tree after -rc1 is out so that developers can continue to
work on these in linux-next over the next development cycle.
- Android Binder driver implemented in Rust.
This is the big one, and was driving a huge majority of the rust
binding work over the past years. Right now there are two binder
drivers in the kernel, selected only at build time as to which one
to use as binder wants to be included in the system at boot time.
The binder C maintainers all agreed on this, as eventually, they
want the C code to be removed from the tree, but it will take a few
releases to get there while both are maintained to ensure that the
rust implementation is fully stable and compliant with the existing
userspace apis.
All of these have been in linux-next for a while"
* tag 'char-misc-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (320 commits)
rust: usb: keep usb::Device private for now
rust: usb: don't retain device context for the interface parent
USB: disable rust bindings from the build for now
samples: rust: add a USB driver sample
rust: usb: add basic USB abstractions
coresight: Add label sysfs node support
dt-bindings: arm: Add label in the coresight components
coresight: tnoc: add new AMBA ID to support Trace Noc V2
coresight: Fix incorrect handling for return value of devm_kzalloc
coresight: tpda: fix the logic to setup the element size
coresight: trbe: Return NULL pointer for allocation failures
coresight: Refactor runtime PM
coresight: Make clock sequence consistent
coresight: Refactor driver data allocation
coresight: Consolidate clock enabling
coresight: Avoid enable programming clock duplicately
coresight: Appropriately disable trace bus clocks
coresight: Appropriately disable programming clocks
coresight: etm4x: Support atclk
coresight: catu: Support atclk
...
Diffstat (limited to 'drivers/iio/adc')
58 files changed, 4439 insertions, 978 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 24f2572c487e..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,6 +1342,16 @@ 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 && GPIOLIB 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 4d8c6bafd1c3..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 */ @@ -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 683146e83ab2..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; @@ -205,8 +220,10 @@ struct ad7173_channel_config { 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), { } }; @@ -582,14 +668,18 @@ static bool ad7173_is_setup_equal(const struct ad7173_channel_config *cfg1, 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->odr == cfg2->odr && - cfg1->ref_sel == cfg2->ref_sel; + 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 * @@ -630,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); @@ -649,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) @@ -761,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), @@ -777,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), @@ -793,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), @@ -1180,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); @@ -1218,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; @@ -1226,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; @@ -1243,17 +1390,40 @@ static int ad7173_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct ad7173_state *st = iio_priv(indio_dev); + 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, @@ -1396,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 = { @@ -1412,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) @@ -1652,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++; } @@ -1719,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"); @@ -1748,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; @@ -1780,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/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)<c2314_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, ¤t_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 cadb0446bc29..1010e0511b3e 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -248,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; } @@ -410,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; } 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 */ |