Message ID | 1327727444-23908-5-git-send-email-plagnioj@jcrosoft.com |
---|---|
State | New, archived |
Headers | show |
On Sat, Jan 28, 2012 at 06:10:43AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote: > use a local copy of board informatin and fill with DT data > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > Cc: Nicolas Ferre <nicolas.ferre@atmel.com> > Cc: devicetree-discuss@lists.ozlabs.org > Cc: linux-mtd@lists.infradead.org Nitpicks below, but otherwise: Acked-by: Grant Likely <grant.likely@secretlab.ca> > --- > .../devicetree/bindings/mtd/atmel-nand.txt | 41 ++++++++ > drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++---- > 2 files changed, 130 insertions(+), 18 deletions(-) > create mode 100644 Documentation/devicetree/bindings/mtd/atmel-nand.txt > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > new file mode 100644 > index 0000000..a910ab9 > --- /dev/null > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -0,0 +1,41 @@ > +Atmel NAND flash > + > +Required properties: > +- compatible : "atmel,at91rm9200-nand". > +- reg : should specify localbus address and size used for the chip, > + and if availlable the ECC. > +- atmel,nand-addr-offset : offset for the address latch. > +- atmel,nand-cmd-offset : offset for the command latch. > +- #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. detect is an > + optional gpio and may be set to 0 if not present. > + > +Optional properties: > +- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. > + Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", > + "soft_bch". > +- nand-bus-width : 8 or 16 bus width if not present 8 > +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false > + > +Examples: > +nand0: nand@40000000,0 { > + compatible = "atmel,at91rm9200-nand"; > + #address-cells = <1>; > + #size-cells = <1>; > + reg = <0x40000000 0x10000000 > + 0xffffe800 0x200 > + >; > + atmel,nand-addr-offset = <21>; > + atmel,nand-cmd-offset = <22>; > + nand-on-flash-bbt = <1>; > + nand-ecc-mode = "soft"; > + gpios = <&pioC 13 0 > + &pioC 14 0 > + 0 > + >; > + partition@0 { > + ... > + }; > +}; > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index d3bde9b..ea7643a 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,10 @@ > #include <linux/module.h> > #include <linux/moduleparam.h> > #include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/of_gpio.h> > +#include <linux/of_mtd.h> > #include <linux/mtd/mtd.h> > #include <linux/mtd/nand.h> > #include <linux/mtd/partitions.h> > @@ -83,7 +87,7 @@ struct atmel_nand_host { > struct mtd_info mtd; > void __iomem *io_base; > dma_addr_t io_phys; > - struct atmel_nand_data *board; > + struct atmel_nand_data board; > struct device *dev; > void __iomem *ecc; > > @@ -101,8 +105,8 @@ static int cpu_has_dma(void) > */ > static void atmel_nand_enable(struct atmel_nand_host *host) > { > - if (gpio_is_valid(host->board->enable_pin)) > - gpio_set_value(host->board->enable_pin, 0); > + if (gpio_is_valid(host->board.enable_pin)) > + gpio_set_value(host->board.enable_pin, 0); > } > > /* > @@ -110,8 +114,8 @@ static void atmel_nand_enable(struct atmel_nand_host *host) > */ > static void atmel_nand_disable(struct atmel_nand_host *host) > { > - if (gpio_is_valid(host->board->enable_pin)) > - gpio_set_value(host->board->enable_pin, 1); > + if (gpio_is_valid(host->board.enable_pin)) > + gpio_set_value(host->board.enable_pin, 1); > } > > /* > @@ -132,9 +136,9 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl > return; > > if (ctrl & NAND_CLE) > - writeb(cmd, host->io_base + (1 << host->board->cle)); > + writeb(cmd, host->io_base + (1 << host->board.cle)); > else > - writeb(cmd, host->io_base + (1 << host->board->ale)); > + writeb(cmd, host->io_base + (1 << host->board.ale)); > } > > /* > @@ -145,8 +149,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) > struct nand_chip *nand_chip = mtd->priv; > struct atmel_nand_host *host = nand_chip->priv; > > - return gpio_get_value(host->board->rdy_pin) ^ > - !!host->board->rdy_pin_active_low; > + return gpio_get_value(host->board.rdy_pin) ^ > + !!host->board.rdy_pin_active_low; > } > > static void dma_complete_func(void *completion) > @@ -432,6 +436,54 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) > } > } > > +static int __devinit atmel_of_init_port(struct atmel_nand_host *host, > + struct device_node *np) > +{ > + u32 val; > + int ecc_mode; > + struct atmel_nand_data *board = &host->board; > + enum of_gpio_flags flags; > + > + if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { > + if (val >= 32) { > + dev_err(host->dev, "invalid addr-offset %u\n", val); > + return -EINVAL; > + } > + board->ale = val; > + } > + > + if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) { > + if (val >= 32) { > + dev_err(host->dev, "invalid cmd-offset %u\n", val); > + return -EINVAL; > + } > + board->cle = val; > + } > + > + ecc_mode = of_get_nand_ecc_mode(np); > + > + if (ecc_mode < 0) > + board->ecc_mode = NAND_ECC_SOFT; > + else > + board->ecc_mode = ecc_mode; Nit: board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode; > + > + board->on_flash_bbt = of_get_nand_on_flash_bbt(np); > + > + if (of_get_nand_bus_width(np) == 16) > + board->bus_width_16 = 1; > + > + board->rdy_pin = of_get_gpio_flags(np, 0, &flags); > + if (flags == OF_GPIO_ACTIVE_LOW) > + board->rdy_pin_active_low = 1; > + else > + board->rdy_pin_active_low = 0; Nit: board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW); Just a bit more compact that way. > + > + board->enable_pin = of_get_gpio(np, 1); > + board->det_pin = of_get_gpio(np, 2); > + > + return 0; > +} > + > /* > * Probe for the NAND device. > */ > @@ -442,6 +494,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > struct nand_chip *nand_chip; > struct resource *regs; > struct resource *mem; > + struct mtd_part_parser_data ppdata = {}; > int res; > > mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > @@ -468,8 +521,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > > mtd = &host->mtd; > nand_chip = &host->nand_chip; > - host->board = pdev->dev.platform_data; > host->dev = &pdev->dev; > + if (pdev->dev.of_node) { > + res = atmel_of_init_port(host, pdev->dev.of_node); > + if (res) > + goto err_nand_ioremap; > + } else { > + memcpy(&host->board, pdev->dev.platform_data, > + sizeof(struct atmel_nand_data)); > + } > > nand_chip->priv = host; /* link the private data structures */ > mtd->priv = nand_chip; > @@ -480,10 +540,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > nand_chip->IO_ADDR_W = host->io_base; > nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; > > - if (gpio_is_valid(host->board->rdy_pin)) > + if (gpio_is_valid(host->board.rdy_pin)) > nand_chip->dev_ready = atmel_nand_device_ready; > > - nand_chip->ecc.mode = host->board->ecc_mode; > + nand_chip->ecc.mode = host->board.ecc_mode; > > regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); > if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) { > @@ -508,7 +568,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > > nand_chip->chip_delay = 20; /* 20us command delay time */ > > - if (host->board->bus_width_16) /* 16-bit bus width */ > + if (host->board.bus_width_16) /* 16-bit bus width */ > nand_chip->options |= NAND_BUSWIDTH_16; > > nand_chip->read_buf = atmel_read_buf; > @@ -517,15 +577,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > platform_set_drvdata(pdev, host); > atmel_nand_enable(host); > > - if (gpio_is_valid(host->board->det_pin)) { > - if (gpio_get_value(host->board->det_pin)) { > + if (gpio_is_valid(host->board.det_pin)) { > + if (gpio_get_value(host->board.det_pin)) { > printk(KERN_INFO "No SmartMedia card inserted.\n"); > res = -ENXIO; > goto err_no_card; > } > } > > - if (host->board->on_flash_bbt || on_flash_bbt) { > + if (host->board.on_flash_bbt || on_flash_bbt) { > printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); > nand_chip->bbt_options |= NAND_BBT_USE_FLASH; > } > @@ -600,8 +660,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > } > > mtd->name = "atmel_nand"; > - res = mtd_device_parse_register(mtd, NULL, 0, > - host->board->parts, host->board->num_parts); > + ppdata.of_node = pdev->dev.of_node; > + res = mtd_device_parse_register(mtd, NULL, &ppdata, > + host->board.parts, host->board.num_parts); > if (!res) > return res; > > @@ -645,11 +706,21 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) > return 0; > } > > +#if defined(CONFIG_OF) > +static const struct of_device_id atmel_nand_dt_ids[] = { > + { .compatible = "atmel,at91rm9200-nand" }, > + { /* sentinel */ } > +}; > + > +MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids); > +#endif > + > static struct platform_driver atmel_nand_driver = { > .remove = __exit_p(atmel_nand_remove), > .driver = { > .name = "atmel_nand", > .owner = THIS_MODULE, > + .of_match_table = of_match_ptr(atmel_nand_dt_ids), > }, > }; > > -- > 1.7.7 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hi, On Fri, Jan 27, 2012 at 9:10 PM, Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> wrote: > use a local copy of board informatin and fill with DT data > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > Cc: Nicolas Ferre <nicolas.ferre@atmel.com> > Cc: devicetree-discuss@lists.ozlabs.org > Cc: linux-mtd@lists.infradead.org > --- > .../devicetree/bindings/mtd/atmel-nand.txt | 41 ++++++++ > drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++---- > 2 files changed, 130 insertions(+), 18 deletions(-) > create mode 100644 Documentation/devicetree/bindings/mtd/atmel-nand.txt > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > new file mode 100644 > index 0000000..a910ab9 > --- /dev/null > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -0,0 +1,41 @@ > +Atmel NAND flash > + > +Required properties: > +- compatible : "atmel,at91rm9200-nand". > +- reg : should specify localbus address and size used for the chip, > + and if availlable the ECC. > +- atmel,nand-addr-offset : offset for the address latch. > +- atmel,nand-cmd-offset : offset for the command latch. > +- #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. detect is an > + optional gpio and may be set to 0 if not present. What does this mean please? What is 'detect' and what 'control' do the gpios provide? Below you have two GPIOs pioC 13 and pioC 14. I think the binding should document the two GPIOs, the order, and what they are for. > + > +Optional properties: > +- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. > + Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", > + "soft_bch". > +- nand-bus-width : 8 or 16 bus width if not present 8 > +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false > + > +Examples: > +nand0: nand@40000000,0 { > + compatible = "atmel,at91rm9200-nand"; > + #address-cells = <1>; > + #size-cells = <1>; > + reg = <0x40000000 0x10000000 > + 0xffffe800 0x200 > + >; > + atmel,nand-addr-offset = <21>; > + atmel,nand-cmd-offset = <22>; > + nand-on-flash-bbt = <1>; > + nand-ecc-mode = "soft"; > + gpios = <&pioC 13 0 > + &pioC 14 0 > + 0 Sorry, I haven't seen this before, perhaps it is a standard thing in Linux. Does 0 mean end of list? Can we not just use the property's size value for this? Regards, Simon > + >; > + partition@0 { > + ... > + }; > +}; > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index d3bde9b..ea7643a 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,10 @@ > #include <linux/module.h> > #include <linux/moduleparam.h> > #include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/of_gpio.h> > +#include <linux/of_mtd.h> > #include <linux/mtd/mtd.h> > #include <linux/mtd/nand.h> > #include <linux/mtd/partitions.h> > @@ -83,7 +87,7 @@ struct atmel_nand_host { > struct mtd_info mtd; > void __iomem *io_base; > dma_addr_t io_phys; > - struct atmel_nand_data *board; > + struct atmel_nand_data board; > struct device *dev; > void __iomem *ecc; > > @@ -101,8 +105,8 @@ static int cpu_has_dma(void) > */ > static void atmel_nand_enable(struct atmel_nand_host *host) > { > - if (gpio_is_valid(host->board->enable_pin)) > - gpio_set_value(host->board->enable_pin, 0); > + if (gpio_is_valid(host->board.enable_pin)) > + gpio_set_value(host->board.enable_pin, 0); > } > > /* > @@ -110,8 +114,8 @@ static void atmel_nand_enable(struct atmel_nand_host *host) > */ > static void atmel_nand_disable(struct atmel_nand_host *host) > { > - if (gpio_is_valid(host->board->enable_pin)) > - gpio_set_value(host->board->enable_pin, 1); > + if (gpio_is_valid(host->board.enable_pin)) > + gpio_set_value(host->board.enable_pin, 1); > } > > /* > @@ -132,9 +136,9 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl > return; > > if (ctrl & NAND_CLE) > - writeb(cmd, host->io_base + (1 << host->board->cle)); > + writeb(cmd, host->io_base + (1 << host->board.cle)); > else > - writeb(cmd, host->io_base + (1 << host->board->ale)); > + writeb(cmd, host->io_base + (1 << host->board.ale)); > } > > /* > @@ -145,8 +149,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) > struct nand_chip *nand_chip = mtd->priv; > struct atmel_nand_host *host = nand_chip->priv; > > - return gpio_get_value(host->board->rdy_pin) ^ > - !!host->board->rdy_pin_active_low; > + return gpio_get_value(host->board.rdy_pin) ^ > + !!host->board.rdy_pin_active_low; > } > > static void dma_complete_func(void *completion) > @@ -432,6 +436,54 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) > } > } > > +static int __devinit atmel_of_init_port(struct atmel_nand_host *host, > + struct device_node *np) > +{ > + u32 val; > + int ecc_mode; > + struct atmel_nand_data *board = &host->board; > + enum of_gpio_flags flags; > + > + if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { > + if (val >= 32) { > + dev_err(host->dev, "invalid addr-offset %u\n", val); > + return -EINVAL; > + } > + board->ale = val; > + } > + > + if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) { > + if (val >= 32) { > + dev_err(host->dev, "invalid cmd-offset %u\n", val); > + return -EINVAL; > + } > + board->cle = val; > + } > + > + ecc_mode = of_get_nand_ecc_mode(np); > + > + if (ecc_mode < 0) > + board->ecc_mode = NAND_ECC_SOFT; > + else > + board->ecc_mode = ecc_mode; > + > + board->on_flash_bbt = of_get_nand_on_flash_bbt(np); > + > + if (of_get_nand_bus_width(np) == 16) > + board->bus_width_16 = 1; > + > + board->rdy_pin = of_get_gpio_flags(np, 0, &flags); > + if (flags == OF_GPIO_ACTIVE_LOW) > + board->rdy_pin_active_low = 1; > + else > + board->rdy_pin_active_low = 0; > + > + board->enable_pin = of_get_gpio(np, 1); > + board->det_pin = of_get_gpio(np, 2); > + > + return 0; > +} > + > /* > * Probe for the NAND device. > */ > @@ -442,6 +494,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > struct nand_chip *nand_chip; > struct resource *regs; > struct resource *mem; > + struct mtd_part_parser_data ppdata = {}; > int res; > > mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > @@ -468,8 +521,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > > mtd = &host->mtd; > nand_chip = &host->nand_chip; > - host->board = pdev->dev.platform_data; > host->dev = &pdev->dev; > + if (pdev->dev.of_node) { > + res = atmel_of_init_port(host, pdev->dev.of_node); > + if (res) > + goto err_nand_ioremap; > + } else { > + memcpy(&host->board, pdev->dev.platform_data, > + sizeof(struct atmel_nand_data)); > + } > > nand_chip->priv = host; /* link the private data structures */ > mtd->priv = nand_chip; > @@ -480,10 +540,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > nand_chip->IO_ADDR_W = host->io_base; > nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; > > - if (gpio_is_valid(host->board->rdy_pin)) > + if (gpio_is_valid(host->board.rdy_pin)) > nand_chip->dev_ready = atmel_nand_device_ready; > > - nand_chip->ecc.mode = host->board->ecc_mode; > + nand_chip->ecc.mode = host->board.ecc_mode; > > regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); > if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) { > @@ -508,7 +568,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > > nand_chip->chip_delay = 20; /* 20us command delay time */ > > - if (host->board->bus_width_16) /* 16-bit bus width */ > + if (host->board.bus_width_16) /* 16-bit bus width */ > nand_chip->options |= NAND_BUSWIDTH_16; > > nand_chip->read_buf = atmel_read_buf; > @@ -517,15 +577,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > platform_set_drvdata(pdev, host); > atmel_nand_enable(host); > > - if (gpio_is_valid(host->board->det_pin)) { > - if (gpio_get_value(host->board->det_pin)) { > + if (gpio_is_valid(host->board.det_pin)) { > + if (gpio_get_value(host->board.det_pin)) { > printk(KERN_INFO "No SmartMedia card inserted.\n"); > res = -ENXIO; > goto err_no_card; > } > } > > - if (host->board->on_flash_bbt || on_flash_bbt) { > + if (host->board.on_flash_bbt || on_flash_bbt) { > printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); > nand_chip->bbt_options |= NAND_BBT_USE_FLASH; > } > @@ -600,8 +660,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) > } > > mtd->name = "atmel_nand"; > - res = mtd_device_parse_register(mtd, NULL, 0, > - host->board->parts, host->board->num_parts); > + ppdata.of_node = pdev->dev.of_node; > + res = mtd_device_parse_register(mtd, NULL, &ppdata, > + host->board.parts, host->board.num_parts); > if (!res) > return res; > > @@ -645,11 +706,21 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) > return 0; > } > > +#if defined(CONFIG_OF) > +static const struct of_device_id atmel_nand_dt_ids[] = { > + { .compatible = "atmel,at91rm9200-nand" }, > + { /* sentinel */ } > +}; > + > +MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids); > +#endif > + > static struct platform_driver atmel_nand_driver = { > .remove = __exit_p(atmel_nand_remove), > .driver = { > .name = "atmel_nand", > .owner = THIS_MODULE, > + .of_match_table = of_match_ptr(atmel_nand_dt_ids), > }, > }; > > -- > 1.7.7 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On 10:31 Sun 29 Jan , Simon Glass wrote: > Hi, > > On Fri, Jan 27, 2012 at 9:10 PM, Jean-Christophe PLAGNIOL-VILLARD > <plagnioj@jcrosoft.com> wrote: > > use a local copy of board informatin and fill with DT data > > > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > > Cc: Nicolas Ferre <nicolas.ferre@atmel.com> > > Cc: devicetree-discuss@lists.ozlabs.org > > Cc: linux-mtd@lists.infradead.org > > --- > > .../devicetree/bindings/mtd/atmel-nand.txt | 41 ++++++++ > > drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++---- > > 2 files changed, 130 insertions(+), 18 deletions(-) > > create mode 100644 Documentation/devicetree/bindings/mtd/atmel-nand.txt > > > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > > new file mode 100644 > > index 0000000..a910ab9 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > > @@ -0,0 +1,41 @@ > > +Atmel NAND flash > > + > > +Required properties: > > +- compatible : "atmel,at91rm9200-nand". > > +- reg : should specify localbus address and size used for the chip, > > + and if availlable the ECC. > > +- atmel,nand-addr-offset : offset for the address latch. > > +- atmel,nand-cmd-offset : offset for the command latch. > > +- #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. detect is an > > + optional gpio and may be set to 0 if not present. > > What does this mean please? What is 'detect' and what 'control' do the > gpios provide? > > Below you have two GPIOs pioC 13 and pioC 14. I think the binding > should document the two GPIOs, the order, and what they are for. no as it's said in the binding the detect pin is optional > > > + > > +Optional properties: > > +- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. > > + Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", > > + "soft_bch". > > +- nand-bus-width : 8 or 16 bus width if not present 8 > > +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false > > + > > +Examples: > > +nand0: nand@40000000,0 { > > + compatible = "atmel,at91rm9200-nand"; > > + #address-cells = <1>; > > + #size-cells = <1>; > > + reg = <0x40000000 0x10000000 > > + 0xffffe800 0x200 > > + >; > > + atmel,nand-addr-offset = <21>; > > + atmel,nand-cmd-offset = <22>; > > + nand-on-flash-bbt = <1>; > > + nand-ecc-mode = "soft"; > > + gpios = <&pioC 13 0 > > + &pioC 14 0 > > + 0 > > Sorry, I haven't seen this before, perhaps it is a standard thing in > Linux. Does 0 mean end of list? Can we not just use the property's > size value for this? 0 means not used as specified in the DT Best Regards, J.
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt new file mode 100644 index 0000000..a910ab9 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -0,0 +1,41 @@ +Atmel NAND flash + +Required properties: +- compatible : "atmel,at91rm9200-nand". +- reg : should specify localbus address and size used for the chip, + and if availlable the ECC. +- atmel,nand-addr-offset : offset for the address latch. +- atmel,nand-cmd-offset : offset for the command latch. +- #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. detect is an + optional gpio and may be set to 0 if not present. + +Optional properties: +- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. + Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", + "soft_bch". +- nand-bus-width : 8 or 16 bus width if not present 8 +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + +Examples: +nand0: nand@40000000,0 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000 + 0xffffe800 0x200 + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + nand-on-flash-bbt = <1>; + nand-ecc-mode = "soft"; + gpios = <&pioC 13 0 + &pioC 14 0 + 0 + >; + partition@0 { + ... + }; +}; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d3bde9b..ea7643a 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,10 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/of_mtd.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> @@ -83,7 +87,7 @@ struct atmel_nand_host { struct mtd_info mtd; void __iomem *io_base; dma_addr_t io_phys; - struct atmel_nand_data *board; + struct atmel_nand_data board; struct device *dev; void __iomem *ecc; @@ -101,8 +105,8 @@ static int cpu_has_dma(void) */ static void atmel_nand_enable(struct atmel_nand_host *host) { - if (gpio_is_valid(host->board->enable_pin)) - gpio_set_value(host->board->enable_pin, 0); + if (gpio_is_valid(host->board.enable_pin)) + gpio_set_value(host->board.enable_pin, 0); } /* @@ -110,8 +114,8 @@ static void atmel_nand_enable(struct atmel_nand_host *host) */ static void atmel_nand_disable(struct atmel_nand_host *host) { - if (gpio_is_valid(host->board->enable_pin)) - gpio_set_value(host->board->enable_pin, 1); + if (gpio_is_valid(host->board.enable_pin)) + gpio_set_value(host->board.enable_pin, 1); } /* @@ -132,9 +136,9 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl return; if (ctrl & NAND_CLE) - writeb(cmd, host->io_base + (1 << host->board->cle)); + writeb(cmd, host->io_base + (1 << host->board.cle)); else - writeb(cmd, host->io_base + (1 << host->board->ale)); + writeb(cmd, host->io_base + (1 << host->board.ale)); } /* @@ -145,8 +149,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) struct nand_chip *nand_chip = mtd->priv; struct atmel_nand_host *host = nand_chip->priv; - return gpio_get_value(host->board->rdy_pin) ^ - !!host->board->rdy_pin_active_low; + return gpio_get_value(host->board.rdy_pin) ^ + !!host->board.rdy_pin_active_low; } static void dma_complete_func(void *completion) @@ -432,6 +436,54 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) } } +static int __devinit atmel_of_init_port(struct atmel_nand_host *host, + struct device_node *np) +{ + u32 val; + int ecc_mode; + struct atmel_nand_data *board = &host->board; + enum of_gpio_flags flags; + + if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { + if (val >= 32) { + dev_err(host->dev, "invalid addr-offset %u\n", val); + return -EINVAL; + } + board->ale = val; + } + + if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) { + if (val >= 32) { + dev_err(host->dev, "invalid cmd-offset %u\n", val); + return -EINVAL; + } + board->cle = val; + } + + ecc_mode = of_get_nand_ecc_mode(np); + + if (ecc_mode < 0) + board->ecc_mode = NAND_ECC_SOFT; + else + board->ecc_mode = ecc_mode; + + board->on_flash_bbt = of_get_nand_on_flash_bbt(np); + + if (of_get_nand_bus_width(np) == 16) + board->bus_width_16 = 1; + + board->rdy_pin = of_get_gpio_flags(np, 0, &flags); + if (flags == OF_GPIO_ACTIVE_LOW) + board->rdy_pin_active_low = 1; + else + board->rdy_pin_active_low = 0; + + board->enable_pin = of_get_gpio(np, 1); + board->det_pin = of_get_gpio(np, 2); + + return 0; +} + /* * Probe for the NAND device. */ @@ -442,6 +494,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct nand_chip *nand_chip; struct resource *regs; struct resource *mem; + struct mtd_part_parser_data ppdata = {}; int res; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -468,8 +521,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) mtd = &host->mtd; nand_chip = &host->nand_chip; - host->board = pdev->dev.platform_data; host->dev = &pdev->dev; + if (pdev->dev.of_node) { + res = atmel_of_init_port(host, pdev->dev.of_node); + if (res) + goto err_nand_ioremap; + } else { + memcpy(&host->board, pdev->dev.platform_data, + sizeof(struct atmel_nand_data)); + } nand_chip->priv = host; /* link the private data structures */ mtd->priv = nand_chip; @@ -480,10 +540,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->IO_ADDR_W = host->io_base; nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; - if (gpio_is_valid(host->board->rdy_pin)) + if (gpio_is_valid(host->board.rdy_pin)) nand_chip->dev_ready = atmel_nand_device_ready; - nand_chip->ecc.mode = host->board->ecc_mode; + nand_chip->ecc.mode = host->board.ecc_mode; regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) { @@ -508,7 +568,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 20; /* 20us command delay time */ - if (host->board->bus_width_16) /* 16-bit bus width */ + if (host->board.bus_width_16) /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; nand_chip->read_buf = atmel_read_buf; @@ -517,15 +577,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); atmel_nand_enable(host); - if (gpio_is_valid(host->board->det_pin)) { - if (gpio_get_value(host->board->det_pin)) { + if (gpio_is_valid(host->board.det_pin)) { + if (gpio_get_value(host->board.det_pin)) { printk(KERN_INFO "No SmartMedia card inserted.\n"); res = -ENXIO; goto err_no_card; } } - if (host->board->on_flash_bbt || on_flash_bbt) { + if (host->board.on_flash_bbt || on_flash_bbt) { printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } @@ -600,8 +660,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } mtd->name = "atmel_nand"; - res = mtd_device_parse_register(mtd, NULL, 0, - host->board->parts, host->board->num_parts); + ppdata.of_node = pdev->dev.of_node; + res = mtd_device_parse_register(mtd, NULL, &ppdata, + host->board.parts, host->board.num_parts); if (!res) return res; @@ -645,11 +706,21 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id atmel_nand_dt_ids[] = { + { .compatible = "atmel,at91rm9200-nand" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids); +#endif + static struct platform_driver atmel_nand_driver = { .remove = __exit_p(atmel_nand_remove), .driver = { .name = "atmel_nand", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_nand_dt_ids), }, };
use a local copy of board informatin and fill with DT data Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-mtd@lists.infradead.org --- .../devicetree/bindings/mtd/atmel-nand.txt | 41 ++++++++ drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++---- 2 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/atmel-nand.txt