* Querry on IIO/ADC DT based consumer device probe
@ 2012-10-05 9:07 Naveen Krishna Ch
2012-10-05 11:35 ` Jonathan Cameron
2012-11-08 16:53 ` Alban Bedel
0 siblings, 2 replies; 5+ messages in thread
From: Naveen Krishna Ch @ 2012-10-05 9:07 UTC (permalink / raw)
To: linux-iio, jic23
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
The DT snippet:
adc@12D10000 {
thermistor@3 {
compatible = "ntc,ncp15wb473";
consumer-name = "ntc,ncp15wb473";
consumer-channel = "adc-3";
pullup-uV = <1800000>;
pullup-ohm = <47000>;
pulldown-ohm = <0>;
connected-positive;
};
thermistor@4 {
compatible = "ntc,ncp15wb473";
consumer-name = "ntc,ncp15wb473";
consumer-channel = "adc-4";
pullup-uV = <1800000>;
pullup-ohm = <47000>;
pulldown-ohm = <0>;
connected-positive;
};
};
Parsing snippet:
for_each_child_of_node(node, client_node) {
char *channel, *label = NULL;
if (of_property_read_string(client_node,
"consumer-channel", &channel) != 0) {
dev_err(&pdev->dev, "Missing consumer-channel
property in the DT.\n");
return -EINVAL;
}
client_map[i].consumer_channel = channel;
label = "lable-adc"; //TODO
client_map[i].adc_channel_label = label;
if (of_property_read_string(client_node,
"consumer-name", &client_map[i].consumer_dev_name) != 0) {
dev_err(&pdev->dev, "Missing consumer-name
property in the DT.\n");
return -EINVAL;
}
i++;
}
Can some one suggest a way to get the consumer thermistor driver to
get probed from iio framework via DT.
Kindly, point me towards any existing framework to do the same.
--
Shine bright,
(: Nav :)
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: Querry on IIO/ADC DT based consumer device probe 2012-10-05 9:07 Querry on IIO/ADC DT based consumer device probe Naveen Krishna Ch @ 2012-10-05 11:35 ` Jonathan Cameron 2012-11-08 16:53 ` Alban Bedel 1 sibling, 0 replies; 5+ messages in thread From: Jonathan Cameron @ 2012-10-05 11:35 UTC (permalink / raw) To: Naveen Krishna Ch; +Cc: linux-iio, jic23 On 05/10/12 10:07, Naveen Krishna Ch 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 > > The DT snippet: > adc@12D10000 { > thermistor@3 { > compatible = "ntc,ncp15wb473"; > consumer-name = "ntc,ncp15wb473"; > consumer-channel = "adc-3"; > pullup-uV = <1800000>; > pullup-ohm = <47000>; > pulldown-ohm = <0>; > connected-positive; > }; > > thermistor@4 { > compatible = "ntc,ncp15wb473"; > consumer-name = "ntc,ncp15wb473"; > consumer-channel = "adc-4"; > pullup-uV = <1800000>; > pullup-ohm = <47000>; > pulldown-ohm = <0>; > connected-positive; > }; > }; > > Parsing snippet: > for_each_child_of_node(node, client_node) { > char *channel, *label = NULL; > > if (of_property_read_string(client_node, > "consumer-channel", &channel) != 0) { > dev_err(&pdev->dev, "Missing consumer-channel > property in the DT.\n"); > return -EINVAL; > } > > client_map[i].consumer_channel = channel; > label = "lable-adc"; //TODO > client_map[i].adc_channel_label = label; > > > if (of_property_read_string(client_node, > "consumer-name", &client_map[i].consumer_dev_name) != 0) { > dev_err(&pdev->dev, "Missing consumer-name > property in the DT.\n"); > return -EINVAL; > } > > i++; > } > > Can some one suggest a way to get the consumer thermistor driver to > get probed from iio framework via DT. > Kindly, point me towards any existing framework to do the same. Sorry, I don't think anyone has implemented a device tree version yet. Just comes down to no one until you having needed it. Feel free to send patches! ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Querry on IIO/ADC DT based consumer device probe 2012-10-05 9:07 Querry on IIO/ADC DT based consumer device probe Naveen Krishna Ch 2012-10-05 11:35 ` Jonathan Cameron @ 2012-11-08 16:53 ` Alban Bedel 2012-11-09 14:48 ` Lars-Peter Clausen 1 sibling, 1 reply; 5+ messages in thread From: Alban Bedel @ 2012-11-08 16:53 UTC (permalink / raw) To: linux-iio On Fri, 5 Oct 2012 14:37:01 +0530 Naveen Krishna Ch <naveenkrishna.ch@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@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@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) + +GPIO properties should be named "[<name>-]iio-channels". Exact +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 -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: Querry on IIO/ADC DT based consumer device probe @ 2012-11-09 14:48 ` Lars-Peter Clausen 0 siblings, 0 replies; 5+ messages in thread From: Lars-Peter Clausen @ 2012-11-09 14:48 UTC (permalink / raw) To: Alban Bedel; +Cc: linux-iio, devicetree-discuss On 11/08/2012 05:53 PM, Alban Bedel wrote: > On Fri, 5 Oct 2012 14:37:01 +0530 > Naveen Krishna Ch > <naveenkrishna.ch@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@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@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 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Querry on IIO/ADC DT based consumer device probe @ 2012-11-09 14:48 ` Lars-Peter Clausen 0 siblings, 0 replies; 5+ messages in thread From: Lars-Peter Clausen @ 2012-11-09 14:48 UTC (permalink / raw) To: Alban Bedel Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ On 11/08/2012 05:53 PM, Alban Bedel wrote: > On Fri, 5 Oct 2012 14:37:01 +0530 > Naveen Krishna Ch > <naveenkrishna.ch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org> > 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-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org> > --- > .../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 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-11-09 14:48 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-10-05 9:07 Querry on IIO/ADC DT based consumer device probe Naveen Krishna Ch 2012-10-05 11:35 ` Jonathan Cameron 2012-11-08 16:53 ` Alban Bedel 2012-11-09 14:48 ` Lars-Peter Clausen 2012-11-09 14:48 ` Lars-Peter Clausen
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.