summaryrefslogtreecommitdiffstats
path: root/drivers/iio/industrialio-buffer.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-06-10 20:48:34 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-06-10 20:48:34 -0700
commit78a66b00d97c89a43b1ee753814913c55ec2e3ee (patch)
treee5cb4bcf3db64b0fb0f68c4578e4722397605b71 /drivers/iio/industrialio-buffer.c
parente703f23747e25db6ccc1f752f787925f86c27f31 (diff)
parentbbf5f037fad47e4affef6696aaf88a40b261e639 (diff)
downloadlinux-78a66b00d97c89a43b1ee753814913c55ec2e3ee.tar.bz2
Merge tag 'iio-for-v4.2c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: Third round of new IIO drivers, cleanups and functionality for the 4.2 cycle. Given Linus announced a 4.8rc coming up, hopefully time for one more lot of IIO patches this cycle. Some of these are actually improvements / fixes for patches earlier in the cycle. New device support * st_accel driver - support devices with 8 bit channels. Cleanup * A general cleanup of the iio tools under /tools/ from Hartmut. I'm more than a little embarassed by how bad some of these were! Are well, much more refined and less bug prone now. These cover lots of stuff like unhandled error returns, memory leaks as well as general refactoring to tidy the code up. * iio_simple_dummy - fix memory leaks in the init functions, drop some pointless error returns from functions that never generate errors and make the module parameter explicitly unsigned. * More buffer handling reworks from Lars-Peter, this time targetting hardware buffers (a little used corner that looks likely to get more use in the near future). Specifically: - Always compute the masklength as inkernel buffer users may need it. - Add a means of labeling which buffer modes a given buffer implementation supports. - In the case of hardware buffers, require strict scan matching rather than matching to a superset. Currently the demux is bypassed by these drivers (this may well not change for efficiency reasons) so allowing a superset of channels to be selected would otherwise lead to more data than requested confusing userspace. Driver funcationality improvments * mmc35240 - adds a compensation to the raw values as borrowed form Memsic's own input driver. * mma8452 - event support - event debouncing - high pass filter configuration - triggers * vf610 - allow conversion mode to be adjusted Fixlets * mmc35240 - Off by one error that by coincidence had no real effect. - i2c_device_name should be lowercase. - Lack of null terminator at end of attributes array. - Avoid computing the fractional part of the magnetic field by moving the scaling into userspace where floating point is available to simplify the maths. - Use a smaller sleep before assuming the measurement is done. This is safe and improves the possible polling rate. - Fix sensitivity on z-axis - datasheet disagrees with Memsic's releasedd code and the value used in the code seems to be correct. * stk3310 - make a local variable signed to ensure error handling works. * twl4030 - fix calculation of the temperature sense current - bug unlikely to have ever been noticed as the difference is small. - Fix errors in descriptions.
Diffstat (limited to 'drivers/iio/industrialio-buffer.c')
-rw-r--r--drivers/iio/industrialio-buffer.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 11291259b7b9..6eee1b044c60 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -239,13 +239,19 @@ static ssize_t iio_scan_el_show(struct device *dev,
/* Note NULL used as error indicator as it doesn't make sense. */
static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
unsigned int masklength,
- const unsigned long *mask)
+ const unsigned long *mask,
+ bool strict)
{
if (bitmap_empty(mask, masklength))
return NULL;
while (*av_masks) {
- if (bitmap_subset(mask, av_masks, masklength))
- return av_masks;
+ if (strict) {
+ if (bitmap_equal(mask, av_masks, masklength))
+ return av_masks;
+ } else {
+ if (bitmap_subset(mask, av_masks, masklength))
+ return av_masks;
+ }
av_masks += BITS_TO_LONGS(masklength);
}
return NULL;
@@ -295,7 +301,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
if (indio_dev->available_scan_masks) {
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- trialmask);
+ trialmask, false);
if (!mask)
goto err_invalid_mask;
}
@@ -602,8 +608,10 @@ static int iio_verify_update(struct iio_dev *indio_dev,
{
unsigned long *compound_mask;
const unsigned long *scan_mask;
+ bool strict_scanmask = false;
struct iio_buffer *buffer;
bool scan_timestamp;
+ unsigned int modes;
memset(config, 0, sizeof(*config));
@@ -615,12 +623,30 @@ static int iio_verify_update(struct iio_dev *indio_dev,
list_is_singular(&indio_dev->buffer_list))
return 0;
+ modes = indio_dev->modes;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ if (buffer == remove_buffer)
+ continue;
+ modes &= buffer->access->modes;
+ }
+
+ if (insert_buffer)
+ modes &= insert_buffer->access->modes;
+
/* Definitely possible for devices to support both of these. */
- if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
+ if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
config->mode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ } else if (modes & INDIO_BUFFER_HARDWARE) {
+ /*
+ * Keep things simple for now and only allow a single buffer to
+ * be connected in hardware mode.
+ */
+ if (insert_buffer && !list_empty(&indio_dev->buffer_list))
+ return -EINVAL;
config->mode = INDIO_BUFFER_HARDWARE;
- } else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
+ strict_scanmask = true;
+ } else if (modes & INDIO_BUFFER_SOFTWARE) {
config->mode = INDIO_BUFFER_SOFTWARE;
} else {
/* Can only occur on first buffer */
@@ -654,7 +680,8 @@ static int iio_verify_update(struct iio_dev *indio_dev,
if (indio_dev->available_scan_masks) {
scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- compound_mask);
+ compound_mask,
+ strict_scanmask);
kfree(compound_mask);
if (scan_mask == NULL)
return -EINVAL;
@@ -888,8 +915,6 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
ret = __iio_update_buffers(indio_dev,
NULL, indio_dev->buffer);
- if (ret < 0)
- goto done;
done:
mutex_unlock(&indio_dev->mlock);
return (ret < 0) ? ret : len;
@@ -968,6 +993,15 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
int ret, i, attrn, attrcount, attrcount_orig = 0;
const struct iio_chan_spec *channels;
+ channels = indio_dev->channels;
+ if (channels) {
+ int ml = indio_dev->masklength;
+
+ for (i = 0; i < indio_dev->num_channels; i++)
+ ml = max(ml, channels[i].scan_index + 1);
+ indio_dev->masklength = ml;
+ }
+
if (!buffer)
return 0;
@@ -1011,12 +1045,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
if (channels[i].scan_index < 0)
continue;
- /* Establish necessary mask length */
- if (channels[i].scan_index >
- (int)indio_dev->masklength - 1)
- indio_dev->masklength
- = channels[i].scan_index + 1;
-
ret = iio_buffer_add_channel_sysfs(indio_dev,
&channels[i]);
if (ret < 0)