diff options
Diffstat (limited to 'drivers/iio/adc')
| -rw-r--r-- | drivers/iio/adc/Kconfig | 31 | ||||
| -rw-r--r-- | drivers/iio/adc/Makefile | 3 | ||||
| -rw-r--r-- | drivers/iio/adc/ad4030.c | 4 | ||||
| -rw-r--r-- | drivers/iio/adc/ad4080.c | 126 | ||||
| -rw-r--r-- | drivers/iio/adc/ad7124.c | 295 | ||||
| -rw-r--r-- | drivers/iio/adc/ad7768-1.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/ade9000.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/aspeed_adc.c | 34 | ||||
| -rw-r--r-- | drivers/iio/adc/max14001.c | 391 | ||||
| -rw-r--r-- | drivers/iio/adc/mcp3564.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/meson_saradc.c | 6 | ||||
| -rw-r--r-- | drivers/iio/adc/mt6360-adc.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/pac1921.c | 8 | ||||
| -rw-r--r-- | drivers/iio/adc/pac1934.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/qcom-spmi-rradc.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/rohm-bd79112.c | 13 | ||||
| -rw-r--r-- | drivers/iio/adc/rohm-bd79124.c | 39 | ||||
| -rw-r--r-- | drivers/iio/adc/rzn1-adc.c | 490 | ||||
| -rw-r--r-- | drivers/iio/adc/rzt2h_adc.c | 304 | ||||
| -rw-r--r-- | drivers/iio/adc/ti-ads131e08.c | 2 | ||||
| -rw-r--r-- | drivers/iio/adc/ti_am335x_adc.c | 2 |
21 files changed, 1526 insertions, 234 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 58a14e6833f6..58da8255525e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1020,6 +1020,16 @@ config MAX1363 To compile this driver as a module, choose M here: the module will be called max1363. +config MAX14001 + tristate "Analog Devices MAX14001/MAX14002 ADC driver" + depends on SPI + help + Say yes here to build support for Analog Devices MAX14001/MAX14002 + Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs. + + To compile this driver as a module, choose M here: the module will be + called max14001. + config MAX34408 tristate "Maxim max34408/max344089 ADC driver" depends on I2C @@ -1403,6 +1413,27 @@ config RZG2L_ADC To compile this driver as a module, choose M here: the module will be called rzg2l_adc. +config RZN1_ADC + tristate "Renesas RZ/N1 ADC driver" + depends on ARCH_RZN1 || COMPILE_TEST + help + Say yes here to build support for the ADC found in Renesas + RZ/N1 family. + + To compile this driver as a module, choose M here: the + module will be called rzn1-adc. + +config RZT2H_ADC + tristate "Renesas RZ/T2H / RZ/N2H ADC driver" + depends on ARCH_RENESAS || COMPILE_TEST + select IIO_ADC_HELPER + help + Say yes here to build support for the ADC found in Renesas + RZ/T2H / RZ/N2H SoCs. + + To compile this driver as a module, choose M here: the + module will be called rzt2h_adc. + config SC27XX_ADC tristate "Spreadtrum SC27xx series PMICs ADC" depends on MFD_SC27XX_PMIC || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index d008f78dc010..7cc8f9a12f76 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_MAX11205) += max11205.o obj-$(CONFIG_MAX11410) += max11410.o obj-$(CONFIG_MAX1241) += max1241.o obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MAX14001) += max14001.o obj-$(CONFIG_MAX34408) += max34408.o obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o @@ -123,6 +124,8 @@ obj-$(CONFIG_ROHM_BD79112) += rohm-bd79112.o obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o +obj-$(CONFIG_RZN1_ADC) += rzn1-adc.o +obj-$(CONFIG_RZT2H_ADC) += rzt2h_adc.o obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o obj-$(CONFIG_SOPHGO_CV1800B_ADC) += sophgo-cv1800b-adc.o diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index d8bee6a4215a..68446db9bef1 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -852,8 +852,8 @@ static int ad4030_read_label(struct iio_dev *indio_dev, char *label) { if (chan->differential) - return sprintf(label, "differential%lu\n", chan->address); - return sprintf(label, "common-mode%lu\n", chan->address); + return sysfs_emit(label, "differential%lu\n", chan->address); + return sysfs_emit(label, "common-mode%lu\n", chan->address); } static int ad4030_get_current_scan_type(const struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 6e61787ed321..7cf3b6ed7940 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -125,7 +125,12 @@ /* Miscellaneous Definitions */ #define AD4080_SPI_READ BIT(7) -#define AD4080_CHIP_ID GENMASK(2, 0) +#define AD4080_CHIP_ID 0x0050 +#define AD4081_CHIP_ID 0x0051 +#define AD4083_CHIP_ID 0x0053 +#define AD4084_CHIP_ID 0x0054 +#define AD4086_CHIP_ID 0x0056 +#define AD4087_CHIP_ID 0x0057 #define AD4080_LVDS_CNV_CLK_CNT_MAX 7 @@ -167,6 +172,7 @@ struct ad4080_chip_info { const unsigned int (*scale_table)[2]; const struct iio_chan_spec *channels; unsigned int num_channels; + unsigned int lvds_cnv_clk_cnt_max; }; struct ad4080_state { @@ -414,23 +420,35 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = { { } }; -static const struct iio_chan_spec ad4080_channel = { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - .info_mask_shared_by_all_available = - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - .ext_info = ad4080_ext_info, - .scan_index = 0, - .scan_type = { - .sign = 's', - .realbits = 20, - .storagebits = 32, - }, -}; +#define AD4080_CHANNEL_DEFINE(bits, storage) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = ad4080_ext_info, \ + .scan_index = 0, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = (storage), \ + }, \ +} + +static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32); + +static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32); + +static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16); + +static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16); + +static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16); + +static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16); static const struct ad4080_chip_info ad4080_chip_info = { .name = "ad4080", @@ -439,13 +457,65 @@ static const struct ad4080_chip_info ad4080_chip_info = { .num_scales = ARRAY_SIZE(ad4080_scale_table), .num_channels = 1, .channels = &ad4080_channel, + .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX, +}; + +static const struct ad4080_chip_info ad4081_chip_info = { + .name = "ad4081", + .product_id = AD4081_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4081_channel, + .lvds_cnv_clk_cnt_max = 2, +}; + +static const struct ad4080_chip_info ad4083_chip_info = { + .name = "ad4083", + .product_id = AD4083_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4083_channel, + .lvds_cnv_clk_cnt_max = 5, +}; + +static const struct ad4080_chip_info ad4084_chip_info = { + .name = "ad4084", + .product_id = AD4084_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4084_channel, + .lvds_cnv_clk_cnt_max = 2, +}; + +static const struct ad4080_chip_info ad4086_chip_info = { + .name = "ad4086", + .product_id = AD4086_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4086_channel, + .lvds_cnv_clk_cnt_max = 4, +}; + +static const struct ad4080_chip_info ad4087_chip_info = { + .name = "ad4087", + .product_id = AD4087_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4087_channel, + .lvds_cnv_clk_cnt_max = 1, }; static int ad4080_setup(struct iio_dev *indio_dev) { struct ad4080_state *st = iio_priv(indio_dev); struct device *dev = regmap_get_device(st->regmap); - unsigned int id; + __le16 id_le; + u16 id; int ret; ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, @@ -458,11 +528,13 @@ static int ad4080_setup(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_read(st->regmap, AD4080_REG_CHIP_TYPE, &id); + ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le, + sizeof(id_le)); if (ret) return ret; - if (id != AD4080_CHIP_ID) + id = le16_to_cpu(id_le); + if (id != st->info->product_id) dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id); ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A, @@ -488,7 +560,7 @@ static int ad4080_setup(struct iio_dev *indio_dev) AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, - AD4080_LVDS_CNV_CLK_CNT_MAX)); + st->info->lvds_cnv_clk_cnt_max)); if (ret) return ret; @@ -593,12 +665,22 @@ static int ad4080_probe(struct spi_device *spi) static const struct spi_device_id ad4080_id[] = { { "ad4080", (kernel_ulong_t)&ad4080_chip_info }, + { "ad4081", (kernel_ulong_t)&ad4081_chip_info }, + { "ad4083", (kernel_ulong_t)&ad4083_chip_info }, + { "ad4084", (kernel_ulong_t)&ad4084_chip_info }, + { "ad4086", (kernel_ulong_t)&ad4086_chip_info }, + { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); static const struct of_device_id ad4080_of_match[] = { { .compatible = "adi,ad4080", &ad4080_chip_info }, + { .compatible = "adi,ad4081", &ad4081_chip_info }, + { .compatible = "adi,ad4083", &ad4083_chip_info }, + { .compatible = "adi,ad4084", &ad4084_chip_info }, + { .compatible = "adi,ad4086", &ad4086_chip_info }, + { .compatible = "adi,ad4087", &ad4087_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4080_of_match); diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 61623cc6cb25..5c1a8f886bcc 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -10,6 +10,7 @@ #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> @@ -110,6 +111,8 @@ #define AD7124_FILTER_SINGLE_CYCLE BIT(16) #define AD7124_FILTER_FS GENMASK(10, 0) +#define AD7124_CFG_SLOT_UNASSIGNED ~0U + #define AD7124_MAX_CONFIGS 8 #define AD7124_MAX_CHANNELS 16 @@ -175,14 +178,13 @@ enum ad7124_filter_type { }; struct ad7124_channel_config { - bool live; unsigned int cfg_slot; unsigned int requested_odr; unsigned int requested_odr_micro; /* * Following fields are used to compare for equality. If you * make adaptations in it, you most likely also have to adapt - * ad7124_find_similar_live_cfg(), too. + * ad7124_config_equal(), too. */ struct_group(config_props, enum ad7124_ref_sel refsel; @@ -199,7 +201,6 @@ struct ad7124_channel_config { }; struct ad7124_channel { - unsigned int nr; struct ad7124_channel_config cfg; unsigned int ain; unsigned int slot; @@ -215,14 +216,14 @@ struct ad7124_state { unsigned int adc_control; unsigned int num_channels; struct mutex cfgs_lock; /* lock for configs access */ - unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */ + u8 cfg_slot_use_count[AD7124_MAX_CONFIGS]; /* * Stores the power-on reset value for the GAIN(x) registers which are * needed for measurements at gain 1 (i.e. CONFIG(x).PGA == 0) */ unsigned int gain_default; - DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS); + bool enable_single_cycle; }; static const struct ad7124_chip_info ad7124_4_chip_info = { @@ -366,9 +367,6 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel cfg->requested_odr_micro * factor / MICRO; odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, divisor), 1, 2047); - if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) - st->channels[channel].cfg.live = false; - st->channels[channel].cfg.odr_sel_bits = odr_sel_bits; } @@ -403,61 +401,6 @@ static int ad7124_get_3db_filter_factor(struct ad7124_state *st, } } -static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st, - struct ad7124_channel_config *cfg) -{ - struct ad7124_channel_config *cfg_aux; - int i; - - /* - * This is just to make sure that the comparison is adapted after - * struct ad7124_channel_config was changed. - */ - static_assert(sizeof_field(struct ad7124_channel_config, config_props) == - sizeof(struct { - enum ad7124_ref_sel refsel; - bool bipolar; - bool buf_positive; - bool buf_negative; - unsigned int vref_mv; - unsigned int pga_bits; - unsigned int odr_sel_bits; - enum ad7124_filter_type filter_type; - unsigned int calibration_offset; - unsigned int calibration_gain; - })); - - for (i = 0; i < st->num_channels; i++) { - cfg_aux = &st->channels[i].cfg; - - if (cfg_aux->live && - cfg->refsel == cfg_aux->refsel && - cfg->bipolar == cfg_aux->bipolar && - cfg->buf_positive == cfg_aux->buf_positive && - cfg->buf_negative == cfg_aux->buf_negative && - cfg->vref_mv == cfg_aux->vref_mv && - cfg->pga_bits == cfg_aux->pga_bits && - cfg->odr_sel_bits == cfg_aux->odr_sel_bits && - cfg->filter_type == cfg_aux->filter_type && - cfg->calibration_offset == cfg_aux->calibration_offset && - cfg->calibration_gain == cfg_aux->calibration_gain) - return cfg_aux; - } - - return NULL; -} - -static int ad7124_find_free_config_slot(struct ad7124_state *st) -{ - unsigned int free_cfg_slot; - - free_cfg_slot = find_first_zero_bit(&st->cfg_slots_status, AD7124_MAX_CONFIGS); - if (free_cfg_slot == AD7124_MAX_CONFIGS) - return -1; - - return free_cfg_slot; -} - /* Only called during probe, so dev_err_probe() can be used */ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg) { @@ -486,6 +429,21 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe } } +static bool ad7124_config_equal(struct ad7124_channel_config *a, + struct ad7124_channel_config *b) +{ + return a->refsel == b->refsel && + a->bipolar == b->bipolar && + a->buf_positive == b->buf_positive && + a->buf_negative == b->buf_negative && + a->vref_mv == b->vref_mv && + a->pga_bits == b->pga_bits && + a->odr_sel_bits == b->odr_sel_bits && + a->filter_type == b->filter_type && + a->calibration_offset == b->calibration_offset && + a->calibration_gain == b->calibration_gain; +} + static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg, unsigned int cfg_slot) { @@ -494,13 +452,13 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co unsigned int post = 0; int ret; - cfg->cfg_slot = cfg_slot; - - ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(cfg->cfg_slot), 3, cfg->calibration_offset); + ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(cfg_slot), 3, + cfg->calibration_offset); if (ret) return ret; - ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(cfg->cfg_slot), 3, cfg->calibration_gain); + ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(cfg_slot), 3, + cfg->calibration_gain); if (ret) return ret; @@ -510,7 +468,7 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co (cfg->buf_negative ? AD7124_CONFIG_AIN_BUFM : 0) | FIELD_PREP(AD7124_CONFIG_PGA, cfg->pga_bits); - ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val); + ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg_slot), 2, val); if (ret < 0) return ret; @@ -560,108 +518,107 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co * sampling frequency even when only one channel is enabled in a * buffered read. If it was not set, the N in ad7124_set_channel_odr() * would be 1 and we would get a faster sampling frequency than what - * was requested. + * was requested. It may only be disabled through debugfs for testing + * purposes. */ - return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg->cfg_slot), 3, + return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg_slot), 3, FIELD_PREP(AD7124_FILTER_FILTER, filter) | FIELD_PREP(AD7124_FILTER_REJ60, rej60) | FIELD_PREP(AD7124_FILTER_POST_FILTER, post) | - AD7124_FILTER_SINGLE_CYCLE | + FIELD_PREP(AD7124_FILTER_SINGLE_CYCLE, + st->enable_single_cycle) | FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits)); } -static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st) +/** + * ad7124_request_config_slot() - Request a config slot for a given config + * @st: Driver instance + * @channel: Channel to request a slot for + * + * Tries to find a matching config already in use, otherwise finds a free + * slot. If this function returns successfully, the use count for the slot is + * increased and the slot number is stored in cfg->cfg_slot. + * + * The slot must be released again with ad7124_release_config_slot() when no + * longer needed. + * + * Returns: 0 if a slot was successfully assigned, -EUSERS if no slot is + * available or other error if SPI communication fails. + */ +static int ad7124_request_config_slot(struct ad7124_state *st, u8 channel) { - struct ad7124_channel_config *lru_cfg; - struct ad7124_channel_config *cfg; - int ret; - int i; + unsigned int other, slot; + int last_used_slot = -1; - /* - * Pop least recently used config from the fifo - * in order to make room for the new one - */ - ret = kfifo_get(&st->live_cfgs_fifo, &lru_cfg); - if (ret <= 0) - return NULL; + /* Find another channel with a matching config, if any. */ + for (other = 0; other < st->num_channels; other++) { + if (other == channel) + continue; - lru_cfg->live = false; + if (st->channels[other].cfg.cfg_slot == AD7124_CFG_SLOT_UNASSIGNED) + continue; - /* mark slot as free */ - assign_bit(lru_cfg->cfg_slot, &st->cfg_slots_status, 0); + last_used_slot = max_t(int, last_used_slot, + st->channels[other].cfg.cfg_slot); - /* invalidate all other configs that pointed to this one */ - for (i = 0; i < st->num_channels; i++) { - cfg = &st->channels[i].cfg; + if (!ad7124_config_equal(&st->channels[other].cfg, + &st->channels[channel].cfg)) + continue; - if (cfg->cfg_slot == lru_cfg->cfg_slot) - cfg->live = false; + /* Found a match, re-use that slot. */ + slot = st->channels[other].cfg.cfg_slot; + st->cfg_slot_use_count[slot]++; + st->channels[channel].cfg.cfg_slot = slot; + + return 0; } - return lru_cfg; + /* No match, use next free slot. */ + slot = last_used_slot + 1; + if (slot >= AD7124_MAX_CONFIGS) + return -EUSERS; + + st->cfg_slot_use_count[slot]++; + st->channels[channel].cfg.cfg_slot = slot; + + return ad7124_write_config(st, &st->channels[channel].cfg, slot); } -static int ad7124_push_config(struct ad7124_state *st, struct ad7124_channel_config *cfg) +static void ad7124_release_config_slot(struct ad7124_state *st, u8 channel) { - struct ad7124_channel_config *lru_cfg; - int free_cfg_slot; - - free_cfg_slot = ad7124_find_free_config_slot(st); - if (free_cfg_slot >= 0) { - /* push the new config in configs queue */ - kfifo_put(&st->live_cfgs_fifo, cfg); - } else { - /* pop one config to make room for the new one */ - lru_cfg = ad7124_pop_config(st); - if (!lru_cfg) - return -EINVAL; + unsigned int slot; - /* push the new config in configs queue */ - free_cfg_slot = lru_cfg->cfg_slot; - kfifo_put(&st->live_cfgs_fifo, cfg); - } + /* + * All of these early return conditions can happen at probe when all + * channels are disabled. Otherwise, they should not happen normally. + */ + if (channel >= st->num_channels) + return; - /* mark slot as used */ - assign_bit(free_cfg_slot, &st->cfg_slots_status, 1); + slot = st->channels[channel].cfg.cfg_slot; - return ad7124_write_config(st, cfg, free_cfg_slot); -} + if (slot == AD7124_CFG_SLOT_UNASSIGNED || + st->cfg_slot_use_count[slot] == 0) + return; -static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel *ch) -{ - ch->cfg.live = true; - return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain | - FIELD_PREP(AD7124_CHANNEL_SETUP, ch->cfg.cfg_slot) | - AD7124_CHANNEL_ENABLE); + st->cfg_slot_use_count[slot]--; + st->channels[channel].cfg.cfg_slot = AD7124_CFG_SLOT_UNASSIGNED; } static int ad7124_prepare_read(struct ad7124_state *st, int address) { struct ad7124_channel_config *cfg = &st->channels[address].cfg; - struct ad7124_channel_config *live_cfg; + int ret; - /* - * Before doing any reads assign the channel a configuration. - * Check if channel's config is on the device - */ - if (!cfg->live) { - /* check if config matches another one */ - live_cfg = ad7124_find_similar_live_cfg(st, cfg); - if (!live_cfg) - ad7124_push_config(st, cfg); - else - cfg->cfg_slot = live_cfg->cfg_slot; - } + ret = ad7124_request_config_slot(st, address); + if (ret) + return ret; /* point channel to the config slot and enable */ - return ad7124_enable_channel(st, &st->channels[address]); -} - -static int __ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel) -{ - struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); - - return ad7124_prepare_read(st, channel); + return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(address), 2, + st->channels[address].ain | + FIELD_PREP(AD7124_CHANNEL_SETUP, cfg->cfg_slot) | + AD7124_CHANNEL_ENABLE); } static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel) @@ -670,7 +627,7 @@ static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel) int ret; mutex_lock(&st->cfgs_lock); - ret = __ad7124_set_channel(sd, channel); + ret = ad7124_prepare_read(st, channel); mutex_unlock(&st->cfgs_lock); return ret; @@ -700,6 +657,8 @@ static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan) { struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); + ad7124_release_config_slot(st, chan); + /* The relevant thing here is that AD7124_CHANNEL_ENABLE is cleared. */ return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan), 2, 0); } @@ -709,7 +668,7 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd) int ret; int i; - for (i = 0; i < 16; i++) { + for (i = 0; i < AD7124_MAX_CHANNELS; i++) { ret = ad7124_disable_one(sd, i); if (ret < 0) return ret; @@ -921,9 +880,6 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, gain = DIV_ROUND_CLOSEST(res, val2); res = ad7124_find_closest_match(ad7124_gain, ARRAY_SIZE(ad7124_gain), gain); - if (st->channels[chan->address].cfg.pga_bits != res) - st->channels[chan->address].cfg.live = false; - st->channels[chan->address].cfg.pga_bits = res; return 0; default: @@ -965,7 +921,7 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev, for (i = 0; i < st->num_channels; i++) { bit_set = test_bit(i, scan_mask); if (bit_set) - ret = __ad7124_set_channel(&st->sd, i); + ret = ad7124_prepare_read(st, i); else ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE, 0, 2); @@ -1066,7 +1022,11 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan if (ret < 0) return ret; - ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(ch->cfg.cfg_slot), 3, + /* + * Making the assumption that a single conversion will always + * use configuration slot 0 for the OFFSET/GAIN registers. + */ + ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(0), 3, &ch->cfg.calibration_offset); if (ret < 0) return ret; @@ -1081,7 +1041,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan if (ret < 0) return ret; - ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(ch->cfg.cfg_slot), 3, + ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &ch->cfg.calibration_gain); if (ret < 0) return ret; @@ -1172,7 +1132,6 @@ static int ad7124_set_filter_type_attr(struct iio_dev *dev, guard(mutex)(&st->cfgs_lock); - cfg->live = false; cfg->filter_type = value; ad7124_set_channel_odr(st, chan->address); @@ -1305,7 +1264,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, return dev_err_probe(dev, -EINVAL, "diff-channels property of %pfwP contains invalid data\n", child); - st->channels[channel].nr = channel; st->channels[channel].ain = FIELD_PREP(AD7124_CHANNEL_AINP, ain[0]) | FIELD_PREP(AD7124_CHANNEL_AINM, ain[1]); @@ -1332,7 +1290,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, if (num_channels < AD7124_MAX_CHANNELS) { st->channels[num_channels] = (struct ad7124_channel) { - .nr = num_channels, .ain = FIELD_PREP(AD7124_CHANNEL_AINP, AD7124_CHANNEL_AINx_TEMPSENSOR) | FIELD_PREP(AD7124_CHANNEL_AINM, AD7124_CHANNEL_AINx_AVSS), .cfg = { @@ -1358,6 +1315,7 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, }, .address = num_channels, .scan_index = num_channels, + .ext_info = ad7124_calibsys_ext_info, }; } @@ -1489,8 +1447,10 @@ static int ad7124_setup(struct ad7124_state *st) st->adc_control &= ~AD7124_ADC_CONTROL_MODE; st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, AD_SD_MODE_IDLE); - mutex_init(&st->cfgs_lock); - INIT_KFIFO(st->live_cfgs_fifo); + ret = devm_mutex_init(dev, &st->cfgs_lock); + if (ret) + return ret; + for (i = 0; i < st->num_channels; i++) { struct ad7124_channel_config *cfg = &st->channels[i].cfg; @@ -1498,6 +1458,8 @@ static int ad7124_setup(struct ad7124_state *st) if (ret < 0) return ret; + cfg->cfg_slot = AD7124_CFG_SLOT_UNASSIGNED; + /* Default filter type on the ADC after reset. */ cfg->filter_type = AD7124_FILTER_TYPE_SINC4; @@ -1559,9 +1521,9 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio * after full-scale calibration because the next * ad_sd_calibrate() call overwrites this via * ad_sigma_delta_set_channel() -> ad7124_set_channel() - * ... -> ad7124_enable_channel(). + * -> ad7124_prepare_read(). */ - ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(st->channels[i].cfg.cfg_slot), 3, + ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->channels[i].cfg.calibration_gain); if (ret < 0) return ret; @@ -1571,7 +1533,11 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio if (ret < 0) return ret; - ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(st->channels[i].cfg.cfg_slot), 3, + /* + * Making the assumption that a single conversion will always + * use configuration slot 0 for the OFFSET/GAIN registers. + */ + ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(0), 3, &st->channels[i].cfg.calibration_offset); if (ret < 0) return ret; @@ -1613,6 +1579,18 @@ static void ad7124_reg_disable(void *r) regulator_disable(r); } +static void ad7124_debugfs_init(struct iio_dev *indio_dev) +{ + struct dentry *dentry = iio_get_debugfs_dentry(indio_dev); + struct ad7124_state *st = iio_priv(indio_dev); + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return; + + debugfs_create_bool("enable_single_cycle", 0644, dentry, + &st->enable_single_cycle); +} + static int ad7124_probe(struct spi_device *spi) { const struct ad7124_chip_info *info; @@ -1633,6 +1611,9 @@ static int ad7124_probe(struct spi_device *spi) st->chip_info = info; + /* Only disabled for debug/testing purposes. */ + st->enable_single_cycle = true; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7124_info; @@ -1690,6 +1671,8 @@ static int ad7124_probe(struct spi_device *spi) if (ret < 0) return dev_err_probe(dev, ret, "Failed to register iio device\n"); + ad7124_debugfs_init(indio_dev); + return 0; } diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 872c88d0c86c..d96802b7847a 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -899,7 +899,7 @@ static int ad7768_read_label(struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); - return sprintf(label, "%s\n", st->labels[chan->channel]); + return sysfs_emit(label, "%s\n", st->labels[chan->channel]); } static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c index 94e05e11abd9..2de8a718d62a 100644 --- a/drivers/iio/adc/ade9000.c +++ b/drivers/iio/adc/ade9000.c @@ -1629,7 +1629,7 @@ static const struct regmap_config ade9000_regmap_config = { .val_bits = 32, .max_register = 0x6bc, .zero_flag_mask = true, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_read = ade9000_spi_read_reg, .reg_write = ade9000_spi_write_reg, .volatile_reg = ade9000_is_volatile_reg, diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 1d5fd5f534b8..bf2bfd6bdc41 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -645,6 +645,16 @@ static const struct aspeed_adc_trim_locate ast2600_adc1_trim = { .field = GENMASK(7, 4), }; +static const struct aspeed_adc_trim_locate ast2700_adc0_trim = { + .offset = 0x820, + .field = GENMASK(3, 0), +}; + +static const struct aspeed_adc_trim_locate ast2700_adc1_trim = { + .offset = 0x820, + .field = GENMASK(7, 4), +}; + static const struct aspeed_adc_model_data ast2400_model_data = { .model_name = "ast2400-adc", .vref_fixed_mv = 2500, @@ -689,11 +699,35 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = { .trim_locate = &ast2600_adc1_trim, }; +static const struct aspeed_adc_model_data ast2700_adc0_model_data = { + .model_name = "ast2700-adc0", + .min_sampling_rate = 10000, + .max_sampling_rate = 500000, + .wait_init_sequence = true, + .bat_sense_sup = true, + .scaler_bit_width = 16, + .num_channels = 8, + .trim_locate = &ast2700_adc0_trim, +}; + +static const struct aspeed_adc_model_data ast2700_adc1_model_data = { + .model_name = "ast2700-adc1", + .min_sampling_rate = 10000, + .max_sampling_rate = 500000, + .wait_init_sequence = true, + .bat_sense_sup = true, + .scaler_bit_width = 16, + .num_channels = 8, + .trim_locate = &ast2700_adc1_trim, +}; + static const struct of_device_id aspeed_adc_matches[] = { { .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data }, { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data }, { .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data }, { .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data }, + { .compatible = "aspeed,ast2700-adc0", .data = &ast2700_adc0_model_data }, + { .compatible = "aspeed,ast2700-adc1", .data = &ast2700_adc1_model_data }, { } }; MODULE_DEVICE_TABLE(of, aspeed_adc_matches); diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c new file mode 100644 index 000000000000..90ad4cb5868d --- /dev/null +++ b/drivers/iio/adc/max14001.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Analog Devices MAX14001/MAX14002 ADC driver + * + * Copyright (C) 2023-2025 Analog Devices Inc. + * Copyright (C) 2023 Kim Seer Paller <kimseer.paller@analog.com> + * Copyright (c) 2025 Marilene Andrade Garcia <marilene.agarcia@gmail.com> + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitrev.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/units.h> +#include <asm/byteorder.h> + +#include <linux/iio/iio.h> +#include <linux/iio/types.h> + +/* MAX14001 Registers Address */ +#define MAX14001_REG_ADC 0x00 +#define MAX14001_REG_FADC 0x01 +#define MAX14001_REG_FLAGS 0x02 +#define MAX14001_REG_FLTEN 0x03 +#define MAX14001_REG_THL 0x04 +#define MAX14001_REG_THU 0x05 +#define MAX14001_REG_INRR 0x06 +#define MAX14001_REG_INRT 0x07 +#define MAX14001_REG_INRP 0x08 +#define MAX14001_REG_CFG 0x09 +#define MAX14001_REG_ENBL 0x0A +#define MAX14001_REG_ACT 0x0B +#define MAX14001_REG_WEN 0x0C + +#define MAX14001_REG_VERIFICATION(x) ((x) + 0x10) + +#define MAX14001_REG_CFG_BIT_EXRF BIT(5) + +#define MAX14001_REG_WEN_VALUE_WRITE 0x294 + +#define MAX14001_MASK_ADDR GENMASK(15, 11) +#define MAX14001_MASK_WR BIT(10) +#define MAX14001_MASK_DATA GENMASK(9, 0) + +struct max14001_state { + const struct max14001_chip_info *chip_info; + struct spi_device *spi; + struct regmap *regmap; + int vref_mV; + bool spi_hw_has_lsb_first; + + /* + * The following buffers will be bit-reversed during device + * communication, because the device transmits and receives data + * LSB-first. + * DMA (thus cache coherency maintenance) requires the transfer + * buffers to live in their own cache lines. + */ + union { + __be16 be; + __le16 le; + } spi_tx_buffer __aligned(IIO_DMA_MINALIGN); + + union { + __be16 be; + __le16 le; + } spi_rx_buffer; +}; + +struct max14001_chip_info { + const char *name; +}; + +static int max14001_read(void *context, unsigned int reg, unsigned int *val) +{ + struct max14001_state *st = context; + struct spi_transfer xfers[] = { + { + .tx_buf = &st->spi_tx_buffer, + .len = sizeof(st->spi_tx_buffer), + .cs_change = 1, + }, { + .rx_buf = &st->spi_rx_buffer, + .len = sizeof(st->spi_rx_buffer), + }, + }; + int ret; + unsigned int addr, data; + + /* + * Prepare SPI transmit buffer 16 bit-value and reverse bit order + * to align with the LSB-first input on SDI port in order to meet + * the device communication requirements. If the controller supports + * SPI_LSB_FIRST, this step will be handled by the SPI controller. + */ + addr = FIELD_PREP(MAX14001_MASK_ADDR, reg); + + if (st->spi_hw_has_lsb_first) + st->spi_tx_buffer.le = cpu_to_le16(addr); + else + st->spi_tx_buffer.be = cpu_to_be16(bitrev16(addr)); + + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + if (ret) + return ret; + + /* + * Convert received 16-bit value to cpu-endian format and reverse + * bit order. If the controller supports SPI_LSB_FIRST, this step + * will be handled by the SPI controller. + */ + if (st->spi_hw_has_lsb_first) + data = le16_to_cpu(st->spi_rx_buffer.le); + else + data = bitrev16(be16_to_cpu(st->spi_rx_buffer.be)); + + *val = FIELD_GET(MAX14001_MASK_DATA, data); + + return 0; +} + +static int max14001_write(struct max14001_state *st, unsigned int reg, unsigned int val) +{ + unsigned int addr; + + /* + * Prepare SPI transmit buffer 16 bit-value and reverse bit order + * to align with the LSB-first input on SDI port in order to meet + * the device communication requirements. If the controller supports + * SPI_LSB_FIRST, this step will be handled by the SPI controller. + */ + addr = FIELD_PREP(MAX14001_MASK_ADDR, reg) | + FIELD_PREP(MAX14001_MASK_WR, 1) | + FIELD_PREP(MAX14001_MASK_DATA, val); + + if (st->spi_hw_has_lsb_first) + st->spi_tx_buffer.le = cpu_to_le16(addr); + else + st->spi_tx_buffer.be = cpu_to_be16(bitrev16(addr)); + + return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer)); +} + +static int max14001_write_single_reg(void *context, unsigned int reg, unsigned int val) +{ + struct max14001_state *st = context; + int ret; + + /* Enable writing to the SPI register. */ + ret = max14001_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_VALUE_WRITE); + if (ret) + return ret; + + /* Writing data into SPI register. */ + ret = max14001_write(st, reg, val); + if (ret) + return ret; + + /* Disable writing to the SPI register. */ + return max14001_write(st, MAX14001_REG_WEN, 0); +} + +static int max14001_write_verification_reg(struct max14001_state *st, unsigned int reg) +{ + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, reg, &val); + if (ret) + return ret; + + return max14001_write(st, MAX14001_REG_VERIFICATION(reg), val); +} + +static int max14001_disable_mv_fault(struct max14001_state *st) +{ + unsigned int reg; + int ret; + + /* Enable writing to the SPI registers. */ + ret = max14001_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_VALUE_WRITE); + if (ret) + return ret; + + /* + * Reads all registers and writes the values to their appropriate + * verification registers to clear the Memory Validation fault. + */ + for (reg = MAX14001_REG_FLTEN; reg <= MAX14001_REG_ENBL; reg++) { + ret = max14001_write_verification_reg(st, reg); + if (ret) + return ret; + } + + /* Disable writing to the SPI registers. */ + return max14001_write(st, MAX14001_REG_WEN, 0); +} + +static int max14001_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct max14001_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static int max14001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max14001_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(st->regmap, MAX14001_REG_ADC, val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->vref_mV; + *val2 = 10; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct regmap_range max14001_regmap_rd_range[] = { + regmap_reg_range(MAX14001_REG_ADC, MAX14001_REG_ENBL), + regmap_reg_range(MAX14001_REG_WEN, MAX14001_REG_WEN), + regmap_reg_range(MAX14001_REG_VERIFICATION(MAX14001_REG_FLTEN), + MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL)), +}; + +static const struct regmap_access_table max14001_regmap_rd_table = { + .yes_ranges = max14001_regmap_rd_range, + .n_yes_ranges = ARRAY_SIZE(max14001_regmap_rd_range), +}; + +static const struct regmap_range max14001_regmap_wr_range[] = { + regmap_reg_range(MAX14001_REG_FLTEN, MAX14001_REG_WEN), + regmap_reg_range(MAX14001_REG_VERIFICATION(MAX14001_REG_FLTEN), + MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL)), +}; + +static const struct regmap_access_table max14001_regmap_wr_table = { + .yes_ranges = max14001_regmap_wr_range, + .n_yes_ranges = ARRAY_SIZE(max14001_regmap_wr_range), +}; + +static const struct regmap_config max14001_regmap_config = { + .reg_read = max14001_read, + .reg_write = max14001_write_single_reg, + .max_register = MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL), + .rd_table = &max14001_regmap_rd_table, + .wr_table = &max14001_regmap_wr_table, +}; + +static const struct iio_info max14001_info = { + .read_raw = max14001_read_raw, + .debugfs_reg_access = max14001_debugfs_reg_access, +}; + +static const struct iio_chan_spec max14001_channel[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int max14001_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct max14001_state *st; + int ret; + bool use_ext_vrefin = false; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->spi_hw_has_lsb_first = spi->mode & SPI_LSB_FIRST; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -EINVAL; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &max14001_info; + indio_dev->channels = max14001_channel; + indio_dev->num_channels = ARRAY_SIZE(max14001_channel); + indio_dev->modes = INDIO_DIRECT_MODE; + + st->regmap = devm_regmap_init(dev, NULL, st, &max14001_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to initialize regmap\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable Vdd supply\n"); + + ret = devm_regulator_get_enable(dev, "vddl"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable Vddl supply\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get REFIN voltage\n"); + + if (ret == -ENODEV) + ret = 1250000; + else + use_ext_vrefin = true; + st->vref_mV = ret / (MICRO / MILLI); + + if (use_ext_vrefin) { + /* + * Configure the MAX14001/MAX14002 to use an external voltage + * reference source by setting the bit 5 of the configuration register. + */ + ret = regmap_set_bits(st->regmap, MAX14001_REG_CFG, + MAX14001_REG_CFG_BIT_EXRF); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set External REFIN in Configuration Register\n"); + } + + ret = max14001_disable_mv_fault(st); + if (ret) + return dev_err_probe(dev, ret, "Failed to disable MV Fault\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static struct max14001_chip_info max14001_chip_info = { + .name = "max14001", +}; + +static struct max14001_chip_info max14002_chip_info = { + .name = "max14002", +}; + +static const struct spi_device_id max14001_id_table[] = { + { "max14001", (kernel_ulong_t)&max14001_chip_info }, + { "max14002", (kernel_ulong_t)&max14002_chip_info }, + { } +}; + +static const struct of_device_id max14001_of_match[] = { + { .compatible = "adi,max14001", .data = &max14001_chip_info }, + { .compatible = "adi,max14002", .data = &max14002_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, max14001_of_match); + +static struct spi_driver max14001_driver = { + .driver = { + .name = "max14001", + .of_match_table = max14001_of_match, + }, + .probe = max14001_probe, + .id_table = max14001_id_table, +}; +module_spi_driver(max14001_driver); + +MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); +MODULE_AUTHOR("Marilene Andrade Garcia <marilene.agarcia@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices MAX14001/MAX14002 ADCs driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index cd679ff10a97..fcdf13f49c48 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -987,7 +987,7 @@ static int mcp3564_read_label(struct iio_dev *indio_dev, { struct mcp3564_state *adc = iio_priv(indio_dev); - return sprintf(label, "%s\n", adc->labels[chan->scan_index]); + return sysfs_emit(label, "%s\n", adc->labels[chan->scan_index]); } static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index f7e7172ef4f6..47cd350498a0 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1181,12 +1181,12 @@ static int read_label(struct iio_dev *indio_dev, char *label) { if (chan->type == IIO_TEMP) - return sprintf(label, "temp-sensor\n"); + return sysfs_emit(label, "temp-sensor\n"); if (chan->type == IIO_VOLTAGE && chan->channel >= NUM_MUX_0_VSS) - return sprintf(label, "%s\n", + return sysfs_emit(label, "%s\n", chan7_mux_names[chan->channel - NUM_MUX_0_VSS]); if (chan->type == IIO_VOLTAGE) - return sprintf(label, "channel-%d\n", chan->channel); + return sysfs_emit(label, "channel-%d\n", chan->channel); return 0; } diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index 69b3569c90e5..e0e4df418612 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -216,7 +216,7 @@ static const char *mt6360_channel_labels[MT6360_CHAN_MAX] = { static int mt6360_adc_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, char *label) { - return snprintf(label, PAGE_SIZE, "%s\n", mt6360_channel_labels[chan->channel]); + return sysfs_emit(label, "%s\n", mt6360_channel_labels[chan->channel]); } static const struct iio_info mt6360_adc_iio_info = { diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index 35433250b008..a0227b57f238 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -672,13 +672,13 @@ static int pac1921_read_label(struct iio_dev *indio_dev, { switch (chan->channel) { case PAC1921_CHAN_VBUS: - return sprintf(label, "vbus\n"); + return sysfs_emit(label, "vbus\n"); case PAC1921_CHAN_VSENSE: - return sprintf(label, "vsense\n"); + return sysfs_emit(label, "vsense\n"); case PAC1921_CHAN_CURRENT: - return sprintf(label, "current\n"); + return sysfs_emit(label, "current\n"); case PAC1921_CHAN_POWER: - return sprintf(label, "power\n"); + return sysfs_emit(label, "power\n"); default: return -EINVAL; } diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 48df16509260..ec96bb0f2ed6 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -768,7 +768,7 @@ static int pac1934_retrieve_data(struct pac1934_chip_info *info, * Re-schedule the work for the read registers on timeout * (to prevent chip registers saturation) */ - mod_delayed_work(system_wq, &info->work_chip_rfsh, + mod_delayed_work(system_percpu_wq, &info->work_chip_rfsh, msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS)); } diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c index f61ad0510f04..b245416bae12 100644 --- a/drivers/iio/adc/qcom-spmi-rradc.c +++ b/drivers/iio/adc/qcom-spmi-rradc.c @@ -769,7 +769,7 @@ static int rradc_read_raw(struct iio_dev *indio_dev, static int rradc_read_label(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, char *label) { - return snprintf(label, PAGE_SIZE, "%s\n", + return sysfs_emit(label, "%s\n", rradc_chans[chan->address].label); } diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c index d15e06c8b94d..7420aa6627d5 100644 --- a/drivers/iio/adc/rohm-bd79112.c +++ b/drivers/iio/adc/rohm-bd79112.c @@ -168,15 +168,10 @@ static int _get_gpio_reg(unsigned int offset, unsigned int base) #define GET_GPI_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_VALUE_A0_A7) static const struct regmap_range bd71815_volatile_ro_ranges[] = { - { - /* Read ADC data */ - .range_min = BD79112_REG_AGIO0A, - .range_max = BD79112_REG_AGIO15B, - }, { - /* GPI state */ - .range_min = BD79112_REG_GPI_VALUE_B8_15, - .range_max = BD79112_REG_GPI_VALUE_A0_A7, - }, + /* Read ADC data */ + regmap_reg_range(BD79112_REG_AGIO0A, BD79112_REG_AGIO15B), + /* GPI state */ + regmap_reg_range(BD79112_REG_GPI_VALUE_B8_15, BD79112_REG_GPI_VALUE_A0_A7), }; static const struct regmap_access_table bd79112_volatile_regs = { diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c index 06c55c8da93f..fc0452749b79 100644 --- a/drivers/iio/adc/rohm-bd79124.c +++ b/drivers/iio/adc/rohm-bd79124.c @@ -126,13 +126,8 @@ struct bd79124_data { }; static const struct regmap_range bd79124_ro_ranges[] = { - { - .range_min = BD79124_REG_EVENT_FLAG, - .range_max = BD79124_REG_EVENT_FLAG, - }, { - .range_min = BD79124_REG_RECENT_CH0_LSB, - .range_max = BD79124_REG_RECENT_CH7_MSB, - }, + regmap_reg_range(BD79124_REG_EVENT_FLAG, BD79124_REG_EVENT_FLAG), + regmap_reg_range(BD79124_REG_RECENT_CH0_LSB, BD79124_REG_RECENT_CH7_MSB), }; static const struct regmap_access_table bd79124_ro_regs = { @@ -141,22 +136,11 @@ static const struct regmap_access_table bd79124_ro_regs = { }; static const struct regmap_range bd79124_volatile_ranges[] = { - { - .range_min = BD79124_REG_RECENT_CH0_LSB, - .range_max = BD79124_REG_RECENT_CH7_MSB, - }, { - .range_min = BD79124_REG_EVENT_FLAG, - .range_max = BD79124_REG_EVENT_FLAG, - }, { - .range_min = BD79124_REG_EVENT_FLAG_HI, - .range_max = BD79124_REG_EVENT_FLAG_HI, - }, { - .range_min = BD79124_REG_EVENT_FLAG_LO, - .range_max = BD79124_REG_EVENT_FLAG_LO, - }, { - .range_min = BD79124_REG_SYSTEM_STATUS, - .range_max = BD79124_REG_SYSTEM_STATUS, - }, + regmap_reg_range(BD79124_REG_RECENT_CH0_LSB, BD79124_REG_RECENT_CH7_MSB), + regmap_reg_range(BD79124_REG_EVENT_FLAG, BD79124_REG_EVENT_FLAG), + regmap_reg_range(BD79124_REG_EVENT_FLAG_HI, BD79124_REG_EVENT_FLAG_HI), + regmap_reg_range(BD79124_REG_EVENT_FLAG_LO, BD79124_REG_EVENT_FLAG_LO), + regmap_reg_range(BD79124_REG_SYSTEM_STATUS, BD79124_REG_SYSTEM_STATUS), }; static const struct regmap_access_table bd79124_volatile_regs = { @@ -165,13 +149,8 @@ static const struct regmap_access_table bd79124_volatile_regs = { }; static const struct regmap_range bd79124_precious_ranges[] = { - { - .range_min = BD79124_REG_EVENT_FLAG_HI, - .range_max = BD79124_REG_EVENT_FLAG_HI, - }, { - .range_min = BD79124_REG_EVENT_FLAG_LO, - .range_max = BD79124_REG_EVENT_FLAG_LO, - }, + regmap_reg_range(BD79124_REG_EVENT_FLAG_HI, BD79124_REG_EVENT_FLAG_HI), + regmap_reg_range(BD79124_REG_EVENT_FLAG_LO, BD79124_REG_EVENT_FLAG_LO), }; static const struct regmap_access_table bd79124_precious_regs = { diff --git a/drivers/iio/adc/rzn1-adc.c b/drivers/iio/adc/rzn1-adc.c new file mode 100644 index 000000000000..93b0feef8ea0 --- /dev/null +++ b/drivers/iio/adc/rzn1-adc.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/N1 ADC driver + * + * Copyright (C) 2025 Schneider-Electric + * + * Author: Herve Codina <herve.codina@bootlin.com> + * + * The RZ/N1 ADC controller can handle channels from its internal ADC1 and/or + * ADC2 cores. The driver use ADC1 and/or ADC2 cores depending on the presence + * of the related power supplies (AVDD and VREF) description in the device-tree. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> + +#define RZN1_ADC_CONTROL_REG 0x02c +#define RZN1_ADC_CONTROL_ADC_BUSY BIT(6) + +#define RZN1_ADC_FORCE_REG 0x030 +#define RZN1_ADC_SET_FORCE_REG 0x034 +#define RZN1_ADC_CLEAR_FORCE_REG 0x038 +#define RZN1_ADC_FORCE_VC(_n) BIT(_n) + +#define RZN1_ADC_CONFIG_REG 0x040 +#define RZN1_ADC_CONFIG_ADC_POWER_DOWN BIT(3) + +#define RZN1_ADC_VC_REG(_n) (0x0c0 + 4 * (_n)) +#define RZN1_ADC_VC_ADC2_ENABLE BIT(16) +#define RZN1_ADC_VC_ADC1_ENABLE BIT(15) +#define RZN1_ADC_VC_ADC2_CHANNEL_SEL_MASK GENMASK(5, 3) +#define RZN1_ADC_VC_ADC1_CHANNEL_SEL_MASK GENMASK(2, 0) + +#define RZN1_ADC_ADC1_DATA_REG(_n) (0x100 + 4 * (_n)) +#define RZN1_ADC_ADC2_DATA_REG(_n) (0x140 + 4 * (_n)) +#define RZN1_ADC_ADCX_DATA_DATA_MASK GENMASK(11, 0) + +#define RZN1_ADC_NO_CHANNEL -1 + +#define RZN1_ADC_CHANNEL_SHARED_SCALE(_ch, _ds_name) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = (_ds_name), \ +} + +#define RZN1_ADC_CHANNEL_SEPARATED_SCALE(_ch, _ds_name) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = (_ds_name), \ +} + +/* + * 8 ADC1_IN signals existed numbered 0..4, 6..8 + * ADCx_IN5 doesn't exist in RZ/N1 datasheet + */ +static struct iio_chan_spec rzn1_adc1_channels[] = { + RZN1_ADC_CHANNEL_SHARED_SCALE(0, "ADC1_IN0"), + RZN1_ADC_CHANNEL_SHARED_SCALE(1, "ADC1_IN1"), + RZN1_ADC_CHANNEL_SHARED_SCALE(2, "ADC1_IN2"), + RZN1_ADC_CHANNEL_SHARED_SCALE(3, "ADC1_IN3"), + RZN1_ADC_CHANNEL_SHARED_SCALE(4, "ADC1_IN4"), + RZN1_ADC_CHANNEL_SHARED_SCALE(5, "ADC1_IN6"), + RZN1_ADC_CHANNEL_SHARED_SCALE(6, "ADC1_IN7"), + RZN1_ADC_CHANNEL_SHARED_SCALE(7, "ADC1_IN8"), +}; + +static struct iio_chan_spec rzn1_adc2_channels[] = { + RZN1_ADC_CHANNEL_SHARED_SCALE(8, "ADC2_IN0"), + RZN1_ADC_CHANNEL_SHARED_SCALE(9, "ADC2_IN1"), + RZN1_ADC_CHANNEL_SHARED_SCALE(10, "ADC2_IN2"), + RZN1_ADC_CHANNEL_SHARED_SCALE(11, "ADC2_IN3"), + RZN1_ADC_CHANNEL_SHARED_SCALE(12, "ADC2_IN4"), + RZN1_ADC_CHANNEL_SHARED_SCALE(13, "ADC2_IN6"), + RZN1_ADC_CHANNEL_SHARED_SCALE(14, "ADC2_IN7"), + RZN1_ADC_CHANNEL_SHARED_SCALE(15, "ADC2_IN8"), +}; + +/* + * If both ADCs core are used, scale cannot be common. Indeed, scale is + * based on Vref connected on each ADC core. + */ +static struct iio_chan_spec rzn1_adc1_adc2_channels[] = { + RZN1_ADC_CHANNEL_SEPARATED_SCALE(0, "ADC1_IN0"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(1, "ADC1_IN1"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(2, "ADC1_IN2"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(3, "ADC1_IN3"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(4, "ADC1_IN4"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(5, "ADC1_IN6"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(6, "ADC1_IN7"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(7, "ADC1_IN8"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(8, "ADC2_IN0"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(9, "ADC2_IN1"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(10, "ADC2_IN2"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(11, "ADC2_IN3"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(12, "ADC2_IN4"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(13, "ADC2_IN6"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(14, "ADC2_IN7"), + RZN1_ADC_CHANNEL_SEPARATED_SCALE(15, "ADC2_IN8"), +}; + +struct rzn1_adc { + struct device *dev; + void __iomem *regs; + struct mutex lock; /* ADC lock */ + int adc1_vref_mV; /* ADC1 Vref in mV. Negative if ADC1 is not used */ + int adc2_vref_mV; /* ADC2 Vref in mV. Negative if ADC2 is not used */ +}; + +static int rzn1_adc_power(struct rzn1_adc *rzn1_adc, bool power) +{ + u32 v; + + writel(power ? 0 : RZN1_ADC_CONFIG_ADC_POWER_DOWN, + rzn1_adc->regs + RZN1_ADC_CONFIG_REG); + + /* Wait for the ADC_BUSY to clear */ + return readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_CONTROL_REG, + v, !(v & RZN1_ADC_CONTROL_ADC_BUSY), + 0, 500); +} + +static void rzn1_adc_vc_setup_conversion(struct rzn1_adc *rzn1_adc, u32 ch, + int adc1_ch, int adc2_ch) +{ + u32 vc = 0; + + if (adc1_ch != RZN1_ADC_NO_CHANNEL) + vc |= RZN1_ADC_VC_ADC1_ENABLE | + FIELD_PREP(RZN1_ADC_VC_ADC1_CHANNEL_SEL_MASK, adc1_ch); + + if (adc2_ch != RZN1_ADC_NO_CHANNEL) + vc |= RZN1_ADC_VC_ADC2_ENABLE | + FIELD_PREP(RZN1_ADC_VC_ADC2_CHANNEL_SEL_MASK, adc2_ch); + + writel(vc, rzn1_adc->regs + RZN1_ADC_VC_REG(ch)); +} + +static int rzn1_adc_vc_start_conversion(struct rzn1_adc *rzn1_adc, u32 ch) +{ + u32 val; + + val = readl(rzn1_adc->regs + RZN1_ADC_FORCE_REG); + if (val & RZN1_ADC_FORCE_VC(ch)) + return -EBUSY; + + writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_SET_FORCE_REG); + + return 0; +} + +static void rzn1_adc_vc_stop_conversion(struct rzn1_adc *rzn1_adc, u32 ch) +{ + writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_CLEAR_FORCE_REG); +} + +static int rzn1_adc_vc_wait_conversion(struct rzn1_adc *rzn1_adc, u32 ch, + u32 *adc1_data, u32 *adc2_data) +{ + u32 data_reg; + int ret; + u32 v; + + /* + * When a VC is selected, it needs 20 ADC clocks to perform the + * conversion. + * + * The worst case is when the 16 VCs need to perform a conversion and + * our VC is the lowest in term of priority. + * + * In that case, the conversion is performed in 16 * 20 ADC clocks. + * + * The ADC clock can be set from 4MHz to 20MHz. This leads to a worst + * case of 16 * 20 * 1/4Mhz = 80us. + * + * Round it up to 100us. + */ + + /* Wait for the ADC_FORCE_VC(n) to clear */ + ret = readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_FORCE_REG, + v, !(v & RZN1_ADC_FORCE_VC(ch)), + 0, 100); + if (ret) + return ret; + + if (adc1_data) { + data_reg = readl(rzn1_adc->regs + RZN1_ADC_ADC1_DATA_REG(ch)); + *adc1_data = FIELD_GET(RZN1_ADC_ADCX_DATA_DATA_MASK, data_reg); + } + + if (adc2_data) { + data_reg = readl(rzn1_adc->regs + RZN1_ADC_ADC2_DATA_REG(ch)); + *adc2_data = FIELD_GET(RZN1_ADC_ADCX_DATA_DATA_MASK, data_reg); + } + + return 0; +} + +static int rzn1_adc_read_raw_ch(struct rzn1_adc *rzn1_adc, unsigned int chan, int *val) +{ + u32 *adc1_data, *adc2_data; + int adc1_ch, adc2_ch; + u32 adc_data; + int ret; + + /* + * IIO chan are decoupled from chans used in rzn1_adc_vc_*() functions. + * The RZ/N1 ADC VC controller can handle on a single VC chan one + * channel from the ADC1 core and one channel from the ADC2 core. + * + * Even if IIO chans are mapped 1:1 to ADC core chans and so uses only + * a chan from ADC1 or a chan from ADC2, future improvements can define + * an IIO chan that uses one chan from ADC1 and one chan from ADC2. + */ + + if (chan < 8) { + /* chan 0..7 used to get ADC1 ch 0..7 */ + adc1_ch = chan; + adc1_data = &adc_data; + adc2_ch = RZN1_ADC_NO_CHANNEL; + adc2_data = NULL; + } else if (chan < 16) { + /* chan 8..15 used to get ADC2 ch 0..7 */ + adc1_ch = RZN1_ADC_NO_CHANNEL; + adc1_data = NULL; + adc2_ch = chan - 8; + adc2_data = &adc_data; + } else { + return -EINVAL; + } + + ACQUIRE(pm_runtime_active_auto_try_enabled, pm)(rzn1_adc->dev); + ret = ACQUIRE_ERR(pm_runtime_active_auto_try_enabled, &pm); + if (ret < 0) + return ret; + + scoped_guard(mutex, &rzn1_adc->lock) { + rzn1_adc_vc_setup_conversion(rzn1_adc, chan, adc1_ch, adc2_ch); + + ret = rzn1_adc_vc_start_conversion(rzn1_adc, chan); + if (ret) + return ret; + + ret = rzn1_adc_vc_wait_conversion(rzn1_adc, chan, adc1_data, adc2_data); + if (ret) { + rzn1_adc_vc_stop_conversion(rzn1_adc, chan); + return ret; + } + } + + *val = adc_data; + ret = IIO_VAL_INT; + + return 0; +} + +static int rzn1_adc_get_vref_mV(struct rzn1_adc *rzn1_adc, unsigned int chan) +{ + /* chan 0..7 use ADC1 ch 0..7. Vref related to ADC1 core */ + if (chan < 8) + return rzn1_adc->adc1_vref_mV; + + /* chan 8..15 use ADC2 ch 0..7. Vref related to ADC2 core */ + if (chan < 16) + return rzn1_adc->adc2_vref_mV; + + return -EINVAL; +} + +static int rzn1_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rzn1_adc *rzn1_adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = rzn1_adc_read_raw_ch(rzn1_adc, chan->channel, val); + if (ret) + return ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret = rzn1_adc_get_vref_mV(rzn1_adc, chan->channel); + if (ret < 0) + return ret; + *val = ret; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static const struct iio_info rzn1_adc_info = { + .read_raw = &rzn1_adc_read_raw, +}; + +static int rzn1_adc_set_iio_dev_channels(struct rzn1_adc *rzn1_adc, + struct iio_dev *indio_dev) +{ + /* + * When an ADC core is not used, its related vref_mV is set to a + * negative error code. Use the correct IIO channels table based on + * those vref_mV values. + */ + if (rzn1_adc->adc1_vref_mV >= 0) { + if (rzn1_adc->adc2_vref_mV >= 0) { + indio_dev->channels = rzn1_adc1_adc2_channels; + indio_dev->num_channels = ARRAY_SIZE(rzn1_adc1_adc2_channels); + } else { + indio_dev->channels = rzn1_adc1_channels; + indio_dev->num_channels = ARRAY_SIZE(rzn1_adc1_channels); + } + return 0; + } + + if (rzn1_adc->adc2_vref_mV >= 0) { + indio_dev->channels = rzn1_adc2_channels; + indio_dev->num_channels = ARRAY_SIZE(rzn1_adc2_channels); + return 0; + } + + return dev_err_probe(rzn1_adc->dev, -ENODEV, + "Failed to set IIO channels, no ADC core used\n"); +} + +static int rzn1_adc_core_get_regulators(struct rzn1_adc *rzn1_adc, + int *adc_vref_mV, + const char *avdd_name, const char *vref_name) +{ + struct device *dev = rzn1_adc->dev; + int ret; + + /* + * For a given ADC core (ADC1 or ADC2), both regulators (AVDD and VREF) + * must be available in order to have the ADC core used. + * + * We use the regulators presence to check the usage of the related + * ADC core. If both regulators are available, the ADC core is used. + * Otherwise, the ADC core is not used. + * + * The adc_vref_mV value is set to a negative error code (-ENODEV) when + * the ADC core is not used. Otherwise it is set to the VRef mV value. + */ + + *adc_vref_mV = -ENODEV; + + ret = devm_regulator_get_enable_optional(dev, avdd_name); + if (ret == -ENODEV) + return 0; + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get '%s' regulator\n", + avdd_name); + + ret = devm_regulator_get_enable_read_voltage(dev, vref_name); + if (ret == -ENODEV) + return 0; + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get '%s' regulator\n", + vref_name); + + /* + * Both regulators are available. + * Set adc_vref_mV to the Vref value in mV. This, as the value set is + * positive, also signals that the ADC is used. + */ + *adc_vref_mV = ret / 1000; + + return 0; +} + +static int rzn1_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct rzn1_adc *rzn1_adc; + struct clk *clk; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*rzn1_adc)); + if (!indio_dev) + return -ENOMEM; + + rzn1_adc = iio_priv(indio_dev); + rzn1_adc->dev = dev; + + ret = devm_mutex_init(dev, &rzn1_adc->lock); + if (ret) + return ret; + + rzn1_adc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rzn1_adc->regs)) + return PTR_ERR(rzn1_adc->regs); + + clk = devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "Failed to get pclk\n"); + + clk = devm_clk_get_enabled(dev, "adc"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "Failed to get adc clk\n"); + + ret = rzn1_adc_core_get_regulators(rzn1_adc, &rzn1_adc->adc1_vref_mV, + "adc1-avdd", "adc1-vref"); + if (ret) + return ret; + + ret = rzn1_adc_core_get_regulators(rzn1_adc, &rzn1_adc->adc2_vref_mV, + "adc2-avdd", "adc2-vref"); + if (ret) + return ret; + + platform_set_drvdata(pdev, rzn1_adc); + + indio_dev->name = "rzn1-adc"; + indio_dev->info = &rzn1_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + ret = rzn1_adc_set_iio_dev_channels(rzn1_adc, indio_dev); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 500); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static int rzn1_adc_pm_runtime_suspend(struct device *dev) +{ + struct rzn1_adc *rzn1_adc = dev_get_drvdata(dev); + + return rzn1_adc_power(rzn1_adc, false); +} + +static int rzn1_adc_pm_runtime_resume(struct device *dev) +{ + struct rzn1_adc *rzn1_adc = dev_get_drvdata(dev); + + return rzn1_adc_power(rzn1_adc, true); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(rzn1_adc_pm_ops, + rzn1_adc_pm_runtime_suspend, + rzn1_adc_pm_runtime_resume, + NULL); + +static const struct of_device_id rzn1_adc_of_match[] = { + { .compatible = "renesas,rzn1-adc" }, + { } +}; +MODULE_DEVICE_TABLE(of, rzn1_adc_of_match); + +static struct platform_driver rzn1_adc_driver = { + .probe = rzn1_adc_probe, + .driver = { + .name = "rzn1-adc", + .of_match_table = rzn1_adc_of_match, + .pm = pm_ptr(&rzn1_adc_pm_ops), + }, +}; +module_platform_driver(rzn1_adc_driver); + +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); +MODULE_DESCRIPTION("Renesas RZ/N1 ADC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c new file mode 100644 index 000000000000..33ce5cc44ff4 --- /dev/null +++ b/drivers/iio/adc/rzt2h_adc.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/iio/adc-helpers.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> + +#define RZT2H_ADCSR_REG 0x00 +#define RZT2H_ADCSR_ADIE_MASK BIT(12) +#define RZT2H_ADCSR_ADCS_MASK GENMASK(14, 13) +#define RZT2H_ADCSR_ADCS_SINGLE 0b00 +#define RZT2H_ADCSR_ADST_MASK BIT(15) + +#define RZT2H_ADANSA0_REG 0x04 +#define RZT2H_ADANSA0_CH_MASK(x) BIT(x) + +#define RZT2H_ADDR_REG(x) (0x20 + 0x2 * (x)) + +#define RZT2H_ADCALCTL_REG 0x1f0 +#define RZT2H_ADCALCTL_CAL_MASK BIT(0) +#define RZT2H_ADCALCTL_CAL_RDY_MASK BIT(1) +#define RZT2H_ADCALCTL_CAL_ERR_MASK BIT(2) + +#define RZT2H_ADC_MAX_CHANNELS 16 + +struct rzt2h_adc { + void __iomem *base; + struct device *dev; + + struct completion completion; + /* lock to protect against multiple access to the device */ + struct mutex lock; + + const struct iio_chan_spec *channels; + unsigned int num_channels; + unsigned int max_channels; +}; + +static void rzt2h_adc_start(struct rzt2h_adc *adc, unsigned int conversion_type) +{ + u16 reg; + + reg = readw(adc->base + RZT2H_ADCSR_REG); + + /* Set conversion type */ + FIELD_MODIFY(RZT2H_ADCSR_ADCS_MASK, ®, conversion_type); + + /* Set end of conversion interrupt and start bit. */ + reg |= RZT2H_ADCSR_ADIE_MASK | RZT2H_ADCSR_ADST_MASK; + + writew(reg, adc->base + RZT2H_ADCSR_REG); +} + +static void rzt2h_adc_stop(struct rzt2h_adc *adc) +{ + u16 reg; + + reg = readw(adc->base + RZT2H_ADCSR_REG); + + /* Clear end of conversion interrupt and start bit. */ + reg &= ~(RZT2H_ADCSR_ADIE_MASK | RZT2H_ADCSR_ADST_MASK); + + writew(reg, adc->base + RZT2H_ADCSR_REG); +} + +static int rzt2h_adc_read_single(struct rzt2h_adc *adc, unsigned int ch, int *val) +{ + int ret; + + ret = pm_runtime_resume_and_get(adc->dev); + if (ret) + return ret; + + mutex_lock(&adc->lock); + + reinit_completion(&adc->completion); + + /* Enable a single channel */ + writew(RZT2H_ADANSA0_CH_MASK(ch), adc->base + RZT2H_ADANSA0_REG); + + rzt2h_adc_start(adc, RZT2H_ADCSR_ADCS_SINGLE); + + /* + * Datasheet Page 2770, Table 41.1: + * 0.32us per channel when sample-and-hold circuits are not in use. + */ + ret = wait_for_completion_timeout(&adc->completion, usecs_to_jiffies(1)); + if (!ret) { + ret = -ETIMEDOUT; + goto disable; + } + + *val = readw(adc->base + RZT2H_ADDR_REG(ch)); + ret = IIO_VAL_INT; + +disable: + rzt2h_adc_stop(adc); + + mutex_unlock(&adc->lock); + + pm_runtime_put_autosuspend(adc->dev); + + return ret; +} + +static void rzt2h_adc_set_cal(struct rzt2h_adc *adc, bool cal) +{ + u16 val; + + val = readw(adc->base + RZT2H_ADCALCTL_REG); + if (cal) + val |= RZT2H_ADCALCTL_CAL_MASK; + else + val &= ~RZT2H_ADCALCTL_CAL_MASK; + + writew(val, adc->base + RZT2H_ADCALCTL_REG); +} + +static int rzt2h_adc_calibrate(struct rzt2h_adc *adc) +{ + u16 val; + int ret; + + rzt2h_adc_set_cal(adc, true); + + ret = read_poll_timeout(readw, val, val & RZT2H_ADCALCTL_CAL_RDY_MASK, + 200, 1000, true, adc->base + RZT2H_ADCALCTL_REG); + if (ret) { + dev_err(adc->dev, "Calibration timed out: %d\n", ret); + return ret; + } + + rzt2h_adc_set_cal(adc, false); + + if (val & RZT2H_ADCALCTL_CAL_ERR_MASK) { + dev_err(adc->dev, "Calibration failed\n"); + return -EINVAL; + } + + return 0; +} + +static int rzt2h_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rzt2h_adc *adc = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return rzt2h_adc_read_single(adc, chan->channel, val); + case IIO_CHAN_INFO_SCALE: + *val = 1800; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info rzt2h_adc_iio_info = { + .read_raw = rzt2h_adc_read_raw, +}; + +static irqreturn_t rzt2h_adc_isr(int irq, void *private) +{ + struct rzt2h_adc *adc = private; + + complete(&adc->completion); + + return IRQ_HANDLED; +} + +static const struct iio_chan_spec rzt2h_adc_chan_template = { + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .type = IIO_VOLTAGE, +}; + +static int rzt2h_adc_parse_properties(struct rzt2h_adc *adc) +{ + struct iio_chan_spec *chan_array; + unsigned int i; + int ret; + + ret = devm_iio_adc_device_alloc_chaninfo_se(adc->dev, + &rzt2h_adc_chan_template, + RZT2H_ADC_MAX_CHANNELS - 1, + &chan_array); + if (ret < 0) + return dev_err_probe(adc->dev, ret, "Failed to read channel info"); + + adc->num_channels = ret; + adc->channels = chan_array; + + for (i = 0; i < adc->num_channels; i++) + if (chan_array[i].channel + 1 > adc->max_channels) + adc->max_channels = chan_array[i].channel + 1; + + return 0; +} + +static int rzt2h_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct rzt2h_adc *adc; + int ret, irq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->dev = dev; + init_completion(&adc->completion); + + ret = devm_mutex_init(dev, &adc->lock); + if (ret) + return ret; + + platform_set_drvdata(pdev, adc); + + ret = rzt2h_adc_parse_properties(adc); + if (ret) + return ret; + + adc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adc->base)) + return PTR_ERR(adc->base); + + pm_runtime_set_autosuspend_delay(dev, 300); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + irq = platform_get_irq_byname(pdev, "adi"); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rzt2h_adc_isr, 0, dev_name(dev), adc); + if (ret) + return ret; + + indio_dev->name = "rzt2h-adc"; + indio_dev->info = &rzt2h_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc->channels; + indio_dev->num_channels = adc->num_channels; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id rzt2h_adc_match[] = { + { .compatible = "renesas,r9a09g077-adc" }, + { } +}; +MODULE_DEVICE_TABLE(of, rzt2h_adc_match); + +static int rzt2h_adc_pm_runtime_resume(struct device *dev) +{ + struct rzt2h_adc *adc = dev_get_drvdata(dev); + + /* + * Datasheet Page 2810, Section 41.5.6: + * After release from the module-stop state, wait for at least + * 0.5 µs before starting A/D conversion. + */ + fsleep(1); + + return rzt2h_adc_calibrate(adc); +} + +static const struct dev_pm_ops rzt2h_adc_pm_ops = { + RUNTIME_PM_OPS(NULL, rzt2h_adc_pm_runtime_resume, NULL) +}; + +static struct platform_driver rzt2h_adc_driver = { + .probe = rzt2h_adc_probe, + .driver = { + .name = "rzt2h-adc", + .of_match_table = rzt2h_adc_match, + .pm = pm_ptr(&rzt2h_adc_pm_ops), + }, +}; + +module_platform_driver(rzt2h_adc_driver); + +MODULE_AUTHOR("Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/T2H / RZ/N2H ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DRIVER"); diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index 742acc6d8cf9..c9a20024d6b1 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -848,7 +848,7 @@ static int ads131e08_probe(struct spi_device *spi) ret = devm_iio_trigger_register(&spi->dev, st->trig); if (ret) { dev_err(&spi->dev, "failed to register IIO trigger\n"); - return -ENOMEM; + return ret; } indio_dev->trig = iio_trigger_get(st->trig); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 99f274adc870..a1a28584de93 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -123,7 +123,7 @@ static void tiadc_step_config(struct iio_dev *indio_dev) chan = adc_dev->channel_line[i]; - if (adc_dev->step_avg[i]) + if (adc_dev->step_avg[i] && adc_dev->step_avg[i] <= STEPCONFIG_AVG_16) stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | STEPCONFIG_FIFO1; else |
