diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 17315e53cd600c..0b83b236ea67bc 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -45,6 +45,8 @@ #define AD7124_STATUS_POR_FLAG_MSK BIT(4) /* AD7124_ADC_CONTROL */ +#define AD7124_ADC_STATUS_EN_MSK BIT(10) +#define AD7124_ADC_STATUS_EN(x) FIELD_PREP(AD7124_ADC_STATUS_EN_MSK, x) #define AD7124_ADC_CTRL_REF_EN_MSK BIT(8) #define AD7124_ADC_CTRL_REF_EN(x) FIELD_PREP(AD7124_ADC_CTRL_REF_EN_MSK, x) #define AD7124_ADC_CTRL_PWR_MSK GENMASK(7, 6) @@ -519,12 +521,32 @@ static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int slot, return ret; } +static int ad7124_append_status(struct ad_sigma_delta *sd, bool append) +{ + struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); + unsigned int adc_control = st->adc_control; + int ret; + + adc_control &= ~AD7124_ADC_STATUS_EN_MSK; + adc_control |= AD7124_ADC_STATUS_EN(append); + + ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, adc_control); + if (ret < 0) + return ret; + + st->adc_control = adc_control; + + return 0; +} + static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { .set_channel = ad7124_set_channel, + .append_status = ad7124_append_status, .set_mode = ad7124_set_mode, .has_registers = true, .addr_shift = 0, .read_mask = BIT(6), + .status_ch_mask = GENMASK(3, 0), .data_reg = AD7124_DATA, .irq_flags = IRQF_TRIGGER_FALLING }; @@ -914,8 +936,8 @@ static int ad7124_probe(struct spi_device *spi) st->chip_info = info; - ad_sd_init(&st->sd, indio_dev, spi, &ad7124_sigma_delta_info); st->sd.num_slots = AD7124_SEQUENCER_SLOTS; + ad_sd_init(&st->sd, indio_dev, spi, &ad7124_sigma_delta_info); indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 5075d41e334641..dadacc86eb4760 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -6,6 +6,7 @@ * Licensed under the GPL-2. */ +#include "linux/bitfield.h" #include #include #include @@ -77,6 +78,10 @@ #define AD7173_GPIO_GP_DATA1 BIT(1) #define AD7173_GPIO_GP_DATA0 BIT(0) +#define AD7173_INTERFACE_DATA_STAT BIT(6) +#define AD7173_INTERFACE_DATA_STAT_EN(x) \ + FIELD_PREP(AD7173_INTERFACE_DATA_STAT, x) + #define AD7173_SETUP_BIPOLAR BIT(12) #define AD7173_SETUP_AREF_BUF (0x3 << 10) #define AD7173_SETUP_AIN_BUF (0x3 << 8) @@ -118,6 +123,7 @@ struct ad7173_state { struct ad_sigma_delta sd; const struct ad7173_device_info *info; + unsigned int *channel_ains; #ifdef CONFIG_GPIOLIB struct gpio_chip gpiochip; @@ -438,11 +444,12 @@ static int ad7173_set_channel(struct ad_sigma_delta *sd, unsigned int slot, unsigned int val; if (channel == AD_SD_SLOT_DISABLE) - val = 0; + val = 0; else - val = AD7173_CH_ENABLE | channel; + val = AD7173_CH_ENABLE | AD7173_CH_SETUP_SEL(slot) | + st->channel_ains[channel]; - return ad_sd_write_reg(&st->sd, AD7173_REG_CH(slot), 2, val); + return ad_sd_write_reg(&st->sd, AD7173_REG_CH(channel), 2, val); } static int ad7173_set_mode(struct ad_sigma_delta *sd, @@ -456,14 +463,33 @@ static int ad7173_set_mode(struct ad_sigma_delta *sd, return ad_sd_write_reg(&st->sd, AD7173_REG_ADC_MODE, 2, st->adc_mode); } +static int ad7173_append_status(struct ad_sigma_delta *sd, bool append) +{ + struct ad7173_state *st = ad_sigma_delta_to_ad7173(sd); + unsigned int interface_mode = st->interface_mode; + int ret; + + interface_mode &= ~AD7173_INTERFACE_DATA_STAT; + interface_mode |= AD7173_INTERFACE_DATA_STAT_EN(append); + ret = ad_sd_write_reg(&st->sd, AD7173_REG_INTERFACE_MODE, 2, interface_mode); + if (ret) + return ret; + + st->interface_mode = interface_mode; + + return 0; +} + static const struct ad_sigma_delta_info ad7173_sigma_delta_info = { .set_channel = ad7173_set_channel, + .append_status = ad7173_append_status, .prepare_channel = ad7173_prepare_channel, .set_mode = ad7173_set_mode, .has_registers = true, .data_reg = AD7173_REG_DATA, .addr_shift = 0, .read_mask = BIT(6), + .status_ch_mask = GENMASK(3, 0), .irq_flags = IRQF_TRIGGER_FALLING }; @@ -633,7 +659,6 @@ static const struct iio_chan_spec ad7173_temp_channel_template = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .address = AD7173_CH_ADDRESS(17, 18), .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), @@ -654,6 +679,7 @@ static int ad7173_of_parse_channel_config(struct iio_dev *indio_dev, struct device_node *chan_node, *child; struct iio_chan_spec *chan; unsigned int num_ext_channels = 0; + unsigned int *channel_ains; unsigned int num_channels = 0; unsigned int scan_index = 0; unsigned int chan_index = 0; @@ -669,16 +695,29 @@ static int ad7173_of_parse_channel_config(struct iio_dev *indio_dev, if (num_channels == 0) return 0; + if (num_channels > st->info->num_channels) { + dev_err(indio_dev->dev.parent, + "Number of defined channels exceeds the maximum number of supported channels.\n"); + return -EINVAL; + } + chan = devm_kcalloc(indio_dev->dev.parent, sizeof(*chan), num_channels, GFP_KERNEL); if (!chan) return -ENOMEM; + channel_ains = devm_kcalloc(indio_dev->dev.parent, sizeof(*channel_ains), + num_channels, GFP_KERNEL); + if (!channel_ains) + return -ENOMEM; + + st->channel_ains = channel_ains; indio_dev->channels = chan; indio_dev->num_channels = num_channels; if (st->info->has_temp) { *chan = ad7173_temp_channel_template; + channel_ains[scan_index] = AD7173_CH_ADDRESS(17, 18); chan++; scan_index++; } @@ -708,7 +747,8 @@ static int ad7173_of_parse_channel_config(struct iio_dev *indio_dev, *chan = ad7173_channel_template; - chan->address = AD7173_CH_ADDRESS(ain[0], ain[1]); + chan->address = scan_index; + channel_ains[scan_index] = AD7173_CH_ADDRESS(ain[0], ain[1]); chan->scan_index = scan_index; chan->channel = ain[0]; chan->channel2 = ain[1]; @@ -747,9 +787,8 @@ static int ad7173_probe(struct spi_device *spi) id = spi_get_device_id(spi); st->info = &ad7173_device_info[id->driver_data]; - ad_sd_init(&st->sd, indio_dev, spi, &ad7173_sigma_delta_info); - st->sd.num_slots = st->info->num_configs; + ad_sd_init(&st->sd, indio_dev, spi, &ad7173_sigma_delta_info); spi_set_drvdata(spi, indio_dev); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index f1e615bb159c2e..0dbc3de6bbc042 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -383,6 +383,10 @@ static void ad_sd_prepare_transfer_msg(struct iio_dev *indio_dev) else data_reg = AD_SD_REG_DATA; + /* Status word will be appended to the sample during transfer */ + if (sigma_delta->status_appended) + reg_size++; + BUG_ON(reg_size > 4); /* We store reg_size bytes samples in a 32 bit word. Keep the upper * reg_size bytes set to zero. @@ -411,6 +415,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) indio_dev->channels[i].address); if (ret) goto err_predisable; + sigma_delta->slots[slot] = indio_dev->channels[i].address; slot++; } @@ -419,9 +424,21 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) if (!sigma_delta->buf_data) return -ENOMEM; + sigma_delta->active_slots = slot; ad_sigma_delta_set_active_slots(sigma_delta, slot); sigma_delta->current_slot = 0; + /* + * Activation of append_status will cause incrementation of the reg_size + * in ad_sd_prepare_transfer_msg() and the transfer size will include + * the status byte. + */ + if (sigma_delta->active_slots > 1) { + ret = ad_sigma_delta_append_status(sigma_delta, true); + if (ret) + return ret; + } + spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; sigma_delta->keep_cs_asserted = true; @@ -472,6 +489,8 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) sigma_delta->keep_cs_asserted = false; ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + if (sigma_delta->status_appended) + ad_sigma_delta_append_status(sigma_delta, false); sigma_delta->bus_locked = false; return spi_bus_unlock(sigma_delta->spi->master); @@ -482,24 +501,58 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + unsigned int status_pos; unsigned int reg_size; int ret; - sigma_delta->current_slot++; - ret = spi_sync_locked(sigma_delta->spi, &sigma_delta->spi_msg); + + reg_size = sigma_delta->spi_transfer[1].len; + if (sigma_delta->status_appended) { + u8 converted_channel; + /* + * If status_appended is active, reg_size was incremented in + * ad_sd_prepare_transfer_msg(). + * + * The status byte will be the byte following the last + * sample byte. + */ + status_pos = reg_size - 1; + converted_channel = ((u8 *)sigma_delta->spi_transfer[1].rx_buf)[status_pos] & + sigma_delta->info->status_ch_mask; + if (converted_channel != sigma_delta->slots[sigma_delta->current_slot]) { + /* + * Desync occurred during continuous sampling of multiple channels. + * Drop this incomplete sample and start from first channel again. + */ + sigma_delta->current_slot = 0; + sigma_delta->spi_transfer[1].rx_buf = sigma_delta->buf_data; + sigma_delta->spi_transfer[1].rx_buf += 4 - reg_size; + goto irq_handled; + } + + /* + * Get rid of the status byte and move samples to the right to + * comply with "Keep the upper reg_size bytes set to zero". + */ + memmove(sigma_delta->spi_transfer[1].rx_buf + 1, sigma_delta->spi_transfer[1].rx_buf, + reg_size - 1); + ((u8 *)sigma_delta->spi_transfer[1].rx_buf)[0] = 0; + } + + sigma_delta->current_slot++; if (ret == 0 && sigma_delta->current_slot == sigma_delta->active_slots) { iio_push_to_buffers_with_timestamp(indio_dev, sigma_delta->buf_data, pf->timestamp); sigma_delta->current_slot = 0; sigma_delta->spi_transfer[1].rx_buf = sigma_delta->buf_data; - reg_size = sigma_delta->spi_transfer[1].len; sigma_delta->spi_transfer[1].rx_buf += 4 - reg_size; } else { sigma_delta->spi_transfer[1].rx_buf += indio_dev->channels[0].scan_type.storagebits / 8; } +irq_handled: iio_trigger_notify_done(indio_dev->trig); sigma_delta->irq_dis = false; enable_irq(sigma_delta->spi->irq); @@ -609,6 +662,11 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi if (spi_engine_offload_supported(sigma_delta->spi)) indio_dev->modes |= INDIO_BUFFER_HARDWARE; + sigma_delta->slots = devm_kcalloc(dev, sigma_delta->num_slots, + sizeof(*sigma_delta->slots), GFP_KERNEL); + if (!sigma_delta->slots) + return -ENOMEM; + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &ad_sd_trigger_handler, @@ -635,8 +693,12 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, { sigma_delta->spi = spi; sigma_delta->info = info; - sigma_delta->num_slots = 1; sigma_delta->active_slots = 1; + + /* If the field is unset, asume there can only be 1 slot. */ + if (!sigma_delta->num_slots) + sigma_delta->num_slots = 1; + iio_device_set_drvdata(indio_dev, sigma_delta); return 0; diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index d492408a24ce25..66806875102f9f 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -34,6 +34,7 @@ struct iio_dev; /** * struct ad_sigma_delta_info - Sigma Delta driver specific callbacks and options * @set_channel: Will be called to select the current channel, may be NULL. + * @append_status: Will be called to enable status append at the end of the sample, may be NULL. * @prepare_channel: Will be called to prepare and configure a channel, may be * NULL. * @set_mode: Will be called to select the current mode, may be NULL. @@ -42,6 +43,7 @@ struct iio_dev; * @has_registers: true if the device has writable and readable registers, false * if there is just one read-only sample data shift register. * @addr_shift: Shift of the register address in the communications register. + * @status_ch_mask: Mask for the channel number stored in status register. * @read_mask: Mask for the communications register having the read bit set. * @data_reg: Address of the data register, if 0 the default address of 0x3 will * be used. @@ -50,6 +52,7 @@ struct iio_dev; struct ad_sigma_delta_info { int (*set_channel)(struct ad_sigma_delta *, unsigned int slot, unsigned int channel); + int (*append_status)(struct ad_sigma_delta *, bool append); int (*prepare_channel)(struct ad_sigma_delta *, unsigned int slot, const struct iio_chan_spec *); int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode); @@ -57,6 +60,7 @@ struct ad_sigma_delta_info { bool has_registers; unsigned int addr_shift; unsigned int read_mask; + unsigned int status_ch_mask; unsigned int data_reg; unsigned long irq_flags; }; @@ -88,6 +92,9 @@ struct ad_sigma_delta { const struct ad_sigma_delta_info *info; unsigned int active_slots; unsigned int current_slot; + bool status_appended; + /* map slots to channels in order to know what to expect from devices */ + unsigned int *slots; struct spi_message spi_msg; struct spi_transfer spi_transfer[2]; @@ -122,6 +129,21 @@ static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd, return 0; } +static inline int ad_sigma_delta_append_status(struct ad_sigma_delta *sd, bool append) +{ + int ret; + + if (sd->info->append_status) { + ret = sd->info->append_status(sd, append); + if (ret < 0) + return ret; + + sd->status_appended = append; + } + + return 0; +} + static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd, unsigned int mode) {