Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 363560
b: refs/heads/master
c: 17d82b4
h: refs/heads/master
v: v3
  • Loading branch information
Guenter Roeck authored and Jonathan Cameron committed Mar 16, 2013
1 parent 9813382 commit 055f47c
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cddc1424f39e7c04045a6431eaf13a003fb8335a
refs/heads/master: 17d82b47a215ded05ee3fb8d93b7c1269dbe0083
97 changes: 97 additions & 0 deletions trunk/Documentation/devicetree/bindings/iio/iio-bindings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
This binding is derived from clock bindings, and based on suggestions
from Lars-Peter Clausen [1].

Sources of IIO channels can be represented by any node in the device
tree. Those nodes are designated as IIO providers. IIO consumer
nodes use a phandle and IIO specifier pair to connect IIO provider
outputs to IIO inputs. Similar to the gpio specifiers, an IIO
specifier is an array of one or more cells identifying the IIO
output on a device. The length of an IIO specifier is defined by the
value of a #io-channel-cells property in the IIO provider node.

[1] http://marc.info/?l=linux-iio&m=135902119507483&w=2

==IIO providers==

Required properties:
#io-channel-cells: Number of cells in an IIO specifier; Typically 0 for nodes
with a single IIO output and 1 for nodes with multiple
IIO outputs.

Example for a simple configuration with no trigger:

adc: voltage-sensor@35 {
compatible = "maxim,max1139";
reg = <0x35>;
#io-channel-cells = <1>;
};

Example for a configuration with trigger:

adc@35 {
compatible = "some-vendor,some-adc";
reg = <0x35>;

adc1: iio-device@0 {
#io-channel-cells = <1>;
/* other properties */
};
adc2: iio-device@1 {
#io-channel-cells = <1>;
/* other properties */
};
};

==IIO consumers==

Required properties:
io-channels: List of phandle and IIO specifier pairs, one pair
for each IIO input to the device. Note: if the
IIO provider specifies '0' for #io-channel-cells,
then only the phandle portion of the pair will appear.

Optional properties:
io-channel-names:
List of IIO input name strings sorted in the same
order as the io-channels property. Consumers drivers
will use io-channel-names to match IIO input names
with IIO specifiers.
io-channel-ranges:
Empty property indicating that child nodes can inherit named
IIO channels from this node. Useful for bus nodes to provide
and IIO channel to their children.

For example:

device {
io-channels = <&adc 1>, <&ref 0>;
io-channel-names = "vcc", "vdd";
};

This represents a device with two IIO inputs, named "vcc" and "vdd".
The vcc channel is connected to output 1 of the &adc device, and the
vdd channel is connected to output 0 of the &ref device.

==Example==

adc: max1139@35 {
compatible = "maxim,max1139";
reg = <0x35>;
#io-channel-cells = <1>;
};

...

iio_hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 0>, <&adc 1>, <&adc 2>,
<&adc 3>, <&adc 4>, <&adc 5>,
<&adc 6>, <&adc 7>, <&adc 8>,
<&adc 9>;
};

some_consumer {
compatible = "some-consumer";
io-channels = <&adc 10>, <&adc 11>;
io-channel-names = "adc1", "adc2";
};
1 change: 1 addition & 0 deletions trunk/drivers/iio/iio_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
struct iio_chan_spec;
struct iio_dev;

extern struct device_type iio_device_type;

int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
Expand Down
8 changes: 6 additions & 2 deletions trunk/drivers/iio/industrialio-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ static void iio_dev_release(struct device *device)
kfree(indio_dev);
}

static struct device_type iio_dev_type = {
struct device_type iio_device_type = {
.name = "iio_device",
.release = iio_dev_release,
};
Expand All @@ -869,7 +869,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)

if (dev) {
dev->dev.groups = dev->groups;
dev->dev.type = &iio_dev_type;
dev->dev.type = &iio_device_type;
dev->dev.bus = &iio_bus_type;
device_initialize(&dev->dev);
dev_set_drvdata(&dev->dev, (void *)dev);
Expand Down Expand Up @@ -960,6 +960,10 @@ int iio_device_register(struct iio_dev *indio_dev)
{
int ret;

/* If the calling driver did not initialize of_node, do it here */
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;

/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);

Expand Down
171 changes: 171 additions & 0 deletions trunk/drivers/iio/inkern.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -92,6 +93,164 @@ static const struct iio_chan_spec
return chan;
}

#ifdef CONFIG_OF

static int iio_dev_node_match(struct device *dev, void *data)
{
return dev->of_node == data && dev->type == &iio_device_type;
}

static int __of_iio_channel_get(struct iio_channel *channel,
struct device_node *np, int index)
{
struct device *idev;
struct iio_dev *indio_dev;
int err;
struct of_phandle_args iiospec;

err = of_parse_phandle_with_args(np, "io-channels",
"#io-channel-cells",
index, &iiospec);
if (err)
return err;

idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
iio_dev_node_match);
of_node_put(iiospec.np);
if (idev == NULL)
return -EPROBE_DEFER;

indio_dev = dev_to_iio_dev(idev);
channel->indio_dev = indio_dev;
index = iiospec.args_count ? iiospec.args[0] : 0;
if (index >= indio_dev->num_channels) {
return -EINVAL;
goto err_put;
}
channel->channel = &indio_dev->channels[index];

return 0;

err_put:
iio_device_put(indio_dev);
return err;
}

static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
{
struct iio_channel *channel;
int err;

if (index < 0)
return ERR_PTR(-EINVAL);

channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (channel == NULL)
return ERR_PTR(-ENOMEM);

err = __of_iio_channel_get(channel, np, index);
if (err)
goto err_free_channel;

return channel;

err_free_channel:
kfree(channel);
return ERR_PTR(err);
}

static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
const char *name)
{
struct iio_channel *chan = NULL;

/* Walk up the tree of devices looking for a matching iio channel */
while (np) {
int index = 0;

/*
* For named iio channels, first look up the name in the
* "io-channel-names" property. If it cannot be found, the
* index will be an error code, and of_iio_channel_get()
* will fail.
*/
if (name)
index = of_property_match_string(np, "io-channel-names",
name);
chan = of_iio_channel_get(np, index);
if (!IS_ERR(chan))
break;
else if (name && index >= 0) {
pr_err("ERROR: could not get IIO channel %s:%s(%i)\n",
np->full_name, name ? name : "", index);
return chan;
}

/*
* No matching IIO channel found on this node.
* If the parent node has a "io-channel-ranges" property,
* then we can try one of its channels.
*/
np = np->parent;
if (np && !of_get_property(np, "io-channel-ranges", NULL))
break;
}
return chan;
}

static struct iio_channel *of_iio_channel_get_all(struct device *dev)
{
struct iio_channel *chans;
int i, mapind, nummaps = 0;
int ret;

do {
ret = of_parse_phandle_with_args(dev->of_node,
"io-channels",
"#io-channel-cells",
nummaps, NULL);
if (ret < 0)
break;
} while (++nummaps);

if (nummaps == 0) /* no error, return NULL to search map table */
return NULL;

/* NULL terminated array to save passing size */
chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
if (chans == NULL)
return ERR_PTR(-ENOMEM);

/* Search for OF matches */
for (mapind = 0; mapind < nummaps; mapind++) {
ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
mapind);
if (ret)
goto error_free_chans;
}
return chans;

error_free_chans:
for (i = 0; i < mapind; i++)
iio_device_put(chans[i].indio_dev);
kfree(chans);
return ERR_PTR(ret);
}

#else /* CONFIG_OF */

static inline struct iio_channel *
of_iio_channel_get_by_name(struct device_node *np, const char *name)
{
return NULL;
}

static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
{
return NULL;
}

#endif /* CONFIG_OF */

static struct iio_channel *iio_channel_get_sys(const char *name,
const char *channel_name)
Expand Down Expand Up @@ -150,7 +309,14 @@ struct iio_channel *iio_channel_get(struct device *dev,
const char *channel_name)
{
const char *name = dev ? dev_name(dev) : NULL;
struct iio_channel *channel;

if (dev) {
channel = of_iio_channel_get_by_name(dev->of_node,
channel_name);
if (channel != NULL)
return channel;
}
return iio_channel_get_sys(name, channel_name);
}
EXPORT_SYMBOL_GPL(iio_channel_get);
Expand All @@ -173,6 +339,11 @@ struct iio_channel *iio_channel_get_all(struct device *dev)

if (dev == NULL)
return ERR_PTR(-EINVAL);

chans = of_iio_channel_get_all(dev);
if (chans)
return chans;

name = dev_name(dev);

mutex_lock(&iio_map_list_lock);
Expand Down

0 comments on commit 055f47c

Please sign in to comment.