Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2017 Analog Devices Inc.
0004  *  Author: Lars-Peter Clausen <lars@metafoo.de>
0005  */
0006 
0007 #include <linux/err.h>
0008 #include <linux/export.h>
0009 #include <linux/slab.h>
0010 #include <linux/module.h>
0011 
0012 #include <linux/iio/iio.h>
0013 #include <linux/iio/consumer.h>
0014 #include <linux/iio/hw-consumer.h>
0015 #include <linux/iio/buffer_impl.h>
0016 
0017 /**
0018  * struct iio_hw_consumer - IIO hw consumer block
0019  * @buffers: hardware buffers list head.
0020  * @channels: IIO provider channels.
0021  */
0022 struct iio_hw_consumer {
0023     struct list_head buffers;
0024     struct iio_channel *channels;
0025 };
0026 
0027 struct hw_consumer_buffer {
0028     struct list_head head;
0029     struct iio_dev *indio_dev;
0030     struct iio_buffer buffer;
0031     long scan_mask[];
0032 };
0033 
0034 static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer(
0035     struct iio_buffer *buffer)
0036 {
0037     return container_of(buffer, struct hw_consumer_buffer, buffer);
0038 }
0039 
0040 static void iio_hw_buf_release(struct iio_buffer *buffer)
0041 {
0042     struct hw_consumer_buffer *hw_buf =
0043         iio_buffer_to_hw_consumer_buffer(buffer);
0044     kfree(hw_buf);
0045 }
0046 
0047 static const struct iio_buffer_access_funcs iio_hw_buf_access = {
0048     .release = &iio_hw_buf_release,
0049     .modes = INDIO_BUFFER_HARDWARE,
0050 };
0051 
0052 static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
0053     struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
0054 {
0055     struct hw_consumer_buffer *buf;
0056 
0057     list_for_each_entry(buf, &hwc->buffers, head) {
0058         if (buf->indio_dev == indio_dev)
0059             return buf;
0060     }
0061 
0062     buf = kzalloc(struct_size(buf, scan_mask, BITS_TO_LONGS(indio_dev->masklength)),
0063               GFP_KERNEL);
0064     if (!buf)
0065         return NULL;
0066 
0067     buf->buffer.access = &iio_hw_buf_access;
0068     buf->indio_dev = indio_dev;
0069     buf->buffer.scan_mask = buf->scan_mask;
0070 
0071     iio_buffer_init(&buf->buffer);
0072     list_add_tail(&buf->head, &hwc->buffers);
0073 
0074     return buf;
0075 }
0076 
0077 /**
0078  * iio_hw_consumer_alloc() - Allocate IIO hardware consumer
0079  * @dev: Pointer to consumer device.
0080  *
0081  * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure.
0082  */
0083 struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
0084 {
0085     struct hw_consumer_buffer *buf;
0086     struct iio_hw_consumer *hwc;
0087     struct iio_channel *chan;
0088     int ret;
0089 
0090     hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
0091     if (!hwc)
0092         return ERR_PTR(-ENOMEM);
0093 
0094     INIT_LIST_HEAD(&hwc->buffers);
0095 
0096     hwc->channels = iio_channel_get_all(dev);
0097     if (IS_ERR(hwc->channels)) {
0098         ret = PTR_ERR(hwc->channels);
0099         goto err_free_hwc;
0100     }
0101 
0102     chan = &hwc->channels[0];
0103     while (chan->indio_dev) {
0104         buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev);
0105         if (!buf) {
0106             ret = -ENOMEM;
0107             goto err_put_buffers;
0108         }
0109         set_bit(chan->channel->scan_index, buf->buffer.scan_mask);
0110         chan++;
0111     }
0112 
0113     return hwc;
0114 
0115 err_put_buffers:
0116     list_for_each_entry(buf, &hwc->buffers, head)
0117         iio_buffer_put(&buf->buffer);
0118     iio_channel_release_all(hwc->channels);
0119 err_free_hwc:
0120     kfree(hwc);
0121     return ERR_PTR(ret);
0122 }
0123 EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc);
0124 
0125 /**
0126  * iio_hw_consumer_free() - Free IIO hardware consumer
0127  * @hwc: hw consumer to free.
0128  */
0129 void iio_hw_consumer_free(struct iio_hw_consumer *hwc)
0130 {
0131     struct hw_consumer_buffer *buf, *n;
0132 
0133     iio_channel_release_all(hwc->channels);
0134     list_for_each_entry_safe(buf, n, &hwc->buffers, head)
0135         iio_buffer_put(&buf->buffer);
0136     kfree(hwc);
0137 }
0138 EXPORT_SYMBOL_GPL(iio_hw_consumer_free);
0139 
0140 static void devm_iio_hw_consumer_release(void *iio_hwc)
0141 {
0142     iio_hw_consumer_free(iio_hwc);
0143 }
0144 
0145 /**
0146  * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc()
0147  * @dev: Pointer to consumer device.
0148  *
0149  * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function
0150  * is automatically freed on driver detach.
0151  *
0152  * returns pointer to allocated iio_hw_consumer on success, NULL on failure.
0153  */
0154 struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev)
0155 {
0156     struct iio_hw_consumer *iio_hwc;
0157     int ret;
0158 
0159     iio_hwc = iio_hw_consumer_alloc(dev);
0160     if (IS_ERR(iio_hwc))
0161         return iio_hwc;
0162 
0163     ret = devm_add_action_or_reset(dev, devm_iio_hw_consumer_release,
0164                        iio_hwc);
0165     if (ret)
0166         return ERR_PTR(ret);
0167 
0168     return iio_hwc;
0169 }
0170 EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc);
0171 
0172 /**
0173  * iio_hw_consumer_enable() - Enable IIO hardware consumer
0174  * @hwc: iio_hw_consumer to enable.
0175  *
0176  * Returns 0 on success.
0177  */
0178 int iio_hw_consumer_enable(struct iio_hw_consumer *hwc)
0179 {
0180     struct hw_consumer_buffer *buf;
0181     int ret;
0182 
0183     list_for_each_entry(buf, &hwc->buffers, head) {
0184         ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL);
0185         if (ret)
0186             goto err_disable_buffers;
0187     }
0188 
0189     return 0;
0190 
0191 err_disable_buffers:
0192     list_for_each_entry_continue_reverse(buf, &hwc->buffers, head)
0193         iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
0194     return ret;
0195 }
0196 EXPORT_SYMBOL_GPL(iio_hw_consumer_enable);
0197 
0198 /**
0199  * iio_hw_consumer_disable() - Disable IIO hardware consumer
0200  * @hwc: iio_hw_consumer to disable.
0201  */
0202 void iio_hw_consumer_disable(struct iio_hw_consumer *hwc)
0203 {
0204     struct hw_consumer_buffer *buf;
0205 
0206     list_for_each_entry(buf, &hwc->buffers, head)
0207         iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
0208 }
0209 EXPORT_SYMBOL_GPL(iio_hw_consumer_disable);
0210 
0211 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
0212 MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework");
0213 MODULE_LICENSE("GPL v2");