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