diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-07-21 22:46:22 -0400 |
---|---|---|
committer | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-07-21 22:46:22 -0400 |
commit | 22648cbcf5efd94c2632b3fe8c5c90ae54df928d (patch) | |
tree | 56a49fcd9a974d61f1a4e224f23efe9b4fd1b438 /drivers | |
parent | db9431f0e697b132a7b6aca9c946f85851af5a39 (diff) | |
parent | 5049b88232de6414144f4cf0f4510227afd0098e (diff) |
Merge branch 'devicetree/linaro-3.0' of git://git.secretlab.ca/git/linux-2.6 into linaro-3.0
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/xsysace.c | 98 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-cpm.c | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s6000.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 29 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.c | 34 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.h | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 49 | ||||
-rw-r--r-- | drivers/of/address.c | 18 | ||||
-rw-r--r-- | drivers/of/base.c | 65 | ||||
-rw-r--r-- | drivers/of/gpio.c | 11 | ||||
-rw-r--r-- | drivers/of/platform.c | 196 | ||||
-rw-r--r-- | drivers/spi/spi_tegra.c | 12 | ||||
-rw-r--r-- | drivers/tty/serial/of_serial.c | 43 |
15 files changed, 452 insertions, 128 deletions
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 6c7fd7db6df..fb1975d82a7 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -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); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 3a20961bef1..b1d9cd28d8d 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -662,11 +662,8 @@ static int __devinit cpm_i2c_probe(struct platform_device *ofdev) /* register new adapter to i2c module... */ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); - if (data && len == 4) { - cpm->adap.nr = *data; - result = i2c_add_numbered_adapter(&cpm->adap); - } else - result = i2c_add_adapter(&cpm->adap); + cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; + result = i2c_add_numbered_adapter(&cpm->adap); if (result < 0) { dev_err(&ofdev->dev, "Unable to register with I2C\n"); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index f59224a5c76..d6036465099 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1079,7 +1079,7 @@ static int i2c_pxa_probe(struct platform_device *dev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - i2c->adap.nr = dev->id != -1 ? dev->id : 0; + i2c->adap.nr = dev->id; snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u", i2c->adap.nr); @@ -1142,10 +1142,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - if (i2c_type == REGS_CE4100) - ret = i2c_add_adapter(&i2c->adap); - else - ret = i2c_add_numbered_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); goto eadapt; diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c index cb5d01e279c..c64ba736f48 100644 --- a/drivers/i2c/busses/i2c-s6000.c +++ b/drivers/i2c/busses/i2c-s6000.c @@ -341,10 +341,7 @@ static int __devinit s6i2c_probe(struct platform_device *dev) i2c_wr16(iface, S6_I2C_TXTL, 0); platform_set_drvdata(dev, iface); - if (bus_num < 0) - rc = i2c_add_adapter(p_adap); - else - rc = i2c_add_numbered_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc) goto err_irq_free; return 0; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index fb3b4f8f815..7ac2f7a87e6 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/i2c-tegra.h> +#include <linux/of_i2c.h> #include <asm/unaligned.h> @@ -546,6 +547,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) struct resource *iomem; struct clk *clk; struct clk *i2c_clk; + const unsigned int *prop; void *base; int irq; int ret = 0; @@ -603,7 +605,17 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; - i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000; + + i2c_dev->bus_clk_rate = 100000; /* default clock rate */ + if (pdata) { + i2c_dev->bus_clk_rate = pdata->bus_clk_rate; + } else if (i2c_dev->dev->of_node) { + /* if there is a device tree node ... */ + prop = of_get_property(i2c_dev->dev->of_node, + "clock-frequency", NULL); + if (prop) + i2c_dev->bus_clk_rate = be32_to_cpup(prop); + } if (pdev->id == 3) i2c_dev->is_dvc = 1; @@ -633,6 +645,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; + i2c_dev->adapter.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { @@ -640,6 +653,8 @@ static int tegra_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(&i2c_dev->adapter); + return 0; err_free_irq: free_irq(i2c_dev->irq, i2c_dev); @@ -704,6 +719,17 @@ static int tegra_i2c_resume(struct platform_device *pdev) } #endif +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); +#else +#define tegra_i2c_of_match NULL +#endif + static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, @@ -714,6 +740,7 @@ static struct platform_driver tegra_i2c_driver = { .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, + .of_match_table = tegra_i2c_of_match, }, }; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9a58994ff7e..131079a3e29 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -925,6 +925,9 @@ EXPORT_SYMBOL(i2c_add_adapter); * or otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * + * If the requested bus number is set to -1, then this function will behave + * identically to i2c_add_adapter, and will dynamically assign a bus number. + * * If no devices have pre-been declared for this bus, then be sure to * register the adapter before any dynamically allocated ones. Otherwise * the required bus ID may not be available. @@ -940,6 +943,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap) int id; int status; + if (adap->nr == -1) /* -1 means dynamically assign bus id */ + return i2c_add_adapter(adap); if (adap->nr & ~MAX_ID_MASK) return -EINVAL; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index dbab0407f4b..e231f917225 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -49,10 +49,30 @@ static struct sdhci_ops sdhci_pltfm_ops = { * Device probing/removal * * * \*****************************************************************************/ +#if defined(CONFIG_OF) +#include <linux/of_device.h> +static const struct of_device_id sdhci_dt_ids[] = { + { .compatible = "nvidia,tegra20-sdhci", .data = &sdhci_tegra_dt_pdata }, + { } +}; +MODULE_DEVICE_TABLE(platform, sdhci_dt_ids); + +static const struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return of_match_device(sdhci_dt_ids, &pdev->dev); +} +#else +#define sdhci_dt_ids NULL +static inline struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return NULL; +} +#endif static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); struct sdhci_pltfm_data *pdata; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -61,6 +81,8 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) if (platid && platid->driver_data) pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; else pdata = pdev->dev.platform_data; @@ -140,12 +162,21 @@ err: static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) { - struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; + const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); + struct sdhci_pltfm_data *pdata; struct sdhci_host *host = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int dead; u32 scratch; + if (platid && platid->driver_data) + pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; + else + pdata = pdev->dev.platform_data; + dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -203,6 +234,7 @@ static struct platform_driver sdhci_pltfm_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, + .of_match_table = sdhci_dt_ids, }, .probe = sdhci_pltfm_probe, .remove = __devexit_p(sdhci_pltfm_remove), diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 2b37016ad0a..2a438175839 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -24,5 +24,6 @@ extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; extern struct sdhci_pltfm_data sdhci_dove_pdata; extern struct sdhci_pltfm_data sdhci_tegra_pdata; +extern struct sdhci_pltfm_data sdhci_tegra_dt_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 343c97edba3..c9d4d282041 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -18,8 +18,10 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> +#include <linux/slab.h> #include <mach/gpio.h> #include <mach/sdhci.h> @@ -216,6 +218,33 @@ out: return rc; } +static int tegra_sdhci_pltfm_dt_init(struct sdhci_host *host, + struct sdhci_pltfm_data *pdata) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + + if (pdev->dev.platform_data) { + dev_err(&pdev->dev, "%s: platform_data not NULL; aborting\n", + __func__); + return -ENODEV; + } + + plat = kzalloc(sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + pdev->dev.platform_data = plat; + + plat->cd_gpio = of_get_gpio(pdev->dev.of_node, 0); + plat->wp_gpio = of_get_gpio(pdev->dev.of_node, 1); + plat->power_gpio = of_get_gpio(pdev->dev.of_node, 2); + + dev_info(&pdev->dev, "using gpios cd=%i, wp=%i power=%i\n", + plat->cd_gpio, plat->wp_gpio, plat->power_gpio); + + return tegra_sdhci_pltfm_init(host, pdata); +} + static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -244,6 +273,16 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) clk_put(pltfm_host->clk); } +static void tegra_sdhci_pltfm_dt_exit(struct sdhci_host *host) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + + tegra_sdhci_pltfm_exit(host); + + kfree(pdev->dev.platform_data); + pdev->dev.platform_data = NULL; +} + static struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_l = tegra_sdhci_readl, @@ -261,3 +300,13 @@ struct sdhci_pltfm_data sdhci_tegra_pdata = { .init = tegra_sdhci_pltfm_init, .exit = tegra_sdhci_pltfm_exit, }; + +struct sdhci_pltfm_data sdhci_tegra_dt_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, + .init = tegra_sdhci_pltfm_dt_init, + .exit = tegra_sdhci_pltfm_dt_exit, +}; diff --git a/drivers/of/address.c b/drivers/of/address.c index b4559c58c09..da1f4b9605d 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -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 diff --git a/drivers/of/base.c b/drivers/of/base.c index 632ebae7f17..02ed36719de 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -596,6 +596,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 * @phandle_name: Name of property holding a phandle value diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 905960338fb..3007662ac61 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -21,8 +21,9 @@ #include <linux/slab.h> /** - * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API + * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from + * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * @@ -30,8 +31,8 @@ * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -int of_get_gpio_flags(struct device_node *np, int index, - enum of_gpio_flags *flags) +int of_get_named_gpio_flags(struct device_node *np, const char *propname, + int index, enum of_gpio_flags *flags) { int ret; struct device_node *gpio_np; @@ -40,7 +41,7 @@ int of_get_gpio_flags(struct device_node *np, int index, const void *gpio_spec; const __be32 *gpio_cells; - ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, + ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index, &gpio_np, &gpio_spec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); @@ -79,7 +80,7 @@ err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; } -EXPORT_SYMBOL(of_get_gpio_flags); +EXPORT_SYMBOL(of_get_named_gpio_flags); /** * of_gpio_count - Count GPIOs for a device diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 63d3cb73bdb..e75af391e28 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -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 */ diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c index 6c3aa6ecaad..b0e3586d1e1 100644 --- a/drivers/spi/spi_tegra.c +++ b/drivers/spi/spi_tegra.c @@ -546,6 +546,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev) tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; tspi->rx_dma_req.dev = tspi; + master->dev.of_node = pdev->dev.of_node; ret = spi_register_master(master); if (ret < 0) @@ -595,10 +596,21 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev) MODULE_ALIAS("platform:spi_tegra"); +#ifdef CONFIG_OF +static struct of_device_id spi_tegra_of_match_table[] __devinitdata = { + { .compatible = "nvidia,tegra20-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_tegra_of_match_table); +#else /* CONFIG_OF */ +#define spi_tegra_of_match_table NULL +#endif /* CONFIG_OF */ + static struct platform_driver spi_tegra_driver = { .driver = { .name = "spi_tegra", .owner = THIS_MODULE, + .of_match_table = spi_tegra_of_match_table, }, .remove = __devexit_p(spi_tegra_remove), }; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index c911b2419ab..e58cece6f44 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -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, }, |