Felipe,

Another minor comment below, in addition to Dave's comments:

Felipe Balbi <[EMAIL PROTECTED]> writes:

> 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)

I believe this should be __devexit, or there are linker problems when
the driver is built in.

Kevin


>  {
> -     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

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

Reply via email to