Skip to content

Commit f1aa31e

Browse files
dlechnunojsa
authored andcommitted
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 <dlechner@baylibre.com> Reviewed-by: Nuno Sa <nuno.sa@analog.com> Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-3-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
1 parent d4adb69 commit f1aa31e

File tree

2 files changed

+92
-22
lines changed

2 files changed

+92
-22
lines changed

drivers/iio/industrialio-buffer.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,16 @@ static ssize_t iio_show_fixed_type(struct device *dev,
399399
struct device_attribute *attr,
400400
char *buf)
401401
{
402+
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
402403
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
403-
const struct iio_scan_type *scan_type = &this_attr->c->scan_type;
404-
u8 type = scan_type->endianness;
404+
const struct iio_scan_type *scan_type;
405+
u8 type;
406+
407+
scan_type = iio_get_current_scan_type(indio_dev, this_attr->c);
408+
if (IS_ERR(scan_type))
409+
return PTR_ERR(scan_type);
410+
411+
type = scan_type->endianness;
405412

406413
if (type == IIO_CPU) {
407414
#ifdef __LITTLE_ENDIAN
@@ -732,24 +739,20 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
732739
return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer));
733740
}
734741

735-
static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
736-
unsigned int scan_index)
742+
static int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
743+
unsigned int scan_index)
737744
{
738745
const struct iio_chan_spec *ch;
739-
const struct iio_scan_type *scan_type;
740746
unsigned int bytes;
741747

742748
ch = iio_find_channel_from_si(indio_dev, scan_index);
743-
scan_type = &ch->scan_type;
744-
bytes = scan_type->storagebits / 8;
745-
746-
if (scan_type->repeat > 1)
747-
bytes *= scan_type->repeat;
748-
749+
bytes = ch->scan_type.storagebits / 8;
750+
if (ch->scan_type.repeat > 1)
751+
bytes *= ch->scan_type.repeat;
749752
return bytes;
750753
}
751754

752-
static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
755+
static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
753756
{
754757
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
755758

@@ -767,13 +770,19 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
767770
for_each_set_bit(i, mask,
768771
indio_dev->masklength) {
769772
length = iio_storage_bytes_for_si(indio_dev, i);
773+
if (length < 0)
774+
return length;
775+
770776
bytes = ALIGN(bytes, length);
771777
bytes += length;
772778
largest = max(largest, length);
773779
}
774780

775781
if (timestamp) {
776782
length = iio_storage_bytes_for_timestamp(indio_dev);
783+
if (length < 0)
784+
return length;
785+
777786
bytes = ALIGN(bytes, length);
778787
bytes += length;
779788
largest = max(largest, length);
@@ -1052,14 +1061,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
10521061
indio_dev->masklength,
10531062
in_ind + 1);
10541063
while (in_ind != out_ind) {
1055-
length = iio_storage_bytes_for_si(indio_dev, in_ind);
1064+
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
1065+
if (ret < 0)
1066+
goto error_clear_mux_table;
1067+
1068+
length = ret;
10561069
/* Make sure we are aligned */
10571070
in_loc = roundup(in_loc, length) + length;
10581071
in_ind = find_next_bit(indio_dev->active_scan_mask,
10591072
indio_dev->masklength,
10601073
in_ind + 1);
10611074
}
1062-
length = iio_storage_bytes_for_si(indio_dev, in_ind);
1075+
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
1076+
if (ret < 0)
1077+
goto error_clear_mux_table;
1078+
1079+
length = ret;
10631080
out_loc = roundup(out_loc, length);
10641081
in_loc = roundup(in_loc, length);
10651082
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1070,7 +1087,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
10701087
}
10711088
/* Relies on scan_timestamp being last */
10721089
if (buffer->scan_timestamp) {
1073-
length = iio_storage_bytes_for_timestamp(indio_dev);
1090+
ret = iio_storage_bytes_for_timestamp(indio_dev);
1091+
if (ret < 0)
1092+
goto error_clear_mux_table;
1093+
1094+
length = ret;
10741095
out_loc = roundup(out_loc, length);
10751096
in_loc = roundup(in_loc, length);
10761097
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1899,16 +1920,14 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
18991920
if (channels[i].scan_index < 0)
19001921
continue;
19011922

1902-
scan_type = &channels[i].scan_type;
1903-
19041923
/* Verify that sample bits fit into storage */
19051924
if (scan_type->storagebits <
19061925
scan_type->realbits + scan_type->shift) {
19071926
dev_err(&indio_dev->dev,
19081927
"Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
1909-
i, scan_type->storagebits,
1910-
scan_type->realbits,
1911-
scan_type->shift);
1928+
i, channels[i].scan_type.storagebits,
1929+
channels[i].scan_type.realbits,
1930+
channels[i].scan_type.shift);
19121931
ret = -EINVAL;
19131932
goto error_cleanup_dynamic;
19141933
}

include/linux/iio/iio.h

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,13 @@ struct iio_scan_type {
204204
* @address: Driver specific identifier.
205205
* @scan_index: Monotonic index to give ordering in scans when read
206206
* from a buffer.
207-
* @scan_type: struct describing the scan type
207+
* @scan_type: struct describing the scan type - mutually exclusive
208+
* with ext_scan_type.
209+
* @ext_scan_type: Used in rare cases where there is more than one scan
210+
* format for a channel. When this is used, the flag
211+
* has_ext_scan_type must be set and the driver must
212+
* implement get_current_scan_type in struct iio_info.
213+
* @num_ext_scan_type: Number of elements in ext_scan_type.
208214
* @info_mask_separate: What information is to be exported that is specific to
209215
* this channel.
210216
* @info_mask_separate_available: What availability information is to be
@@ -245,14 +251,21 @@ struct iio_scan_type {
245251
* attributes but not for event codes.
246252
* @output: Channel is output.
247253
* @differential: Channel is differential.
254+
* @has_ext_scan_type: True if ext_scan_type is used instead of scan_type.
248255
*/
249256
struct iio_chan_spec {
250257
enum iio_chan_type type;
251258
int channel;
252259
int channel2;
253260
unsigned long address;
254261
int scan_index;
255-
struct iio_scan_type scan_type;
262+
union {
263+
struct iio_scan_type scan_type;
264+
struct {
265+
const struct iio_scan_type *ext_scan_type;
266+
unsigned int num_ext_scan_type;
267+
};
268+
};
256269
long info_mask_separate;
257270
long info_mask_separate_available;
258271
long info_mask_shared_by_type;
@@ -270,6 +283,7 @@ struct iio_chan_spec {
270283
unsigned indexed:1;
271284
unsigned output:1;
272285
unsigned differential:1;
286+
unsigned has_ext_scan_type:1;
273287
};
274288

275289

@@ -427,6 +441,9 @@ struct iio_trigger; /* forward declaration */
427441
* for better event identification.
428442
* @validate_trigger: function to validate the trigger when the
429443
* current trigger gets changed.
444+
* @get_current_scan_type: must be implemented by drivers that use ext_scan_type
445+
* in the channel spec to return the index of the currently
446+
* active ext_scan type for a channel.
430447
* @update_scan_mode: function to configure device and scan buffer when
431448
* channels have changed
432449
* @debugfs_reg_access: function to read or write register value of device
@@ -517,6 +534,8 @@ struct iio_info {
517534

518535
int (*validate_trigger)(struct iio_dev *indio_dev,
519536
struct iio_trigger *trig);
537+
int (*get_current_scan_type)(const struct iio_dev *indio_dev,
538+
const struct iio_chan_spec *chan);
520539
int (*update_scan_mode)(struct iio_dev *indio_dev,
521540
const unsigned long *scan_mask);
522541
int (*debugfs_reg_access)(struct iio_dev *indio_dev,
@@ -787,6 +806,38 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
787806
}
788807
#endif
789808

809+
/**
810+
* iio_get_current_scan_type - Get the current scan type for a channel
811+
* @indio_dev: the IIO device to get the scan type for
812+
* @chan: the channel to get the scan type for
813+
*
814+
* Most devices only have one scan type per channel and can just access it
815+
* directly without calling this function. Core IIO code and drivers that
816+
* implement ext_scan_type in the channel spec should use this function to
817+
* get the current scan type for a channel.
818+
*
819+
* Returns: the current scan type for the channel or error.
820+
*/
821+
static inline const struct iio_scan_type
822+
*iio_get_current_scan_type(const struct iio_dev *indio_dev,
823+
const struct iio_chan_spec *chan)
824+
{
825+
int ret;
826+
827+
if (chan->has_ext_scan_type) {
828+
ret = indio_dev->info->get_current_scan_type(indio_dev, chan);
829+
if (ret < 0)
830+
return ERR_PTR(ret);
831+
832+
if (ret >= chan->num_ext_scan_type)
833+
return ERR_PTR(-EINVAL);
834+
835+
return &chan->ext_scan_type[ret];
836+
}
837+
838+
return &chan->scan_type;
839+
}
840+
790841
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
791842

792843
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,

0 commit comments

Comments
 (0)