Merge branch 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6

* 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6:
  dt: include linux/errno.h in linux/of_address.h
  of/address: Add of_find_matching_node_by_address helper
  dt: remove extra xsysace platform_driver registration
  tty/serial: Add devicetree support for nVidia Tegra serial ports
  dt: add empty of_property_read_u32[_array] for non-dt
  dt: bindings: move SEC node under new crypto/
  dt: add helper function to read u32 arrays
  tty/serial: change of_serial to use new of_property_read_u32() api
  dt: add 'const' for of_property_read_string parameter **out_string
  dt: add helper functions to read u32 and string property values
  tty: of_serial: support for 32 bit accesses
  dt: document the of_serial bindings
  dt/platform: allow device name to be overridden
  drivers/amba: create devices from device tree
  dt: add of_platform_populate() for creating device from the device tree
  dt: Add default match table for bus ids
This commit is contained in:
Linus Torvalds 2011-07-22 14:53:38 -07:00
commit 8181780c16
11 changed files with 444 additions and 109 deletions

View file

@ -577,6 +577,24 @@ int of_address_to_resource(struct device_node *dev, int index,
}
EXPORT_SYMBOL_GPL(of_address_to_resource);
struct device_node *of_find_matching_node_by_address(struct device_node *from,
const struct of_device_id *matches,
u64 base_address)
{
struct device_node *dn = of_find_matching_node(from, matches);
struct resource res;
while (dn) {
if (of_address_to_resource(dn, 0, &res))
continue;
if (res.start == base_address)
return dn;
dn = of_find_matching_node(dn, matches);
}
return NULL;
}
/**
* of_iomap - Maps the memory mapped IO for a given device_node

View file

@ -595,6 +595,71 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
* of_property_read_u32_array - Find and read an array of 32 bit integers
* from a property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_value: pointer to return value, modified only if return value is 0.
*
* Search for a property in a device node and read 32-bit value(s) from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u32 value can be decoded.
*/
int of_property_read_u32_array(const struct device_node *np, char *propname,
u32 *out_values, size_t sz)
{
struct property *prop = of_find_property(np, propname, NULL);
const __be32 *val;
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
if ((sz * sizeof(*out_values)) > prop->length)
return -EOVERFLOW;
val = prop->value;
while (sz--)
*out_values++ = be32_to_cpup(val++);
return 0;
}
EXPORT_SYMBOL_GPL(of_property_read_u32_array);
/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_string: pointer to null terminated return string, modified only if
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
* terminated string value (pointer to data, not a copy). Returns 0 on
* success, -EINVAL if the property does not exist, -ENODATA if property
* does not have a value, and -EILSEQ if the string is not null-terminated
* within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
int of_property_read_string(struct device_node *np, char *propname,
const char **out_string)
{
struct property *prop = of_find_property(np, propname, NULL);
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
if (strnlen(prop->value, prop->length) >= prop->length)
return -EILSEQ;
*out_string = prop->value;
return 0;
}
EXPORT_SYMBOL_GPL(of_property_read_string);
/**
* of_parse_phandle - Resolve a phandle property to a device_node pointer
* @np: Pointer to device node holding phandle property

View file

@ -13,6 +13,7 @@
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/amba/bus.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
@ -22,6 +23,14 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
const struct of_device_id of_default_bus_match_table[] = {
{ .compatible = "simple-bus", },
#ifdef CONFIG_ARM_AMBA
{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
{} /* Empty terminated list */
};
static int of_dev_node_match(struct device *dev, void *data)
{
return dev->of_node == data;
@ -168,17 +177,20 @@ struct platform_device *of_device_alloc(struct device_node *np,
EXPORT_SYMBOL(of_device_alloc);
/**
* of_platform_device_create - Alloc, initialize and register an of_device
* of_platform_device_create_pdata - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
* @bus_id: name to assign device
* @platform_data: pointer to populate platform_data pointer with
* @parent: Linux device model parent device.
*
* Returns pointer to created platform device, or NULL if a device was not
* registered. Unavailable devices will not get registered.
*/
struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent)
struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;
@ -194,6 +206,7 @@ struct platform_device *of_platform_device_create(struct device_node *np,
#endif
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
@ -207,8 +220,111 @@ struct platform_device *of_platform_device_create(struct device_node *np,
return dev;
}
/**
* of_platform_device_create - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
* @bus_id: name to assign device
* @parent: Linux device model parent device.
*
* Returns pointer to created platform device, or NULL if a device was not
* registered. Unavailable devices will not get registered.
*/
struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent)
{
return of_platform_device_create_pdata(np, bus_id, NULL, parent);
}
EXPORT_SYMBOL(of_platform_device_create);
#ifdef CONFIG_ARM_AMBA
static struct amba_device *of_amba_device_create(struct device_node *node,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct amba_device *dev;
const void *prop;
int i, ret;
pr_debug("Creating amba device %s\n", node->full_name);
if (!of_device_is_available(node))
return NULL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
/* setup generic device info */
dev->dev.coherent_dma_mask = ~0;
dev->dev.of_node = of_node_get(node);
dev->dev.parent = parent;
dev->dev.platform_data = platform_data;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
else
of_device_make_bus_id(&dev->dev);
/* setup amba-specific device info */
dev->dma_mask = ~0;
/* Allow the HW Peripheral ID to be overridden */
prop = of_get_property(node, "arm,primecell-periphid", NULL);
if (prop)
dev->periphid = of_read_ulong(prop, 1);
/* Decode the IRQs and address ranges */
for (i = 0; i < AMBA_NR_IRQS; i++)
dev->irq[i] = irq_of_parse_and_map(node, i);
ret = of_address_to_resource(node, 0, &dev->res);
if (ret)
goto err_free;
ret = amba_device_register(dev, &iomem_resource);
if (ret)
goto err_free;
return dev;
err_free:
kfree(dev);
return NULL;
}
#else /* CONFIG_ARM_AMBA */
static struct amba_device *of_amba_device_create(struct device_node *node,
const char *bus_id,
void *platform_data,
struct device *parent)
{
return NULL;
}
#endif /* CONFIG_ARM_AMBA */
/**
* of_devname_lookup() - Given a device node, lookup the preferred Linux name
*/
static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup,
struct device_node *np)
{
struct resource res;
if (lookup) {
for(; lookup->name != NULL; lookup++) {
if (!of_device_is_compatible(np, lookup->compatible))
continue;
if (of_address_to_resource(np, 0, &res))
continue;
if (res.start != lookup->phys_addr)
continue;
pr_debug("%s: devname=%s\n", np->full_name, lookup->name);
return lookup;
}
}
return NULL;
}
/**
* of_platform_bus_create() - Create a device for a node and its children.
* @bus: device node of the bus to instantiate
@ -221,19 +337,41 @@ EXPORT_SYMBOL(of_platform_device_create);
*/
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
struct device *parent)
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
dev = of_platform_device_create(bus, NULL, parent);
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, "compatible", NULL))) {
pr_debug("%s() - skipping %s, no compatible prop\n",
__func__, bus->full_name);
return 0;
}
auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
}
if (of_device_is_compatible(bus, "arm,primecell")) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;
for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
rc = of_platform_bus_create(child, matches, &dev->dev);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
@ -267,11 +405,11 @@ int of_platform_bus_probe(struct device_node *root,
/* Do a self check of bus type, if there's a match, create children */
if (of_match_node(matches, root)) {
rc = of_platform_bus_create(root, matches, parent);
rc = of_platform_bus_create(root, matches, NULL, parent, false);
} else for_each_child_of_node(root, child) {
if (!of_match_node(matches, child))
continue;
rc = of_platform_bus_create(child, matches, parent);
rc = of_platform_bus_create(child, matches, NULL, parent, false);
if (rc)
break;
}
@ -280,4 +418,44 @@ int of_platform_bus_probe(struct device_node *root,
return rc;
}
EXPORT_SYMBOL(of_platform_bus_probe);
/**
* of_platform_populate() - Populate platform_devices from device tree data
* @root: parent of the first level to probe or NULL for the root of the tree
* @matches: match table, NULL to use the default
* @parent: parent to hook devices from, NULL for toplevel
*
* Similar to of_platform_bus_probe(), this function walks the device tree
* and creates devices from nodes. It differs in that it follows the modern
* convention of requiring all device nodes to have a 'compatible' property,
* and it is suitable for creating devices which are children of the root
* node (of_platform_bus_probe will only create children of the root which
* are selected by the @matches argument).
*
* New board support should be using this function instead of
* of_platform_bus_probe().
*
* Returns 0 on success, < 0 on failure.
*/
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
#endif /* !CONFIG_SPARC */