mtd: nand: omap: Switch to using GPMC-NAND ops for writebuffer empty check
[cascardo/linux.git] / drivers / mtd / nand / omap2.c
index c553f78..98023d5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
 
+#include <linux/omap-gpmc.h>
 #include <linux/platform_data/mtd-nand-omap2.h>
 
 #define        DRIVER_NAME     "omap2-nand"
@@ -168,7 +169,9 @@ struct omap_nand_info {
        } iomode;
        u_char                          *buf;
        int                                     buf_len;
+       /* Interface to GPMC */
        struct gpmc_nand_regs           reg;
+       struct gpmc_nand_ops            *ops;
        /* generated at runtime depending on ECC algorithm and layout selected */
        struct nand_ecclayout           oobinfo;
        /* fields specific for BCHx_HW ECC scheme */
@@ -288,14 +291,13 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 {
        struct omap_nand_info *info = mtd_to_omap(mtd);
        u_char *p = (u_char *)buf;
-       u32     status = 0;
+       bool status;
 
        while (len--) {
                iowrite8(*p++, info->nand.IO_ADDR_W);
                /* wait until buffer is available for write */
                do {
-                       status = readl(info->reg.gpmc_status) &
-                                       STATUS_BUFF_EMPTY;
+                       status = info->ops->nand_writebuffer_empty();
                } while (!status);
        }
 }
@@ -323,7 +325,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 {
        struct omap_nand_info *info = mtd_to_omap(mtd);
        u16 *p = (u16 *) buf;
-       u32     status = 0;
+       bool status;
        /* FIXME try bursts of writesw() or DMA ... */
        len >>= 1;
 
@@ -331,8 +333,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
                iowrite16(*p++, info->nand.IO_ADDR_W);
                /* wait until buffer is available for write */
                do {
-                       status = readl(info->reg.gpmc_status) &
-                                       STATUS_BUFF_EMPTY;
+                       status = info->ops->nand_writebuffer_empty();
                } while (!status);
        }
 }
@@ -1665,9 +1666,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, info);
 
+       info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
+       if (!info->ops) {
+               dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
+               return -ENODEV;
+       }
        info->pdev              = pdev;
        info->gpmc_cs           = pdata->cs;
-       info->reg               = pdata->reg;
        info->of_node           = pdata->of_node;
        info->ecc_opt           = pdata->ecc_opt;
        nand_chip               = &info->nand;
@@ -1807,13 +1812,19 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
+       /*
+        * Bail out earlier to let NAND_ECC_SOFT code create its own
+        * ecclayout instead of using ours.
+        */
+       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               goto scan_tail;
+       }
+
        /* populate MTD interface based on ECC scheme */
        ecclayout               = &info->oobinfo;
+       nand_chip->ecc.layout   = ecclayout;
        switch (info->ecc_opt) {
-       case OMAP_ECC_HAM1_CODE_SW:
-               nand_chip->ecc.mode = NAND_ECC_SOFT;
-               break;
-
        case OMAP_ECC_HAM1_CODE_HW:
                pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
                nand_chip->ecc.mode             = NAND_ECC_HW;
@@ -1861,10 +1872,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->oobfree->offset      = 1 +
                                ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
-               nand_chip->ecc.priv             = nand_bch_init(mtd,
-                                                       nand_chip->ecc.size,
-                                                       nand_chip->ecc.bytes,
-                                                       &ecclayout);
+               nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
                        dev_err(&info->pdev->dev, "unable to use BCH library\n");
                        err = -EINVAL;
@@ -1925,10 +1933,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->oobfree->offset      = 1 +
                                ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
-               nand_chip->ecc.priv             = nand_bch_init(mtd,
-                                                       nand_chip->ecc.size,
-                                                       nand_chip->ecc.bytes,
-                                                       &ecclayout);
+               nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
                        dev_err(&info->pdev->dev, "unable to use BCH library\n");
                        err = -EINVAL;
@@ -2002,9 +2007,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
-       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW)
-               goto scan_tail;
-
        /* all OOB bytes from oobfree->offset till end off OOB are free */
        ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
        /* check if NAND device's OOB is enough to store ECC signatures */
@@ -2015,7 +2017,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                err = -EINVAL;
                goto return_error;
        }
-       nand_chip->ecc.layout = ecclayout;
 
 scan_tail:
        /* second phase scan */