Skip to content

Commit 6a10a30

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 <[email protected]> Reviewed-by: Nuno Sa <[email protected]> Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-3-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron <[email protected]>
1 parent f66f4e1 commit 6a10a30

File tree

2 files changed

+133
-23
lines changed

2 files changed

+133
-23
lines changed

drivers/iio/industrialio-buffer.c

Lines changed: 80 additions & 21 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,15 +739,18 @@ 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;
739746
const struct iio_scan_type *scan_type;
740747
unsigned int bytes;
741748

742749
ch = iio_find_channel_from_si(indio_dev, scan_index);
743-
scan_type = &ch->scan_type;
750+
scan_type = iio_get_current_scan_type(indio_dev, ch);
751+
if (IS_ERR(scan_type))
752+
return PTR_ERR(scan_type);
753+
744754
bytes = scan_type->storagebits / 8;
745755

746756
if (scan_type->repeat > 1)
@@ -749,7 +759,7 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
749759
return bytes;
750760
}
751761

752-
static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
762+
static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
753763
{
754764
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
755765

@@ -767,13 +777,19 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
767777
for_each_set_bit(i, mask,
768778
indio_dev->masklength) {
769779
length = iio_storage_bytes_for_si(indio_dev, i);
780+
if (length < 0)
781+
return length;
782+
770783
bytes = ALIGN(bytes, length);
771784
bytes += length;
772785
largest = max(largest, length);
773786
}
774787

775788
if (timestamp) {
776789
length = iio_storage_bytes_for_timestamp(indio_dev);
790+
if (length < 0)
791+
return length;
792+
777793
bytes = ALIGN(bytes, length);
778794
bytes += length;
779795
largest = max(largest, length);
@@ -1052,14 +1068,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
10521068
indio_dev->masklength,
10531069
in_ind + 1);
10541070
while (in_ind != out_ind) {
1055-
length = iio_storage_bytes_for_si(indio_dev, in_ind);
1071+
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
1072+
if (ret < 0)
1073+
goto error_clear_mux_table;
1074+
1075+
length = ret;
10561076
/* Make sure we are aligned */
10571077
in_loc = roundup(in_loc, length) + length;
10581078
in_ind = find_next_bit(indio_dev->active_scan_mask,
10591079
indio_dev->masklength,
10601080
in_ind + 1);
10611081
}
1062-
length = iio_storage_bytes_for_si(indio_dev, in_ind);
1082+
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
1083+
if (ret < 0)
1084+
goto error_clear_mux_table;
1085+
1086+
length = ret;
10631087
out_loc = roundup(out_loc, length);
10641088
in_loc = roundup(in_loc, length);
10651089
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,
10701094
}
10711095
/* Relies on scan_timestamp being last */
10721096
if (buffer->scan_timestamp) {
1073-
length = iio_storage_bytes_for_timestamp(indio_dev);
1097+
ret = iio_storage_bytes_for_timestamp(indio_dev);
1098+
if (ret < 0)
1099+
goto error_clear_mux_table;
1100+
1101+
length = ret;
10741102
out_loc = roundup(out_loc, length);
10751103
in_loc = roundup(in_loc, length);
10761104
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
18721900
}
18731901
}
18741902

1903+
static int iio_channel_validate_scan_type(struct device *dev, int ch,
1904+
const struct iio_scan_type *scan_type)
1905+
{
1906+
/* Verify that sample bits fit into storage */
1907+
if (scan_type->storagebits < scan_type->realbits + scan_type->shift) {
1908+
dev_err(dev,
1909+
"Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
1910+
ch, scan_type->storagebits,
1911+
scan_type->realbits,
1912+
scan_type->shift);
1913+
return -EINVAL;
1914+
}
1915+
1916+
return 0;
1917+
}
1918+
18751919
static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
18761920
struct iio_dev *indio_dev,
18771921
int index)
@@ -1899,18 +1943,33 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
18991943
if (channels[i].scan_index < 0)
19001944
continue;
19011945

1902-
scan_type = &channels[i].scan_type;
1903-
1904-
/* Verify that sample bits fit into storage */
1905-
if (scan_type->storagebits <
1906-
scan_type->realbits + scan_type->shift) {
1907-
dev_err(&indio_dev->dev,
1908-
"Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
1909-
i, scan_type->storagebits,
1910-
scan_type->realbits,
1911-
scan_type->shift);
1912-
ret = -EINVAL;
1913-
goto error_cleanup_dynamic;
1946+
if (channels[i].has_ext_scan_type) {
1947+
int j;
1948+
1949+
/*
1950+
* get_current_scan_type is required when using
1951+
* extended scan types.
1952+
*/
1953+
if (!indio_dev->info->get_current_scan_type) {
1954+
ret = -EINVAL;
1955+
goto error_cleanup_dynamic;
1956+
}
1957+
1958+
for (j = 0; j < channels[i].num_ext_scan_type; j++) {
1959+
scan_type = &channels[i].ext_scan_type[j];
1960+
1961+
ret = iio_channel_validate_scan_type(
1962+
&indio_dev->dev, i, scan_type);
1963+
if (ret)
1964+
goto error_cleanup_dynamic;
1965+
}
1966+
} else {
1967+
scan_type = &channels[i].scan_type;
1968+
1969+
ret = iio_channel_validate_scan_type(
1970+
&indio_dev->dev, i, scan_type);
1971+
if (ret)
1972+
goto error_cleanup_dynamic;
19141973
}
19151974

19161975
ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,

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
/**
791842
* iio_get_masklength - Get length of the channels mask
792843
* @indio_dev: the IIO device to get the masklength for

0 commit comments

Comments
 (0)