From c28cc7e92b937af4c0d56855f71024483f80ecf6 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:08 -0500 Subject: [PATCH 1/4] iio: introduce struct iio_scan_type This gives the channel scan_type a named type so that it can be used to simplify code in later commits. Signed-off-by: David Lechner --- include/linux/iio/iio.h | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e7da2aa6f1c3d5..88a1532c4876b4 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -172,6 +172,27 @@ struct iio_event_spec { unsigned long mask_shared_by_all; }; +/** + * struct iio_scan_type - specification for channel data format in buffer + * @sign: 's' or 'u' to specify signed or unsigned + * @realbits: Number of valid bits of data + * @storagebits: Realbits + padding + * @shift: Shift right by this before masking out realbits. + * @repeat: Number of times real/storage bits repeats. When the + * repeat element is more than 1, then the type element in + * sysfs will show a repeat value. Otherwise, the number + * of repetitions is omitted. + * @endianness: little or big endian + */ +struct iio_scan_type { + char sign; + u8 realbits; + u8 storagebits; + u8 shift; + u8 repeat; + enum iio_endian endianness; +}; + /** * struct iio_chan_spec - specification of a single channel * @type: What type of measurement is the channel making. @@ -183,17 +204,6 @@ struct iio_event_spec { * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. * @scan_type: struct describing the scan type - * @scan_type.sign: 's' or 'u' to specify signed or unsigned - * @scan_type.realbits: Number of valid bits of data - * @scan_type.storagebits: Realbits + padding - * @scan_type.shift: Shift right by this before masking out - * realbits. - * @scan_type.repeat: Number of times real/storage bits repeats. - * When the repeat element is more than 1, then - * the type element in sysfs will show a repeat - * value. Otherwise, the number of repetitions - * is omitted. - * @scan_type.endianness: little or big endian * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be @@ -241,14 +251,7 @@ struct iio_chan_spec { int channel2; unsigned long address; int scan_index; - struct { - char sign; - u8 realbits; - u8 storagebits; - u8 shift; - u8 repeat; - enum iio_endian endianness; - } scan_type; + struct iio_scan_type scan_type; long info_mask_separate; long info_mask_separate_available; long info_mask_shared_by_type; From 116bf07221e86c1c46ae39ade60fbd8e86a70ff4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:09 -0500 Subject: [PATCH 2/4] iio: buffer: use struct iio_scan_type to simplify code By using struct iio_scan_type, we can simplify the code by removing lots of duplicate pointer dereferences. This make the code a bit easier to read. This also prepares for a future where channels may have more than one scan_type. Signed-off-by: David Lechner --- drivers/iio/industrialio-buffer.c | 48 ++++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 5d656c131f6a78..9ae096c240cb86 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -400,7 +400,8 @@ static ssize_t iio_show_fixed_type(struct device *dev, char *buf) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 type = this_attr->c->scan_type.endianness; + const struct iio_scan_type *scan_type = &this_attr->c->scan_type; + u8 type = scan_type->endianness; if (type == IIO_CPU) { #ifdef __LITTLE_ENDIAN @@ -409,21 +410,21 @@ static ssize_t iio_show_fixed_type(struct device *dev, type = IIO_BE; #endif } - if (this_attr->c->scan_type.repeat > 1) + if (scan_type->repeat > 1) return sysfs_emit(buf, "%s:%c%d/%dX%d>>%u\n", iio_endian_prefix[type], - this_attr->c->scan_type.sign, - this_attr->c->scan_type.realbits, - this_attr->c->scan_type.storagebits, - this_attr->c->scan_type.repeat, - this_attr->c->scan_type.shift); + scan_type->sign, + scan_type->realbits, + scan_type->storagebits, + scan_type->repeat, + scan_type->shift); else return sysfs_emit(buf, "%s:%c%d/%d>>%u\n", iio_endian_prefix[type], - this_attr->c->scan_type.sign, - this_attr->c->scan_type.realbits, - this_attr->c->scan_type.storagebits, - this_attr->c->scan_type.shift); + scan_type->sign, + scan_type->realbits, + scan_type->storagebits, + scan_type->shift); } static ssize_t iio_scan_el_show(struct device *dev, @@ -735,12 +736,16 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, unsigned int scan_index) { const struct iio_chan_spec *ch; + const struct iio_scan_type *scan_type; unsigned int bytes; ch = iio_find_channel_from_si(indio_dev, scan_index); - bytes = ch->scan_type.storagebits / 8; - if (ch->scan_type.repeat > 1) - bytes *= ch->scan_type.repeat; + scan_type = &ch->scan_type; + bytes = scan_type->storagebits / 8; + + if (scan_type->repeat > 1) + bytes *= scan_type->repeat; + return bytes; } @@ -1889,18 +1894,21 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, if (channels) { /* new magic */ for (i = 0; i < indio_dev->num_channels; i++) { + const struct iio_scan_type *scan_type; + if (channels[i].scan_index < 0) continue; + scan_type = &channels[i].scan_type; + /* Verify that sample bits fit into storage */ - if (channels[i].scan_type.storagebits < - channels[i].scan_type.realbits + - channels[i].scan_type.shift) { + if (scan_type->storagebits < + scan_type->realbits + scan_type->shift) { dev_err(&indio_dev->dev, "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", - i, channels[i].scan_type.storagebits, - channels[i].scan_type.realbits, - channels[i].scan_type.shift); + i, scan_type->storagebits, + scan_type->realbits, + scan_type->shift); ret = -EINVAL; goto error_cleanup_dynamic; } From 264db3dfa78a87abc48f6a76de86f413948ad1f5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:10 -0500 Subject: [PATCH 3/4] iio: add support for multiple scan types per channel This adds new fields to the iio_channel structure to support multiple scan types per channel. This is useful for devices that support multiple resolution modes or other modes that require different data formats of the raw data. To make use of this, drivers need to implement the new callback get_current_scan_type() to resolve the scan type for a given channel based on the current state of the driver. There is a new scan_type_ext field in the iio_channel structure that should be used to store the scan types for any channel that has more than one. There is also a new flag has_ext_scan_type that acts as a type discriminator for the scan_type/ext_scan_type union. A union is used so that we don't grow the size of the iio_channel structure and also makes it clear that scan_type and ext_scan_type are mutually exclusive. The buffer code is the only code in the IIO core code that is using the scan_type field. This patch updates the buffer code to use the new iio_channel_validate_scan_type() function to ensure it is returning the correct scan type for the current state of the device when reading the sysfs attributes. The buffer validation code is also update to validate any additional scan types that are set in the scan_type_ext field. Part of that code is refactored to a new function to avoid duplication. Some userspace tools may need to be updated to re-read the scan type after writing any other attribute. During testing, we noticed that we had to restart iiod to get it to re-read the scan type after enabling oversampling on the ad7380 driver. Signed-off-by: David Lechner --- drivers/iio/industrialio-buffer.c | 101 +++++++++++++++++++++++------- include/linux/iio/iio.h | 55 +++++++++++++++- 2 files changed, 133 insertions(+), 23 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 9ae096c240cb86..8eb442bce68160 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -399,9 +399,16 @@ static ssize_t iio_show_fixed_type(struct device *dev, struct device_attribute *attr, char *buf) { + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - const struct iio_scan_type *scan_type = &this_attr->c->scan_type; - u8 type = scan_type->endianness; + const struct iio_scan_type *scan_type; + u8 type; + + scan_type = iio_get_current_scan_type(indio_dev, this_attr->c); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + type = scan_type->endianness; if (type == IIO_CPU) { #ifdef __LITTLE_ENDIAN @@ -732,15 +739,18 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer)); } -static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, - unsigned int scan_index) +static int iio_storage_bytes_for_si(struct iio_dev *indio_dev, + unsigned int scan_index) { const struct iio_chan_spec *ch; const struct iio_scan_type *scan_type; unsigned int bytes; ch = iio_find_channel_from_si(indio_dev, scan_index); - scan_type = &ch->scan_type; + scan_type = iio_get_current_scan_type(indio_dev, ch); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + bytes = scan_type->storagebits / 8; if (scan_type->repeat > 1) @@ -749,7 +759,7 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, return bytes; } -static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) +static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); @@ -767,6 +777,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, for_each_set_bit(i, mask, indio_dev->masklength) { length = iio_storage_bytes_for_si(indio_dev, i); + if (length < 0) + return length; + bytes = ALIGN(bytes, length); bytes += length; largest = max(largest, length); @@ -774,6 +787,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, if (timestamp) { length = iio_storage_bytes_for_timestamp(indio_dev); + if (length < 0) + return length; + bytes = ALIGN(bytes, length); bytes += length; largest = max(largest, length); @@ -1052,14 +1068,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, indio_dev->masklength, in_ind + 1); while (in_ind != out_ind) { - length = iio_storage_bytes_for_si(indio_dev, in_ind); + ret = iio_storage_bytes_for_si(indio_dev, in_ind); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; /* Make sure we are aligned */ in_loc = roundup(in_loc, length) + length; in_ind = find_next_bit(indio_dev->active_scan_mask, indio_dev->masklength, in_ind + 1); } - length = iio_storage_bytes_for_si(indio_dev, in_ind); + ret = iio_storage_bytes_for_si(indio_dev, in_ind); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; out_loc = roundup(out_loc, length); in_loc = roundup(in_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); @@ -1070,7 +1094,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, } /* Relies on scan_timestamp being last */ if (buffer->scan_timestamp) { - length = iio_storage_bytes_for_timestamp(indio_dev); + ret = iio_storage_bytes_for_timestamp(indio_dev); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; out_loc = roundup(out_loc, length); in_loc = roundup(in_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); @@ -1872,6 +1900,22 @@ static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp } } +static int iio_channel_validate_scan_type(struct device *dev, int ch, + const struct iio_scan_type *scan_type) +{ + /* Verify that sample bits fit into storage */ + if (scan_type->storagebits < scan_type->realbits + scan_type->shift) { + dev_err(dev, + "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", + ch, scan_type->storagebits, + scan_type->realbits, + scan_type->shift); + return -EINVAL; + } + + return 0; +} + static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, struct iio_dev *indio_dev, int index) @@ -1899,18 +1943,33 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, if (channels[i].scan_index < 0) continue; - scan_type = &channels[i].scan_type; - - /* Verify that sample bits fit into storage */ - if (scan_type->storagebits < - scan_type->realbits + scan_type->shift) { - dev_err(&indio_dev->dev, - "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", - i, scan_type->storagebits, - scan_type->realbits, - scan_type->shift); - ret = -EINVAL; - goto error_cleanup_dynamic; + if (channels[i].has_ext_scan_type) { + int j; + + /* + * get_current_scan_type is required when using + * extended scan types. + */ + if (!indio_dev->info->get_current_scan_type) { + ret = -EINVAL; + goto error_cleanup_dynamic; + } + + for (j = 0; j < channels[i].num_ext_scan_type; j++) { + scan_type = &channels[i].ext_scan_type[j]; + + ret = iio_channel_validate_scan_type( + &indio_dev->dev, i, scan_type); + if (ret) + goto error_cleanup_dynamic; + } + } else { + scan_type = &channels[i].scan_type; + + ret = iio_channel_validate_scan_type( + &indio_dev->dev, i, scan_type); + if (ret) + goto error_cleanup_dynamic; } ret = iio_buffer_add_channel_sysfs(indio_dev, buffer, diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 88a1532c4876b4..50547953a13a8f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -203,7 +203,13 @@ struct iio_scan_type { * @address: Driver specific identifier. * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. - * @scan_type: struct describing the scan type + * @scan_type: struct describing the scan type - mutually exclusive + * with ext_scan_type. + * @ext_scan_type: Used in rare cases where there is more than one scan + * format for a channel. When this is used, the flag + * has_ext_scan_type must be set and the driver must + * implement get_current_scan_type in struct iio_info. + * @num_ext_scan_type: Number of elements in ext_scan_type. * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be @@ -244,6 +250,7 @@ struct iio_scan_type { * attributes but not for event codes. * @output: Channel is output. * @differential: Channel is differential. + * @has_ext_scan_type: True if ext_scan_type is used instead of scan_type. */ struct iio_chan_spec { enum iio_chan_type type; @@ -251,7 +258,13 @@ struct iio_chan_spec { int channel2; unsigned long address; int scan_index; - struct iio_scan_type scan_type; + union { + struct iio_scan_type scan_type; + struct { + const struct iio_scan_type *ext_scan_type; + unsigned int num_ext_scan_type; + }; + }; long info_mask_separate; long info_mask_separate_available; long info_mask_shared_by_type; @@ -269,6 +282,7 @@ struct iio_chan_spec { unsigned indexed:1; unsigned output:1; unsigned differential:1; + unsigned has_ext_scan_type:1; }; @@ -426,6 +440,9 @@ struct iio_trigger; /* forward declaration */ * for better event identification. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. + * @get_current_scan_type: must be implemented by drivers that use ext_scan_type + * in the channel spec to return the index of the currently + * active ext_scan type for a channel. * @update_scan_mode: function to configure device and scan buffer when * channels have changed * @debugfs_reg_access: function to read or write register value of device @@ -516,6 +533,8 @@ struct iio_info { int (*validate_trigger)(struct iio_dev *indio_dev, struct iio_trigger *trig); + int (*get_current_scan_type)(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan); int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask); int (*debugfs_reg_access)(struct iio_dev *indio_dev, @@ -760,6 +779,38 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) } #endif +/** + * iio_get_current_scan_type - Get the current scan type for a channel + * @indio_dev: the IIO device to get the scan type for + * @chan: the channel to get the scan type for + * + * Most devices only have one scan type per channel and can just access it + * directly without calling this function. Core IIO code and drivers that + * implement ext_scan_type in the channel spec should use this function to + * get the current scan type for a channel. + * + * Returns: the current scan type for the channel or error. + */ +static inline const struct iio_scan_type +*iio_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + int ret; + + if (chan->has_ext_scan_type) { + ret = indio_dev->info->get_current_scan_type(indio_dev, chan); + if (ret < 0) + return ERR_PTR(ret); + + if (ret >= chan->num_ext_scan_type) + return ERR_PTR(-EINVAL); + + return &chan->ext_scan_type[ret]; + } + + return &chan->scan_type; +} + ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, From 0bfc867110e2c94b8562a495998dd4f88f2152de Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Thu, 12 Sep 2024 18:52:58 -0300 Subject: [PATCH 4/4] iio: adc: ad4630: Add scan_types to read ADC common mode bits AD4030, AD4630, ADAQ4224, and similar devices can append an 8-bit code representing the input common-mode voltage to the 16-bit or 24-bit ADC conversion output code. Those 8-bit common mode code come after the conversion bits in the same SPI transfer. Thus, when common-mode output is enabled, every conversion brings common mode bits and common mode bits can only be read by doing an ADC conversion. Because ADC conversion bits and common mode bits are put together into buffer scan elements, user space applications can't properly handle data from IIO buffers since it only has info about one data element (either ADC conversion or common mode bits). The number of shift bits and the amount of realbits are different for when common-mode output is disabled and for when it's enabled. Add iio_scan_type structs to tell user space different parameters for element shift and realbits so applications can handle buffer elements properly when common mode bits are enabled. Signed-off-by: Marcelo Schmitt --- drivers/iio/adc/ad4630.c | 243 +++++++++++++++++++++++++++++++++++---- 1 file changed, 222 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ad4630.c b/drivers/iio/adc/ad4630.c index 540866a64fea0c..43a3b48d237aa0 100644 --- a/drivers/iio/adc/ad4630.c +++ b/drivers/iio/adc/ad4630.c @@ -152,6 +152,12 @@ enum { AD4630_MAX_PGA, }; +enum ad4630_scan_type { + AD4630_SCAN_TYPE_NORMAL, + AD4630_SCAN_TYPE_COMMON_MODE, + AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE, +}; + /* * Gains computed as fractions of 1000 so they can be expressed by integers. */ @@ -202,6 +208,7 @@ struct ad4630_state { int scale_tbl[ARRAY_SIZE(ad4630_gains)][2]; unsigned int out_data; unsigned int max_rate; + enum ad4630_scan_type current_scan_type; /* offload sampling spi message */ struct spi_transfer offload_xfer; @@ -317,6 +324,7 @@ static int ad4630_read_raw(struct iio_dev *indio_dev, int *val2, long info) { struct ad4630_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type = iio_get_current_scan_type(indio_dev, chan); unsigned int temp; int ret; @@ -331,7 +339,7 @@ static int ad4630_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_NANO; } *val = (st->vref * 2) / 1000; - *val2 = chan->scan_type.realbits; + *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_CALIBSCALE: ret = ad4630_get_chan_gain(indio_dev, chan->channel, &temp); @@ -456,12 +464,17 @@ static int ad4630_set_chan_offset(struct iio_dev *indio_dev, int ch, int offset) return ret; } -static void ad4630_fill_scale_tbl(struct ad4630_state *st) +static void ad4630_fill_scale_tbl(struct iio_dev *indio_dev, + struct ad4630_state *st) { + const struct iio_scan_type *scan_type; int val, val2, tmp0, tmp1, i; u64 tmp2; - val2 = st->chip->modes[st->out_data].channels->scan_type.realbits; + scan_type = iio_get_current_scan_type(indio_dev, + st->chip->modes[st->out_data].channels); + + val2 = scan_type->realbits; for (i = 0; i < ARRAY_SIZE(ad4630_gains); i++) { val = (st->vref * 2) / 1000; /* Multiply by MILLI here to avoid losing precision */ @@ -571,14 +584,27 @@ static int ad4630_write_raw(struct iio_dev *indio_dev, int val2, long info) { struct ad4630_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; + enum ad4630_scan_type cur_scan_type; int gain_idx; switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: return ad4630_set_sampling_freq(indio_dev, val); case IIO_CHAN_INFO_SCALE: + /* + * Common mode and normal + common mode scan types declare + * different amount of realbits. Though, to get to the scale + * factor for converting ADC output codes to voltage units only + * the ADC precision bits matter. Thus, use normal scan_type + * realbits to calcalte scale related parameters. + */ + cur_scan_type = st->current_scan_type; + st->current_scan_type = AD4630_SCAN_TYPE_NORMAL; + scan_type = iio_get_current_scan_type(indio_dev, chan); gain_idx = ad4630_calc_pga_gain(val, val2, st->vref, - chan->scan_type.realbits); + scan_type->realbits); + st->current_scan_type = cur_scan_type; return ad4630_set_pga_gain(indio_dev, gain_idx); case IIO_CHAN_INFO_CALIBSCALE: return ad4630_set_chan_gain(indio_dev, chan->channel, val, @@ -759,6 +785,32 @@ static int ad4630_buffer_postdisable(struct iio_dev *indio_dev) return ret; } +static int ad4630_set_scan_type(struct iio_dev *dev, + const struct iio_chan_spec *chan, + unsigned int scan_type) +{ + struct ad4630_state *st = iio_priv(dev); + int ret; + + ret = iio_device_claim_direct_mode(dev); + if (ret) + return ret; + + if (chan->has_ext_scan_type) + st->current_scan_type = scan_type; + + iio_device_release_direct_mode(dev); + return 0; +} + +static int ad4630_get_scan_type(struct iio_dev *dev, + const struct iio_chan_spec *chan) +{ + const struct ad4630_state *st = iio_priv(dev); + + return st->current_scan_type; +} + static const char *const ad4630_average_modes[] = { "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "65536" @@ -779,6 +831,25 @@ static const struct iio_chan_spec_ext_info ad4630_ext_info[] = { {} }; +static const char *const ad4630_scan_types[] = { + "conversion_data", "common_mode_data", "conversion_plus_common_mode_data" +}; + +static const struct iio_enum ad4630_scan_type_enum = { + .items = ad4630_scan_types, + .num_items = ARRAY_SIZE(ad4630_scan_types), + .set = ad4630_set_scan_type, + .get = ad4630_get_scan_type, +}; + +static const struct iio_chan_spec_ext_info ad4630_com_ext_info[] = { + IIO_ENUM("scan_type", IIO_SHARED_BY_TYPE, + &ad4630_scan_type_enum), + IIO_ENUM_AVAILABLE("scan_type", IIO_SHARED_BY_TYPE, + &ad4630_scan_type_enum), + {} +}; + #define AD4630_CHAN(_idx, _msk_avail, _storage, _real, _shift, _info) { \ .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ @@ -798,6 +869,114 @@ static const struct iio_chan_spec_ext_info ad4630_ext_info[] = { }, \ } +#define AD4630_COM_CHAN(_idx, _msk_avail, _storage, _real, _shift, _count, _info) {\ + .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_separate_available = _msk_avail, \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _idx, \ + .scan_index = _idx, \ + .ext_info = ad4630_com_ext_info, \ + .has_ext_scan_type = 1, \ + .ext_scan_type = ad4630_scan_type_##_real##_count, \ + .num_ext_scan_type = ARRAY_SIZE(ad4630_scan_type_##_real##_count),\ +} + +/* + * IIO correctly sign-extend buffer data elements to a twos-complement + * signed number if their scan_type is set to signed. However, if common mode + * data bits are together with ADC conversion bits, sign extend will also affect + * common mode bits. To avoid that, set AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE + * scan_types to unsigned. This will have the side effect of applications having + * to sign-extend ADC conversion data themselves, though. + */ +static const struct iio_scan_type ad4630_scan_type_16_dual[] = { + [AD4630_SCAN_TYPE_NORMAL] = { + .sign = 's', + .storagebits = 64, + .realbits = 16, + .shift = 8, + }, + [AD4630_SCAN_TYPE_COMMON_MODE] = { + .sign = 'u', + .storagebits = 64, + .realbits = 8, + .shift = 0, + }, + [AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE] = { + .sign = 'u', + .storagebits = 64, + .realbits = 32, + .shift = 0, + }, +}; + +static const struct iio_scan_type ad4630_scan_type_24_dual[] = { + [AD4630_SCAN_TYPE_NORMAL] = { + .sign = 's', + .storagebits = 64, + .realbits = 24, + .shift = 8, + }, + [AD4630_SCAN_TYPE_COMMON_MODE] = { + .sign = 'u', + .storagebits = 64, + .realbits = 8, + .shift = 0, + }, + [AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE] = { + .sign = 'u', + .storagebits = 64, + .realbits = 32, + .shift = 0, + }, +}; + +static const struct iio_scan_type ad4630_scan_type_16_single[] = { + [AD4630_SCAN_TYPE_NORMAL] = { + .sign = 's', + .storagebits = 32, + .realbits = 16, + .shift = 8, + }, + [AD4630_SCAN_TYPE_COMMON_MODE] = { + .sign = 'u', + .storagebits = 32, + .realbits = 8, + .shift = 0, + }, + [AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE] = { + .sign = 'u', + .storagebits = 32, + .realbits = 24, + .shift = 0, + }, +}; + +static const struct iio_scan_type ad4630_scan_type_24_single[] = { + [AD4630_SCAN_TYPE_NORMAL] = { + .sign = 's', + .storagebits = 32, + .realbits = 24, + .shift = 8, + }, + [AD4630_SCAN_TYPE_COMMON_MODE] = { + .sign = 'u', + .storagebits = 32, + .realbits = 8, + .shift = 0, + }, + [AD4630_SCAN_TYPE_NORMAL_AND_COMMON_MODE] = { + .sign = 'u', + .storagebits = 32, + .realbits = 32, + .shift = 0, + }, +}; + /* * We need the sample size to be 64 bytes when both channels are enabled as the * HW will always fill in the DMA bus which is 64bits. If we had just 16 bits @@ -815,13 +994,15 @@ static const struct ad4630_out_mode ad4030_24_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, AD4630_CHAN_INFO_NONE, 64, 16, 8, NULL), + AD4630_COM_CHAN(0, AD4630_CHAN_INFO_NONE, 64, 16, 8, + _dual, NULL), }, .data_width = 24, }, [AD4630_24_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, AD4630_CHAN_INFO_NONE, 64, 24, 8, NULL), + AD4630_COM_CHAN(0, AD4630_CHAN_INFO_NONE, 64, 24, 8, + _dual, NULL), }, .data_width = 32, }, @@ -844,8 +1025,10 @@ static const struct ad4630_out_mode ad4630_16_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 16, 8, NULL), - AD4630_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 16, 8, NULL), + AD4630_COM_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 16, 8, + _single, NULL), + AD4630_COM_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 16, 8, + _single, NULL), }, .data_width = 24, }, @@ -870,15 +1053,19 @@ static const struct ad4630_out_mode ad4630_24_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 16, 8, NULL), - AD4630_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 16, 8, NULL), + AD4630_COM_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 16, 8, + _single, NULL), + AD4630_COM_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 16, 8, + _single, NULL), }, .data_width = 24, }, [AD4630_24_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 24, 8, NULL), - AD4630_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 24, 8, NULL), + AD4630_COM_CHAN(0, AD4630_CHAN_INFO_NONE, 32, 24, 8, + _single, NULL), + AD4630_COM_CHAN(1, AD4630_CHAN_INFO_NONE, 32, 24, 8, + _single, NULL), }, .data_width = 32, }, @@ -902,7 +1089,8 @@ static const struct ad4630_out_mode adaq4216_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, NULL), + AD4630_COM_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, + _dual, NULL), }, .data_width = 24, }, @@ -923,7 +1111,8 @@ static const struct ad4630_out_mode adaq4220_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, NULL), + AD4630_COM_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, + _dual, NULL), }, .data_width = 24, }, @@ -944,13 +1133,15 @@ static const struct ad4630_out_mode adaq4224_modes[] = { }, [AD4630_16_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, NULL), + AD4630_COM_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, + _dual, NULL), }, .data_width = 24, }, [AD4630_24_DIFF_8_COM] = { .channels = { - AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 24, 8, NULL), + AD4630_COM_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 24, 8, + _dual, NULL), }, .data_width = 32, }, @@ -1323,12 +1514,21 @@ static int ad4630_config(struct ad4630_state *st) return ret; st->max_rate = AD4630_MAX_RATE; + st->current_scan_type = AD4630_SCAN_TYPE_NORMAL; ad4630_prepare_spi_sampling_msg(st, clock_mode, lane_mode, data_rate); return 0; } +static int ad4630_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad4630_state *st = iio_priv(indio_dev); + + return st->current_scan_type; +} + static const struct iio_buffer_setup_ops ad4630_buffer_setup_ops = { .preenable = &ad4630_buffer_preenable, .postdisable = &ad4630_buffer_postdisable, @@ -1339,6 +1539,7 @@ static const struct iio_info ad4630_info = { .read_avail = &ad4630_read_avail, .write_raw = &ad4630_write_raw, .write_raw_get_fmt = &ad4630_write_raw_get_fmt, + .get_current_scan_type = &ad4630_get_current_scan_type, .debugfs_reg_access = &ad4630_reg_access, }; @@ -1520,11 +1721,6 @@ static int ad4630_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, ret, "Config failed: %d\n", ret); - if (st->pga_gpios) { - ad4630_fill_scale_tbl(st); - ad4630_set_pga_gain(indio_dev, 0); - } - /* * Due to a hardware bug in some chips when using average mode zero * (no averaging), set default averaging mode to 2 samples. @@ -1546,6 +1742,11 @@ static int ad4630_probe(struct spi_device *spi) indio_dev->available_scan_masks = st->chip->available_masks; indio_dev->setup_ops = &ad4630_buffer_setup_ops; + if (st->pga_gpios) { + ad4630_fill_scale_tbl(indio_dev, st); + ad4630_set_pga_gain(indio_dev, 0); + } + ret = devm_iio_dmaengine_buffer_setup(dev, indio_dev, "rx", IIO_BUFFER_DIRECTION_IN); if (ret)