mtd: denali: split the generic driver and PCI layer
authorDinh Nguyen <dinguyen@altera.com>
Thu, 27 Sep 2012 16:58:05 +0000 (10:58 -0600)
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Thu, 15 Nov 2012 13:37:46 +0000 (15:37 +0200)
The Denali controller can also be found in SoC devices attached to a
simple bus.  Move the PCI specific parts into denali_pci so that we can
add a denali_dt that uses the same driver but for a device tree driver
instead of a PCI based device.

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_pci.c [new file with mode: 0644]

index 4883139..5102e87 100644 (file)
@@ -57,8 +57,15 @@ config MTD_NAND_AUTCPU12
          access the SmartMediaCard.
 
 config MTD_NAND_DENALI
-       depends on PCI
+        tristate "Support Denali NAND controller"
+        help
+         Enable support for the Denali NAND controller.  This should be
+         combined with either the PCI or platform drivers to provide device
+         registration.
+
+config MTD_NAND_DENALI_PCI
         tristate "Support Denali NAND controller on Intel Moorestown"
+       depends on PCI && MTD_NAND_DENALI
         help
           Enable the driver for NAND flash on Intel Moorestown, using the
           Denali NAND controller core.
@@ -66,7 +73,7 @@ config MTD_NAND_DENALI
 config MTD_NAND_DENALI_SCRATCH_REG_ADDR
         hex "Denali NAND size scratch register address"
         default "0xFF108018"
-        depends on MTD_NAND_DENALI
+        depends on MTD_NAND_DENALI_PCI
         help
           Some platforms place the NAND chip size in a scratch register
           because (some versions of) the driver aren't able to automatically
index 2cbd091..96a6171 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_SPIA)           += spia.o
 obj-$(CONFIG_MTD_NAND_AMS_DELTA)       += ams-delta.o
 obj-$(CONFIG_MTD_NAND_AUTCPU12)                += autcpu12.o
 obj-$(CONFIG_MTD_NAND_DENALI)          += denali.o
+obj-$(CONFIG_MTD_NAND_DENALI_PCI)      += denali_pci.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
index e706a23..0c8bb6b 100644 (file)
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  *
  */
-
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 
@@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
  * format the bank into the proper bits for the controller */
 #define BANK(x) ((x) << 24)
 
-/* List of platforms this NAND controller has be integrated into */
-static const struct pci_device_id denali_pci_ids[] = {
-       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
-       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
-       { /* end: all zeroes */ }
-};
-
 /* forward declarations */
 static void clear_interrupts(struct denali_nand_info *denali);
 static uint32_t wait_for_irq(struct denali_nand_info *denali,
@@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
 
        if (comp_res == 0) {
                /* timeout */
-               printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n",
+               pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n",
                                intr_status, irq_mask);
 
                intr_status = 0;
@@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
                /* TODO: Read OOB data */
                break;
        default:
-               printk(KERN_ERR ": unsupported command"
-                               " received 0x%x\n", cmd);
+               pr_err(": unsupported command received 0x%x\n", cmd);
                break;
        }
 }
@@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali)
        denali->irq_status = 0;
 }
 
-/* driver entry point */
-static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+int denali_init(struct denali_nand_info *denali)
 {
-       int ret = -ENODEV;
-       resource_size_t csr_base, mem_base;
-       unsigned long csr_len, mem_len;
-       struct denali_nand_info *denali;
-
-       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
-       if (!denali)
-               return -ENOMEM;
+       int ret;
 
-       ret = pci_enable_device(dev);
-       if (ret) {
-               printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
-               goto failed_alloc_memery;
-       }
-
-       if (id->driver_data == INTEL_CE4100) {
+       if (denali->platform == INTEL_CE4100) {
                /* Due to a silicon limitation, we can only support
                 * ONFI timing mode 1 and below.
                 */
                if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
-                       printk(KERN_ERR "Intel CE4100 only supports"
-                                       " ONFI timing mode 1 or below\n");
-                       ret = -EINVAL;
-                       goto failed_enable_dev;
-               }
-               denali->platform = INTEL_CE4100;
-               mem_base = pci_resource_start(dev, 0);
-               mem_len = pci_resource_len(dev, 1);
-               csr_base = pci_resource_start(dev, 1);
-               csr_len = pci_resource_len(dev, 1);
-       } else {
-               denali->platform = INTEL_MRST;
-               csr_base = pci_resource_start(dev, 0);
-               csr_len = pci_resource_len(dev, 0);
-               mem_base = pci_resource_start(dev, 1);
-               mem_len = pci_resource_len(dev, 1);
-               if (!mem_len) {
-                       mem_base = csr_base + csr_len;
-                       mem_len = csr_len;
+                       pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n");
+                       return -EINVAL;
                }
        }
 
        /* Is 32-bit DMA supported? */
-       ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
+       ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
        if (ret) {
-               printk(KERN_ERR "Spectra: no usable DMA configuration\n");
-               goto failed_enable_dev;
+               pr_err("Spectra: no usable DMA configuration\n");
+               return ret;
        }
-       denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf,
+       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
                                             DENALI_BUF_SIZE,
                                             DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) {
-               dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n");
-               goto failed_enable_dev;
-       }
-
-       pci_set_master(dev);
-       denali->dev = &dev->dev;
-       denali->mtd.dev.parent = &dev->dev;
-
-       ret = pci_request_regions(dev, DENALI_NAND_NAME);
-       if (ret) {
-               printk(KERN_ERR "Spectra: Unable to request memory regions\n");
-               goto failed_dma_map;
-       }
-
-       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
-       if (!denali->flash_reg) {
-               printk(KERN_ERR "Spectra: Unable to remap memory region\n");
-               ret = -ENOMEM;
-               goto failed_req_regions;
-       }
-
-       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
-       if (!denali->flash_mem) {
-               printk(KERN_ERR "Spectra: ioremap_nocache failed!");
-               ret = -ENOMEM;
-               goto failed_remap_reg;
+       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
+               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               return -EIO;
        }
-
+       denali->mtd.dev.parent = denali->dev;
        denali_hw_init(denali);
        denali_drv_init(denali);
 
        /* denali_isr register is done after all the hardware
         * initilization is finished*/
-       if (request_irq(dev->irq, denali_isr, IRQF_SHARED,
+       if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
                        DENALI_NAND_NAME, denali)) {
-               printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
-               ret = -ENODEV;
-               goto failed_remap_mem;
+               pr_err("Spectra: Unable to allocate IRQ\n");
+               return -ENODEV;
        }
 
        /* now that our ISR is registered, we can enable interrupts */
        denali_set_intr_modes(denali, true);
-
-       pci_set_drvdata(dev, denali);
-
        denali->mtd.name = "denali-nand";
        denali->mtd.owner = THIS_MODULE;
        denali->mtd.priv = &denali->nand;
@@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         */
        if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
                ret = -ENODEV;
-               printk(KERN_ERR "Spectra: device size not supported by this "
-                       "version of MTD.");
+               pr_err("Spectra: device size not supported by this version of MTD.");
                goto failed_req_irq;
        }
 
@@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        } else if (denali->mtd.oobsize < (denali->bbtskipbytes +
                        ECC_8BITS * (denali->mtd.writesize /
                        ECC_SECTOR_SIZE))) {
-               printk(KERN_ERR "Your NAND chip OOB is not large enough to"
-                               contain 8bit ECC correction codes");
+               pr_err("Your NAND chip OOB is not large enough to \
+                               contain 8bit ECC correction codes");
                goto failed_req_irq;
        } else {
                denali->nand.ecc.strength = 8;
@@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        ret = mtd_device_register(&denali->mtd, NULL, 0);
        if (ret) {
-               dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n",
+               dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
                                ret);
                goto failed_req_irq;
        }
        return 0;
 
 failed_req_irq:
-       denali_irq_cleanup(dev->irq, denali);
-failed_remap_mem:
-       iounmap(denali->flash_mem);
-failed_remap_reg:
-       iounmap(denali->flash_reg);
-failed_req_regions:
-       pci_release_regions(dev);
-failed_dma_map:
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-failed_enable_dev:
-       pci_disable_device(dev);
-failed_alloc_memery:
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+
        return ret;
 }
+EXPORT_SYMBOL(denali_init);
 
 /* driver exit point */
-static void denali_pci_remove(struct pci_dev *dev)
+void denali_remove(struct denali_nand_info *denali)
 {
-       struct denali_nand_info *denali = pci_get_drvdata(dev);
-
-       nand_release(&denali->mtd);
-
-       denali_irq_cleanup(dev->irq, denali);
-
-       iounmap(denali->flash_reg);
-       iounmap(denali->flash_mem);
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-       pci_set_drvdata(dev, NULL);
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+       dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+                       DMA_BIDIRECTIONAL);
 }
-
-MODULE_DEVICE_TABLE(pci, denali_pci_ids);
-
-static struct pci_driver denali_pci_driver = {
-       .name = DENALI_NAND_NAME,
-       .id_table = denali_pci_ids,
-       .probe = denali_pci_probe,
-       .remove = denali_pci_remove,
-};
-
-module_pci_driver(denali_pci_driver);
+EXPORT_SYMBOL(denali_remove);
index fabb9d5..e5aa995 100644 (file)
@@ -487,6 +487,7 @@ struct denali_nand_info {
        uint32_t irq_status;
        int irq_debug_array[32];
        int idx;
+       int irq;
 
        uint32_t devnum;        /* represent how many nands connected */
        uint32_t fwblks; /* represent how many blocks FW used */
@@ -496,4 +497,7 @@ struct denali_nand_info {
        uint32_t max_banks;
 };
 
+extern int denali_init(struct denali_nand_info *denali);
+extern void denali_remove(struct denali_nand_info *denali);
+
 #endif /*_LLD_NAND_*/
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
new file mode 100644 (file)
index 0000000..ea074e6
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright © 2009-2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "denali.h"
+
+#define DENALI_NAND_NAME    "denali-nand-pci"
+
+/* List of platforms this NAND controller has be integrated into */
+static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
+       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
+       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
+       { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, denali_pci_ids);
+
+static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       int ret = -ENODEV;
+       resource_size_t csr_base, mem_base;
+       unsigned long csr_len, mem_len;
+       struct denali_nand_info *denali;
+
+       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
+       if (!denali)
+               return -ENOMEM;
+
+       ret = pci_enable_device(dev);
+       if (ret) {
+               pr_err("Spectra: pci_enable_device failed.\n");
+               goto failed_alloc_memery;
+       }
+
+       if (id->driver_data == INTEL_CE4100) {
+               denali->platform = INTEL_CE4100;
+               mem_base = pci_resource_start(dev, 0);
+               mem_len = pci_resource_len(dev, 1);
+               csr_base = pci_resource_start(dev, 1);
+               csr_len = pci_resource_len(dev, 1);
+       } else {
+               denali->platform = INTEL_MRST;
+               csr_base = pci_resource_start(dev, 0);
+               csr_len = pci_resource_len(dev, 0);
+               mem_base = pci_resource_start(dev, 1);
+               mem_len = pci_resource_len(dev, 1);
+               if (!mem_len) {
+                       mem_base = csr_base + csr_len;
+                       mem_len = csr_len;
+               }
+       }
+
+       pci_set_master(dev);
+       denali->dev = &dev->dev;
+       denali->irq = dev->irq;
+
+       ret = pci_request_regions(dev, DENALI_NAND_NAME);
+       if (ret) {
+               pr_err("Spectra: Unable to request memory regions\n");
+               goto failed_enable_dev;
+       }
+
+       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
+       if (!denali->flash_reg) {
+               pr_err("Spectra: Unable to remap memory region\n");
+               ret = -ENOMEM;
+               goto failed_req_regions;
+       }
+
+       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
+       if (!denali->flash_mem) {
+               pr_err("Spectra: ioremap_nocache failed!");
+               ret = -ENOMEM;
+               goto failed_remap_reg;
+       }
+
+       ret = denali_init(denali);
+       if (ret)
+               goto failed_remap_mem;
+
+       pci_set_drvdata(dev, denali);
+
+       return 0;
+
+failed_remap_mem:
+       iounmap(denali->flash_mem);
+failed_remap_reg:
+       iounmap(denali->flash_reg);
+failed_req_regions:
+       pci_release_regions(dev);
+failed_enable_dev:
+       pci_disable_device(dev);
+failed_alloc_memery:
+       kfree(denali);
+
+       return ret;
+}
+
+/* driver exit point */
+static void denali_pci_remove(struct pci_dev *dev)
+{
+       struct denali_nand_info *denali = pci_get_drvdata(dev);
+
+       denali_remove(denali);
+       iounmap(denali->flash_reg);
+       iounmap(denali->flash_mem);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       kfree(denali);
+}
+
+static struct pci_driver denali_pci_driver = {
+       .name = DENALI_NAND_NAME,
+       .id_table = denali_pci_ids,
+       .probe = denali_pci_probe,
+       .remove = denali_pci_remove,
+};
+
+static int __devinit denali_init_pci(void)
+{
+       pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
+       return pci_register_driver(&denali_pci_driver);
+}
+module_init(denali_init_pci);
+
+static void __devexit denali_exit_pci(void)
+{
+       pci_unregister_driver(&denali_pci_driver);
+}
+module_exit(denali_exit_pci);