diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-09 17:33:19 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-09 17:33:19 (GMT) |
commit | ef9a61bef917e38f8e096f6df303329aed6cf467 (patch) | |
tree | 31cfe2444d0270e77ff8ef792df11591fed6075c /drivers/mtd/nand/pxa3xx_nand.c | |
parent | b5f0998cae3d7ea56d3d8377e46328fe972b9546 (diff) | |
parent | 6c3b88970175e18a67eb8e55c4eba10614d0d5dc (diff) | |
download | linux-fsl-qoriq-ef9a61bef917e38f8e096f6df303329aed6cf467.tar.xz |
Merge tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd
Pull mtd updates from David Woodhouse:
- factor out common code from MTD tests
- nand-gpio cleanup and portability to non-ARM
- m25p80 support for 4-byte addressing chips, other new chips
- pxa3xx cleanup and support for new platforms
- remove obsolete alauda, octagon-5066 drivers
- erase/write support for bcm47xxsflash
- improve detection of ECC requirements for NAND, controller setup
- NFC acceleration support for atmel-nand, read/write via SRAM
- etc
* tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd: (184 commits)
mtd: chips: Add support for PMC SPI Flash chips in m25p80.c
mtd: ofpart: use for_each_child_of_node() macro
mtd: mtdswap: replace strict_strtoul() with kstrtoul()
mtd cs553x_nand: use kzalloc() instead of memset
mtd: atmel_nand: fix error return code in atmel_nand_probe()
mtd: bcm47xxsflash: writing support
mtd: bcm47xxsflash: implement erasing support
mtd: bcm47xxsflash: convert to module_platform_driver instead of init/exit
mtd: bcm47xxsflash: convert kzalloc to avoid invalid access
mtd: remove alauda driver
mtd: nand: mxc_nand: mark 'const' properly
mtd: maps: cfi_flagadm: add missing __iomem annotation
mtd: spear_smi: add missing __iomem annotation
mtd: r852: Staticize local symbols
mtd: nandsim: Staticize local symbols
mtd: impa7: add missing __iomem annotation
mtd: sm_ftl: Staticize local symbols
mtd: m25p80: add support for mr25h10
mtd: m25p80: make CONFIG_M25PXX_USE_FAST_READ safe to enable
mtd: m25p80: Pass flags through CAT25_INFO macro
...
Diffstat (limited to 'drivers/mtd/nand/pxa3xx_nand.c')
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 384 |
1 files changed, 221 insertions, 163 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index dec80ca..5db900d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -25,7 +25,14 @@ #include <linux/of.h> #include <linux/of_device.h> +#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) +#define ARCH_HAS_DMA +#endif + +#ifdef ARCH_HAS_DMA #include <mach/dma.h> +#endif + #include <linux/platform_data/mtd-nand-pxa3xx.h> #define CHIP_DELAY_TIMEOUT (2 * HZ/10) @@ -80,6 +87,7 @@ #define NDSR_RDDREQ (0x1 << 1) #define NDSR_WRCMDREQ (0x1) +#define NDCB0_LEN_OVRD (0x1 << 28) #define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) @@ -123,9 +131,13 @@ enum { STATE_READY, }; +enum pxa3xx_nand_variant { + PXA3XX_NAND_VARIANT_PXA, + PXA3XX_NAND_VARIANT_ARMADA370, +}; + struct pxa3xx_nand_host { struct nand_chip chip; - struct pxa3xx_nand_cmdset *cmdset; struct mtd_info *mtd; void *info_data; @@ -139,10 +151,6 @@ struct pxa3xx_nand_host { unsigned int row_addr_cycles; size_t read_id_bytes; - /* cached register value */ - uint32_t reg_ndcr; - uint32_t ndtr0cs0; - uint32_t ndtr1cs0; }; struct pxa3xx_nand_info { @@ -171,9 +179,16 @@ struct pxa3xx_nand_info { struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; unsigned int state; + /* + * This driver supports NFCv1 (as found in PXA SoC) + * and NFCv2 (as found in Armada 370/XP SoC). + */ + enum pxa3xx_nand_variant variant; + int cs; int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ + int use_spare; /* use spare ? */ int is_ready; unsigned int page_size; /* page size of attached chip */ @@ -181,33 +196,22 @@ struct pxa3xx_nand_info { unsigned int oob_size; int retcode; + /* cached register value */ + uint32_t reg_ndcr; + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; + /* generated NDCBx register values */ uint32_t ndcb0; uint32_t ndcb1; uint32_t ndcb2; + uint32_t ndcb3; }; static bool use_dma = 1; module_param(use_dma, bool, 0444); MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW"); -/* - * Default NAND flash controller configuration setup by the - * bootloader. This configuration is used only when pdata->keep_config is set - */ -static struct pxa3xx_nand_cmdset default_cmdset = { - .read1 = 0x3000, - .read2 = 0x0050, - .program = 0x1080, - .read_status = 0x0070, - .read_id = 0x0090, - .erase = 0xD060, - .reset = 0x00FF, - .lock = 0x002A, - .unlock = 0x2423, - .lock_status = 0x007A, -}; - static struct pxa3xx_nand_timing timing[] = { { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, @@ -230,8 +234,6 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) -const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; - #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) #define NDTR0_tWH(c) (min((c), 7) << 11) @@ -264,8 +266,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); - host->ndtr0cs0 = ndtr0; - host->ndtr1cs0 = ndtr1; + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } @@ -273,7 +275,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { struct pxa3xx_nand_host *host = info->host[info->cs]; - int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; + int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; info->data_size = host->page_size; if (!oob_enable) { @@ -299,12 +301,25 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) */ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) { - struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr; - ndcr = host->reg_ndcr; - ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; - ndcr |= info->use_dma ? NDCR_DMA_EN : 0; + ndcr = info->reg_ndcr; + + if (info->use_ecc) + ndcr |= NDCR_ECC_EN; + else + ndcr &= ~NDCR_ECC_EN; + + if (info->use_dma) + ndcr |= NDCR_DMA_EN; + else + ndcr &= ~NDCR_DMA_EN; + + if (info->use_spare) + ndcr |= NDCR_SPARE_EN; + else + ndcr &= ~NDCR_SPARE_EN; + ndcr |= NDCR_ND_RUN; /* clear status bits and run */ @@ -333,7 +348,8 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) nand_writel(info, NDSR, NDSR_MASK); } -static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) +static void __maybe_unused +enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) { uint32_t ndcr; @@ -373,6 +389,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) } } +#ifdef ARCH_HAS_DMA static void start_data_dma(struct pxa3xx_nand_info *info) { struct pxa_dma_desc *desc = info->data_desc; @@ -419,6 +436,10 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data) enable_int(info, NDCR_INT_MASK); nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); } +#else +static void start_data_dma(struct pxa3xx_nand_info *info) +{} +#endif static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { @@ -467,9 +488,22 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) nand_writel(info, NDSR, NDSR_WRCMDREQ); status &= ~NDSR_WRCMDREQ; info->state = STATE_CMD_HANDLE; + + /* + * Command buffer registers NDCB{0-2} (and optionally NDCB3) + * must be loaded by writing directly either 12 or 16 + * bytes directly to NDCB0, four bytes at a time. + * + * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored + * but each NDCBx register can be read. + */ nand_writel(info, NDCB0, info->ndcb0); nand_writel(info, NDCB0, info->ndcb1); nand_writel(info, NDCB0, info->ndcb2); + + /* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */ + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + nand_writel(info, NDCB0, info->ndcb3); } /* clear NDSR to let the controller exit the IRQ */ @@ -491,7 +525,6 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, uint16_t column, int page_addr) { - uint16_t cmd; int addr_cycle, exec_cmd; struct pxa3xx_nand_host *host; struct mtd_info *mtd; @@ -506,6 +539,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->buf_count = 0; info->oob_size = 0; info->use_ecc = 0; + info->use_spare = 1; + info->use_dma = (use_dma) ? 1 : 0; info->is_ready = 0; info->retcode = ERR_NONE; if (info->cs != 0) @@ -520,12 +555,16 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, case NAND_CMD_READOOB: pxa3xx_set_datasize(info); break; + case NAND_CMD_PARAM: + info->use_spare = 0; + break; case NAND_CMD_SEQIN: exec_cmd = 0; break; default: info->ndcb1 = 0; info->ndcb2 = 0; + info->ndcb3 = 0; break; } @@ -535,21 +574,17 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, switch (command) { case NAND_CMD_READOOB: case NAND_CMD_READ0: - cmd = host->cmdset->read1; + info->buf_start = column; + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | addr_cycle + | NAND_CMD_READ0; + if (command == NAND_CMD_READOOB) - info->buf_start = mtd->writesize + column; - else - info->buf_start = column; + info->buf_start += mtd->writesize; - if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) - info->ndcb0 |= NDCB0_CMD_TYPE(0) - | addr_cycle - | (cmd & NDCB0_CMD1_MASK); - else - info->ndcb0 |= NDCB0_CMD_TYPE(0) - | NDCB0_DBC - | addr_cycle - | cmd; + /* Second command setting for large pages */ + if (host->page_size >= PAGE_CHUNK_SIZE) + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); case NAND_CMD_SEQIN: /* small page addr setting */ @@ -580,49 +615,58 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - cmd = host->cmdset->program; info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_AUTO_RS | NDCB0_ST_ROW_EN | NDCB0_DBC - | cmd + | (NAND_CMD_PAGEPROG << 8) + | NAND_CMD_SEQIN | addr_cycle; break; + case NAND_CMD_PARAM: + info->buf_count = 256; + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | NDCB0_ADDR_CYC(1) + | NDCB0_LEN_OVRD + | command; + info->ndcb1 = (column & 0xFF); + info->ndcb3 = 256; + info->data_size = 256; + break; + case NAND_CMD_READID: - cmd = host->cmdset->read_id; info->buf_count = host->read_id_bytes; info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) - | cmd; + | command; + info->ndcb1 = (column & 0xFF); info->data_size = 8; break; case NAND_CMD_STATUS: - cmd = host->cmdset->read_status; info->buf_count = 1; info->ndcb0 |= NDCB0_CMD_TYPE(4) | NDCB0_ADDR_CYC(1) - | cmd; + | command; info->data_size = 8; break; case NAND_CMD_ERASE1: - cmd = host->cmdset->erase; info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3) | NDCB0_DBC - | cmd; + | (NAND_CMD_ERASE2 << 8) + | NAND_CMD_ERASE1; info->ndcb1 = page_addr; info->ndcb2 = 0; break; case NAND_CMD_RESET: - cmd = host->cmdset->reset; info->ndcb0 |= NDCB0_CMD_TYPE(5) - | cmd; + | command; break; @@ -652,7 +696,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, * "byte" address into a "word" address appropriate * for indexing a word-oriented device */ - if (host->reg_ndcr & NDCR_DWIDTH_M) + if (info->reg_ndcr & NDCR_DWIDTH_M) column /= 2; /* @@ -662,8 +706,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, */ if (info->cs != host->cs) { info->cs = host->cs; - nand_writel(info, NDTR0CS0, host->ndtr0cs0); - nand_writel(info, NDTR1CS0, host->ndtr1cs0); + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); } info->state = STATE_PREPARED; @@ -803,7 +847,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_flash *f) { struct platform_device *pdev = info->pdev; - struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr = 0x0; /* enable all interrupts */ @@ -818,7 +862,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, } /* calculate flash information */ - host->cmdset = &default_cmdset; host->page_size = f->page_size; host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; @@ -840,7 +883,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); ndcr |= NDCR_SPARE_EN; /* enable spare by default */ - host->reg_ndcr = ndcr; + info->reg_ndcr = ndcr; pxa3xx_nand_set_timing(host, f->timing); return 0; @@ -863,12 +906,9 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) host->read_id_bytes = 2; } - host->reg_ndcr = ndcr & ~NDCR_INT_MASK; - host->cmdset = &default_cmdset; - - host->ndtr0cs0 = nand_readl(info, NDTR0CS0); - host->ndtr1cs0 = nand_readl(info, NDTR1CS0); - + info->reg_ndcr = ndcr & ~NDCR_INT_MASK; + info->ndtr0cs0 = nand_readl(info, NDTR0CS0); + info->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; } @@ -878,6 +918,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) */ #define MAX_BUFF_SIZE PAGE_SIZE +#ifdef ARCH_HAS_DMA static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) { struct platform_device *pdev = info->pdev; @@ -912,6 +953,32 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) return 0; } +static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) +{ + struct platform_device *pdev = info->pdev; + if (use_dma) { + pxa_free_dma(info->data_dma_ch); + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, + info->data_buff, info->data_buff_phys); + } else { + kfree(info->data_buff); + } +} +#else +static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) +{ + info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); + if (info->data_buff == NULL) + return -ENOMEM; + return 0; +} + +static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) +{ + kfree(info->data_buff); +} +#endif + static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { struct mtd_info *mtd; @@ -934,7 +1001,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; struct platform_device *pdev = info->pdev; - struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; @@ -1003,7 +1070,7 @@ KEEP_CONFIG: chip->ecc.size = host->page_size; chip->ecc.strength = 1; - if (host->reg_ndcr & NDCR_DWIDTH_M) + if (info->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, def)) @@ -1019,8 +1086,6 @@ KEEP_CONFIG: host->row_addr_cycles = 3; else host->row_addr_cycles = 2; - - mtd->name = mtd_names[0]; return nand_scan_tail(mtd); } @@ -1034,13 +1099,11 @@ static int alloc_nand_resource(struct platform_device *pdev) struct resource *r; int ret, irq, cs; - pdata = pdev->dev.platform_data; - info = kzalloc(sizeof(*info) + (sizeof(*mtd) + - sizeof(*host)) * pdata->num_cs, GFP_KERNEL); - if (!info) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + pdata = dev_get_platdata(&pdev->dev); + info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) + + sizeof(*host)) * pdata->num_cs, GFP_KERNEL); + if (!info) return -ENOMEM; - } info->pdev = pdev; for (cs = 0; cs < pdata->num_cs; cs++) { @@ -1069,72 +1132,64 @@ static int alloc_nand_resource(struct platform_device *pdev) spin_lock_init(&chip->controller->lock); init_waitqueue_head(&chip->controller->wq); - info->clk = clk_get(&pdev->dev, NULL); + info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed to get nand clock\n"); - ret = PTR_ERR(info->clk); - goto fail_free_mtd; + return PTR_ERR(info->clk); } - clk_enable(info->clk); - - /* - * This is a dirty hack to make this driver work from devicetree - * bindings. It can be removed once we have a prober DMA controller - * framework for DT. - */ - if (pdev->dev.of_node && cpu_is_pxa3xx()) { - info->drcmr_dat = 97; - info->drcmr_cmd = 99; - } else { - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for data DMA\n"); - ret = -ENXIO; - goto fail_put_clk; - } - info->drcmr_dat = r->start; + ret = clk_prepare_enable(info->clk); + if (ret < 0) + return ret; - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for command DMA\n"); - ret = -ENXIO; - goto fail_put_clk; + if (use_dma) { + /* + * This is a dirty hack to make this driver work from + * devicetree bindings. It can be removed once we have + * a prober DMA controller framework for DT. + */ + if (pdev->dev.of_node && + of_machine_is_compatible("marvell,pxa3xx")) { + info->drcmr_dat = 97; + info->drcmr_cmd = 99; + } else { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r == NULL) { + dev_err(&pdev->dev, + "no resource defined for data DMA\n"); + ret = -ENXIO; + goto fail_disable_clk; + } + info->drcmr_dat = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r == NULL) { + dev_err(&pdev->dev, + "no resource defined for cmd DMA\n"); + ret = -ENXIO; + goto fail_disable_clk; + } + info->drcmr_cmd = r->start; } - info->drcmr_cmd = r->start; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no IRQ resource defined\n"); ret = -ENXIO; - goto fail_put_clk; + goto fail_disable_clk; } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no IO memory resource defined\n"); - ret = -ENODEV; - goto fail_put_clk; - } - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (r == NULL) { - dev_err(&pdev->dev, "failed to request memory resource\n"); - ret = -EBUSY; - goto fail_put_clk; - } - - info->mmio_base = ioremap(r->start, resource_size(r)); - if (info->mmio_base == NULL) { - dev_err(&pdev->dev, "ioremap() failed\n"); - ret = -ENODEV; - goto fail_free_res; + info->mmio_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(info->mmio_base)) { + ret = PTR_ERR(info->mmio_base); + goto fail_disable_clk; } info->mmio_phys = r->start; ret = pxa3xx_nand_init_buff(info); if (ret) - goto fail_free_io; + goto fail_disable_clk; /* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK); @@ -1152,21 +1207,9 @@ static int alloc_nand_resource(struct platform_device *pdev) fail_free_buf: free_irq(irq, info); - if (use_dma) { - pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, - info->data_buff, info->data_buff_phys); - } else - kfree(info->data_buff); -fail_free_io: - iounmap(info->mmio_base); -fail_free_res: - release_mem_region(r->start, resource_size(r)); -fail_put_clk: - clk_disable(info->clk); - clk_put(info->clk); -fail_free_mtd: - kfree(info); + pxa3xx_nand_free_buff(info); +fail_disable_clk: + clk_disable_unprepare(info->clk); return ret; } @@ -1174,44 +1217,48 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); struct pxa3xx_nand_platform_data *pdata; - struct resource *r; int irq, cs; if (!info) return 0; - pdata = pdev->dev.platform_data; - platform_set_drvdata(pdev, NULL); + pdata = dev_get_platdata(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq >= 0) free_irq(irq, info); - if (use_dma) { - pxa_free_dma(info->data_dma_ch); - dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, - info->data_buff, info->data_buff_phys); - } else - kfree(info->data_buff); - - iounmap(info->mmio_base); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); + pxa3xx_nand_free_buff(info); - clk_disable(info->clk); - clk_put(info->clk); + clk_disable_unprepare(info->clk); for (cs = 0; cs < pdata->num_cs; cs++) nand_release(info->host[cs]->mtd); - kfree(info); return 0; } #ifdef CONFIG_OF static struct of_device_id pxa3xx_nand_dt_ids[] = { - { .compatible = "marvell,pxa3xx-nand" }, + { + .compatible = "marvell,pxa3xx-nand", + .data = (void *)PXA3XX_NAND_VARIANT_PXA, + }, + { + .compatible = "marvell,armada370-nand", + .data = (void *)PXA3XX_NAND_VARIANT_ARMADA370, + }, {} }; -MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); +MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); + +static enum pxa3xx_nand_variant +pxa3xx_nand_get_variant(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); + if (!of_id) + return PXA3XX_NAND_VARIANT_PXA; + return (enum pxa3xx_nand_variant)of_id->data; +} static int pxa3xx_nand_probe_dt(struct platform_device *pdev) { @@ -1251,11 +1298,18 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) struct pxa3xx_nand_info *info; int ret, cs, probe_success; +#ifndef ARCH_HAS_DMA + if (use_dma) { + use_dma = 0; + dev_warn(&pdev->dev, + "This platform can't do DMA on this device\n"); + } +#endif ret = pxa3xx_nand_probe_dt(pdev); if (ret) return ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -ENODEV; @@ -1268,10 +1322,14 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } info = platform_get_drvdata(pdev); + info->variant = pxa3xx_nand_get_variant(pdev); probe_success = 0; for (cs = 0; cs < pdata->num_cs; cs++) { + struct mtd_info *mtd = info->host[cs]->mtd; + + mtd->name = pdev->name; info->cs = cs; - ret = pxa3xx_nand_scan(info->host[cs]->mtd); + ret = pxa3xx_nand_scan(mtd); if (ret) { dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", cs); @@ -1279,7 +1337,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } ppdata.of_node = pdev->dev.of_node; - ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, + ret = mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts[cs], pdata->nr_parts[cs]); if (!ret) @@ -1302,7 +1360,7 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) struct mtd_info *mtd; int cs; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; @@ -1323,7 +1381,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) struct mtd_info *mtd; int cs; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); /* We don't want to handle interrupt without calling mtd routine */ disable_int(info, NDCR_INT_MASK); |