diff options
Diffstat (limited to 'include/linux/iio/iio.h')
| -rw-r--r-- | include/linux/iio/iio.h | 225 |
1 files changed, 194 insertions, 31 deletions
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 56161e02f002..2c91b7659ce9 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -7,9 +7,12 @@ #ifndef _INDUSTRIAL_IO_H_ #define _INDUSTRIAL_IO_H_ +#include <linux/align.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/cleanup.h> +#include <linux/compiler_types.h> +#include <linux/minmax.h> #include <linux/slab.h> #include <linux/iio/types.h> /* IIO TODO LIST */ @@ -269,14 +272,14 @@ struct iio_chan_spec { unsigned int num_ext_scan_type; }; }; - long info_mask_separate; - long info_mask_separate_available; - long info_mask_shared_by_type; - long info_mask_shared_by_type_available; - long info_mask_shared_by_dir; - long info_mask_shared_by_dir_available; - long info_mask_shared_by_all; - long info_mask_shared_by_all_available; + unsigned long info_mask_separate; + unsigned long info_mask_separate_available; + unsigned long info_mask_shared_by_type; + unsigned long info_mask_shared_by_type_available; + unsigned long info_mask_shared_by_dir; + unsigned long info_mask_shared_by_dir_available; + unsigned long info_mask_shared_by_all; + unsigned long info_mask_shared_by_all_available; const struct iio_event_spec *event_spec; unsigned int num_event_specs; const struct iio_chan_spec_ext_info *ext_info; @@ -659,37 +662,148 @@ void iio_device_unregister(struct iio_dev *indio_dev); int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, struct module *this_mod); int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp); -int iio_device_claim_direct_mode(struct iio_dev *indio_dev); -void iio_device_release_direct_mode(struct iio_dev *indio_dev); + +void __iio_dev_mode_lock(struct iio_dev *indio_dev) __acquires(indio_dev); +void __iio_dev_mode_unlock(struct iio_dev *indio_dev) __releases(indio_dev); /* - * This autocleanup logic is normally used via - * iio_device_claim_direct_scoped(). + * Helper functions that allow claim and release of direct mode + * in a fashion that doesn't generate many false positives from sparse. + * Note this must remain static inline in the header so that sparse + * can see the __acquires() and __releases() annotations. + */ + +/** + * iio_device_claim_direct() - Keep device in direct mode + * @indio_dev: the iio_dev associated with the device + * + * If the device is in direct mode it is guaranteed to stay + * that way until iio_device_release_direct() is called. + * + * Use with iio_device_release_direct(). + * + * Returns: true on success, false on failure. + */ +static inline bool iio_device_claim_direct(struct iio_dev *indio_dev) +{ + __iio_dev_mode_lock(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + __iio_dev_mode_unlock(indio_dev); + return false; + } + + return true; +} + +/** + * iio_device_release_direct() - Releases claim on direct mode + * @indio_dev: the iio_dev associated with the device + * + * Release the claim. Device is no longer guaranteed to stay + * in direct mode. + * + * Use with iio_device_claim_direct(). + */ +#define iio_device_release_direct(indio_dev) __iio_dev_mode_unlock(indio_dev) + +/** + * iio_device_try_claim_buffer_mode() - Keep device in buffer mode + * @indio_dev: the iio_dev associated with the device + * + * If the device is in buffer mode it is guaranteed to stay + * that way until iio_device_release_buffer_mode() is called. + * + * Use with iio_device_release_buffer_mode(). + * + * Returns: true on success, false on failure. + */ +static inline bool iio_device_try_claim_buffer_mode(struct iio_dev *indio_dev) +{ + __iio_dev_mode_lock(indio_dev); + + if (!iio_buffer_enabled(indio_dev)) { + __iio_dev_mode_unlock(indio_dev); + return false; + } + + return true; +} + +/** + * iio_device_release_buffer_mode() - releases claim on buffer mode + * @indio_dev: the iio_dev associated with the device + * + * Release the claim. Device is no longer guaranteed to stay + * in buffer mode. + * + * Use with iio_device_try_claim_buffer_mode(). */ -DEFINE_GUARD(iio_claim_direct, struct iio_dev *, iio_device_claim_direct_mode(_T), - iio_device_release_direct_mode(_T)) +#define iio_device_release_buffer_mode(indio_dev) __iio_dev_mode_unlock(indio_dev) -DEFINE_GUARD_COND(iio_claim_direct, _try, ({ - struct iio_dev *dev; - int d = iio_device_claim_direct_mode(_T); +/* + * These classes are not meant to be used directly by drivers (hence the + * __priv__ prefix). Instead, documented wrapper macros are provided below to + * enforce the use of ACQUIRE() or guard() semantics and avoid the problematic + * scoped guard variants. + */ +DEFINE_GUARD(__priv__iio_dev_mode_lock, struct iio_dev *, + __iio_dev_mode_lock(_T), __iio_dev_mode_unlock(_T)); +DEFINE_GUARD_COND(__priv__iio_dev_mode_lock, _try_direct, + iio_device_claim_direct(_T)); - if (d < 0) - dev = NULL; - else - dev = _T; - dev; - })) +/** + * IIO_DEV_ACQUIRE_DIRECT_MODE() - Tries to acquire the direct mode lock with + * automatic release + * @dev: IIO device instance + * @claim: Variable identifier to store acquire result + * + * Tries to acquire the direct mode lock with cleanup ACQUIRE() semantics and + * automatically releases it at the end of the scope. It most be always paired + * with IIO_DEV_ACQUIRE_ERR(), for example (notice the scope braces):: + * + * switch() { + * case IIO_CHAN_INFO_RAW: { + * IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + * if (IIO_DEV_ACQUIRE_FAILED(claim)) + * return -EBUSY; + * + * ... + * } + * case IIO_CHAN_INFO_SCALE: + * ... + * ... + * } + * + * Context: Can sleep + */ +#define IIO_DEV_ACQUIRE_DIRECT_MODE(dev, claim) \ + ACQUIRE(__priv__iio_dev_mode_lock_try_direct, claim)(dev) /** - * iio_device_claim_direct_scoped() - Scoped call to iio_device_claim_direct. - * @fail: What to do on failure to claim device. - * @iio_dev: Pointer to the IIO devices structure + * IIO_DEV_ACQUIRE_FAILED() - ACQUIRE_ERR() wrapper + * @claim: The claim variable passed to IIO_DEV_ACQUIRE_*_MODE() + * + * Return: true if failed to acquire the mode, otherwise false. */ -#define iio_device_claim_direct_scoped(fail, iio_dev) \ - scoped_cond_guard(iio_claim_direct_try, fail, iio_dev) +#define IIO_DEV_ACQUIRE_FAILED(claim) \ + ACQUIRE_ERR(__priv__iio_dev_mode_lock_try_direct, &(claim)) -int iio_device_claim_buffer_mode(struct iio_dev *indio_dev); -void iio_device_release_buffer_mode(struct iio_dev *indio_dev); +/** + * IIO_DEV_GUARD_CURRENT_MODE() - Acquires the mode lock with automatic release + * @dev: IIO device instance + * + * Acquires the mode lock with cleanup guard() semantics. It is usually paired + * with iio_buffer_enabled(). + * + * This should *not* be used to protect internal driver state and it's use in + * general is *strongly* discouraged. Use any of the IIO_DEV_ACQUIRE_*_MODE() + * variants. + * + * Context: Can sleep + */ +#define IIO_DEV_GUARD_CURRENT_MODE(dev) \ + guard(__priv__iio_dev_mode_lock)(dev) extern const struct bus_type iio_bus_type; @@ -778,8 +892,57 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev) * to in turn include IIO_DMA_MINALIGN'd elements such as buffers which * must not share cachelines with the rest of the structure, thus making * them safe for use with non-coherent DMA. + * + * A number of drivers also use this on buffers that include a 64-bit timestamp + * that is used with iio_push_to_buffers_with_ts(). Therefore, in the case where + * DMA alignment is not sufficient for proper timestamp alignment, we align to + * 8 bytes instead. + */ +#define IIO_DMA_MINALIGN MAX(ARCH_DMA_MINALIGN, sizeof(s64)) + +#define __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \ + type name[ALIGN((count), sizeof(s64) / sizeof(type)) + sizeof(s64) / sizeof(type)] + +/** + * IIO_DECLARE_BUFFER_WITH_TS() - Declare a buffer with timestamp + * @type: element type of the buffer + * @name: identifier name of the buffer + * @count: number of elements in the buffer + * + * Declares a buffer that is safe to use with iio_push_to_buffers_with_ts(). In + * addition to allocating enough space for @count elements of @type, it also + * allocates space for a s64 timestamp at the end of the buffer and ensures + * proper alignment of the timestamp. */ -#define IIO_DMA_MINALIGN ARCH_DMA_MINALIGN +#define IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \ + __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) __aligned(sizeof(s64)) + +/** + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp + * @type: element type of the buffer + * @name: identifier name of the buffer + * @count: number of elements in the buffer + * + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN) + * to ensure that the buffer doesn't share cachelines with anything that comes + * before it in a struct. This should not be used for stack-allocated buffers + * as stack memory cannot generally be used for DMA. + */ +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count) \ + __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) __aligned(IIO_DMA_MINALIGN) + +/** + * IIO_DECLARE_QUATERNION() - Declare a quaternion element + * @type: element type of the individual vectors + * @name: identifier name + * + * Quaternions are a vector composed of 4 elements (W, X, Y, Z). Use this macro + * to declare a quaternion element in a struct to ensure proper alignment in + * an IIO buffer. + */ +#define IIO_DECLARE_QUATERNION(type, name) \ + type name[4] __aligned(sizeof(type) * 4) + struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv); /* The information at the returned address is guaranteed to be cacheline aligned */ |
