From e36db6a06937c6fce3291f0c362d4f757b8ec703 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:21 +0200 Subject: iio: kfifo: add devm_iio_kfifo_buffer_setup() helper This change adds the devm_iio_kfifo_buffer_setup() helper/short-hand, which groups the simple routine of allocating a kfifo buffers via devm_iio_kfifo_allocate() and calling iio_device_attach_buffer(). The mode_flags parameter is required, as the IIO kfifo supports 2 modes: INDIO_BUFFER_SOFTWARE & INDIO_BUFFER_TRIGGERED. The setup_ops parameter is optional. This function will be a bit more useful when needing to define multiple buffers per IIO device. The naming for this function has been inspired from iio_triggered_buffer_setup() since that one does a kfifo alloc + a pollfunc alloc. So, this should have a more familiar ring to what it is. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-3-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/kfifo_buf.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux') diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 1fc1efa7799d..92c411b9ac26 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -3,6 +3,8 @@ #define __LINUX_IIO_KFIFO_BUF_H__ struct iio_buffer; +struct iio_buffer_setup_ops; +struct iio_dev; struct device; struct iio_buffer *iio_kfifo_allocate(void); @@ -10,4 +12,9 @@ void iio_kfifo_free(struct iio_buffer *r); struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev); +int devm_iio_kfifo_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + int mode_flags, + const struct iio_buffer_setup_ops *setup_ops); + #endif -- cgit v1.2.3 From 99f6e8215b627730e2e6d371430a1f81e8ed6c27 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:24 +0200 Subject: iio: kfifo: un-export devm_iio_kfifo_allocate() function At this point all drivers should use devm_iio_kfifo_buffer_setup() instead of manually allocating via devm_iio_kfifo_allocate() and assigning ops and modes. With this change, the devm_iio_kfifo_allocate() will be made private to the IIO core, since all drivers should call either devm_iio_kfifo_buffer_setup() or devm_iio_triggered_buffer_setup() to create a kfifo buffer. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-6-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - drivers/iio/buffer/kfifo_buf.c | 3 +-- include/linux/iio/kfifo_buf.h | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'include/linux') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 562f5722281e..4b15b3e9358b 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -285,7 +285,6 @@ I2C IIO devm_iio_device_alloc() devm_iio_device_register() - devm_iio_kfifo_allocate() devm_iio_kfifo_buffer_setup() devm_iio_triggered_buffer_setup() devm_iio_trigger_alloc() diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 6472c9fa1937..c35a625280b1 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -186,7 +186,7 @@ static void devm_iio_kfifo_release(struct device *dev, void *res) * RETURNS: * Pointer to allocated iio_buffer on success, NULL on failure. */ -struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) +static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) { struct iio_buffer **ptr, *r; @@ -204,7 +204,6 @@ struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) return r; } -EXPORT_SYMBOL(devm_iio_kfifo_allocate); /** * devm_iio_kfifo_buffer_setup - Allocate a kfifo buffer & attach it to an IIO device diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 92c411b9ac26..1522896e1daf 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -10,8 +10,6 @@ struct device; struct iio_buffer *iio_kfifo_allocate(void); void iio_kfifo_free(struct iio_buffer *r); -struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev); - int devm_iio_kfifo_buffer_setup(struct device *dev, struct iio_dev *indio_dev, int mode_flags, -- cgit v1.2.3 From a02c09e42b3ed6cefae671e302835f1f04bf474e Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:25 +0200 Subject: iio: buffer-dma,adi-axi-adc: introduce devm_iio_dmaengine_buffer_setup() This change does a conversion of the devm_iio_dmaengine_buffer_alloc() to devm_iio_dmaengine_buffer_setup(). This will allocate an IIO DMA buffer and attach it to the IIO device, similar to devm_iio_triggered_buffer_setup() (though the underlying code is different, the final logic is the same). Since the only user of the devm_iio_dmaengine_buffer_alloc() was the adi-axi-adc driver, this change does the replacement in a single go in the driver. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-7-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 + drivers/iio/adc/adi-axi-adc.c | 12 ++------ drivers/iio/buffer/industrialio-buffer-dmaengine.c | 33 ++++++++++++++++++++-- include/linux/iio/buffer-dmaengine.h | 7 +++-- 4 files changed, 38 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 4b15b3e9358b..5f8c6c303ff2 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -285,6 +285,7 @@ I2C IIO devm_iio_device_alloc() devm_iio_device_register() + devm_iio_dmaengine_buffer_setup() devm_iio_kfifo_buffer_setup() devm_iio_triggered_buffer_setup() devm_iio_trigger_alloc() diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 9109da2d2e15..2e84623f732e 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -104,7 +104,6 @@ static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, static int adi_axi_adc_config_dma_buffer(struct device *dev, struct iio_dev *indio_dev) { - struct iio_buffer *buffer; const char *dma_name; if (!device_property_present(dev, "dmas")) @@ -113,15 +112,8 @@ static int adi_axi_adc_config_dma_buffer(struct device *dev, if (device_property_read_string(dev, "dma-names", &dma_name)) dma_name = "rx"; - buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, - dma_name); - if (IS_ERR(buffer)) - return PTR_ERR(buffer); - - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - iio_device_attach_buffer(indio_dev, buffer); - - return 0; + return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, + indio_dev, dma_name); } static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index b0cb9a35f5cd..9981896e1495 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -244,7 +244,7 @@ static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) * * The buffer will be automatically de-allocated once the device gets destroyed. */ -struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, +static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, const char *channel) { struct iio_buffer **bufferp, *buffer; @@ -265,7 +265,36 @@ struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, return buffer; } -EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_alloc); + +/** + * devm_iio_dmaengine_buffer_setup() - Setup a DMA buffer for an IIO device + * @dev: Parent device for the buffer + * @indio_dev: IIO device to which to attach this buffer. + * @channel: DMA channel name, typically "rx". + * + * This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc() + * and attaches it to an IIO device with iio_device_attach_buffer(). + * It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the + * IIO device. + */ +int devm_iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel) +{ + struct iio_buffer *buffer; + + buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, + channel); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + iio_device_attach_buffer(indio_dev, buffer); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index 5b502291d6a4..5c355be89814 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -7,10 +7,11 @@ #ifndef __IIO_DMAENGINE_H__ #define __IIO_DMAENGINE_H__ -struct iio_buffer; +struct iio_dev; struct device; -struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, - const char *channel); +int devm_iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel); #endif -- cgit v1.2.3 From 32f171724e5cbecc80594fb6eced057cfdd6eb6f Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:29 +0200 Subject: iio: core: rework iio device group creation Up until now, the device groups that an IIO device had were limited to 6. Two of these groups would account for buffer attributes (the buffer/ and scan_elements/ directories). Since we want to add multiple buffers per IIO device, this number may not be enough, when adding a second buffer. So, this change reallocates the groups array whenever an IIO device group is added, via a iio_device_register_sysfs_group() helper. This also means that the groups array should be assigned to 'indio_dev.dev.groups' really late, right before {cdev_}device_add() is called to do the entire setup. And we also must take care to free this array when the sysfs resources are being cleaned up. With this change we can also move the 'groups' & 'groupcounter' fields to the iio_dev_opaque object. Up until now, this didn't make a whole lot of sense (especially since we weren't sure how multibuffer support would look like in the end). But doing it now kills one birds with one stone. An alternative, would be to add a configurable Kconfig symbol CONFIG_IIO_MAX_BUFFERS_PER_DEVICE (or something like that) and compute a static maximum of the groups we can support per IIO device. But that would probably annoy a few people since that would make the system less configurable. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-11-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/iio_core.h | 3 +++ drivers/iio/industrialio-buffer.c | 12 ++++++++++-- drivers/iio/industrialio-core.c | 30 +++++++++++++++++++++++++++--- drivers/iio/industrialio-event.c | 5 ++++- drivers/iio/industrialio-trigger.c | 6 ++---- include/linux/iio/iio-opaque.h | 4 ++++ include/linux/iio/iio.h | 5 ----- 7 files changed, 50 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index fced02cadcc3..7d5b179c1fe7 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -46,6 +46,9 @@ int __iio_add_chan_devattr(const char *postfix, struct list_head *attr_list); void iio_free_chan_devattr_list(struct list_head *attr_list); +int iio_device_register_sysfs_group(struct iio_dev *indio_dev, + const struct attribute_group *group); + ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); /* Event interface flags */ diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 2f7426a2f47c..cc846988fdb9 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1287,7 +1287,9 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, buffer->buffer_group.name = "buffer"; buffer->buffer_group.attrs = attr; - indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; + ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group); + if (ret) + goto error_free_buffer_attrs; attrcount = 0; INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); @@ -1330,14 +1332,20 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr; - indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group; + + ret = iio_device_register_sysfs_group(indio_dev, &buffer->scan_el_group); + if (ret) + goto error_free_scan_el_attrs; return 0; +error_free_scan_el_attrs: + kfree(buffer->scan_el_group.attrs); error_free_scan_mask: bitmap_free(buffer->scan_mask); error_cleanup_dynamic: iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); +error_free_buffer_attrs: kfree(buffer->buffer_group.attrs); return ret; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 92efbc245098..924f3a167125 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1454,6 +1454,25 @@ static ssize_t iio_store_timestamp_clock(struct device *dev, return len; } +int iio_device_register_sysfs_group(struct iio_dev *indio_dev, + const struct attribute_group *group) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + const struct attribute_group **new, **old = iio_dev_opaque->groups; + unsigned int cnt = iio_dev_opaque->groupcounter; + + new = krealloc(old, sizeof(*new) * (cnt + 2), GFP_KERNEL); + if (!new) + return -ENOMEM; + + new[iio_dev_opaque->groupcounter++] = group; + new[iio_dev_opaque->groupcounter] = NULL; + + iio_dev_opaque->groups = new; + + return 0; +} + static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR, iio_show_timestamp_clock, iio_store_timestamp_clock); @@ -1527,8 +1546,10 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) if (clk) iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk; - indio_dev->groups[indio_dev->groupcounter++] = - &iio_dev_opaque->chan_attr_group; + ret = iio_device_register_sysfs_group(indio_dev, + &iio_dev_opaque->chan_attr_group); + if (ret) + goto error_clear_attrs; return 0; @@ -1545,6 +1566,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list); kfree(iio_dev_opaque->chan_attr_group.attrs); iio_dev_opaque->chan_attr_group.attrs = NULL; + kfree(iio_dev_opaque->groups); } static void iio_dev_release(struct device *device) @@ -1594,7 +1616,6 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN); dev->dev.parent = parent; - dev->dev.groups = dev->groups; dev->dev.type = &iio_device_type; dev->dev.bus = &iio_bus_type; device_initialize(&dev->dev); @@ -1857,6 +1878,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) indio_dev->chrdev.owner = this_mod; } + /* assign device groups now; they should be all registered now */ + indio_dev->dev.groups = iio_dev_opaque->groups; + ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev); if (ret < 0) goto error_unreg_eventset; diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 7e532117ac55..ea8947cc21e4 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -544,7 +544,10 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) /* Add all elements from the list. */ list_for_each_entry(p, &ev_int->dev_attr_list, l) ev_int->group.attrs[attrn++] = &p->dev_attr.attr; - indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group; + + ret = iio_device_register_sysfs_group(indio_dev, &ev_int->group); + if (ret) + goto error_free_setup_event_lines; ev_int->ioctl_handler.ioctl = iio_event_ioctl; iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev, diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 438d5012e8b8..a035d5c2a445 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -694,10 +694,8 @@ EXPORT_SYMBOL(iio_trigger_validate_own_device); int iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { - indio_dev->groups[indio_dev->groupcounter++] = - &iio_trigger_consumer_attr_group; - - return 0; + return iio_device_register_sysfs_group(indio_dev, + &iio_trigger_consumer_attr_group); } void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index 07c5a8e52ca8..8ba13a5c7af6 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -12,6 +12,8 @@ * attributes * @chan_attr_group: group for all attrs in base directory * @ioctl_handlers: ioctl handlers registered with the core handler + * @groups: attribute groups + * @groupcounter: index of next attribute group * @debugfs_dentry: device specific debugfs dentry * @cached_reg_addr: cached register address for debugfs reads * @read_buf: read buffer to be used for the initial reg read @@ -24,6 +26,8 @@ struct iio_dev_opaque { struct list_head channel_attr_list; struct attribute_group chan_attr_group; struct list_head ioctl_handlers; + const struct attribute_group **groups; + int groupcounter; #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_dentry; unsigned cached_reg_addr; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e4a9822e6495..f8585d01fc76 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -518,8 +518,6 @@ struct iio_buffer_setup_ops { * @setup_ops: [DRIVER] callbacks to call before and after buffer * enable/disable * @chrdev: [INTERN] associated character device - * @groups: [INTERN] attribute groups - * @groupcounter: [INTERN] index of next attribute group * @flags: [INTERN] file ops related flags including busy flag. * @priv: [DRIVER] reference to driver's private information * **MUST** be accessed **ONLY** via iio_priv() helper @@ -556,9 +554,6 @@ struct iio_dev { struct mutex info_exist_lock; const struct iio_buffer_setup_ops *setup_ops; struct cdev chrdev; -#define IIO_MAX_GROUPS 6 - const struct attribute_group *groups[IIO_MAX_GROUPS + 1]; - int groupcounter; unsigned long flags; void *priv; -- cgit v1.2.3 From d9a625744ed0e452f5c495cd8c51eed4b6623a4c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:31 +0200 Subject: iio: core: merge buffer/ & scan_elements/ attributes With this change, we create a new directory for the IIO device called buffer0, under which both the old buffer/ and scan_elements/ are stored. This is done to simplify the addition of multiple IIO buffers per IIO device. Otherwise we would need to add a bufferX/ and scan_elementsX/ directory for each IIO buffer. With the current way of storing attribute groups, we can't have directories stored under each other (i.e. scan_elements/ under buffer/), so the best approach moving forward is to merge their attributes. The old/legacy buffer/ & scan_elements/ groups are not stored on the opaque IIO device object. This way the IIO buffer can have just a single attribute_group object, saving a bit of memory when adding multiple IIO buffers. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-13-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 115 +++++++++++++++++++++++++++++--------- include/linux/iio/buffer_impl.h | 9 +-- include/linux/iio/iio-opaque.h | 4 ++ 3 files changed, 95 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 01ab3dd0726a..76f0f6a61ebc 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1175,8 +1175,6 @@ done: return (ret < 0) ? ret : len; } -static const char * const iio_scan_elements_group_name = "scan_elements"; - static ssize_t iio_buffer_show_watermark(struct device *dev, struct device_attribute *attr, char *buf) @@ -1252,8 +1250,68 @@ static struct attribute *iio_buffer_attrs[] = { &dev_attr_data_available.attr, }; +static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev, + struct attribute **buffer_attrs, + int buffer_attrcount, + int scan_el_attrcount) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct attribute_group *group; + struct attribute **attrs; + int ret; + + attrs = kcalloc(buffer_attrcount + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + memcpy(attrs, buffer_attrs, buffer_attrcount * sizeof(*attrs)); + + group = &iio_dev_opaque->legacy_buffer_group; + group->attrs = attrs; + group->name = "buffer"; + + ret = iio_device_register_sysfs_group(indio_dev, group); + if (ret) + goto error_free_buffer_attrs; + + attrs = kcalloc(scan_el_attrcount + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) { + ret = -ENOMEM; + goto error_free_buffer_attrs; + } + + memcpy(attrs, &buffer_attrs[buffer_attrcount], + scan_el_attrcount * sizeof(*attrs)); + + group = &iio_dev_opaque->legacy_scan_el_group; + group->attrs = attrs; + group->name = "scan_elements"; + + ret = iio_device_register_sysfs_group(indio_dev, group); + if (ret) + goto error_free_scan_el_attrs; + + return 0; + +error_free_buffer_attrs: + kfree(iio_dev_opaque->legacy_buffer_group.attrs); +error_free_scan_el_attrs: + kfree(iio_dev_opaque->legacy_scan_el_group.attrs); + + return ret; +} + +static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + kfree(iio_dev_opaque->legacy_buffer_group.attrs); + kfree(iio_dev_opaque->legacy_scan_el_group.attrs); +} + static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, - struct iio_dev *indio_dev) + struct iio_dev *indio_dev, + int index) { struct iio_dev_attr *p; struct attribute **attr; @@ -1294,8 +1352,8 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, } } - attr = kcalloc(buffer_attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1, - sizeof(*attr), GFP_KERNEL); + attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs); + attr = kcalloc(attrn + 1, sizeof(* attr), GFP_KERNEL); if (!attr) { ret = -ENOMEM; goto error_free_scan_mask; @@ -1313,37 +1371,38 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, sizeof(struct attribute *) * buffer_attrcount); buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs); - attr[buffer_attrcount] = NULL; - - buffer->buffer_group.name = "buffer"; - buffer->buffer_group.attrs = attr; - ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group); - if (ret) - goto error_free_buffer_attrs; + attrn = buffer_attrcount; - buffer->scan_el_group.name = iio_scan_elements_group_name; + list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) + attr[attrn++] = &p->dev_attr.attr; - buffer->scan_el_group.attrs = kcalloc(scan_el_attrcount + 1, - sizeof(buffer->scan_el_group.attrs[0]), - GFP_KERNEL); - if (buffer->scan_el_group.attrs == NULL) { + buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index); + if (!buffer->buffer_group.name) { ret = -ENOMEM; - goto error_free_scan_mask; + goto error_free_buffer_attrs; } - attrn = 0; - list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) - buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr; + buffer->buffer_group.attrs = attr; - ret = iio_device_register_sysfs_group(indio_dev, &buffer->scan_el_group); + ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group); if (ret) - goto error_free_scan_el_attrs; + goto error_free_buffer_attr_group_name; + + /* we only need to register the legacy groups for the first buffer */ + if (index > 0) + return 0; + + ret = iio_buffer_register_legacy_sysfs_groups(indio_dev, attr, + buffer_attrcount, + scan_el_attrcount); + if (ret) + goto error_free_buffer_attr_group_name; return 0; -error_free_scan_el_attrs: - kfree(buffer->scan_el_group.attrs); +error_free_buffer_attr_group_name: + kfree(buffer->buffer_group.name); error_free_buffer_attrs: kfree(buffer->buffer_group.attrs); error_free_scan_mask: @@ -1372,14 +1431,14 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) if (!buffer) return 0; - return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev); + return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, 0); } static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) { bitmap_free(buffer->scan_mask); + kfree(buffer->buffer_group.name); kfree(buffer->buffer_group.attrs); - kfree(buffer->scan_el_group.attrs); iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); } @@ -1390,6 +1449,8 @@ void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) if (!buffer) return; + iio_buffer_unregister_legacy_sysfs_groups(indio_dev); + __iio_buffer_free_sysfs_and_mask(buffer); } diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index a63dc07b7350..3e555e58475b 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -100,14 +100,11 @@ struct iio_buffer { /* @scan_el_dev_attr_list: List of scan element related attributes. */ struct list_head scan_el_dev_attr_list; - /* @buffer_group: Attributes of the buffer group. */ - struct attribute_group buffer_group; - /* - * @scan_el_group: Attribute group for those attributes not - * created from the iio_chan_info array. + * @buffer_group: Attributes of the new buffer group. + * Includes scan elements attributes. */ - struct attribute_group scan_el_group; + struct attribute_group buffer_group; /* @attrs: Standard attributes of the buffer. */ const struct attribute **attrs; diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index 8ba13a5c7af6..1a9310b0145f 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -14,6 +14,8 @@ * @ioctl_handlers: ioctl handlers registered with the core handler * @groups: attribute groups * @groupcounter: index of next attribute group + * @legacy_scan_el_group: attribute group for legacy scan elements attribute group + * @legacy_buffer_group: attribute group for legacy buffer attributes group * @debugfs_dentry: device specific debugfs dentry * @cached_reg_addr: cached register address for debugfs reads * @read_buf: read buffer to be used for the initial reg read @@ -28,6 +30,8 @@ struct iio_dev_opaque { struct list_head ioctl_handlers; const struct attribute_group **groups; int groupcounter; + struct attribute_group legacy_scan_el_group; + struct attribute_group legacy_buffer_group; #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_dentry; unsigned cached_reg_addr; -- cgit v1.2.3 From 3e3d11b2e43b9a967d98261250c19636b893b7ed Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:32 +0200 Subject: iio: add reference to iio buffer on iio_dev_attr This change adds a reference to a 'struct iio_buffer' object on the iio_dev_attr object. This way, we can use the created iio_dev_attr objects on per-buffer basis (since they're allocated anyway). A minor downside of this change is that the number of parameters on __iio_add_chan_devattr() grows by 1. This looks like it could do with a bit of a re-think. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-14-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/iio_core.h | 2 ++ drivers/iio/industrialio-buffer.c | 4 ++++ drivers/iio/industrialio-core.c | 6 ++++++ drivers/iio/industrialio-event.c | 1 + include/linux/iio/sysfs.h | 3 +++ 5 files changed, 16 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 7d5b179c1fe7..731f5170d5b9 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -12,6 +12,7 @@ #include #include +struct iio_buffer; struct iio_chan_spec; struct iio_dev; @@ -43,6 +44,7 @@ int __iio_add_chan_devattr(const char *postfix, u64 mask, enum iio_shared_by shared_by, struct device *dev, + struct iio_buffer *buffer, struct list_head *attr_list); void iio_free_chan_devattr_list(struct list_head *attr_list); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 76f0f6a61ebc..e6edec3bcb73 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -447,6 +447,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, IIO_SEPARATE, &indio_dev->dev, + buffer, &buffer->scan_el_dev_attr_list); if (ret) return ret; @@ -458,6 +459,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, 0, &indio_dev->dev, + buffer, &buffer->scan_el_dev_attr_list); if (ret) return ret; @@ -470,6 +472,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, chan->scan_index, 0, &indio_dev->dev, + buffer, &buffer->scan_el_dev_attr_list); else ret = __iio_add_chan_devattr("en", @@ -479,6 +482,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, chan->scan_index, 0, &indio_dev->dev, + buffer, &buffer->scan_el_dev_attr_list); if (ret) return ret; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 924f3a167125..f4e5a08bbcd5 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1116,6 +1116,7 @@ int __iio_add_chan_devattr(const char *postfix, u64 mask, enum iio_shared_by shared_by, struct device *dev, + struct iio_buffer *buffer, struct list_head *attr_list) { int ret; @@ -1131,6 +1132,7 @@ int __iio_add_chan_devattr(const char *postfix, goto error_iio_dev_attr_free; iio_attr->c = chan; iio_attr->address = mask; + iio_attr->buffer = buffer; list_for_each_entry(t, attr_list, l) if (strcmp(t->dev_attr.attr.name, iio_attr->dev_attr.attr.name) == 0) { @@ -1167,6 +1169,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev, 0, IIO_SEPARATE, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); if (ret < 0) return ret; @@ -1192,6 +1195,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, i, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; @@ -1228,6 +1232,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, i, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); kfree(avail_postfix); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) @@ -1324,6 +1329,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, i, ext_info->shared, &indio_dev->dev, + NULL, &iio_dev_opaque->channel_attr_list); i++; if (ret == -EBUSY && ext_info->shared) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index ea8947cc21e4..a30e289fc362 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -385,6 +385,7 @@ static int iio_device_add_event(struct iio_dev *indio_dev, ret = __iio_add_chan_devattr(postfix, chan, show, store, (i << 16) | spec_index, shared_by, &indio_dev->dev, + NULL, &iio_dev_opaque->event_interface->dev_attr_list); kfree(postfix); diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index b532c875bc24..e51fba66de4b 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -9,6 +9,7 @@ #ifndef _INDUSTRIAL_IO_SYSFS_H_ #define _INDUSTRIAL_IO_SYSFS_H_ +struct iio_buffer; struct iio_chan_spec; /** @@ -17,12 +18,14 @@ struct iio_chan_spec; * @address: associated register address * @l: list head for maintaining list of dynamically created attrs * @c: specification for the underlying channel + * @buffer: the IIO buffer to which this attribute belongs to (if any) */ struct iio_dev_attr { struct device_attribute dev_attr; u64 address; struct list_head l; struct iio_chan_spec const *c; + struct iio_buffer *buffer; }; #define to_iio_dev_attr(_dev_attr) \ -- cgit v1.2.3 From 15097c7a1adc0554ce8eb6f5fd6758d063bfea44 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:33 +0200 Subject: iio: buffer: wrap all buffer attributes into iio_dev_attr This change wraps all buffer attributes into iio_dev_attr objects, and assigns a reference to the IIO buffer they belong to. With the addition of multiple IIO buffers per one IIO device, we need a way to know which IIO buffer is being enabled/disabled/controlled. We know that all buffer attributes are device_attributes. So we can wrap them with a iio_dev_attr types. In the iio_dev_attr type, we can also hold a reference to an IIO buffer. So, we end up being able to allocate wrapped attributes for all buffer attributes (even the one from other drivers). The neat part with this mechanism, is that we don't need to add any extra cleanup, because these attributes are being added to a dynamic list that will get cleaned up via iio_free_chan_devattr_list(). With this change, the 'buffer->scan_el_dev_attr_list' list is being renamed to 'buffer->buffer_attr_list', effectively merging (or finalizing the merge) of the buffer/ & scan_elements/ attributes internally. Accessing these new buffer attributes can now be done via 'to_iio_dev_attr(attr)->buffer' inside the show/store handlers. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-15-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 77 ++++++++++++++++++++++++++------------- drivers/iio/industrialio-core.c | 2 +- include/linux/iio/buffer_impl.h | 4 +- 3 files changed, 54 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index e6edec3bcb73..ea91f9578dee 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -253,8 +253,7 @@ static ssize_t iio_scan_el_show(struct device *dev, char *buf) { int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; /* Ensure ret is 0 or 1. */ ret = !!test_bit(to_iio_dev_attr(attr)->address, @@ -367,8 +366,8 @@ static ssize_t iio_scan_el_store(struct device *dev, int ret; bool state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_buffer *buffer = this_attr->buffer; ret = strtobool(buf, &state); if (ret < 0) @@ -402,8 +401,7 @@ static ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; return sprintf(buf, "%d\n", buffer->scan_timestamp); } @@ -415,7 +413,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; bool state; ret = strtobool(buf, &state); @@ -448,7 +446,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, IIO_SEPARATE, &indio_dev->dev, buffer, - &buffer->scan_el_dev_attr_list); + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -460,7 +458,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, &indio_dev->dev, buffer, - &buffer->scan_el_dev_attr_list); + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -473,7 +471,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, &indio_dev->dev, buffer, - &buffer->scan_el_dev_attr_list); + &buffer->buffer_attr_list); else ret = __iio_add_chan_devattr("en", chan, @@ -483,7 +481,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, &indio_dev->dev, buffer, - &buffer->scan_el_dev_attr_list); + &buffer->buffer_attr_list); if (ret) return ret; attrcount++; @@ -495,8 +493,7 @@ static ssize_t iio_buffer_read_length(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; return sprintf(buf, "%d\n", buffer->length); } @@ -506,7 +503,7 @@ static ssize_t iio_buffer_write_length(struct device *dev, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; unsigned int val; int ret; @@ -538,8 +535,7 @@ static ssize_t iio_buffer_show_enable(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; return sprintf(buf, "%d\n", iio_buffer_is_active(buffer)); } @@ -1154,7 +1150,7 @@ static ssize_t iio_buffer_store_enable(struct device *dev, int ret; bool requested_state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; bool inlist; ret = strtobool(buf, &requested_state); @@ -1183,8 +1179,7 @@ static ssize_t iio_buffer_show_watermark(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; return sprintf(buf, "%u\n", buffer->watermark); } @@ -1195,7 +1190,7 @@ static ssize_t iio_buffer_store_watermark(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; unsigned int val; int ret; @@ -1228,8 +1223,7 @@ static ssize_t iio_dma_show_data_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer; return sprintf(buf, "%zu\n", iio_buffer_data_available(buffer)); } @@ -1254,6 +1248,27 @@ static struct attribute *iio_buffer_attrs[] = { &dev_attr_data_available.attr, }; +#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) + +static struct attribute *iio_buffer_wrap_attr(struct iio_buffer *buffer, + struct attribute *attr) +{ + struct device_attribute *dattr = to_dev_attr(attr); + struct iio_dev_attr *iio_attr; + + iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL); + if (!iio_attr) + return NULL; + + iio_attr->buffer = buffer; + memcpy(&iio_attr->dev_attr, dattr, sizeof(iio_attr->dev_attr)); + iio_attr->dev_attr.attr.name = kstrdup_const(attr->name, GFP_KERNEL); + + list_add(&iio_attr->l, &buffer->buffer_attr_list); + + return &iio_attr->dev_attr.attr; +} + static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev, struct attribute **buffer_attrs, int buffer_attrcount, @@ -1329,7 +1344,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, } scan_el_attrcount = 0; - INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); + INIT_LIST_HEAD(&buffer->buffer_attr_list); channels = indio_dev->channels; if (channels) { /* new magic */ @@ -1376,9 +1391,19 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs); - attrn = buffer_attrcount; + for (i = 0; i < buffer_attrcount; i++) { + struct attribute *wrapped; + + wrapped = iio_buffer_wrap_attr(buffer, attr[i]); + if (!wrapped) { + ret = -ENOMEM; + goto error_free_scan_mask; + } + attr[i] = wrapped; + } - list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) + attrn = 0; + list_for_each_entry(p, &buffer->buffer_attr_list, l) attr[attrn++] = &p->dev_attr.attr; buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index); @@ -1412,7 +1437,7 @@ error_free_buffer_attrs: error_free_scan_mask: bitmap_free(buffer->scan_mask); error_cleanup_dynamic: - iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); + iio_free_chan_devattr_list(&buffer->buffer_attr_list); return ret; } @@ -1443,7 +1468,7 @@ static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) bitmap_free(buffer->scan_mask); kfree(buffer->buffer_group.name); kfree(buffer->buffer_group.attrs); - iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); + iio_free_chan_devattr_list(&buffer->buffer_attr_list); } void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index f4e5a08bbcd5..b8b149ccecef 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1357,7 +1357,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list) struct iio_dev_attr *p, *n; list_for_each_entry_safe(p, n, attr_list, l) { - kfree(p->dev_attr.attr.name); + kfree_const(p->dev_attr.attr.name); list_del(&p->l); kfree(p); } diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 3e555e58475b..41044320e581 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -97,8 +97,8 @@ struct iio_buffer { /* @scan_timestamp: Does the scan mode include a timestamp. */ bool scan_timestamp; - /* @scan_el_dev_attr_list: List of scan element related attributes. */ - struct list_head scan_el_dev_attr_list; + /* @buffer_attr_list: List of buffer attributes. */ + struct list_head buffer_attr_list; /* * @buffer_group: Attributes of the new buffer group. -- cgit v1.2.3 From ee708e6baacd3afdace9b721c25fbbe106cebb94 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:38 +0200 Subject: iio: buffer: introduce support for attaching more IIO buffers With this change, calling iio_device_attach_buffer() will actually attach more buffers. Right now this doesn't do any validation of whether a buffer is attached twice; maybe that can be added later (if needed). Attaching a buffer more than once should yield noticeably bad results. The first buffer is the legacy buffer, so a reference is kept to it. At this point, accessing the data for the extra buffers (that are added after the first one) isn't possible yet. The iio_device_attach_buffer() is also changed to return an error code, which for now is -ENOMEM if the array could not be realloc-ed for more buffers. To adapt to this new change iio_device_attach_buffer() is called last in all place where it's called. The realloc failure is a bit difficult to handle during un-managed calls when unwinding, so it's better to have this as the last error in the setup_buffer calls. At this point, no driver should call iio_device_attach_buffer() directly, it should call one of the {devm_}iio_triggered_buffer_setup() or devm_iio_kfifo_buffer_setup() or devm_iio_dmaengine_buffer_setup() functions. This makes iio_device_attach_buffer() a bit easier to handle. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-20-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 4 +- drivers/iio/buffer/industrialio-triggered-buffer.c | 10 ++- drivers/iio/buffer/kfifo_buf.c | 4 +- drivers/iio/iio_core.h | 10 ++- drivers/iio/industrialio-buffer.c | 100 +++++++++++++++++---- drivers/iio/industrialio-core.c | 12 +-- include/linux/iio/buffer.h | 4 +- include/linux/iio/buffer_impl.h | 3 + include/linux/iio/iio-opaque.h | 4 + 9 files changed, 111 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index a64b222289be..d76179878ff9 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -290,9 +290,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, indio_dev->modes |= INDIO_BUFFER_HARDWARE; - iio_device_attach_buffer(indio_dev, buffer); - - return 0; + return iio_device_attach_buffer(indio_dev, buffer); } EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index 92b8aea3e063..b2b1b7d27af4 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -50,8 +50,6 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, goto error_ret; } - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->pollfunc = iio_alloc_pollfunc(h, thread, IRQF_ONESHOT, @@ -72,10 +70,16 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, buffer->attrs = buffer_attrs; + ret = iio_device_attach_buffer(indio_dev, buffer); + if (ret < 0) + goto error_dealloc_pollfunc; + return 0; +error_dealloc_pollfunc: + iio_dealloc_pollfunc(indio_dev->pollfunc); error_kfifo_free: - iio_kfifo_free(indio_dev->buffer); + iio_kfifo_free(buffer); error_ret: return ret; } diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index c35a625280b1..34289ce12f20 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -235,12 +235,10 @@ int devm_iio_kfifo_buffer_setup(struct device *dev, if (!buffer) return -ENOMEM; - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->modes |= mode_flags; indio_dev->setup_ops = setup_ops; - return 0; + return iio_device_attach_buffer(indio_dev, buffer); } EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup); diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 87868fff7d37..7990c759f1f5 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -69,29 +69,31 @@ __poll_t iio_buffer_poll(struct file *filp, ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, size_t n, loff_t *f_ps); -int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev); -void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev); +int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev); +void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev); #define iio_buffer_poll_addr (&iio_buffer_poll) #define iio_buffer_read_outer_addr (&iio_buffer_read_outer) void iio_disable_all_buffers(struct iio_dev *indio_dev); void iio_buffer_wakeup_poll(struct iio_dev *indio_dev); +void iio_buffers_put(struct iio_dev *indio_dev); #else #define iio_buffer_poll_addr NULL #define iio_buffer_read_outer_addr NULL -static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) +static inline int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) { return 0; } -static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {} +static inline void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) {} static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {} static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {} +static inline void iio_buffers_put(struct iio_dev *indio_dev) {} #endif diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 349c0c011745..b60c2e66bd1c 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -193,12 +193,14 @@ __poll_t iio_buffer_poll(struct file *filp, */ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; - - if (!buffer) - return; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + unsigned int i; - wake_up(&buffer->pollq); + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + wake_up(&buffer->pollq); + } } void iio_buffer_init(struct iio_buffer *buffer) @@ -212,6 +214,18 @@ void iio_buffer_init(struct iio_buffer *buffer) } EXPORT_SYMBOL(iio_buffer_init); +void iio_buffers_put(struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + unsigned int i; + + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + iio_buffer_put(buffer); + } +} + static ssize_t iio_show_scan_index(struct device *dev, struct device_attribute *attr, char *buf) @@ -1452,11 +1466,13 @@ static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) iio_free_chan_devattr_list(&buffer->buffer_attr_list); } -int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) +int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); const struct iio_chan_spec *channels; - int i; + struct iio_buffer *buffer; + int unwind_idx; + int ret, i; channels = indio_dev->channels; if (channels) { @@ -1467,22 +1483,46 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) indio_dev->masklength = ml; } - if (!buffer) + if (!iio_dev_opaque->attached_buffers_cnt) return 0; - return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, 0); + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { + buffer = iio_dev_opaque->attached_buffers[i]; + ret = __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, i); + if (ret) { + unwind_idx = i; + goto error_unwind_sysfs_and_mask; + } + } + + return 0; + +error_unwind_sysfs_and_mask: + for (; unwind_idx >= 0; unwind_idx--) { + buffer = iio_dev_opaque->attached_buffers[unwind_idx]; + __iio_buffer_free_sysfs_and_mask(buffer); + } + kfree(iio_dev_opaque->attached_buffers); + return ret; } -void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) +void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) { - struct iio_buffer *buffer = indio_dev->buffer; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer *buffer; + int i; - if (!buffer) + if (!iio_dev_opaque->attached_buffers_cnt) return; iio_buffer_unregister_legacy_sysfs_groups(indio_dev); - __iio_buffer_free_sysfs_and_mask(buffer); + for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) { + buffer = iio_dev_opaque->attached_buffers[i]; + __iio_buffer_free_sysfs_and_mask(buffer); + } + + kfree(iio_dev_opaque->attached_buffers); } /** @@ -1600,13 +1640,35 @@ EXPORT_SYMBOL_GPL(iio_buffer_put); * @indio_dev: The device the buffer should be attached to * @buffer: The buffer to attach to the device * + * Return 0 if successful, negative if error. + * * This function attaches a buffer to a IIO device. The buffer stays attached to - * the device until the device is freed. The function should only be called at - * most once per device. + * the device until the device is freed. For legacy reasons, the first attached + * buffer will also be assigned to 'indio_dev->buffer'. */ -void iio_device_attach_buffer(struct iio_dev *indio_dev, - struct iio_buffer *buffer) +int iio_device_attach_buffer(struct iio_dev *indio_dev, + struct iio_buffer *buffer) { - indio_dev->buffer = iio_buffer_get(buffer); + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_buffer **new, **old = iio_dev_opaque->attached_buffers; + unsigned int cnt = iio_dev_opaque->attached_buffers_cnt; + + cnt++; + + new = krealloc(old, sizeof(*new) * cnt, GFP_KERNEL); + if (!new) + return -ENOMEM; + iio_dev_opaque->attached_buffers = new; + + buffer = iio_buffer_get(buffer); + + /* first buffer is legacy; attach it to the IIO device directly */ + if (!indio_dev->buffer) + indio_dev->buffer = buffer; + + iio_dev_opaque->attached_buffers[cnt - 1] = buffer; + iio_dev_opaque->attached_buffers_cnt = cnt; + + return 0; } EXPORT_SYMBOL_GPL(iio_device_attach_buffer); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index b96acfe13e92..1645c739c44f 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1585,7 +1585,7 @@ static void iio_dev_release(struct device *device) iio_device_unregister_eventset(indio_dev); iio_device_unregister_sysfs(indio_dev); - iio_buffer_put(indio_dev->buffer); + iio_buffers_put(indio_dev); ida_simple_remove(&iio_ida, indio_dev->id); kfree(iio_dev_opaque); @@ -1862,7 +1862,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) iio_device_register_debugfs(indio_dev); - ret = iio_buffer_alloc_sysfs_and_mask(indio_dev); + ret = iio_buffers_alloc_sysfs_and_mask(indio_dev); if (ret) { dev_err(indio_dev->dev.parent, "Failed to create buffer sysfs interfaces\n"); @@ -1888,12 +1888,12 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) indio_dev->setup_ops == NULL) indio_dev->setup_ops = &noop_ring_setup_ops; - if (indio_dev->buffer) + if (iio_dev_opaque->attached_buffers_cnt) cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); else if (iio_dev_opaque->event_interface) cdev_init(&indio_dev->chrdev, &iio_event_fileops); - if (indio_dev->buffer || iio_dev_opaque->event_interface) { + if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) { indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); indio_dev->chrdev.owner = this_mod; } @@ -1912,7 +1912,7 @@ error_unreg_eventset: error_free_sysfs: iio_device_unregister_sysfs(indio_dev); error_buffer_free_sysfs: - iio_buffer_free_sysfs_and_mask(indio_dev); + iio_buffers_free_sysfs_and_mask(indio_dev); error_unreg_debugfs: iio_device_unregister_debugfs(indio_dev); return ret; @@ -1946,7 +1946,7 @@ void iio_device_unregister(struct iio_dev *indio_dev) mutex_unlock(&indio_dev->info_exist_lock); - iio_buffer_free_sysfs_and_mask(indio_dev); + iio_buffers_free_sysfs_and_mask(indio_dev); } EXPORT_SYMBOL(iio_device_unregister); diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 8febc23f5f26..b6928ac5c63d 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -41,7 +41,7 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, const unsigned long *mask); -void iio_device_attach_buffer(struct iio_dev *indio_dev, - struct iio_buffer *buffer); +int iio_device_attach_buffer(struct iio_dev *indio_dev, + struct iio_buffer *buffer); #endif /* _IIO_BUFFER_GENERIC_H_ */ diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 41044320e581..768b90c64412 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -112,6 +112,9 @@ struct iio_buffer { /* @demux_bounce: Buffer for doing gather from incoming scan. */ void *demux_bounce; + /* @attached_entry: Entry in the devices list of buffers attached by the driver. */ + struct list_head attached_entry; + /* @buffer_list: Entry in the devices list of current buffers. */ struct list_head buffer_list; diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index 1a9310b0145f..b6ebc04af3e7 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -7,6 +7,8 @@ * struct iio_dev_opaque - industrial I/O device opaque information * @indio_dev: public industrial I/O device information * @event_interface: event chrdevs associated with interrupt lines + * @attached_buffers: array of buffers statically attached by the driver + * @attached_buffers_cnt: number of buffers in the array of statically attached buffers * @buffer_list: list of all buffers currently attached * @channel_attr_list: keep track of automatically created channel * attributes @@ -24,6 +26,8 @@ struct iio_dev_opaque { struct iio_dev indio_dev; struct iio_event_interface *event_interface; + struct iio_buffer **attached_buffers; + unsigned int attached_buffers_cnt; struct list_head buffer_list; struct list_head channel_attr_list; struct attribute_group chan_attr_group; -- cgit v1.2.3 From f73f7f4da581875f9b1f2fb8ebd1ab15ed634488 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 15 Feb 2021 12:40:39 +0200 Subject: iio: buffer: add ioctl() to support opening extra buffers for IIO device With this change, an ioctl() call is added to open a character device for a buffer. The ioctl() number is 'i' 0x91, which follows the IIO_GET_EVENT_FD_IOCTL ioctl. The ioctl() will return an FD for the requested buffer index. The indexes are the same from the /sys/iio/devices/iio:deviceX/bufferY (i.e. the Y variable). Since there doesn't seem to be a sane way to return the FD for buffer0 to be the same FD for the /dev/iio:deviceX, this ioctl() will return another FD for buffer0 (or the first buffer). This duplicate FD will be able to access the same buffer object (for buffer0) as accessing directly the /dev/iio:deviceX chardev. Also, there is no IIO_BUFFER_GET_BUFFER_COUNT ioctl() implemented, as the index for each buffer (and the count) can be deduced from the '/sys/bus/iio/devices/iio:deviceX/bufferY' folders (i.e the number of bufferY folders). Used following C code to test this: ------------------------------------------------------------------- #include #include #include #include #include #define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int) int main(int argc, char *argv[]) { int fd; int fd1; int ret; if ((fd = open("/dev/iio:device0", O_RDWR))<0) { fprintf(stderr, "Error open() %d errno %d\n",fd, errno); return -1; } fprintf(stderr, "Using FD %d\n", fd); fd1 = atoi(argv[1]); ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &fd1); if (ret < 0) { fprintf(stderr, "Error for buffer %d ioctl() %d errno %d\n", fd1, ret, errno); close(fd); return -1; } fprintf(stderr, "Got FD %d\n", fd1); close(fd1); close(fd); return 0; } ------------------------------------------------------------------- Results are: ------------------------------------------------------------------- # ./test 0 Using FD 3 Got FD 4 # ./test 1 Using FD 3 Got FD 4 # ./test 2 Using FD 3 Got FD 4 # ./test 3 Using FD 3 Got FD 4 # ls /sys/bus/iio/devices/iio\:device0 buffer buffer0 buffer1 buffer2 buffer3 dev in_voltage_sampling_frequency in_voltage_scale in_voltage_scale_available name of_node power scan_elements subsystem uevent ------------------------------------------------------------------- iio:device0 has some fake kfifo buffers attached to an IIO device. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210215104043.91251-21-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/iio_core.h | 12 ++-- drivers/iio/industrialio-buffer.c | 144 ++++++++++++++++++++++++++++++++++++-- include/linux/iio/buffer_impl.h | 5 ++ include/linux/iio/iio-opaque.h | 2 + include/uapi/linux/iio/buffer.h | 10 +++ 5 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 include/uapi/linux/iio/buffer.h (limited to 'include/linux') diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 7990c759f1f5..062fe16c6c49 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -64,16 +64,16 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); #ifdef CONFIG_IIO_BUFFER struct poll_table_struct; -__poll_t iio_buffer_poll(struct file *filp, - struct poll_table_struct *wait); -ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, - size_t n, loff_t *f_ps); +__poll_t iio_buffer_poll_wrapper(struct file *filp, + struct poll_table_struct *wait); +ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps); int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev); void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev); -#define iio_buffer_poll_addr (&iio_buffer_poll) -#define iio_buffer_read_outer_addr (&iio_buffer_read_outer) +#define iio_buffer_poll_addr (&iio_buffer_poll_wrapper) +#define iio_buffer_read_outer_addr (&iio_buffer_read_wrapper) void iio_disable_all_buffers(struct iio_dev *indio_dev); void iio_buffer_wakeup_poll(struct iio_dev *indio_dev); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index b60c2e66bd1c..a48e494a9fbb 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -9,9 +9,11 @@ * - Better memory allocation techniques? * - Alternative access techniques? */ +#include #include #include #include +#include #include #include #include @@ -89,7 +91,7 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, } /** - * iio_buffer_read_outer() - chrdev read for buffer access + * iio_buffer_read() - chrdev read for buffer access * @filp: File structure pointer for the char device * @buf: Destination buffer for iio buffer read * @n: First n bytes to read @@ -101,8 +103,8 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, * Return: negative values corresponding to error codes or ret != 0 * for ending the reading activity **/ -ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, - size_t n, loff_t *f_ps) +static ssize_t iio_buffer_read(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps) { struct iio_dev_buffer_pair *ib = filp->private_data; struct iio_buffer *rb = ib->buffer; @@ -168,8 +170,8 @@ ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, * Return: (EPOLLIN | EPOLLRDNORM) if data is available for reading * or 0 for other cases */ -__poll_t iio_buffer_poll(struct file *filp, - struct poll_table_struct *wait) +static __poll_t iio_buffer_poll(struct file *filp, + struct poll_table_struct *wait) { struct iio_dev_buffer_pair *ib = filp->private_data; struct iio_buffer *rb = ib->buffer; @@ -184,6 +186,32 @@ __poll_t iio_buffer_poll(struct file *filp, return 0; } +ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf, + size_t n, loff_t *f_ps) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + + /* check if buffer was opened through new API */ + if (test_bit(IIO_BUSY_BIT_POS, &rb->flags)) + return -EBUSY; + + return iio_buffer_read(filp, buf, n, f_ps); +} + +__poll_t iio_buffer_poll_wrapper(struct file *filp, + struct poll_table_struct *wait) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + struct iio_buffer *rb = ib->buffer; + + /* check if buffer was opened through new API */ + if (test_bit(IIO_BUSY_BIT_POS, &rb->flags)) + return 0; + + return iio_buffer_poll(filp, wait); +} + /** * iio_buffer_wakeup_poll - Wakes up the buffer waitqueue * @indio_dev: The IIO device @@ -1344,6 +1372,96 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) kfree(iio_dev_opaque->legacy_scan_el_group.attrs); } +static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) +{ + struct iio_dev_buffer_pair *ib = filep->private_data; + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_buffer *buffer = ib->buffer; + + wake_up(&buffer->pollq); + + kfree(ib); + clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); + iio_device_put(indio_dev); + + return 0; +} + +static const struct file_operations iio_buffer_chrdev_fileops = { + .owner = THIS_MODULE, + .llseek = noop_llseek, + .read = iio_buffer_read, + .poll = iio_buffer_poll, + .release = iio_buffer_chrdev_release, +}; + +static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + int __user *ival = (int __user *)arg; + struct iio_dev_buffer_pair *ib; + struct iio_buffer *buffer; + int fd, idx, ret; + + if (copy_from_user(&idx, ival, sizeof(idx))) + return -EFAULT; + + if (idx >= iio_dev_opaque->attached_buffers_cnt) + return -ENODEV; + + iio_device_get(indio_dev); + + buffer = iio_dev_opaque->attached_buffers[idx]; + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &buffer->flags)) { + ret = -EBUSY; + goto error_iio_dev_put; + } + + ib = kzalloc(sizeof(*ib), GFP_KERNEL); + if (!ib) { + ret = -ENOMEM; + goto error_clear_busy_bit; + } + + ib->indio_dev = indio_dev; + ib->buffer = buffer; + + fd = anon_inode_getfd("iio:buffer", &iio_buffer_chrdev_fileops, + ib, O_RDWR | O_CLOEXEC); + if (fd < 0) { + ret = fd; + goto error_free_ib; + } + + if (copy_to_user(ival, &fd, sizeof(fd))) { + put_unused_fd(fd); + ret = -EFAULT; + goto error_free_ib; + } + + return fd; + +error_free_ib: + kfree(ib); +error_clear_busy_bit: + clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); +error_iio_dev_put: + iio_device_put(indio_dev); + return ret; +} + +static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case IIO_BUFFER_GET_FD_IOCTL: + return iio_device_buffer_getfd(indio_dev, arg); + default: + return IIO_IOCTL_UNHANDLED; + } +} + static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, struct iio_dev *indio_dev, int index) @@ -1473,6 +1591,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) struct iio_buffer *buffer; int unwind_idx; int ret, i; + size_t sz; channels = indio_dev->channels; if (channels) { @@ -1494,6 +1613,18 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) goto error_unwind_sysfs_and_mask; } } + unwind_idx = iio_dev_opaque->attached_buffers_cnt - 1; + + sz = sizeof(*(iio_dev_opaque->buffer_ioctl_handler)); + iio_dev_opaque->buffer_ioctl_handler = kzalloc(sz, GFP_KERNEL); + if (!iio_dev_opaque->buffer_ioctl_handler) { + ret = -ENOMEM; + goto error_unwind_sysfs_and_mask; + } + + iio_dev_opaque->buffer_ioctl_handler->ioctl = iio_device_buffer_ioctl; + iio_device_ioctl_handler_register(indio_dev, + iio_dev_opaque->buffer_ioctl_handler); return 0; @@ -1515,6 +1646,9 @@ void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) if (!iio_dev_opaque->attached_buffers_cnt) return; + iio_device_ioctl_handler_unregister(iio_dev_opaque->buffer_ioctl_handler); + kfree(iio_dev_opaque->buffer_ioctl_handler); + iio_buffer_unregister_legacy_sysfs_groups(indio_dev); for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) { diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 768b90c64412..245b32918ae1 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -6,6 +6,8 @@ #ifdef CONFIG_IIO_BUFFER +#include + struct iio_dev; struct iio_buffer; @@ -72,6 +74,9 @@ struct iio_buffer { /** @length: Number of datums in buffer. */ unsigned int length; + /** @flags: File ops flags including busy flag. */ + unsigned long flags; + /** @bytes_per_datum: Size of individual datum including timestamp. */ size_t bytes_per_datum; diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index b6ebc04af3e7..32addd5e790e 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -9,6 +9,7 @@ * @event_interface: event chrdevs associated with interrupt lines * @attached_buffers: array of buffers statically attached by the driver * @attached_buffers_cnt: number of buffers in the array of statically attached buffers + * @buffer_ioctl_handler: ioctl() handler for this IIO device's buffer interface * @buffer_list: list of all buffers currently attached * @channel_attr_list: keep track of automatically created channel * attributes @@ -28,6 +29,7 @@ struct iio_dev_opaque { struct iio_event_interface *event_interface; struct iio_buffer **attached_buffers; unsigned int attached_buffers_cnt; + struct iio_ioctl_handler *buffer_ioctl_handler; struct list_head buffer_list; struct list_head channel_attr_list; struct attribute_group chan_attr_group; diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h new file mode 100644 index 000000000000..13939032b3f6 --- /dev/null +++ b/include/uapi/linux/iio/buffer.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* industrial I/O buffer definitions needed both in and out of kernel + */ + +#ifndef _UAPI_IIO_BUFFER_H_ +#define _UAPI_IIO_BUFFER_H_ + +#define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int) + +#endif /* _UAPI_IIO_BUFFER_H_ */ -- cgit v1.2.3 From 0e41fd515f94dcfcc24b6e510d29528431e46f60 Mon Sep 17 00:00:00 2001 From: Ye Xiang Date: Mon, 1 Feb 2021 13:49:20 +0800 Subject: iio: hid-sensors: Move get sensitivity attribute to hid-sensor-common No functional change has been made with this patch. The main intent here is to reduce code repetition of getting sensitivity attribute. In the current implementation, sensor_hub_input_get_attribute_info() is called from multiple drivers to get attribute info for sensitivity field. Moving this to common place will avoid code repetition. Signed-off-by: Ye Xiang Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210201054921.18214-2-xiang.ye@intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 23 ++++++---------- .../iio/common/hid-sensors/hid-sensor-attributes.c | 17 +++++++++++- drivers/iio/gyro/hid-sensor-gyro-3d.c | 19 +++++-------- drivers/iio/humidity/hid-sensor-humidity.c | 16 +++++------ drivers/iio/light/hid-sensor-als.c | 19 +++++-------- drivers/iio/light/hid-sensor-prox.c | 27 ++++++------------ drivers/iio/magnetometer/hid-sensor-magn-3d.c | 32 +++++++--------------- drivers/iio/orientation/hid-sensor-incl-3d.c | 19 +++++-------- drivers/iio/orientation/hid-sensor-rotation.c | 23 ++++++---------- .../iio/position/hid-sensor-custom-intel-hinge.c | 20 +++++--------- drivers/iio/pressure/hid-sensor-press.c | 19 +++++-------- drivers/iio/temperature/hid-sensor-temperature.c | 16 +++++------ drivers/rtc/rtc-hid-sensor-time.c | 4 ++- include/linux/hid-sensor-hub.h | 4 ++- 14 files changed, 107 insertions(+), 151 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 5d63ed19e6e2..2f9465cb382f 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -43,6 +43,10 @@ static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ACCEL_Z_AXIS }; +static const u32 accel_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ACCELERATION, +}; + /* Channel definitions */ static const struct iio_chan_spec accel_3d_channels[] = { { @@ -317,18 +321,6 @@ static int accel_3d_parse_report(struct platform_device *pdev, &st->accel[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ACCELERATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return ret; } @@ -366,8 +358,11 @@ static int hid_accel_3d_probe(struct platform_device *pdev) channel_size = sizeof(gravity_channels); indio_dev->num_channels = ARRAY_SIZE(gravity_channels); } - ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &accel_state->common_attributes); + ret = hid_sensor_parse_common_attributes(hsdev, + hsdev->usage, + &accel_state->common_attributes, + accel_3d_sensitivity_addresses, + ARRAY_SIZE(accel_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 5b822a4298a0..d349ace2e33f 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -448,12 +448,15 @@ EXPORT_SYMBOL(hid_sensor_batch_mode_supported); int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, - struct hid_sensor_common *st) + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len) { struct hid_sensor_hub_attribute_info timestamp; s32 value; int ret; + int i; hid_sensor_get_reporting_interval(hsdev, usage_id, st); @@ -475,6 +478,18 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, &st->sensitivity); + /* + * Set Sensitivity field ids, when there is no individual modifier, will + * check absolute sensitivity of data field + */ + for (i = 0; i < sensitivity_addresses_len && st->sensitivity.index < 0; i++) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + sensitivity_addresses[i], + &st->sensitivity); + } + st->raw_hystersis = -1; sensor_hub_input_get_attribute_info(hsdev, diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index fb0d678ece1a..dad26ee4fd1f 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -45,6 +45,10 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS }; +static const u32 gryo_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, +}; + /* Channel definitions */ static const struct iio_chan_spec gyro_3d_channels[] = { { @@ -271,17 +275,6 @@ static int gyro_3d_parse_report(struct platform_device *pdev, &st->gyro[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -305,7 +298,9 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_GYRO_3D, - &gyro_state->common_attributes); + &gyro_state->common_attributes, + gryo_3d_sensitivity_addresses, + ARRAY_SIZE(gryo_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index 52f605114ef7..ec88ae3f233d 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -22,6 +22,10 @@ struct hid_humidity_state { int value_offset; }; +static const u32 humidity_sensitivity_addresses[] = { + HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, +}; + /* Channel definitions */ static const struct iio_chan_spec humidity_channels[] = { { @@ -174,14 +178,6 @@ static int humidity_parse_report(struct platform_device *pdev, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, - &st->common_attributes.sensitivity); - return ret; } @@ -210,7 +206,9 @@ static int hid_humidity_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_HUMIDITY, - &humid_st->common_attributes); + &humid_st->common_attributes, + humidity_sensitivity_addresses, + ARRAY_SIZE(humidity_sensitivity_addresses)); if (ret) return ret; diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 4093f2353d95..8bf6e9e0a0e0 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -39,6 +39,10 @@ struct als_state { s64 timestamp; }; +static const u32 als_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_LIGHT, +}; + /* Channel definitions */ static const struct iio_chan_spec als_channels[] = { { @@ -252,17 +256,6 @@ static int als_parse_report(struct platform_device *pdev, &st->als_illum, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_LIGHT, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -285,7 +278,9 @@ static int hid_als_probe(struct platform_device *pdev) als_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, - &als_state->common_attributes); + &als_state->common_attributes, + als_sensitivity_addresses, + ARRAY_SIZE(als_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 330cf359e0b8..4ab285a418d5 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -25,6 +25,11 @@ struct prox_state { u32 human_presence; }; +static const u32 prox_sensitivity_addresses[] = { + HID_USAGE_SENSOR_HUMAN_PRESENCE, + HID_USAGE_SENSOR_DATA_PRESENCE, +}; + /* Channel definitions */ static const struct iio_chan_spec prox_channels[] = { { @@ -216,24 +221,6 @@ static int prox_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index, st->prox_attr.report_id); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_PRESENCE, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_HUMAN_PRESENCE, - &st->common_attributes.sensitivity); - return ret; } @@ -257,7 +244,9 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, - &prox_state->common_attributes); + &prox_state->common_attributes, + prox_sensitivity_addresses, + ARRAY_SIZE(prox_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index fa48044b7f5b..b78691523dd4 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -62,6 +62,11 @@ static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_TIME_TIMESTAMP, }; +static const u32 magn_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX, +}; + /* Channel definitions */ static const struct iio_chan_spec magn_3d_channels[] = { { @@ -448,27 +453,6 @@ static int magn_3d_parse_report(struct platform_device *pdev, &st->rot_attr.scale_pre_decml, &st->rot_attr.scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->magn_flux_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->magn_flux_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->magn_flux_attributes.sensitivity.index, - st->magn_flux_attributes.sensitivity.report_id); - } - if (st->magn_flux_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX, - &st->magn_flux_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->magn_flux_attributes.sensitivity.index, - st->magn_flux_attributes.sensitivity.report_id); - } if (st->rot_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -507,12 +491,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_COMPASS_3D, - &magn_state->magn_flux_attributes); + &magn_state->magn_flux_attributes, + magn_3d_sensitivity_addresses, + ARRAY_SIZE(magn_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; } magn_state->rot_attributes = magn_state->magn_flux_attributes; + /* sensitivity of rot_attribute is not the same as magn_flux_attributes */ + magn_state->rot_attributes.sensitivity.index = -1; ret = magn_3d_parse_report(pdev, hsdev, &channels, &chan_count, diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 52ebef30f9be..6e69f6e673cc 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -47,6 +47,10 @@ static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ORIENT_TILT_Z }; +static const u32 incl_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, +}; + /* Channel definitions */ static const struct iio_chan_spec incl_3d_channels[] = { { @@ -291,17 +295,6 @@ static int incl_3d_parse_report(struct platform_device *pdev, &st->incl[CHANNEL_SCAN_INDEX_X], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -327,7 +320,9 @@ static int hid_incl_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D, - &incl_state->common_attributes); + &incl_state->common_attributes, + incl_3d_sensitivity_addresses, + ARRAY_SIZE(incl_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index c087d8f72a54..baa2ee353ba4 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -31,6 +31,10 @@ struct dev_rot_state { s64 timestamp; }; +static const u32 rotation_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ORIENTATION, +}; + /* Channel definitions */ static const struct iio_chan_spec dev_rot_channels[] = { { @@ -221,18 +225,6 @@ static int dev_rot_parse_report(struct platform_device *pdev, &st->quaternion, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return 0; } @@ -270,8 +262,11 @@ static int hid_dev_rot_probe(struct platform_device *pdev) return -EINVAL; } - ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &rot_state->common_attributes); + ret = hid_sensor_parse_common_attributes(hsdev, + hsdev->usage, + &rot_state->common_attributes, + rotation_sensitivity_addresses, + ARRAY_SIZE(rotation_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 64a7fa7db6af..fd77e7ee87f3 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -47,6 +47,10 @@ struct hinge_state { u64 timestamp; }; +static const u32 hinge_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), +}; + /* Channel definitions */ static const struct iio_chan_spec hinge_channels[] = { { @@ -251,18 +255,6 @@ static int hinge_parse_report(struct platform_device *pdev, &st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE], &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } - return ret; } @@ -289,7 +281,9 @@ static int hid_hinge_probe(struct platform_device *pdev) st->labels[i] = hinge_labels[i]; ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, - &st->common_attributes); + &st->common_attributes, + hinge_sensitivity_addresses, + ARRAY_SIZE(hinge_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 5c458788f346..8cac2c94e75a 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -29,6 +29,10 @@ struct press_state { int value_offset; }; +static const u32 press_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, +}; + /* Channel definitions */ static const struct iio_chan_spec press_channels[] = { { @@ -225,17 +229,6 @@ static int press_parse_report(struct platform_device *pdev, &st->press_attr, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -260,7 +253,9 @@ static int hid_press_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PRESSURE, - &press_state->common_attributes); + &press_state->common_attributes, + press_sensitivity_addresses, + ARRAY_SIZE(press_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 81688f1b932f..e3d38cbcf354 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -22,6 +22,10 @@ struct temperature_state { int value_offset; }; +static const u32 temperature_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, +}; + /* Channel definitions */ static const struct iio_chan_spec temperature_channels[] = { { @@ -171,14 +175,6 @@ static int temperature_parse_report(struct platform_device *pdev, &st->temperature_attr, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, - &st->common_attributes.sensitivity); - return ret; } @@ -207,7 +203,9 @@ static int hid_temperature_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_TEMPERATURE, - &temp_st->common_attributes); + &temp_st->common_attributes, + temperature_sensitivity_addresses, + ARRAY_SIZE(temperature_sensitivity_addresses)); if (ret) return ret; diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 1b42ee0758d2..47cd12db2356 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -238,7 +238,9 @@ static int hid_time_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_TIME, - &time_state->common_attributes); + &time_state->common_attributes, + NULL, + 0); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes!\n"); return ret; diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 763802b2b8f9..637ec53a98a1 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -248,7 +248,9 @@ static inline int hid_sensor_convert_exponent(int unit_expo) int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, - struct hid_sensor_common *st); + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len); int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, -- cgit v1.2.3 From 1c71a2863a0c56123e5a67880cf658083c0a0b1e Mon Sep 17 00:00:00 2001 From: Ye Xiang Date: Sun, 7 Feb 2021 15:00:46 +0800 Subject: iio: Add relative sensitivity support Some hid sensors may use relative sensitivity such as als sensor. This patch adds relative sensitivity checking for all hid sensors. Signed-off-by: Ye Xiang Acked-by: Jiri Kosina Link: https://lore.kernel.org/r/20210207070048.23935-2-xiang.ye@intel.com Signed-off-by: Jonathan Cameron --- .../iio/common/hid-sensors/hid-sensor-attributes.c | 74 ++++++++++++++++++++-- drivers/iio/industrialio-core.c | 1 + include/linux/hid-sensor-hub.h | 5 ++ include/linux/hid-sensor-ids.h | 1 + include/linux/iio/types.h | 1 + 5 files changed, 78 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index d349ace2e33f..cb52b4fd6bf7 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -263,6 +263,29 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, } EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value); +int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, + int *val2) +{ + s32 value; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) { + *val1 = *val2 = 0; + return -EINVAL; + } + + convert_from_vtf_format(value, st->sensitivity_rel.size, + st->sensitivity_rel.unit_expo, val1, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_read_raw_hyst_rel_value); + + int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2) { @@ -294,6 +317,37 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, } EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); +int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, + int val1, int val2) +{ + s32 value; + int ret; + + if (val1 < 0 || val2 < 0) + return -EINVAL; + + value = convert_to_vtf_format(st->sensitivity_rel.size, + st->sensitivity_rel.unit_expo, + val1, val2); + ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) + return -EINVAL; + + ret = sensor_hub_get_feature(st->hsdev, + st->sensitivity_rel.report_id, + st->sensitivity_rel.index, sizeof(value), + &value); + if (ret < 0 || value < 0) + return -EINVAL; + + st->raw_hystersis = value; + + return 0; +} +EXPORT_SYMBOL(hid_sensor_write_raw_hyst_rel_value); + /* * This fuction applies the unit exponent to the scale. * For example: @@ -478,16 +532,28 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, &st->sensitivity); + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT, + &st->sensitivity_rel); /* * Set Sensitivity field ids, when there is no individual modifier, will - * check absolute sensitivity of data field + * check absolute sensitivity and relative sensitivity of data field */ - for (i = 0; i < sensitivity_addresses_len && st->sensitivity.index < 0; i++) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, + for (i = 0; i < sensitivity_addresses_len; i++) { + if (st->sensitivity.index < 0) + sensor_hub_input_get_attribute_info( + hsdev, HID_FEATURE_REPORT, usage_id, HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | sensitivity_addresses[i], &st->sensitivity); + + if (st->sensitivity_rel.index < 0) + sensor_hub_input_get_attribute_info( + hsdev, HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT | + sensitivity_addresses[i], + &st->sensitivity_rel); } st->raw_hystersis = -1; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2e2970f3e21c..cb2735d2ae4b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -157,6 +157,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis", + [IIO_CHAN_INFO_HYSTERESIS_RELATIVE] = "hysteresis_relative", [IIO_CHAN_INFO_INT_TIME] = "integration_time", [IIO_CHAN_INFO_ENABLE] = "en", [IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight", diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 637ec53a98a1..c27329e2a5ad 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -231,6 +231,7 @@ struct hid_sensor_common { struct hid_sensor_hub_attribute_info report_state; struct hid_sensor_hub_attribute_info power_state; struct hid_sensor_hub_attribute_info sensitivity; + struct hid_sensor_hub_attribute_info sensitivity_rel; struct hid_sensor_hub_attribute_info report_latency; struct work_struct work; }; @@ -253,8 +254,12 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 sensitivity_addresses_len); int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2); +int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, int val1, + int val2); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, int *val1, int *val2); +int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, + int *val1, int *val2); int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, int val1, int val2); int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 3bbdbccc5805..ac631159403a 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -149,6 +149,7 @@ /* Per data field properties */ #define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 +#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT 0xE000 /* Power state enumerations */ #define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850 diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 1e3ed6f55bca..5aa7f66d4345 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -50,6 +50,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_PHASE, IIO_CHAN_INFO_HARDWAREGAIN, IIO_CHAN_INFO_HYSTERESIS, + IIO_CHAN_INFO_HYSTERESIS_RELATIVE, IIO_CHAN_INFO_INT_TIME, IIO_CHAN_INFO_ENABLE, IIO_CHAN_INFO_CALIBHEIGHT, -- cgit v1.2.3 From aa29cf932fb345e111cd7fef04320846fa73e372 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 19 Feb 2021 11:01:34 +0200 Subject: iio: adc: adi-axi-adc: fix typo in doc-string The channels are of type iio_chan_spec, not axi_adc_chan_spec. They were in some earlier version, but forgot to rename in the doc-string. Fixes: ef04070692a21 ("iio: adc: adi-axi-adc: add support for AXI ADC IP core") Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210219090134.48057-1-alexandru.ardelean@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/adc/adi-axi-adc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h index c5d48e1c2d36..52620e5b8052 100644 --- a/include/linux/iio/adc/adi-axi-adc.h +++ b/include/linux/iio/adc/adi-axi-adc.h @@ -15,7 +15,7 @@ struct iio_chan_spec; * struct adi_axi_adc_chip_info - Chip specific information * @name Chip name * @id Chip ID (usually product ID) - * @channels Channel specifications of type @struct axi_adc_chan_spec + * @channels Channel specifications of type @struct iio_chan_spec * @num_channels Number of @channels * @scale_table Supported scales by the chip; tuples of 2 ints * @num_scales Number of scales in the table -- cgit v1.2.3 From 15aacc980dcb326ef33dfc32772faea1067f9178 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 18 Feb 2021 12:40:39 +0100 Subject: iio: adis: add helpers for locking Add some helpers to lock and unlock the device. As this is such a simple change, we update all the users that were using the lock already in this patch. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210218114039.216091-5-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 22 ++++++++++------------ drivers/iio/imu/adis16475.c | 10 +++++----- drivers/iio/imu/adis16480.c | 15 +++++++-------- include/linux/iio/imu/adis.h | 10 ++++++++++ 4 files changed, 32 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 54af2ed664f6..b1ec14bf439f 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -505,7 +505,6 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; int ret, sps; switch (info) { @@ -518,18 +517,18 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, * Need to cache values so we can update if the frequency * changes. */ - mutex_lock(slock); + adis_dev_lock(&st->adis); st->filt_int = val; /* Work out update to current value */ sps = st->variant->get_freq(st); if (sps < 0) { - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return sps; } ret = __adis16400_set_filter(indio_dev, sps, val * 1000 + val2 / 1000); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; case IIO_CHAN_INFO_SAMP_FREQ: sps = val * 1000 + val2 / 1000; @@ -537,9 +536,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, if (sps <= 0) return -EINVAL; - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = st->variant->set_freq(st, sps); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; default: return -EINVAL; @@ -550,7 +549,6 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; int16_t val16; int ret; @@ -606,17 +604,17 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_offset; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(slock); + adis_dev_lock(&st->adis); /* Need both the number of taps and the sampling frequency */ ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret) { - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; } ret = st->variant->get_freq(st); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); if (ret) return ret; ret /= adis16400_3db_divisors[val16 & 0x07]; @@ -624,9 +622,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = st->variant->get_freq(st); - mutex_unlock(slock); + adis_dev_unlock(&st->adis); if (ret) return ret; *val = ret / 1000; diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 5759cd8ffbef..8f6bea4b6608 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -263,7 +263,7 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq) u16 dec; u32 sample_rate = st->clk_freq; - mutex_lock(&st->adis.state_lock); + adis_dev_lock(&st->adis); if (st->sync_mode == ADIS16475_SYNC_SCALED) { u16 sync_scale; @@ -279,13 +279,13 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq) if (ret) goto error; - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); *freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1); return 0; error: - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); return ret; } @@ -298,7 +298,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) if (!freq) return -EINVAL; - mutex_lock(&st->adis.state_lock); + adis_dev_lock(&st->adis); /* * When using sync scaled mode, the input clock needs to be scaled so that we have * an IMU sample rate between (optimally) 1900 and 2100. After this, we can use the @@ -366,7 +366,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) return 0; error: - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); return ret; } diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index c41b8ef1e250..f81b86690b76 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -329,7 +329,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t == 0) return -EINVAL; - mutex_lock(&st->adis.state_lock); + adis_dev_lock(&st->adis); /* * When using PPS mode, the input clock needs to be scaled so that we have an IMU * sample rate between (optimally) 4000 and 4250. After this, we can use the @@ -386,7 +386,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); error: - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); return ret; } @@ -397,7 +397,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) int ret; unsigned int freq, sample_rate = st->clk_freq; - mutex_lock(&st->adis.state_lock); + adis_dev_lock(&st->adis); if (st->clk_mode == ADIS16480_CLK_PPS) { u16 sync_scale; @@ -413,7 +413,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) if (ret) goto error; - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1)); @@ -422,7 +422,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) return IIO_VAL_INT_PLUS_MICRO; error: - mutex_unlock(&st->adis.state_lock); + adis_dev_unlock(&st->adis); return ret; } @@ -598,7 +598,6 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int freq) { struct adis16480 *st = iio_priv(indio_dev); - struct mutex *slock = &st->adis.state_lock; unsigned int enable_mask, offset, reg; unsigned int diff, best_diff; unsigned int i, best_freq; @@ -609,7 +608,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, offset = ad16480_filter_data[chan->scan_index][1]; enable_mask = BIT(offset + 2); - mutex_lock(slock); + adis_dev_lock(&st->adis); ret = __adis_read_reg_16(&st->adis, reg, &val); if (ret) @@ -637,7 +636,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, ret = __adis_write_reg_16(&st->adis, reg, val); out_unlock: - mutex_unlock(slock); + adis_dev_unlock(&st->adis); return ret; } diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 04e96d688ba9..f9b728d490b1 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -428,6 +428,16 @@ static inline int adis_initial_startup(struct adis *adis) return ret; } +static inline void adis_dev_lock(struct adis *adis) +{ + mutex_lock(&adis->state_lock); +} + +static inline void adis_dev_unlock(struct adis *adis) +{ + mutex_unlock(&adis->state_lock); +} + int adis_single_conversion(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int error_mask, int *val); -- cgit v1.2.3 From 374be283ad429bf703d9036b799331dda793aeb7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 10 Feb 2021 18:45:59 -0800 Subject: platform/chrome: cros_ec: Add SW_FRONT_PROXIMITY MKBP define Some cros ECs support a front proximity MKBP event via 'EC_MKBP_FRONT_PROXIMITY'. Add this define so it can be used in a future patch. Cc: Dmitry Torokhov Cc: Benson Leung Cc: Guenter Roeck Cc: Douglas Anderson Cc: Gwendal Grignou Acked-by: Enric Balletbo i Serra Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20210211024601.1963379-2-swboyd@chromium.org Signed-off-by: Jonathan Cameron --- include/linux/platform_data/cros_ec_commands.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 5ff8597ceabd..6035d9a98fb8 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -3467,6 +3467,7 @@ struct ec_response_get_next_event_v1 { #define EC_MKBP_LID_OPEN 0 #define EC_MKBP_TABLET_MODE 1 #define EC_MKBP_BASE_ATTACHED 2 +#define EC_MKBP_FRONT_PROXIMITY 3 /* Run keyboard factory test scanning */ #define EC_CMD_KEYBOARD_FACTORY_TEST 0x0068 -- cgit v1.2.3 From 995071d36bb9804b644265450142fcb91c427ee8 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Tue, 9 Mar 2021 11:36:13 -0800 Subject: iio: set default trig->dev.parent When allocated with [devm_]iio_trigger_alloc(), set trig device parent to the device the trigger is allocated for by default. It can always be reassigned in the probe routine. Change iio_trigger_alloc() API to add the device pointer to be coherent with devm_iio_trigger_alloc, using similar interface to iio_device_alloc(). Signed-off-by: Gwendal Grignou Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210309193620.2176163-2-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 3 +- drivers/iio/adc/ad_sigma_delta.c | 6 ++-- drivers/iio/adc/at91_adc.c | 3 +- .../iio/common/hid-sensors/hid-sensor-trigger.c | 4 +-- drivers/iio/common/st_sensors/st_sensors_trigger.c | 4 +-- drivers/iio/gyro/itg3200_buffer.c | 3 +- drivers/iio/industrialio-trigger.c | 34 +++++++++++++++------- drivers/iio/trigger/iio-trig-hrtimer.c | 2 +- drivers/iio/trigger/iio-trig-interrupt.c | 2 +- drivers/iio/trigger/iio-trig-loop.c | 2 +- drivers/iio/trigger/iio-trig-sysfs.c | 3 +- include/linux/iio/iio.h | 2 +- include/linux/iio/trigger.h | 3 +- 13 files changed, 40 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 71f85a3e525b..b8a7469cdae4 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1044,7 +1044,7 @@ static int bma180_probe(struct i2c_client *client, indio_dev->info = &bma180_info; if (client->irq > 0) { - data->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!data->trig) { ret = -ENOMEM; @@ -1059,7 +1059,6 @@ static int bma180_probe(struct i2c_client *client, goto err_trigger_free; } - data->trig->dev.parent = dev; data->trig->ops = &bma180_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); indio_dev->trig = iio_trigger_get(data->trig); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 3a6f239d4acc..9289812c0a94 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -475,8 +475,9 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); int ret; - sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); + sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev, + "%s-dev%d", indio_dev->name, + indio_dev->id); if (sigma_delta->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -496,7 +497,6 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) sigma_delta->irq_dis = true; disable_irq_nosync(sigma_delta->spi->irq); } - sigma_delta->trig->dev.parent = &sigma_delta->spi->dev; iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta); ret = iio_trigger_register(sigma_delta->trig); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 70750abb5dea..0b5f0c91d0d7 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -625,12 +625,11 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, struct iio_trigger *trig; int ret; - trig = iio_trigger_alloc("%s-dev%d-%s", idev->name, + trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name, idev->id, trigger->name); if (trig == NULL) return NULL; - trig->dev.parent = idev->dev.parent; iio_trigger_set_drvdata(trig, idev); trig->ops = &at91_adc_trigger_ops; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 064c32bec9c7..95ddccb44f1c 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -255,14 +255,14 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, return ret; } - trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id); + trig = iio_trigger_alloc(indio_dev->dev.parent, + "%s-dev%d", name, indio_dev->id); if (trig == NULL) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); ret = -ENOMEM; goto error_triggered_buffer_cleanup; } - trig->dev.parent = indio_dev->dev.parent; iio_trigger_set_drvdata(trig, attrb); trig->ops = &hid_sensor_trigger_ops; ret = iio_trigger_register(trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 2dbd2646e44e..0b511665dee5 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -123,7 +123,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, unsigned long irq_trig; int err; - sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); + sdata->trig = iio_trigger_alloc(sdata->dev, "%s-trigger", + indio_dev->name); if (sdata->trig == NULL) { dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n"); return -ENOMEM; @@ -131,7 +132,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, iio_trigger_set_drvdata(sdata->trig, indio_dev); sdata->trig->ops = trigger_ops; - sdata->trig->dev.parent = sdata->dev; irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq)); /* diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 1c3c1bd53374..af0aaa146f0c 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -113,7 +113,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) int ret; struct itg3200 *st = iio_priv(indio_dev); - st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) return -ENOMEM; @@ -127,7 +127,6 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) goto error_free_trig; - st->trig->dev.parent = &st->i2c->dev; st->trig->ops = &itg3200_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); ret = iio_trigger_register(st->trig); diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index a035d5c2a445..32ac1bec25e3 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -514,8 +514,10 @@ static void iio_trig_subirqunmask(struct irq_data *d) trig->subirqs[d->irq - trig->subirq_base].enabled = true; } -static __printf(1, 0) -struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs) +static __printf(2, 0) +struct iio_trigger *viio_trigger_alloc(struct device *parent, + const char *fmt, + va_list vargs) { struct iio_trigger *trig; int i; @@ -524,6 +526,7 @@ struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs) if (!trig) return NULL; + trig->dev.parent = parent; trig->dev.type = &iio_trig_type; trig->dev.bus = &iio_bus_type; device_initialize(&trig->dev); @@ -559,13 +562,23 @@ free_trig: return NULL; } -struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) +/** + * iio_trigger_alloc - Allocate a trigger + * @parent: Device to allocate iio_trigger for + * @fmt: trigger name format. If it includes format + * specifiers, the additional arguments following + * format are formatted and inserted in the resulting + * string replacing their respective specifiers. + * RETURNS: + * Pointer to allocated iio_trigger on success, NULL on failure. + */ +struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...) { struct iio_trigger *trig; va_list vargs; va_start(vargs, fmt); - trig = viio_trigger_alloc(fmt, vargs); + trig = viio_trigger_alloc(parent, fmt, vargs); va_end(vargs); return trig; @@ -586,20 +599,19 @@ static void devm_iio_trigger_release(struct device *dev, void *res) /** * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() - * @dev: Device to allocate iio_trigger for + * Managed iio_trigger_alloc. iio_trigger allocated with this function is + * automatically freed on driver detach. + * @parent: Device to allocate iio_trigger for * @fmt: trigger name format. If it includes format * specifiers, the additional arguments following * format are formatted and inserted in the resulting * string replacing their respective specifiers. * - * Managed iio_trigger_alloc. iio_trigger allocated with this function is - * automatically freed on driver detach. * * RETURNS: * Pointer to allocated iio_trigger on success, NULL on failure. */ -struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, - const char *fmt, ...) +struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fmt, ...) { struct iio_trigger **ptr, *trig; va_list vargs; @@ -611,11 +623,11 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, /* use raw alloc_dr for kmalloc caller tracing */ va_start(vargs, fmt); - trig = viio_trigger_alloc(fmt, vargs); + trig = viio_trigger_alloc(parent, fmt, vargs); va_end(vargs); if (trig) { *ptr = trig; - devres_add(dev, ptr); + devres_add(parent, ptr); } else { devres_free(ptr); } diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c index e68a2c56d459..51e362f091c2 100644 --- a/drivers/iio/trigger/iio-trig-hrtimer.c +++ b/drivers/iio/trigger/iio-trig-hrtimer.c @@ -135,7 +135,7 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) if (!trig_info) return ERR_PTR(-ENOMEM); - trig_info->swt.trigger = iio_trigger_alloc("%s", name); + trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name); if (!trig_info->swt.trigger) { ret = -ENOMEM; goto err_free_trig_info; diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 94a487caf421..f746c460bf2a 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -45,7 +45,7 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev) irq = irq_res->start; - trig = iio_trigger_alloc("irqtrig%d", irq); + trig = iio_trigger_alloc(NULL, "irqtrig%d", irq); if (!trig) { ret = -ENOMEM; goto error_ret; diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c index 4a00668e3258..96ec06bbe546 100644 --- a/drivers/iio/trigger/iio-trig-loop.c +++ b/drivers/iio/trigger/iio-trig-loop.c @@ -84,7 +84,7 @@ static struct iio_sw_trigger *iio_trig_loop_probe(const char *name) if (!trig_info) return ERR_PTR(-ENOMEM); - trig_info->swt.trigger = iio_trigger_alloc("%s", name); + trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name); if (!trig_info->swt.trigger) { ret = -ENOMEM; goto err_free_trig_info; diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 0f6b512a5c37..e9adfff45b39 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -149,7 +149,7 @@ static int iio_sysfs_trigger_probe(int id) goto out1; } t->id = id; - t->trig = iio_trigger_alloc("sysfstrig%d", id); + t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id); if (!t->trig) { ret = -ENOMEM; goto free_t; @@ -157,7 +157,6 @@ static int iio_sysfs_trigger_probe(int id) t->trig->dev.groups = iio_sysfs_trigger_attr_groups; t->trig->ops = &iio_sysfs_trigger_ops; - t->trig->dev.parent = &iio_sysfs_trig_dev; iio_trigger_set_drvdata(t->trig, t); t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index f8585d01fc76..f2d65e2e88b6 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -693,7 +693,7 @@ static inline void *iio_priv(const struct iio_dev *indio_dev) void iio_device_free(struct iio_dev *indio_dev); struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv); __printf(2, 3) -struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, +struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fmt, ...); /** * iio_buffer_enabled() - helper function to test if the buffer is enabled diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 055890b6ffcf..096f68dd2e0c 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -161,7 +161,8 @@ void iio_trigger_poll_chained(struct iio_trigger *trig); irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); -__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...); +__printf(2, 3) +struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...); void iio_trigger_free(struct iio_trigger *trig); /** -- cgit v1.2.3 From 635ef601b2387c3215252c9931786524d122c0e7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 8 Mar 2021 11:02:18 +0100 Subject: iio: Provide iio_read_channel_processed_scale() API Since the old iio_read_channel_processed() would lose precision if we fall back to reading raw and scaling, we introduce a new API that will pass in a scale factor when reading a processed channel: iio_read_channel_processed_scale(). Refactor iio_read_channel_processed() as a special case with scale factor 1. Cc: Peter Rosin Cc: Chris Lesiak Cc: Jonathan Cameron Cc: linux-iio@vger.kernel.org Link: https://lore.kernel.org/linux-iio/20201224011607.1059534-1-linus.walleij@linaro.org/ Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20210308100219.2732156-1-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 16 ++++++++++++++-- include/linux/iio/consumer.h | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index db77a2d4a56b..c61fc06f98b8 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -688,7 +688,8 @@ int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) } EXPORT_SYMBOL_GPL(iio_read_channel_offset); -int iio_read_channel_processed(struct iio_channel *chan, int *val) +int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, + unsigned int scale) { int ret; @@ -701,11 +702,15 @@ int iio_read_channel_processed(struct iio_channel *chan, int *val) if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_PROCESSED); + if (ret) + goto err_unlock; + *val *= scale; } else { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); if (ret < 0) goto err_unlock; - ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); + ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, + scale); } err_unlock: @@ -713,6 +718,13 @@ err_unlock: return ret; } +EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); + +int iio_read_channel_processed(struct iio_channel *chan, int *val) +{ + /* This is just a special case with scale factor 1 */ + return iio_read_channel_processed_scale(chan, val, 1); +} EXPORT_SYMBOL_GPL(iio_read_channel_processed); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 0a90ba8fa1bb..5fa5957586cf 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -241,6 +241,21 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val); */ int iio_read_channel_processed(struct iio_channel *chan, int *val); +/** + * iio_read_channel_processed_scale() - read and scale a processed value + * @chan: The channel being queried. + * @val: Value read back. + * @scale: Scale factor to apply during the conversion + * + * Returns an error code or 0. + * + * This function will read a processed value from a channel. This will work + * like @iio_read_channel_processed() but also scale with an additional + * scale factor while attempting to minimize any precision loss. + */ +int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, + unsigned int scale); + /** * iio_write_channel_attribute() - Write values to the device attribute. * @chan: The channel being queried. -- cgit v1.2.3 From 0a21526bc1d41456f1b320cce35c9c66238fb1c9 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 11 Mar 2021 11:10:42 +0200 Subject: iio: kfifo: add devm_iio_triggered_buffer_setup_ext variant This is similar to the {devm_}iio_triggered_buffer_setup_ext variants added via commit 5164c7889857 ("iio: triggered-buffer: add {devm_}iio_triggered_buffer_setup_ext variants"). These can be used to pass extra buffer attributes to the buffer object. This is a bit of temporary mechanism (hopefully) so that drivers that want to allocate a kfifo buffer with extra buffer attributes, don't need to include 'buffer_impl.h' directly. This can also become an API function (in it's own right, unfortunately), but it may be a little less bad vs drivers having to include 'buffer_impl.h'. So, far the drivers that want to pass buffer attributes, all have to do with some HW FIFO attributes, so there may be a chance of unifying them into IIO core somehow (as some standard API). But, until that happens, we just need to let them register their HW FIFO attributes directly (without having to let them include 'buffer_impl.h' directly). Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210311091042.22417-1-aardelean@deviqon.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/kfifo_buf.c | 16 ++++++++++------ include/linux/iio/kfifo_buf.h | 12 ++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index d72cfb354be6..516eb3465de1 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -206,22 +206,24 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) } /** - * devm_iio_kfifo_buffer_setup - Allocate a kfifo buffer & attach it to an IIO device + * devm_iio_kfifo_buffer_setup_ext - Allocate a kfifo buffer & attach it to an IIO device * @dev: Device object to which to attach the life-time of this kfifo buffer * @indio_dev: The device the buffer should be attached to * @mode_flags: The mode flags for this buffer (INDIO_BUFFER_SOFTWARE and/or * INDIO_BUFFER_TRIGGERED). * @setup_ops: The setup_ops required to configure the HW part of the buffer (optional) + * @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer * * This function allocates a kfifo buffer via devm_iio_kfifo_allocate() and * attaches it to the IIO device via iio_device_attach_buffer(). * This is meant to be a bit of a short-hand/helper function as there are a few * drivers that seem to do this. */ -int devm_iio_kfifo_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - int mode_flags, - const struct iio_buffer_setup_ops *setup_ops) +int devm_iio_kfifo_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + int mode_flags, + const struct iio_buffer_setup_ops *setup_ops, + const struct attribute **buffer_attrs) { struct iio_buffer *buffer; @@ -237,8 +239,10 @@ int devm_iio_kfifo_buffer_setup(struct device *dev, indio_dev->modes |= mode_flags; indio_dev->setup_ops = setup_ops; + buffer->attrs = buffer_attrs; + return iio_device_attach_buffer(indio_dev, buffer); } -EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup); +EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext); MODULE_LICENSE("GPL"); diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 1522896e1daf..ccd2ceae7b25 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -10,9 +10,13 @@ struct device; struct iio_buffer *iio_kfifo_allocate(void); void iio_kfifo_free(struct iio_buffer *r); -int devm_iio_kfifo_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - int mode_flags, - const struct iio_buffer_setup_ops *setup_ops); +int devm_iio_kfifo_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + int mode_flags, + const struct iio_buffer_setup_ops *setup_ops, + const struct attribute **buffer_attrs); + +#define devm_iio_kfifo_buffer_setup(dev, indio_dev, mode_flags, setup_ops) \ + devm_iio_kfifo_buffer_setup_ext((dev), (indio_dev), (mode_flags), (setup_ops), NULL) #endif -- cgit v1.2.3 From 80346b2b55fcbb042acd0b90120004da8738101f Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Thu, 18 Mar 2021 11:48:57 -0700 Subject: iio: cros: unify hw fifo attributes without API changes Commit 2e2366c2d141 ("iio: cros_ec: unify hw fifo attributes into the core file") should be reverted as it set buffer extended attributes at the wrong place. However, to revert it will requires to revert more commits: commit 165aea80e2e2 ("iio: cros_ec: use devm_iio_triggered_buffer_setup_ext()") commit 21232b4456ba ("iio: buffer: remove iio_buffer_set_attrs() helper")). and we would still have conflict with more recent development. commit ee708e6baacd ("iio: buffer: introduce support for attaching more IIO buffers") Instead, this commit reverts the first 2 commits without re-adding iio_buffer_set_attrs() and set the buffer extended attributes at the right place: 1. Instead of adding has_fw_fifo, deduct it from the configuration: - EC must support FIFO (EC_FEATURE_MOTION_SENSE_FIFO) set. - sensors send data a regular interval (accelerometer, gyro, magnetomer, barometer, light sensor). - "Legacy accelerometer" is only present on EC without FIFO, so we don't need to set buffer attributes. 2. devm_iio_triggered_buffer_setup_ext() does not need to be called when EC does not support FIFO, as there is no FIFO to manage. 3. Use devm_iio_triggered_buffer_setup_ext() when EC has a FIFO to specify the buffer extended attributes. Fixes: 2e2366c2d141 ("iio: cros_ec: unify hw fifo attributes into the core file") Fixes: 165aea80e2e2 ("iio: cros_ec: use devm_iio_triggered_buffer_setup_ext()") Signed-off-by: Gwendal Grignou Reviewed-by: Alexandru Ardelean Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318184857.2679181-1-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/cros_ec_accel_legacy.c | 2 +- .../iio/common/cros_ec_sensors/cros_ec_lid_angle.c | 3 +-- .../iio/common/cros_ec_sensors/cros_ec_sensors.c | 3 +-- .../common/cros_ec_sensors/cros_ec_sensors_core.c | 24 ++++++++-------------- drivers/iio/light/cros_ec_light_prox.c | 3 +-- drivers/iio/pressure/cros_ec_baro.c | 3 +-- include/linux/iio/common/cros_ec_sensors_core.h | 3 +-- 7 files changed, 14 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index 8f1232c38e0d..b6f3471b62dc 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -215,7 +215,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) return -ENOMEM; ret = cros_ec_sensors_core_init(pdev, indio_dev, true, - cros_ec_sensors_capture, NULL, false); + cros_ec_sensors_capture, NULL); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 752f59037715..af801e203623 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -97,8 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, - NULL, false); + ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index dee1191de752..376a5b30010a 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -236,8 +236,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index a266eedd9ec1..28bde13003b7 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -240,7 +241,6 @@ static void cros_ec_sensors_core_clean(void *arg) * for backward compatibility. * @push_data: function to call when cros_ec_sensorhub receives * a sample for that sensor. - * @has_hw_fifo: Set true if this device has/uses a HW FIFO * * Return: 0 on success, -errno on failure. */ @@ -248,8 +248,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device, cros_ec_sensors_capture_t trigger_capture, - cros_ec_sensorhub_push_data_cb_t push_data, - bool has_hw_fifo) + cros_ec_sensorhub_push_data_cb_t push_data) { struct device *dev = &pdev->dev; struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); @@ -334,9 +333,9 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, * We can not use trigger here, as events are generated * as soon as sample_frequency is set. */ - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - INDIO_BUFFER_SOFTWARE, - NULL); + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, NULL, + cros_ec_sensor_fifo_attributes); if (ret) return ret; @@ -355,21 +354,14 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME); if (ret) return ret; - } else { - const struct attribute **fifo_attrs; - - if (has_hw_fifo) - fifo_attrs = cros_ec_sensor_fifo_attributes; - else - fifo_attrs = NULL; + } else { /* * The only way to get samples in buffer is to set a * software trigger (systrig, hrtimer). */ - ret = devm_iio_triggered_buffer_setup_ext( - dev, indio_dev, NULL, trigger_capture, - NULL, fifo_attrs); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + NULL, trigger_capture, NULL); if (ret) return ret; } diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 75d6b5fcf2cc..de472f23d1cb 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -182,8 +182,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index aa043cb9ac42..2f882e109423 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -139,8 +139,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev) ret = cros_ec_sensors_core_init(pdev, indio_dev, true, cros_ec_sensors_capture, - cros_ec_sensors_push_data, - true); + cros_ec_sensors_push_data); if (ret) return ret; diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index c9b80be82440..7ce8a8adad58 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -96,8 +96,7 @@ struct platform_device; int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device, cros_ec_sensors_capture_t trigger_capture, - cros_ec_sensorhub_push_data_cb_t push_data, - bool has_hw_fifo); + cros_ec_sensorhub_push_data_cb_t push_data); irqreturn_t cros_ec_sensors_capture(int irq, void *p); int cros_ec_sensors_push_data(struct iio_dev *indio_dev, -- cgit v1.2.3 From 7b2d92a3c8e5e8a7ef2710a928a1011bcebc2b91 Mon Sep 17 00:00:00 2001 From: Guoqing Chi Date: Mon, 22 Mar 2021 09:30:24 +0800 Subject: iio:imu:mpu6050: Modify matricies to matrices The plural of "matrix" is "matrices". Signed-off-by: Guoqing Chi Acked-by: Randy Dunlap Acked-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20210322013024.1849-1-chi962464zy@163.com Signed-off-by: Jonathan Cameron --- include/linux/platform_data/invensense_mpu6050.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/platform_data/invensense_mpu6050.h b/include/linux/platform_data/invensense_mpu6050.h index 93974f4cfba1..f05b37521f67 100644 --- a/include/linux/platform_data/invensense_mpu6050.h +++ b/include/linux/platform_data/invensense_mpu6050.h @@ -12,7 +12,7 @@ * mounting matrix retrieved from device-tree) * * Contains platform specific information on how to configure the MPU6050 to - * work on this platform. The orientation matricies are 3x3 rotation matricies + * work on this platform. The orientation matrices are 3x3 rotation matrices * that are applied to the data to rotate from the mounting orientation to the * platform orientation. The values must be one of 0, 1, or -1 and each row and * column should have exactly 1 non-zero value. -- cgit v1.2.3 From 45b77828b01cdf2af655e4edbc63646fc7e07b48 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 14 Mar 2021 18:14:57 +0000 Subject: iio:event: Add timeout event info type For adaptive threshold events, the current value is compared with a (typically) low pass filtered version of the same signal that slowly tracks large scale changes. However, sometimes a step change can result in a large lag before the low pass filtered version begins to track the signal again. Timeouts can be used to made an instantaneous 'correction'. Documentation of this attribute is added in a later patch. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210314181511.531414-11-jic23@kernel.org --- drivers/iio/industrialio-event.c | 1 + include/linux/iio/types.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 1b3a15bc75fe..d0732eac0f0a 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -245,6 +245,7 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_PERIOD] = "period", [IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db", [IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db", + [IIO_EV_INFO_TIMEOUT] = "timeout", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 5aa7f66d4345..84b3f8175cc6 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -16,6 +16,7 @@ enum iio_event_info { IIO_EV_INFO_PERIOD, IIO_EV_INFO_HIGH_PASS_FILTER_3DB, IIO_EV_INFO_LOW_PASS_FILTER_3DB, + IIO_EV_INFO_TIMEOUT, }; #define IIO_VAL_INT 1 -- cgit v1.2.3 From 8cc110478cab83d71f217a9aafec034ed63a5f8e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Apr 2021 14:17:45 +0200 Subject: dt-bindings:iio:dac: update microchip,mcp4725.yaml reference Changeset 6ced946a4bba ("dt-bindings:iio:dac:microchip,mcp4725 yaml conversion") renamed: Documentation/devicetree/bindings/iio/dac/mcp4725.txt to: Documentation/devicetree/bindings/iio/dac/microchip,mcp4725.yaml. Update its cross-reference accordingly. Fixes: 6ced946a4bba ("dt-bindings:iio:dac:microchip,mcp4725 yaml conversion") Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/82fb54974e8a22be15e64343260a6de39a18edda.1617279356.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Cameron --- include/linux/iio/dac/mcp4725.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/iio/dac/mcp4725.h b/include/linux/iio/dac/mcp4725.h index e9801c8d49c0..1f7e53c506b6 100644 --- a/include/linux/iio/dac/mcp4725.h +++ b/include/linux/iio/dac/mcp4725.h @@ -15,7 +15,7 @@ * @vref_buffered: Controls buffering of the external reference voltage. * * Vref related settings are available only on MCP4756. See - * Documentation/devicetree/bindings/iio/dac/mcp4725.txt for more information. + * Documentation/devicetree/bindings/iio/dac/microchip,mcp4725.yaml for more information. */ struct mcp4725_platform_data { bool use_vref; -- cgit v1.2.3