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); | ||||
| 
 | ||||
| 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 | ||||
| @ -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, | ||||
|  | ||||
| @ -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); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user