summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-11-25 20:35:16 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-11-25 20:35:16 +0300
commit56d784d1778c1d33e0803fdd00a59c2bb13989fb (patch)
treeb1fd1a7a858214f321eeae59a25f52ac09fa7258 /drivers/iio/adc
parent02cd3032b154fa02fdf90e7467abaeed889330b2 (diff)
parent12491d35551df69709777bd7769e1e33641943cc (diff)
downloadlinux-56d784d1778c1d33e0803fdd00a59c2bb13989fb.tar.xz
Merge tag 'iio-for-6.2a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: 1st set of IIO new device support, feature and cleanup for 6.2 (take2) We have finally managed to take the mlock mutex entirely private so as to avoid it being used for multiple purposes. Now it is just used to protect device mode transitions (typically to and from buffered capture). Includes merge of an immutable i2c branch to get the new i2c_client_get_device_id() (thanks to Wolfram for providing the branch). Based on rc3 to pick up some precursor fixes from early in the cycle and avoid an unnecessarily messy history. New device support * adi,ad4310 - New driver to support this very flexible measurement device including a 24 bit ADC. Later fix for documentation build issue. * adi,adxl355 - Add support of the ADXL359 accelerometer. * adi,ltc2983 - Support additional variants of the temperatures sensor: LTC2984 with an EEPROM LTC2985, LTC2986 with only 10 channels. * invensense,icm42600 - Add support for icm42631 (needed only ID and WHOAMI) * kionix,kx022a - New driver for this 3 axis accelerometer. * maxim,max11401 - New driver to support this 24-bit 10 channel ADC. Includes some new ABI to support configuration of notch filters. * mediatek,mt6370 - Add new driver to support the ADC part of the mt6370. * st,lsm6dsx - Add support for LSM6DSV accelerometer and gyroscope. Simple additional of chip specific data and IDs. - Add support for LSM6DSV16X accelerometer and gyroscope. Compatible with features currently implemented for the LSM6DSV. * st,stm32-adc - Add support for stm32pm13x SoCs. core / subsystem wide: - Add new IIO_STATIC_CONST_DEVICE_ATTR() which is a dance necessary to allow for the wrapping of attributes in the code that duplicates them for multiple buffers. - Harden against future issues with expectation that all buffer attributes are iio_dev_attrs by changing the code to take an array of pointers of the correct type. - Last transitions of drivers to local locks rather than missuses of mlock. - Add an iio_device_claim_buffer_mode() callback to avoid a race in the max30100 driver without directly using mlock. - Move mlock to the opaque IIO device structure to prevent misuse. - Add missing spi_device_id tables to support auto loading of modules. - Update some ADI maintainers in DT bindings. - A few more moves of bus drivers and core module sets to export name spaces. - Extensive use of new devm_regulator_get_enable() and friends. - Switch a bunch of i2c drivers to probe_new() including the bmp280 which makes use of the new i2c_client_get_device_id() helper to simplify this change. dt-bindings: - More use of spi-peripheral-props.yaml. Features * freescale,mpl115 - Use runtime PM to implement shutdown GPIO support. * melexis,mlx90632 - More sophisticated runtime power management - Provide access to sampling frequency. - Trivial follow up fixes. * microchip,mcp3911 - Support control of PGA. * st,lsm6dsx - Add support for software triggers for cases where the IRQ lines are not wired up. * vishay,vcnl4000 - Add control of integration time. Minor cleanups and fixes * adi,ad4130 - Improve ABI documentation formatting. - Kconfig dependency fixup. * adi,ad5758 - Minor dt binding fix. * adi,ad9834 - Tidy up line breaks. * adi,ade7854 - Minor improvement in code clarity by replacing a ternary. * adi,admv8818 - Harden code against hardware returning wrong values. * adi,adxl355 - Warn only if unknown device ID detected to allow for fall back device tree compatibles on future devices. * adi,ltc2983 - dt-bindings clarifications and general improvements. - Ensure DMA safe buffer for bulk writes without relying on current regmap implementation choices. * avago,adps9960 - Fix up a disconnect between event enable attributes and what was enabled. * bosch,bma400 - Switch to dev_err_probe() from open coded EPROBE_DEFER handling. * cosmic,cc10001 - Fully devm managed probe() and related tidying up. * meas,ms5611 - Add an example of spi-max-frequency. * meleixs,mlx90632 - Tidy up confusing error return value. - Style improvements. * multiplexer - Switch to dev_err_probe() from open coded EPROBE_DEFER handling. * qcom,spmi-vadc - Minor dt binding improvements. * rockchip,saradc - Add ID for rv1126. * semtech,sx9360 - Add SAMM0208 ACPI ID. Doesn't appear to be a valid vendor prefix but is in the wild. * st,lsm6dsx - Factor out common code as _device_set_enable(). - Fix up wrong docs after LSM6DSV addition. * st,stm32-adc - Manage the min sampling time on all internal channels. * trig,sysfs - Improve error labels. * tag 'iio-for-6.2a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (146 commits) iio: pressure: bmp280: convert to i2c's .probe_new() iio: imu: st_lsm6dsx: fix LSM6DSV sensor description iio: adc: ad4130: depend on GPIOLIB staging: iio: meter: replace ternary operator by if condition iio: light: apds9960: Fix iio_event_spec structures dt-bindings: iio: imu: Add inv_icm42600 documentation iio: imu: inv_icm42600: Add support for icm42631 dt-bindings: iio: adc: rockchip-saradc: Add saradc for rv1126 dt-bindings: iio: dac: adi,ad5758: Drop 'contains' from 'adi,dc-dc-mode' dt-bindings: iio: imu: st_lsm6dsx: add lsm6dsv16x iio: imu: st_lsm6dsx: add support to LSM6DSV16X iio: proximity: sx9360: Add a new ACPI hardware ID iio: temperature: mlx90632: Add missing static marking on devm_pm_ops iio: temperature: mlx90632: Add error handling for devm_pm_runtime_enable() iio: temperature: ltc2983: support more parts dt-bindings: iio: temperature: ltc2983: support more parts dt-bindings: iio: temperature: ltc2983: use generic node name in example dt-bindings: iio: temperature: ltc2983: describe broken mux delay property dt-bindings: iio: temperature: ltc2983: refine descriptions dt-bindings: iio: temperature: ltc2983: change default excitation for custom thermistors ...
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig40
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad4130.c2100
-rw-r--r--drivers/iio/adc/ad7124.c10
-rw-r--r--drivers/iio/adc/ad7192.c27
-rw-r--r--drivers/iio/adc/ad7476.c11
-rw-r--r--drivers/iio/adc/ad7606.c22
-rw-r--r--drivers/iio/adc/ad7606.h2
-rw-r--r--drivers/iio/adc/ad799x.c20
-rw-r--r--drivers/iio/adc/ad9467.c11
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c8
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c33
-rw-r--r--drivers/iio/adc/axp288_adc.c9
-rw-r--r--drivers/iio/adc/cc10001_adc.c89
-rw-r--r--drivers/iio/adc/imx7d_adc.c14
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c11
-rw-r--r--drivers/iio/adc/ltc2497-core.c7
-rw-r--r--drivers/iio/adc/ltc2497.h2
-rw-r--r--drivers/iio/adc/max11410.c1050
-rw-r--r--drivers/iio/adc/max1241.c28
-rw-r--r--drivers/iio/adc/max1363.c12
-rw-r--r--drivers/iio/adc/mcp3911.c104
-rw-r--r--drivers/iio/adc/meson_saradc.c11
-rw-r--r--drivers/iio/adc/mt6370-adc.c305
-rw-r--r--drivers/iio/adc/rockchip_saradc.c15
-rw-r--r--drivers/iio/adc/sc27xx_adc.c14
-rw-r--r--drivers/iio/adc/stm32-adc-core.c30
-rw-r--r--drivers/iio/adc/stm32-adc-core.h30
-rw-r--r--drivers/iio/adc/stm32-adc.c236
-rw-r--r--drivers/iio/adc/ti-ads131e08.c11
-rw-r--r--drivers/iio/adc/vf610_adc.c104
31 files changed, 4073 insertions, 296 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 791612ca6012..63f80d747cbd 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -21,6 +21,21 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+config AD4130
+ tristate "Analog Device AD4130 ADC Driver"
+ depends on SPI
+ depends on GPIOLIB
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select REGMAP_SPI
+ depends on COMMON_CLK
+ help
+ Say yes here to build support for Analog Devices AD4130-8 SPI analog
+ to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4130.
+
config AD7091R5
tristate "Analog Devices AD7091R5 ADC Driver"
depends on I2C
@@ -667,6 +682,19 @@ config MAX11205
To compile this driver as a module, choose M here: the module will be
called max11205.
+config MAX11410
+ tristate "Analog Devices MAX11410 ADC driver"
+ depends on SPI
+ select REGMAP_SPI
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices MAX11410 ADCs.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max11410.
+
config MAX1241
tristate "Maxim max1241 ADC driver"
depends on SPI_MASTER
@@ -752,6 +780,18 @@ config MEDIATEK_MT6360_ADC
is used in smartphones and tablets and supports a 11 channel
general purpose ADC.
+config MEDIATEK_MT6370_ADC
+ tristate "MediaTek MT6370 ADC driver"
+ depends on MFD_MT6370
+ help
+ Say yes here to enable MediaTek MT6370 ADC support.
+
+ This ADC driver provides 9 channels for system monitoring (charger
+ current, voltage, and temperature).
+
+ This driver can also be built as a module. If so, the module
+ will be called "mt6370-adc".
+
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 46caba7a010c..4ef41a7dfac6 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
+obj-$(CONFIG_AD4130) += ad4130.o
obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7192) += ad7192.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o
obj-$(CONFIG_MAX11205) += max11205.o
+obj-$(CONFIG_MAX11410) += max11410.o
obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX9611) += max9611.o
@@ -69,6 +71,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
new file mode 100644
index 000000000000..38394341fd6e
--- /dev/null
+++ b/drivers/iio/adc/ad4130.c
@@ -0,0 +1,2100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.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/units.h>
+
+#include <asm/div64.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
+#define AD4130_NAME "ad4130"
+
+#define AD4130_COMMS_READ_MASK BIT(6)
+
+#define AD4130_STATUS_REG 0x00
+
+#define AD4130_ADC_CONTROL_REG 0x01
+#define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14)
+#define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13)
+#define AD4130_INT_REF_2_5V 2500000
+#define AD4130_INT_REF_1_25V 1250000
+#define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9)
+#define AD4130_ADC_CONTROL_INT_REF_EN_MASK BIT(8)
+#define AD4130_ADC_CONTROL_MODE_MASK GENMASK(5, 2)
+#define AD4130_ADC_CONTROL_MCLK_SEL_MASK GENMASK(1, 0)
+#define AD4130_MCLK_FREQ_76_8KHZ 76800
+#define AD4130_MCLK_FREQ_153_6KHZ 153600
+
+#define AD4130_DATA_REG 0x02
+
+#define AD4130_IO_CONTROL_REG 0x03
+#define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8)
+#define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4)
+#define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0)
+
+#define AD4130_VBIAS_REG 0x04
+
+#define AD4130_ID_REG 0x05
+
+#define AD4130_ERROR_REG 0x06
+
+#define AD4130_ERROR_EN_REG 0x07
+
+#define AD4130_MCLK_COUNT_REG 0x08
+
+#define AD4130_CHANNEL_X_REG(x) (0x09 + (x))
+#define AD4130_CHANNEL_EN_MASK BIT(23)
+#define AD4130_CHANNEL_SETUP_MASK GENMASK(22, 20)
+#define AD4130_CHANNEL_AINP_MASK GENMASK(17, 13)
+#define AD4130_CHANNEL_AINM_MASK GENMASK(12, 8)
+#define AD4130_CHANNEL_IOUT1_MASK GENMASK(7, 4)
+#define AD4130_CHANNEL_IOUT2_MASK GENMASK(3, 0)
+
+#define AD4130_CONFIG_X_REG(x) (0x19 + (x))
+#define AD4130_CONFIG_IOUT1_VAL_MASK GENMASK(15, 13)
+#define AD4130_CONFIG_IOUT2_VAL_MASK GENMASK(12, 10)
+#define AD4130_CONFIG_BURNOUT_MASK GENMASK(9, 8)
+#define AD4130_CONFIG_REF_BUFP_MASK BIT(7)
+#define AD4130_CONFIG_REF_BUFM_MASK BIT(6)
+#define AD4130_CONFIG_REF_SEL_MASK GENMASK(5, 4)
+#define AD4130_CONFIG_PGA_MASK GENMASK(3, 1)
+
+#define AD4130_FILTER_X_REG(x) (0x21 + (x))
+#define AD4130_FILTER_MODE_MASK GENMASK(15, 12)
+#define AD4130_FILTER_SELECT_MASK GENMASK(10, 0)
+#define AD4130_FILTER_SELECT_MIN 1
+
+#define AD4130_OFFSET_X_REG(x) (0x29 + (x))
+
+#define AD4130_GAIN_X_REG(x) (0x31 + (x))
+
+#define AD4130_MISC_REG 0x39
+
+#define AD4130_FIFO_CONTROL_REG 0x3a
+#define AD4130_FIFO_CONTROL_HEADER_MASK BIT(18)
+#define AD4130_FIFO_CONTROL_MODE_MASK GENMASK(17, 16)
+#define AD4130_FIFO_CONTROL_WM_INT_EN_MASK BIT(9)
+#define AD4130_FIFO_CONTROL_WM_MASK GENMASK(7, 0)
+#define AD4130_WATERMARK_256 0
+
+#define AD4130_FIFO_STATUS_REG 0x3b
+
+#define AD4130_FIFO_THRESHOLD_REG 0x3c
+
+#define AD4130_FIFO_DATA_REG 0x3d
+#define AD4130_FIFO_SIZE 256
+#define AD4130_FIFO_MAX_SAMPLE_SIZE 3
+
+#define AD4130_MAX_ANALOG_PINS 16
+#define AD4130_MAX_CHANNELS 16
+#define AD4130_MAX_DIFF_INPUTS 30
+#define AD4130_MAX_GPIOS 4
+#define AD4130_MAX_ODR 2400
+#define AD4130_MAX_PGA 8
+#define AD4130_MAX_SETUPS 8
+
+#define AD4130_AIN2_P1 0x2
+#define AD4130_AIN3_P2 0x3
+
+#define AD4130_RESET_BUF_SIZE 8
+#define AD4130_RESET_SLEEP_US (160 * MICRO / AD4130_MCLK_FREQ_76_8KHZ)
+
+#define AD4130_INVALID_SLOT -1
+
+static const unsigned int ad4130_reg_size[] = {
+ [AD4130_STATUS_REG] = 1,
+ [AD4130_ADC_CONTROL_REG] = 2,
+ [AD4130_DATA_REG] = 3,
+ [AD4130_IO_CONTROL_REG] = 2,
+ [AD4130_VBIAS_REG] = 2,
+ [AD4130_ID_REG] = 1,
+ [AD4130_ERROR_REG] = 2,
+ [AD4130_ERROR_EN_REG] = 2,
+ [AD4130_MCLK_COUNT_REG] = 1,
+ [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3,
+ [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
+ [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_MISC_REG] = 2,
+ [AD4130_FIFO_CONTROL_REG] = 3,
+ [AD4130_FIFO_STATUS_REG] = 1,
+ [AD4130_FIFO_THRESHOLD_REG] = 3,
+ [AD4130_FIFO_DATA_REG] = 3,
+};
+
+enum ad4130_int_ref_val {
+ AD4130_INT_REF_VAL_2_5V,
+ AD4130_INT_REF_VAL_1_25V,
+};
+
+enum ad4130_mclk_sel {
+ AD4130_MCLK_76_8KHZ,
+ AD4130_MCLK_76_8KHZ_OUT,
+ AD4130_MCLK_76_8KHZ_EXT,
+ AD4130_MCLK_153_6KHZ_EXT,
+};
+
+enum ad4130_int_pin_sel {
+ AD4130_INT_PIN_INT,
+ AD4130_INT_PIN_CLK,
+ AD4130_INT_PIN_P2,
+ AD4130_INT_PIN_DOUT,
+};
+
+enum ad4130_iout {
+ AD4130_IOUT_OFF,
+ AD4130_IOUT_10000NA,
+ AD4130_IOUT_20000NA,
+ AD4130_IOUT_50000NA,
+ AD4130_IOUT_100000NA,
+ AD4130_IOUT_150000NA,
+ AD4130_IOUT_200000NA,
+ AD4130_IOUT_100NA,
+ AD4130_IOUT_MAX
+};
+
+enum ad4130_burnout {
+ AD4130_BURNOUT_OFF,
+ AD4130_BURNOUT_500NA,
+ AD4130_BURNOUT_2000NA,
+ AD4130_BURNOUT_4000NA,
+ AD4130_BURNOUT_MAX
+};
+
+enum ad4130_ref_sel {
+ AD4130_REF_REFIN1,
+ AD4130_REF_REFIN2,
+ AD4130_REF_REFOUT_AVSS,
+ AD4130_REF_AVDD_AVSS,
+ AD4130_REF_SEL_MAX
+};
+
+enum ad4130_fifo_mode {
+ AD4130_FIFO_MODE_DISABLED = 0b00,
+ AD4130_FIFO_MODE_WM = 0b01,
+};
+
+enum ad4130_mode {
+ AD4130_MODE_CONTINUOUS = 0b0000,
+ AD4130_MODE_IDLE = 0b0100,
+};
+
+enum ad4130_filter_mode {
+ AD4130_FILTER_SINC4,
+ AD4130_FILTER_SINC4_SINC1,
+ AD4130_FILTER_SINC3,
+ AD4130_FILTER_SINC3_REJ60,
+ AD4130_FILTER_SINC3_SINC1,
+ AD4130_FILTER_SINC3_PF1,
+ AD4130_FILTER_SINC3_PF2,
+ AD4130_FILTER_SINC3_PF3,
+ AD4130_FILTER_SINC3_PF4,
+};
+
+enum ad4130_pin_function {
+ AD4130_PIN_FN_NONE,
+ AD4130_PIN_FN_SPECIAL = BIT(0),
+ AD4130_PIN_FN_DIFF = BIT(1),
+ AD4130_PIN_FN_EXCITATION = BIT(2),
+ AD4130_PIN_FN_VBIAS = BIT(3),
+};
+
+struct ad4130_setup_info {
+ unsigned int iout0_val;
+ unsigned int iout1_val;
+ unsigned int burnout;
+ unsigned int pga;
+ unsigned int fs;
+ u32 ref_sel;
+ enum ad4130_filter_mode filter_mode;
+ bool ref_bufp;
+ bool ref_bufm;
+};
+
+struct ad4130_slot_info {
+ struct ad4130_setup_info setup;
+ unsigned int enabled_channels;
+ unsigned int channels;
+};
+
+struct ad4130_chan_info {
+ struct ad4130_setup_info setup;
+ u32 iout0;
+ u32 iout1;
+ int slot;
+ bool enabled;
+ bool initialized;
+};
+
+struct ad4130_filter_config {
+ enum ad4130_filter_mode filter_mode;
+ unsigned int odr_div;
+ unsigned int fs_max;
+ enum iio_available_type samp_freq_avail_type;
+ int samp_freq_avail_len;
+ int samp_freq_avail[3][2];
+};
+
+struct ad4130_state {
+ struct regmap *regmap;
+ struct spi_device *spi;
+ struct clk *mclk;
+ struct regulator_bulk_data regulators[4];
+ u32 irq_trigger;
+ u32 inv_irq_trigger;
+
+ /*
+ * Synchronize access to members the of driver state, and ensure
+ * atomicity of consecutive regmap operations.
+ */
+ struct mutex lock;
+ struct completion completion;
+
+ struct iio_chan_spec chans[AD4130_MAX_CHANNELS];
+ struct ad4130_chan_info chans_info[AD4130_MAX_CHANNELS];
+ struct ad4130_slot_info slots_info[AD4130_MAX_SETUPS];
+ enum ad4130_pin_function pins_fn[AD4130_MAX_ANALOG_PINS];
+ u32 vbias_pins[AD4130_MAX_ANALOG_PINS];
+ u32 num_vbias_pins;
+ int scale_tbls[AD4130_REF_SEL_MAX][AD4130_MAX_PGA][2];
+ struct gpio_chip gc;
+ struct clk_hw int_clk_hw;
+
+ u32 int_pin_sel;
+ u32 int_ref_uv;
+ u32 mclk_sel;
+ bool int_ref_en;
+ bool bipolar;
+
+ unsigned int num_enabled_channels;
+ unsigned int effective_watermark;
+ unsigned int watermark;
+
+ struct spi_message fifo_msg;
+ struct spi_transfer fifo_xfer[2];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires any transfer
+ * buffers to live in their own cache lines. As the use of these
+ * buffers is synchronous, all of the buffers used for DMA in this
+ * driver may share a cache line.
+ */
+ u8 reset_buf[AD4130_RESET_BUF_SIZE] __aligned(IIO_DMA_MINALIGN);
+ u8 reg_write_tx_buf[4];
+ u8 reg_read_tx_buf[1];
+ u8 reg_read_rx_buf[3];
+ u8 fifo_tx_buf[2];
+ u8 fifo_rx_buf[AD4130_FIFO_SIZE *
+ AD4130_FIFO_MAX_SAMPLE_SIZE];
+};
+
+static const char * const ad4130_int_pin_names[] = {
+ [AD4130_INT_PIN_INT] = "int",
+ [AD4130_INT_PIN_CLK] = "clk",
+ [AD4130_INT_PIN_P2] = "p2",
+ [AD4130_INT_PIN_DOUT] = "dout",
+};
+
+static const unsigned int ad4130_iout_current_na_tbl[AD4130_IOUT_MAX] = {
+ [AD4130_IOUT_OFF] = 0,
+ [AD4130_IOUT_100NA] = 100,
+ [AD4130_IOUT_10000NA] = 10000,
+ [AD4130_IOUT_20000NA] = 20000,
+ [AD4130_IOUT_50000NA] = 50000,
+ [AD4130_IOUT_100000NA] = 100000,
+ [AD4130_IOUT_150000NA] = 150000,
+ [AD4130_IOUT_200000NA] = 200000,
+};
+
+static const unsigned int ad4130_burnout_current_na_tbl[AD4130_BURNOUT_MAX] = {
+ [AD4130_BURNOUT_OFF] = 0,
+ [AD4130_BURNOUT_500NA] = 500,
+ [AD4130_BURNOUT_2000NA] = 2000,
+ [AD4130_BURNOUT_4000NA] = 4000,
+};
+
+#define AD4130_VARIABLE_ODR_CONFIG(_filter_mode, _odr_div, _fs_max) \
+{ \
+ .filter_mode = (_filter_mode), \
+ .odr_div = (_odr_div), \
+ .fs_max = (_fs_max), \
+ .samp_freq_avail_type = IIO_AVAIL_RANGE, \
+ .samp_freq_avail = { \
+ { AD4130_MAX_ODR, (_odr_div) * (_fs_max) }, \
+ { AD4130_MAX_ODR, (_odr_div) * (_fs_max) }, \
+ { AD4130_MAX_ODR, (_odr_div) }, \
+ }, \
+}
+
+#define AD4130_FIXED_ODR_CONFIG(_filter_mode, _odr_div) \
+{ \
+ .filter_mode = (_filter_mode), \
+ .odr_div = (_odr_div), \
+ .fs_max = AD4130_FILTER_SELECT_MIN, \
+ .samp_freq_avail_type = IIO_AVAIL_LIST, \
+ .samp_freq_avail_len = 1, \
+ .samp_freq_avail = { \
+ { AD4130_MAX_ODR, (_odr_div) }, \
+ }, \
+}
+
+static const struct ad4130_filter_config ad4130_filter_configs[] = {
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4, 1, 10),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4_SINC1, 11, 10),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3, 1, 2047),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_REJ60, 1, 2047),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_SINC1, 10, 2047),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF1, 92),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF2, 100),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF3, 124),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF4, 148),
+};
+
+static const char * const ad4130_filter_modes_str[] = {
+ [AD4130_FILTER_SINC4] = "sinc4",
+ [AD4130_FILTER_SINC4_SINC1] = "sinc4+sinc1",
+ [AD4130_FILTER_SINC3] = "sinc3",
+ [AD4130_FILTER_SINC3_REJ60] = "sinc3+rej60",
+ [AD4130_FILTER_SINC3_SINC1] = "sinc3+sinc1",
+ [AD4130_FILTER_SINC3_PF1] = "sinc3+pf1",
+ [AD4130_FILTER_SINC3_PF2] = "sinc3+pf2",
+ [AD4130_FILTER_SINC3_PF3] = "sinc3+pf3",
+ [AD4130_FILTER_SINC3_PF4] = "sinc3+pf4",
+};
+
+static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg,
+ unsigned int *size)
+{
+ if (reg >= ARRAY_SIZE(ad4130_reg_size))
+ return -EINVAL;
+
+ *size = ad4130_reg_size[reg];
+
+ return 0;
+}
+
+static unsigned int ad4130_data_reg_size(struct ad4130_state *st)
+{
+ unsigned int data_reg_size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, AD4130_DATA_REG, &data_reg_size);
+ if (ret)
+ return 0;
+
+ return data_reg_size;
+}
+
+static unsigned int ad4130_resolution(struct ad4130_state *st)
+{
+ return ad4130_data_reg_size(st) * BITS_PER_BYTE;
+}
+
+static int ad4130_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ad4130_state *st = context;
+ unsigned int size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ st->reg_write_tx_buf[0] = reg;
+
+ switch (size) {
+ case 3:
+ put_unaligned_be24(val, &st->reg_write_tx_buf[1]);
+ break;
+ case 2:
+ put_unaligned_be16(val, &st->reg_write_tx_buf[1]);
+ break;
+ case 1:
+ st->reg_write_tx_buf[1] = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return spi_write(st->spi, st->reg_write_tx_buf, size + 1);
+}
+
+static int ad4130_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ad4130_state *st = context;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = st->reg_read_tx_buf,
+ .len = sizeof(st->reg_read_tx_buf),
+ },
+ {
+ .rx_buf = st->reg_read_rx_buf,
+ },
+ };
+ unsigned int size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ st->reg_read_tx_buf[0] = AD4130_COMMS_READ_MASK | reg;
+ t[1].len = size;
+
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
+ if (ret)
+ return ret;
+
+ switch (size) {
+ case 3:
+ *val = get_unaligned_be24(st->reg_read_rx_buf);
+ break;
+ case 2:
+ *val = get_unaligned_be16(st->reg_read_rx_buf);
+ break;
+ case 1:
+ *val = st->reg_read_rx_buf[0];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config ad4130_regmap_config = {
+ .reg_read = ad4130_reg_read,
+ .reg_write = ad4130_reg_write,
+};
+
+static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct ad4130_state *st = gpiochip_get_data(gc);
+ unsigned int i;
+
+ /*
+ * Output-only GPIO functionality is available on pins AIN2 through
+ * AIN5. If these pins are used for anything else, do not expose them.
+ */
+ for (i = 0; i < ngpios; i++) {
+ unsigned int pin = i + AD4130_AIN2_P1;
+ bool valid = st->pins_fn[pin] == AD4130_PIN_FN_NONE;
+
+ __assign_bit(i, valid_mask, valid);
+ }
+
+ return 0;
+}
+
+static int ad4130_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct ad4130_state *st = gpiochip_get_data(gc);
+ unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
+ BIT(offset));
+
+ regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
+ value ? mask : 0);
+}
+
+static int ad4130_set_mode(struct ad4130_state *st, enum ad4130_mode mode)
+{
+ return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+ AD4130_ADC_CONTROL_MODE_MASK,
+ FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, mode));
+}
+
+static int ad4130_set_watermark_interrupt_en(struct ad4130_state *st, bool en)
+{
+ return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_WM_INT_EN_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_WM_INT_EN_MASK, en));
+}
+
+static unsigned int ad4130_watermark_reg_val(unsigned int val)
+{
+ if (val == AD4130_FIFO_SIZE)
+ val = AD4130_WATERMARK_256;
+
+ return val;
+}
+
+static int ad4130_set_fifo_mode(struct ad4130_state *st,
+ enum ad4130_fifo_mode mode)
+{
+ return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_MODE_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_MODE_MASK, mode));
+}
+
+static void ad4130_push_fifo_data(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int data_reg_size = ad4130_data_reg_size(st);
+ unsigned int transfer_len = st->effective_watermark * data_reg_size;
+ unsigned int set_size = st->num_enabled_channels * data_reg_size;
+ unsigned int i;
+ int ret;
+
+ st->fifo_tx_buf[1] = ad4130_watermark_reg_val(st->effective_watermark);
+ st->fifo_xfer[1].len = transfer_len;
+
+ ret = spi_sync(st->spi, &st->fifo_msg);
+ if (ret)
+ return;
+
+ for (i = 0; i < transfer_len; i += set_size)
+ iio_push_to_buffers(indio_dev, &st->fifo_rx_buf[i]);
+}
+
+static irqreturn_t ad4130_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct ad4130_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ ad4130_push_fifo_data(indio_dev);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int ad4130_find_slot(struct ad4130_state *st,
+ struct ad4130_setup_info *target_setup_info,
+ unsigned int *slot, bool *overwrite)
+{
+ unsigned int i;
+
+ *slot = AD4130_INVALID_SLOT;
+ *overwrite = false;
+
+ for (i = 0; i < AD4130_MAX_SETUPS; i++) {
+ struct ad4130_slot_info *slot_info = &st->slots_info[i];
+
+ /* Immediately accept a matching setup info. */
+ if (!memcmp(target_setup_info, &slot_info->setup,
+ sizeof(*target_setup_info))) {
+ *slot = i;
+ return 0;
+ }
+
+ /* Ignore all setups which are used by enabled channels. */
+ if (slot_info->enabled_channels)
+ continue;
+
+ /* Find the least used slot. */
+ if (*slot == AD4130_INVALID_SLOT ||
+ slot_info->channels < st->slots_info[*slot].channels)
+ *slot = i;
+ }
+
+ if (*slot == AD4130_INVALID_SLOT)
+ return -EINVAL;
+
+ *overwrite = true;
+
+ return 0;
+}
+
+static void ad4130_unlink_channel(struct ad4130_state *st, unsigned int channel)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_slot_info *slot_info = &st->slots_info[chan_info->slot];
+
+ chan_info->slot = AD4130_INVALID_SLOT;
+ slot_info->channels--;
+}
+
+static int ad4130_unlink_slot(struct ad4130_state *st, unsigned int slot)
+{
+ unsigned int i;
+
+ for (i = 0; i < AD4130_MAX_CHANNELS; i++) {
+ struct ad4130_chan_info *chan_info = &st->chans_info[i];
+
+ if (!chan_info->initialized || chan_info->slot != slot)
+ continue;
+
+ ad4130_unlink_channel(st, i);
+ }
+
+ return 0;
+}
+
+static int ad4130_link_channel_slot(struct ad4130_state *st,
+ unsigned int channel, unsigned int slot)
+{
+ struct ad4130_slot_info *slot_info = &st->slots_info[slot];
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+ AD4130_CHANNEL_SETUP_MASK,
+ FIELD_PREP(AD4130_CHANNEL_SETUP_MASK, slot));
+ if (ret)
+ return ret;
+
+ chan_info->slot = slot;
+ slot_info->channels++;
+
+ return 0;
+}
+
+static int ad4130_write_slot_setup(struct ad4130_state *st,
+ unsigned int slot,
+ struct ad4130_setup_info *setup_info)
+{
+ unsigned int val;
+ int ret;
+
+ val = FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout0_val) |
+ FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout1_val) |
+ FIELD_PREP(AD4130_CONFIG_BURNOUT_MASK, setup_info->burnout) |
+ FIELD_PREP(AD4130_CONFIG_REF_BUFP_MASK, setup_info->ref_bufp) |
+ FIELD_PREP(AD4130_CONFIG_REF_BUFM_MASK, setup_info->ref_bufm) |
+ FIELD_PREP(AD4130_CONFIG_REF_SEL_MASK, setup_info->ref_sel) |
+ FIELD_PREP(AD4130_CONFIG_PGA_MASK, setup_info->pga);
+
+ ret = regmap_write(st->regmap, AD4130_CONFIG_X_REG(slot), val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(AD4130_FILTER_MODE_MASK, setup_info->filter_mode) |
+ FIELD_PREP(AD4130_FILTER_SELECT_MASK, setup_info->fs);
+
+ ret = regmap_write(st->regmap, AD4130_FILTER_X_REG(slot), val);
+ if (ret)
+ return ret;
+
+ memcpy(&st->slots_info[slot].setup, setup_info, sizeof(*setup_info));
+
+ return 0;
+}
+
+static int ad4130_write_channel_setup(struct ad4130_state *st,
+ unsigned int channel, bool on_enable)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ bool overwrite;
+ int slot;
+ int ret;
+
+ /*
+ * The following cases need to be handled.
+ *
+ * 1. Enabled and linked channel with setup changes:
+ * - Find a slot. If not possible, return error.
+ * - Unlink channel from current slot.
+ * - If the slot has channels linked to it, unlink all channels, and
+ * write the new setup to it.
+ * - Link channel to new slot.
+ *
+ * 2. Soon to be enabled and unlinked channel:
+ * - Find a slot. If not possible, return error.
+ * - If the slot has channels linked to it, unlink all channels, and
+ * write the new setup to it.
+ * - Link channel to the slot.
+ *
+ * 3. Disabled and linked channel with setup changes:
+ * - Unlink channel from current slot.
+ *
+ * 4. Soon to be enabled and linked channel:
+ * 5. Disabled and unlinked channel with setup changes:
+ * - Do nothing.
+ */
+
+ /* Case 4 */
+ if (on_enable && chan_info->slot != AD4130_INVALID_SLOT)
+ return 0;
+
+ if (!on_enable && !chan_info->enabled) {
+ if (chan_info->slot != AD4130_INVALID_SLOT)
+ /* Case 3 */
+ ad4130_unlink_channel(st, channel);
+
+ /* Cases 3 & 5 */
+ return 0;
+ }
+
+ /* Cases 1 & 2 */
+ ret = ad4130_find_slot(st, setup_info, &slot, &overwrite);
+ if (ret)
+ return ret;
+
+ if (chan_info->slot != AD4130_INVALID_SLOT)
+ /* Case 1 */
+ ad4130_unlink_channel(st, channel);
+
+ if (overwrite) {
+ ret = ad4130_unlink_slot(st, slot);
+ if (ret)
+ return ret;
+
+ ret = ad4130_write_slot_setup(st, slot, setup_info);
+ if (ret)
+ return ret;
+ }
+
+ return ad4130_link_channel_slot(st, channel, slot);
+}
+
+static int ad4130_set_channel_enable(struct ad4130_state *st,
+ unsigned int channel, bool status)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_slot_info *slot_info;
+ int ret;
+
+ if (chan_info->enabled == status)
+ return 0;
+
+ if (status) {
+ ret = ad4130_write_channel_setup(st, channel, true);
+ if (ret)
+ return ret;
+ }
+
+ slot_info = &st->slots_info[chan_info->slot];
+
+ ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+ AD4130_CHANNEL_EN_MASK,
+ FIELD_PREP(AD4130_CHANNEL_EN_MASK, status));
+ if (ret)
+ return ret;
+
+ slot_info->enabled_channels += status ? 1 : -1;
+ chan_info->enabled = status;
+
+ return 0;
+}
+
+/*
+ * Table 58. FILTER_MODE_n bits and Filter Types of the datasheet describes
+ * the relation between filter mode, ODR and FS.
+ *
+ * Notice that the max ODR of each filter mode is not necessarily the
+ * absolute max ODR supported by the chip.
+ *
+ * The ODR divider is not explicitly specified, but it can be deduced based
+ * on the ODR range of each filter mode.
+ *
+ * For example, for Sinc4+Sinc1, max ODR is 218.18. That means that the
+ * absolute max ODR is divided by 11 to achieve the max ODR of this filter
+ * mode.
+ *
+ * The formulas for converting between ODR and FS for a specific filter
+ * mode can be deduced from the same table.
+ *
+ * Notice that FS = 1 actually means max ODR, and that ODR decreases by
+ * (maximum ODR / maximum FS) for each increment of FS.
+ *
+ * odr = MAX_ODR / odr_div * (1 - (fs - 1) / fs_max) <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (fs_max - fs + 1) / (fs_max * odr_div)
+ * (used in ad4130_fs_to_freq)
+ *
+ * For the opposite formula, FS can be extracted from the last one.
+ *
+ * MAX_ODR * (fs_max - fs + 1) = fs_max * odr_div * odr <=>
+ * fs_max - fs + 1 = fs_max * odr_div * odr / MAX_ODR <=>
+ * fs = 1 + fs_max - fs_max * odr_div * odr / MAX_ODR
+ * (used in ad4130_fs_to_freq)
+ */
+
+static void ad4130_freq_to_fs(enum ad4130_filter_mode filter_mode,
+ int val, int val2, unsigned int *fs)
+{
+ const struct ad4130_filter_config *filter_config =
+ &ad4130_filter_configs[filter_mode];
+ u64 dividend, divisor;
+ int temp;
+
+ dividend = filter_config->fs_max * filter_config->odr_div *
+ ((u64)val * NANO + val2);
+ divisor = (u64)AD4130_MAX_ODR * NANO;
+
+ temp = AD4130_FILTER_SELECT_MIN + filter_config->fs_max -
+ DIV64_U64_ROUND_CLOSEST(dividend, divisor);
+
+ if (temp < AD4130_FILTER_SELECT_MIN)
+ temp = AD4130_FILTER_SELECT_MIN;
+ else if (temp > filter_config->fs_max)
+ temp = filter_config->fs_max;
+
+ *fs = temp;
+}
+
+static void ad4130_fs_to_freq(enum ad4130_filter_mode filter_mode,
+ unsigned int fs, int *val, int *val2)
+{
+ const struct ad4130_filter_config *filter_config =
+ &ad4130_filter_configs[filter_mode];
+ unsigned int dividend, divisor;
+ u64 temp;
+
+ dividend = (filter_config->fs_max - fs + AD4130_FILTER_SELECT_MIN) *
+ AD4130_MAX_ODR;
+ divisor = filter_config->fs_max * filter_config->odr_div;
+
+ temp = div_u64((u64)dividend * NANO, divisor);
+ *val = div_u64_rem(temp, NANO, val2);
+}
+
+static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ enum ad4130_filter_mode old_filter_mode;
+ int freq_val, freq_val2;
+ unsigned int old_fs;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ if (setup_info->filter_mode == val)
+ goto out;
+
+ old_fs = setup_info->fs;
+ old_filter_mode = setup_info->filter_mode;
+
+ /*
+ * When switching between filter modes, try to match the ODR as
+ * close as possible. To do this, convert the current FS into ODR
+ * using the old filter mode, then convert it back into FS using
+ * the new filter mode.
+ */
+ ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ &freq_val, &freq_val2);
+
+ ad4130_freq_to_fs(val, freq_val, freq_val2, &setup_info->fs);
+
+ setup_info->filter_mode = val;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret) {
+ setup_info->fs = old_fs;
+ setup_info->filter_mode = old_filter_mode;
+ }
+
+ out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+ enum ad4130_filter_mode filter_mode;
+
+ mutex_lock(&st->lock);
+ filter_mode = setup_info->filter_mode;
+ mutex_unlock(&st->lock);
+
+ return filter_mode;
+}
+
+static const struct iio_enum ad4130_filter_mode_enum = {
+ .items = ad4130_filter_modes_str,
+ .num_items = ARRAY_SIZE(ad4130_filter_modes_str),
+ .set = ad4130_set_filter_mode,
+ .get = ad4130_get_filter_mode,
+};
+
+static const struct iio_chan_spec_ext_info ad4130_filter_mode_ext_info[] = {
+ IIO_ENUM("filter_mode", IIO_SEPARATE, &ad4130_filter_mode_enum),
+ IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_TYPE,
+ &ad4130_filter_mode_enum),
+ { }
+};
+
+static const struct iio_chan_spec ad4130_channel_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .differential = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .ext_info = ad4130_filter_mode_ext_info,
+ .scan_type = {
+ .sign = 'u',
+ .endianness = IIO_BE,
+ },
+};
+
+static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
+ int val, int val2)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ unsigned int pga, old_pga;
+ int ret = 0;
+
+ for (pga = 0; pga < AD4130_MAX_PGA; pga++)
+ if (val == st->scale_tbls[setup_info->ref_sel][pga][0] &&
+ val2 == st->scale_tbls[setup_info->ref_sel][pga][1])
+ break;
+
+ if (pga == AD4130_MAX_PGA)
+ return -EINVAL;
+
+ mutex_lock(&st->lock);
+ if (pga == setup_info->pga)
+ goto out;
+
+ old_pga = setup_info->pga;
+ setup_info->pga = pga;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret)
+ setup_info->pga = old_pga;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_set_channel_freq(struct ad4130_state *st,
+ unsigned int channel, int val, int val2)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ unsigned int fs, old_fs;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ old_fs = setup_info->fs;
+
+ ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
+
+ if (fs == setup_info->fs)
+ goto out;
+
+ setup_info->fs = fs;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret)
+ setup_info->fs = old_fs;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+ int *val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad4130_set_channel_enable(st, channel, true);
+ if (ret)
+ return ret;
+
+ reinit_completion(&st->completion);
+
+ ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD4130_DATA_REG, val);
+ if (ret)
+ return ret;
+
+ ret = ad4130_set_channel_enable(st, channel, false);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+ int *val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+ ret = _ad4130_read_sample(indio_dev, channel, val);
+ mutex_unlock(&st->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
+static int ad4130_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return ad4130_read_sample(indio_dev, channel, val);
+ case IIO_CHAN_INFO_SCALE:
+ mutex_lock(&st->lock);
+ *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
+ *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1];
+ mutex_unlock(&st->lock);
+
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ mutex_lock(&st->lock);
+ ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ val, val2);
+ mutex_unlock(&st->lock);
+
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+ const struct ad4130_filter_config *filter_config;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)st->scale_tbls[setup_info->ref_sel];
+ *length = ARRAY_SIZE(st->scale_tbls[setup_info->ref_sel]) * 2;
+
+ *type = IIO_VAL_INT_PLUS_NANO;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ mutex_lock(&st->lock);
+ filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+ mutex_unlock(&st->lock);
+
+ *vals = (int *)filter_config->samp_freq_avail;
+ *length = filter_config->samp_freq_avail_len * 2;
+ *type = IIO_VAL_FRACTIONAL;
+
+ return filter_config->samp_freq_avail_type;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad4130_set_channel_pga(st, channel, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4130_set_channel_freq(st, channel, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4130_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel;
+ unsigned int val = 0;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ for_each_set_bit(channel, scan_mask, indio_dev->num_channels) {
+ ret = ad4130_set_channel_enable(st, channel, true);
+ if (ret)
+ goto out;
+
+ val++;
+ }
+
+ st->num_enabled_channels = val;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return 0;
+}
+
+static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int eff;
+ int ret;
+
+ if (val > AD4130_FIFO_SIZE)
+ return -EINVAL;
+
+ eff = val * st->num_enabled_channels;
+ if (eff > AD4130_FIFO_SIZE)
+ /*
+ * Always set watermark to a multiple of the number of
+ * enabled channels to avoid making the FIFO unaligned.
+ */
+ eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels);
+
+ mutex_lock(&st->lock);
+
+ ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_WM_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK,
+ ad4130_watermark_reg_val(eff)));
+ if (ret)
+ goto out;
+
+ st->effective_watermark = eff;
+ st->watermark = val;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_info ad4130_info = {
+ .read_raw = ad4130_read_raw,
+ .read_avail = ad4130_read_avail,
+ .write_raw_get_fmt = ad4130_write_raw_get_fmt,
+ .write_raw = ad4130_write_raw,
+ .update_scan_mode = ad4130_update_scan_mode,
+ .hwfifo_set_watermark = ad4130_set_fifo_watermark,
+ .debugfs_reg_access = ad4130_reg_access,
+};
+
+static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = ad4130_set_watermark_interrupt_en(st, true);
+ if (ret)
+ goto out;
+
+ ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+ if (ret)
+ goto out;
+
+ ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_watermark_interrupt_en(st, false);
+ if (ret)
+ goto out;
+
+ /*
+ * update_scan_mode() is not called in the disable path, disable all
+ * channels here.
+ */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ ret = ad4130_set_channel_enable(st, i, false);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops ad4130_buffer_ops = {
+ .postenable = ad4130_buffer_postenable,
+ .predisable = ad4130_buffer_predisable,
+};
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+ unsigned int val;
+
+ mutex_lock(&st->lock);
+ val = st->watermark;
+ mutex_unlock(&st->lock);
+
+ return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD4130_FIFO_CONTROL_REG, &val);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(AD4130_FIFO_CONTROL_MODE_MASK, val);
+
+ return sysfs_emit(buf, "%d\n", val != AD4130_FIFO_MODE_DISABLED);
+}
+
+static ssize_t hwfifo_watermark_min_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", "1");
+}
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", __stringify(AD4130_FIFO_SIZE));
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+
+static const struct iio_dev_attr *ad4130_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
+static int _ad4130_find_table_index(const unsigned int *tbl, size_t len,
+ unsigned int val)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ if (tbl[i] == val)
+ return i;
+
+ return -EINVAL;
+}
+
+#define ad4130_find_table_index(table, val) \
+ _ad4130_find_table_index(table, ARRAY_SIZE(table), val)
+
+static int ad4130_get_ref_voltage(struct ad4130_state *st,
+ enum ad4130_ref_sel ref_sel)
+{
+ switch (ref_sel) {
+ case AD4130_REF_REFIN1:
+ return regulator_get_voltage(st->regulators[2].consumer);
+ case AD4130_REF_REFIN2:
+ return regulator_get_voltage(st->regulators[3].consumer);
+ case AD4130_REF_AVDD_AVSS:
+ return regulator_get_voltage(st->regulators[0].consumer);
+ case AD4130_REF_REFOUT_AVSS:
+ return st->int_ref_uv;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_parse_fw_setup(struct ad4130_state *st,
+ struct fwnode_handle *child,
+ struct ad4130_setup_info *setup_info)
+{
+ struct device *dev = &st->spi->dev;
+ u32 tmp;
+ int ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,excitation-current-0-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid excitation current %unA\n", tmp);
+ setup_info->iout0_val = ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,excitation-current-1-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid excitation current %unA\n", tmp);
+ setup_info->iout1_val = ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,burnout-current-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_burnout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid burnout current %unA\n", tmp);
+ setup_info->burnout = ret;
+
+ setup_info->ref_bufp = fwnode_property_read_bool(child, "adi,buffered-positive");
+ setup_info->ref_bufm = fwnode_property_read_bool(child, "adi,buffered-negative");
+
+ setup_info->ref_sel = AD4130_REF_REFIN1;
+ fwnode_property_read_u32(child, "adi,reference-select",
+ &setup_info->ref_sel);
+ if (setup_info->ref_sel >= AD4130_REF_SEL_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid reference selected %u\n",
+ setup_info->ref_sel);
+
+ if (setup_info->ref_sel == AD4130_REF_REFOUT_AVSS)
+ st->int_ref_en = true;
+
+ ret = ad4130_get_ref_voltage(st, setup_info->ref_sel);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Cannot use reference %u\n",
+ setup_info->ref_sel);
+
+ return 0;
+}
+
+static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_DIFF_INPUTS)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid differential channel %u\n", pin);
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return 0;
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_DIFF;
+
+ return 0;
+}
+
+static int ad4130_validate_diff_channels(struct ad4130_state *st,
+ u32 *pins, unsigned int len)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = ad4130_validate_diff_channel(st, pins[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid excitation pin %u\n", pin);
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_EXCITATION;
+
+ return 0;
+}
+
+static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n",
+ pin);
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_VBIAS;
+
+ return 0;
+}
+
+static int ad4130_validate_vbias_pins(struct ad4130_state *st,
+ u32 *pins, unsigned int len)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < st->num_vbias_pins; i++) {
+ ret = ad4130_validate_vbias_pin(st, pins[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_parse_fw_channel(struct iio_dev *indio_dev,
+ struct fwnode_handle *child)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int resolution = ad4130_resolution(st);
+ unsigned int index = indio_dev->num_channels++;
+ struct device *dev = &st->spi->dev;
+ struct ad4130_chan_info *chan_info;
+ struct iio_chan_spec *chan;
+ u32 pins[2];
+ int ret;
+
+ if (index >= AD4130_MAX_CHANNELS)
+ return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+
+ chan = &st->chans[index];
+ chan_info = &st->chans_info[index];
+
+ *chan = ad4130_channel_template;
+ chan->scan_type.realbits = resolution;
+ chan->scan_type.storagebits = resolution;
+ chan->scan_index = index;
+
+ chan_info->slot = AD4130_INVALID_SLOT;
+ chan_info->setup.fs = AD4130_FILTER_SELECT_MIN;
+ chan_info->initialized = true;
+
+ ret = fwnode_property_read_u32_array(child, "diff-channels", pins,
+ ARRAY_SIZE(pins));
+ if (ret)
+ return ret;
+
+ ret = ad4130_validate_diff_channels(st, pins, ARRAY_SIZE(pins));
+ if (ret)
+ return ret;
+
+ chan->channel = pins[0];
+ chan->channel2 = pins[1];
+
+ ret = ad4130_parse_fw_setup(st, child, &chan_info->setup);
+ if (ret)
+ return ret;
+
+ fwnode_property_read_u32(child, "adi,excitation-pin-0",
+ &chan_info->iout0);
+ if (chan_info->setup.iout0_val != AD4130_IOUT_OFF) {
+ ret = ad4130_validate_excitation_pin(st, chan_info->iout0);
+ if (ret)
+ return ret;
+ }
+
+ fwnode_property_read_u32(child, "adi,excitation-pin-1",
+ &chan_info->iout1);
+ if (chan_info->setup.iout1_val != AD4130_IOUT_OFF) {
+ ret = ad4130_validate_excitation_pin(st, chan_info->iout1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_parse_fw_children(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ struct fwnode_handle *child;
+ int ret;
+
+ indio_dev->channels = st->chans;
+
+ device_for_each_child_node(dev, child) {
+ ret = ad4130_parse_fw_channel(indio_dev, child);
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ad4310_parse_fw(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 ext_clk_freq = AD4130_MCLK_FREQ_76_8KHZ;
+ unsigned int i;
+ int avdd_uv;
+ int irq;
+ int ret;
+
+ st->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(st->mclk))
+ return dev_err_probe(dev, PTR_ERR(st->mclk),
+ "Failed to get mclk\n");
+
+ st->int_pin_sel = AD4130_INT_PIN_INT;
+
+ for (i = 0; i < ARRAY_SIZE(ad4130_int_pin_names); i++) {
+ irq = fwnode_irq_get_byname(dev_fwnode(dev),
+ ad4130_int_pin_names[i]);
+ if (irq > 0) {
+ st->int_pin_sel = i;
+ break;
+ }
+ }
+
+ if (st->int_pin_sel == AD4130_INT_PIN_DOUT)
+ return dev_err_probe(dev, -EINVAL,
+ "Cannot use DOUT as interrupt pin\n");
+
+ if (st->int_pin_sel == AD4130_INT_PIN_P2)
+ st->pins_fn[AD4130_AIN3_P2] = AD4130_PIN_FN_SPECIAL;
+
+ device_property_read_u32(dev, "adi,ext-clk-freq-hz", &ext_clk_freq);
+ if (ext_clk_freq != AD4130_MCLK_FREQ_153_6KHZ &&
+ ext_clk_freq != AD4130_MCLK_FREQ_76_8KHZ)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid external clock frequency %u\n",
+ ext_clk_freq);
+
+ if (st->mclk && ext_clk_freq == AD4130_MCLK_FREQ_153_6KHZ)
+ st->mclk_sel = AD4130_MCLK_153_6KHZ_EXT;
+ else if (st->mclk)
+ st->mclk_sel = AD4130_MCLK_76_8KHZ_EXT;
+ else
+ st->mclk_sel = AD4130_MCLK_76_8KHZ;
+
+ if (st->int_pin_sel == AD4130_INT_PIN_CLK &&
+ st->mclk_sel != AD4130_MCLK_76_8KHZ)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid clock %u for interrupt pin %u\n",
+ st->mclk_sel, st->int_pin_sel);
+
+ st->int_ref_uv = AD4130_INT_REF_2_5V;
+
+ /*
+ * When the AVDD supply is set to below 2.5V the internal reference of
+ * 1.25V should be selected.
+ * See datasheet page 37, section ADC REFERENCE.
+ */
+ avdd_uv = regulator_get_voltage(st->regulators[0].consumer);
+ if (avdd_uv > 0 && avdd_uv < AD4130_INT_REF_2_5V)
+ st->int_ref_uv = AD4130_INT_REF_1_25V;
+
+ st->bipolar = device_property_read_bool(dev, "adi,bipolar");
+
+ ret = device_property_count_u32(dev, "adi,vbias-pins");
+ if (ret > 0) {
+ if (ret > AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many vbias pins %u\n", ret);
+
+ st->num_vbias_pins = ret;
+
+ ret = device_property_read_u32_array(dev, "adi,vbias-pins",
+ st->vbias_pins,
+ st->num_vbias_pins);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read vbias pins\n");
+
+ ret = ad4130_validate_vbias_pins(st, st->vbias_pins,
+ st->num_vbias_pins);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad4130_parse_fw_children(indio_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ad4130_fill_scale_tbls(struct ad4130_state *st)
+{
+ unsigned int pow = ad4130_resolution(st) - st->bipolar;
+ unsigned int i, j;
+
+ for (i = 0; i < AD4130_REF_SEL_MAX; i++) {
+ int ret;
+ u64 nv;
+
+ ret = ad4130_get_ref_voltage(st, i);
+ if (ret < 0)
+ continue;
+
+ nv = (u64)ret * NANO;
+
+ for (j = 0; j < AD4130_MAX_PGA; j++)
+ st->scale_tbls[i][j][1] = div_u64(nv >> (pow + j), MILLI);
+ }
+}
+
+static void ad4130_clk_disable_unprepare(void *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
+static int ad4130_set_mclk_sel(struct ad4130_state *st,
+ enum ad4130_mclk_sel mclk_sel)
+{
+ return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+ AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+ FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+ mclk_sel));
+}
+
+static unsigned long ad4130_int_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return AD4130_MCLK_FREQ_76_8KHZ;
+}
+
+static int ad4130_int_clk_is_enabled(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+
+ return st->mclk_sel == AD4130_MCLK_76_8KHZ_OUT;
+}
+
+static int ad4130_int_clk_prepare(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+ int ret;
+
+ ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ_OUT);
+ if (ret)
+ return ret;
+
+ st->mclk_sel = AD4130_MCLK_76_8KHZ_OUT;
+
+ return 0;
+}
+
+static void ad4130_int_clk_unprepare(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+ int ret;
+
+ ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ);
+ if (ret)
+ return;
+
+ st->mclk_sel = AD4130_MCLK_76_8KHZ;
+}
+
+static const struct clk_ops ad4130_int_clk_ops = {
+ .recalc_rate = ad4130_int_clk_recalc_rate,
+ .is_enabled = ad4130_int_clk_is_enabled,
+ .prepare = ad4130_int_clk_prepare,
+ .unprepare = ad4130_int_clk_unprepare,
+};
+
+static int ad4130_setup_int_clk(struct ad4130_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct device_node *of_node = dev_of_node(dev);
+ struct clk_init_data init;
+ const char *clk_name;
+ struct clk *clk;
+
+ if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
+ st->mclk_sel != AD4130_MCLK_76_8KHZ)
+ return 0;
+
+ if (!of_node)
+ return 0;
+
+ clk_name = of_node->name;
+ of_property_read_string(of_node, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &ad4130_int_clk_ops;
+
+ st->int_clk_hw.init = &init;
+ clk = devm_clk_register(dev, &st->int_clk_hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+}
+
+static int ad4130_setup(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ unsigned int int_ref_val;
+ unsigned long rate = AD4130_MCLK_FREQ_76_8KHZ;
+ unsigned int val;
+ unsigned int i;
+ int ret;
+
+ if (st->mclk_sel == AD4130_MCLK_153_6KHZ_EXT)
+ rate = AD4130_MCLK_FREQ_153_6KHZ;
+
+ ret = clk_set_rate(st->mclk, rate);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(st->mclk);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ad4130_clk_disable_unprepare,
+ st->mclk);
+ if (ret)
+ return ret;
+
+ if (st->int_ref_uv == AD4130_INT_REF_2_5V)
+ int_ref_val = AD4130_INT_REF_VAL_2_5V;
+ else
+ int_ref_val = AD4130_INT_REF_VAL_1_25V;
+
+ /* Switch to SPI 4-wire mode. */
+ val = FIELD_PREP(AD4130_ADC_CONTROL_CSB_EN_MASK, 1);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_BIPOLAR_MASK, st->bipolar);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_EN_MASK, st->int_ref_en);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, AD4130_MODE_IDLE);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK, st->mclk_sel);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_VAL_MASK, int_ref_val);
+
+ ret = regmap_write(st->regmap, AD4130_ADC_CONTROL_REG, val);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure all GPIOs for output. If configured, the interrupt function
+ * of P2 takes priority over the GPIO out function.
+ */
+ val = AD4130_IO_CONTROL_GPIO_CTRL_MASK;
+ val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
+
+ ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val);
+ if (ret)
+ return ret;
+
+ val = 0;
+ for (i = 0; i < st->num_vbias_pins; i++)
+ val |= BIT(st->vbias_pins[i]);
+
+ ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_HEADER_MASK, 0);
+ if (ret)
+ return ret;
+
+ /* FIFO watermark interrupt starts out as enabled, disable it. */
+ ret = ad4130_set_watermark_interrupt_en(st, false);
+ if (ret)
+ return ret;
+
+ /* Setup channels. */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ struct ad4130_chan_info *chan_info = &st->chans_info[i];
+ struct iio_chan_spec *chan = &st->chans[i];
+ unsigned int val;
+
+ val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) |
+ FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1);
+
+ ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_soft_reset(struct ad4130_state *st)
+{
+ int ret;
+
+ ret = spi_write(st->spi, st->reset_buf, sizeof(st->reset_buf));
+ if (ret)
+ return ret;
+
+ fsleep(AD4130_RESET_SLEEP_US);
+
+ return 0;
+}
+
+static void ad4130_disable_regulators(void *data)
+{
+ struct ad4130_state *st = data;
+
+ regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
+}
+
+static int ad4130_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad4130_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ memset(st->reset_buf, 0xff, sizeof(st->reset_buf));
+ init_completion(&st->completion);
+ mutex_init(&st->lock);
+ st->spi = spi;
+
+ /*
+ * Xfer: [ XFR1 ] [ XFR2 ]
+ * Master: 0x7D N ......................
+ * Slave: ...... DATA1 DATA2 ... DATAN
+ */
+ st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG;
+ st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
+ st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
+ st->fifo_xfer[1].rx_buf = st->fifo_rx_buf;
+ spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer,
+ ARRAY_SIZE(st->fifo_xfer));
+
+ indio_dev->name = AD4130_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ad4130_info;
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ st->regulators[0].supply = "avdd";
+ st->regulators[1].supply = "iovdd";
+ st->regulators[2].supply = "refin1";
+ st->regulators[3].supply = "refin2";
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators),
+ st->regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ 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");
+
+ ret = ad4130_soft_reset(st);
+ if (ret)
+ return ret;
+
+ ret = ad4310_parse_fw(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4130_setup(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4130_setup_int_clk(st);
+ if (ret)
+ return ret;
+
+ ad4130_fill_scale_tbls(st);
+
+ st->gc.owner = THIS_MODULE;
+ st->gc.label = AD4130_NAME;
+ st->gc.base = -1;
+ st->gc.ngpio = AD4130_MAX_GPIOS;
+ st->gc.parent = dev;
+ st->gc.can_sleep = true;
+ st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
+ st->gc.get_direction = ad4130_gpio_get_direction;
+ st->gc.set = ad4130_gpio_set;
+
+ ret = devm_gpiochip_add_data(dev, &st->gc, st);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &ad4130_buffer_ops,
+ ad4130_fifo_attributes);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, spi->irq, NULL,
+ ad4130_irq_handler, IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq\n");
+
+ /*
+ * When the chip enters FIFO mode, IRQ polarity is inverted.
+ * When the chip exits FIFO mode, IRQ polarity returns to normal.
+ * See datasheet pages: 65, FIFO Watermark Interrupt section,
+ * and 71, Bit Descriptions for STATUS Register, RDYB.
+ * Cache the normal and inverted IRQ triggers to set them when
+ * entering and exiting FIFO mode.
+ */
+ st->irq_trigger = irq_get_trigger_type(spi->irq);
+ if (st->irq_trigger & IRQF_TRIGGER_RISING)
+ st->inv_irq_trigger = IRQF_TRIGGER_FALLING;
+ else if (st->irq_trigger & IRQF_TRIGGER_FALLING)
+ st->inv_irq_trigger = IRQF_TRIGGER_RISING;
+ else
+ return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n",
+ st->irq_trigger);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad4130_of_match[] = {
+ {
+ .compatible = "adi,ad4130",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4130_of_match);
+
+static struct spi_driver ad4130_driver = {
+ .driver = {
+ .name = AD4130_NAME,
+ .of_match_table = ad4130_of_match,
+ },
+ .probe = ad4130_probe,
+};
+module_spi_driver(ad4130_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4130 SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 4088786e1026..050a2fbf5c49 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -945,6 +945,8 @@ static int ad7124_probe(struct spi_device *spi)
info = of_device_get_match_data(&spi->dev);
if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
+ if (!info)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1021,12 +1023,20 @@ static const struct of_device_id ad7124_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad7124_of_match);
+static const struct spi_device_id ad71124_ids[] = {
+ { "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
+ { "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad71124_ids);
+
static struct spi_driver ad71124_driver = {
.driver = {
.name = "ad7124",
.of_match_table = ad7124_of_match,
},
.probe = ad7124_probe,
+ .id_table = ad71124_ids,
};
module_spi_driver(ad71124_driver);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index d71977be7d22..55a6ab591016 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -177,7 +177,6 @@ struct ad7192_chip_info {
struct ad7192_state {
const struct ad7192_chip_info *chip_info;
struct regulator *avdd;
- struct regulator *dvdd;
struct clk *mclk;
u16 int_vref_mv;
u32 fclk;
@@ -1015,19 +1014,9 @@ static int ad7192_probe(struct spi_device *spi)
if (ret)
return ret;
- st->dvdd = devm_regulator_get(&spi->dev, "dvdd");
- if (IS_ERR(st->dvdd))
- return PTR_ERR(st->dvdd);
-
- ret = regulator_enable(st->dvdd);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified DVdd supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->dvdd);
+ ret = devm_regulator_get_enable(&spi->dev, "dvdd");
if (ret)
- return ret;
+ return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
ret = regulator_get_voltage(st->avdd);
if (ret < 0) {
@@ -1037,6 +1026,8 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret / 1000;
st->chip_info = of_device_get_match_data(&spi->dev);
+ if (!st->chip_info)
+ st->chip_info = (void *)spi_get_device_id(spi)->driver_data;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1098,12 +1089,22 @@ static const struct of_device_id ad7192_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad7192_of_match);
+static const struct spi_device_id ad7192_ids[] = {
+ { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
+ { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
+ { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
+ { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7192_ids);
+
static struct spi_driver ad7192_driver = {
.driver = {
.name = "ad7192",
.of_match_table = ad7192_of_match,
},
.probe = ad7192_probe,
+ .id_table = ad7192_ids,
};
module_spi_driver(ad7192_driver);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 94776f696290..80aebed47d1f 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -368,16 +368,7 @@ static int ad7476_probe(struct spi_device *spi)
}
if (st->chip_info->has_vdrive) {
- reg = devm_regulator_get(&spi->dev, "vdrive");
- if (IS_ERR(reg))
- return PTR_ERR(reg);
-
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
- reg);
+ ret = devm_regulator_get_enable(&spi->dev, "vdrive");
if (ret)
return ret;
}
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index ba24f99523e0..dd6b603f65ea 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -557,13 +557,6 @@ static const struct iio_trigger_ops ad7606_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
-static void ad7606_regulator_disable(void *data)
-{
- struct ad7606_state *st = data;
-
- regulator_disable(st->reg);
-}
-
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_bus_ops *bops)
@@ -589,19 +582,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->scale_avail = ad7606_scale_avail;
st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
- st->reg = devm_regulator_get(dev, "avcc");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret) {
- dev_err(dev, "Failed to enable specified AVcc supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st);
+ ret = devm_regulator_get_enable(dev, "avcc");
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to enable specified AVcc supply\n");
st->chip_info = &ad7606_chip_info_tbl[id];
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 2dc4f599f9df..0c6a88cc4695 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -62,7 +62,6 @@ struct ad7606_chip_info {
* struct ad7606_state - driver instance specific data
* @dev pointer to kernel device
* @chip_info entry in the table of chips that describes this device
- * @reg regulator info for the power supply of the device
* @bops bus operations (SPI or parallel)
* @range voltage range selection, selects which scale to apply
* @oversampling oversampling selection
@@ -92,7 +91,6 @@ struct ad7606_chip_info {
struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
- struct regulator *reg;
const struct ad7606_bus_ops *bops;
unsigned int range[16];
unsigned int oversampling;
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 6dbe9d5e08a2..4730d8d0f4c3 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
@@ -125,6 +126,8 @@ struct ad799x_state {
const struct ad799x_chip_config *chip_config;
struct regulator *reg;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
unsigned id;
u16 config;
@@ -290,7 +293,9 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
+ mutex_lock(&st->lock);
ret = ad799x_scan_direct(st, chan->scan_index);
+ mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
@@ -351,7 +356,8 @@ static ssize_t ad799x_write_frequency(struct device *dev,
if (ret)
return ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
+
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
goto error_ret_mutex;
@@ -373,7 +379,7 @@ static ssize_t ad799x_write_frequency(struct device *dev,
ret = len;
error_ret_mutex:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -407,6 +413,8 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
if (ret)
return ret;
+ mutex_lock(&st->lock);
+
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
else
@@ -418,6 +426,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
+ mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return ret;
}
@@ -454,11 +463,9 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_write_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info),
val << chan->scan_type.shift);
- mutex_unlock(&indio_dev->mlock);
return ret;
}
@@ -473,10 +480,8 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info));
- mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
@@ -863,6 +868,9 @@ static int ad799x_probe(struct i2c_client *client,
if (ret)
goto error_cleanup_ring;
}
+
+ mutex_init(&st->lock);
+
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 7534572f7475..0621cf59d614 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -388,6 +388,8 @@ static int ad9467_probe(struct spi_device *spi)
info = of_device_get_match_data(&spi->dev);
if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
+ if (!info)
return -ENODEV;
conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st));
@@ -447,12 +449,21 @@ static const struct of_device_id ad9467_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad9467_of_match);
+static const struct spi_device_id ad9467_ids[] = {
+ { "ad9265", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9265] },
+ { "ad9434", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9434] },
+ { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9467] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad9467_ids);
+
static struct spi_driver ad9467_driver = {
.driver = {
.name = "ad9467",
.of_match_table = ad9467_of_match,
},
.probe = ad9467_probe,
+ .id_table = ad9467_ids,
};
module_spi_driver(ad9467_driver);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 261a9a6b45e1..d8570f620785 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -281,10 +281,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
unsigned int data_reg;
int ret = 0;
- if (iio_buffer_enabled(indio_dev))
- return -EBUSY;
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
- mutex_lock(&indio_dev->mlock);
ad_sigma_delta_set_channel(sigma_delta, chan->address);
spi_bus_lock(sigma_delta->spi->master);
@@ -323,7 +323,7 @@ out:
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
- mutex_unlock(&indio_dev->mlock);
+ iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 870f4cb60923..ed4f8501bda8 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2193,32 +2193,19 @@ static ssize_t at91_adc_get_watermark(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
}
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", "2");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", AT91_HWFIFO_MAX_SIZE_STR);
-}
-
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
at91_adc_get_fifo_state, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
at91_adc_get_watermark, NULL, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
-
-static const struct attribute *at91_adc_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "2");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR);
+
+static const struct iio_dev_attr *at91_adc_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
@@ -2235,7 +2222,7 @@ static int at91_adc_buffer_and_trigger_init(struct device *dev,
struct iio_dev *indio)
{
struct at91_adc_state *st = iio_priv(indio);
- const struct attribute **fifo_attrs;
+ const struct iio_dev_attr **fifo_attrs;
int ret;
if (st->selected_trig->hw_trig)
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
index 580361bd9849..49fff1cabd0d 100644
--- a/drivers/iio/adc/axp288_adc.c
+++ b/drivers/iio/adc/axp288_adc.c
@@ -9,6 +9,7 @@
#include <linux/dmi.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/regmap.h>
@@ -50,6 +51,8 @@ enum axp288_adc_id {
struct axp288_adc_info {
int irq;
struct regmap *regmap;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
bool ts_enabled;
};
@@ -161,7 +164,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
int ret;
struct axp288_adc_info *info = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON_ONDEMAND,
@@ -178,7 +181,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
default:
ret = -EINVAL;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
@@ -289,6 +292,8 @@ static int axp288_adc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ mutex_init(&info->lock);
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
index e16ac935693b..2cde4b44fc6e 100644
--- a/drivers/iio/adc/cc10001_adc.c
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -305,16 +305,27 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
return 0;
}
+static void cc10001_reg_disable(void *priv)
+{
+ regulator_disable(priv);
+}
+
+static void cc10001_pd_cb(void *priv)
+{
+ cc10001_adc_power_down(priv);
+}
+
static int cc10001_adc_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
struct cc10001_adc_device *adc_dev;
unsigned long adc_clk_rate;
struct iio_dev *indio_dev;
unsigned long channel_map;
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
if (indio_dev == NULL)
return -ENOMEM;
@@ -326,7 +337,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
channel_map &= ~ret;
}
- adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
+ adc_dev->reg = devm_regulator_get(dev, "vref");
if (IS_ERR(adc_dev->reg))
return PTR_ERR(adc_dev->reg);
@@ -334,34 +345,28 @@ static int cc10001_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- indio_dev->name = dev_name(&pdev->dev);
+ ret = devm_add_action_or_reset(dev, cc10001_reg_disable, adc_dev->reg);
+ if (ret)
+ return ret;
+
+ indio_dev->name = dev_name(dev);
indio_dev->info = &cc10001_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(adc_dev->reg_base)) {
- ret = PTR_ERR(adc_dev->reg_base);
- goto err_disable_reg;
- }
+ if (IS_ERR(adc_dev->reg_base))
+ return PTR_ERR(adc_dev->reg_base);
- adc_dev->adc_clk = devm_clk_get(&pdev->dev, "adc");
+ adc_dev->adc_clk = devm_clk_get_enabled(dev, "adc");
if (IS_ERR(adc_dev->adc_clk)) {
- dev_err(&pdev->dev, "failed to get the clock\n");
- ret = PTR_ERR(adc_dev->adc_clk);
- goto err_disable_reg;
- }
-
- ret = clk_prepare_enable(adc_dev->adc_clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable the clock\n");
- goto err_disable_reg;
+ dev_err(dev, "failed to get/enable the clock\n");
+ return PTR_ERR(adc_dev->adc_clk);
}
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
if (!adc_clk_rate) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "null clock rate!\n");
- goto err_disable_clk;
+ dev_err(dev, "null clock rate!\n");
+ return -EINVAL;
}
adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
@@ -375,47 +380,22 @@ static int cc10001_adc_probe(struct platform_device *pdev)
if (adc_dev->shared)
cc10001_adc_power_up(adc_dev);
+ ret = devm_add_action_or_reset(dev, cc10001_pd_cb, adc_dev);
+ if (ret)
+ return ret;
/* Setup the ADC channels available on the device */
ret = cc10001_adc_channel_init(indio_dev, channel_map);
if (ret < 0)
- goto err_disable_clk;
+ return ret;
mutex_init(&adc_dev->lock);
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- &cc10001_adc_trigger_h, NULL);
- if (ret < 0)
- goto err_disable_clk;
-
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &cc10001_adc_trigger_h, NULL);
if (ret < 0)
- goto err_cleanup_buffer;
-
- platform_set_drvdata(pdev, indio_dev);
-
- return 0;
-
-err_cleanup_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-err_disable_clk:
- clk_disable_unprepare(adc_dev->adc_clk);
-err_disable_reg:
- regulator_disable(adc_dev->reg);
- return ret;
-}
-
-static int cc10001_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
-
- cc10001_adc_power_down(adc_dev);
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- clk_disable_unprepare(adc_dev->adc_clk);
- regulator_disable(adc_dev->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id cc10001_adc_dt_ids[] = {
@@ -430,7 +410,6 @@ static struct platform_driver cc10001_adc_driver = {
.of_match_table = cc10001_adc_dt_ids,
},
.probe = cc10001_adc_probe,
- .remove = cc10001_adc_remove,
};
module_platform_driver(cc10001_adc_driver);
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 86caff1d006b..22da81bac97f 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -108,7 +109,8 @@ struct imx7d_adc {
struct device *dev;
void __iomem *regs;
struct clk *clk;
-
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
u32 vref_uv;
u32 value;
u32 channel;
@@ -293,7 +295,7 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
reinit_completion(&info->completion);
channel = chan->channel & 0x03;
@@ -303,16 +305,16 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
ret = wait_for_completion_interruptible_timeout
(&info->completion, IMX7D_ADC_TIMEOUT);
if (ret == 0) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return -ETIMEDOUT;
}
if (ret < 0) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
*val = info->value;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -531,6 +533,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mutex_init(&info->lock);
+
ret = devm_iio_device_register(dev, indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c
index b56ce15255cf..732c924a976d 100644
--- a/drivers/iio/adc/lpc32xx_adc.c
+++ b/drivers/iio/adc/lpc32xx_adc.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -49,6 +50,8 @@ struct lpc32xx_adc_state {
struct clk *clk;
struct completion completion;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
u32 value;
};
@@ -64,10 +67,10 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = clk_prepare_enable(st->clk);
if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
/* Measurement setup */
@@ -80,7 +83,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
wait_for_completion(&st->completion); /* set by ISR */
clk_disable_unprepare(st->clk);
*val = st->value;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return IIO_VAL_INT;
@@ -201,6 +204,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
iodev->modes = INDIO_DIRECT_MODE;
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
+ mutex_init(&st->lock);
+
retval = devm_iio_device_register(&pdev->dev, iodev);
if (retval)
return retval;
diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index f52d37af4d1f..996f6cbbed3c 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -10,6 +10,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include "ltc2497.h"
@@ -81,9 +82,9 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&ddata->lock);
ret = ltc2497core_read(ddata, chan->address, val);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&ddata->lock);
if (ret < 0)
return ret;
@@ -214,6 +215,8 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
ddata->time_prev = ktime_get();
+ mutex_init(&ddata->lock);
+
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index e023de0d88c4..781519b52475 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -12,6 +12,8 @@ struct ltc2497_chip_info {
struct ltc2497core_driverdata {
struct regulator *ref;
ktime_t time_prev;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
const struct ltc2497_chip_info *chip_info;
u8 addr_prev;
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
new file mode 100644
index 000000000000..8cd566367187
--- /dev/null
+++ b/drivers/iio/adc/max11410.c
@@ -0,0 +1,1050 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX11410 SPI ADC driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+#include <asm-generic/unaligned.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX11410_REG_CONV_START 0x01
+#define MAX11410_CONV_TYPE_SINGLE 0x00
+#define MAX11410_CONV_TYPE_CONTINUOUS 0x01
+#define MAX11410_REG_CAL_START 0x03
+#define MAX11410_CAL_START_SELF 0x00
+#define MAX11410_CAL_START_PGA 0x01
+#define MAX11410_REG_GPIO_CTRL(ch) ((ch) ? 0x05 : 0x04)
+#define MAX11410_GPIO_INTRB 0xC1
+#define MAX11410_REG_FILTER 0x08
+#define MAX11410_FILTER_RATE_MASK GENMASK(3, 0)
+#define MAX11410_FILTER_RATE_MAX 0x0F
+#define MAX11410_FILTER_LINEF_MASK GENMASK(5, 4)
+#define MAX11410_FILTER_50HZ BIT(5)
+#define MAX11410_FILTER_60HZ BIT(4)
+#define MAX11410_REG_CTRL 0x09
+#define MAX11410_CTRL_REFSEL_MASK GENMASK(2, 0)
+#define MAX11410_CTRL_VREFN_BUF_BIT BIT(3)
+#define MAX11410_CTRL_VREFP_BUF_BIT BIT(4)
+#define MAX11410_CTRL_FORMAT_BIT BIT(5)
+#define MAX11410_CTRL_UNIPOLAR_BIT BIT(6)
+#define MAX11410_REG_MUX_CTRL0 0x0B
+#define MAX11410_REG_PGA 0x0E
+#define MAX11410_PGA_GAIN_MASK GENMASK(2, 0)
+#define MAX11410_PGA_SIG_PATH_MASK GENMASK(5, 4)
+#define MAX11410_PGA_SIG_PATH_BUFFERED 0x00
+#define MAX11410_PGA_SIG_PATH_BYPASS 0x01
+#define MAX11410_PGA_SIG_PATH_PGA 0x02
+#define MAX11410_REG_DATA0 0x30
+#define MAX11410_REG_STATUS 0x38
+#define MAX11410_STATUS_CONV_READY_BIT BIT(0)
+#define MAX11410_STATUS_CAL_READY_BIT BIT(2)
+
+#define MAX11410_REFSEL_AVDD_AGND 0x03
+#define MAX11410_REFSEL_MAX 0x06
+#define MAX11410_SIG_PATH_MAX 0x02
+#define MAX11410_CHANNEL_INDEX_MAX 0x0A
+#define MAX11410_AINP_AVDD 0x0A
+#define MAX11410_AINN_GND 0x0A
+
+#define MAX11410_CONVERSION_TIMEOUT_MS 2000
+#define MAX11410_CALIB_TIMEOUT_MS 2000
+
+#define MAX11410_SCALE_AVAIL_SIZE 8
+
+enum max11410_filter {
+ MAX11410_FILTER_FIR5060,
+ MAX11410_FILTER_FIR50,
+ MAX11410_FILTER_FIR60,
+ MAX11410_FILTER_SINC4,
+};
+
+static const u8 max11410_sampling_len[] = {
+ [MAX11410_FILTER_FIR5060] = 5,
+ [MAX11410_FILTER_FIR50] = 6,
+ [MAX11410_FILTER_FIR60] = 6,
+ [MAX11410_FILTER_SINC4] = 10,
+};
+
+static const int max11410_sampling_rates[4][10][2] = {
+ [MAX11410_FILTER_FIR5060] = {
+ { 1, 100000 },
+ { 2, 100000 },
+ { 4, 200000 },
+ { 8, 400000 },
+ { 16, 800000 }
+ },
+ [MAX11410_FILTER_FIR50] = {
+ { 1, 300000 },
+ { 2, 700000 },
+ { 5, 300000 },
+ { 10, 700000 },
+ { 21, 300000 },
+ { 40 }
+ },
+ [MAX11410_FILTER_FIR60] = {
+ { 1, 300000 },
+ { 2, 700000 },
+ { 5, 300000 },
+ { 10, 700000 },
+ { 21, 300000 },
+ { 40 }
+ },
+ [MAX11410_FILTER_SINC4] = {
+ { 4 },
+ { 10 },
+ { 20 },
+ { 40 },
+ { 60 },
+ { 120 },
+ { 240 },
+ { 480 },
+ { 960 },
+ { 1920 }
+ }
+};
+
+struct max11410_channel_config {
+ u32 settling_time_us;
+ u32 *scale_avail;
+ u8 refsel;
+ u8 sig_path;
+ u8 gain;
+ bool bipolar;
+ bool buffered_vrefp;
+ bool buffered_vrefn;
+};
+
+struct max11410_state {
+ struct spi_device *spi_dev;
+ struct iio_trigger *trig;
+ struct completion completion;
+ struct mutex lock; /* Prevent changing channel config during sampling */
+ struct regmap *regmap;
+ struct regulator *avdd;
+ struct regulator *vrefp[3];
+ struct regulator *vrefn[3];
+ struct max11410_channel_config *channels;
+ int irq;
+ struct {
+ u32 data __aligned(IIO_DMA_MINALIGN);
+ s64 ts __aligned(8);
+ } scan;
+};
+
+static const struct iio_chan_spec chanspec_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_LE,
+ },
+};
+
+static unsigned int max11410_reg_size(unsigned int reg)
+{
+ /* Registers from 0x00 to 0x10 are 1 byte, the rest are 3 bytes long. */
+ return reg <= 0x10 ? 1 : 3;
+}
+
+static int max11410_write_reg(struct max11410_state *st, unsigned int reg,
+ unsigned int val)
+{
+ /* This driver only needs to write 8-bit registers */
+ if (max11410_reg_size(reg) != 1)
+ return -EINVAL;
+
+ return regmap_write(st->regmap, reg, val);
+}
+
+static int max11410_read_reg(struct max11410_state *st, unsigned int reg,
+ int *val)
+{
+ int ret;
+
+ if (max11410_reg_size(reg) == 3) {
+ ret = regmap_bulk_read(st->regmap, reg, &st->scan.data, 3);
+ if (ret)
+ return ret;
+
+ *val = get_unaligned_be24(&st->scan.data);
+ return 0;
+ }
+
+ return regmap_read(st->regmap, reg, val);
+}
+
+static struct regulator *max11410_get_vrefp(struct max11410_state *st,
+ u8 refsel)
+{
+ refsel = refsel % 4;
+ if (refsel == 3)
+ return st->avdd;
+
+ return st->vrefp[refsel];
+}
+
+static struct regulator *max11410_get_vrefn(struct max11410_state *st,
+ u8 refsel)
+{
+ if (refsel > 2)
+ return NULL;
+
+ return st->vrefn[refsel];
+}
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x39,
+};
+
+static ssize_t max11410_notch_en_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+ unsigned int val;
+ int ret;
+
+ ret = max11410_read_reg(state, MAX11410_REG_FILTER, &val);
+ if (ret)
+ return ret;
+
+ switch (iio_attr->address) {
+ case 0:
+ val = !FIELD_GET(MAX11410_FILTER_50HZ, val);
+ break;
+ case 1:
+ val = !FIELD_GET(MAX11410_FILTER_60HZ, val);
+ break;
+ case 2:
+ val = FIELD_GET(MAX11410_FILTER_LINEF_MASK, val) == 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t max11410_notch_en_store(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ unsigned int filter_bits;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ switch (iio_attr->address) {
+ case 0:
+ filter_bits = MAX11410_FILTER_50HZ;
+ break;
+ case 1:
+ filter_bits = MAX11410_FILTER_60HZ;
+ break;
+ case 2:
+ default:
+ filter_bits = MAX11410_FILTER_50HZ | MAX11410_FILTER_60HZ;
+ enable = !enable;
+ break;
+ }
+
+ if (enable)
+ ret = regmap_clear_bits(state->regmap, MAX11410_REG_FILTER,
+ filter_bits);
+ else
+ ret = regmap_set_bits(state->regmap, MAX11410_REG_FILTER,
+ filter_bits);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t in_voltage_filter2_notch_center_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ int ret, reg, rate, filter;
+
+ ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg);
+ if (ret)
+ return ret;
+
+ rate = FIELD_GET(MAX11410_FILTER_RATE_MASK, reg);
+ rate = clamp_val(rate, 0,
+ max11410_sampling_len[MAX11410_FILTER_SINC4] - 1);
+ filter = max11410_sampling_rates[MAX11410_FILTER_SINC4][rate][0];
+
+ return sysfs_emit(buf, "%d\n", filter);
+}
+
+static IIO_CONST_ATTR(in_voltage_filter0_notch_center, "50");
+static IIO_CONST_ATTR(in_voltage_filter1_notch_center, "60");
+static IIO_DEVICE_ATTR_RO(in_voltage_filter2_notch_center, 2);
+
+static IIO_DEVICE_ATTR(in_voltage_filter0_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 0);
+static IIO_DEVICE_ATTR(in_voltage_filter1_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 1);
+static IIO_DEVICE_ATTR(in_voltage_filter2_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 2);
+
+static struct attribute *max11410_attributes[] = {
+ &iio_const_attr_in_voltage_filter0_notch_center.dev_attr.attr,
+ &iio_const_attr_in_voltage_filter1_notch_center.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter2_notch_center.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter0_notch_en.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter1_notch_en.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter2_notch_en.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max11410_attribute_group = {
+ .attrs = max11410_attributes,
+};
+
+static int max11410_set_input_mux(struct max11410_state *st, u8 ainp, u8 ainn)
+{
+ if (ainp > MAX11410_CHANNEL_INDEX_MAX ||
+ ainn > MAX11410_CHANNEL_INDEX_MAX)
+ return -EINVAL;
+
+ return max11410_write_reg(st, MAX11410_REG_MUX_CTRL0,
+ (ainp << 4) | ainn);
+}
+
+static int max11410_configure_channel(struct max11410_state *st,
+ struct iio_chan_spec const *chan)
+{
+ struct max11410_channel_config cfg = st->channels[chan->address];
+ unsigned int regval;
+ int ret;
+
+ if (chan->differential)
+ ret = max11410_set_input_mux(st, chan->channel, chan->channel2);
+ else
+ ret = max11410_set_input_mux(st, chan->channel,
+ MAX11410_AINN_GND);
+
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(MAX11410_CTRL_VREFP_BUF_BIT, cfg.buffered_vrefp) |
+ FIELD_PREP(MAX11410_CTRL_VREFN_BUF_BIT, cfg.buffered_vrefn) |
+ FIELD_PREP(MAX11410_CTRL_REFSEL_MASK, cfg.refsel) |
+ FIELD_PREP(MAX11410_CTRL_UNIPOLAR_BIT, cfg.bipolar ? 0 : 1);
+ ret = regmap_update_bits(st->regmap, MAX11410_REG_CTRL,
+ MAX11410_CTRL_REFSEL_MASK |
+ MAX11410_CTRL_VREFN_BUF_BIT |
+ MAX11410_CTRL_VREFN_BUF_BIT |
+ MAX11410_CTRL_UNIPOLAR_BIT, regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK, cfg.sig_path) |
+ FIELD_PREP(MAX11410_PGA_GAIN_MASK, cfg.gain);
+ ret = regmap_write(st->regmap, MAX11410_REG_PGA, regval);
+ if (ret)
+ return ret;
+
+ if (cfg.settling_time_us)
+ fsleep(cfg.settling_time_us);
+
+ return 0;
+}
+
+static int max11410_sample(struct max11410_state *st, int *sample_raw,
+ struct iio_chan_spec const *chan)
+{
+ int val, ret;
+
+ ret = max11410_configure_channel(st, chan);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0)
+ reinit_completion(&st->completion);
+
+ /* Start Conversion */
+ ret = max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_SINGLE);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0) {
+ /* Wait for an interrupt. */
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(MAX11410_CONVERSION_TIMEOUT_MS));
+ if (!ret)
+ return -ETIMEDOUT;
+ } else {
+ /* Wait for status register Conversion Ready flag */
+ ret = read_poll_timeout(max11410_read_reg, ret,
+ ret || (val & MAX11410_STATUS_CONV_READY_BIT),
+ 5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000,
+ true, st, MAX11410_REG_STATUS, &val);
+ if (ret)
+ return ret;
+ }
+
+ /* Read ADC Data */
+ return max11410_read_reg(st, MAX11410_REG_DATA0, sample_raw);
+}
+
+static int max11410_get_scale(struct max11410_state *state,
+ struct max11410_channel_config cfg)
+{
+ struct regulator *vrefp, *vrefn;
+ int scale;
+
+ vrefp = max11410_get_vrefp(state, cfg.refsel);
+
+ scale = regulator_get_voltage(vrefp) / 1000;
+ vrefn = max11410_get_vrefn(state, cfg.refsel);
+ if (vrefn)
+ scale -= regulator_get_voltage(vrefn) / 1000;
+
+ if (cfg.bipolar)
+ scale *= 2;
+
+ return scale >> cfg.gain;
+}
+
+static int max11410_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct max11410_state *state = iio_priv(indio_dev);
+ struct max11410_channel_config cfg = state->channels[chan->address];
+ int ret, reg_val, filter, rate;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *val = max11410_get_scale(state, cfg);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ if (cfg.bipolar)
+ *val = -BIT(chan->scan_type.realbits - 1);
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&state->lock);
+
+ ret = max11410_sample(state, &reg_val, chan);
+
+ mutex_unlock(&state->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ if (ret)
+ return ret;
+
+ *val = reg_val;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+ rate = reg_val & MAX11410_FILTER_RATE_MASK;
+ if (rate >= max11410_sampling_len[filter])
+ rate = max11410_sampling_len[filter] - 1;
+
+ *val = max11410_sampling_rates[filter][rate][0];
+ *val2 = max11410_sampling_rates[filter][rate][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ return -EINVAL;
+}
+
+static int max11410_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ int i, ret, reg_val, filter, gain;
+ u32 *scale_avail;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ scale_avail = st->channels[chan->address].scale_avail;
+ if (!scale_avail)
+ return -EOPNOTSUPP;
+
+ /* Accept values in range 0.000001 <= scale < 1.000000 */
+ if (val != 0 || val2 == 0)
+ return -EINVAL;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Convert from INT_PLUS_MICRO to FRACTIONAL_LOG2 */
+ val2 = val2 * DIV_ROUND_CLOSEST(BIT(24), 1000000);
+ val2 = DIV_ROUND_CLOSEST(scale_avail[0], val2);
+ gain = order_base_2(val2);
+
+ st->channels[chan->address].gain = clamp_val(gain, 0, 7);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+
+ ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ goto out;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+ for (i = 0; i < max11410_sampling_len[filter]; ++i) {
+ if (val == max11410_sampling_rates[filter][i][0] &&
+ val2 == max11410_sampling_rates[filter][i][1])
+ break;
+ }
+ if (i == max11410_sampling_len[filter]) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK, i);
+
+out:
+ mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max11410_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ struct max11410_channel_config cfg;
+ int ret, reg_val, filter;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+ *vals = (const int *)max11410_sampling_rates[filter];
+ *length = max11410_sampling_len[filter] * 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ cfg = st->channels[chan->address];
+
+ if (!cfg.scale_avail)
+ return -EINVAL;
+
+ *vals = cfg.scale_avail;
+ *length = MAX11410_SCALE_AVAIL_SIZE * 2;
+ *type = IIO_VAL_FRACTIONAL_LOG2;
+
+ return IIO_AVAIL_LIST;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info max11410_info = {
+ .read_raw = max11410_read_raw,
+ .write_raw = max11410_write_raw,
+ .read_avail = max11410_read_avail,
+ .attrs = &max11410_attribute_group,
+};
+
+static irqreturn_t max11410_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct max11410_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = max11410_read_reg(st, MAX11410_REG_DATA0, &st->scan.data);
+ if (ret) {
+ dev_err(&indio_dev->dev, "cannot read data\n");
+ goto out;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
+ iio_get_time_ns(indio_dev));
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int max11410_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ int scan_ch, ret;
+
+ scan_ch = ffs(*indio_dev->active_scan_mask) - 1;
+
+ ret = max11410_configure_channel(st, &indio_dev->channels[scan_ch]);
+ if (ret)
+ return ret;
+
+ /* Start continuous conversion. */
+ return max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_CONTINUOUS);
+}
+
+static int max11410_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ /* Stop continuous conversion. */
+ return max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_SINGLE);
+}
+
+static const struct iio_buffer_setup_ops max11410_buffer_ops = {
+ .postenable = &max11410_buffer_postenable,
+ .predisable = &max11410_buffer_predisable,
+ .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_trigger_ops max11410_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static irqreturn_t max11410_interrupt(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll_chained(st->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+};
+
+static int max11410_parse_channels(struct max11410_state *st,
+ struct iio_dev *indio_dev)
+{
+ struct iio_chan_spec chanspec = chanspec_template;
+ struct device *dev = &st->spi_dev->dev;
+ struct max11410_channel_config *cfg;
+ struct iio_chan_spec *channels;
+ struct fwnode_handle *child;
+ u32 reference, sig_path;
+ const char *node_name;
+ u32 inputs[2], scale;
+ unsigned int num_ch;
+ int chan_idx = 0;
+ int ret, i;
+
+ num_ch = device_get_child_node_count(dev);
+ if (num_ch == 0)
+ return dev_err_probe(&indio_dev->dev, -ENODEV,
+ "FW has no channels defined\n");
+
+ /* Reserve space for soft timestamp channel */
+ num_ch++;
+ channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ st->channels = devm_kcalloc(dev, num_ch, sizeof(*st->channels),
+ GFP_KERNEL);
+ if (!st->channels)
+ return -ENOMEM;
+
+ device_for_each_child_node(dev, child) {
+ node_name = fwnode_get_name(child);
+ if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ inputs,
+ ARRAY_SIZE(inputs));
+
+ chanspec.differential = 1;
+ } else {
+ ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+ inputs[1] = 0;
+ chanspec.differential = 0;
+ }
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+
+ if (inputs[0] > MAX11410_CHANNEL_INDEX_MAX ||
+ inputs[1] > MAX11410_CHANNEL_INDEX_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid channel index for %s, should be less than %d\n",
+ node_name,
+ MAX11410_CHANNEL_INDEX_MAX + 1);
+ }
+
+ cfg = &st->channels[chan_idx];
+
+ reference = MAX11410_REFSEL_AVDD_AGND;
+ fwnode_property_read_u32(child, "adi,reference", &reference);
+ if (reference > MAX11410_REFSEL_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid adi,reference value for %s, should be less than %d.\n",
+ node_name, MAX11410_REFSEL_MAX + 1);
+ }
+
+ if (!max11410_get_vrefp(st, reference) ||
+ (!max11410_get_vrefn(st, reference) && reference <= 2)) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid VREF configuration for %s, either specify corresponding VREF regulators or change adi,reference property.\n",
+ node_name);
+ }
+
+ sig_path = MAX11410_PGA_SIG_PATH_BUFFERED;
+ fwnode_property_read_u32(child, "adi,input-mode", &sig_path);
+ if (sig_path > MAX11410_SIG_PATH_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid adi,input-mode value for %s, should be less than %d.\n",
+ node_name, MAX11410_SIG_PATH_MAX + 1);
+ }
+
+ fwnode_property_read_u32(child, "settling-time-us",
+ &cfg->settling_time_us);
+ cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
+ cfg->buffered_vrefp = fwnode_property_read_bool(child, "adi,buffered-vrefp");
+ cfg->buffered_vrefn = fwnode_property_read_bool(child, "adi,buffered-vrefn");
+ cfg->refsel = reference;
+ cfg->sig_path = sig_path;
+ cfg->gain = 0;
+
+ /* Enable scale_available property if input mode is PGA */
+ if (sig_path == MAX11410_PGA_SIG_PATH_PGA) {
+ __set_bit(IIO_CHAN_INFO_SCALE,
+ &chanspec.info_mask_separate_available);
+ cfg->scale_avail = devm_kcalloc(dev, MAX11410_SCALE_AVAIL_SIZE * 2,
+ sizeof(*cfg->scale_avail),
+ GFP_KERNEL);
+ if (!cfg->scale_avail) {
+ fwnode_handle_put(child);
+ return -ENOMEM;
+ }
+
+ scale = max11410_get_scale(st, *cfg);
+ for (i = 0; i < MAX11410_SCALE_AVAIL_SIZE; i++) {
+ cfg->scale_avail[2 * i] = scale >> i;
+ cfg->scale_avail[2 * i + 1] = chanspec.scan_type.realbits;
+ }
+ } else {
+ __clear_bit(IIO_CHAN_INFO_SCALE,
+ &chanspec.info_mask_separate_available);
+ }
+
+ chanspec.address = chan_idx;
+ chanspec.scan_index = chan_idx;
+ chanspec.channel = inputs[0];
+ chanspec.channel2 = inputs[1];
+
+ channels[chan_idx] = chanspec;
+ chan_idx++;
+ }
+
+ channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
+
+ indio_dev->num_channels = chan_idx + 1;
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static void max11410_disable_reg(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static int max11410_init_vref(struct device *dev,
+ struct regulator **vref,
+ const char *id)
+{
+ struct regulator *reg;
+ int ret;
+
+ reg = devm_regulator_get_optional(dev, id);
+ if (PTR_ERR(reg) == -ENODEV) {
+ *vref = NULL;
+ return 0;
+ } else if (IS_ERR(reg)) {
+ return PTR_ERR(reg);
+ }
+ ret = regulator_enable(reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable regulator %s\n", id);
+
+ *vref = reg;
+ return devm_add_action_or_reset(dev, max11410_disable_reg, reg);
+}
+
+static int max11410_calibrate(struct max11410_state *st, u32 cal_type)
+{
+ int ret, val;
+
+ ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type);
+ if (ret)
+ return ret;
+
+ /* Wait for status register Calibration Ready flag */
+ return read_poll_timeout(max11410_read_reg, ret,
+ ret || (val & MAX11410_STATUS_CAL_READY_BIT),
+ 50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
+ st, MAX11410_REG_STATUS, &val);
+}
+
+static int max11410_self_calibrate(struct max11410_state *st)
+{
+ int ret, i;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK,
+ FIELD_PREP(MAX11410_FILTER_RATE_MASK,
+ MAX11410_FILTER_RATE_MAX));
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, MAX11410_CAL_START_SELF);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_SIG_PATH_MASK,
+ FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+ MAX11410_PGA_SIG_PATH_PGA));
+ if (ret)
+ return ret;
+
+ /* PGA calibrations */
+ for (i = 1; i < 8; ++i) {
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_GAIN_MASK, i);
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, MAX11410_CAL_START_PGA);
+ if (ret)
+ return ret;
+ }
+
+ /* Cleanup */
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_GAIN_MASK, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK, 0);
+ if (ret)
+ return ret;
+
+ return regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_SIG_PATH_MASK,
+ FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+ MAX11410_PGA_SIG_PATH_BUFFERED));
+}
+
+static int max11410_probe(struct spi_device *spi)
+{
+ const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
+ const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
+ struct device *dev = &spi->dev;
+ struct max11410_state *st;
+ struct iio_dev *indio_dev;
+ int ret, irqs[2];
+ int i;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi_dev = spi;
+ init_completion(&st->completion);
+ mutex_init(&st->lock);
+
+ indio_dev->name = "max11410";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &max11410_info;
+
+ st->regmap = devm_regmap_init_spi(spi, &regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "regmap initialization failed\n");
+
+ ret = max11410_init_vref(dev, &st->avdd, "avdd");
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(vrefp_regs); i++) {
+ ret = max11410_init_vref(dev, &st->vrefp[i], vrefp_regs[i]);
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(dev, &st->vrefn[i], vrefn_regs[i]);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Regulators must be configured before parsing channels for
+ * validating "adi,reference" property of each channel.
+ */
+ ret = max11410_parse_channels(st, indio_dev);
+ if (ret)
+ return ret;
+
+ irqs[0] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio0");
+ irqs[1] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio1");
+
+ if (irqs[0] > 0) {
+ st->irq = irqs[0];
+ ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(0),
+ MAX11410_GPIO_INTRB);
+ } else if (irqs[1] > 0) {
+ st->irq = irqs[1];
+ ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(1),
+ MAX11410_GPIO_INTRB);
+ } else if (spi->irq > 0) {
+ return dev_err_probe(dev, -ENODEV,
+ "no interrupt name specified");
+ }
+
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->regmap, MAX11410_REG_CTRL,
+ MAX11410_CTRL_FORMAT_BIT);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &max11410_trigger_handler,
+ &max11410_buffer_ops);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0) {
+ 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 = &max11410_trigger_ops;
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, st->irq, NULL,
+ &max11410_interrupt,
+ IRQF_ONESHOT, "max11410",
+ indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = max11410_self_calibrate(st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "cannot perform device self calibration\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id max11410_spi_of_id[] = {
+ { .compatible = "adi,max11410" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max11410_spi_of_id);
+
+static const struct spi_device_id max11410_id[] = {
+ { "max11410" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max11410_id);
+
+static struct spi_driver max11410_driver = {
+ .driver = {
+ .name = "max11410",
+ .of_match_table = max11410_spi_of_id,
+ },
+ .probe = max11410_probe,
+ .id_table = max11410_id,
+};
+module_spi_driver(max11410_driver);
+
+MODULE_AUTHOR("David Jung <David.Jung@analog.com>");
+MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
+MODULE_DESCRIPTION("Analog Devices MAX11410 ADC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
index a815ad1f6913..500bb09ab19b 100644
--- a/drivers/iio/adc/max1241.c
+++ b/drivers/iio/adc/max1241.c
@@ -22,7 +22,6 @@ enum max1241_id {
struct max1241 {
struct spi_device *spi;
struct mutex lock;
- struct regulator *vdd;
struct regulator *vref;
struct gpio_desc *shutdown;
@@ -110,17 +109,6 @@ static const struct iio_info max1241_info = {
.read_raw = max1241_read_raw,
};
-static void max1241_disable_vdd_action(void *data)
-{
- struct max1241 *adc = data;
- struct device *dev = &adc->spi->dev;
- int err;
-
- err = regulator_disable(adc->vdd);
- if (err)
- dev_err(dev, "could not disable vdd regulator.\n");
-}
-
static void max1241_disable_vref_action(void *data)
{
struct max1241 *adc = data;
@@ -147,20 +135,10 @@ static int max1241_probe(struct spi_device *spi)
adc->spi = spi;
mutex_init(&adc->lock);
- adc->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(adc->vdd))
- return dev_err_probe(dev, PTR_ERR(adc->vdd),
- "failed to get vdd regulator\n");
-
- ret = regulator_enable(adc->vdd);
+ ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, max1241_disable_vdd_action, adc);
- if (ret) {
- dev_err(dev, "could not set up vdd regulator cleanup action\n");
- return ret;
- }
+ return dev_err_probe(dev, ret,
+ "failed to get/enable vdd regulator\n");
adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(adc->vref))
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index a28cf86cdce8..42d3479cefb7 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -148,7 +148,6 @@ struct max1363_chip_info {
* @chip_info: chip model specific constants, available modes, etc.
* @current_mode: the scan mode of this chip
* @requestedmask: a valid requested set of channels
- * @reg: supply regulator
* @lock: lock to ensure state is consistent
* @monitor_on: whether monitor mode is enabled
* @monitor_speed: parameter corresponding to device monitor speed setting
@@ -168,7 +167,6 @@ struct max1363_state {
const struct max1363_chip_info *chip_info;
const struct max1363_mode *current_mode;
u32 requestedmask;
- struct regulator *reg;
struct mutex lock;
/* Using monitor modes and buffer at the same time is
@@ -1597,15 +1595,7 @@ static int max1363_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
mutex_init(&st->lock);
- st->reg = devm_regulator_get(&client->dev, "vcc");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, st->reg);
+ ret = devm_regulator_get_enable(&client->dev, "vcc");
if (ret)
return ret;
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 76b334f5ac61..974c5bd923a6 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -29,6 +29,8 @@
#define MCP3911_REG_MOD 0x06
#define MCP3911_REG_PHASE 0x07
#define MCP3911_REG_GAIN 0x09
+#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch)
+#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch))
#define MCP3911_REG_STATUSCOM 0x0a
#define MCP3911_STATUSCOM_DRHIZ BIT(12)
@@ -60,8 +62,10 @@
#define MCP3911_REG_MASK GENMASK(4, 1)
#define MCP3911_NUM_CHANNELS 2
+#define MCP3911_NUM_SCALES 6
static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2];
struct mcp3911 {
struct spi_device *spi;
@@ -70,6 +74,7 @@ struct mcp3911 {
struct clk *clki;
u32 dev_addr;
struct iio_trigger *trig;
+ u32 gain[MCP3911_NUM_CHANNELS];
struct {
u32 channels[MCP3911_NUM_CHANNELS];
s64 ts __aligned(8);
@@ -146,6 +151,11 @@ static int mcp3911_read_avail(struct iio_dev *indio_dev,
*vals = mcp3911_osr_table;
*length = ARRAY_SIZE(mcp3911_osr_table);
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *vals = (int *)mcp3911_scale_table;
+ *length = ARRAY_SIZE(mcp3911_scale_table) * 2;
+ return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
@@ -190,29 +200,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_SCALE:
- if (adc->vref) {
- ret = regulator_get_voltage(adc->vref);
- if (ret < 0) {
- dev_err(indio_dev->dev.parent,
- "failed to get vref voltage: %d\n",
- ret);
- goto out;
- }
-
- *val = ret / 1000;
- } else {
- *val = MCP3911_INT_VREF_MV;
- }
-
- /*
- * For 24bit Conversion
- * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
- * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
- */
-
- /* val2 = (2^23 * 1.5) */
- *val2 = 12582912;
- ret = IIO_VAL_FRACTIONAL;
+ *val = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][0];
+ *val2 = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][1];
+ ret = IIO_VAL_INT_PLUS_NANO;
break;
}
@@ -230,6 +220,18 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
mutex_lock(&adc->lock);
switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+ if (val == mcp3911_scale_table[i][0] &&
+ val2 == mcp3911_scale_table[i][1]) {
+
+ adc->gain[channel->channel] = BIT(i);
+ ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(channel->channel),
+ MCP3911_GAIN_VAL(channel->channel, i), 1);
+ }
+ }
+ break;
case IIO_CHAN_INFO_OFFSET:
if (val2 != 0) {
ret = -EINVAL;
@@ -265,6 +267,44 @@ out:
return ret;
}
+static int mcp3911_calc_scale_table(struct mcp3911 *adc)
+{
+ u32 ref = MCP3911_INT_VREF_MV;
+ u32 div;
+ int ret;
+ u64 tmp;
+
+ if (adc->vref) {
+ ret = regulator_get_voltage(adc->vref);
+ if (ret < 0) {
+ dev_err(&adc->spi->dev,
+ "failed to get vref voltage: %d\n",
+ ret);
+ return ret;
+ }
+
+ ref = ret / 1000;
+ }
+
+ /*
+ * For 24-bit Conversion
+ * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
+ * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
+ *
+ * ref = Reference voltage
+ * div = (2^23 * 1.5 * gain) = 12582912 * gain
+ */
+ for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+ div = 12582912 * BIT(i);
+ tmp = div_s64((s64)ref * 1000000000LL, div);
+
+ mcp3911_scale_table[i][0] = 0;
+ mcp3911_scale_table[i][1] = tmp;
+ }
+
+ return 0;
+}
+
#define MCP3911_CHAN(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -274,8 +314,10 @@ out:
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_shared_by_type_available = \
+ .info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_separate_available = \
+ BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 's', \
.realbits = 24, \
@@ -482,6 +524,20 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
+ ret = mcp3911_calc_scale_table(adc);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) {
+ adc->gain[i] = 1;
+ ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(i),
+ MCP3911_GAIN_VAL(i, 0), 1);
+ if (ret)
+ return ret;
+ }
+
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp3911_info;
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 1a68b099d323..85b6826cc10c 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/interrupt.h>
#include <linux/of.h>
@@ -276,6 +277,8 @@ struct meson_sar_adc_priv {
struct clk *adc_div_clk;
struct clk_divider clk_div;
struct completion done;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
int calibbias;
int calibscale;
struct regmap *tsc_regmap;
@@ -486,7 +489,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
int val, ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&priv->lock);
if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
@@ -504,7 +507,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
!(val & MESON_SAR_ADC_DELAY_BL30_BUSY),
1, 10000);
if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&priv->lock);
return ret;
}
}
@@ -521,7 +524,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&priv->lock);
}
static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev)
@@ -1250,6 +1253,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (ret)
goto err;
+ mutex_init(&priv->lock);
+
ret = meson_sar_adc_hw_enable(indio_dev);
if (ret)
goto err;
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644
index 000000000000..bc62e5a9d50d
--- /dev/null
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.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/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3 0x113
+#define MT6370_REG_CHG_CTRL7 0x117
+#define MT6370_REG_CHG_ADC 0x121
+#define MT6370_REG_ADC_DATA_H 0x14C
+
+#define MT6370_ADC_START_MASK BIT(0)
+#define MT6370_ADC_IN_SEL_MASK GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK GENMASK(7, 2)
+
+#define MT6370_AICR_100_mA 0x0
+#define MT6370_AICR_150_mA 0x1
+#define MT6370_AICR_200_mA 0x2
+#define MT6370_AICR_250_mA 0x3
+#define MT6370_AICR_300_mA 0x4
+#define MT6370_AICR_350_mA 0x5
+
+#define MT6370_ICHG_100_mA 0x0
+#define MT6370_ICHG_200_mA 0x1
+#define MT6370_ICHG_300_mA 0x2
+#define MT6370_ICHG_400_mA 0x3
+#define MT6370_ICHG_500_mA 0x4
+#define MT6370_ICHG_600_mA 0x5
+#define MT6370_ICHG_700_mA 0x6
+#define MT6370_ICHG_800_mA 0x7
+
+#define ADC_CONV_TIME_MS 35
+#define ADC_CONV_POLLING_TIME_US 1000
+
+struct mt6370_adc_data {
+ struct device *dev;
+ struct regmap *regmap;
+ /*
+ * This mutex lock is for preventing the different ADC channels
+ * from being read at the same time.
+ */
+ struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+ unsigned long addr, int *val)
+{
+ unsigned int reg_val;
+ __be16 be_val;
+ int ret;
+
+ mutex_lock(&priv->adc_lock);
+
+ reg_val = MT6370_ADC_START_MASK |
+ FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+ ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+ if (ret)
+ goto adc_unlock;
+
+ msleep(ADC_CONV_TIME_MS);
+
+ ret = regmap_read_poll_timeout(priv->regmap,
+ MT6370_REG_CHG_ADC, reg_val,
+ !(reg_val & MT6370_ADC_START_MASK),
+ ADC_CONV_POLLING_TIME_US,
+ ADC_CONV_TIME_MS * MILLI * 3);
+ if (ret) {
+ dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+ goto adc_unlock;
+ }
+
+ ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+ &be_val, sizeof(be_val));
+ if (ret)
+ goto adc_unlock;
+
+ *val = be16_to_cpu(be_val);
+ ret = IIO_VAL_INT;
+
+adc_unlock:
+ mutex_unlock(&priv->adc_lock);
+
+ return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+ int chan, int *val1, int *val2)
+{
+ unsigned int reg_val;
+ int ret;
+
+ switch (chan) {
+ case MT6370_CHAN_VBAT:
+ case MT6370_CHAN_VSYS:
+ case MT6370_CHAN_CHG_VDDP:
+ *val1 = 5;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_IBUS:
+ ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+ switch (reg_val) {
+ case MT6370_AICR_100_mA:
+ case MT6370_AICR_150_mA:
+ case MT6370_AICR_200_mA:
+ case MT6370_AICR_250_mA:
+ case MT6370_AICR_300_mA:
+ case MT6370_AICR_350_mA:
+ *val1 = 3350;
+ break;
+ default:
+ *val1 = 5000;
+ break;
+ }
+
+ *val2 = 100;
+
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_IBAT:
+ ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+ switch (reg_val) {
+ case MT6370_ICHG_100_mA:
+ case MT6370_ICHG_200_mA:
+ case MT6370_ICHG_300_mA:
+ case MT6370_ICHG_400_mA:
+ *val1 = 2375;
+ break;
+ case MT6370_ICHG_500_mA:
+ case MT6370_ICHG_600_mA:
+ case MT6370_ICHG_700_mA:
+ case MT6370_ICHG_800_mA:
+ *val1 = 2680;
+ break;
+ default:
+ *val1 = 5000;
+ break;
+ }
+
+ *val2 = 100;
+
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_VBUSDIV5:
+ *val1 = 25;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_VBUSDIV2:
+ *val1 = 10;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_TS_BAT:
+ *val1 = 25;
+ *val2 = 10000;
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_TEMP_JC:
+ *val1 = 2000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+ int chan, int *val)
+{
+ *val = -20;
+
+ return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return mt6370_adc_read_channel(priv, chan->channel,
+ chan->address, val);
+ case IIO_CHAN_INFO_SCALE:
+ return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+ case IIO_CHAN_INFO_OFFSET:
+ return mt6370_adc_read_offset(priv, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+ [MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+ [MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+ [MT6370_CHAN_VSYS] = "vsys",
+ [MT6370_CHAN_VBAT] = "vbat",
+ [MT6370_CHAN_TS_BAT] = "ts_bat",
+ [MT6370_CHAN_IBUS] = "ibus",
+ [MT6370_CHAN_IBAT] = "ibat",
+ [MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+ [MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+ .read_raw = mt6370_adc_read_raw,
+ .read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) { \
+ .type = _type, \
+ .channel = MT6370_CHAN_##_idx, \
+ .address = _addr, \
+ .scan_index = MT6370_CHAN_##_idx, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ _extra_info, \
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+ MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+ MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+ MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+ MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+ MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+ MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+ MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+ MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+ MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mt6370_adc_data *priv;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+ priv->dev = dev;
+ priv->regmap = regmap;
+ mutex_init(&priv->adc_lock);
+
+ ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+ indio_dev->name = "mt6370-adc";
+ indio_dev->info = &mt6370_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mt6370_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+ { .compatible = "mediatek,mt6370-adc", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+ .driver = {
+ .name = "mt6370-adc",
+ .of_match_table = mt6370_adc_of_id,
+ },
+ .probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index b87ea7148b58..79448c5ffc2a 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -49,6 +50,8 @@ struct rockchip_saradc {
struct clk *clk;
struct completion completion;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
int uv_vref;
struct reset_control *reset;
const struct rockchip_saradc_data *data;
@@ -94,17 +97,17 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
ret = rockchip_saradc_conversion(info, chan);
if (ret) {
rockchip_saradc_power_down(info);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
*val = info->last_val;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = info->uv_vref / 1000;
@@ -270,7 +273,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
int ret;
int i, j = 0;
- mutex_lock(&i_dev->mlock);
+ mutex_lock(&info->lock);
for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) {
const struct iio_chan_spec *chan = &i_dev->channels[i];
@@ -287,7 +290,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
out:
- mutex_unlock(&i_dev->mlock);
+ mutex_unlock(&info->lock);
iio_trigger_notify_done(i_dev->trig);
@@ -478,6 +481,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mutex_init(&info->lock);
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index f8421cbba8fa..ff1fc329bb9b 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -4,6 +4,7 @@
#include <linux/hwspinlock.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -83,6 +84,8 @@ struct sc27xx_adc_data {
struct device *dev;
struct regulator *volref;
struct regmap *regmap;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
/*
* One hardware spinlock to synchronize between the multiple
* subsystems which will access the unique ADC controller.
@@ -664,9 +667,9 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&data->lock);
ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&data->lock);
if (ret)
return ret;
@@ -675,10 +678,10 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&data->lock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
&tmp);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&data->lock);
if (ret)
return ret;
@@ -934,6 +937,9 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
indio_dev->info = &sc27xx_info;
indio_dev->channels = sc27xx_channels;
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
+
+ mutex_init(&sc27xx_data->lock);
+
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
dev_err(dev, "could not register iio (ADC)");
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 81d5db91c67b..48f02dcc81c1 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/units.h>
#include "stm32-adc-core.h"
@@ -306,8 +307,8 @@ out:
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
- .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3},
- .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3},
+ .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3 },
+ .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3 },
.ier = STM32F4_ADC_CR1,
.eocie_msk = STM32F4_EOCIE,
};
@@ -316,8 +317,18 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
- .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV},
- .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV},
+ .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV },
+ .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV },
+ .ier = STM32H7_ADC_IER,
+ .eocie_msk = STM32H7_EOCIE,
+};
+
+/* STM32MP13 common registers definitions */
+static const struct stm32_adc_common_regs stm32mp13_adc_common_regs = {
+ .csr = STM32H7_ADC_CSR,
+ .ccr = STM32H7_ADC_CCR,
+ .eoc_msk = { STM32H7_EOC_MST },
+ .ovr_msk = { STM32H7_OVR_MST },
.ier = STM32H7_ADC_IER,
.eocie_msk = STM32H7_EOCIE,
};
@@ -868,6 +879,14 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.num_irqs = 2,
};
+static const struct stm32_adc_priv_cfg stm32mp13_adc_priv_cfg = {
+ .regs = &stm32mp13_adc_common_regs,
+ .clk_sel = stm32h7_adc_clk_sel,
+ .max_clk_rate_hz = 75 * HZ_PER_MHZ,
+ .ipid = STM32MP13_IPIDR_NUMBER,
+ .num_irqs = 1,
+};
+
static const struct of_device_id stm32_adc_of_match[] = {
{
.compatible = "st,stm32f4-adc-core",
@@ -879,6 +898,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
.compatible = "st,stm32mp1-adc-core",
.data = (void *)&stm32mp1_adc_priv_cfg
}, {
+ .compatible = "st,stm32mp13-adc-core",
+ .data = (void *)&stm32mp13_adc_priv_cfg
+ }, {
},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 2118ef63843d..9d6dfa1c03fa 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -112,6 +112,11 @@
#define STM32MP1_ADC_IPDR 0x3F8
#define STM32MP1_ADC_SIDR 0x3FC
+/* STM32MP13 - Registers for each ADC instance */
+#define STM32MP13_ADC_DIFSEL 0xB0
+#define STM32MP13_ADC_CALFACT 0xB4
+#define STM32MP13_ADC2_OR 0xC8
+
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
@@ -161,6 +166,9 @@ enum stm32h7_adc_dmngt {
STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
};
+/* STM32H7_ADC_DIFSEL - bit fields */
+#define STM32H7_DIFSEL_MASK GENMASK(19, 0)
+
/* STM32H7_ADC_CALFACT - bit fields */
#define STM32H7_CALFACT_D_SHIFT 16
#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
@@ -210,7 +218,29 @@ enum stm32h7_adc_dmngt {
/* STM32MP1_ADC_SIDR - bit fields */
#define STM32MP1_SIDR_MASK GENMASK(31, 0)
+/* STM32MP13_ADC_CFGR specific bit fields */
+#define STM32MP13_DMAEN BIT(0)
+#define STM32MP13_DMACFG BIT(1)
+#define STM32MP13_DFSDMCFG BIT(2)
+#define STM32MP13_RES_SHIFT 3
+#define STM32MP13_RES_MASK GENMASK(4, 3)
+
+/* STM32MP13_ADC_DIFSEL - bit fields */
+#define STM32MP13_DIFSEL_MASK GENMASK(18, 0)
+
+/* STM32MP13_ADC_CALFACT - bit fields */
+#define STM32MP13_CALFACT_D_SHIFT 16
+#define STM32MP13_CALFACT_D_MASK GENMASK(22, 16)
+#define STM32MP13_CALFACT_S_SHIFT 0
+#define STM32MP13_CALFACT_S_MASK GENMASK(6, 0)
+
+/* STM32MP13_ADC2_OR - bit fields */
+#define STM32MP13_OP2 BIT(2)
+#define STM32MP13_OP1 BIT(1)
+#define STM32MP13_OP0 BIT(0)
+
#define STM32MP15_IPIDR_NUMBER 0x00110005
+#define STM32MP13_IPIDR_NUMBER 0x00110006
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 3cda529f081d..8d03d21a33d6 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -82,6 +82,8 @@ enum stm32_adc_extsel {
enum stm32_adc_int_ch {
STM32_ADC_INT_CH_NONE = -1,
STM32_ADC_INT_CH_VDDCORE,
+ STM32_ADC_INT_CH_VDDCPU,
+ STM32_ADC_INT_CH_VDDQ_DDR,
STM32_ADC_INT_CH_VREFINT,
STM32_ADC_INT_CH_VBAT,
STM32_ADC_INT_CH_NB,
@@ -99,6 +101,8 @@ struct stm32_adc_ic {
static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
{ "vddcore", STM32_ADC_INT_CH_VDDCORE },
+ { "vddcpu", STM32_ADC_INT_CH_VDDCPU },
+ { "vddq_ddr", STM32_ADC_INT_CH_VDDQ_DDR },
{ "vrefint", STM32_ADC_INT_CH_VREFINT },
{ "vbat", STM32_ADC_INT_CH_VBAT },
};
@@ -160,9 +164,14 @@ struct stm32_adc_vrefint {
* @exten: trigger control register & bitfield
* @extsel: trigger selection register & bitfield
* @res: resolution selection register & bitfield
+ * @difsel: differential mode selection register & bitfield
+ * @calfact_s: single-ended calibration factors register & bitfield
+ * @calfact_d: differential calibration factors register & bitfield
* @smpr: smpr1 & smpr2 registers offset array
* @smp_bits: smpr1 & smpr2 index and bitfields
- * @or_vdd: option register & vddcore bitfield
+ * @or_vddcore: option register & vddcore bitfield
+ * @or_vddcpu: option register & vddcpu bitfield
+ * @or_vddq_ddr: option register & vddq_ddr bitfield
* @ccr_vbat: common register & vbat bitfield
* @ccr_vref: common register & vrefint bitfield
*/
@@ -176,9 +185,14 @@ struct stm32_adc_regspec {
const struct stm32_adc_regs exten;
const struct stm32_adc_regs extsel;
const struct stm32_adc_regs res;
+ const struct stm32_adc_regs difsel;
+ const struct stm32_adc_regs calfact_s;
+ const struct stm32_adc_regs calfact_d;
const u32 smpr[2];
const struct stm32_adc_regs *smp_bits;
- const struct stm32_adc_regs or_vdd;
+ const struct stm32_adc_regs or_vddcore;
+ const struct stm32_adc_regs or_vddcpu;
+ const struct stm32_adc_regs or_vddq_ddr;
const struct stm32_adc_regs ccr_vbat;
const struct stm32_adc_regs ccr_vref;
};
@@ -192,13 +206,16 @@ struct stm32_adc;
* @trigs: external trigger sources
* @clk_required: clock is required
* @has_vregready: vregready status flag presence
+ * @has_boostmode: boost mode support flag
+ * @has_linearcal: linear calibration support flag
+ * @has_presel: channel preselection support flag
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
* @stop_conv: routine to stop conversions
* @unprepare: optional unprepare routine (disable, power-down)
* @irq_clear: routine to clear irqs
* @smp_cycles: programmable sampling time (ADC clock cycles)
- * @ts_vrefint_ns: vrefint minimum sampling time in ns
+ * @ts_int_ch: pointer to array of internal channels minimum sampling time in ns
*/
struct stm32_adc_cfg {
const struct stm32_adc_regspec *regs;
@@ -206,13 +223,16 @@ struct stm32_adc_cfg {
struct stm32_adc_trig_info *trigs;
bool clk_required;
bool has_vregready;
+ bool has_boostmode;
+ bool has_linearcal;
+ bool has_presel;
int (*prepare)(struct iio_dev *);
void (*start_conv)(struct iio_dev *, bool dma);
void (*stop_conv)(struct iio_dev *);
void (*unprepare)(struct iio_dev *);
void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
const unsigned int *smp_cycles;
- const unsigned int ts_vrefint_ns;
+ const unsigned int *ts_int_ch;
};
/**
@@ -312,6 +332,13 @@ static const struct stm32_adc_info stm32h7_adc_info = {
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
};
+/* stm32mp13 can have up to 19 channels */
+static const struct stm32_adc_info stm32mp13_adc_info = {
+ .max_channels = 19,
+ .resolutions = stm32f4_adc_resolutions,
+ .num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
+};
+
/*
* stm32f4_sq - describe regular sequence registers
* - L: sequence len (register & bit field)
@@ -497,10 +524,45 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
STM32H7_EXTSEL_SHIFT },
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
+ .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK,
+ STM32H7_CALFACT_S_SHIFT },
+ .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK,
+ STM32H7_CALFACT_D_SHIFT },
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
.smp_bits = stm32h7_smp_bits,
};
+/* STM32MP13 programmable sampling time (ADC clock cycles, rounded down) */
+static const unsigned int stm32mp13_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
+ 2, 6, 12, 24, 47, 92, 247, 640,
+};
+
+static const struct stm32_adc_regspec stm32mp13_adc_regspec = {
+ .dr = STM32H7_ADC_DR,
+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+ .sqr = stm32h7_sq,
+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+ STM32H7_EXTSEL_SHIFT },
+ .res = { STM32H7_ADC_CFGR, STM32MP13_RES_MASK, STM32MP13_RES_SHIFT },
+ .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK},
+ .calfact_s = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_S_MASK,
+ STM32MP13_CALFACT_S_SHIFT },
+ .calfact_d = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_D_MASK,
+ STM32MP13_CALFACT_D_SHIFT },
+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+ .smp_bits = stm32h7_smp_bits,
+ .or_vddcore = { STM32MP13_ADC2_OR, STM32MP13_OP0 },
+ .or_vddcpu = { STM32MP13_ADC2_OR, STM32MP13_OP1 },
+ .or_vddq_ddr = { STM32MP13_ADC2_OR, STM32MP13_OP2 },
+ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
.dr = STM32H7_ADC_DR,
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
@@ -512,9 +574,14 @@ static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
STM32H7_EXTSEL_SHIFT },
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
+ .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK,
+ STM32H7_CALFACT_S_SHIFT },
+ .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK,
+ STM32H7_CALFACT_D_SHIFT },
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
.smp_bits = stm32h7_smp_bits,
- .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
+ .or_vddcore = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
.ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
.ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
};
@@ -675,8 +742,18 @@ static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
switch (i) {
case STM32_ADC_INT_CH_VDDCORE:
dev_dbg(&indio_dev->dev, "Enable VDDCore\n");
- stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg,
- adc->cfg->regs->or_vdd.mask);
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcore.reg,
+ adc->cfg->regs->or_vddcore.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ dev_dbg(&indio_dev->dev, "Enable VDDCPU\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+ adc->cfg->regs->or_vddcpu.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ dev_dbg(&indio_dev->dev, "Enable VDDQ_DDR\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+ adc->cfg->regs->or_vddq_ddr.mask);
break;
case STM32_ADC_INT_CH_VREFINT:
dev_dbg(&indio_dev->dev, "Enable VREFInt\n");
@@ -702,8 +779,16 @@ static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
switch (i) {
case STM32_ADC_INT_CH_VDDCORE:
- stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg,
- adc->cfg->regs->or_vdd.mask);
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcore.reg,
+ adc->cfg->regs->or_vddcore.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+ adc->cfg->regs->or_vddcpu.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+ adc->cfg->regs->or_vddq_ddr.mask);
break;
case STM32_ADC_INT_CH_VREFINT:
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
@@ -801,6 +886,7 @@ static void stm32h7_adc_stop_conv(struct iio_dev *indio_dev)
if (ret)
dev_warn(&indio_dev->dev, "stop failed\n");
+ /* STM32H7_DMNGT_MASK covers STM32MP13_DMAEN & STM32MP13_DMACFG */
stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK);
}
@@ -811,6 +897,17 @@ static void stm32h7_adc_irq_clear(struct iio_dev *indio_dev, u32 msk)
stm32_adc_set_bits(adc, adc->cfg->regs->isr_eoc.reg, msk);
}
+static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ if (dma)
+ stm32_adc_set_bits(adc, STM32H7_ADC_CFGR,
+ STM32MP13_DMAEN | STM32MP13_DMACFG);
+
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
+}
+
static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -821,7 +918,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
- if (adc->common->rate > STM32H7_BOOST_CLKRATE)
+ if (adc->cfg->has_boostmode &&
+ adc->common->rate > STM32H7_BOOST_CLKRATE)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */
@@ -843,7 +941,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
{
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
+ if (adc->cfg->has_boostmode)
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
@@ -901,6 +1000,9 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
int i, ret;
u32 lincalrdyw_mask, val;
+ if (!adc->cfg->has_linearcal)
+ goto skip_linearcal;
+
/* Read linearity calibration */
lincalrdyw_mask = STM32H7_LINCALRDYW6;
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
@@ -923,12 +1025,13 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
lincalrdyw_mask >>= 1;
}
+skip_linearcal:
/* Read offset calibration */
- val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT);
- adc->cal.calfact_s = (val & STM32H7_CALFACT_S_MASK);
- adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT;
- adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK);
- adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT;
+ val = stm32_adc_readl(adc, adc->cfg->regs->calfact_s.reg);
+ adc->cal.calfact_s = (val & adc->cfg->regs->calfact_s.mask);
+ adc->cal.calfact_s >>= adc->cfg->regs->calfact_s.shift;
+ adc->cal.calfact_d = (val & adc->cfg->regs->calfact_d.mask);
+ adc->cal.calfact_d >>= adc->cfg->regs->calfact_d.shift;
adc->cal.calibrated = true;
return 0;
@@ -945,9 +1048,12 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
int i, ret;
u32 lincalrdyw_mask, val;
- val = (adc->cal.calfact_s << STM32H7_CALFACT_S_SHIFT) |
- (adc->cal.calfact_d << STM32H7_CALFACT_D_SHIFT);
- stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val);
+ val = (adc->cal.calfact_s << adc->cfg->regs->calfact_s.shift) |
+ (adc->cal.calfact_d << adc->cfg->regs->calfact_d.shift);
+ stm32_adc_writel(adc, adc->cfg->regs->calfact_s.reg, val);
+
+ if (!adc->cfg->has_linearcal)
+ return 0;
lincalrdyw_mask = STM32H7_LINCALRDYW6;
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
@@ -1016,11 +1122,14 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
int ret;
+ u32 msk = STM32H7_ADCALDIF;
u32 val;
if (adc->cal.calibrated)
return true;
+ if (adc->cfg->has_linearcal)
+ msk |= STM32H7_ADCALLIN;
/* ADC must be disabled for calibration */
stm32h7_adc_disable(indio_dev);
@@ -1029,8 +1138,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
* - Offset calibration for single ended inputs
* - No linearity calibration (do it later, before reading it)
*/
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALLIN);
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
/* Start calibration, then wait for completion */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
@@ -1048,8 +1156,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
* - Linearity calibration (needs to be done only once for single/diff)
* will run simultaneously with offset calibration.
*/
- stm32_adc_set_bits(adc, STM32H7_ADC_CR,
- STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, msk);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & STM32H7_ADCAL), 100,
@@ -1060,8 +1167,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
}
out:
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
- STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
return ret;
}
@@ -1093,7 +1199,7 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
stm32_adc_int_ch_enable(indio_dev);
- stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
+ stm32_adc_writel(adc, adc->cfg->regs->difsel.reg, adc->difsel);
ret = stm32h7_adc_enable(indio_dev);
if (ret)
@@ -1107,7 +1213,8 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
if (ret)
goto disable;
- stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
return 0;
@@ -1125,7 +1232,8 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
- stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
stm32h7_adc_disable(indio_dev);
stm32_adc_int_ch_disable(adc);
stm32h7_adc_enter_pwr_down(adc);
@@ -1802,14 +1910,15 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
{
const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
u32 period_ns, shift = smpr->shift, mask = smpr->mask;
- unsigned int smp, r = smpr->reg;
+ unsigned int i, smp, r = smpr->reg;
/*
- * For vrefint channel, ensure that the sampling time cannot
+ * For internal channels, ensure that the sampling time cannot
* be lower than the one specified in the datasheet
*/
- if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT])
- smp_ns = max(smp_ns, adc->cfg->ts_vrefint_ns);
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
+ if (channel == adc->int_ch[i] && adc->int_ch[i] != STM32_ADC_INT_CH_NONE)
+ smp_ns = max(smp_ns, adc->cfg->ts_int_ch[i]);
/* Determine sampling time (ADC clock cycles) */
period_ns = NSEC_PER_SEC / adc->common->rate;
@@ -1857,7 +1966,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
adc->pcsel |= BIT(chan->channel);
if (differential) {
/* pre-build diff channels mask */
- adc->difsel |= BIT(chan->channel);
+ adc->difsel |= BIT(chan->channel) & adc->cfg->regs->difsel.mask;
/* Also add negative input to pre-selected channels */
adc->pcsel |= BIT(chan->channel2);
}
@@ -1998,6 +2107,35 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
+ /* Check internal channel availability */
+ switch (i) {
+ case STM32_ADC_INT_CH_VDDCORE:
+ if (!adc->cfg->regs->or_vddcore.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ if (!adc->cfg->regs->or_vddcpu.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ if (!adc->cfg->regs->or_vddq_ddr.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VREFINT:
+ if (!adc->cfg->regs->ccr_vref.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VBAT:
+ if (!adc->cfg->regs->ccr_vbat.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ }
+
if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT) {
adc->int_ch[i] = chan;
break;
@@ -2431,36 +2569,66 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.irq_clear = stm32f4_adc_irq_clear,
};
+const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
+
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.regs = &stm32h7_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
+ .ts_int_ch = stm32_adc_min_ts_h7,
};
+const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
+
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.regs = &stm32mp1_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
.has_vregready = true,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
- .ts_vrefint_ns = 4300,
+ .ts_int_ch = stm32_adc_min_ts_mp1,
+};
+
+const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
+
+static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
+ .regs = &stm32mp13_adc_regspec,
+ .adc_info = &stm32mp13_adc_info,
+ .trigs = stm32h7_adc_trigs,
+ .start_conv = stm32mp13_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32h7_adc_prepare,
+ .unprepare = stm32h7_adc_unprepare,
+ .smp_cycles = stm32mp13_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .ts_int_ch = stm32_adc_min_ts_mp13,
};
static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
+ { .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
{},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index 5235a93f28bc..fcfc46254313 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -807,6 +807,8 @@ static int ads131e08_probe(struct spi_device *spi)
int ret;
info = device_get_match_data(&spi->dev);
+ if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
if (!info) {
dev_err(&spi->dev, "failed to get match data\n");
return -ENODEV;
@@ -926,12 +928,21 @@ static const struct of_device_id ads131e08_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ads131e08_of_match);
+static const struct spi_device_id ads131e08_ids[] = {
+ { "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] },
+ { "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] },
+ { "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ads131e08_ids);
+
static struct spi_driver ads131e08_driver = {
.driver = {
.name = "ads131e08",
.of_match_table = ads131e08_of_match,
},
.probe = ads131e08_probe,
+ .id_table = ads131e08_ids,
};
module_spi_driver(ads131e08_driver);
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index c6b16cf6e367..ae31aafd2653 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -7,6 +7,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@@ -156,6 +157,9 @@ struct vf610_adc {
void __iomem *regs;
struct clk *clk;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
+
u32 vref_uv;
u32 value;
struct regulator *vref;
@@ -467,11 +471,11 @@ static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
{
struct vf610_adc *info = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
info->adc_feature.conv_mode = mode;
vf610_adc_calculate_rates(info);
vf610_adc_hw_init(info);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return 0;
}
@@ -622,6 +626,58 @@ static const struct attribute_group vf610_attribute_group = {
.attrs = vf610_attributes,
};
+static int vf610_read_sample(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int hc_cfg;
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&info->lock);
+ reinit_completion(&info->completion);
+ hc_cfg = VF610_ADC_ADCHC(chan->channel);
+ hc_cfg |= VF610_ADC_AIEN;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+ ret = wait_for_completion_interruptible_timeout(&info->completion,
+ VF610_ADC_TIMEOUT);
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+
+ if (ret < 0)
+ goto out_unlock;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = info->value;
+ break;
+ case IIO_TEMP:
+ /*
+ * Calculate in degree Celsius times 1000
+ * Using the typical sensor slope of 1.84 mV/°C
+ * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
+ */
+ *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
+ 1000000 / VF610_TEMP_SLOPE_COEFF;
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&info->lock);
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
static int vf610_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -629,53 +685,15 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
- unsigned int hc_cfg;
long ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
- mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
- mutex_unlock(&indio_dev->mlock);
- return -EBUSY;
- }
-
- reinit_completion(&info->completion);
- hc_cfg = VF610_ADC_ADCHC(chan->channel);
- hc_cfg |= VF610_ADC_AIEN;
- writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
- ret = wait_for_completion_interruptible_timeout
- (&info->completion, VF610_ADC_TIMEOUT);
- if (ret == 0) {
- mutex_unlock(&indio_dev->mlock);
- return -ETIMEDOUT;
- }
- if (ret < 0) {
- mutex_unlock(&indio_dev->mlock);
+ ret = vf610_read_sample(indio_dev, chan, val);
+ if (ret < 0)
return ret;
- }
- switch (chan->type) {
- case IIO_VOLTAGE:
- *val = info->value;
- break;
- case IIO_TEMP:
- /*
- * Calculate in degree Celsius times 1000
- * Using the typical sensor slope of 1.84 mV/°C
- * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
- */
- *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
- 1000000 / VF610_TEMP_SLOPE_COEFF;
-
- break;
- default:
- mutex_unlock(&indio_dev->mlock);
- return -EINVAL;
- }
-
- mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -878,6 +896,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
goto error_iio_device_register;
}
+ mutex_init(&info->lock);
+
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");