iio: Add callback to check whether a scan mask is valid
This is useful for cases where the number of valid scan masks grows exponentially, but it is rather easy to check whether a mask is valid or not programmatically. An example of such a case is a device with multiple ADCs where each ADC has a upstream MUX, which allows to select from a number of physical channels. +-------+ +-------+ | | | | --- Channel 1 | ADC 1 |---| MUX 1 | --- ... | | | | --- Channel M +-------+ +-------+ . . . . . . . . . +-------+ +-------+ | | | | --- Channel M * N + 1 | ADC N |---| MUX N | --- ... | | | | --- Channel M * N + M +-------+ +-------+ The number of necessary scan masks for this case is (M+1)**N - 1, on the other hand it is easy to check whether subsets for each ADC of the scanmask have only one bit set. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
c732a24c5a
commit
939546d1a9
|
@ -570,6 +570,15 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iio_sw_buffer_preenable);
|
EXPORT_SYMBOL(iio_sw_buffer_preenable);
|
||||||
|
|
||||||
|
static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
|
||||||
|
const unsigned long *mask)
|
||||||
|
{
|
||||||
|
if (!indio_dev->setup_ops->validate_scan_mask)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iio_scan_mask_set() - set particular bit in the scan mask
|
* iio_scan_mask_set() - set particular bit in the scan mask
|
||||||
* @buffer: the buffer whose scan mask we are interested in
|
* @buffer: the buffer whose scan mask we are interested in
|
||||||
|
@ -589,27 +598,31 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (!indio_dev->masklength) {
|
if (!indio_dev->masklength) {
|
||||||
WARN_ON("trying to set scanmask prior to registering buffer\n");
|
WARN_ON("trying to set scanmask prior to registering buffer\n");
|
||||||
kfree(trialmask);
|
goto err_invalid_mask;
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
|
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
|
||||||
set_bit(bit, trialmask);
|
set_bit(bit, trialmask);
|
||||||
|
|
||||||
|
if (!iio_validate_scan_mask(indio_dev, trialmask))
|
||||||
|
goto err_invalid_mask;
|
||||||
|
|
||||||
if (indio_dev->available_scan_masks) {
|
if (indio_dev->available_scan_masks) {
|
||||||
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
|
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
|
||||||
indio_dev->masklength,
|
indio_dev->masklength,
|
||||||
trialmask);
|
trialmask);
|
||||||
if (!mask) {
|
if (!mask)
|
||||||
kfree(trialmask);
|
goto err_invalid_mask;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
|
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
|
||||||
|
|
||||||
kfree(trialmask);
|
kfree(trialmask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
|
||||||
|
err_invalid_mask:
|
||||||
|
kfree(trialmask);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(iio_scan_mask_set);
|
EXPORT_SYMBOL_GPL(iio_scan_mask_set);
|
||||||
|
|
||||||
int iio_scan_mask_query(struct iio_dev *indio_dev,
|
int iio_scan_mask_query(struct iio_dev *indio_dev,
|
||||||
|
|
|
@ -363,12 +363,16 @@ struct iio_info {
|
||||||
* @predisable: [DRIVER] function to run prior to marking buffer
|
* @predisable: [DRIVER] function to run prior to marking buffer
|
||||||
* disabled
|
* disabled
|
||||||
* @postdisable: [DRIVER] function to run after marking buffer disabled
|
* @postdisable: [DRIVER] function to run after marking buffer disabled
|
||||||
|
* @validate_scan_mask: [DRIVER] function callback to check whether a given
|
||||||
|
* scan mask is valid for the device.
|
||||||
*/
|
*/
|
||||||
struct iio_buffer_setup_ops {
|
struct iio_buffer_setup_ops {
|
||||||
int (*preenable)(struct iio_dev *);
|
int (*preenable)(struct iio_dev *);
|
||||||
int (*postenable)(struct iio_dev *);
|
int (*postenable)(struct iio_dev *);
|
||||||
int (*predisable)(struct iio_dev *);
|
int (*predisable)(struct iio_dev *);
|
||||||
int (*postdisable)(struct iio_dev *);
|
int (*postdisable)(struct iio_dev *);
|
||||||
|
bool (*validate_scan_mask)(struct iio_dev *indio_dev,
|
||||||
|
const unsigned long *scan_mask);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue