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