Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: Add hardware consumer buffer support

Hardware consumer interface can be used when one IIO device has
a direct connection to another device in hardware.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Lars-Peter Clausen and committed by
Mark Brown
48b66f8f 4fbd8d19

+211
+10
drivers/iio/buffer/Kconfig
··· 29 29 30 30 Should be selected by drivers that want to use this functionality. 31 31 32 + config IIO_BUFFER_HW_CONSUMER 33 + tristate "Industrial I/O HW buffering" 34 + help 35 + Provides a way to bonding when an IIO device has a direct connection 36 + to another device in hardware. In this case buffers for data transfers 37 + are handled by hardware. 38 + 39 + Should be selected by drivers that want to use the generic Hw consumer 40 + interface. 41 + 32 42 config IIO_KFIFO_BUF 33 43 tristate "Industrial I/O buffering based on kfifo" 34 44 help
+1
drivers/iio/buffer/Makefile
··· 7 7 obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o 8 8 obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o 9 9 obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o 10 + obj-$(CONFIG_IIO_BUFFER_HW_CONSUMER) += industrialio-hw-consumer.o 10 11 obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o 11 12 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+181
drivers/iio/buffer/industrialio-hw-consumer.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2017 Analog Devices Inc. 4 + * Author: Lars-Peter Clausen <lars@metafoo.de> 5 + */ 6 + 7 + #include <linux/err.h> 8 + #include <linux/export.h> 9 + #include <linux/slab.h> 10 + #include <linux/module.h> 11 + 12 + #include <linux/iio/iio.h> 13 + #include <linux/iio/consumer.h> 14 + #include <linux/iio/hw-consumer.h> 15 + #include <linux/iio/buffer_impl.h> 16 + 17 + /** 18 + * struct iio_hw_consumer - IIO hw consumer block 19 + * @buffers: hardware buffers list head. 20 + * @channels: IIO provider channels. 21 + */ 22 + struct iio_hw_consumer { 23 + struct list_head buffers; 24 + struct iio_channel *channels; 25 + }; 26 + 27 + struct hw_consumer_buffer { 28 + struct list_head head; 29 + struct iio_dev *indio_dev; 30 + struct iio_buffer buffer; 31 + long scan_mask[]; 32 + }; 33 + 34 + static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer( 35 + struct iio_buffer *buffer) 36 + { 37 + return container_of(buffer, struct hw_consumer_buffer, buffer); 38 + } 39 + 40 + static void iio_hw_buf_release(struct iio_buffer *buffer) 41 + { 42 + struct hw_consumer_buffer *hw_buf = 43 + iio_buffer_to_hw_consumer_buffer(buffer); 44 + kfree(hw_buf); 45 + } 46 + 47 + static const struct iio_buffer_access_funcs iio_hw_buf_access = { 48 + .release = &iio_hw_buf_release, 49 + .modes = INDIO_BUFFER_HARDWARE, 50 + }; 51 + 52 + static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( 53 + struct iio_hw_consumer *hwc, struct iio_dev *indio_dev) 54 + { 55 + size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long); 56 + struct hw_consumer_buffer *buf; 57 + 58 + list_for_each_entry(buf, &hwc->buffers, head) { 59 + if (buf->indio_dev == indio_dev) 60 + return buf; 61 + } 62 + 63 + buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL); 64 + if (!buf) 65 + return NULL; 66 + 67 + buf->buffer.access = &iio_hw_buf_access; 68 + buf->indio_dev = indio_dev; 69 + buf->buffer.scan_mask = buf->scan_mask; 70 + 71 + iio_buffer_init(&buf->buffer); 72 + list_add_tail(&buf->head, &hwc->buffers); 73 + 74 + return buf; 75 + } 76 + 77 + /** 78 + * iio_hw_consumer_alloc() - Allocate IIO hardware consumer 79 + * @dev: Pointer to consumer device. 80 + * 81 + * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure. 82 + */ 83 + struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev) 84 + { 85 + struct hw_consumer_buffer *buf; 86 + struct iio_hw_consumer *hwc; 87 + struct iio_channel *chan; 88 + int ret; 89 + 90 + hwc = kzalloc(sizeof(*hwc), GFP_KERNEL); 91 + if (!hwc) 92 + return ERR_PTR(-ENOMEM); 93 + 94 + INIT_LIST_HEAD(&hwc->buffers); 95 + 96 + hwc->channels = iio_channel_get_all(dev); 97 + if (IS_ERR(hwc->channels)) { 98 + ret = PTR_ERR(hwc->channels); 99 + goto err_free_hwc; 100 + } 101 + 102 + chan = &hwc->channels[0]; 103 + while (chan->indio_dev) { 104 + buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev); 105 + if (!buf) { 106 + ret = -ENOMEM; 107 + goto err_put_buffers; 108 + } 109 + set_bit(chan->channel->scan_index, buf->buffer.scan_mask); 110 + chan++; 111 + } 112 + 113 + return hwc; 114 + 115 + err_put_buffers: 116 + list_for_each_entry(buf, &hwc->buffers, head) 117 + iio_buffer_put(&buf->buffer); 118 + iio_channel_release_all(hwc->channels); 119 + err_free_hwc: 120 + kfree(hwc); 121 + return ERR_PTR(ret); 122 + } 123 + EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc); 124 + 125 + /** 126 + * iio_hw_consumer_free() - Free IIO hardware consumer 127 + * @hwc: hw consumer to free. 128 + */ 129 + void iio_hw_consumer_free(struct iio_hw_consumer *hwc) 130 + { 131 + struct hw_consumer_buffer *buf, *n; 132 + 133 + iio_channel_release_all(hwc->channels); 134 + list_for_each_entry_safe(buf, n, &hwc->buffers, head) 135 + iio_buffer_put(&buf->buffer); 136 + kfree(hwc); 137 + } 138 + EXPORT_SYMBOL_GPL(iio_hw_consumer_free); 139 + 140 + /** 141 + * iio_hw_consumer_enable() - Enable IIO hardware consumer 142 + * @hwc: iio_hw_consumer to enable. 143 + * 144 + * Returns 0 on success. 145 + */ 146 + int iio_hw_consumer_enable(struct iio_hw_consumer *hwc) 147 + { 148 + struct hw_consumer_buffer *buf; 149 + int ret; 150 + 151 + list_for_each_entry(buf, &hwc->buffers, head) { 152 + ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL); 153 + if (ret) 154 + goto err_disable_buffers; 155 + } 156 + 157 + return 0; 158 + 159 + err_disable_buffers: 160 + list_for_each_entry_continue_reverse(buf, &hwc->buffers, head) 161 + iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); 162 + return ret; 163 + } 164 + EXPORT_SYMBOL_GPL(iio_hw_consumer_enable); 165 + 166 + /** 167 + * iio_hw_consumer_disable() - Disable IIO hardware consumer 168 + * @hwc: iio_hw_consumer to disable. 169 + */ 170 + void iio_hw_consumer_disable(struct iio_hw_consumer *hwc) 171 + { 172 + struct hw_consumer_buffer *buf; 173 + 174 + list_for_each_entry(buf, &hwc->buffers, head) 175 + iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); 176 + } 177 + EXPORT_SYMBOL_GPL(iio_hw_consumer_disable); 178 + 179 + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 180 + MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework"); 181 + MODULE_LICENSE("GPL v2");
+19
include/linux/iio/hw-consumer.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Industrial I/O in kernel hardware consumer interface 4 + * 5 + * Copyright 2017 Analog Devices Inc. 6 + * Author: Lars-Peter Clausen <lars@metafoo.de> 7 + */ 8 + 9 + #ifndef LINUX_IIO_HW_CONSUMER_H 10 + #define LINUX_IIO_HW_CONSUMER_H 11 + 12 + struct iio_hw_consumer; 13 + 14 + struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev); 15 + void iio_hw_consumer_free(struct iio_hw_consumer *hwc); 16 + int iio_hw_consumer_enable(struct iio_hw_consumer *hwc); 17 + void iio_hw_consumer_disable(struct iio_hw_consumer *hwc); 18 + 19 + #endif