1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Helpers for parsing common ADC information from a firmware node.
4 *
5 * Copyright (c) 2025 Matti Vaittinen <mazziesaccount@gmail.com>
6 */
7
8 #include <linux/device.h>
9 #include <linux/errno.h>
10 #include <linux/export.h>
11 #include <linux/module.h>
12 #include <linux/property.h>
13 #include <linux/types.h>
14
15 #include <linux/iio/adc-helpers.h>
16 #include <linux/iio/iio.h>
17
18 /**
19 * devm_iio_adc_device_alloc_chaninfo_se - allocate and fill iio_chan_spec for ADC
20 *
21 * Scan the device node for single-ended ADC channel information. Channel ID is
22 * expected to be found from the "reg" property. Allocate and populate the
23 * iio_chan_spec structure corresponding to channels that are found. The memory
24 * for iio_chan_spec structure will be freed upon device detach.
25 *
26 * @dev: Pointer to the ADC device.
27 * @template: Template iio_chan_spec from which the fields of all
28 * found and allocated channels are initialized.
29 * @max_chan_id: Maximum value of a channel ID. Use negative value if no
30 * checking is required.
31 * @cs: Location where pointer to allocated iio_chan_spec
32 * should be stored.
33 *
34 * Return: Number of found channels on success. Negative value to indicate
35 * failure. Specifically, -ENOENT if no channel nodes were found.
36 */
devm_iio_adc_device_alloc_chaninfo_se(struct device * dev,const struct iio_chan_spec * template,int max_chan_id,struct iio_chan_spec ** cs)37 int devm_iio_adc_device_alloc_chaninfo_se(struct device *dev,
38 const struct iio_chan_spec *template,
39 int max_chan_id,
40 struct iio_chan_spec **cs)
41 {
42 struct iio_chan_spec *chan_array, *chan;
43 int num_chan, ret;
44
45 num_chan = iio_adc_device_num_channels(dev);
46 if (num_chan < 0)
47 return num_chan;
48
49 if (!num_chan)
50 return -ENOENT;
51
52 chan_array = devm_kcalloc(dev, num_chan, sizeof(*chan_array),
53 GFP_KERNEL);
54 if (!chan_array)
55 return -ENOMEM;
56
57 chan = &chan_array[0];
58
59 device_for_each_named_child_node_scoped(dev, child, "channel") {
60 u32 ch;
61
62 ret = fwnode_property_read_u32(child, "reg", &ch);
63 if (ret)
64 return ret;
65
66 if (max_chan_id >= 0 && ch > max_chan_id)
67 return -ERANGE;
68
69 *chan = *template;
70 chan->channel = ch;
71 chan++;
72 }
73
74 *cs = chan_array;
75
76 return num_chan;
77 }
78 EXPORT_SYMBOL_NS_GPL(devm_iio_adc_device_alloc_chaninfo_se, "IIO_DRIVER");
79
80 MODULE_LICENSE("GPL");
81 MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
82 MODULE_DESCRIPTION("IIO ADC fwnode parsing helpers");
83