Skip to content

Commit

Permalink
iio: Add callback to check whether a scan mask is valid
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lars-Peter Clausen authored and Jonathan Cameron committed Jul 9, 2012
1 parent c732a24 commit 939546d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
27 changes: 20 additions & 7 deletions drivers/iio/industrialio-buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,15 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
}
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
* @buffer: the buffer whose scan mask we are interested in
Expand All @@ -589,27 +598,31 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
return -ENOMEM;
if (!indio_dev->masklength) {
WARN_ON("trying to set scanmask prior to registering buffer\n");
kfree(trialmask);
return -EINVAL;
goto err_invalid_mask;
}
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
set_bit(bit, trialmask);

if (!iio_validate_scan_mask(indio_dev, trialmask))
goto err_invalid_mask;

if (indio_dev->available_scan_masks) {
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
trialmask);
if (!mask) {
kfree(trialmask);
return -EINVAL;
}
if (!mask)
goto err_invalid_mask;
}
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);

kfree(trialmask);

return 0;
};

err_invalid_mask:
kfree(trialmask);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(iio_scan_mask_set);

int iio_scan_mask_query(struct iio_dev *indio_dev,
Expand Down
4 changes: 4 additions & 0 deletions include/linux/iio/iio.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,16 @@ struct iio_info {
* @predisable: [DRIVER] function to run prior to 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 {
int (*preenable)(struct iio_dev *);
int (*postenable)(struct iio_dev *);
int (*predisable)(struct iio_dev *);
int (*postdisable)(struct iio_dev *);
bool (*validate_scan_mask)(struct iio_dev *indio_dev,
const unsigned long *scan_mask);
};

/**
Expand Down

0 comments on commit 939546d

Please sign in to comment.