mtd: rawnand: omap2: convert driver to nand_scan()
authorMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 25 Jul 2018 13:31:39 +0000 (15:31 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Tue, 31 Jul 2018 07:46:08 +0000 (09:46 +0200)
Two helpers have been added to the core to do all kind of controller
side configuration/initialization between the detection phase and the
final NAND scan. Implement these hooks so that we can convert the driver
to just use nand_scan() instead of the nand_scan_ident() +
nand_scan_tail() pair.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
drivers/mtd/nand/raw/omap2.c

index e943b2e5a5e2e92ed2e765aec52e1306d5b3c24e..4546ac0bed4a0eb7435c8806c2323170327f61f3 100644 (file)
@@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
        0xac, 0x6b, 0xff, 0x99, 0x7b};
 static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
 
-/* Shared among all NAND instances to synchronize access to the ECC Engine */
-static struct nand_controller omap_gpmc_controller = {
-       .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
-       .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
-};
-
 struct omap_nand_info {
        struct nand_chip                nand;
        struct platform_device          *pdev;
@@ -1915,106 +1909,26 @@ static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
        .free = omap_sw_ooblayout_free,
 };
 
-static int omap_nand_probe(struct platform_device *pdev)
+static int omap_nand_attach_chip(struct nand_chip *chip)
 {
-       struct omap_nand_info           *info;
-       struct mtd_info                 *mtd;
-       struct nand_chip                *nand_chip;
-       int                             err;
-       dma_cap_mask_t                  mask;
-       struct resource                 *res;
-       struct device                   *dev = &pdev->dev;
-       int                             min_oobbytes = BADBLOCK_MARKER_LENGTH;
-       int                             oobbytes_per_step;
-
-       info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
-                               GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->pdev = pdev;
-
-       err = omap_get_dt_info(dev, info);
-       if (err)
-               return err;
-
-       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;
-       }
-
-       nand_chip               = &info->nand;
-       mtd                     = nand_to_mtd(nand_chip);
-       mtd->dev.parent         = &pdev->dev;
-       nand_chip->ecc.priv     = NULL;
-       nand_set_flash_node(nand_chip, dev->of_node);
-
-       if (!mtd->name) {
-               mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-                                          "omap2-nand.%d", info->gpmc_cs);
-               if (!mtd->name) {
-                       dev_err(&pdev->dev, "Failed to set MTD name\n");
-                       return -ENOMEM;
-               }
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(nand_chip->IO_ADDR_R))
-               return PTR_ERR(nand_chip->IO_ADDR_R);
-
-       info->phys_base = res->start;
-
-       nand_chip->controller = &omap_gpmc_controller;
-
-       nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
-       nand_chip->cmd_ctrl  = omap_hwcontrol;
-
-       info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
-                                                   GPIOD_IN);
-       if (IS_ERR(info->ready_gpiod)) {
-               dev_err(dev, "failed to get ready gpio\n");
-               return PTR_ERR(info->ready_gpiod);
-       }
-
-       /*
-        * If RDY/BSY line is connected to OMAP then use the omap ready
-        * function and the generic nand_wait function which reads the status
-        * register after monitoring the RDY/BSY line. Otherwise use a standard
-        * chip delay which is slightly more than tR (AC Timing) of the NAND
-        * device and read status register until you get a failure or success
-        */
-       if (info->ready_gpiod) {
-               nand_chip->dev_ready = omap_dev_ready;
-               nand_chip->chip_delay = 0;
-       } else {
-               nand_chip->waitfunc = omap_wait;
-               nand_chip->chip_delay = 50;
-       }
-
-       if (info->flash_bbt)
-               nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-       /* scan NAND device connected to chip controller */
-       nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
-       err = nand_scan_ident(mtd, 1, NULL);
-       if (err) {
-               dev_err(&info->pdev->dev,
-                       "scan failed, may be bus-width mismatch\n");
-               goto return_error;
-       }
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct device *dev = &info->pdev->dev;
+       int min_oobbytes = BADBLOCK_MARKER_LENGTH;
+       int oobbytes_per_step;
+       dma_cap_mask_t mask;
+       int err;
 
-       if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
-               nand_chip->bbt_options |= NAND_BBT_NO_OOB;
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
        else
-               nand_chip->options |= NAND_SKIP_BBTSCAN;
+               chip->options |= NAND_SKIP_BBTSCAN;
 
-       /* re-populate low-level callbacks based on xfer modes */
+       /* Re-populate low-level callbacks based on xfer modes */
        switch (info->xfer_type) {
        case NAND_OMAP_PREFETCH_POLLED:
-               nand_chip->read_buf   = omap_read_buf_pref;
-               nand_chip->write_buf  = omap_write_buf_pref;
+               chip->read_buf = omap_read_buf_pref;
+               chip->write_buf = omap_write_buf_pref;
                break;
 
        case NAND_OMAP_POLLED:
@@ -2024,12 +1938,11 @@ static int omap_nand_probe(struct platform_device *pdev)
        case NAND_OMAP_PREFETCH_DMA:
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
-               info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
+               info->dma = dma_request_chan(dev, "rxtx");
 
                if (IS_ERR(info->dma)) {
-                       dev_err(&pdev->dev, "DMA engine request failed\n");
-                       err = PTR_ERR(info->dma);
-                       goto return_error;
+                       dev_err(dev, "DMA engine request failed\n");
+                       return PTR_ERR(info->dma);
                } else {
                        struct dma_slave_config cfg;
 
@@ -2042,222 +1955,306 @@ static int omap_nand_probe(struct platform_device *pdev)
                        cfg.dst_maxburst = 16;
                        err = dmaengine_slave_config(info->dma, &cfg);
                        if (err) {
-                               dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
+                               dev_err(dev,
+                                       "DMA engine slave config failed: %d\n",
                                        err);
-                               goto return_error;
+                               return err;
                        }
-                       nand_chip->read_buf   = omap_read_buf_dma_pref;
-                       nand_chip->write_buf  = omap_write_buf_dma_pref;
+                       chip->read_buf = omap_read_buf_dma_pref;
+                       chip->write_buf = omap_write_buf_dma_pref;
                }
                break;
 
        case NAND_OMAP_PREFETCH_IRQ:
-               info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
+               info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
                if (info->gpmc_irq_fifo <= 0) {
-                       dev_err(&pdev->dev, "error getting fifo irq\n");
-                       err = -ENODEV;
-                       goto return_error;
+                       dev_err(dev, "Error getting fifo IRQ\n");
+                       return -ENODEV;
                }
-               err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-                                       omap_nand_irq, IRQF_SHARED,
-                                       "gpmc-nand-fifo", info);
+               err = devm_request_irq(dev, info->gpmc_irq_fifo,
+                                      omap_nand_irq, IRQF_SHARED,
+                                      "gpmc-nand-fifo", info);
                if (err) {
-                       dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-                                               info->gpmc_irq_fifo, err);
+                       dev_err(dev, "Requesting IRQ %d, error %d\n",
+                               info->gpmc_irq_fifo, err);
                        info->gpmc_irq_fifo = 0;
-                       goto return_error;
+                       return err;
                }
 
-               info->gpmc_irq_count = platform_get_irq(pdev, 1);
+               info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
                if (info->gpmc_irq_count <= 0) {
-                       dev_err(&pdev->dev, "error getting count irq\n");
-                       err = -ENODEV;
-                       goto return_error;
+                       dev_err(dev, "Error getting IRQ count\n");
+                       return -ENODEV;
                }
-               err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
-                                       omap_nand_irq, IRQF_SHARED,
-                                       "gpmc-nand-count", info);
+               err = devm_request_irq(dev, info->gpmc_irq_count,
+                                      omap_nand_irq, IRQF_SHARED,
+                                      "gpmc-nand-count", info);
                if (err) {
-                       dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-                                               info->gpmc_irq_count, err);
+                       dev_err(dev, "Requesting IRQ %d, error %d\n",
+                               info->gpmc_irq_count, err);
                        info->gpmc_irq_count = 0;
-                       goto return_error;
+                       return err;
                }
 
-               nand_chip->read_buf  = omap_read_buf_irq_pref;
-               nand_chip->write_buf = omap_write_buf_irq_pref;
+               chip->read_buf = omap_read_buf_irq_pref;
+               chip->write_buf = omap_write_buf_irq_pref;
 
                break;
 
        default:
-               dev_err(&pdev->dev,
-                       "xfer_type(%d) not supported!\n", info->xfer_type);
-               err = -EINVAL;
-               goto return_error;
+               dev_err(dev, "xfer_type %d not supported!\n", info->xfer_type);
+               return -EINVAL;
        }
 
-       if (!omap2_nand_ecc_check(info)) {
-               err = -EINVAL;
-               goto return_error;
-       }
+       if (!omap2_nand_ecc_check(info))
+               return -EINVAL;
 
        /*
         * Bail out earlier to let NAND_ECC_SOFT code create its own
         * ooblayout instead of using ours.
         */
        if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
-               nand_chip->ecc.mode = NAND_ECC_SOFT;
-               nand_chip->ecc.algo = NAND_ECC_HAMMING;
-               goto scan_tail;
+               chip->ecc.mode = NAND_ECC_SOFT;
+               chip->ecc.algo = NAND_ECC_HAMMING;
+               return 0;
        }
 
-       /* populate MTD interface based on ECC scheme */
+       /* Populate MTD interface based on ECC scheme */
        switch (info->ecc_opt) {
        case OMAP_ECC_HAM1_CODE_HW:
-               pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.bytes            = 3;
-               nand_chip->ecc.size             = 512;
-               nand_chip->ecc.strength         = 1;
-               nand_chip->ecc.calculate        = omap_calculate_ecc;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc;
-               nand_chip->ecc.correct          = omap_correct_data;
+               dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.bytes         = 3;
+               chip->ecc.size          = 512;
+               chip->ecc.strength      = 1;
+               chip->ecc.calculate     = omap_calculate_ecc;
+               chip->ecc.hwctl         = omap_enable_hwecc;
+               chip->ecc.correct       = omap_correct_data;
                mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-               oobbytes_per_step               = nand_chip->ecc.bytes;
+               oobbytes_per_step       chip->ecc.bytes;
 
-               if (!(nand_chip->options & NAND_BUSWIDTH_16))
-                       min_oobbytes            = 1;
+               if (!(chip->options & NAND_BUSWIDTH_16))
+                       min_oobbytes    = 1;
 
                break;
 
        case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
                pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.size             = 512;
-               nand_chip->ecc.bytes            = 7;
-               nand_chip->ecc.strength         = 4;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
-               nand_chip->ecc.correct          = nand_bch_correct_data;
-               nand_chip->ecc.calculate        = omap_calculate_ecc_bch_sw;
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.size          = 512;
+               chip->ecc.bytes         = 7;
+               chip->ecc.strength      = 4;
+               chip->ecc.hwctl         = omap_enable_hwecc_bch;
+               chip->ecc.correct       = nand_bch_correct_data;
+               chip->ecc.calculate     = omap_calculate_ecc_bch_sw;
                mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
                /* Reserve one byte for the OMAP marker */
-               oobbytes_per_step               = nand_chip->ecc.bytes + 1;
-               /* software bch library is used for locating errors */
-               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;
-                       goto return_error;
+               oobbytes_per_step       = chip->ecc.bytes + 1;
+               /* Software BCH library is used for locating errors */
+               chip->ecc.priv          = nand_bch_init(mtd);
+               if (!chip->ecc.priv) {
+                       dev_err(dev, "Unable to use BCH library\n");
+                       return -EINVAL;
                }
                break;
 
        case OMAP_ECC_BCH4_CODE_HW:
                pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.size             = 512;
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.size          = 512;
                /* 14th bit is kept reserved for ROM-code compatibility */
-               nand_chip->ecc.bytes            = 7 + 1;
-               nand_chip->ecc.strength         = 4;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
-               nand_chip->ecc.correct          = omap_elm_correct_data;
-               nand_chip->ecc.read_page        = omap_read_page_bch;
-               nand_chip->ecc.write_page       = omap_write_page_bch;
-               nand_chip->ecc.write_subpage    = omap_write_subpage_bch;
+               chip->ecc.bytes         = 7 + 1;
+               chip->ecc.strength      = 4;
+               chip->ecc.hwctl         = omap_enable_hwecc_bch;
+               chip->ecc.correct       = omap_elm_correct_data;
+               chip->ecc.read_page     = omap_read_page_bch;
+               chip->ecc.write_page    = omap_write_page_bch;
+               chip->ecc.write_subpage = omap_write_subpage_bch;
                mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-               oobbytes_per_step               = nand_chip->ecc.bytes;
+               oobbytes_per_step       chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH4_ECC,
-                                mtd->writesize / nand_chip->ecc.size,
-                                nand_chip->ecc.size, nand_chip->ecc.bytes);
+                                mtd->writesize / chip->ecc.size,
+                                chip->ecc.size, chip->ecc.bytes);
                if (err < 0)
-                       goto return_error;
+                       return err;
                break;
 
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
                pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.size             = 512;
-               nand_chip->ecc.bytes            = 13;
-               nand_chip->ecc.strength         = 8;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
-               nand_chip->ecc.correct          = nand_bch_correct_data;
-               nand_chip->ecc.calculate        = omap_calculate_ecc_bch_sw;
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.size          = 512;
+               chip->ecc.bytes         = 13;
+               chip->ecc.strength      = 8;
+               chip->ecc.hwctl         = omap_enable_hwecc_bch;
+               chip->ecc.correct       = nand_bch_correct_data;
+               chip->ecc.calculate     = omap_calculate_ecc_bch_sw;
                mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
                /* Reserve one byte for the OMAP marker */
-               oobbytes_per_step               = nand_chip->ecc.bytes + 1;
-               /* software bch library is used for locating errors */
-               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;
-                       goto return_error;
+               oobbytes_per_step       = chip->ecc.bytes + 1;
+               /* Software BCH library is used for locating errors */
+               chip->ecc.priv          = nand_bch_init(mtd);
+               if (!chip->ecc.priv) {
+                       dev_err(dev, "unable to use BCH library\n");
+                       return -EINVAL;
                }
                break;
 
        case OMAP_ECC_BCH8_CODE_HW:
                pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.size             = 512;
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.size          = 512;
                /* 14th bit is kept reserved for ROM-code compatibility */
-               nand_chip->ecc.bytes            = 13 + 1;
-               nand_chip->ecc.strength         = 8;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
-               nand_chip->ecc.correct          = omap_elm_correct_data;
-               nand_chip->ecc.read_page        = omap_read_page_bch;
-               nand_chip->ecc.write_page       = omap_write_page_bch;
-               nand_chip->ecc.write_subpage    = omap_write_subpage_bch;
+               chip->ecc.bytes         = 13 + 1;
+               chip->ecc.strength      = 8;
+               chip->ecc.hwctl         = omap_enable_hwecc_bch;
+               chip->ecc.correct       = omap_elm_correct_data;
+               chip->ecc.read_page     = omap_read_page_bch;
+               chip->ecc.write_page    = omap_write_page_bch;
+               chip->ecc.write_subpage = omap_write_subpage_bch;
                mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-               oobbytes_per_step               = nand_chip->ecc.bytes;
+               oobbytes_per_step       chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH8_ECC,
-                                mtd->writesize / nand_chip->ecc.size,
-                                nand_chip->ecc.size, nand_chip->ecc.bytes);
+                                mtd->writesize / chip->ecc.size,
+                                chip->ecc.size, chip->ecc.bytes);
                if (err < 0)
-                       goto return_error;
+                       return err;
 
                break;
 
        case OMAP_ECC_BCH16_CODE_HW:
-               pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
-               nand_chip->ecc.mode             = NAND_ECC_HW;
-               nand_chip->ecc.size             = 512;
-               nand_chip->ecc.bytes            = 26;
-               nand_chip->ecc.strength         = 16;
-               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
-               nand_chip->ecc.correct          = omap_elm_correct_data;
-               nand_chip->ecc.read_page        = omap_read_page_bch;
-               nand_chip->ecc.write_page       = omap_write_page_bch;
-               nand_chip->ecc.write_subpage    = omap_write_subpage_bch;
+               pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
+               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.size          = 512;
+               chip->ecc.bytes         = 26;
+               chip->ecc.strength      = 16;
+               chip->ecc.hwctl         = omap_enable_hwecc_bch;
+               chip->ecc.correct       = omap_elm_correct_data;
+               chip->ecc.read_page     = omap_read_page_bch;
+               chip->ecc.write_page    = omap_write_page_bch;
+               chip->ecc.write_subpage = omap_write_subpage_bch;
                mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-               oobbytes_per_step               = nand_chip->ecc.bytes;
+               oobbytes_per_step       chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH16_ECC,
-                                mtd->writesize / nand_chip->ecc.size,
-                                nand_chip->ecc.size, nand_chip->ecc.bytes);
+                                mtd->writesize / chip->ecc.size,
+                                chip->ecc.size, chip->ecc.bytes);
                if (err < 0)
-                       goto return_error;
+                       return err;
 
                break;
        default:
-               dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
-               err = -EINVAL;
-               goto return_error;
+               dev_err(dev, "Invalid or unsupported ECC scheme\n");
+               return -EINVAL;
        }
 
-       /* check if NAND device's OOB is enough to store ECC signatures */
+       /* Check if NAND device's OOB is enough to store ECC signatures */
        min_oobbytes += (oobbytes_per_step *
-                        (mtd->writesize / nand_chip->ecc.size));
+                        (mtd->writesize / chip->ecc.size));
        if (mtd->oobsize < min_oobbytes) {
-               dev_err(&info->pdev->dev,
-                       "not enough OOB bytes required = %d, available=%d\n",
+               dev_err(dev,
+                       "Not enough OOB bytes: required = %d, available=%d\n",
                        min_oobbytes, mtd->oobsize);
-               err = -EINVAL;
-               goto return_error;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops omap_nand_controller_ops = {
+       .attach_chip = omap_nand_attach_chip,
+};
+
+/* Shared among all NAND instances to synchronize access to the ECC Engine */
+static struct nand_controller omap_gpmc_controller = {
+       .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
+       .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
+       .ops = &omap_nand_controller_ops,
+};
+
+static int omap_nand_probe(struct platform_device *pdev)
+{
+       struct omap_nand_info           *info;
+       struct mtd_info                 *mtd;
+       struct nand_chip                *nand_chip;
+       int                             err;
+       struct resource                 *res;
+       struct device                   *dev = &pdev->dev;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
+                               GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->pdev = pdev;
+
+       err = omap_get_dt_info(dev, info);
+       if (err)
+               return err;
+
+       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;
+       }
+
+       nand_chip               = &info->nand;
+       mtd                     = nand_to_mtd(nand_chip);
+       mtd->dev.parent         = &pdev->dev;
+       nand_chip->ecc.priv     = NULL;
+       nand_set_flash_node(nand_chip, dev->of_node);
+
+       if (!mtd->name) {
+               mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                          "omap2-nand.%d", info->gpmc_cs);
+               if (!mtd->name) {
+                       dev_err(&pdev->dev, "Failed to set MTD name\n");
+                       return -ENOMEM;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nand_chip->IO_ADDR_R))
+               return PTR_ERR(nand_chip->IO_ADDR_R);
+
+       info->phys_base = res->start;
+
+       nand_chip->controller = &omap_gpmc_controller;
+
+       nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
+       nand_chip->cmd_ctrl  = omap_hwcontrol;
+
+       info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
+                                                   GPIOD_IN);
+       if (IS_ERR(info->ready_gpiod)) {
+               dev_err(dev, "failed to get ready gpio\n");
+               return PTR_ERR(info->ready_gpiod);
+       }
+
+       /*
+        * If RDY/BSY line is connected to OMAP then use the omap ready
+        * function and the generic nand_wait function which reads the status
+        * register after monitoring the RDY/BSY line. Otherwise use a standard
+        * chip delay which is slightly more than tR (AC Timing) of the NAND
+        * device and read status register until you get a failure or success
+        */
+       if (info->ready_gpiod) {
+               nand_chip->dev_ready = omap_dev_ready;
+               nand_chip->chip_delay = 0;
+       } else {
+               nand_chip->waitfunc = omap_wait;
+               nand_chip->chip_delay = 50;
        }
 
-scan_tail:
-       /* second phase scan */
-       err = nand_scan_tail(mtd);
+       if (info->flash_bbt)
+               nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+       /* scan NAND device connected to chip controller */
+       nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
+
+       err = nand_scan(mtd, 1);
        if (err)
                goto return_error;