Skip to content

Commit c199ff2

Browse files
dlechjonathanns
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>
1 parent 263e011 commit c199ff2

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
@@ -203,7 +203,13 @@ struct iio_scan_type {
203203
* @address: Driver specific identifier.
204204
* @scan_index: Monotonic index to give ordering in scans when read
205205
* from a buffer.
206-
* @scan_type: struct describing the scan type
206+
* @scan_type: struct describing the scan type - mutually exclusive
207+
* with ext_scan_type.
208+
* @ext_scan_type: Used in rare cases where there is more than one scan
209+
* format for a channel. When this is used, the flag
210+
* has_ext_scan_type must be set and the driver must
211+
* implement get_current_scan_type in struct iio_info.
212+
* @num_ext_scan_type: Number of elements in ext_scan_type.
207213
* @info_mask_separate: What information is to be exported that is specific to
208214
* this channel.
209215
* @info_mask_separate_available: What availability information is to be
@@ -244,14 +250,21 @@ struct iio_scan_type {
244250
* attributes but not for event codes.
245251
* @output: Channel is output.
246252
* @differential: Channel is differential.
253+
* @has_ext_scan_type: True if ext_scan_type is used instead of scan_type.
247254
*/
248255
struct iio_chan_spec {
249256
enum iio_chan_type type;
250257
int channel;
251258
int channel2;
252259
unsigned long address;
253260
int scan_index;
254-
struct iio_scan_type scan_type;
261+
union {
262+
struct iio_scan_type scan_type;
263+
struct {
264+
const struct iio_scan_type *ext_scan_type;
265+
unsigned int num_ext_scan_type;
266+
};
267+
};
255268
long info_mask_separate;
256269
long info_mask_separate_available;
257270
long info_mask_shared_by_type;
@@ -269,6 +282,7 @@ struct iio_chan_spec {
269282
unsigned indexed:1;
270283
unsigned output:1;
271284
unsigned differential:1;
285+
unsigned has_ext_scan_type:1;
272286
};
273287

274288

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

517534
int (*validate_trigger)(struct iio_dev *indio_dev,
518535
struct iio_trigger *trig);
536+
int (*get_current_scan_type)(const struct iio_dev *indio_dev,
537+
const struct iio_chan_spec *chan);
519538
int (*update_scan_mode)(struct iio_dev *indio_dev,
520539
const unsigned long *scan_mask);
521540
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)
760779
}
761780
#endif
762781

782+
/**
783+
* iio_get_current_scan_type - Get the current scan type for a channel
784+
* @indio_dev: the IIO device to get the scan type for
785+
* @chan: the channel to get the scan type for
786+
*
787+
* Most devices only have one scan type per channel and can just access it
788+
* directly without calling this function. Core IIO code and drivers that
789+
* implement ext_scan_type in the channel spec should use this function to
790+
* get the current scan type for a channel.
791+
*
792+
* Returns: the current scan type for the channel or error.
793+
*/
794+
static inline const struct iio_scan_type
795+
*iio_get_current_scan_type(const struct iio_dev *indio_dev,
796+
const struct iio_chan_spec *chan)
797+
{
798+
int ret;
799+
800+
if (chan->has_ext_scan_type) {
801+
ret = indio_dev->info->get_current_scan_type(indio_dev, chan);
802+
if (ret < 0)
803+
return ERR_PTR(ret);
804+
805+
if (ret >= chan->num_ext_scan_type)
806+
return ERR_PTR(-EINVAL);
807+
808+
return &chan->ext_scan_type[ret];
809+
}
810+
811+
return &chan->scan_type;
812+
}
813+
763814
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
764815

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

0 commit comments

Comments
 (0)