linux/drivers/mtd/nand/gpio.c
<<
>>
Prefs
   1/*
   2 * drivers/mtd/nand/gpio.c
   3 *
   4 * Updated, and converted to generic GPIO based driver by Russell King.
   5 *
   6 * Written by Ben Dooks <ben@simtec.co.uk>
   7 *   Based on 2.4 version by Mark Whittaker
   8 *
   9 * © 2004 Simtec Electronics
  10 *
  11 * Device driver for NAND flash that uses a memory mapped interface to
  12 * read/write the NAND commands and data, and GPIO pins for control signals
  13 * (the DT binding refers to this as "GPIO assisted NAND flash")
  14 *
  15 * This program is free software; you can redistribute it and/or modify
  16 * it under the terms of the GNU General Public License version 2 as
  17 * published by the Free Software Foundation.
  18 *
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/err.h>
  23#include <linux/slab.h>
  24#include <linux/module.h>
  25#include <linux/platform_device.h>
  26#include <linux/gpio.h>
  27#include <linux/io.h>
  28#include <linux/mtd/mtd.h>
  29#include <linux/mtd/nand.h>
  30#include <linux/mtd/partitions.h>
  31#include <linux/mtd/nand-gpio.h>
  32#include <linux/of.h>
  33#include <linux/of_address.h>
  34#include <linux/of_gpio.h>
  35
  36struct gpiomtd {
  37        void __iomem            *io_sync;
  38        struct mtd_info         mtd_info;
  39        struct nand_chip        nand_chip;
  40        struct gpio_nand_platdata plat;
  41};
  42
  43#define gpio_nand_getpriv(x) container_of(x, struct gpiomtd, mtd_info)
  44
  45
  46#ifdef CONFIG_ARM
  47/* gpio_nand_dosync()
  48 *
  49 * Make sure the GPIO state changes occur in-order with writes to NAND
  50 * memory region.
  51 * Needed on PXA due to bus-reordering within the SoC itself (see section on
  52 * I/O ordering in PXA manual (section 2.3, p35)
  53 */
  54static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
  55{
  56        unsigned long tmp;
  57
  58        if (gpiomtd->io_sync) {
  59                /*
  60                 * Linux memory barriers don't cater for what's required here.
  61                 * What's required is what's here - a read from a separate
  62                 * region with a dependency on that read.
  63                 */
  64                tmp = readl(gpiomtd->io_sync);
  65                asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
  66        }
  67}
  68#else
  69static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
  70#endif
  71
  72static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  73{
  74        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
  75
  76        gpio_nand_dosync(gpiomtd);
  77
  78        if (ctrl & NAND_CTRL_CHANGE) {
  79                gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE));
  80                gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
  81                gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
  82                gpio_nand_dosync(gpiomtd);
  83        }
  84        if (cmd == NAND_CMD_NONE)
  85                return;
  86
  87        writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
  88        gpio_nand_dosync(gpiomtd);
  89}
  90
  91static int gpio_nand_devready(struct mtd_info *mtd)
  92{
  93        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
  94
  95        return gpio_get_value(gpiomtd->plat.gpio_rdy);
  96}
  97
  98#ifdef CONFIG_OF
  99static const struct of_device_id gpio_nand_id_table[] = {
 100        { .compatible = "gpio-control-nand" },
 101        {}
 102};
 103MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
 104
 105static int gpio_nand_get_config_of(const struct device *dev,
 106                                   struct gpio_nand_platdata *plat)
 107{
 108        u32 val;
 109
 110        if (!dev->of_node)
 111                return -ENODEV;
 112
 113        if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
 114                if (val == 2) {
 115                        plat->options |= NAND_BUSWIDTH_16;
 116                } else if (val != 1) {
 117                        dev_err(dev, "invalid bank-width %u\n", val);
 118                        return -EINVAL;
 119                }
 120        }
 121
 122        plat->gpio_rdy = of_get_gpio(dev->of_node, 0);
 123        plat->gpio_nce = of_get_gpio(dev->of_node, 1);
 124        plat->gpio_ale = of_get_gpio(dev->of_node, 2);
 125        plat->gpio_cle = of_get_gpio(dev->of_node, 3);
 126        plat->gpio_nwp = of_get_gpio(dev->of_node, 4);
 127
 128        if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
 129                plat->chip_delay = val;
 130
 131        return 0;
 132}
 133
 134static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
 135{
 136        struct resource *r;
 137        u64 addr;
 138
 139        if (of_property_read_u64(pdev->dev.of_node,
 140                                       "gpio-control-nand,io-sync-reg", &addr))
 141                return NULL;
 142
 143        r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
 144        if (!r)
 145                return NULL;
 146
 147        r->start = addr;
 148        r->end = r->start + 0x3;
 149        r->flags = IORESOURCE_MEM;
 150
 151        return r;
 152}
 153#else /* CONFIG_OF */
 154static inline int gpio_nand_get_config_of(const struct device *dev,
 155                                          struct gpio_nand_platdata *plat)
 156{
 157        return -ENOSYS;
 158}
 159
 160static inline struct resource *
 161gpio_nand_get_io_sync_of(struct platform_device *pdev)
 162{
 163        return NULL;
 164}
 165#endif /* CONFIG_OF */
 166
 167static inline int gpio_nand_get_config(const struct device *dev,
 168                                       struct gpio_nand_platdata *plat)
 169{
 170        int ret = gpio_nand_get_config_of(dev, plat);
 171
 172        if (!ret)
 173                return ret;
 174
 175        if (dev_get_platdata(dev)) {
 176                memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
 177                return 0;
 178        }
 179
 180        return -EINVAL;
 181}
 182
 183static inline struct resource *
 184gpio_nand_get_io_sync(struct platform_device *pdev)
 185{
 186        struct resource *r = gpio_nand_get_io_sync_of(pdev);
 187
 188        if (r)
 189                return r;
 190
 191        return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 192}
 193
 194static int gpio_nand_remove(struct platform_device *pdev)
 195{
 196        struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 197
 198        nand_release(&gpiomtd->mtd_info);
 199
 200        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 201                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
 202        gpio_set_value(gpiomtd->plat.gpio_nce, 1);
 203
 204        return 0;
 205}
 206
 207static int gpio_nand_probe(struct platform_device *pdev)
 208{
 209        struct gpiomtd *gpiomtd;
 210        struct nand_chip *chip;
 211        struct resource *res;
 212        struct mtd_part_parser_data ppdata = {};
 213        int ret = 0;
 214
 215        if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
 216                return -EINVAL;
 217
 218        gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
 219        if (!gpiomtd)
 220                return -ENOMEM;
 221
 222        chip = &gpiomtd->nand_chip;
 223
 224        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 225        chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
 226        if (IS_ERR(chip->IO_ADDR_R))
 227                return PTR_ERR(chip->IO_ADDR_R);
 228
 229        res = gpio_nand_get_io_sync(pdev);
 230        if (res) {
 231                gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
 232                if (IS_ERR(gpiomtd->io_sync))
 233                        return PTR_ERR(gpiomtd->io_sync);
 234        }
 235
 236        ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
 237        if (ret)
 238                return ret;
 239
 240        ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
 241        if (ret)
 242                return ret;
 243        gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
 244
 245        if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
 246                ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
 247                                        "NAND NWP");
 248                if (ret)
 249                        return ret;
 250        }
 251
 252        ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
 253        if (ret)
 254                return ret;
 255        gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
 256
 257        ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
 258        if (ret)
 259                return ret;
 260        gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
 261
 262        if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
 263                ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
 264                                        "NAND RDY");
 265                if (ret)
 266                        return ret;
 267                gpio_direction_input(gpiomtd->plat.gpio_rdy);
 268                chip->dev_ready = gpio_nand_devready;
 269        }
 270
 271        chip->IO_ADDR_W         = chip->IO_ADDR_R;
 272        chip->ecc.mode          = NAND_ECC_SOFT;
 273        chip->options           = gpiomtd->plat.options;
 274        chip->chip_delay        = gpiomtd->plat.chip_delay;
 275        chip->cmd_ctrl          = gpio_nand_cmd_ctrl;
 276
 277        gpiomtd->mtd_info.priv  = chip;
 278        gpiomtd->mtd_info.owner = THIS_MODULE;
 279
 280        platform_set_drvdata(pdev, gpiomtd);
 281
 282        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 283                gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 284
 285        if (nand_scan(&gpiomtd->mtd_info, 1)) {
 286                ret = -ENXIO;
 287                goto err_wp;
 288        }
 289
 290        if (gpiomtd->plat.adjust_parts)
 291                gpiomtd->plat.adjust_parts(&gpiomtd->plat,
 292                                           gpiomtd->mtd_info.size);
 293
 294        ppdata.of_node = pdev->dev.of_node;
 295        ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
 296                                        gpiomtd->plat.parts,
 297                                        gpiomtd->plat.num_parts);
 298        if (!ret)
 299                return 0;
 300
 301err_wp:
 302        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 303                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
 304
 305        return ret;
 306}
 307
 308static struct platform_driver gpio_nand_driver = {
 309        .probe          = gpio_nand_probe,
 310        .remove         = gpio_nand_remove,
 311        .driver         = {
 312                .name   = "gpio-nand",
 313                .of_match_table = of_match_ptr(gpio_nand_id_table),
 314        },
 315};
 316
 317module_platform_driver(gpio_nand_driver);
 318
 319MODULE_LICENSE("GPL");
 320MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 321MODULE_DESCRIPTION("GPIO NAND Driver");
 322