On 11/08/2012 05:53 PM, Alban Bedel wrote: > On Fri, 5 Oct 2012 14:37:01 +0530 > Naveen Krishna Ch > <naveenkrishna.ch@xxxxxxxxx> wrote: > >> Hello All, >> >> I'm trying to add an ADC driver under IIO/ADC. >> Machine is DT based so, passing the ADC device as tree node and >> consumer devices (thermistors) as child nodes via DT. >> >> I don't find a frame work to parse the child nodes and probe them like >> I2C does using of/of_i2c.c > > Here is my take at DT support in IIO, I wanted to submit that later on > after some more test and cleanup but you can see if it help you. > > Alban > > From 15decde13239f09101673b08aa0bd7e67e970b3c Mon Sep 17 00:00:00 2001 > From: Alban Bedel <alban.bedel@xxxxxxxxxxxxxxxxx> > Date: Thu, 18 Oct 2012 17:07:29 +0200 > Subject: [PATCH] IIO: Add basic DT/devm support for in kernel users > > Signed-off-by: Alban Bedel <alban.bedel@xxxxxxxxxxxxxxxxx> > --- > .../devicetree/bindings/iio/iio-channel.txt | 27 ++++ > drivers/iio/inkern.c | 154 ++++++++++++++++++++ > include/linux/iio/consumer.h | 63 ++++++++ > 3 files changed, 244 insertions(+), 0 deletions(-) > create mode 100644 Documentation/devicetree/bindings/iio/iio-channel.txt > > diff --git a/Documentation/devicetree/bindings/iio/iio-channel.txt b/Documentation/devicetree/bindings/iio/iio-channel.txt > new file mode 100644 > index 0000000..dc894f4 > --- /dev/null > +++ b/Documentation/devicetree/bindings/iio/iio-channel.txt > @@ -0,0 +1,27 @@ > +Specifying IIO channels for devices > +=================================== > + > +1) iio-channels property > +------------------------ > + > +Nodes that makes use of IIO channels should specify them using one or more > +properties, each containing a iio-channels-list': > + > + iio-channel-list ::= <single-iio-channel> [iio-channel-list] > + single-iio-channel ::= <iio-channel-phandle> <iio-channel-specifier> > + iio-channel-phandle : phandle to iio-channel controller node > + iio-channel-specifier : Array of #iio-channel-cells specifying > + specific IIO channel (controller specific) I'd prefer something that is more in sync with what we have for other subsystems which have a provider-consumer relationship, like for example the clk and dma frameworks. Something like: iio-channels = <&phandle1 &phandle2>; iio-channel-names = "voltage", "current"; Also there is another major issue here. Devicetree is supposed to be operating system independent, IIO on the other hand is a Linux specific term. I'm not sure though yet what could be used instead. Maybe just 'io-...'. I've put the devicetree list on Cc. > + > +GPIO properties should be named "[<name>-]iio-channels". Exact IIO ;) > +meaning of each gpios property must be documented in the device tree > +binding for each device. > + > +2) iio device nodes > +------------------------ > + > +Every IIO device must have #iio-channel-cells contain the size of the > +iio-channel-specifier. > + > +Currently #iio-channel-cells will always be 1 but this will most > +propably change in the future. > diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c > index 6d5194f..5986ef5 100644 > --- a/drivers/iio/inkern.c > +++ b/drivers/iio/inkern.c > @@ -10,6 +10,7 @@ > #include <linux/export.h> > #include <linux/slab.h> > #include <linux/mutex.h> > +#include <linux/of.h> > > #include <linux/iio/iio.h> > #include "iio_core.h" > @@ -404,3 +405,156 @@ err_unlock: > return ret; > } > EXPORT_SYMBOL_GPL(iio_get_channel_type); > + > +#ifdef CONFIG_OF > +static int of_dev_node_match(struct device *dev, void *data) > +{ > + return dev->parent ? dev->parent->of_node == data : 0; > +} > + > +int __of_get_named_iio_channel(struct iio_channel* channel, > + struct device_node *np, > + const char *propname, > + int index) > +{ > + struct device *dev; > + struct of_phandle_args ph; > + struct iio_dev *indio_dev; > + int ret, channel_id = -1; > + > + ret = of_parse_phandle_with_args(np, propname, "#iio-channel-cells", > + index, &ph); > + if (ret) > + return ret; > + > + dev = bus_find_device(&iio_bus_type, NULL, ph.np, > + of_dev_node_match); > + if (!dev) > + return -EPROBE_DEFER; > + > + if (ph.args_count > 0) > + channel_id = ph.args[0]; > + > + indio_dev = dev_to_iio_dev(dev); > + if (channel_id < 0 || channel_id >= indio_dev->num_channels) > + return -EINVAL; > + > + iio_device_get(indio_dev); > + channel->indio_dev = indio_dev; > + channel->channel = &indio_dev->channels[channel_id]; > + > + return 0; > +} > + > +/** > + * of_get_iio_channel() - get a iio channel from a device tree property > + * @np: Device node to get the channel from > + * @propname: The property to read > + * @index: Index of the channel > + */ > +struct iio_channel* of_get_named_iio_channel(struct device_node *np, > + const char *propname, > + int index) > +{ > + struct iio_channel* channel; > + int ret; > + > + channel = kzalloc(sizeof(*channel), GFP_KERNEL); > + if (!channel) > + return ERR_PTR(-ENOMEM); > + > + ret = __of_get_named_iio_channel(channel, np, propname, index); > + if (ret) { > + kfree(channel); > + return ERR_PTR(ret); > + } > + return channel; > +} > + > +EXPORT_SYMBOL_GPL(of_get_named_iio_channel); > + > +struct iio_channel* of_get_named_all_iio_channels(struct device_node *np, > + const char *propname) > +{ > + int ret, i, cnt; > + struct iio_channel* channels; > + > + cnt = of_iio_channel_named_count(np, propname); > + if (cnt == 0) > + return NULL; > + > + channels = kzalloc((cnt+1) * sizeof(*channels), GFP_KERNEL); > + if (!channels) > + return ERR_PTR(-ENOMEM); > + > + for (i = 0 ; i < cnt ; i += 1) { > + ret = __of_get_named_iio_channel(&channels[i], > + np, propname, i); > + if (ret) > + break; > + } > + > + if (ret) { > + for ( ; i >= 0 ; i -= 1) > + iio_device_put(channels[i].indio_dev); > + kfree(channels); > + return ERR_PTR(ret); > + } > + > + return channels; > + > +} > +EXPORT_SYMBOL_GPL(of_get_named_all_iio_channels); > + > +unsigned int of_iio_channel_named_count(struct device_node *np, > + const char *propname) > +{ > + unsigned int cnt = 0; > + > + do { > + int ret; > + > + ret = of_parse_phandle_with_args(np, propname, "#iio-channel-cells", > + cnt, NULL); > + /* A hole in the gpios = <> counts anyway. */ > + if (ret < 0 && ret != -EEXIST) > + break; > + } while (++cnt); > + > + return cnt; > + > +} > +EXPORT_SYMBOL_GPL(of_iio_channel_named_count); > + > +struct iio_channel_devres { > + struct iio_channel* channel; > +}; > + > +static void devm_iio_channel_release(struct device *dev, void *res) > +{ > + struct iio_channel_devres *dr = res; > + iio_channel_release(dr->channel); > +} > + > +struct iio_channel* devm_iio_channel_get(struct device* dev, int index) > +{ > + struct iio_channel_devres *dr; > + struct iio_channel *channel; > + > + channel = of_get_iio_channel(dev->of_node, index); > + if (IS_ERR(channel)) > + return channel; > + > + dr = devres_alloc(devm_iio_channel_release, sizeof(*dr), GFP_KERNEL); > + if (!dr) { > + iio_channel_release(channel); > + return ERR_PTR(-ENOMEM); > + } > + > + dr->channel = channel; > + devres_add(dev, dr); > + return dr->channel; > +} > +EXPORT_SYMBOL_GPL(devm_iio_channel_get); > + > +#endif > diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h > index e4ff665..e2f958a 100644 > --- a/include/linux/iio/consumer.h > +++ b/include/linux/iio/consumer.h > @@ -131,4 +131,67 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, > int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, > int *processed, unsigned int scale); > > +#ifdef CONFIG_OF > +struct iio_channel* of_get_named_iio_channel(struct device_node *np, > + const char *propname, > + int index); > + > +struct iio_channel* of_get_named_all_iio_channels(struct device_node *np, > + const char *propname); > + > +unsigned int of_iio_channel_named_count(struct device_node *np, > + const char *propname); > + > +#else > +struct iio_channel* of_get_named_iio_channel(struct device_node *np, > + const char *propname, > + int index) > +{ > + return ERR_PTR(-ENODEV); > +} > + > +struct iio_channel* of_get_named_all_iio_channels(struct device_node *np, > + const char *propname) > +{ > + return ERR_PTR(-ENODEV); > +} > + > +unsigned int of_iio_channel_named_count(struct device_node *np, > + const char *propname) > +{ > + return 0; > +} > +#endif > + > +/** > + * of_get_iio_channel() - get a iio channel from the device tree > + * @np: Device node to get the channel from > + * @index: Index of the channel > + */ > +static inline struct iio_channel* of_get_iio_channel(struct device_node *np, > + int index) > +{ > + return of_get_named_iio_channel(np, "iio-channels", index); > +} > + > +/** > + * of_get_all_iio_channels() - get a iio channel from the device tree > + * @np: Device node to get the channel from > + */ > +static inline struct iio_channel* of_get_all_iio_channels(struct device_node *np) > +{ > + return of_get_named_all_iio_channels(np, "iio-channels"); > +} > + > +/** > + * of_get_iio_channel() - get the number of iio channel from the device tree > + * @np: Device node to get the number of channel from > + */ > +static inline unsigned int of_iio_channel_count(struct device_node *np) > +{ > + return of_iio_channel_named_count(np, "iio-channels"); > +} > + > +struct iio_channel* devm_iio_channel_get(struct device* dev, int index); > + > #endif -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html