summaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
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/ad7091r5.c6
-rw-r--r--drivers/iio/adc/ad7124.c10
-rw-r--r--drivers/iio/adc/ad7192.c27
-rw-r--r--drivers/iio/adc/ad7291.c6
-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/ad7606_par.c3
-rw-r--r--drivers/iio/adc/ad799x.c26
-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/ina2xx-adc.c6
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c11
-rw-r--r--drivers/iio/adc/ltc2471.c6
-rw-r--r--drivers/iio/adc/ltc2485.c6
-rw-r--r--drivers/iio/adc/ltc2497-core.c7
-rw-r--r--drivers/iio/adc/ltc2497.c6
-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.c18
-rw-r--r--drivers/iio/adc/max9611.c5
-rw-r--r--drivers/iio/adc/mcp3422.c6
-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.h31
-rw-r--r--drivers/iio/adc/stm32-adc.c307
-rw-r--r--drivers/iio/adc/ti-adc081c.c6
-rw-r--r--drivers/iio/adc/ti-adc128s052.c14
-rw-r--r--drivers/iio/adc/ti-ads1015.c6
-rw-r--r--drivers/iio/adc/ti-ads131e08.c11
-rw-r--r--drivers/iio/adc/vf610_adc.c104
43 files changed, 4162 insertions, 367 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/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
index 47f5763023a4..7d6709da1005 100644
--- a/drivers/iio/adc/ad7091r5.c
+++ b/drivers/iio/adc/ad7091r5.c
@@ -69,9 +69,9 @@ static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
.vref_mV = 2500,
};
-static int ad7091r5_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad7091r5_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
const struct ad7091r_chip_info *chip_info;
struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
@@ -103,7 +103,7 @@ static struct i2c_driver ad7091r5_driver = {
.name = "ad7091r5",
.of_match_table = ad7091r5_dt_ids,
},
- .probe = ad7091r5_i2c_probe,
+ .probe_new = ad7091r5_i2c_probe,
.id_table = ad7091r5_i2c_ids,
};
module_i2c_driver(ad7091r5_driver);
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/ad7291.c b/drivers/iio/adc/ad7291.c
index e9129dac762f..3dd0105f63d7 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -465,9 +465,9 @@ static void ad7291_reg_disable(void *reg)
regulator_disable(reg);
}
-static int ad7291_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad7291_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ad7291_chip_info *chip;
struct iio_dev *indio_dev;
int ret;
@@ -553,7 +553,7 @@ static struct i2c_driver ad7291_driver = {
.name = KBUILD_MODNAME,
.of_match_table = ad7291_of_match,
},
- .probe = ad7291_probe,
+ .probe_new = ad7291_probe,
.id_table = ad7291_id,
};
module_i2c_driver(ad7291_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/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index b912b4df9b56..d8408052262e 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -57,8 +57,7 @@ static int ad7606_par_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- addr = devm_ioremap_resource(&pdev->dev, res);
+ addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(addr))
return PTR_ERR(addr);
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 6dbe9d5e08a2..8f0a3a35e727 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) &
@@ -770,9 +775,9 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
};
-static int ad799x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad799x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
int extra_config = 0;
struct ad799x_state *st;
@@ -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;
@@ -960,7 +968,7 @@ static struct i2c_driver ad799x_driver = {
.name = "ad799x",
.pm = pm_sleep_ptr(&ad799x_pm_ops),
},
- .probe = ad799x_probe,
+ .probe_new = ad799x_probe,
.remove = ad799x_remove,
.id_table = ad799x_id,
};
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/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 910e7e965fc4..38d9d7b2313e 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -946,9 +946,9 @@ static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
return ina2xx_set_calibration(chip);
}
-static int ina2xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ina2xx_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ina2xx_chip_info *chip;
struct iio_dev *indio_dev;
unsigned int val;
@@ -1090,7 +1090,7 @@ static struct i2c_driver ina2xx_driver = {
.name = KBUILD_MODNAME,
.of_match_table = ina2xx_of_match,
},
- .probe = ina2xx_probe,
+ .probe_new = ina2xx_probe,
.remove = ina2xx_remove,
.id_table = ina2xx_id,
};
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/ltc2471.c b/drivers/iio/adc/ltc2471.c
index 0e0fe881a8e6..eeb2945829eb 100644
--- a/drivers/iio/adc/ltc2471.c
+++ b/drivers/iio/adc/ltc2471.c
@@ -99,9 +99,9 @@ static const struct iio_info ltc2471_info = {
.read_raw = ltc2471_read_raw,
};
-static int ltc2471_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2471_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct ltc2471_data *data;
int ret;
@@ -146,7 +146,7 @@ static struct i2c_driver ltc2471_i2c_driver = {
.driver = {
.name = "ltc2471",
},
- .probe = ltc2471_i2c_probe,
+ .probe_new = ltc2471_i2c_probe,
.id_table = ltc2471_i2c_id,
};
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
index 37c762f8218c..6a23427344ec 100644
--- a/drivers/iio/adc/ltc2485.c
+++ b/drivers/iio/adc/ltc2485.c
@@ -89,9 +89,9 @@ static const struct iio_info ltc2485_info = {
.read_raw = ltc2485_read_raw,
};
-static int ltc2485_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2485_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct ltc2485_data *data;
int ret;
@@ -133,7 +133,7 @@ static struct i2c_driver ltc2485_driver = {
.driver = {
.name = "ltc2485",
},
- .probe = ltc2485_probe,
+ .probe_new = ltc2485_probe,
.id_table = ltc2485_id,
};
module_i2c_driver(ltc2485_driver);
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.c b/drivers/iio/adc/ltc2497.c
index 556f10dfb502..17370c5eb6fe 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -94,9 +94,9 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
return ret;
}
-static int ltc2497_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2497_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ltc2497_chip_info *chip_info;
struct iio_dev *indio_dev;
struct ltc2497_driverdata *st;
@@ -165,7 +165,7 @@ static struct i2c_driver ltc2497_driver = {
.name = "ltc2497",
.of_match_table = ltc2497_of_match,
},
- .probe = ltc2497_probe,
+ .probe_new = ltc2497_probe,
.remove = ltc2497_remove,
.id_table = ltc2497_id,
};
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..fdc9f03135b5
--- /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_VREFP_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..73b783b430d7 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
@@ -1581,9 +1579,9 @@ static void max1363_reg_disable(void *reg)
regulator_disable(reg);
}
-static int max1363_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max1363_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
@@ -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;
@@ -1728,7 +1718,7 @@ static struct i2c_driver max1363_driver = {
.name = "max1363",
.of_match_table = max1363_of_match,
},
- .probe = max1363_probe,
+ .probe_new = max1363_probe,
.id_table = max1363_id,
};
module_i2c_driver(max1363_driver);
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index f982f00303dc..cb7f4785423a 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -510,8 +510,7 @@ static const struct of_device_id max9611_of_table[] = {
};
MODULE_DEVICE_TABLE(of, max9611_of_table);
-static int max9611_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max9611_probe(struct i2c_client *client)
{
const char * const shunt_res_prop = "shunt-resistor-micro-ohms";
struct max9611_dev *max9611;
@@ -557,7 +556,7 @@ static struct i2c_driver max9611_driver = {
.name = DRIVER_NAME,
.of_match_table = max9611_of_table,
},
- .probe = max9611_probe,
+ .probe_new = max9611_probe,
};
module_i2c_driver(max9611_driver);
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index da353dcb1e9d..ada844c3f7ec 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -330,9 +330,9 @@ static const struct iio_info mcp3422_info = {
.attrs = &mcp3422_attribute_group,
};
-static int mcp3422_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp3422_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct mcp3422 *adc;
int err;
@@ -417,7 +417,7 @@ static struct i2c_driver mcp3422_driver = {
.name = "mcp3422",
.of_match_table = mcp3422_of_match,
},
- .probe = mcp3422_probe,
+ .probe_new = mcp3422_probe,
.id_table = mcp3422_id,
};
module_i2c_driver(mcp3422_driver);
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..73b2c2e91c08 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)
@@ -137,6 +142,7 @@
#define STM32H7_LINCALRDYW3 BIT(24)
#define STM32H7_LINCALRDYW2 BIT(23)
#define STM32H7_LINCALRDYW1 BIT(22)
+#define STM32H7_LINCALRDYW_MASK GENMASK(27, 22)
#define STM32H7_ADCALLIN BIT(16)
#define STM32H7_BOOST BIT(8)
#define STM32H7_ADSTP BIT(4)
@@ -161,6 +167,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 +219,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..45d4e79f8e55 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -7,6 +7,7 @@
*/
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -82,6 +83,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 +102,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 },
};
@@ -115,16 +120,12 @@ struct stm32_adc_trig_info {
/**
* struct stm32_adc_calib - optional adc calibration data
- * @calfact_s: Calibration offset for single ended channels
- * @calfact_d: Calibration offset in differential
* @lincalfact: Linearity calibration factor
- * @calibrated: Indicates calibration status
+ * @lincal_saved: Indicates that linear calibration factors are saved
*/
struct stm32_adc_calib {
- u32 calfact_s;
- u32 calfact_d;
u32 lincalfact[STM32H7_LINCALFACT_NUM];
- bool calibrated;
+ bool lincal_saved;
};
/**
@@ -160,9 +161,12 @@ 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
* @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 +180,12 @@ 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 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 +199,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 +216,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 +325,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 +517,37 @@ 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},
.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},
+ .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 +559,10 @@ 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},
.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 +723,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 +760,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 +867,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 +878,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 +899,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 +922,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);
@@ -922,14 +1002,7 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
lincalrdyw_mask >>= 1;
}
-
- /* 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;
- adc->cal.calibrated = true;
+ adc->cal.lincal_saved = true;
return 0;
}
@@ -945,10 +1018,6 @@ 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);
-
lincalrdyw_mask = STM32H7_LINCALRDYW6;
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
/*
@@ -1010,17 +1079,21 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
/**
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC
* @indio_dev: IIO device instance
+ * @do_lincal: linear calibration request flag
* Note: Must be called once ADC is out of power down.
+ *
+ * Run offset calibration unconditionally.
+ * Run linear calibration if requested & supported.
*/
-static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
+static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal)
{
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 && do_lincal)
+ msk |= STM32H7_ADCALLIN;
/* ADC must be disabled for calibration */
stm32h7_adc_disable(indio_dev);
@@ -1029,8 +1102,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);
@@ -1038,7 +1110,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
!(val & STM32H7_ADCAL), 100,
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
- dev_err(&indio_dev->dev, "calibration failed\n");
+ dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret);
goto out;
}
@@ -1048,25 +1120,51 @@ 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,
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
- dev_err(&indio_dev->dev, "calibration failed\n");
+ dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n",
+ (msk & STM32H7_ADCALLIN) ? "+linear" : "", ret);
goto out;
}
out:
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
- STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
return ret;
}
/**
+ * stm32h7_adc_check_selfcalib() - Check linear calibration status
+ * @indio_dev: IIO device instance
+ *
+ * Used to check if linear calibration has been done.
+ * Return true if linear calibration factors are already saved in private data
+ * or if a linear calibration has been done at boot stage.
+ */
+static int stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 val;
+
+ if (adc->cal.lincal_saved)
+ return true;
+
+ /*
+ * Check if linear calibration factors are available in ADC registers,
+ * by checking that all LINCALRDYWx bits are set.
+ */
+ val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK;
+ if (val == STM32H7_LINCALRDYW_MASK)
+ return true;
+
+ return false;
+}
+
+/**
* stm32h7_adc_prepare() - Leave power down mode to enable ADC.
* @indio_dev: IIO device instance
* Leave power down mode.
@@ -1080,34 +1178,41 @@ out:
static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
- int calib, ret;
+ int lincal_done = false;
+ int ret;
ret = stm32h7_adc_exit_pwr_down(indio_dev);
if (ret)
return ret;
- ret = stm32h7_adc_selfcalib(indio_dev);
+ if (adc->cfg->has_linearcal)
+ lincal_done = stm32h7_adc_check_selfcalib(indio_dev);
+
+ /* Always run offset calibration. Run linear calibration only once */
+ ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done);
if (ret < 0)
goto pwr_dwn;
- calib = ret;
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)
goto ch_disable;
- /* Either restore or read calibration result for future reference */
- if (calib)
- ret = stm32h7_adc_restore_selfcalib(indio_dev);
- else
- ret = stm32h7_adc_read_selfcalib(indio_dev);
- if (ret)
- goto disable;
+ if (adc->cfg->has_linearcal) {
+ if (!adc->cal.lincal_saved)
+ ret = stm32h7_adc_read_selfcalib(indio_dev);
+ else
+ ret = stm32h7_adc_restore_selfcalib(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 +1230,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);
@@ -1774,6 +1880,23 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
{},
};
+static void stm32_adc_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+ struct stm32_adc_calib *cal = &adc->cal;
+ char buf[16];
+ unsigned int i;
+
+ if (!adc->cfg->has_linearcal)
+ return;
+
+ for (i = 0; i < STM32H7_LINCALFACT_NUM; i++) {
+ snprintf(buf, sizeof(buf), "lincalfact%d", i + 1);
+ debugfs_create_u32(buf, 0444, d, &cal->lincalfact[i]);
+ }
+}
+
static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev)
{
struct device *dev = &indio_dev->dev;
@@ -1802,14 +1925,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 +1981,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 +2122,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;
@@ -2330,6 +2483,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ stm32_adc_debugfs_init(indio_dev);
+
return 0;
err_hw_stop:
@@ -2358,6 +2514,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
struct stm32_adc *adc = iio_priv(indio_dev);
pm_runtime_get_sync(&pdev->dev);
+ /* iio_device_unregister() also removes debugfs entries */
iio_device_unregister(indio_dev);
stm32_adc_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -2431,36 +2588,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-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index bd48b073e720..c663dc59d459 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -152,9 +152,9 @@ static void adc081c_reg_disable(void *reg)
regulator_disable(reg);
}
-static int adc081c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adc081c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *iio;
struct adc081c *adc;
const struct adcxx1c_model *model;
@@ -235,7 +235,7 @@ static struct i2c_driver adc081c_driver = {
.of_match_table = adc081c_of_match,
.acpi_match_table = adc081c_acpi_match,
},
- .probe = adc081c_probe,
+ .probe_new = adc081c_probe,
.id_table = adc081c_id,
};
module_i2c_driver(adc081c_driver);
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 622fd384983c..b3d5b9b7255b 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -181,13 +181,13 @@ static int adc128_probe(struct spi_device *spi)
}
static const struct of_device_id adc128_of_match[] = {
- { .compatible = "ti,adc128s052", },
- { .compatible = "ti,adc122s021", },
- { .compatible = "ti,adc122s051", },
- { .compatible = "ti,adc122s101", },
- { .compatible = "ti,adc124s021", },
- { .compatible = "ti,adc124s051", },
- { .compatible = "ti,adc124s101", },
+ { .compatible = "ti,adc128s052", .data = (void*)0L, },
+ { .compatible = "ti,adc122s021", .data = (void*)1L, },
+ { .compatible = "ti,adc122s051", .data = (void*)1L, },
+ { .compatible = "ti,adc122s101", .data = (void*)1L, },
+ { .compatible = "ti,adc124s021", .data = (void*)2L, },
+ { .compatible = "ti,adc124s051", .data = (void*)2L, },
+ { .compatible = "ti,adc124s101", .data = (void*)2L, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 8bceba694026..56af5e148802 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -974,9 +974,9 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
mode << ADS1015_CFG_MOD_SHIFT);
}
-static int ads1015_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ads1015_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ads1015_chip_data *chip;
struct iio_dev *indio_dev;
struct ads1015_data *data;
@@ -1195,7 +1195,7 @@ static struct i2c_driver ads1015_driver = {
.of_match_table = ads1015_of_match,
.pm = &ads1015_pm_ops,
},
- .probe = ads1015_probe,
+ .probe_new = ads1015_probe,
.remove = ads1015_remove,
.id_table = ads1015_id,
};
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");