Roy Zang wrote:
> Move Freescale elbc interrupt from nand dirver to elbc driver.
> Then all elbc devices can use the interrupt instead of ONLY nand.
> 
> For former nand driver, it had the two functions:
> 
> 1. detecting nand flash partitions;
> 2. registering elbc interrupt.
> 
> Now, second function is removed to fsl_lbc.c.
> 
> Signed-off-by: Lan Chunhe-B25806 <b25...@freescale.com>
> Signed-off-by: Roy Zang <tie-fei.z...@freescale.com>
> Reviewed-by: Anton Vorontsov <cbouatmai...@gmail.com>
> Cc: Wood Scott-B07421 <b07...@freescale.com>
> ---
> 
> These two patches are based on the following commits:
> 1.    
> http://lists.infradead.org/pipermail/linux-mtd/2010-September/032112.html
> 2.    
> http://lists.infradead.org/pipermail/linux-mtd/2010-September/032110.html
> 3.    
> http://lists.infradead.org/pipermail/linux-mtd/2010-September/032111.html
> According to Anton's comment, I merge 1 & 2 together and start a new thread.
> Comparing the provided link:
> 1.    Merge 1 & 2 together.
> 2.    Some code style updates
> 3.    Add counter protect for elbc driver remove 
> 4.    Rebase to 2.6.36-rc7
> 
> Other histories from the links:
> V2: Comparing with v1, according to the feedback, add some decorations.
> 
> V3: Comparing with v2:
> 1.    according to the feedback, add some decorations.
> 2.    change of_platform_driver to platform_driver
> 3.    rebase to 2.6.36-rc4
> 
> V4: Comparing with v3
> 1.    minor fix from type unsigned int to u32
> 2.    fix platform_driver issue.
> 3.    add mutex for nand probe
> 
>  arch/powerpc/Kconfig               |    7 +-
>  arch/powerpc/include/asm/fsl_lbc.h |   33 +++-
>  arch/powerpc/sysdev/fsl_lbc.c      |  229 ++++++++++++++---
>  drivers/mtd/nand/Kconfig           |    1 +
>  drivers/mtd/nand/fsl_elbc_nand.c   |  482 
> +++++++++++++++---------------------
>  5 files changed, 425 insertions(+), 327 deletions(-)
> 
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 631e5a0..44df1ba 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -687,9 +687,12 @@ config 4xx_SOC
>       bool
>  
>  config FSL_LBC
> -     bool
> +     bool "Freescale Local Bus support"
> +     depends on FSL_SOC
>       help
> -       Freescale Localbus support
> +       Enables reporting of errors from the Freescale local bus
> +       controller.  Also contains some common code used by
> +       drivers for specific local bus peripherals.
>  
>  config FSL_GTM
>       bool
> diff --git a/arch/powerpc/include/asm/fsl_lbc.h 
> b/arch/powerpc/include/asm/fsl_lbc.h
> index 1b5a210..0c40c05 100644
> --- a/arch/powerpc/include/asm/fsl_lbc.h
> +++ b/arch/powerpc/include/asm/fsl_lbc.h
> @@ -1,9 +1,10 @@
>  /* Freescale Local Bus Controller
>   *
> - * Copyright (c) 2006-2007 Freescale Semiconductor
> + * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
>   *
>   * Authors: Nick Spence <nick.spe...@freescale.com>,
>   *          Scott Wood <scottw...@freescale.com>
> + *          Jack Lan <jack....@freescale.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
> @@ -26,6 +27,8 @@
>  #include <linux/compiler.h>
>  #include <linux/types.h>
>  #include <linux/io.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
>  
>  struct fsl_lbc_bank {
>       __be32 br;             /**< Base Register  */
> @@ -125,13 +128,23 @@ struct fsl_lbc_regs {
>  #define LTESR_ATMW 0x00800000
>  #define LTESR_ATMR 0x00400000
>  #define LTESR_CS   0x00080000
> +#define LTESR_UPM  0x00000002
>  #define LTESR_CC   0x00000001
>  #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
> +#define LTESR_MASK      (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
> +                      | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
> +                      | LTESR_CC)
> +#define LTESR_CLEAR  0xFFFFFFFF
> +#define LTECCR_CLEAR 0xFFFFFFFF
> +#define LTESR_STATUS LTESR_MASK
> +#define LTEIR_ENABLE LTESR_MASK
> +#define LTEDR_ENABLE 0x00000000
>       __be32 ltedr;           /**< Transfer Error Disable Register */
>       __be32 lteir;           /**< Transfer Error Interrupt Register */
>       __be32 lteatr;          /**< Transfer Error Attributes Register */
>       __be32 ltear;           /**< Transfer Error Address Register */
> -     u8 res6[0xC];
> +     __be32 lteccr;          /**< Transfer Error ECC Register */
> +     u8 res6[0x8];
>       __be32 lbcr;            /**< Configuration Register */
>  #define LBCR_LDIS  0x80000000
>  #define LBCR_LDIS_SHIFT    31
> @@ -265,7 +278,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm 
> *upm)
>               cpu_relax();
>  }
>  
> +/* overview of the fsl lbc controller */
> +
> +struct fsl_lbc_ctrl {
> +     /* device info */
> +     struct device                   *dev;
> +     struct fsl_lbc_regs __iomem     *regs;
> +     int                             irq;
> +     wait_queue_head_t               irq_wait;
> +     spinlock_t                      lock;
> +     void                            *nand;
> +
> +     /* status read from LTESR by irq handler */
> +     unsigned int                    irq_status;
> +};
> +
>  extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
>                              u32 mar);
> +extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
>  
>  #endif /* __ASM_FSL_LBC_H */
> diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
> index dceb8d1..4bb0336 100644
> --- a/arch/powerpc/sysdev/fsl_lbc.c
> +++ b/arch/powerpc/sysdev/fsl_lbc.c
> @@ -2,8 +2,11 @@
>   * Freescale LBC and UPM routines.
>   *
>   * Copyright (c) 2007-2008  MontaVista Software, Inc.
> + * Copyright (c) 2010 Freescale Semiconductor
>   *
>   * Author: Anton Vorontsov <avoront...@ru.mvista.com>
> + * Author: Jack Lan <jack....@freescale.com>
> + * Author: Roy Zang <tie-fei.z...@freescale.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
> @@ -19,39 +22,16 @@
>  #include <linux/types.h>
>  #include <linux/io.h>
>  #include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/mod_devicetable.h>
>  #include <asm/prom.h>
>  #include <asm/fsl_lbc.h>
>  
>  static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
> -static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
> -
> -static char __initdata *compat_lbc[] = {
> -     "fsl,pq2-localbus",
> -     "fsl,pq2pro-localbus",
> -     "fsl,pq3-localbus",
> -     "fsl,elbc",
> -};
> -
> -static int __init fsl_lbc_init(void)
> -{
> -     struct device_node *lbus;
> -     int i;
> -
> -     for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
> -             lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
> -             if (lbus)
> -                     goto found;
> -     }
> -     return -ENODEV;
> -
> -found:
> -     fsl_lbc_regs = of_iomap(lbus, 0);
> -     of_node_put(lbus);
> -     if (!fsl_lbc_regs)
> -             return -ENOMEM;
> -     return 0;
> -}
> -arch_initcall(fsl_lbc_init);
> +struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
> +EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
>  
>  /**
>   * fsl_lbc_find - find Localbus bank
> @@ -65,13 +45,15 @@ arch_initcall(fsl_lbc_init);
>  int fsl_lbc_find(phys_addr_t addr_base)
>  {
>       int i;
> +     struct fsl_lbc_regs __iomem *lbc;
>  
> -     if (!fsl_lbc_regs)
> +     if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
>               return -ENODEV;
>  
> -     for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
> -             __be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
> -             __be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
> +     lbc = fsl_lbc_ctrl_dev->regs;
> +     for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
> +             __be32 br = in_be32(&lbc->bank[i].br);
> +             __be32 or = in_be32(&lbc->bank[i].or);
>  
>               if (br & BR_V && (br & or & BR_BA) == addr_base)
>                       return i;
> @@ -94,22 +76,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm 
> *upm)
>  {
>       int bank;
>       __be32 br;
> +     struct fsl_lbc_regs __iomem *lbc;
>  
>       bank = fsl_lbc_find(addr_base);
>       if (bank < 0)
>               return bank;
>  
> -     br = in_be32(&fsl_lbc_regs->bank[bank].br);
> +     if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> +             return -ENODEV;
> +
> +     lbc = fsl_lbc_ctrl_dev->regs;
> +     br = in_be32(&lbc->bank[bank].br);
>  
>       switch (br & BR_MSEL) {
>       case BR_MS_UPMA:
> -             upm->mxmr = &fsl_lbc_regs->mamr;
> +             upm->mxmr = &lbc->mamr;
>               break;
>       case BR_MS_UPMB:
> -             upm->mxmr = &fsl_lbc_regs->mbmr;
> +             upm->mxmr = &lbc->mbmr;
>               break;
>       case BR_MS_UPMC:
> -             upm->mxmr = &fsl_lbc_regs->mcmr;
> +             upm->mxmr = &lbc->mcmr;
>               break;
>       default:
>               return -EINVAL;
> @@ -148,9 +135,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void 
> __iomem *io_base, u32 mar)
>       int ret = 0;
>       unsigned long flags;
>  
> +     if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> +             return -ENODEV;
> +
>       spin_lock_irqsave(&fsl_lbc_lock, flags);
>  
> -     out_be32(&fsl_lbc_regs->mar, mar);
> +     out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
>  
>       switch (upm->width) {
>       case 8:
> @@ -172,3 +162,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void 
> __iomem *io_base, u32 mar)
>       return ret;
>  }
>  EXPORT_SYMBOL(fsl_upm_run_pattern);
> +
> +static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
> +{
> +     struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +
> +     /* clear event registers */
> +     setbits32(&lbc->ltesr, LTESR_CLEAR);
> +     out_be32(&lbc->lteatr, 0);
> +     out_be32(&lbc->ltear, 0);
> +     out_be32(&lbc->lteccr, LTECCR_CLEAR);
> +     out_be32(&lbc->ltedr, LTEDR_ENABLE);
> +
> +     /* Enable interrupts for any detected events */
> +     out_be32(&lbc->lteir, LTEIR_ENABLE);
> +
> +     return 0;
> +}
> +
> +/*
> + * NOTE: This interrupt is used to report localbus events of various kinds,
> + * such as transaction errors on the chipselects.
> + */
> +
> +static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
> +{
> +     struct fsl_lbc_ctrl *ctrl = data;
> +     struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +     u32 status;
> +
> +     status = in_be32(&lbc->ltesr);
> +     if (!status)
> +             return IRQ_NONE;
> +
> +     out_be32(&lbc->ltesr, LTESR_CLEAR);
> +     out_be32(&lbc->lteatr, 0);
> +     out_be32(&lbc->ltear, 0);
> +     ctrl->irq_status = status;
> +
> +     if (status & LTESR_BM)
> +             dev_err(ctrl->dev, "Local bus monitor time-out: "
> +                     "LTESR 0x%08X\n", status);
> +     if (status & LTESR_WP)
> +             dev_err(ctrl->dev, "Write protect error: "
> +                     "LTESR 0x%08X\n", status);
> +     if (status & LTESR_ATMW)
> +             dev_err(ctrl->dev, "Atomic write error: "
> +                     "LTESR 0x%08X\n", status);
> +     if (status & LTESR_ATMR)
> +             dev_err(ctrl->dev, "Atomic read error: "
> +                     "LTESR 0x%08X\n", status);
> +     if (status & LTESR_CS)
> +             dev_err(ctrl->dev, "Chip select error: "
> +                     "LTESR 0x%08X\n", status);
> +     if (status & LTESR_UPM)
> +             ;
> +     if (status & LTESR_FCT) {
> +             dev_err(ctrl->dev, "FCM command time-out: "
> +                     "LTESR 0x%08X\n", status);
> +             smp_wmb();
> +             wake_up(&ctrl->irq_wait);
> +     }
> +     if (status & LTESR_PAR) {
> +             dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
> +                     "LTESR 0x%08X\n", status);
> +             smp_wmb();
> +             wake_up(&ctrl->irq_wait);
> +     }
> +     if (status & LTESR_CC) {
> +             smp_wmb();
> +             wake_up(&ctrl->irq_wait);
> +     }
> +     if (status & ~LTESR_MASK)
> +             dev_err(ctrl->dev, "Unknown error: "
> +                     "LTESR 0x%08X\n", status);
> +     return IRQ_HANDLED;
> +}
> +
> +/*
> + * fsl_lbc_ctrl_probe
> + *
> + * called by device layer when it finds a device matching
> + * one our driver can handled. This code allocates all of
> + * the resources needed for the controller only.  The
> + * resources for the NAND banks themselves are allocated
> + * in the chip probe function.
> +*/
> +
> +static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
> +{
> +     int ret;
> +
> +     if (!dev->dev.of_node) {
> +             dev_err(&dev->dev, "Device OF-Node is NULL");
> +             return -EFAULT;
> +     }
> +
> +     fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
> +     if (!fsl_lbc_ctrl_dev)
> +             return -ENOMEM;
> +
> +     dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
> +
> +     spin_lock_init(&fsl_lbc_ctrl_dev->lock);
> +     init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
> +
> +     fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
> +     if (!fsl_lbc_ctrl_dev->regs) {
> +             dev_err(&dev->dev, "failed to get memory region\n");
> +             ret = -ENODEV;
> +             goto err;

Looks you always iounmap(fsl_lbc_ctrl_dev->regs) on position 'err' but here
of_iomap() is already failed you should skip iounmap() fsl_lbc_ctrl_dev->regs
again. So you should improve that as the following on 'err', or layout 'err' in
gain.
------
        if(fsl_lbc_ctrl_dev->regs)
                iounmap(fsl_lbc_ctrl_dev->regs);

Tiejun

> +     }
> +
> +     fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
> +     if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
> +             dev_err(&dev->dev, "failed to get irq resource\n");
> +             ret = -ENODEV;
> +             goto err;
> +     }
> +
> +     fsl_lbc_ctrl_dev->dev = &dev->dev;
> +
> +     ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
> +     if (ret < 0)
> +             goto err;
> +
> +     ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
> +                             "fsl-lbc", fsl_lbc_ctrl_dev);
> +     if (ret != 0) {
> +             dev_err(&dev->dev, "failed to install irq (%d)\n",
> +                     fsl_lbc_ctrl_dev->irq);
> +             ret = fsl_lbc_ctrl_dev->irq;
> +             goto err;
> +     }
> +
> +     return 0;
> +
> +err:
> +     iounmap(fsl_lbc_ctrl_dev->regs);
> +     kfree(fsl_lbc_ctrl_dev);
> +     return ret;
> +}
> +
> +static const struct of_device_id fsl_lbc_match[] = {
> +     { .compatible = "fsl,elbc", },
> +     { .compatible = "fsl,pq3-localbus", },
> +     { .compatible = "fsl,pq2-localbus", },
> +     { .compatible = "fsl,pq2pro-localbus", },
> +     {},
> +};
> +
> +static struct platform_driver fsl_lbc_ctrl_driver = {
> +     .driver = {
> +             .name = "fsl-lbc",
> +             .of_match_table = fsl_lbc_match,
> +     },
> +     .probe = fsl_lbc_ctrl_probe,
> +};
> +
> +static int __init fsl_lbc_init(void)
> +{
> +     return platform_driver_register(&fsl_lbc_ctrl_driver);
> +}
> +module_init(fsl_lbc_init);
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 8b4b67c..4132c46 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -458,6 +458,7 @@ config MTD_NAND_ORION
>  config MTD_NAND_FSL_ELBC
>       tristate "NAND support for Freescale eLBC controllers"
>       depends on PPC_OF
> +     select FSL_LBC
>       help
>         Various Freescale chips, including the 8313, include a NAND Flash
>         Controller Module with built-in hardware ECC capabilities.
> diff --git a/drivers/mtd/nand/fsl_elbc_nand.c 
> b/drivers/mtd/nand/fsl_elbc_nand.c
> index 80de0bf..400f01f 100644
> --- a/drivers/mtd/nand/fsl_elbc_nand.c
> +++ b/drivers/mtd/nand/fsl_elbc_nand.c
> @@ -1,9 +1,11 @@
>  /* Freescale Enhanced Local Bus Controller NAND driver
>   *
> - * Copyright (c) 2006-2007 Freescale Semiconductor
> + * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
>   *
>   * Authors: Nick Spence <nick.spe...@freescale.com>,
>   *          Scott Wood <scottw...@freescale.com>
> + *          Jack Lan <jack....@freescale.com>
> + *          Roy Zang <tie-fei.z...@freescale.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
> @@ -27,6 +29,7 @@
>  #include <linux/string.h>
>  #include <linux/ioport.h>
>  #include <linux/of_platform.h>
> +#include <linux/platform_device.h>
>  #include <linux/slab.h>
>  #include <linux/interrupt.h>
>  
> @@ -42,14 +45,12 @@
>  #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
>  #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
>  
> -struct fsl_elbc_ctrl;
> -
>  /* mtd information per set */
>  
>  struct fsl_elbc_mtd {
>       struct mtd_info mtd;
>       struct nand_chip chip;
> -     struct fsl_elbc_ctrl *ctrl;
> +     struct fsl_lbc_ctrl *ctrl;
>  
>       struct device *dev;
>       int bank;               /* Chip select bank number           */
> @@ -58,18 +59,12 @@ struct fsl_elbc_mtd {
>       unsigned int fmr;       /* FCM Flash Mode Register value     */
>  };
>  
> -/* overview of the fsl elbc controller */
> +/* Freescale eLBC FCM controller infomation */
>  
> -struct fsl_elbc_ctrl {
> +struct fsl_elbc_fcm_ctrl {
>       struct nand_hw_control controller;
>       struct fsl_elbc_mtd *chips[MAX_BANKS];
>  
> -     /* device info */
> -     struct device *dev;
> -     struct fsl_lbc_regs __iomem *regs;
> -     int irq;
> -     wait_queue_head_t irq_wait;
> -     unsigned int irq_status; /* status read from LTESR by irq handler */
>       u8 __iomem *addr;        /* Address of assigned FCM buffer        */
>       unsigned int page;       /* Last page written to / read from      */
>       unsigned int read_bytes; /* Number of bytes read during command   */
> @@ -79,6 +74,7 @@ struct fsl_elbc_ctrl {
>       unsigned int mdr;        /* UPM/FCM Data Register value           */
>       unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
>       unsigned int oob;        /* Non zero if operating on OOB data     */
> +     unsigned int counter;    /* counter for the initializations       */
>       char *oob_poi;           /* Place to write ECC after read back    */
>  };
>  
> @@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, 
> int page_addr, int oob)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
>       int buf_num;
>  
> -     ctrl->page = page_addr;
> +     elbc_fcm_ctrl->page = page_addr;
>  
>       out_be32(&lbc->fbar,
>                page_addr >> (chip->phys_erase_shift - chip->page_shift));
> @@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, 
> int page_addr, int oob)
>               buf_num = page_addr & 7;
>       }
>  
> -     ctrl->addr = priv->vbase + buf_num * 1024;
> -     ctrl->index = column;
> +     elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
> +     elbc_fcm_ctrl->index = column;
>  
>       /* for OOB data point to the second half of the buffer */
>       if (oob)
> -             ctrl->index += priv->page_size ? 2048 : 512;
> +             elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
>  
> -     dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
> +     dev_vdbg(priv->dev, "set_addr: bank=%d, "
> +                         "elbc_fcm_ctrl->addr=0x%p (0x%p), "
>                           "index %x, pes %d ps %d\n",
> -              buf_num, ctrl->addr, priv->vbase, ctrl->index,
> +              buf_num, elbc_fcm_ctrl->addr, priv->vbase,
> +              elbc_fcm_ctrl->index,
>                chip->phys_erase_shift, chip->page_shift);
>  }
>  
> @@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>  
>       /* Setup the FMR[OP] to execute without write protection */
>       out_be32(&lbc->fmr, priv->fmr | 3);
> -     if (ctrl->use_mdr)
> -             out_be32(&lbc->mdr, ctrl->mdr);
> +     if (elbc_fcm_ctrl->use_mdr)
> +             out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
>  
> -     dev_vdbg(ctrl->dev,
> +     dev_vdbg(priv->dev,
>                "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
>                in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
> -     dev_vdbg(ctrl->dev,
> +     dev_vdbg(priv->dev,
>                "fsl_elbc_run_command: fbar=%08x fpar=%08x "
>                "fbcr=%08x bank=%d\n",
>                in_be32(&lbc->fbar), in_be32(&lbc->fpar),
> @@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
>       /* wait for FCM complete flag or timeout */
>       wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
>                          FCM_TIMEOUT_MSECS * HZ/1000);
> -     ctrl->status = ctrl->irq_status;
> -
> +     elbc_fcm_ctrl->status = ctrl->irq_status;
>       /* store mdr value in case it was needed */
> -     if (ctrl->use_mdr)
> -             ctrl->mdr = in_be32(&lbc->mdr);
> +     if (elbc_fcm_ctrl->use_mdr)
> +             elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
>  
> -     ctrl->use_mdr = 0;
> +     elbc_fcm_ctrl->use_mdr = 0;
>  
> -     if (ctrl->status != LTESR_CC) {
> -             dev_info(ctrl->dev,
> +     if (elbc_fcm_ctrl->status != LTESR_CC) {
> +             dev_info(priv->dev,
>                        "command failed: fir %x fcr %x status %x mdr %x\n",
>                        in_be32(&lbc->fir), in_be32(&lbc->fcr),
> -                      ctrl->status, ctrl->mdr);
> +                      elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
>               return -EIO;
>       }
>  
> @@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
>  static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
>  {
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>  
>       if (priv->page_size) {
> @@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>  
> -     ctrl->use_mdr = 0;
> +     elbc_fcm_ctrl->use_mdr = 0;
>  
>       /* clear the read buffer */
> -     ctrl->read_bytes = 0;
> +     elbc_fcm_ctrl->read_bytes = 0;
>       if (command != NAND_CMD_PAGEPROG)
> -             ctrl->index = 0;
> +             elbc_fcm_ctrl->index = 0;
>  
>       switch (command) {
>       /* READ0 and READ1 read the entire buffer to use hardware ECC. */
> @@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  
>       /* fall-through */
>       case NAND_CMD_READ0:
> -             dev_dbg(ctrl->dev,
> +             dev_dbg(priv->dev,
>                       "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
>                       " 0x%x, column: 0x%x.\n", page_addr, column);
>  
> @@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>               out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
>               set_addr(mtd, 0, page_addr, 0);
>  
> -             ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> -             ctrl->index += column;
> +             elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> +             elbc_fcm_ctrl->index += column;
>  
>               fsl_elbc_do_read(chip, 0);
>               fsl_elbc_run_command(mtd);
> @@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  
>       /* READOOB reads only the OOB because no ECC is performed. */
>       case NAND_CMD_READOOB:
> -             dev_vdbg(ctrl->dev,
> +             dev_vdbg(priv->dev,
>                        "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
>                        " 0x%x, column: 0x%x.\n", page_addr, column);
>  
>               out_be32(&lbc->fbcr, mtd->oobsize - column);
>               set_addr(mtd, column, page_addr, 1);
>  
> -             ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> +             elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
>  
>               fsl_elbc_do_read(chip, 1);
>               fsl_elbc_run_command(mtd);
> @@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  
>       /* READID must read all 5 possible bytes while CEB is active */
>       case NAND_CMD_READID:
> -             dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
> +             dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
>  
>               out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
>                                   (FIR_OP_UA  << FIR_OP1_SHIFT) |
> @@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>               out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
>               /* 5 bytes for manuf, device and exts */
>               out_be32(&lbc->fbcr, 5);
> -             ctrl->read_bytes = 5;
> -             ctrl->use_mdr = 1;
> -             ctrl->mdr = 0;
> +             elbc_fcm_ctrl->read_bytes = 5;
> +             elbc_fcm_ctrl->use_mdr = 1;
> +             elbc_fcm_ctrl->mdr = 0;
>  
>               set_addr(mtd, 0, 0, 0);
>               fsl_elbc_run_command(mtd);
> @@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  
>       /* ERASE1 stores the block and page address */
>       case NAND_CMD_ERASE1:
> -             dev_vdbg(ctrl->dev,
> +             dev_vdbg(priv->dev,
>                        "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
>                        "page_addr: 0x%x.\n", page_addr);
>               set_addr(mtd, 0, page_addr, 0);
> @@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>  
>       /* ERASE2 uses the block and page address from ERASE1 */
>       case NAND_CMD_ERASE2:
> -             dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
> +             dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
>  
>               out_be32(&lbc->fir,
>                        (FIR_OP_CM0 << FIR_OP0_SHIFT) |
> @@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>                        (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
>  
>               out_be32(&lbc->fbcr, 0);
> -             ctrl->read_bytes = 0;
> -             ctrl->use_mdr = 1;
> +             elbc_fcm_ctrl->read_bytes = 0;
> +             elbc_fcm_ctrl->use_mdr = 1;
>  
>               fsl_elbc_run_command(mtd);
>               return;
> @@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>       /* SEQIN sets up the addr buffer and all registers except the length */
>       case NAND_CMD_SEQIN: {
>               __be32 fcr;
> -             dev_vdbg(ctrl->dev,
> -                      "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
> +             dev_vdbg(priv->dev,
> +                      "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
>                        "page_addr: 0x%x, column: 0x%x.\n",
>                        page_addr, column);
>  
> -             ctrl->column = column;
> -             ctrl->oob = 0;
> -             ctrl->use_mdr = 1;
> +             elbc_fcm_ctrl->use_mdr = 1;
>  
>               fcr = (NAND_CMD_STATUS   << FCR_CMD1_SHIFT) |
>                     (NAND_CMD_SEQIN    << FCR_CMD2_SHIFT) |
> @@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>                               /* OOB area --> READOOB */
>                               column -= mtd->writesize;
>                               fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
> -                             ctrl->oob = 1;
> +                             elbc_fcm_ctrl->oob = 1;
>                       } else {
>                               WARN_ON(column != 0);
>                               /* First 256 bytes --> READ0 */
> @@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>               }
>  
>               out_be32(&lbc->fcr, fcr);
> -             set_addr(mtd, column, page_addr, ctrl->oob);
> +             set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
>               return;
>       }
>  
>       /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
>       case NAND_CMD_PAGEPROG: {
>               int full_page;
> -             dev_vdbg(ctrl->dev,
> +             dev_vdbg(priv->dev,
>                        "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
> -                      "writing %d bytes.\n", ctrl->index);
> +                      "writing %d bytes.\n", elbc_fcm_ctrl->index);
>  
>               /* if the write did not start at 0 or is not a full page
>                * then set the exact length, otherwise use a full page
>                * write so the HW generates the ECC.
>                */
> -             if (ctrl->oob || ctrl->column != 0 ||
> -                 ctrl->index != mtd->writesize + mtd->oobsize) {
> -                     out_be32(&lbc->fbcr, ctrl->index);
> +             if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
> +                 elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) {
> +                     out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
>                       full_page = 0;
>               } else {
>                       out_be32(&lbc->fbcr, 0);
> @@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>               /* Read back the page in order to fill in the ECC for the
>                * caller.  Is this really needed?
>                */
> -             if (full_page && ctrl->oob_poi) {
> +             if (full_page && elbc_fcm_ctrl->oob_poi) {
>                       out_be32(&lbc->fbcr, 3);
>                       set_addr(mtd, 6, page_addr, 1);
>  
> -                     ctrl->read_bytes = mtd->writesize + 9;
> +                     elbc_fcm_ctrl->read_bytes = mtd->writesize + 9;
>  
>                       fsl_elbc_do_read(chip, 1);
>                       fsl_elbc_run_command(mtd);
>  
> -                     memcpy_fromio(ctrl->oob_poi + 6,
> -                                   &ctrl->addr[ctrl->index], 3);
> -                     ctrl->index += 3;
> +                     memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6,
> +                             &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3);
> +                     elbc_fcm_ctrl->index += 3;
>               }
>  
> -             ctrl->oob_poi = NULL;
> +             elbc_fcm_ctrl->oob_poi = NULL;
>               return;
>       }
>  
> @@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
> unsigned int command,
>               out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
>               out_be32(&lbc->fbcr, 1);
>               set_addr(mtd, 0, 0, 0);
> -             ctrl->read_bytes = 1;
> +             elbc_fcm_ctrl->read_bytes = 1;
>  
>               fsl_elbc_run_command(mtd);
>  
>               /* The chip always seems to report that it is
>                * write-protected, even when it is not.
>                */
> -             setbits8(ctrl->addr, NAND_STATUS_WP);
> +             setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
>               return;
>  
>       /* RESET without waiting for the ready line */
>       case NAND_CMD_RESET:
> -             dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
> +             dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
>               out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
>               out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
>               fsl_elbc_run_command(mtd);
>               return;
>  
>       default:
> -             dev_err(ctrl->dev,
> +             dev_err(priv->dev,
>                       "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
>                       command);
>       }
> @@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, 
> const u8 *buf, int len)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>       unsigned int bufsize = mtd->writesize + mtd->oobsize;
>  
>       if (len <= 0) {
> -             dev_err(ctrl->dev, "write_buf of %d bytes", len);
> -             ctrl->status = 0;
> +             dev_err(priv->dev, "write_buf of %d bytes", len);
> +             elbc_fcm_ctrl->status = 0;
>               return;
>       }
>  
> -     if ((unsigned int)len > bufsize - ctrl->index) {
> -             dev_err(ctrl->dev,
> +     if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
> +             dev_err(priv->dev,
>                       "write_buf beyond end of buffer "
>                       "(%d requested, %u available)\n",
> -                     len, bufsize - ctrl->index);
> -             len = bufsize - ctrl->index;
> +                     len, bufsize - elbc_fcm_ctrl->index);
> +             len = bufsize - elbc_fcm_ctrl->index;
>       }
>  
> -     memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
> +     memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
>       /*
>        * This is workaround for the weird elbc hangs during nand write,
>        * Scott Wood says: "...perhaps difference in how long it takes a
> @@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, 
> const u8 *buf, int len)
>        * is causing problems, and sync isn't helping for some reason."
>        * Reading back the last byte helps though.
>        */
> -     in_8(&ctrl->addr[ctrl->index] + len - 1);
> +     in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
>  
> -     ctrl->index += len;
> +     elbc_fcm_ctrl->index += len;
>  }
>  
>  /*
> @@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>  
>       /* If there are still bytes in the FCM, then use the next byte. */
> -     if (ctrl->index < ctrl->read_bytes)
> -             return in_8(&ctrl->addr[ctrl->index++]);
> +     if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
> +             return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
>  
> -     dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
> +     dev_err(priv->dev, "read_byte beyond end of buffer\n");
>       return ERR_BYTE;
>  }
>  
> @@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 
> *buf, int len)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>       int avail;
>  
>       if (len < 0)
>               return;
>  
> -     avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
> -     memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
> -     ctrl->index += avail;
> +     avail = min((unsigned int)len,
> +                     elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
> +     memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
> +     elbc_fcm_ctrl->index += avail;
>  
>       if (len > avail)
> -             dev_err(ctrl->dev,
> +             dev_err(priv->dev,
>                       "read_buf beyond end of buffer "
>                       "(%d requested, %d available)\n",
>                       len, avail);
> @@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, 
> const u_char *buf, int len)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>       int i;
>  
>       if (len < 0) {
> -             dev_err(ctrl->dev, "write_buf of %d bytes", len);
> +             dev_err(priv->dev, "write_buf of %d bytes", len);
>               return -EINVAL;
>       }
>  
> -     if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
> -             dev_err(ctrl->dev,
> -                     "verify_buf beyond end of buffer "
> -                     "(%d requested, %u available)\n",
> -                     len, ctrl->read_bytes - ctrl->index);
> +     if ((unsigned int)len >
> +                     elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) {
> +             dev_err(priv->dev,
> +                     "verify_buf beyond end of buffer "
> +                     "(%d requested, %u available)\n",
> +                     len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
>  
> -             ctrl->index = ctrl->read_bytes;
> +             elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes;
>               return -EINVAL;
>       }
>  
>       for (i = 0; i < len; i++)
> -             if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
> +             if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
> +                             != buf[i])
>                       break;
>  
> -     ctrl->index += len;
> -     return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
> +     elbc_fcm_ctrl->index += len;
> +     return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
>  }
>  
>  /* This function is called after Program and Erase Operations to
> @@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, 
> const u_char *buf, int len)
>  static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
>  {
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>  
> -     if (ctrl->status != LTESR_CC)
> +     if (elbc_fcm_ctrl->status != LTESR_CC)
>               return NAND_STATUS_FAIL;
>  
>       /* The chip always seems to report that it is
>        * write-protected, even when it is not.
>        */
> -     return (ctrl->mdr & 0xff) | NAND_STATUS_WP;
> +     return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
>  }
>  
>  static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
>  {
>       struct nand_chip *chip = mtd->priv;
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>       unsigned int al;
>  
> @@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
>       priv->fmr |= (12 << FMR_CWTO_SHIFT) |  /* Timeout > 12 ms */
>                    (al << FMR_AL_SHIFT);
>  
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
>               chip->numchips);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
>               chip->chipsize);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
>               chip->pagemask);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
>               chip->chip_delay);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
>               chip->badblockpos);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
>               chip->chip_shift);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
>               chip->page_shift);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
>               chip->phys_erase_shift);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
>               chip->ecclayout);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
>               chip->ecc.mode);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
>               chip->ecc.steps);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
>               chip->ecc.bytes);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
>               chip->ecc.total);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
>               chip->ecc.layout);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
> +     dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
> +     dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
>               mtd->erasesize);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
>               mtd->writesize);
> -     dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
> +     dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
>               mtd->oobsize);
>  
>       /* adjust Option Register and ECC to match Flash page size */
> @@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
>                       chip->badblock_pattern = &largepage_memorybased;
>               }
>       } else {
> -             dev_err(ctrl->dev,
> +             dev_err(priv->dev,
>                       "fsl_elbc_init: page size %d is not supported\n",
>                       mtd->writesize);
>               return -1;
> @@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,
>                                  const uint8_t *buf)
>  {
>       struct fsl_elbc_mtd *priv = chip->priv;
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>  
>       fsl_elbc_write_buf(mtd, buf, mtd->writesize);
>       fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
>  
> -     ctrl->oob_poi = chip->oob_poi;
> +     elbc_fcm_ctrl->oob_poi = chip->oob_poi;
>  }
>  
>  static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
>  {
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> +     struct fsl_lbc_ctrl *ctrl = priv->ctrl;
>       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
>       struct nand_chip *chip = &priv->chip;
>  
>       dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
> @@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
>       chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
>                       NAND_USE_FLASH_BBT;
>  
> -     chip->controller = &ctrl->controller;
> +     chip->controller = &elbc_fcm_ctrl->controller;
>       chip->priv = priv;
>  
>       chip->ecc.read_page = fsl_elbc_read_page;
> @@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
>  
>  static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
>  {
> -     struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> -
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>       nand_release(&priv->mtd);
>  
>       kfree(priv->mtd.name);
> @@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd 
> *priv)
>       if (priv->vbase)
>               iounmap(priv->vbase);
>  
> -     ctrl->chips[priv->bank] = NULL;
> +     elbc_fcm_ctrl->chips[priv->bank] = NULL;
>       kfree(priv);
> -
> +     kfree(elbc_fcm_ctrl);
>       return 0;
>  }
>  
> -static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
> -                                      struct device_node *node)
> +static DEFINE_MUTEX(fsl_elbc_nand_mutex);
> +
> +static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
>  {
> -     struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +     struct fsl_lbc_regs __iomem *lbc;
>       struct fsl_elbc_mtd *priv;
>       struct resource res;
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
> +
>  #ifdef CONFIG_MTD_PARTITIONS
>       static const char *part_probe_types[]
>               = { "cmdlinepart", "RedBoot", NULL };
> @@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct 
> fsl_elbc_ctrl *ctrl,
>  #endif
>       int ret;
>       int bank;
> +     struct device *dev;
> +     struct device_node *node = pdev->dev.of_node;
> +
> +     if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> +             return -ENODEV;
> +     lbc = fsl_lbc_ctrl_dev->regs;
> +     dev = fsl_lbc_ctrl_dev->dev;
>  
>       /* get, allocate and map the memory resource */
>       ret = of_address_to_resource(node, 0, &res);
>       if (ret) {
> -             dev_err(ctrl->dev, "failed to get resource\n");
> +             dev_err(dev, "failed to get resource\n");
>               return ret;
>       }
>  
> @@ -861,7 +872,7 @@ static int __devinit fsl_elbc_chip_probe(struct 
> fsl_elbc_ctrl *ctrl,
>                       break;
>  
>       if (bank >= MAX_BANKS) {
> -             dev_err(ctrl->dev, "address did not match any chip selects\n");
> +             dev_err(dev, "address did not match any chip selects\n");
>               return -ENODEV;
>       }
>  
> @@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct 
> fsl_elbc_ctrl *ctrl,
>       if (!priv)
>               return -ENOMEM;
>  
> -     ctrl->chips[bank] = priv;
> +     mutex_lock(&fsl_elbc_nand_mutex);
> +     if (!fsl_lbc_ctrl_dev->nand) {
> +             elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
> +             if (!elbc_fcm_ctrl) {
> +                     dev_err(dev, "failed to allocate memory\n");
> +                     mutex_unlock(&fsl_elbc_nand_mutex);
> +                     ret = -ENOMEM;
> +                     goto err;
> +             }
> +             elbc_fcm_ctrl->counter++;
> +
> +             spin_lock_init(&elbc_fcm_ctrl->controller.lock);
> +             init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
> +             fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
> +     } else {
> +             elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
> +     }
> +     mutex_unlock(&fsl_elbc_nand_mutex);
> +
> +     elbc_fcm_ctrl->chips[bank] = priv;
>       priv->bank = bank;
> -     priv->ctrl = ctrl;
> -     priv->dev = ctrl->dev;
> +     priv->ctrl = fsl_lbc_ctrl_dev;
> +     priv->dev = dev;
>  
>       priv->vbase = ioremap(res.start, resource_size(&res));
>       if (!priv->vbase) {
> -             dev_err(ctrl->dev, "failed to map chip region\n");
> +             dev_err(dev, "failed to map chip region\n");
>               ret = -ENOMEM;
>               goto err;
>       }
> @@ -933,171 +963,53 @@ err:
>       return ret;
>  }
>  
> -static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
> +static int fsl_elbc_nand_remove(struct platform_device *pdev)
>  {
> -     struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> -
> -     /*
> -      * NAND transactions can tie up the bus for a long time, so set the
> -      * bus timeout to max by clearing LBCR[BMT] (highest base counter
> -      * value) and setting LBCR[BMTPS] to the highest prescaler value.
> -      */
> -     clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15);
> -
> -     /* clear event registers */
> -     setbits32(&lbc->ltesr, LTESR_NAND_MASK);
> -     out_be32(&lbc->lteatr, 0);
> -
> -     /* Enable interrupts for any detected events */
> -     out_be32(&lbc->lteir, LTESR_NAND_MASK);
> -
> -     ctrl->read_bytes = 0;
> -     ctrl->index = 0;
> -     ctrl->addr = NULL;
> -
> -     return 0;
> -}
> -
> -static int fsl_elbc_ctrl_remove(struct platform_device *ofdev)
> -{
> -     struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
>       int i;
> -
> +     struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
>       for (i = 0; i < MAX_BANKS; i++)
> -             if (ctrl->chips[i])
> -                     fsl_elbc_chip_remove(ctrl->chips[i]);
> -
> -     if (ctrl->irq)
> -             free_irq(ctrl->irq, ctrl);
> -
> -     if (ctrl->regs)
> -             iounmap(ctrl->regs);
> -
> -     dev_set_drvdata(&ofdev->dev, NULL);
> -     kfree(ctrl);
> -     return 0;
> -}
> -
> -/* NOTE: This interrupt is also used to report other localbus events,
> - * such as transaction errors on other chipselects.  If we want to
> - * capture those, we'll need to move the IRQ code into a shared
> - * LBC driver.
> - */
> -
> -static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
> -{
> -     struct fsl_elbc_ctrl *ctrl = data;
> -     struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> -     __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
> -
> -     if (status) {
> -             out_be32(&lbc->ltesr, status);
> -             out_be32(&lbc->lteatr, 0);
> -
> -             ctrl->irq_status = status;
> -             smp_wmb();
> -             wake_up(&ctrl->irq_wait);
> -
> -             return IRQ_HANDLED;
> +             if (elbc_fcm_ctrl->chips[i])
> +                     fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
> +
> +     mutex_lock(&fsl_elbc_nand_mutex);
> +     elbc_fcm_ctrl->counter--;
> +     if (!elbc_fcm_ctrl->counter) {
> +             fsl_lbc_ctrl_dev->nand = NULL;
> +             kfree(elbc_fcm_ctrl);
>       }
> -
> -     return IRQ_NONE;
> -}
> -
> -/* fsl_elbc_ctrl_probe
> - *
> - * called by device layer when it finds a device matching
> - * one our driver can handled. This code allocates all of
> - * the resources needed for the controller only.  The
> - * resources for the NAND banks themselves are allocated
> - * in the chip probe function.
> -*/
> -
> -static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev,
> -                                         const struct of_device_id *match)
> -{
> -     struct device_node *child;
> -     struct fsl_elbc_ctrl *ctrl;
> -     int ret;
> -
> -     ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
> -     if (!ctrl)
> -             return -ENOMEM;
> -
> -     dev_set_drvdata(&ofdev->dev, ctrl);
> -
> -     spin_lock_init(&ctrl->controller.lock);
> -     init_waitqueue_head(&ctrl->controller.wq);
> -     init_waitqueue_head(&ctrl->irq_wait);
> -
> -     ctrl->regs = of_iomap(ofdev->dev.of_node, 0);
> -     if (!ctrl->regs) {
> -             dev_err(&ofdev->dev, "failed to get memory region\n");
> -             ret = -ENODEV;
> -             goto err;
> -     }
> -
> -     ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
> -     if (ctrl->irq == NO_IRQ) {
> -             dev_err(&ofdev->dev, "failed to get irq resource\n");
> -             ret = -ENODEV;
> -             goto err;
> -     }
> -
> -     ctrl->dev = &ofdev->dev;
> -
> -     ret = fsl_elbc_ctrl_init(ctrl);
> -     if (ret < 0)
> -             goto err;
> -
> -     ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
> -     if (ret != 0) {
> -             dev_err(&ofdev->dev, "failed to install irq (%d)\n",
> -                     ctrl->irq);
> -             ret = ctrl->irq;
> -             goto err;
> -     }
> -
> -     for_each_child_of_node(ofdev->dev.of_node, child)
> -             if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
> -                     fsl_elbc_chip_probe(ctrl, child);
> +     mutex_unlock(&fsl_elbc_nand_mutex);
>  
>       return 0;
>  
> -err:
> -     fsl_elbc_ctrl_remove(ofdev);
> -     return ret;
>  }
>  
> -static const struct of_device_id fsl_elbc_match[] = {
> -     {
> -             .compatible = "fsl,elbc",
> -     },
> +static const struct of_device_id fsl_elbc_nand_match[] = {
> +     { .compatible = "fsl,elbc-fcm-nand", },
>       {}
>  };
>  
> -static struct of_platform_driver fsl_elbc_ctrl_driver = {
> +static struct platform_driver fsl_elbc_nand_driver = {
>       .driver = {
> -             .name = "fsl-elbc",
> +             .name = "fsl,elbc-fcm-nand",
>               .owner = THIS_MODULE,
> -             .of_match_table = fsl_elbc_match,
> +             .of_match_table = fsl_elbc_nand_match,
>       },
> -     .probe = fsl_elbc_ctrl_probe,
> -     .remove = fsl_elbc_ctrl_remove,
> +     .probe = fsl_elbc_nand_probe,
> +     .remove = fsl_elbc_nand_remove,
>  };
>  
> -static int __init fsl_elbc_init(void)
> +static int __init fsl_elbc_nand_init(void)
>  {
> -     return of_register_platform_driver(&fsl_elbc_ctrl_driver);
> +     return platform_driver_register(&fsl_elbc_nand_driver);
>  }
>  
> -static void __exit fsl_elbc_exit(void)
> +static void __exit fsl_elbc_nand_exit(void)
>  {
> -     of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
> +     platform_driver_unregister(&fsl_elbc_nand_driver);
>  }
>  
> -module_init(fsl_elbc_init);
> -module_exit(fsl_elbc_exit);
> +module_init(fsl_elbc_nand_init);
> +module_exit(fsl_elbc_nand_exit);
>  
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Freescale");

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to