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:
Коммит
8181780c16
|
@ -0,0 +1,21 @@
|
|||
* ARM Primecell Peripherals
|
||||
|
||||
ARM, Ltd. Primecell peripherals have a standard id register that can be used to
|
||||
identify the peripheral type, vendor, and revision. This value can be used for
|
||||
driver matching.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be a specific value for peripheral and "arm,primecell"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- arm,primecell-periphid : Value to override the h/w value with
|
||||
|
||||
Example:
|
||||
|
||||
serial@fff36000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00341011>;
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Freescale SoC SEC Security Engines
|
||||
Freescale SoC SEC Security Engines versions 2.x-3.x
|
||||
|
||||
Required properties:
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
* UART (Universal Asynchronous Receiver/Transmitter)
|
||||
|
||||
Required properties:
|
||||
- compatible : one of:
|
||||
- "ns8250"
|
||||
- "ns16450"
|
||||
- "ns16550a"
|
||||
- "ns16550"
|
||||
- "ns16750"
|
||||
- "ns16850"
|
||||
- "nvidia,tegra20-uart"
|
||||
- "ibm,qpace-nwp-serial"
|
||||
- "serial" if the port type is unknown.
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain uart interrupt.
|
||||
- clock-frequency : the input clock frequency for the UART.
|
||||
|
||||
Optional properties:
|
||||
- current-speed : the current active speed of the UART.
|
||||
- reg-offset : offset to apply to the mapbase from the start of the registers.
|
||||
- reg-shift : quantity to shift the register offsets by.
|
||||
- reg-io-width : the size (in bytes) of the IO accesses that should be
|
||||
performed on the device. There are some systems that require 32-bit
|
||||
accesses to the UART (e.g. TI davinci).
|
||||
- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
|
||||
RTAS and should not be registered.
|
||||
|
||||
Example:
|
||||
|
||||
uart@80230000 {
|
||||
compatible = "ns8250";
|
||||
reg = <0x80230000 0x100>;
|
||||
clock-frequency = <3686400>;
|
||||
interrupts = <10>;
|
||||
reg-shift = <2>;
|
||||
};
|
|
@ -1155,12 +1155,19 @@ static int __devinit ace_probe(struct platform_device *dev)
|
|||
{
|
||||
resource_size_t physaddr = 0;
|
||||
int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
|
||||
int id = dev->id;
|
||||
u32 id = dev->id;
|
||||
int irq = NO_IRQ;
|
||||
int i;
|
||||
|
||||
dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
|
||||
|
||||
/* device id and bus width */
|
||||
of_property_read_u32(dev->dev.of_node, "port-number", &id);
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
if (of_find_property(dev->dev.of_node, "8-bit", NULL))
|
||||
bus_width = ACE_BUS_WIDTH_8;
|
||||
|
||||
for (i = 0; i < dev->num_resources; i++) {
|
||||
if (dev->resource[i].flags & IORESOURCE_MEM)
|
||||
physaddr = dev->resource[i].start;
|
||||
|
@ -1181,57 +1188,7 @@ static int __devexit ace_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ace_platform_driver = {
|
||||
.probe = ace_probe,
|
||||
.remove = __devexit_p(ace_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "xsysace",
|
||||
},
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* OF_Platform Bus Support
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static int __devinit ace_of_probe(struct platform_device *op)
|
||||
{
|
||||
struct resource res;
|
||||
resource_size_t physaddr;
|
||||
const u32 *id;
|
||||
int irq, bus_width, rc;
|
||||
|
||||
/* device id */
|
||||
id = of_get_property(op->dev.of_node, "port-number", NULL);
|
||||
|
||||
/* physaddr */
|
||||
rc = of_address_to_resource(op->dev.of_node, 0, &res);
|
||||
if (rc) {
|
||||
dev_err(&op->dev, "invalid address\n");
|
||||
return rc;
|
||||
}
|
||||
physaddr = res.start;
|
||||
|
||||
/* irq */
|
||||
irq = irq_of_parse_and_map(op->dev.of_node, 0);
|
||||
|
||||
/* bus width */
|
||||
bus_width = ACE_BUS_WIDTH_16;
|
||||
if (of_find_property(op->dev.of_node, "8-bit", NULL))
|
||||
bus_width = ACE_BUS_WIDTH_8;
|
||||
|
||||
/* Call the bus-independent setup code */
|
||||
return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0,
|
||||
physaddr, irq, bus_width);
|
||||
}
|
||||
|
||||
static int __devexit ace_of_remove(struct platform_device *op)
|
||||
{
|
||||
ace_free(&op->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id ace_of_match[] __devinitconst = {
|
||||
{ .compatible = "xlnx,opb-sysace-1.00.b", },
|
||||
|
@ -1241,34 +1198,20 @@ static const struct of_device_id ace_of_match[] __devinitconst = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ace_of_match);
|
||||
#else /* CONFIG_OF */
|
||||
#define ace_of_match NULL
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct platform_driver ace_of_driver = {
|
||||
.probe = ace_of_probe,
|
||||
.remove = __devexit_p(ace_of_remove),
|
||||
static struct platform_driver ace_platform_driver = {
|
||||
.probe = ace_probe,
|
||||
.remove = __devexit_p(ace_remove),
|
||||
.driver = {
|
||||
.name = "xsysace",
|
||||
.owner = THIS_MODULE,
|
||||
.name = "xsysace",
|
||||
.of_match_table = ace_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
/* Registration helpers to keep the number of #ifdefs to a minimum */
|
||||
static inline int __init ace_of_register(void)
|
||||
{
|
||||
pr_debug("xsysace: registering OF binding\n");
|
||||
return platform_driver_register(&ace_of_driver);
|
||||
}
|
||||
|
||||
static inline void __exit ace_of_unregister(void)
|
||||
{
|
||||
platform_driver_unregister(&ace_of_driver);
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
/* CONFIG_OF not enabled; do nothing helpers */
|
||||
static inline int __init ace_of_register(void) { return 0; }
|
||||
static inline void __exit ace_of_unregister(void) { }
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Module init/exit routines
|
||||
*/
|
||||
|
@ -1282,11 +1225,6 @@ static int __init ace_init(void)
|
|||
goto err_blk;
|
||||
}
|
||||
|
||||
rc = ace_of_register();
|
||||
if (rc)
|
||||
goto err_of;
|
||||
|
||||
pr_debug("xsysace: registering platform binding\n");
|
||||
rc = platform_driver_register(&ace_platform_driver);
|
||||
if (rc)
|
||||
goto err_plat;
|
||||
|
@ -1295,21 +1233,17 @@ static int __init ace_init(void)
|
|||
return 0;
|
||||
|
||||
err_plat:
|
||||
ace_of_unregister();
|
||||
err_of:
|
||||
unregister_blkdev(ace_major, "xsysace");
|
||||
err_blk:
|
||||
printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);
|
||||
return rc;
|
||||
}
|
||||
module_init(ace_init);
|
||||
|
||||
static void __exit ace_exit(void)
|
||||
{
|
||||
pr_debug("Unregistering Xilinx SystemACE driver\n");
|
||||
platform_driver_unregister(&ace_platform_driver);
|
||||
ace_of_unregister();
|
||||
unregister_blkdev(ace_major, "xsysace");
|
||||
}
|
||||
|
||||
module_init(ace_init);
|
||||
module_exit(ace_exit);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -32,17 +32,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
|
|||
{
|
||||
struct resource resource;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
const __be32 *clk, *spd;
|
||||
const __be32 *prop;
|
||||
int ret, prop_size;
|
||||
u32 clk, spd, prop;
|
||||
int ret;
|
||||
|
||||
memset(port, 0, sizeof *port);
|
||||
spd = of_get_property(np, "current-speed", NULL);
|
||||
clk = of_get_property(np, "clock-frequency", NULL);
|
||||
if (!clk) {
|
||||
if (of_property_read_u32(np, "clock-frequency", &clk)) {
|
||||
dev_warn(&ofdev->dev, "no clock-frequency property set\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
/* If current-speed was set, then try not to change it. */
|
||||
if (of_property_read_u32(np, "current-speed", &spd) == 0)
|
||||
port->custom_divisor = clk / (16 * spd);
|
||||
|
||||
ret = of_address_to_resource(np, 0, &resource);
|
||||
if (ret) {
|
||||
|
@ -54,25 +54,35 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
|
|||
port->mapbase = resource.start;
|
||||
|
||||
/* Check for shifted address mapping */
|
||||
prop = of_get_property(np, "reg-offset", &prop_size);
|
||||
if (prop && (prop_size == sizeof(u32)))
|
||||
port->mapbase += be32_to_cpup(prop);
|
||||
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
|
||||
port->mapbase += prop;
|
||||
|
||||
/* Check for registers offset within the devices address range */
|
||||
prop = of_get_property(np, "reg-shift", &prop_size);
|
||||
if (prop && (prop_size == sizeof(u32)))
|
||||
port->regshift = be32_to_cpup(prop);
|
||||
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
|
||||
port->regshift = prop;
|
||||
|
||||
port->irq = irq_of_parse_and_map(np, 0);
|
||||
port->iotype = UPIO_MEM;
|
||||
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
|
||||
switch (prop) {
|
||||
case 1:
|
||||
port->iotype = UPIO_MEM;
|
||||
break;
|
||||
case 4:
|
||||
port->iotype = UPIO_MEM32;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
|
||||
prop);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
port->type = type;
|
||||
port->uartclk = be32_to_cpup(clk);
|
||||
port->uartclk = clk;
|
||||
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
|
||||
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
port->dev = &ofdev->dev;
|
||||
/* If current-speed was set, then try not to change it. */
|
||||
if (spd)
|
||||
port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -171,6 +181,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
|
|||
{ .compatible = "ns16550", .data = (void *)PORT_16550, },
|
||||
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
|
||||
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
|
||||
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
|
||||
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
|
||||
{ .compatible = "ibm,qpace-nwp-serial",
|
||||
.data = (void *)PORT_NWPSERIAL, },
|
||||
|
|
|
@ -195,6 +195,13 @@ extern struct device_node *of_find_node_with_property(
|
|||
extern struct property *of_find_property(const struct device_node *np,
|
||||
const char *name,
|
||||
int *lenp);
|
||||
extern int of_property_read_u32_array(const struct device_node *np,
|
||||
char *propname,
|
||||
u32 *out_values,
|
||||
size_t sz);
|
||||
|
||||
extern int of_property_read_string(struct device_node *np, char *propname,
|
||||
const char **out_string);
|
||||
extern int of_device_is_compatible(const struct device_node *device,
|
||||
const char *);
|
||||
extern int of_device_is_available(const struct device_node *device);
|
||||
|
@ -227,12 +234,32 @@ extern void of_attach_node(struct device_node *);
|
|||
extern void of_detach_node(struct device_node *);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#else /* CONFIG_OF */
|
||||
|
||||
static inline bool of_have_populated_dt(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int of_property_read_u32_array(const struct device_node *np,
|
||||
char *propname, u32 *out_values, size_t sz)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int of_property_read_string(struct device_node *np,
|
||||
char *propname, const char **out_string)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static inline int of_property_read_u32(const struct device_node *np,
|
||||
char *propname,
|
||||
u32 *out_value)
|
||||
{
|
||||
return of_property_read_u32_array(np, propname, out_value, 1);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_OF_H */
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#ifndef __OF_ADDRESS_H
|
||||
#define __OF_ADDRESS_H
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
|
||||
extern int of_address_to_resource(struct device_node *dev, int index,
|
||||
struct resource *r);
|
||||
extern struct device_node *of_find_matching_node_by_address(
|
||||
struct device_node *from,
|
||||
const struct of_device_id *matches,
|
||||
u64 base_address);
|
||||
extern void __iomem *of_iomap(struct device_node *device, int index);
|
||||
|
||||
/* Extract an address from a device, returns the region size and
|
||||
|
|
|
@ -19,6 +19,40 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/**
|
||||
* struct of_dev_auxdata - lookup table entry for device names & platform_data
|
||||
* @compatible: compatible value of node to match against node
|
||||
* @phys_addr: Start address of registers to match against node
|
||||
* @name: Name to assign for matching nodes
|
||||
* @platform_data: platform_data to assign for matching nodes
|
||||
*
|
||||
* This lookup table allows the caller of of_platform_populate() to override
|
||||
* the names of devices when creating devices from the device tree. The table
|
||||
* should be terminated with an empty entry. It also allows the platform_data
|
||||
* pointer to be set.
|
||||
*
|
||||
* The reason for this functionality is that some Linux infrastructure uses
|
||||
* the device name to look up a specific device, but the Linux-specific names
|
||||
* are not encoded into the device tree, so the kernel needs to provide specific
|
||||
* values.
|
||||
*
|
||||
* Note: Using an auxdata lookup table should be considered a last resort when
|
||||
* converting a platform to use the DT. Normally the automatically generated
|
||||
* device name will not matter, and drivers should obtain data from the device
|
||||
* node instead of from an anonymouns platform_data pointer.
|
||||
*/
|
||||
struct of_dev_auxdata {
|
||||
char *compatible;
|
||||
resource_size_t phys_addr;
|
||||
char *name;
|
||||
void *platform_data;
|
||||
};
|
||||
|
||||
/* Macro to simplify populating a lookup table */
|
||||
#define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \
|
||||
{ .compatible = _compat, .phys_addr = _phys, .name = _name, \
|
||||
.platform_data = _pdata }
|
||||
|
||||
/**
|
||||
* of_platform_driver - Legacy of-aware driver for platform devices.
|
||||
*
|
||||
|
@ -40,6 +74,8 @@ struct of_platform_driver
|
|||
#define to_of_platform_driver(drv) \
|
||||
container_of(drv,struct of_platform_driver, driver)
|
||||
|
||||
extern const struct of_device_id of_default_bus_match_table[];
|
||||
|
||||
/* Platform drivers register/unregister */
|
||||
extern struct platform_device *of_device_alloc(struct device_node *np,
|
||||
const char *bus_id,
|
||||
|
@ -55,6 +91,10 @@ extern struct platform_device *of_platform_device_create(struct device_node *np,
|
|||
extern int of_platform_bus_probe(struct device_node *root,
|
||||
const struct of_device_id *matches,
|
||||
struct device *parent);
|
||||
extern int of_platform_populate(struct device_node *root,
|
||||
const struct of_device_id *matches,
|
||||
const struct of_dev_auxdata *lookup,
|
||||
struct device *parent);
|
||||
#endif /* !CONFIG_SPARC */
|
||||
|
||||
#endif /* CONFIG_OF_DEVICE */
|
||||
|
|
Загрузка…
Ссылка в новой задаче