Querry on IIO/ADC DT based consumer device probe

Lars-Peter Clausen lars at metafoo.de
Sat Nov 10 01:48:05 EST 2012


On 11/08/2012 05:53 PM, Alban Bedel wrote:
> On Fri, 5 Oct 2012 14:37:01 +0530
> Naveen Krishna Ch
> <naveenkrishna.ch at gmail.com> 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 at avionic-design.de>
> 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 at avionic-design.de>
> ---
>  .../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



More information about the devicetree-discuss mailing list