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  */
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