xref: /linux/drivers/iio/buffer/industrialio-hw-consumer.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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 };
32 
33 static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer(
34 	struct iio_buffer *buffer)
35 {
36 	return container_of(buffer, struct hw_consumer_buffer, buffer);
37 }
38 
39 static void iio_hw_buf_release(struct iio_buffer *buffer)
40 {
41 	struct hw_consumer_buffer *hw_buf =
42 		iio_buffer_to_hw_consumer_buffer(buffer);
43 
44 	bitmap_free(buffer->scan_mask);
45 	kfree(hw_buf);
46 }
47 
48 static const struct iio_buffer_access_funcs iio_hw_buf_access = {
49 	.release = &iio_hw_buf_release,
50 	.modes = INDIO_BUFFER_HARDWARE,
51 };
52 
53 static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
54 	struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
55 {
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_obj(*buf);
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 = bitmap_zalloc(iio_get_masklength(indio_dev),
70 					      GFP_KERNEL);
71 	if (!buf->buffer.scan_mask) {
72 		kfree(buf);
73 		return NULL;
74 	}
75 
76 	iio_buffer_init(&buf->buffer);
77 	list_add_tail(&buf->head, &hwc->buffers);
78 
79 	return buf;
80 }
81 
82 /**
83  * iio_hw_consumer_alloc() - Allocate IIO hardware consumer
84  * @dev: Pointer to consumer device.
85  *
86  * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure.
87  */
88 struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
89 {
90 	struct hw_consumer_buffer *buf, *tmp;
91 	struct iio_hw_consumer *hwc;
92 	struct iio_channel *chan;
93 	int ret;
94 
95 	hwc = kzalloc_obj(*hwc);
96 	if (!hwc)
97 		return ERR_PTR(-ENOMEM);
98 
99 	INIT_LIST_HEAD(&hwc->buffers);
100 
101 	hwc->channels = iio_channel_get_all(dev);
102 	if (IS_ERR(hwc->channels)) {
103 		ret = PTR_ERR(hwc->channels);
104 		goto err_free_hwc;
105 	}
106 
107 	chan = &hwc->channels[0];
108 	while (chan->indio_dev) {
109 		buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev);
110 		if (!buf) {
111 			ret = -ENOMEM;
112 			goto err_put_buffers;
113 		}
114 		set_bit(chan->channel->scan_index, buf->buffer.scan_mask);
115 		chan++;
116 	}
117 
118 	return hwc;
119 
120 err_put_buffers:
121 	list_for_each_entry_safe(buf, tmp, &hwc->buffers, head)
122 		iio_buffer_put(&buf->buffer);
123 	iio_channel_release_all(hwc->channels);
124 err_free_hwc:
125 	kfree(hwc);
126 	return ERR_PTR(ret);
127 }
128 EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc);
129 
130 /**
131  * iio_hw_consumer_free() - Free IIO hardware consumer
132  * @hwc: hw consumer to free.
133  */
134 void iio_hw_consumer_free(struct iio_hw_consumer *hwc)
135 {
136 	struct hw_consumer_buffer *buf, *n;
137 
138 	iio_channel_release_all(hwc->channels);
139 	list_for_each_entry_safe(buf, n, &hwc->buffers, head)
140 		iio_buffer_put(&buf->buffer);
141 	kfree(hwc);
142 }
143 EXPORT_SYMBOL_GPL(iio_hw_consumer_free);
144 
145 static void devm_iio_hw_consumer_release(void *iio_hwc)
146 {
147 	iio_hw_consumer_free(iio_hwc);
148 }
149 
150 /**
151  * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc()
152  * @dev: Pointer to consumer device.
153  *
154  * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function
155  * is automatically freed on driver detach.
156  *
157  * returns pointer to allocated iio_hw_consumer on success, NULL on failure.
158  */
159 struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev)
160 {
161 	struct iio_hw_consumer *iio_hwc;
162 	int ret;
163 
164 	iio_hwc = iio_hw_consumer_alloc(dev);
165 	if (IS_ERR(iio_hwc))
166 		return iio_hwc;
167 
168 	ret = devm_add_action_or_reset(dev, devm_iio_hw_consumer_release,
169 				       iio_hwc);
170 	if (ret)
171 		return ERR_PTR(ret);
172 
173 	return iio_hwc;
174 }
175 EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc);
176 
177 /**
178  * iio_hw_consumer_enable() - Enable IIO hardware consumer
179  * @hwc: iio_hw_consumer to enable.
180  *
181  * Returns 0 on success.
182  */
183 int iio_hw_consumer_enable(struct iio_hw_consumer *hwc)
184 {
185 	struct hw_consumer_buffer *buf;
186 	int ret;
187 
188 	list_for_each_entry(buf, &hwc->buffers, head) {
189 		ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL);
190 		if (ret)
191 			goto err_disable_buffers;
192 	}
193 
194 	return 0;
195 
196 err_disable_buffers:
197 	list_for_each_entry_continue_reverse(buf, &hwc->buffers, head)
198 		iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
199 	return ret;
200 }
201 EXPORT_SYMBOL_GPL(iio_hw_consumer_enable);
202 
203 /**
204  * iio_hw_consumer_disable() - Disable IIO hardware consumer
205  * @hwc: iio_hw_consumer to disable.
206  */
207 void iio_hw_consumer_disable(struct iio_hw_consumer *hwc)
208 {
209 	struct hw_consumer_buffer *buf;
210 
211 	list_for_each_entry(buf, &hwc->buffers, head)
212 		iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
213 }
214 EXPORT_SYMBOL_GPL(iio_hw_consumer_disable);
215 
216 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
217 MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework");
218 MODULE_LICENSE("GPL v2");
219 MODULE_IMPORT_NS("IIO_CONSUMER");
220