mtd: gpio-nand: add device tree bindings

Add device tree bindings so that the gpio-nand driver may be
instantiated from the device tree.  This also allows the partitions
to be specified in the device tree.

v7:	- restore runtime device tree/non device tree detection
v6:	- convert to mtd_device_parse_register()
v5:	- fold dt config helpers into a single gpio_nand_of_get_config()
v4:	- get io sync address from gpio-control-nand,io-sync-reg
	  property rather than a resource
	- clarified a few details in the binding
v3:	- remove redundant cast and a couple of whitespace/naming
	  changes
v2:	- add CONFIG_OF guards for non-dt platforms
	- compatible becomes gpio-control-nand
	- clarify some binding details

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
此提交包含在:
Jamie Iles
2011-12-18 10:00:49 +00:00
提交者 David Woodhouse
父節點 f98872fc14
當前提交 775c322087
共有 2 個檔案被更改,包括 152 行新增7 行删除

查看文件

@@ -27,6 +27,9 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand-gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
struct gpiomtd {
void __iomem *io_sync;
@@ -171,6 +174,96 @@ static int gpio_nand_devready(struct mtd_info *mtd)
return gpio_get_value(gpiomtd->plat.gpio_rdy);
}
#ifdef CONFIG_OF
static const struct of_device_id gpio_nand_id_table[] = {
{ .compatible = "gpio-control-nand" },
{}
};
MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
static int gpio_nand_get_config_of(const struct device *dev,
struct gpio_nand_platdata *plat)
{
u32 val;
if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
if (val == 2) {
plat->options |= NAND_BUSWIDTH_16;
} else if (val != 1) {
dev_err(dev, "invalid bank-width %u\n", val);
return -EINVAL;
}
}
plat->gpio_rdy = of_get_gpio(dev->of_node, 0);
plat->gpio_nce = of_get_gpio(dev->of_node, 1);
plat->gpio_ale = of_get_gpio(dev->of_node, 2);
plat->gpio_cle = of_get_gpio(dev->of_node, 3);
plat->gpio_nwp = of_get_gpio(dev->of_node, 4);
if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
plat->chip_delay = val;
return 0;
}
static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
{
struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
u64 addr;
if (!r || of_property_read_u64(pdev->dev.of_node,
"gpio-control-nand,io-sync-reg", &addr))
return NULL;
r->start = addr;
r->end = r->start + 0x3;
r->flags = IORESOURCE_MEM;
return r;
}
#else /* CONFIG_OF */
#define gpio_nand_id_table NULL
static inline int gpio_nand_get_config_of(const struct device *dev,
struct gpio_nand_platdata *plat)
{
return -ENOSYS;
}
static inline struct resource *
gpio_nand_get_io_sync_of(struct platform_device *pdev)
{
return NULL;
}
#endif /* CONFIG_OF */
static inline int gpio_nand_get_config(const struct device *dev,
struct gpio_nand_platdata *plat)
{
int ret = gpio_nand_get_config_of(dev, plat);
if (!ret)
return ret;
if (dev->platform_data) {
memcpy(plat, dev->platform_data, sizeof(*plat));
return 0;
}
return -EINVAL;
}
static inline struct resource *
gpio_nand_get_io_sync(struct platform_device *pdev)
{
struct resource *r = gpio_nand_get_io_sync_of(pdev);
if (r)
return r;
return platform_get_resource(pdev, IORESOURCE_MEM, 1);
}
static int __devexit gpio_nand_remove(struct platform_device *dev)
{
struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
@@ -178,7 +271,7 @@ static int __devexit gpio_nand_remove(struct platform_device *dev)
nand_release(&gpiomtd->mtd_info);
res = platform_get_resource(dev, IORESOURCE_MEM, 1);
res = gpio_nand_get_io_sync(dev);
iounmap(gpiomtd->io_sync);
if (res)
release_mem_region(res->start, resource_size(res));
@@ -226,9 +319,10 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
struct gpiomtd *gpiomtd;
struct nand_chip *this;
struct resource *res0, *res1;
int ret;
struct mtd_part_parser_data ppdata = {};
int ret = 0;
if (!dev->dev.platform_data)
if (!dev->dev.of_node && !dev->dev.platform_data)
return -EINVAL;
res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -248,7 +342,7 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
goto err_map;
}
res1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
res1 = gpio_nand_get_io_sync(dev);
if (res1) {
gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret);
if (!gpiomtd->io_sync) {
@@ -257,7 +351,9 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
}
}
memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat));
ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat);
if (ret)
goto err_nce;
ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE");
if (ret)
@@ -316,8 +412,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
gpiomtd->plat.adjust_parts(&gpiomtd->plat,
gpiomtd->mtd_info.size);
mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts,
gpiomtd->plat.num_parts);
ppdata.of_node = dev->dev.of_node;
ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
gpiomtd->plat.parts,
gpiomtd->plat.num_parts);
if (ret)
goto err_wp;
platform_set_drvdata(dev, gpiomtd);
return 0;
@@ -352,6 +452,7 @@ static struct platform_driver gpio_nand_driver = {
.remove = gpio_nand_remove,
.driver = {
.name = "gpio-nand",
.of_match_table = gpio_nand_id_table,
},
};