From: Felipe Balbi <[EMAIL PROTECTED]>

Introduce a structure to hold device data. Already
changes read/write functions to use __raw_read/write.

Signed-off-by: Felipe Balbi <[EMAIL PROTECTED]>
---
 drivers/mtd/nand/davinci_nand.c |  311 ++++++++++++++++++++++++---------------
 1 files changed, 190 insertions(+), 121 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index b6e1384..e296ce3 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -45,6 +45,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/spinlock.h>
 
 #include <mach/hardware.h>
 #include <mach/nand.h>
@@ -60,14 +61,20 @@
 
 #define DRIVER_NAME "davinci_nand"
 
-static struct clk *nand_clock;
-static void __iomem *nand_vaddr;
-static void __iomem *emif_base;
+struct davinci_nand_info {
+       /* device lock */
+       spinlock_t              lock;
+       struct nand_chip        chip;
+       struct mtd_info         mtd;
 
-/*
- * MTD structure for DaVinici board
- */
-static struct mtd_info *nand_davinci_mtd;
+       struct device           *dev;
+       struct clk              *clk;
+
+       void __iomem            *base;
+       void __iomem            *vaddr;
+};
+
+#define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd)
 
 #ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
@@ -91,18 +98,24 @@ static struct nand_bbt_descr davinci_memorybased_large = {
        .pattern        = scan_ff_pattern
 };
 
-inline unsigned int davinci_nand_readl(int offset)
+/* Caller should take care of locking */
+static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
+               int offset)
 {
-       return davinci_readl(emif_base + offset);
+       return __raw_readl(info->base + offset);
 }
 
-inline void davinci_nand_writel(unsigned long value, int offset)
+/* Caller should take care of locking */
+static inline void davinci_nand_writel(struct davinci_nand_info *info,
+               int offset, unsigned long value)
 {
-       davinci_writel(value, emif_base + offset);
+       __raw_writel(value, info->base + offset);
 }
 
 /*
  * Hardware specific access to control-lines
+ *
+ * REVISIT avoid casting addresses
  */
 static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
                                   unsigned int ctrl)
@@ -134,15 +147,23 @@ static void nand_davinci_select_chip(struct mtd_info 
*mtd, int chip)
 #ifdef CONFIG_NAND_FLASH_HW_ECC
 static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode)
 {
+       struct davinci_nand_info *info;
+       unsigned long flags;
        u32 retval;
 
+       info = to_davinci_nand(mtd);
+
+       spin_lock_irqsave(&info->lock, flags);
+
        /* Reset ECC hardware */
-       retval = davinci_nand_readl(NANDF1ECC_OFFSET);
+       retval = davinci_nand_readl(info, NANDF1ECC_OFFSET);
 
        /* Restart ECC hardware */
-       retval = davinci_nand_readl(NANDFCR_OFFSET);
+       retval = davinci_nand_readl(info, NANDFCR_OFFSET);
        retval |= (1 << 8);
-       davinci_nand_writel(retval, NANDFCR_OFFSET);
+       davinci_nand_writel(info, NANDFCR_OFFSET, retval);
+
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -150,8 +171,18 @@ static void nand_davinci_enable_hwecc(struct mtd_info 
*mtd, int mode)
  */
 static u32 nand_davinci_readecc(struct mtd_info *mtd)
 {
+       struct davinci_nand_info *info;
+       unsigned long flags;
+       unsigned int ecc;
+
+       info = to_davinci_nand(mtd);
+
        /* Read register ECC and clear it */
-       return davinci_nand_readl(NANDF1ECC_OFFSET);
+       spin_lock_irqsave(&info->lock, flags);
+       ecc = davinci_nand_readl(info, NANDF1ECC_OFFSET);
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       return ecc;
 }
 
 /*
@@ -248,6 +279,7 @@ static int nand_davinci_memory_bbt(struct mtd_info *mtd,
        int blocksize = 1 << chip->bbt_erase_shift;
        uint8_t *buf = chip->buffers->databuf;
        int len = bd->options & NAND_BBT_SCAN2NDPAGE ? 2 : 1;
+       struct davinci_nand_info *info = to_davinci_nand(mtd);
 
        /* -numblocks- is 2 times the actual number of eraseblocks */
        numblocks = mtd->size >> (chip->bbt_erase_shift - 1);
@@ -273,7 +305,7 @@ static int nand_davinci_memory_bbt(struct mtd_info *mtd,
                                   table */
                                chip->bbt[i >> 3] |= 0x03 << (i & 0x6);
 
-                               printk(KERN_WARNING "Bad eraseblock %d at " \
+                               dev_dbg(info->dev, "Bad eraseblock %d at " \
                                                    "0x%08x\n", i >> 1,
                                                     (unsigned int)from);
 
@@ -287,7 +319,7 @@ static int nand_davinci_memory_bbt(struct mtd_info *mtd,
                from += blocksize;
        }
 
-       printk(KERN_NOTICE "Bad block scan: %d out of %d blocks are bad.\n",
+       dev_dbg(info->dev, "Bad block scan: %d out of %d blocks are bad.\n",
                            mtd->ecc_stats.badblocks, numblocks>>1);
 
        return 0;
@@ -303,6 +335,7 @@ static int nand_davinci_scan_bbt(struct mtd_info *mtd)
        struct nand_chip *chip = mtd->priv;
        struct nand_bbt_descr *bd;
        int len, ret = 0;
+       struct davinci_nand_info *info = to_davinci_nand(mtd);
 
        chip->bbt_td = NULL;
        chip->bbt_md = NULL;
@@ -322,14 +355,14 @@ static int nand_davinci_scan_bbt(struct mtd_info *mtd)
           table */
        chip->bbt = kzalloc(len, GFP_KERNEL);
        if (!chip->bbt) {
-               printk(KERN_ERR "nand_davinci_scan_bbt: Out of memory\n");
+               dev_err(info->dev, "nand_davinci_scan_bbt: Out of memory\n");
                return -ENOMEM;
        }
 
        /* Now try to fill in the BBT */
        ret = nand_davinci_memory_bbt(mtd, bd);
        if (ret) {
-               printk(KERN_ERR "nand_davinci_scan_bbt: "
+               dev_err(info->dev, "nand_davinci_scan_bbt: "
                       "Can't scan flash and build the RAM-based BBT\n");
 
                kfree(chip->bbt);
@@ -360,7 +393,17 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, 
uint8_t *buf, int len)
  */
 static int nand_davinci_dev_ready(struct mtd_info *mtd)
 {
-       return davinci_nand_readl(NANDFSR_OFFSET) & NAND_BUSY_FLAG;
+       struct davinci_nand_info *info;
+       unsigned long flags;
+       unsigned int ready;
+
+       info = to_davinci_nand(mtd);
+
+       spin_lock_irqsave(&info->lock, flags);
+       ready = davinci_nand_readl(info, NANDFSR_OFFSET) & NAND_BUSY_FLAG;
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       return ready;
 }
 
 static void nand_davinci_set_eccsize(struct nand_chip *chip)
@@ -408,10 +451,13 @@ static void nand_davinci_set_eccbytes(struct nand_chip 
*chip)
 #endif
 }
 
-static void __devinit nand_davinci_flash_init(void)
+static void __devinit nand_davinci_flash_init(struct davinci_nand_info *info)
 {
+       unsigned long flags;
        u32 regval, tmp;
 
+       spin_lock_irqsave(&info->lock, flags);
+
        /* Check for correct pin mux, reconfigure if necessary */
        tmp = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + PINMUX0);
 
@@ -431,14 +477,14 @@ static void __devinit nand_davinci_flash_init(void)
 
                regval = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + PINMUX0);
 
-               printk(KERN_WARNING "Warning: MUX config for NAND: Set " \
+               dev_dbg(info->dev, "Warning: MUX config for NAND: Set " \
                       "PINMUX0 reg to 0x%08x, was 0x%08x, should be done " \
                       "by bootloader.\n", regval, tmp);
        }
 
-       regval = davinci_nand_readl(AWCCR_OFFSET);
+       regval = davinci_nand_readl(info, AWCCR_OFFSET);
        regval |= 0x10000000;
-       davinci_nand_writel(regval, AWCCR_OFFSET);
+       davinci_nand_writel(info, AWCCR_OFFSET, regval);
 
        /*------------------------------------------------------------------*
         *  NAND FLASH CHIP TIMEOUT @ 459 MHz                               *
@@ -459,163 +505,185 @@ static void __devinit nand_davinci_flash_init(void)
                | (3 << 2)            /* turnAround      ?? ns */
                | (0 << 0)            /* asyncSize       8-bit bus */
                ;
-       tmp = davinci_nand_readl(A1CR_OFFSET);
+       tmp = davinci_nand_readl(info, A1CR_OFFSET);
        if (tmp != regval) {
-               printk(KERN_WARNING "Warning: NAND config: Set A1CR " \
+               dev_dbg(info->dev, "Warning: NAND config: Set A1CR " \
                       "reg to 0x%08x, was 0x%08x, should be done by " \
                       "bootloader.\n", regval, tmp);
-               davinci_nand_writel(regval, A1CR_OFFSET); /* 0x0434018C */
+               davinci_nand_writel(info, A1CR_OFFSET, regval); /* 0x0434018C */
        }
 
-       davinci_nand_writel(0x00000101, NANDFCR_OFFSET);
+       davinci_nand_writel(info, NANDFCR_OFFSET, 0x00000101);
+
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
-/*
- * Main initialization routine
- */
-int __devinit nand_davinci_probe(struct platform_device *pdev)
+static int __init nand_davinci_probe(struct platform_device *pdev)
 {
        struct flash_platform_data      *pdata = pdev->dev.platform_data;
-       struct resource                 *res = pdev->resource;
-       struct resource                 *res2 = platform_get_resource(pdev,
-                                               IORESOURCE_MEM, 1);
-       struct nand_chip                *chip;
-       struct device                   *dev = NULL;
-       u32                             nand_rev_code;
+       struct davinci_nand_info        *info;
+       struct resource                 *res1;
+       struct resource                 *res2;
 #ifdef CONFIG_MTD_CMDLINE_PARTS
+       struct mtd_partition            *mtd_parts = 0;
        char                            *master_name;
        int                             mtd_parts_nb = 0;
-       struct mtd_partition            *mtd_parts = 0;
 #endif
+       void __iomem                    *vaddr;
+       void __iomem                    *base;
 
-       nand_clock = clk_get(dev, "AEMIFCLK");
-       if (IS_ERR(nand_clock)) {
-               printk(KERN_ERR "Error %ld getting AEMIFCLK clock?\n",
-                      PTR_ERR(nand_clock));
-               return -1;
+       int                             ret;
+       u32                             rev;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "platform_data missing\n");
+               ret = -ENODEV;
+               goto err_pdata;
        }
 
-       clk_enable(nand_clock);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "unable to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_nomem;
+       }
 
-       /* Allocate memory for MTD device structure and private data */
-       nand_davinci_mtd = kmalloc(sizeof(struct mtd_info) +
-                                  sizeof(struct nand_chip), GFP_KERNEL);
+       spin_lock_init(&info->lock);
+       platform_set_drvdata(pdev, info);
 
-       if (!nand_davinci_mtd) {
-               printk(KERN_ERR "Unable to allocate davinci NAND MTD device " \
-                      "structure.\n");
-               clk_disable(nand_clock);
-               return -ENOMEM;
+       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res1 || !res2) {
+               dev_err(&pdev->dev, "resource missing\n");
+               ret = -EINVAL;
+               goto err_res;
        }
 
-       /* Get pointer to private data */
-       chip = (struct nand_chip *) (&nand_davinci_mtd[1]);
+       vaddr = ioremap(res1->start, res1->end - res1->start);
+       base = ioremap(res2->start, res2->end - res2->start);
+       if (!vaddr || !base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -EINVAL;
+               goto err_ioremap;
 
-       /* Initialize structures */
-       memset((char *)nand_davinci_mtd, 0, sizeof(struct mtd_info));
-       memset((char *)chip, 0, sizeof(struct nand_chip));
-
-       /* Link the private data with the MTD structure */
-       nand_davinci_mtd->priv = chip;
+       }
 
-       nand_rev_code = davinci_nand_readl(NRCSR_OFFSET);
+       info->dev               = &pdev->dev;
+       info->base              = base;
+       info->vaddr             = vaddr;
 
-       printk("DaVinci NAND Controller rev. %d.%d\n",
-              (nand_rev_code >> 8) & 0xff, nand_rev_code & 0xff);
+       info->mtd.priv          = &info->chip;
+       info->mtd.name          = dev_name(&pdev->dev);
+       info->mtd.owner         = THIS_MODULE;
 
-       nand_vaddr = ioremap(res->start, res->end - res->start);
-       emif_base = ioremap(res2->start, res2->end - res2->start);
-       if (nand_vaddr == NULL || emif_base == NULL) {
-               printk(KERN_ERR "DaVinci NAND: ioremap failed.\n");
-               clk_disable(nand_clock);
-               kfree(nand_davinci_mtd);
-               return -ENOMEM;
-       }
+       info->chip.IO_ADDR_R    = vaddr;
+       info->chip.IO_ADDR_W    = vaddr;
+       info->chip.chip_delay   = 0;
+       info->chip.select_chip  = nand_davinci_select_chip;
+       info->chip.options      = 0;
+       info->chip.ecc.mode     = DAVINCI_NAND_ECC_MODE;
 
-       chip->IO_ADDR_R         = nand_vaddr;
-       chip->IO_ADDR_W         = nand_vaddr;
-       chip->chip_delay        = 0;
-       chip->select_chip       = nand_davinci_select_chip;
-       chip->options           = 0;
-       chip->ecc.mode          = DAVINCI_NAND_ECC_MODE;
+       /* Set address of hardware control function */
+       info->chip.cmd_ctrl     = nand_davinci_hwcontrol;
+       info->chip.dev_ready    = nand_davinci_dev_ready;
 
-       /* Set ECC size and bytes */
-       nand_davinci_set_eccsize(chip);
-       nand_davinci_set_eccbytes(chip);
+       /* Speed up the read buffer */
+       info->chip.read_buf      = nand_davinci_read_buf;
 
-       /* Set address of hardware control function */
-       chip->cmd_ctrl          = nand_davinci_hwcontrol;
-       chip->dev_ready         = nand_davinci_dev_ready;
+       /* Speed up the creation of the bad block table */
+       info->chip.scan_bbt      = nand_davinci_scan_bbt;
 
 #ifdef CONFIG_NAND_FLASH_HW_ECC
-       chip->ecc.calculate     = nand_davinci_calculate_ecc;
-       chip->ecc.correct       = nand_davinci_correct_data;
-       chip->ecc.hwctl         = nand_davinci_enable_hwecc;
+       /* REVISIT should be using runtime check */
+       info->chip.ecc.calculate = nand_davinci_calculate_ecc;
+       info->chip.ecc.correct   = nand_davinci_correct_data;
+       info->chip.ecc.hwctl     = nand_davinci_enable_hwecc;
 #endif
 
-       /* Speed up the read buffer */
-       chip->read_buf          = nand_davinci_read_buf;
+       info->clk = clk_get(&pdev->dev, "AEMIFCLK");
+       if (IS_ERR(info->clk)) {
+               ret = PTR_ERR(info->clk);
+               dev_dbg(&pdev->dev, "unable to get AEMIFCLK, err %d\n", ret);
+               goto err_clk;
+       }
 
-       /* Speed up the creation of the bad block table */
-       chip->scan_bbt          = nand_davinci_scan_bbt;
+       ret = clk_enable(info->clk);
+       if (ret < 0) {
+               dev_dbg(&pdev->dev, "unable to enable AEMIFCLK, err %d\n", ret);
+               goto err_clk_enable;
+       }
 
-       nand_davinci_flash_init();
+       /* Set ECC size and bytes */
+       nand_davinci_set_eccsize(&info->chip);
+       nand_davinci_set_eccbytes(&info->chip);
 
-       nand_davinci_mtd->owner = THIS_MODULE;
+       nand_davinci_flash_init(info);
 
        /* Scan to find existence of the device */
-       if (nand_scan(nand_davinci_mtd, 1)) {
-               printk(KERN_ERR "Chip Select is not set for NAND\n");
-               clk_disable(nand_clock);
-               kfree(nand_davinci_mtd);
-               return -ENXIO;
+       if (nand_scan(&info->mtd, 1)) {
+               dev_err(&pdev->dev, "chip select is not set for 'NAND'\n");
+               ret = -ENXIO;
+               goto err_scan;
        }
 
        /* Register the partitions */
-       add_mtd_partitions(nand_davinci_mtd, pdata->parts, pdata->nr_parts);
+       add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
 
 #ifdef CONFIG_MTD_CMDLINE_PARTS
-       /* Set nand_davinci_mtd->name = 0 temporarily */
-       master_name = nand_davinci_mtd->name;
-       nand_davinci_mtd->name  = (char *)0;
+       /* Set info->mtd.name = 0 temporarily */
+       master_name             = info->mtd.name;
+       info->mtd.name          = (char *)0;
 
-       /* nand_davinci_mtd->name == 0, means: don't bother checking
+       /* info->mtd.name == 0, means: don't bother checking
           <mtd-id> */
-       mtd_parts_nb = parse_mtd_partitions(nand_davinci_mtd, part_probes,
+       mtd_parts_nb = parse_mtd_partitions(&info->mtd, part_probes,
                                            &mtd_parts, 0);
 
-       /* Restore nand_davinci_mtd->name */
-       nand_davinci_mtd->name = master_name;
+       /* Restore info->mtd.name */
+       info->mtd.name = master_name;
 
-       add_mtd_partitions(nand_davinci_mtd, mtd_parts, mtd_parts_nb);
+       add_mtd_partitions(&info->mtd, mtd_parts, mtd_parts_nb);
 #endif
 
+       rev = davinci_nand_readl(info, NRCSR_OFFSET);
+       dev_info(&pdev->dev, "controller rev. %d.%d\n",
+              (rev >> 8) & 0xff, rev & 0xff);
+
        return 0;
+
+err_scan:
+       clk_disable(info->clk);
+
+err_clk_enable:
+       clk_put(info->clk);
+
+err_clk:
+err_ioremap:
+       kfree(info);
+
+err_nomem:
+err_res:
+err_pdata:
+       return ret;
 }
 
-/*
- * Clean up routine
- */
-static int nand_davinci_remove(struct platform_device *pdev)
+static int __exit nand_davinci_remove(struct platform_device *pdev)
 {
-       clk_disable(nand_clock);
+       struct davinci_nand_info *info = platform_get_drvdata(pdev);
 
-       if (nand_vaddr)
-               iounmap(nand_vaddr);
+       iounmap(info->base);
+       iounmap(info->vaddr);
 
-       if (emif_base)
-               iounmap(emif_base);
+       nand_release(&info->mtd);
 
-       /* Release resources, unregister device */
-       nand_release(nand_davinci_mtd);
+       clk_disable(info->clk);
+       clk_put(info->clk);
 
-       /* Free the MTD device structure */
-       kfree(nand_davinci_mtd);
+       kfree(info);
 
        return 0;
 }
 
-
 static struct platform_driver nand_davinci_driver = {
        .probe          = nand_davinci_probe,
        .remove         = nand_davinci_remove,
@@ -640,3 +708,4 @@ MODULE_ALIAS(DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("Davinci NAND flash driver");
+
-- 
1.6.0.4.617.g2baf1


_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to