Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 282859
b: refs/heads/master
c: 775c322
h: refs/heads/master
i:
  282857: ab1653b
  282855: a110d76
v: v3
  • Loading branch information
Jamie Iles authored and David Woodhouse committed Jan 9, 2012
1 parent 47b7b9c commit 9a99d72
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 8 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: f98872fc14ecb96f796443911b6bc4767e58e885
refs/heads/master: 775c32208708de3e2e2379c85e429ab11957f864
44 changes: 44 additions & 0 deletions trunk/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
GPIO assisted NAND flash

The GPIO assisted NAND flash uses a memory mapped interface to
read/write the NAND commands and data and GPIO pins for the control
signals.

Required properties:
- compatible : "gpio-control-nand"
- reg : should specify localbus chip select and size used for the chip. The
resource describes the data bus connected to the NAND flash and all accesses
are made in native endianness.
- #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions.
- gpios : specifies the gpio pins to control the NAND device. nwp is an
optional gpio and may be set to 0 if not present.

Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width
defaults to 1 byte.
- chip-delay : chip dependent delay for transferring data from array to
read registers (tR). If not present then a default of 20us is used.
- gpio-control-nand,io-sync-reg : A 64-bit physical address for a read
location used to guard against bus reordering with regards to accesses to
the GPIO's and the NAND flash data bus. If present, then after changing
GPIO state and before and after command byte writes, this register will be
read to ensure that the GPIO accesses have completed.

Examples:

gpio-nand@1,0 {
compatible = "gpio-control-nand";
reg = <1 0x0000 0x2>;
#address-cells = <1>;
#size-cells = <1>;
gpios = <&banka 1 0 /* rdy */
&banka 2 0 /* nce */
&banka 3 0 /* ale */
&banka 4 0 /* cle */
0 /* nwp */>;

partition@0 {
...
};
};
115 changes: 108 additions & 7 deletions trunk/drivers/mtd/nand/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -171,14 +174,104 @@ 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);
struct resource *res;

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));
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
},
};

Expand Down

0 comments on commit 9a99d72

Please sign in to comment.