diff options
Diffstat (limited to 'drivers/mtd/nand')
45 files changed, 1657 insertions, 716 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dae191b3c081..5819eb575210 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -50,16 +50,30 @@ config MTD_NAND_MUSEUM_IDS | |||
50 | of these chips were reused by later, larger chips. | 50 | of these chips were reused by later, larger chips. |
51 | 51 | ||
52 | config MTD_NAND_DENALI | 52 | config MTD_NAND_DENALI |
53 | depends on PCI | 53 | tristate "Support Denali NAND controller" |
54 | help | ||
55 | Enable support for the Denali NAND controller. This should be | ||
56 | combined with either the PCI or platform drivers to provide device | ||
57 | registration. | ||
58 | |||
59 | config MTD_NAND_DENALI_PCI | ||
54 | tristate "Support Denali NAND controller on Intel Moorestown" | 60 | tristate "Support Denali NAND controller on Intel Moorestown" |
61 | depends on PCI && MTD_NAND_DENALI | ||
55 | help | 62 | help |
56 | Enable the driver for NAND flash on Intel Moorestown, using the | 63 | Enable the driver for NAND flash on Intel Moorestown, using the |
57 | Denali NAND controller core. | 64 | Denali NAND controller core. |
58 | 65 | ||
66 | config MTD_NAND_DENALI_DT | ||
67 | tristate "Support Denali NAND controller as a DT device" | ||
68 | depends on HAVE_CLK && MTD_NAND_DENALI | ||
69 | help | ||
70 | Enable the driver for NAND flash on platforms using a Denali NAND | ||
71 | controller as a DT device. | ||
72 | |||
59 | config MTD_NAND_DENALI_SCRATCH_REG_ADDR | 73 | config MTD_NAND_DENALI_SCRATCH_REG_ADDR |
60 | hex "Denali NAND size scratch register address" | 74 | hex "Denali NAND size scratch register address" |
61 | default "0xFF108018" | 75 | default "0xFF108018" |
62 | depends on MTD_NAND_DENALI | 76 | depends on MTD_NAND_DENALI_PCI |
63 | help | 77 | help |
64 | Some platforms place the NAND chip size in a scratch register | 78 | Some platforms place the NAND chip size in a scratch register |
65 | because (some versions of) the driver aren't able to automatically | 79 | because (some versions of) the driver aren't able to automatically |
@@ -433,6 +447,14 @@ config MTD_NAND_GPMI_NAND | |||
433 | block, such as SD card. So pay attention to it when you enable | 447 | block, such as SD card. So pay attention to it when you enable |
434 | the GPMI. | 448 | the GPMI. |
435 | 449 | ||
450 | config MTD_NAND_BCM47XXNFLASH | ||
451 | tristate "Support for NAND flash on BCM4706 BCMA bus" | ||
452 | depends on BCMA_NFLASH | ||
453 | help | ||
454 | BCMA bus can have various flash memories attached, they are | ||
455 | registered by bcma as platform devices. This enables driver for | ||
456 | NAND flash memories. For now only BCM4706 is supported. | ||
457 | |||
436 | config MTD_NAND_PLATFORM | 458 | config MTD_NAND_PLATFORM |
437 | tristate "Support for generic platform NAND driver" | 459 | tristate "Support for generic platform NAND driver" |
438 | depends on HAS_IOMEM | 460 | depends on HAS_IOMEM |
@@ -499,12 +521,6 @@ config MTD_NAND_MXC | |||
499 | This enables the driver for the NAND flash controller on the | 521 | This enables the driver for the NAND flash controller on the |
500 | MXC processors. | 522 | MXC processors. |
501 | 523 | ||
502 | config MTD_NAND_NOMADIK | ||
503 | tristate "ST Nomadik 8815 NAND support" | ||
504 | depends on ARCH_NOMADIK | ||
505 | help | ||
506 | Driver for the NAND flash controller on the Nomadik, with ECC. | ||
507 | |||
508 | config MTD_NAND_SH_FLCTL | 524 | config MTD_NAND_SH_FLCTL |
509 | tristate "Support for NAND on Renesas SuperH FLCTL" | 525 | tristate "Support for NAND on Renesas SuperH FLCTL" |
510 | depends on SUPERH || ARCH_SHMOBILE | 526 | depends on SUPERH || ARCH_SHMOBILE |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 6c7f2b3ca8ae..d76d91205691 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -11,6 +11,8 @@ obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o | |||
11 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o | 11 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o |
12 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o | 12 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o |
13 | obj-$(CONFIG_MTD_NAND_DENALI) += denali.o | 13 | obj-$(CONFIG_MTD_NAND_DENALI) += denali.o |
14 | obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o | ||
15 | obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o | ||
14 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o | 16 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o |
15 | obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o | 17 | obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o |
16 | obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o | 18 | obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o |
@@ -45,11 +47,11 @@ obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o | |||
45 | obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o | 47 | obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o |
46 | obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o | 48 | obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o |
47 | obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o | 49 | obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o |
48 | obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o | ||
49 | obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o | 50 | obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o |
50 | obj-$(CONFIG_MTD_NAND_RICOH) += r852.o | 51 | obj-$(CONFIG_MTD_NAND_RICOH) += r852.o |
51 | obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o | 52 | obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o |
52 | obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ | 53 | obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ |
53 | obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o | 54 | obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o |
55 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ | ||
54 | 56 | ||
55 | nand-objs := nand_base.o nand_bbt.o | 57 | nand-objs := nand_base.o nand_bbt.o |
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 9e7723aa7acc..f1d71cdc8aac 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c | |||
@@ -173,7 +173,7 @@ static const struct gpio _mandatory_gpio[] = { | |||
173 | /* | 173 | /* |
174 | * Main initialization routine | 174 | * Main initialization routine |
175 | */ | 175 | */ |
176 | static int __devinit ams_delta_init(struct platform_device *pdev) | 176 | static int ams_delta_init(struct platform_device *pdev) |
177 | { | 177 | { |
178 | struct nand_chip *this; | 178 | struct nand_chip *this; |
179 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 179 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -270,7 +270,7 @@ out_free: | |||
270 | /* | 270 | /* |
271 | * Clean up routine | 271 | * Clean up routine |
272 | */ | 272 | */ |
273 | static int __devexit ams_delta_cleanup(struct platform_device *pdev) | 273 | static int ams_delta_cleanup(struct platform_device *pdev) |
274 | { | 274 | { |
275 | void __iomem *io_base = platform_get_drvdata(pdev); | 275 | void __iomem *io_base = platform_get_drvdata(pdev); |
276 | 276 | ||
@@ -289,7 +289,7 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev) | |||
289 | 289 | ||
290 | static struct platform_driver ams_delta_nand_driver = { | 290 | static struct platform_driver ams_delta_nand_driver = { |
291 | .probe = ams_delta_init, | 291 | .probe = ams_delta_init, |
292 | .remove = __devexit_p(ams_delta_cleanup), | 292 | .remove = ams_delta_cleanup, |
293 | .driver = { | 293 | .driver = { |
294 | .name = "ams-delta-nand", | 294 | .name = "ams-delta-nand", |
295 | .owner = THIS_MODULE, | 295 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 92623ac2015a..90bdca61c797 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -331,13 +331,13 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
331 | * 12-bits 20-bytes 21-bytes | 331 | * 12-bits 20-bytes 21-bytes |
332 | * 24-bits 39-bytes 42-bytes | 332 | * 24-bits 39-bytes 42-bytes |
333 | */ | 333 | */ |
334 | static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size) | 334 | static int pmecc_get_ecc_bytes(int cap, int sector_size) |
335 | { | 335 | { |
336 | int m = 12 + sector_size / 512; | 336 | int m = 12 + sector_size / 512; |
337 | return (m * cap + 7) / 8; | 337 | return (m * cap + 7) / 8; |
338 | } | 338 | } |
339 | 339 | ||
340 | static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, | 340 | static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, |
341 | int oobsize, int ecc_len) | 341 | int oobsize, int ecc_len) |
342 | { | 342 | { |
343 | int i; | 343 | int i; |
@@ -353,7 +353,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, | |||
353 | oobsize - ecc_len - layout->oobfree[0].offset; | 353 | oobsize - ecc_len - layout->oobfree[0].offset; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) | 356 | static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) |
357 | { | 357 | { |
358 | int table_size; | 358 | int table_size; |
359 | 359 | ||
@@ -375,7 +375,7 @@ static void pmecc_data_free(struct atmel_nand_host *host) | |||
375 | kfree(host->pmecc_delta); | 375 | kfree(host->pmecc_delta); |
376 | } | 376 | } |
377 | 377 | ||
378 | static int __devinit pmecc_data_alloc(struct atmel_nand_host *host) | 378 | static int pmecc_data_alloc(struct atmel_nand_host *host) |
379 | { | 379 | { |
380 | const int cap = host->pmecc_corr_cap; | 380 | const int cap = host->pmecc_corr_cap; |
381 | 381 | ||
@@ -724,6 +724,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, | |||
724 | struct atmel_nand_host *host = nand_chip->priv; | 724 | struct atmel_nand_host *host = nand_chip->priv; |
725 | int i, err_nbr, eccbytes; | 725 | int i, err_nbr, eccbytes; |
726 | uint8_t *buf_pos; | 726 | uint8_t *buf_pos; |
727 | int total_err = 0; | ||
727 | 728 | ||
728 | eccbytes = nand_chip->ecc.bytes; | 729 | eccbytes = nand_chip->ecc.bytes; |
729 | for (i = 0; i < eccbytes; i++) | 730 | for (i = 0; i < eccbytes; i++) |
@@ -751,12 +752,13 @@ normal_check: | |||
751 | pmecc_correct_data(mtd, buf_pos, ecc, i, | 752 | pmecc_correct_data(mtd, buf_pos, ecc, i, |
752 | host->pmecc_bytes_per_sector, err_nbr); | 753 | host->pmecc_bytes_per_sector, err_nbr); |
753 | mtd->ecc_stats.corrected += err_nbr; | 754 | mtd->ecc_stats.corrected += err_nbr; |
755 | total_err += err_nbr; | ||
754 | } | 756 | } |
755 | } | 757 | } |
756 | pmecc_stat >>= 1; | 758 | pmecc_stat >>= 1; |
757 | } | 759 | } |
758 | 760 | ||
759 | return 0; | 761 | return total_err; |
760 | } | 762 | } |
761 | 763 | ||
762 | static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | 764 | static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, |
@@ -768,6 +770,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
768 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 770 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
769 | uint32_t stat; | 771 | uint32_t stat; |
770 | unsigned long end_time; | 772 | unsigned long end_time; |
773 | int bitflips = 0; | ||
771 | 774 | ||
772 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); | 775 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); |
773 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); | 776 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); |
@@ -790,11 +793,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
790 | } | 793 | } |
791 | 794 | ||
792 | stat = pmecc_readl_relaxed(host->ecc, ISR); | 795 | stat = pmecc_readl_relaxed(host->ecc, ISR); |
793 | if (stat != 0) | 796 | if (stat != 0) { |
794 | if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) | 797 | bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]); |
795 | return -EIO; | 798 | if (bitflips < 0) |
799 | /* uncorrectable errors */ | ||
800 | return 0; | ||
801 | } | ||
796 | 802 | ||
797 | return 0; | 803 | return bitflips; |
798 | } | 804 | } |
799 | 805 | ||
800 | static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, | 806 | static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, |
@@ -1206,7 +1212,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) | |||
1206 | } | 1212 | } |
1207 | 1213 | ||
1208 | #if defined(CONFIG_OF) | 1214 | #if defined(CONFIG_OF) |
1209 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | 1215 | static int atmel_of_init_port(struct atmel_nand_host *host, |
1210 | struct device_node *np) | 1216 | struct device_node *np) |
1211 | { | 1217 | { |
1212 | u32 val, table_offset; | 1218 | u32 val, table_offset; |
@@ -1293,7 +1299,7 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | |||
1293 | return 0; | 1299 | return 0; |
1294 | } | 1300 | } |
1295 | #else | 1301 | #else |
1296 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | 1302 | static int atmel_of_init_port(struct atmel_nand_host *host, |
1297 | struct device_node *np) | 1303 | struct device_node *np) |
1298 | { | 1304 | { |
1299 | return -EINVAL; | 1305 | return -EINVAL; |
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 5c47b200045a..217459d02b2f 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -382,7 +382,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i | |||
382 | while(!this->dev_ready(mtd)); | 382 | while(!this->dev_ready(mtd)); |
383 | } | 383 | } |
384 | 384 | ||
385 | static int __devinit find_nand_cs(unsigned long nand_base) | 385 | static int find_nand_cs(unsigned long nand_base) |
386 | { | 386 | { |
387 | void __iomem *base = | 387 | void __iomem *base = |
388 | (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR); | 388 | (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR); |
@@ -403,7 +403,7 @@ static int __devinit find_nand_cs(unsigned long nand_base) | |||
403 | return -ENODEV; | 403 | return -ENODEV; |
404 | } | 404 | } |
405 | 405 | ||
406 | static int __devinit au1550nd_probe(struct platform_device *pdev) | 406 | static int au1550nd_probe(struct platform_device *pdev) |
407 | { | 407 | { |
408 | struct au1550nd_platdata *pd; | 408 | struct au1550nd_platdata *pd; |
409 | struct au1550nd_ctx *ctx; | 409 | struct au1550nd_ctx *ctx; |
@@ -491,7 +491,7 @@ out1: | |||
491 | return ret; | 491 | return ret; |
492 | } | 492 | } |
493 | 493 | ||
494 | static int __devexit au1550nd_remove(struct platform_device *pdev) | 494 | static int au1550nd_remove(struct platform_device *pdev) |
495 | { | 495 | { |
496 | struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); | 496 | struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); |
497 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 497 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -509,7 +509,7 @@ static struct platform_driver au1550nd_driver = { | |||
509 | .owner = THIS_MODULE, | 509 | .owner = THIS_MODULE, |
510 | }, | 510 | }, |
511 | .probe = au1550nd_probe, | 511 | .probe = au1550nd_probe, |
512 | .remove = __devexit_p(au1550nd_remove), | 512 | .remove = au1550nd_remove, |
513 | }; | 513 | }; |
514 | 514 | ||
515 | module_platform_driver(au1550nd_driver); | 515 | module_platform_driver(au1550nd_driver); |
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile new file mode 100644 index 000000000000..f05b119e134b --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | bcm47xxnflash-y += main.o | ||
2 | bcm47xxnflash-y += ops_bcm4706.o | ||
3 | |||
4 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o | ||
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h new file mode 100644 index 000000000000..0bdb2ce4da75 --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef __BCM47XXNFLASH_H | ||
2 | #define __BCM47XXNFLASH_H | ||
3 | |||
4 | #include <linux/mtd/mtd.h> | ||
5 | #include <linux/mtd/nand.h> | ||
6 | |||
7 | struct bcm47xxnflash { | ||
8 | struct bcma_drv_cc *cc; | ||
9 | |||
10 | struct nand_chip nand_chip; | ||
11 | struct mtd_info mtd; | ||
12 | |||
13 | unsigned curr_command; | ||
14 | int curr_page_addr; | ||
15 | int curr_column; | ||
16 | |||
17 | u8 id_data[8]; | ||
18 | }; | ||
19 | |||
20 | int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n); | ||
21 | |||
22 | #endif /* BCM47XXNFLASH */ | ||
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c new file mode 100644 index 000000000000..2b8b05bec3dd --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/main.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * BCM47XX NAND flash driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/bcma/bcma.h> | ||
17 | |||
18 | #include "bcm47xxnflash.h" | ||
19 | |||
20 | MODULE_DESCRIPTION("NAND flash driver for BCMA bus"); | ||
21 | MODULE_LICENSE("GPL"); | ||
22 | MODULE_AUTHOR("Rafał Miłecki"); | ||
23 | |||
24 | static const char *probes[] = { "bcm47xxpart", NULL }; | ||
25 | |||
26 | static int bcm47xxnflash_probe(struct platform_device *pdev) | ||
27 | { | ||
28 | struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); | ||
29 | struct bcm47xxnflash *b47n; | ||
30 | int err = 0; | ||
31 | |||
32 | b47n = kzalloc(sizeof(*b47n), GFP_KERNEL); | ||
33 | if (!b47n) { | ||
34 | err = -ENOMEM; | ||
35 | goto out; | ||
36 | } | ||
37 | |||
38 | b47n->nand_chip.priv = b47n; | ||
39 | b47n->mtd.owner = THIS_MODULE; | ||
40 | b47n->mtd.priv = &b47n->nand_chip; /* Required */ | ||
41 | b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); | ||
42 | |||
43 | if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { | ||
44 | err = bcm47xxnflash_ops_bcm4706_init(b47n); | ||
45 | } else { | ||
46 | pr_err("Device not supported\n"); | ||
47 | err = -ENOTSUPP; | ||
48 | } | ||
49 | if (err) { | ||
50 | pr_err("Initialization failed: %d\n", err); | ||
51 | goto err_init; | ||
52 | } | ||
53 | |||
54 | err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0); | ||
55 | if (err) { | ||
56 | pr_err("Failed to register MTD device: %d\n", err); | ||
57 | goto err_dev_reg; | ||
58 | } | ||
59 | |||
60 | return 0; | ||
61 | |||
62 | err_dev_reg: | ||
63 | err_init: | ||
64 | kfree(b47n); | ||
65 | out: | ||
66 | return err; | ||
67 | } | ||
68 | |||
69 | static int __devexit bcm47xxnflash_remove(struct platform_device *pdev) | ||
70 | { | ||
71 | struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); | ||
72 | |||
73 | if (nflash->mtd) | ||
74 | mtd_device_unregister(nflash->mtd); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static struct platform_driver bcm47xxnflash_driver = { | ||
80 | .remove = __devexit_p(bcm47xxnflash_remove), | ||
81 | .driver = { | ||
82 | .name = "bcma_nflash", | ||
83 | .owner = THIS_MODULE, | ||
84 | }, | ||
85 | }; | ||
86 | |||
87 | static int __init bcm47xxnflash_init(void) | ||
88 | { | ||
89 | int err; | ||
90 | |||
91 | /* | ||
92 | * Platform device "bcma_nflash" exists on SoCs and is registered very | ||
93 | * early, it won't be added during runtime (use platform_driver_probe). | ||
94 | */ | ||
95 | err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe); | ||
96 | if (err) | ||
97 | pr_err("Failed to register serial flash driver: %d\n", err); | ||
98 | |||
99 | return err; | ||
100 | } | ||
101 | |||
102 | static void __exit bcm47xxnflash_exit(void) | ||
103 | { | ||
104 | platform_driver_unregister(&bcm47xxnflash_driver); | ||
105 | } | ||
106 | |||
107 | module_init(bcm47xxnflash_init); | ||
108 | module_exit(bcm47xxnflash_exit); | ||
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c new file mode 100644 index 000000000000..86c9a79b89b3 --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * BCM47XX NAND flash driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/bcma/bcma.h> | ||
16 | |||
17 | #include "bcm47xxnflash.h" | ||
18 | |||
19 | /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has | ||
20 | * shown 164 retries as maxiumum. */ | ||
21 | #define NFLASH_READY_RETRIES 1000 | ||
22 | |||
23 | #define NFLASH_SECTOR_SIZE 512 | ||
24 | |||
25 | #define NCTL_CMD0 0x00010000 | ||
26 | #define NCTL_CMD1W 0x00080000 | ||
27 | #define NCTL_READ 0x00100000 | ||
28 | #define NCTL_WRITE 0x00200000 | ||
29 | #define NCTL_SPECADDR 0x01000000 | ||
30 | #define NCTL_READY 0x04000000 | ||
31 | #define NCTL_ERR 0x08000000 | ||
32 | #define NCTL_CSA 0x40000000 | ||
33 | #define NCTL_START 0x80000000 | ||
34 | |||
35 | /************************************************** | ||
36 | * Various helpers | ||
37 | **************************************************/ | ||
38 | |||
39 | static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock) | ||
40 | { | ||
41 | return ((ns * 1000 * clock) / 1000000) + 1; | ||
42 | } | ||
43 | |||
44 | static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) | ||
45 | { | ||
46 | int i = 0; | ||
47 | |||
48 | bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code); | ||
49 | for (i = 0; i < NFLASH_READY_RETRIES; i++) { | ||
50 | if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) { | ||
51 | i = 0; | ||
52 | break; | ||
53 | } | ||
54 | } | ||
55 | if (i) { | ||
56 | pr_err("NFLASH control command not ready!\n"); | ||
57 | return -EBUSY; | ||
58 | } | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc) | ||
63 | { | ||
64 | int i; | ||
65 | |||
66 | for (i = 0; i < NFLASH_READY_RETRIES; i++) { | ||
67 | if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) { | ||
68 | if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & | ||
69 | BCMA_CC_NFLASH_CTL_ERR) { | ||
70 | pr_err("Error on polling\n"); | ||
71 | return -EBUSY; | ||
72 | } else { | ||
73 | return 0; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | pr_err("Polling timeout!\n"); | ||
79 | return -EBUSY; | ||
80 | } | ||
81 | |||
82 | /************************************************** | ||
83 | * R/W | ||
84 | **************************************************/ | ||
85 | |||
86 | static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, | ||
87 | int len) | ||
88 | { | ||
89 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
90 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
91 | |||
92 | u32 ctlcode; | ||
93 | u32 *dest = (u32 *)buf; | ||
94 | int i; | ||
95 | int toread; | ||
96 | |||
97 | BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); | ||
98 | /* Don't validate column using nand_chip->page_shift, it may be bigger | ||
99 | * when accessing OOB */ | ||
100 | |||
101 | while (len) { | ||
102 | /* We can read maximum of 0x200 bytes at once */ | ||
103 | toread = min(len, 0x200); | ||
104 | |||
105 | /* Set page and column */ | ||
106 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR, | ||
107 | b47n->curr_column); | ||
108 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR, | ||
109 | b47n->curr_page_addr); | ||
110 | |||
111 | /* Prepare to read */ | ||
112 | ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 | | ||
113 | NCTL_CMD0; | ||
114 | ctlcode |= NAND_CMD_READSTART << 8; | ||
115 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) | ||
116 | return; | ||
117 | if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc)) | ||
118 | return; | ||
119 | |||
120 | /* Eventually read some data :) */ | ||
121 | for (i = 0; i < toread; i += 4, dest++) { | ||
122 | ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ; | ||
123 | if (i == toread - 4) /* Last read goes without that */ | ||
124 | ctlcode &= ~NCTL_CSA; | ||
125 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, | ||
126 | ctlcode)) | ||
127 | return; | ||
128 | *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA); | ||
129 | } | ||
130 | |||
131 | b47n->curr_column += toread; | ||
132 | len -= toread; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, | ||
137 | const uint8_t *buf, int len) | ||
138 | { | ||
139 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
140 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
141 | struct bcma_drv_cc *cc = b47n->cc; | ||
142 | |||
143 | u32 ctlcode; | ||
144 | const u32 *data = (u32 *)buf; | ||
145 | int i; | ||
146 | |||
147 | BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); | ||
148 | /* Don't validate column using nand_chip->page_shift, it may be bigger | ||
149 | * when accessing OOB */ | ||
150 | |||
151 | for (i = 0; i < len; i += 4, data++) { | ||
152 | bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); | ||
153 | |||
154 | ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; | ||
155 | if (i == len - 4) /* Last read goes without that */ | ||
156 | ctlcode &= ~NCTL_CSA; | ||
157 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { | ||
158 | pr_err("%s ctl_cmd didn't work!\n", __func__); | ||
159 | return; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | b47n->curr_column += len; | ||
164 | } | ||
165 | |||
166 | /************************************************** | ||
167 | * NAND chip ops | ||
168 | **************************************************/ | ||
169 | |||
170 | /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ | ||
171 | static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, | ||
172 | int chip) | ||
173 | { | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. | ||
179 | * For example, reading chip id is performed in a non-standard way. | ||
180 | * Setting column and page is also handled differently, we use a special | ||
181 | * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert | ||
182 | * standard commands would be much more complicated. | ||
183 | */ | ||
184 | static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, | ||
185 | unsigned command, int column, | ||
186 | int page_addr) | ||
187 | { | ||
188 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
189 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
190 | struct bcma_drv_cc *cc = b47n->cc; | ||
191 | u32 ctlcode; | ||
192 | int i; | ||
193 | |||
194 | if (column != -1) | ||
195 | b47n->curr_column = column; | ||
196 | if (page_addr != -1) | ||
197 | b47n->curr_page_addr = page_addr; | ||
198 | |||
199 | switch (command) { | ||
200 | case NAND_CMD_RESET: | ||
201 | pr_warn("Chip reset not implemented yet\n"); | ||
202 | break; | ||
203 | case NAND_CMD_READID: | ||
204 | ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; | ||
205 | ctlcode |= NAND_CMD_READID; | ||
206 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { | ||
207 | pr_err("READID error\n"); | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Reading is specific, last one has to go without NCTL_CSA | ||
213 | * bit. We don't know how many reads NAND subsystem is going | ||
214 | * to perform, so cache everything. | ||
215 | */ | ||
216 | for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) { | ||
217 | ctlcode = NCTL_CSA | NCTL_READ; | ||
218 | if (i == ARRAY_SIZE(b47n->id_data) - 1) | ||
219 | ctlcode &= ~NCTL_CSA; | ||
220 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, | ||
221 | ctlcode)) { | ||
222 | pr_err("READID error\n"); | ||
223 | break; | ||
224 | } | ||
225 | b47n->id_data[i] = | ||
226 | bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA) | ||
227 | & 0xFF; | ||
228 | } | ||
229 | |||
230 | break; | ||
231 | case NAND_CMD_STATUS: | ||
232 | ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS; | ||
233 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) | ||
234 | pr_err("STATUS command error\n"); | ||
235 | break; | ||
236 | case NAND_CMD_READ0: | ||
237 | break; | ||
238 | case NAND_CMD_READOOB: | ||
239 | if (page_addr != -1) | ||
240 | b47n->curr_column += mtd->writesize; | ||
241 | break; | ||
242 | case NAND_CMD_ERASE1: | ||
243 | bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, | ||
244 | b47n->curr_page_addr); | ||
245 | ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | | ||
246 | NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); | ||
247 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) | ||
248 | pr_err("ERASE1 failed\n"); | ||
249 | break; | ||
250 | case NAND_CMD_ERASE2: | ||
251 | break; | ||
252 | case NAND_CMD_SEQIN: | ||
253 | /* Set page and column */ | ||
254 | bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, | ||
255 | b47n->curr_column); | ||
256 | bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, | ||
257 | b47n->curr_page_addr); | ||
258 | |||
259 | /* Prepare to write */ | ||
260 | ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; | ||
261 | ctlcode |= NAND_CMD_SEQIN; | ||
262 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) | ||
263 | pr_err("SEQIN failed\n"); | ||
264 | break; | ||
265 | case NAND_CMD_PAGEPROG: | ||
266 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | | ||
267 | NAND_CMD_PAGEPROG)) | ||
268 | pr_err("PAGEPROG failed\n"); | ||
269 | if (bcm47xxnflash_ops_bcm4706_poll(cc)) | ||
270 | pr_err("PAGEPROG not ready\n"); | ||
271 | break; | ||
272 | default: | ||
273 | pr_err("Command 0x%X unsupported\n", command); | ||
274 | break; | ||
275 | } | ||
276 | b47n->curr_command = command; | ||
277 | } | ||
278 | |||
279 | static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) | ||
280 | { | ||
281 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
282 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
283 | struct bcma_drv_cc *cc = b47n->cc; | ||
284 | u32 tmp = 0; | ||
285 | |||
286 | switch (b47n->curr_command) { | ||
287 | case NAND_CMD_READID: | ||
288 | if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) { | ||
289 | pr_err("Requested invalid id_data: %d\n", | ||
290 | b47n->curr_column); | ||
291 | return 0; | ||
292 | } | ||
293 | return b47n->id_data[b47n->curr_column++]; | ||
294 | case NAND_CMD_STATUS: | ||
295 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ)) | ||
296 | return 0; | ||
297 | return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff; | ||
298 | case NAND_CMD_READOOB: | ||
299 | bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4); | ||
300 | return tmp & 0xFF; | ||
301 | } | ||
302 | |||
303 | pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, | ||
308 | uint8_t *buf, int len) | ||
309 | { | ||
310 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
311 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
312 | |||
313 | switch (b47n->curr_command) { | ||
314 | case NAND_CMD_READ0: | ||
315 | case NAND_CMD_READOOB: | ||
316 | bcm47xxnflash_ops_bcm4706_read(mtd, buf, len); | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); | ||
321 | } | ||
322 | |||
323 | static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, | ||
324 | const uint8_t *buf, int len) | ||
325 | { | ||
326 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
327 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
328 | |||
329 | switch (b47n->curr_command) { | ||
330 | case NAND_CMD_SEQIN: | ||
331 | bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command); | ||
336 | } | ||
337 | |||
338 | /************************************************** | ||
339 | * Init | ||
340 | **************************************************/ | ||
341 | |||
342 | int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) | ||
343 | { | ||
344 | int err; | ||
345 | u32 freq; | ||
346 | u16 clock; | ||
347 | u8 w0, w1, w2, w3, w4; | ||
348 | |||
349 | unsigned long chipsize; /* MiB */ | ||
350 | u8 tbits, col_bits, col_size, row_bits, row_bsize; | ||
351 | u32 val; | ||
352 | |||
353 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; | ||
354 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; | ||
355 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; | ||
356 | b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; | ||
357 | b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; | ||
358 | b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; | ||
359 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ | ||
360 | |||
361 | /* Enable NAND flash access */ | ||
362 | bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG, | ||
363 | BCMA_CC_4706_FLASHSCFG_NF1); | ||
364 | |||
365 | /* Configure wait counters */ | ||
366 | if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { | ||
367 | freq = 100000000; | ||
368 | } else { | ||
369 | freq = bcma_chipco_pll_read(b47n->cc, 4); | ||
370 | freq = (freq * 0xFFF) >> 3; | ||
371 | freq = (freq * 25000000) >> 3; | ||
372 | } | ||
373 | clock = freq / 1000000; | ||
374 | w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); | ||
375 | w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock); | ||
376 | w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); | ||
377 | w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); | ||
378 | w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock); | ||
379 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0, | ||
380 | (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0)); | ||
381 | |||
382 | /* Scan NAND */ | ||
383 | err = nand_scan(&b47n->mtd, 1); | ||
384 | if (err) { | ||
385 | pr_err("Could not scan NAND flash: %d\n", err); | ||
386 | goto exit; | ||
387 | } | ||
388 | |||
389 | /* Configure FLASH */ | ||
390 | chipsize = b47n->nand_chip.chipsize >> 20; | ||
391 | tbits = ffs(chipsize); /* find first bit set */ | ||
392 | if (!tbits || tbits != fls(chipsize)) { | ||
393 | pr_err("Invalid flash size: 0x%lX\n", chipsize); | ||
394 | err = -ENOTSUPP; | ||
395 | goto exit; | ||
396 | } | ||
397 | tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */ | ||
398 | |||
399 | col_bits = b47n->nand_chip.page_shift + 1; | ||
400 | col_size = (col_bits + 7) / 8; | ||
401 | |||
402 | row_bits = tbits - col_bits + 1; | ||
403 | row_bsize = (row_bits + 7) / 8; | ||
404 | |||
405 | val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2; | ||
406 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val); | ||
407 | |||
408 | exit: | ||
409 | if (err) | ||
410 | bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG, | ||
411 | ~BCMA_CC_4706_FLASHSCFG_NF1); | ||
412 | return err; | ||
413 | } | ||
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index ab0caa74eb43..4271e948d1e2 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
@@ -658,7 +658,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) | |||
658 | /* | 658 | /* |
659 | * Device management interface | 659 | * Device management interface |
660 | */ | 660 | */ |
661 | static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info) | 661 | static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) |
662 | { | 662 | { |
663 | struct mtd_info *mtd = &info->mtd; | 663 | struct mtd_info *mtd = &info->mtd; |
664 | struct mtd_partition *parts = info->platform->partitions; | 664 | struct mtd_partition *parts = info->platform->partitions; |
@@ -667,7 +667,7 @@ static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info) | |||
667 | return mtd_device_register(mtd, parts, nr); | 667 | return mtd_device_register(mtd, parts, nr); |
668 | } | 668 | } |
669 | 669 | ||
670 | static int __devexit bf5xx_nand_remove(struct platform_device *pdev) | 670 | static int bf5xx_nand_remove(struct platform_device *pdev) |
671 | { | 671 | { |
672 | struct bf5xx_nand_info *info = to_nand_info(pdev); | 672 | struct bf5xx_nand_info *info = to_nand_info(pdev); |
673 | 673 | ||
@@ -725,7 +725,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd) | |||
725 | * it can allocate all necessary resources then calls the | 725 | * it can allocate all necessary resources then calls the |
726 | * nand layer to look for devices | 726 | * nand layer to look for devices |
727 | */ | 727 | */ |
728 | static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | 728 | static int bf5xx_nand_probe(struct platform_device *pdev) |
729 | { | 729 | { |
730 | struct bf5xx_nand_platform *plat = to_nand_plat(pdev); | 730 | struct bf5xx_nand_platform *plat = to_nand_plat(pdev); |
731 | struct bf5xx_nand_info *info = NULL; | 731 | struct bf5xx_nand_info *info = NULL; |
@@ -865,7 +865,7 @@ static int bf5xx_nand_resume(struct platform_device *dev) | |||
865 | /* driver device registration */ | 865 | /* driver device registration */ |
866 | static struct platform_driver bf5xx_nand_driver = { | 866 | static struct platform_driver bf5xx_nand_driver = { |
867 | .probe = bf5xx_nand_probe, | 867 | .probe = bf5xx_nand_probe, |
868 | .remove = __devexit_p(bf5xx_nand_remove), | 868 | .remove = bf5xx_nand_remove, |
869 | .suspend = bf5xx_nand_suspend, | 869 | .suspend = bf5xx_nand_suspend, |
870 | .resume = bf5xx_nand_resume, | 870 | .resume = bf5xx_nand_resume, |
871 | .driver = { | 871 | .driver = { |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2bb7170502c2..010d61266536 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
@@ -585,7 +585,7 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
585 | } | 585 | } |
586 | 586 | ||
587 | /* F_2[X]/(X**6+X+1) */ | 587 | /* F_2[X]/(X**6+X+1) */ |
588 | static unsigned short __devinit gf64_mul(u8 a, u8 b) | 588 | static unsigned short gf64_mul(u8 a, u8 b) |
589 | { | 589 | { |
590 | u8 c; | 590 | u8 c; |
591 | unsigned int i; | 591 | unsigned int i; |
@@ -604,7 +604,7 @@ static unsigned short __devinit gf64_mul(u8 a, u8 b) | |||
604 | } | 604 | } |
605 | 605 | ||
606 | /* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X] */ | 606 | /* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X] */ |
607 | static u16 __devinit gf4096_mul(u16 a, u16 b) | 607 | static u16 gf4096_mul(u16 a, u16 b) |
608 | { | 608 | { |
609 | u8 ah, al, bh, bl, ch, cl; | 609 | u8 ah, al, bh, bl, ch, cl; |
610 | 610 | ||
@@ -619,14 +619,14 @@ static u16 __devinit gf4096_mul(u16 a, u16 b) | |||
619 | return (ch << 6) ^ cl; | 619 | return (ch << 6) ^ cl; |
620 | } | 620 | } |
621 | 621 | ||
622 | static int __devinit cafe_mul(int x) | 622 | static int cafe_mul(int x) |
623 | { | 623 | { |
624 | if (x == 0) | 624 | if (x == 0) |
625 | return 1; | 625 | return 1; |
626 | return gf4096_mul(x, 0xe01); | 626 | return gf4096_mul(x, 0xe01); |
627 | } | 627 | } |
628 | 628 | ||
629 | static int __devinit cafe_nand_probe(struct pci_dev *pdev, | 629 | static int cafe_nand_probe(struct pci_dev *pdev, |
630 | const struct pci_device_id *ent) | 630 | const struct pci_device_id *ent) |
631 | { | 631 | { |
632 | struct mtd_info *mtd; | 632 | struct mtd_info *mtd; |
@@ -821,7 +821,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
821 | return err; | 821 | return err; |
822 | } | 822 | } |
823 | 823 | ||
824 | static void __devexit cafe_nand_remove(struct pci_dev *pdev) | 824 | static void cafe_nand_remove(struct pci_dev *pdev) |
825 | { | 825 | { |
826 | struct mtd_info *mtd = pci_get_drvdata(pdev); | 826 | struct mtd_info *mtd = pci_get_drvdata(pdev); |
827 | struct cafe_priv *cafe = mtd->priv; | 827 | struct cafe_priv *cafe = mtd->priv; |
@@ -887,7 +887,7 @@ static struct pci_driver cafe_nand_pci_driver = { | |||
887 | .name = "CAFÉ NAND", | 887 | .name = "CAFÉ NAND", |
888 | .id_table = cafe_nand_tbl, | 888 | .id_table = cafe_nand_tbl, |
889 | .probe = cafe_nand_probe, | 889 | .probe = cafe_nand_probe, |
890 | .remove = __devexit_p(cafe_nand_remove), | 890 | .remove = cafe_nand_remove, |
891 | .resume = cafe_nand_resume, | 891 | .resume = cafe_nand_resume, |
892 | }; | 892 | }; |
893 | 893 | ||
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index adb6c3ef37fb..2cdeab8bebc4 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c | |||
@@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) | |||
237 | this->ecc.hwctl = cs_enable_hwecc; | 237 | this->ecc.hwctl = cs_enable_hwecc; |
238 | this->ecc.calculate = cs_calculate_ecc; | 238 | this->ecc.calculate = cs_calculate_ecc; |
239 | this->ecc.correct = nand_correct_data; | 239 | this->ecc.correct = nand_correct_data; |
240 | this->ecc.strength = 1; | ||
240 | 241 | ||
241 | /* Enable the following for a flash based bad block table */ | 242 | /* Enable the following for a flash based bad block table */ |
242 | this->bbt_options = NAND_BBT_USE_FLASH; | 243 | this->bbt_options = NAND_BBT_USE_FLASH; |
@@ -247,8 +248,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) | |||
247 | goto out_ior; | 248 | goto out_ior; |
248 | } | 249 | } |
249 | 250 | ||
250 | this->ecc.strength = 1; | ||
251 | |||
252 | new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); | 251 | new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); |
253 | 252 | ||
254 | cs553x_mtd[cs] = new_mtd; | 253 | cs553x_mtd[cs] = new_mtd; |
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 945047ad0952..3502606f6480 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c | |||
@@ -821,9 +821,16 @@ syndrome_done: | |||
821 | if (ret < 0) | 821 | if (ret < 0) |
822 | goto err_scan; | 822 | goto err_scan; |
823 | 823 | ||
824 | ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, | 824 | if (pdata->parts) |
825 | pdata->nr_parts); | 825 | ret = mtd_device_parse_register(&info->mtd, NULL, NULL, |
826 | 826 | pdata->parts, pdata->nr_parts); | |
827 | else { | ||
828 | struct mtd_part_parser_data ppdata; | ||
829 | |||
830 | ppdata.of_node = pdev->dev.of_node; | ||
831 | ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata, | ||
832 | NULL, 0); | ||
833 | } | ||
827 | if (ret < 0) | 834 | if (ret < 0) |
828 | goto err_scan; | 835 | goto err_scan; |
829 | 836 | ||
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e706a237170f..0c8bb6bf8424 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c | |||
@@ -16,14 +16,12 @@ | |||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | |||
20 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
21 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
22 | #include <linux/dma-mapping.h> | 21 | #include <linux/dma-mapping.h> |
23 | #include <linux/wait.h> | 22 | #include <linux/wait.h> |
24 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <linux/pci.h> | ||
27 | #include <linux/mtd/mtd.h> | 25 | #include <linux/mtd/mtd.h> |
28 | #include <linux/module.h> | 26 | #include <linux/module.h> |
29 | 27 | ||
@@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." | |||
89 | * format the bank into the proper bits for the controller */ | 87 | * format the bank into the proper bits for the controller */ |
90 | #define BANK(x) ((x) << 24) | 88 | #define BANK(x) ((x) << 24) |
91 | 89 | ||
92 | /* List of platforms this NAND controller has be integrated into */ | ||
93 | static const struct pci_device_id denali_pci_ids[] = { | ||
94 | { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, | ||
95 | { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, | ||
96 | { /* end: all zeroes */ } | ||
97 | }; | ||
98 | |||
99 | /* forward declarations */ | 90 | /* forward declarations */ |
100 | static void clear_interrupts(struct denali_nand_info *denali); | 91 | static void clear_interrupts(struct denali_nand_info *denali); |
101 | static uint32_t wait_for_irq(struct denali_nand_info *denali, | 92 | 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) | |||
699 | 690 | ||
700 | if (comp_res == 0) { | 691 | if (comp_res == 0) { |
701 | /* timeout */ | 692 | /* timeout */ |
702 | printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n", | 693 | pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n", |
703 | intr_status, irq_mask); | 694 | intr_status, irq_mask); |
704 | 695 | ||
705 | intr_status = 0; | 696 | intr_status = 0; |
@@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, | |||
1305 | /* TODO: Read OOB data */ | 1296 | /* TODO: Read OOB data */ |
1306 | break; | 1297 | break; |
1307 | default: | 1298 | default: |
1308 | printk(KERN_ERR ": unsupported command" | 1299 | pr_err(": unsupported command received 0x%x\n", cmd); |
1309 | " received 0x%x\n", cmd); | ||
1310 | break; | 1300 | break; |
1311 | } | 1301 | } |
1312 | } | 1302 | } |
@@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali) | |||
1425 | denali->irq_status = 0; | 1415 | denali->irq_status = 0; |
1426 | } | 1416 | } |
1427 | 1417 | ||
1428 | /* driver entry point */ | 1418 | int denali_init(struct denali_nand_info *denali) |
1429 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
1430 | { | 1419 | { |
1431 | int ret = -ENODEV; | 1420 | int ret; |
1432 | resource_size_t csr_base, mem_base; | ||
1433 | unsigned long csr_len, mem_len; | ||
1434 | struct denali_nand_info *denali; | ||
1435 | |||
1436 | denali = kzalloc(sizeof(*denali), GFP_KERNEL); | ||
1437 | if (!denali) | ||
1438 | return -ENOMEM; | ||
1439 | 1421 | ||
1440 | ret = pci_enable_device(dev); | 1422 | if (denali->platform == INTEL_CE4100) { |
1441 | if (ret) { | ||
1442 | printk(KERN_ERR "Spectra: pci_enable_device failed.\n"); | ||
1443 | goto failed_alloc_memery; | ||
1444 | } | ||
1445 | |||
1446 | if (id->driver_data == INTEL_CE4100) { | ||
1447 | /* Due to a silicon limitation, we can only support | 1423 | /* Due to a silicon limitation, we can only support |
1448 | * ONFI timing mode 1 and below. | 1424 | * ONFI timing mode 1 and below. |
1449 | */ | 1425 | */ |
1450 | if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { | 1426 | if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { |
1451 | printk(KERN_ERR "Intel CE4100 only supports" | 1427 | pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); |
1452 | " ONFI timing mode 1 or below\n"); | 1428 | return -EINVAL; |
1453 | ret = -EINVAL; | ||
1454 | goto failed_enable_dev; | ||
1455 | } | ||
1456 | denali->platform = INTEL_CE4100; | ||
1457 | mem_base = pci_resource_start(dev, 0); | ||
1458 | mem_len = pci_resource_len(dev, 1); | ||
1459 | csr_base = pci_resource_start(dev, 1); | ||
1460 | csr_len = pci_resource_len(dev, 1); | ||
1461 | } else { | ||
1462 | denali->platform = INTEL_MRST; | ||
1463 | csr_base = pci_resource_start(dev, 0); | ||
1464 | csr_len = pci_resource_len(dev, 0); | ||
1465 | mem_base = pci_resource_start(dev, 1); | ||
1466 | mem_len = pci_resource_len(dev, 1); | ||
1467 | if (!mem_len) { | ||
1468 | mem_base = csr_base + csr_len; | ||
1469 | mem_len = csr_len; | ||
1470 | } | 1429 | } |
1471 | } | 1430 | } |
1472 | 1431 | ||
1473 | /* Is 32-bit DMA supported? */ | 1432 | /* Is 32-bit DMA supported? */ |
1474 | ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); | 1433 | ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); |
1475 | if (ret) { | 1434 | if (ret) { |
1476 | printk(KERN_ERR "Spectra: no usable DMA configuration\n"); | 1435 | pr_err("Spectra: no usable DMA configuration\n"); |
1477 | goto failed_enable_dev; | 1436 | return ret; |
1478 | } | 1437 | } |
1479 | denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf, | 1438 | denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, |
1480 | DENALI_BUF_SIZE, | 1439 | DENALI_BUF_SIZE, |
1481 | DMA_BIDIRECTIONAL); | 1440 | DMA_BIDIRECTIONAL); |
1482 | 1441 | ||
1483 | if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) { | 1442 | if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { |
1484 | dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n"); | 1443 | dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); |
1485 | goto failed_enable_dev; | 1444 | return -EIO; |
1486 | } | ||
1487 | |||
1488 | pci_set_master(dev); | ||
1489 | denali->dev = &dev->dev; | ||
1490 | denali->mtd.dev.parent = &dev->dev; | ||
1491 | |||
1492 | ret = pci_request_regions(dev, DENALI_NAND_NAME); | ||
1493 | if (ret) { | ||
1494 | printk(KERN_ERR "Spectra: Unable to request memory regions\n"); | ||
1495 | goto failed_dma_map; | ||
1496 | } | ||
1497 | |||
1498 | denali->flash_reg = ioremap_nocache(csr_base, csr_len); | ||
1499 | if (!denali->flash_reg) { | ||
1500 | printk(KERN_ERR "Spectra: Unable to remap memory region\n"); | ||
1501 | ret = -ENOMEM; | ||
1502 | goto failed_req_regions; | ||
1503 | } | ||
1504 | |||
1505 | denali->flash_mem = ioremap_nocache(mem_base, mem_len); | ||
1506 | if (!denali->flash_mem) { | ||
1507 | printk(KERN_ERR "Spectra: ioremap_nocache failed!"); | ||
1508 | ret = -ENOMEM; | ||
1509 | goto failed_remap_reg; | ||
1510 | } | 1445 | } |
1511 | 1446 | denali->mtd.dev.parent = denali->dev; | |
1512 | denali_hw_init(denali); | 1447 | denali_hw_init(denali); |
1513 | denali_drv_init(denali); | 1448 | denali_drv_init(denali); |
1514 | 1449 | ||
1515 | /* denali_isr register is done after all the hardware | 1450 | /* denali_isr register is done after all the hardware |
1516 | * initilization is finished*/ | 1451 | * initilization is finished*/ |
1517 | if (request_irq(dev->irq, denali_isr, IRQF_SHARED, | 1452 | if (request_irq(denali->irq, denali_isr, IRQF_SHARED, |
1518 | DENALI_NAND_NAME, denali)) { | 1453 | DENALI_NAND_NAME, denali)) { |
1519 | printk(KERN_ERR "Spectra: Unable to allocate IRQ\n"); | 1454 | pr_err("Spectra: Unable to allocate IRQ\n"); |
1520 | ret = -ENODEV; | 1455 | return -ENODEV; |
1521 | goto failed_remap_mem; | ||
1522 | } | 1456 | } |
1523 | 1457 | ||
1524 | /* now that our ISR is registered, we can enable interrupts */ | 1458 | /* now that our ISR is registered, we can enable interrupts */ |
1525 | denali_set_intr_modes(denali, true); | 1459 | denali_set_intr_modes(denali, true); |
1526 | |||
1527 | pci_set_drvdata(dev, denali); | ||
1528 | |||
1529 | denali->mtd.name = "denali-nand"; | 1460 | denali->mtd.name = "denali-nand"; |
1530 | denali->mtd.owner = THIS_MODULE; | 1461 | denali->mtd.owner = THIS_MODULE; |
1531 | denali->mtd.priv = &denali->nand; | 1462 | denali->mtd.priv = &denali->nand; |
@@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1549 | */ | 1480 | */ |
1550 | if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { | 1481 | if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { |
1551 | ret = -ENODEV; | 1482 | ret = -ENODEV; |
1552 | printk(KERN_ERR "Spectra: device size not supported by this " | 1483 | pr_err("Spectra: device size not supported by this version of MTD."); |
1553 | "version of MTD."); | ||
1554 | goto failed_req_irq; | 1484 | goto failed_req_irq; |
1555 | } | 1485 | } |
1556 | 1486 | ||
@@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1602 | } else if (denali->mtd.oobsize < (denali->bbtskipbytes + | 1532 | } else if (denali->mtd.oobsize < (denali->bbtskipbytes + |
1603 | ECC_8BITS * (denali->mtd.writesize / | 1533 | ECC_8BITS * (denali->mtd.writesize / |
1604 | ECC_SECTOR_SIZE))) { | 1534 | ECC_SECTOR_SIZE))) { |
1605 | printk(KERN_ERR "Your NAND chip OOB is not large enough to" | 1535 | pr_err("Your NAND chip OOB is not large enough to \ |
1606 | " contain 8bit ECC correction codes"); | 1536 | contain 8bit ECC correction codes"); |
1607 | goto failed_req_irq; | 1537 | goto failed_req_irq; |
1608 | } else { | 1538 | } else { |
1609 | denali->nand.ecc.strength = 8; | 1539 | denali->nand.ecc.strength = 8; |
@@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1655 | 1585 | ||
1656 | ret = mtd_device_register(&denali->mtd, NULL, 0); | 1586 | ret = mtd_device_register(&denali->mtd, NULL, 0); |
1657 | if (ret) { | 1587 | if (ret) { |
1658 | dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n", | 1588 | dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n", |
1659 | ret); | 1589 | ret); |
1660 | goto failed_req_irq; | 1590 | goto failed_req_irq; |
1661 | } | 1591 | } |
1662 | return 0; | 1592 | return 0; |
1663 | 1593 | ||
1664 | failed_req_irq: | 1594 | failed_req_irq: |
1665 | denali_irq_cleanup(dev->irq, denali); | 1595 | denali_irq_cleanup(denali->irq, denali); |
1666 | failed_remap_mem: | 1596 | |
1667 | iounmap(denali->flash_mem); | ||
1668 | failed_remap_reg: | ||
1669 | iounmap(denali->flash_reg); | ||
1670 | failed_req_regions: | ||
1671 | pci_release_regions(dev); | ||
1672 | failed_dma_map: | ||
1673 | dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, | ||
1674 | DMA_BIDIRECTIONAL); | ||
1675 | failed_enable_dev: | ||
1676 | pci_disable_device(dev); | ||
1677 | failed_alloc_memery: | ||
1678 | kfree(denali); | ||
1679 | return ret; | 1597 | return ret; |
1680 | } | 1598 | } |
1599 | EXPORT_SYMBOL(denali_init); | ||
1681 | 1600 | ||
1682 | /* driver exit point */ | 1601 | /* driver exit point */ |
1683 | static void denali_pci_remove(struct pci_dev *dev) | 1602 | void denali_remove(struct denali_nand_info *denali) |
1684 | { | 1603 | { |
1685 | struct denali_nand_info *denali = pci_get_drvdata(dev); | 1604 | denali_irq_cleanup(denali->irq, denali); |
1686 | 1605 | dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, | |
1687 | nand_release(&denali->mtd); | 1606 | DMA_BIDIRECTIONAL); |
1688 | |||
1689 | denali_irq_cleanup(dev->irq, denali); | ||
1690 | |||
1691 | iounmap(denali->flash_reg); | ||
1692 | iounmap(denali->flash_mem); | ||
1693 | pci_release_regions(dev); | ||
1694 | pci_disable_device(dev); | ||
1695 | dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, | ||
1696 | DMA_BIDIRECTIONAL); | ||
1697 | pci_set_drvdata(dev, NULL); | ||
1698 | kfree(denali); | ||
1699 | } | 1607 | } |
1700 | 1608 | EXPORT_SYMBOL(denali_remove); | |
1701 | MODULE_DEVICE_TABLE(pci, denali_pci_ids); | ||
1702 | |||
1703 | static struct pci_driver denali_pci_driver = { | ||
1704 | .name = DENALI_NAND_NAME, | ||
1705 | .id_table = denali_pci_ids, | ||
1706 | .probe = denali_pci_probe, | ||
1707 | .remove = denali_pci_remove, | ||
1708 | }; | ||
1709 | |||
1710 | module_pci_driver(denali_pci_driver); | ||
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index fabb9d56b39e..cec5712862c9 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h | |||
@@ -466,6 +466,7 @@ struct nand_buf { | |||
466 | 466 | ||
467 | #define INTEL_CE4100 1 | 467 | #define INTEL_CE4100 1 |
468 | #define INTEL_MRST 2 | 468 | #define INTEL_MRST 2 |
469 | #define DT 3 | ||
469 | 470 | ||
470 | struct denali_nand_info { | 471 | struct denali_nand_info { |
471 | struct mtd_info mtd; | 472 | struct mtd_info mtd; |
@@ -487,6 +488,7 @@ struct denali_nand_info { | |||
487 | uint32_t irq_status; | 488 | uint32_t irq_status; |
488 | int irq_debug_array[32]; | 489 | int irq_debug_array[32]; |
489 | int idx; | 490 | int idx; |
491 | int irq; | ||
490 | 492 | ||
491 | uint32_t devnum; /* represent how many nands connected */ | 493 | uint32_t devnum; /* represent how many nands connected */ |
492 | uint32_t fwblks; /* represent how many blocks FW used */ | 494 | uint32_t fwblks; /* represent how many blocks FW used */ |
@@ -496,4 +498,7 @@ struct denali_nand_info { | |||
496 | uint32_t max_banks; | 498 | uint32_t max_banks; |
497 | }; | 499 | }; |
498 | 500 | ||
501 | extern int denali_init(struct denali_nand_info *denali); | ||
502 | extern void denali_remove(struct denali_nand_info *denali); | ||
503 | |||
499 | #endif /*_LLD_NAND_*/ | 504 | #endif /*_LLD_NAND_*/ |
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c new file mode 100644 index 000000000000..546f8cb5688d --- /dev/null +++ b/drivers/mtd/nand/denali_dt.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * NAND Flash Controller Device Driver for DT | ||
3 | * | ||
4 | * Copyright © 2011, Picochip. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | */ | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include "denali.h" | ||
27 | |||
28 | struct denali_dt { | ||
29 | struct denali_nand_info denali; | ||
30 | struct clk *clk; | ||
31 | }; | ||
32 | |||
33 | static void __iomem *request_and_map(struct device *dev, | ||
34 | const struct resource *res) | ||
35 | { | ||
36 | void __iomem *ptr; | ||
37 | |||
38 | if (!devm_request_mem_region(dev, res->start, resource_size(res), | ||
39 | "denali-dt")) { | ||
40 | dev_err(dev, "unable to request %s\n", res->name); | ||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | ptr = devm_ioremap_nocache(dev, res->start, resource_size(res)); | ||
45 | if (!res) | ||
46 | dev_err(dev, "ioremap_nocache of %s failed!", res->name); | ||
47 | |||
48 | return ptr; | ||
49 | } | ||
50 | |||
51 | static const struct of_device_id denali_nand_dt_ids[] = { | ||
52 | { .compatible = "denali,denali-nand-dt" }, | ||
53 | { /* sentinel */ } | ||
54 | }; | ||
55 | |||
56 | MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); | ||
57 | |||
58 | static u64 denali_dma_mask; | ||
59 | |||
60 | static int denali_dt_probe(struct platform_device *ofdev) | ||
61 | { | ||
62 | struct resource *denali_reg, *nand_data; | ||
63 | struct denali_dt *dt; | ||
64 | struct denali_nand_info *denali; | ||
65 | int ret; | ||
66 | const struct of_device_id *of_id; | ||
67 | |||
68 | of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev); | ||
69 | if (of_id) { | ||
70 | ofdev->id_entry = of_id->data; | ||
71 | } else { | ||
72 | pr_err("Failed to find the right device id.\n"); | ||
73 | return -ENOMEM; | ||
74 | } | ||
75 | |||
76 | dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL); | ||
77 | if (!dt) | ||
78 | return -ENOMEM; | ||
79 | denali = &dt->denali; | ||
80 | |||
81 | denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg"); | ||
82 | nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data"); | ||
83 | if (!denali_reg || !nand_data) { | ||
84 | dev_err(&ofdev->dev, "resources not completely defined\n"); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | denali->platform = DT; | ||
89 | denali->dev = &ofdev->dev; | ||
90 | denali->irq = platform_get_irq(ofdev, 0); | ||
91 | if (denali->irq < 0) { | ||
92 | dev_err(&ofdev->dev, "no irq defined\n"); | ||
93 | return -ENXIO; | ||
94 | } | ||
95 | |||
96 | denali->flash_reg = request_and_map(&ofdev->dev, denali_reg); | ||
97 | if (!denali->flash_reg) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | denali->flash_mem = request_and_map(&ofdev->dev, nand_data); | ||
101 | if (!denali->flash_mem) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | if (!of_property_read_u32(ofdev->dev.of_node, | ||
105 | "dma-mask", (u32 *)&denali_dma_mask)) { | ||
106 | denali->dev->dma_mask = &denali_dma_mask; | ||
107 | } else { | ||
108 | denali->dev->dma_mask = NULL; | ||
109 | } | ||
110 | |||
111 | dt->clk = clk_get(&ofdev->dev, NULL); | ||
112 | if (IS_ERR(dt->clk)) { | ||
113 | dev_err(&ofdev->dev, "no clk available\n"); | ||
114 | return PTR_ERR(dt->clk); | ||
115 | } | ||
116 | clk_prepare_enable(dt->clk); | ||
117 | |||
118 | ret = denali_init(denali); | ||
119 | if (ret) | ||
120 | goto out_disable_clk; | ||
121 | |||
122 | platform_set_drvdata(ofdev, dt); | ||
123 | return 0; | ||
124 | |||
125 | out_disable_clk: | ||
126 | clk_disable_unprepare(dt->clk); | ||
127 | clk_put(dt->clk); | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | static int denali_dt_remove(struct platform_device *ofdev) | ||
133 | { | ||
134 | struct denali_dt *dt = platform_get_drvdata(ofdev); | ||
135 | |||
136 | denali_remove(&dt->denali); | ||
137 | clk_disable(dt->clk); | ||
138 | clk_put(dt->clk); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static struct platform_driver denali_dt_driver = { | ||
144 | .probe = denali_dt_probe, | ||
145 | .remove = denali_dt_remove, | ||
146 | .driver = { | ||
147 | .name = "denali-nand-dt", | ||
148 | .owner = THIS_MODULE, | ||
149 | .of_match_table = of_match_ptr(denali_nand_dt_ids), | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static int __init denali_init_dt(void) | ||
154 | { | ||
155 | return platform_driver_register(&denali_dt_driver); | ||
156 | } | ||
157 | module_init(denali_init_dt); | ||
158 | |||
159 | static void __exit denali_exit_dt(void) | ||
160 | { | ||
161 | platform_driver_unregister(&denali_dt_driver); | ||
162 | } | ||
163 | module_exit(denali_exit_dt); | ||
164 | |||
165 | MODULE_LICENSE("GPL"); | ||
166 | MODULE_AUTHOR("Jamie Iles"); | ||
167 | MODULE_DESCRIPTION("DT driver for Denali NAND controller"); | ||
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c new file mode 100644 index 000000000000..e3e46623b2b4 --- /dev/null +++ b/drivers/mtd/nand/denali_pci.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * NAND Flash Controller Device Driver | ||
3 | * Copyright © 2009-2010, Intel Corporation and its suppliers. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "denali.h" | ||
20 | |||
21 | #define DENALI_NAND_NAME "denali-nand-pci" | ||
22 | |||
23 | /* List of platforms this NAND controller has be integrated into */ | ||
24 | static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = { | ||
25 | { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, | ||
26 | { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, | ||
27 | { /* end: all zeroes */ } | ||
28 | }; | ||
29 | MODULE_DEVICE_TABLE(pci, denali_pci_ids); | ||
30 | |||
31 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
32 | { | ||
33 | int ret = -ENODEV; | ||
34 | resource_size_t csr_base, mem_base; | ||
35 | unsigned long csr_len, mem_len; | ||
36 | struct denali_nand_info *denali; | ||
37 | |||
38 | denali = kzalloc(sizeof(*denali), GFP_KERNEL); | ||
39 | if (!denali) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | ret = pci_enable_device(dev); | ||
43 | if (ret) { | ||
44 | pr_err("Spectra: pci_enable_device failed.\n"); | ||
45 | goto failed_alloc_memery; | ||
46 | } | ||
47 | |||
48 | if (id->driver_data == INTEL_CE4100) { | ||
49 | denali->platform = INTEL_CE4100; | ||
50 | mem_base = pci_resource_start(dev, 0); | ||
51 | mem_len = pci_resource_len(dev, 1); | ||
52 | csr_base = pci_resource_start(dev, 1); | ||
53 | csr_len = pci_resource_len(dev, 1); | ||
54 | } else { | ||
55 | denali->platform = INTEL_MRST; | ||
56 | csr_base = pci_resource_start(dev, 0); | ||
57 | csr_len = pci_resource_len(dev, 0); | ||
58 | mem_base = pci_resource_start(dev, 1); | ||
59 | mem_len = pci_resource_len(dev, 1); | ||
60 | if (!mem_len) { | ||
61 | mem_base = csr_base + csr_len; | ||
62 | mem_len = csr_len; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pci_set_master(dev); | ||
67 | denali->dev = &dev->dev; | ||
68 | denali->irq = dev->irq; | ||
69 | |||
70 | ret = pci_request_regions(dev, DENALI_NAND_NAME); | ||
71 | if (ret) { | ||
72 | pr_err("Spectra: Unable to request memory regions\n"); | ||
73 | goto failed_enable_dev; | ||
74 | } | ||
75 | |||
76 | denali->flash_reg = ioremap_nocache(csr_base, csr_len); | ||
77 | if (!denali->flash_reg) { | ||
78 | pr_err("Spectra: Unable to remap memory region\n"); | ||
79 | ret = -ENOMEM; | ||
80 | goto failed_req_regions; | ||
81 | } | ||
82 | |||
83 | denali->flash_mem = ioremap_nocache(mem_base, mem_len); | ||
84 | if (!denali->flash_mem) { | ||
85 | pr_err("Spectra: ioremap_nocache failed!"); | ||
86 | ret = -ENOMEM; | ||
87 | goto failed_remap_reg; | ||
88 | } | ||
89 | |||
90 | ret = denali_init(denali); | ||
91 | if (ret) | ||
92 | goto failed_remap_mem; | ||
93 | |||
94 | pci_set_drvdata(dev, denali); | ||
95 | |||
96 | return 0; | ||
97 | |||
98 | failed_remap_mem: | ||
99 | iounmap(denali->flash_mem); | ||
100 | failed_remap_reg: | ||
101 | iounmap(denali->flash_reg); | ||
102 | failed_req_regions: | ||
103 | pci_release_regions(dev); | ||
104 | failed_enable_dev: | ||
105 | pci_disable_device(dev); | ||
106 | failed_alloc_memery: | ||
107 | kfree(denali); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | /* driver exit point */ | ||
113 | static void denali_pci_remove(struct pci_dev *dev) | ||
114 | { | ||
115 | struct denali_nand_info *denali = pci_get_drvdata(dev); | ||
116 | |||
117 | denali_remove(denali); | ||
118 | iounmap(denali->flash_reg); | ||
119 | iounmap(denali->flash_mem); | ||
120 | pci_release_regions(dev); | ||
121 | pci_disable_device(dev); | ||
122 | pci_set_drvdata(dev, NULL); | ||
123 | kfree(denali); | ||
124 | } | ||
125 | |||
126 | static struct pci_driver denali_pci_driver = { | ||
127 | .name = DENALI_NAND_NAME, | ||
128 | .id_table = denali_pci_ids, | ||
129 | .probe = denali_pci_probe, | ||
130 | .remove = denali_pci_remove, | ||
131 | }; | ||
132 | |||
133 | static int denali_init_pci(void) | ||
134 | { | ||
135 | pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); | ||
136 | return pci_register_driver(&denali_pci_driver); | ||
137 | } | ||
138 | module_init(denali_init_pci); | ||
139 | |||
140 | static void denali_exit_pci(void) | ||
141 | { | ||
142 | pci_unregister_driver(&denali_pci_driver); | ||
143 | } | ||
144 | module_exit(denali_exit_pci); | ||
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 256eb30f6180..81fa5784f98b 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -53,8 +53,6 @@ static unsigned long __initdata doc_locations[] = { | |||
53 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 53 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
54 | 0xe8000, 0xea000, 0xec000, 0xee000, | 54 | 0xe8000, 0xea000, 0xec000, 0xee000, |
55 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 55 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
56 | #else | ||
57 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | ||
58 | #endif | 56 | #endif |
59 | 0xffffffff }; | 57 | 0xffffffff }; |
60 | 58 | ||
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 799da5d1c857..18fa4489e52e 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c | |||
@@ -46,6 +46,25 @@ | |||
46 | #include <linux/bitrev.h> | 46 | #include <linux/bitrev.h> |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * In "reliable mode" consecutive 2k pages are used in parallel (in some | ||
50 | * fashion) to store the same data. The data can be read back from the | ||
51 | * even-numbered pages in the normal manner; odd-numbered pages will appear to | ||
52 | * contain junk. Systems that boot from the docg4 typically write the secondary | ||
53 | * program loader (SPL) code in this mode. The SPL is loaded by the initial | ||
54 | * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped | ||
55 | * to the reset vector address). This module parameter enables you to use this | ||
56 | * driver to write the SPL. When in this mode, no more than 2k of data can be | ||
57 | * written at a time, because the addresses do not increment in the normal | ||
58 | * manner, and the starting offset must be within an even-numbered 2k region; | ||
59 | * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800, | ||
60 | * 0x1a00, ... Reliable mode is a special case and should not be used unless | ||
61 | * you know what you're doing. | ||
62 | */ | ||
63 | static bool reliable_mode; | ||
64 | module_param(reliable_mode, bool, 0); | ||
65 | MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode"); | ||
66 | |||
67 | /* | ||
49 | * You'll want to ignore badblocks if you're reading a partition that contains | 68 | * You'll want to ignore badblocks if you're reading a partition that contains |
50 | * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since | 69 | * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since |
51 | * it does not use mtd nand's method for marking bad blocks (using oob area). | 70 | * it does not use mtd nand's method for marking bad blocks (using oob area). |
@@ -113,6 +132,7 @@ struct docg4_priv { | |||
113 | #define DOCG4_SEQ_PAGEWRITE 0x16 | 132 | #define DOCG4_SEQ_PAGEWRITE 0x16 |
114 | #define DOCG4_SEQ_PAGEPROG 0x1e | 133 | #define DOCG4_SEQ_PAGEPROG 0x1e |
115 | #define DOCG4_SEQ_BLOCKERASE 0x24 | 134 | #define DOCG4_SEQ_BLOCKERASE 0x24 |
135 | #define DOCG4_SEQ_SETMODE 0x45 | ||
116 | 136 | ||
117 | /* DOC_FLASHCOMMAND register commands */ | 137 | /* DOC_FLASHCOMMAND register commands */ |
118 | #define DOCG4_CMD_PAGE_READ 0x00 | 138 | #define DOCG4_CMD_PAGE_READ 0x00 |
@@ -122,6 +142,8 @@ struct docg4_priv { | |||
122 | #define DOC_CMD_PROG_BLOCK_ADDR 0x60 | 142 | #define DOC_CMD_PROG_BLOCK_ADDR 0x60 |
123 | #define DOCG4_CMD_PAGEWRITE 0x80 | 143 | #define DOCG4_CMD_PAGEWRITE 0x80 |
124 | #define DOC_CMD_PROG_CYCLE2 0x10 | 144 | #define DOC_CMD_PROG_CYCLE2 0x10 |
145 | #define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */ | ||
146 | #define DOC_CMD_RELIABLE_MODE 0x22 | ||
125 | #define DOC_CMD_RESET 0xff | 147 | #define DOC_CMD_RESET 0xff |
126 | 148 | ||
127 | /* DOC_POWERMODE register bits */ | 149 | /* DOC_POWERMODE register bits */ |
@@ -190,17 +212,20 @@ struct docg4_priv { | |||
190 | #define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */ | 212 | #define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */ |
191 | 213 | ||
192 | #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */ | 214 | #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */ |
215 | #define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */ | ||
193 | 216 | ||
194 | /* | 217 | /* |
195 | * Oob bytes 0 - 6 are available to the user. | 218 | * Bytes 0, 1 are used as badblock marker. |
196 | * Byte 7 is hamming ecc for first 7 bytes. Bytes 8 - 14 are hw-generated ecc. | 219 | * Bytes 2 - 6 are available to the user. |
220 | * Byte 7 is hamming ecc for first 7 oob bytes only. | ||
221 | * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14. | ||
197 | * Byte 15 (the last) is used by the driver as a "page written" flag. | 222 | * Byte 15 (the last) is used by the driver as a "page written" flag. |
198 | */ | 223 | */ |
199 | static struct nand_ecclayout docg4_oobinfo = { | 224 | static struct nand_ecclayout docg4_oobinfo = { |
200 | .eccbytes = 9, | 225 | .eccbytes = 9, |
201 | .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, | 226 | .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, |
202 | .oobavail = 7, | 227 | .oobavail = 5, |
203 | .oobfree = { {0, 7} } | 228 | .oobfree = { {.offset = 2, .length = 5} } |
204 | }; | 229 | }; |
205 | 230 | ||
206 | /* | 231 | /* |
@@ -611,6 +636,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr) | |||
611 | dev_dbg(doc->dev, | 636 | dev_dbg(doc->dev, |
612 | "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); | 637 | "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); |
613 | sequence_reset(mtd); | 638 | sequence_reset(mtd); |
639 | |||
640 | if (unlikely(reliable_mode)) { | ||
641 | writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE); | ||
642 | writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND); | ||
643 | writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND); | ||
644 | write_nop(docptr); | ||
645 | } | ||
646 | |||
614 | writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); | 647 | writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); |
615 | writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); | 648 | writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); |
616 | write_nop(docptr); | 649 | write_nop(docptr); |
@@ -691,6 +724,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column, | |||
691 | break; | 724 | break; |
692 | 725 | ||
693 | case NAND_CMD_SEQIN: | 726 | case NAND_CMD_SEQIN: |
727 | if (unlikely(reliable_mode)) { | ||
728 | uint16_t g4_page = g4_addr >> 16; | ||
729 | |||
730 | /* writes to odd-numbered 2k pages are invalid */ | ||
731 | if (g4_page & 0x01) | ||
732 | dev_warn(doc->dev, | ||
733 | "invalid reliable mode address\n"); | ||
734 | } | ||
735 | |||
694 | write_page_prologue(mtd, g4_addr); | 736 | write_page_prologue(mtd, g4_addr); |
695 | 737 | ||
696 | /* hack for deferred write of oob bytes */ | 738 | /* hack for deferred write of oob bytes */ |
@@ -979,16 +1021,15 @@ static int __init read_factory_bbt(struct mtd_info *mtd) | |||
979 | struct docg4_priv *doc = nand->priv; | 1021 | struct docg4_priv *doc = nand->priv; |
980 | uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0); | 1022 | uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0); |
981 | uint8_t *buf; | 1023 | uint8_t *buf; |
982 | int i, block, status; | 1024 | int i, block; |
1025 | __u32 eccfailed_stats = mtd->ecc_stats.failed; | ||
983 | 1026 | ||
984 | buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); | 1027 | buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); |
985 | if (buf == NULL) | 1028 | if (buf == NULL) |
986 | return -ENOMEM; | 1029 | return -ENOMEM; |
987 | 1030 | ||
988 | read_page_prologue(mtd, g4_addr); | 1031 | read_page_prologue(mtd, g4_addr); |
989 | status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); | 1032 | docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); |
990 | if (status) | ||
991 | goto exit; | ||
992 | 1033 | ||
993 | /* | 1034 | /* |
994 | * If no memory-based bbt was created, exit. This will happen if module | 1035 | * If no memory-based bbt was created, exit. This will happen if module |
@@ -1000,6 +1041,20 @@ static int __init read_factory_bbt(struct mtd_info *mtd) | |||
1000 | if (nand->bbt == NULL) /* no memory-based bbt */ | 1041 | if (nand->bbt == NULL) /* no memory-based bbt */ |
1001 | goto exit; | 1042 | goto exit; |
1002 | 1043 | ||
1044 | if (mtd->ecc_stats.failed > eccfailed_stats) { | ||
1045 | /* | ||
1046 | * Whoops, an ecc failure ocurred reading the factory bbt. | ||
1047 | * It is stored redundantly, so we get another chance. | ||
1048 | */ | ||
1049 | eccfailed_stats = mtd->ecc_stats.failed; | ||
1050 | docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE); | ||
1051 | if (mtd->ecc_stats.failed > eccfailed_stats) { | ||
1052 | dev_warn(doc->dev, | ||
1053 | "The factory bbt could not be read!\n"); | ||
1054 | goto exit; | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1003 | /* | 1058 | /* |
1004 | * Parse factory bbt and update memory-based bbt. Factory bbt format is | 1059 | * Parse factory bbt and update memory-based bbt. Factory bbt format is |
1005 | * simple: one bit per block, block numbers increase left to right (msb | 1060 | * simple: one bit per block, block numbers increase left to right (msb |
@@ -1019,7 +1074,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd) | |||
1019 | } | 1074 | } |
1020 | exit: | 1075 | exit: |
1021 | kfree(buf); | 1076 | kfree(buf); |
1022 | return status; | 1077 | return 0; |
1023 | } | 1078 | } |
1024 | 1079 | ||
1025 | static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) | 1080 | static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index cc1480a5e4c1..20657209a472 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -109,20 +109,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset | ||
113 | * 1, so we have to adjust bad block pattern. This pattern should be used for | ||
114 | * x8 chips only. So far hardware does not support x16 chips anyway. | ||
115 | */ | ||
116 | static u8 scan_ff_pattern[] = { 0xff, }; | ||
117 | |||
118 | static struct nand_bbt_descr largepage_memorybased = { | ||
119 | .options = 0, | ||
120 | .offs = 0, | ||
121 | .len = 1, | ||
122 | .pattern = scan_ff_pattern, | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, | 112 | * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, |
127 | * interfere with ECC positions, that's why we implement our own descriptors. | 113 | * interfere with ECC positions, that's why we implement our own descriptors. |
128 | * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. | 114 | * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. |
@@ -699,7 +685,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
699 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? | 685 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? |
700 | &fsl_elbc_oob_lp_eccm1 : | 686 | &fsl_elbc_oob_lp_eccm1 : |
701 | &fsl_elbc_oob_lp_eccm0; | 687 | &fsl_elbc_oob_lp_eccm0; |
702 | chip->badblock_pattern = &largepage_memorybased; | ||
703 | } | 688 | } |
704 | } else { | 689 | } else { |
705 | dev_err(priv->dev, | 690 | dev_err(priv->dev, |
@@ -814,7 +799,7 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
814 | 799 | ||
815 | static DEFINE_MUTEX(fsl_elbc_nand_mutex); | 800 | static DEFINE_MUTEX(fsl_elbc_nand_mutex); |
816 | 801 | ||
817 | static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) | 802 | static int fsl_elbc_nand_probe(struct platform_device *pdev) |
818 | { | 803 | { |
819 | struct fsl_lbc_regs __iomem *lbc; | 804 | struct fsl_lbc_regs __iomem *lbc; |
820 | struct fsl_elbc_mtd *priv; | 805 | struct fsl_elbc_mtd *priv; |
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 3551a99076ba..ad6222627fed 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c | |||
@@ -389,7 +389,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
389 | timing = IFC_FIR_OP_RBCD; | 389 | timing = IFC_FIR_OP_RBCD; |
390 | 390 | ||
391 | out_be32(&ifc->ifc_nand.nand_fir0, | 391 | out_be32(&ifc->ifc_nand.nand_fir0, |
392 | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | | 392 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | |
393 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | | 393 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | |
394 | (timing << IFC_NAND_FIR0_OP2_SHIFT)); | 394 | (timing << IFC_NAND_FIR0_OP2_SHIFT)); |
395 | out_be32(&ifc->ifc_nand.nand_fcr0, | 395 | out_be32(&ifc->ifc_nand.nand_fcr0, |
@@ -754,7 +754,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) | |||
754 | 754 | ||
755 | /* READID */ | 755 | /* READID */ |
756 | out_be32(&ifc->ifc_nand.nand_fir0, | 756 | out_be32(&ifc->ifc_nand.nand_fir0, |
757 | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | | 757 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | |
758 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | | 758 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | |
759 | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); | 759 | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); |
760 | out_be32(&ifc->ifc_nand.nand_fcr0, | 760 | out_be32(&ifc->ifc_nand.nand_fcr0, |
@@ -922,7 +922,7 @@ static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank, | |||
922 | 922 | ||
923 | static DEFINE_MUTEX(fsl_ifc_nand_mutex); | 923 | static DEFINE_MUTEX(fsl_ifc_nand_mutex); |
924 | 924 | ||
925 | static int __devinit fsl_ifc_nand_probe(struct platform_device *dev) | 925 | static int fsl_ifc_nand_probe(struct platform_device *dev) |
926 | { | 926 | { |
927 | struct fsl_ifc_regs __iomem *ifc; | 927 | struct fsl_ifc_regs __iomem *ifc; |
928 | struct fsl_ifc_mtd *priv; | 928 | struct fsl_ifc_mtd *priv; |
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 45df542b9c61..5a8f5c4ce512 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c | |||
@@ -152,7 +152,7 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
152 | fun_wait_rnb(fun); | 152 | fun_wait_rnb(fun); |
153 | } | 153 | } |
154 | 154 | ||
155 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun, | 155 | static int fun_chip_init(struct fsl_upm_nand *fun, |
156 | const struct device_node *upm_np, | 156 | const struct device_node *upm_np, |
157 | const struct resource *io_res) | 157 | const struct resource *io_res) |
158 | { | 158 | { |
@@ -201,7 +201,7 @@ err: | |||
201 | return ret; | 201 | return ret; |
202 | } | 202 | } |
203 | 203 | ||
204 | static int __devinit fun_probe(struct platform_device *ofdev) | 204 | static int fun_probe(struct platform_device *ofdev) |
205 | { | 205 | { |
206 | struct fsl_upm_nand *fun; | 206 | struct fsl_upm_nand *fun; |
207 | struct resource io_res; | 207 | struct resource io_res; |
@@ -318,7 +318,7 @@ err1: | |||
318 | return ret; | 318 | return ret; |
319 | } | 319 | } |
320 | 320 | ||
321 | static int __devexit fun_remove(struct platform_device *ofdev) | 321 | static int fun_remove(struct platform_device *ofdev) |
322 | { | 322 | { |
323 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); | 323 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); |
324 | int i; | 324 | int i; |
@@ -350,7 +350,7 @@ static struct platform_driver of_fun_driver = { | |||
350 | .of_match_table = of_fun_match, | 350 | .of_match_table = of_fun_match, |
351 | }, | 351 | }, |
352 | .probe = fun_probe, | 352 | .probe = fun_probe, |
353 | .remove = __devexit_p(fun_remove), | 353 | .remove = fun_remove, |
354 | }; | 354 | }; |
355 | 355 | ||
356 | module_platform_driver(of_fun_driver); | 356 | module_platform_driver(of_fun_driver); |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 38d26240d8b1..1d7446434b0e 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c | |||
@@ -361,7 +361,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
361 | struct nand_chip *this = mtd->priv; | 361 | struct nand_chip *this = mtd->priv; |
362 | struct fsmc_nand_data *host = container_of(mtd, | 362 | struct fsmc_nand_data *host = container_of(mtd, |
363 | struct fsmc_nand_data, mtd); | 363 | struct fsmc_nand_data, mtd); |
364 | void *__iomem *regs = host->regs_va; | 364 | void __iomem *regs = host->regs_va; |
365 | unsigned int bank = host->bank; | 365 | unsigned int bank = host->bank; |
366 | 366 | ||
367 | if (ctrl & NAND_CTRL_CHANGE) { | 367 | if (ctrl & NAND_CTRL_CHANGE) { |
@@ -383,13 +383,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
383 | pc |= FSMC_ENABLE; | 383 | pc |= FSMC_ENABLE; |
384 | else | 384 | else |
385 | pc &= ~FSMC_ENABLE; | 385 | pc &= ~FSMC_ENABLE; |
386 | writel(pc, FSMC_NAND_REG(regs, bank, PC)); | 386 | writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC)); |
387 | } | 387 | } |
388 | 388 | ||
389 | mb(); | 389 | mb(); |
390 | 390 | ||
391 | if (cmd != NAND_CMD_NONE) | 391 | if (cmd != NAND_CMD_NONE) |
392 | writeb(cmd, this->IO_ADDR_W); | 392 | writeb_relaxed(cmd, this->IO_ADDR_W); |
393 | } | 393 | } |
394 | 394 | ||
395 | /* | 395 | /* |
@@ -426,14 +426,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, | |||
426 | tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; | 426 | tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; |
427 | 427 | ||
428 | if (busw) | 428 | if (busw) |
429 | writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC)); | 429 | writel_relaxed(value | FSMC_DEVWID_16, |
430 | FSMC_NAND_REG(regs, bank, PC)); | ||
430 | else | 431 | else |
431 | writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC)); | 432 | writel_relaxed(value | FSMC_DEVWID_8, |
433 | FSMC_NAND_REG(regs, bank, PC)); | ||
432 | 434 | ||
433 | writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, | 435 | writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, |
434 | FSMC_NAND_REG(regs, bank, PC)); | 436 | FSMC_NAND_REG(regs, bank, PC)); |
435 | writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM)); | 437 | writel_relaxed(thiz | thold | twait | tset, |
436 | writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB)); | 438 | FSMC_NAND_REG(regs, bank, COMM)); |
439 | writel_relaxed(thiz | thold | twait | tset, | ||
440 | FSMC_NAND_REG(regs, bank, ATTRIB)); | ||
437 | } | 441 | } |
438 | 442 | ||
439 | /* | 443 | /* |
@@ -446,11 +450,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) | |||
446 | void __iomem *regs = host->regs_va; | 450 | void __iomem *regs = host->regs_va; |
447 | uint32_t bank = host->bank; | 451 | uint32_t bank = host->bank; |
448 | 452 | ||
449 | writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, | 453 | writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, |
450 | FSMC_NAND_REG(regs, bank, PC)); | 454 | FSMC_NAND_REG(regs, bank, PC)); |
451 | writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, | 455 | writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, |
452 | FSMC_NAND_REG(regs, bank, PC)); | 456 | FSMC_NAND_REG(regs, bank, PC)); |
453 | writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, | 457 | writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, |
454 | FSMC_NAND_REG(regs, bank, PC)); | 458 | FSMC_NAND_REG(regs, bank, PC)); |
455 | } | 459 | } |
456 | 460 | ||
@@ -470,7 +474,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, | |||
470 | unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; | 474 | unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; |
471 | 475 | ||
472 | do { | 476 | do { |
473 | if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) | 477 | if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) |
474 | break; | 478 | break; |
475 | else | 479 | else |
476 | cond_resched(); | 480 | cond_resched(); |
@@ -481,25 +485,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, | |||
481 | return -ETIMEDOUT; | 485 | return -ETIMEDOUT; |
482 | } | 486 | } |
483 | 487 | ||
484 | ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); | 488 | ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); |
485 | ecc[0] = (uint8_t) (ecc_tmp >> 0); | 489 | ecc[0] = (uint8_t) (ecc_tmp >> 0); |
486 | ecc[1] = (uint8_t) (ecc_tmp >> 8); | 490 | ecc[1] = (uint8_t) (ecc_tmp >> 8); |
487 | ecc[2] = (uint8_t) (ecc_tmp >> 16); | 491 | ecc[2] = (uint8_t) (ecc_tmp >> 16); |
488 | ecc[3] = (uint8_t) (ecc_tmp >> 24); | 492 | ecc[3] = (uint8_t) (ecc_tmp >> 24); |
489 | 493 | ||
490 | ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2)); | 494 | ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); |
491 | ecc[4] = (uint8_t) (ecc_tmp >> 0); | 495 | ecc[4] = (uint8_t) (ecc_tmp >> 0); |
492 | ecc[5] = (uint8_t) (ecc_tmp >> 8); | 496 | ecc[5] = (uint8_t) (ecc_tmp >> 8); |
493 | ecc[6] = (uint8_t) (ecc_tmp >> 16); | 497 | ecc[6] = (uint8_t) (ecc_tmp >> 16); |
494 | ecc[7] = (uint8_t) (ecc_tmp >> 24); | 498 | ecc[7] = (uint8_t) (ecc_tmp >> 24); |
495 | 499 | ||
496 | ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3)); | 500 | ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); |
497 | ecc[8] = (uint8_t) (ecc_tmp >> 0); | 501 | ecc[8] = (uint8_t) (ecc_tmp >> 0); |
498 | ecc[9] = (uint8_t) (ecc_tmp >> 8); | 502 | ecc[9] = (uint8_t) (ecc_tmp >> 8); |
499 | ecc[10] = (uint8_t) (ecc_tmp >> 16); | 503 | ecc[10] = (uint8_t) (ecc_tmp >> 16); |
500 | ecc[11] = (uint8_t) (ecc_tmp >> 24); | 504 | ecc[11] = (uint8_t) (ecc_tmp >> 24); |
501 | 505 | ||
502 | ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS)); | 506 | ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); |
503 | ecc[12] = (uint8_t) (ecc_tmp >> 16); | 507 | ecc[12] = (uint8_t) (ecc_tmp >> 16); |
504 | 508 | ||
505 | return 0; | 509 | return 0; |
@@ -519,7 +523,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, | |||
519 | uint32_t bank = host->bank; | 523 | uint32_t bank = host->bank; |
520 | uint32_t ecc_tmp; | 524 | uint32_t ecc_tmp; |
521 | 525 | ||
522 | ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); | 526 | ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); |
523 | ecc[0] = (uint8_t) (ecc_tmp >> 0); | 527 | ecc[0] = (uint8_t) (ecc_tmp >> 0); |
524 | ecc[1] = (uint8_t) (ecc_tmp >> 8); | 528 | ecc[1] = (uint8_t) (ecc_tmp >> 8); |
525 | ecc[2] = (uint8_t) (ecc_tmp >> 16); | 529 | ecc[2] = (uint8_t) (ecc_tmp >> 16); |
@@ -601,7 +605,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, | |||
601 | dma_async_issue_pending(chan); | 605 | dma_async_issue_pending(chan); |
602 | 606 | ||
603 | ret = | 607 | ret = |
604 | wait_for_completion_interruptible_timeout(&host->dma_access_complete, | 608 | wait_for_completion_timeout(&host->dma_access_complete, |
605 | msecs_to_jiffies(3000)); | 609 | msecs_to_jiffies(3000)); |
606 | if (ret <= 0) { | 610 | if (ret <= 0) { |
607 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); | 611 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); |
@@ -628,10 +632,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
628 | uint32_t *p = (uint32_t *)buf; | 632 | uint32_t *p = (uint32_t *)buf; |
629 | len = len >> 2; | 633 | len = len >> 2; |
630 | for (i = 0; i < len; i++) | 634 | for (i = 0; i < len; i++) |
631 | writel(p[i], chip->IO_ADDR_W); | 635 | writel_relaxed(p[i], chip->IO_ADDR_W); |
632 | } else { | 636 | } else { |
633 | for (i = 0; i < len; i++) | 637 | for (i = 0; i < len; i++) |
634 | writeb(buf[i], chip->IO_ADDR_W); | 638 | writeb_relaxed(buf[i], chip->IO_ADDR_W); |
635 | } | 639 | } |
636 | } | 640 | } |
637 | 641 | ||
@@ -651,10 +655,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | |||
651 | uint32_t *p = (uint32_t *)buf; | 655 | uint32_t *p = (uint32_t *)buf; |
652 | len = len >> 2; | 656 | len = len >> 2; |
653 | for (i = 0; i < len; i++) | 657 | for (i = 0; i < len; i++) |
654 | p[i] = readl(chip->IO_ADDR_R); | 658 | p[i] = readl_relaxed(chip->IO_ADDR_R); |
655 | } else { | 659 | } else { |
656 | for (i = 0; i < len; i++) | 660 | for (i = 0; i < len; i++) |
657 | buf[i] = readb(chip->IO_ADDR_R); | 661 | buf[i] = readb_relaxed(chip->IO_ADDR_R); |
658 | } | 662 | } |
659 | } | 663 | } |
660 | 664 | ||
@@ -783,7 +787,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, | |||
783 | uint32_t num_err, i; | 787 | uint32_t num_err, i; |
784 | uint32_t ecc1, ecc2, ecc3, ecc4; | 788 | uint32_t ecc1, ecc2, ecc3, ecc4; |
785 | 789 | ||
786 | num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; | 790 | num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; |
787 | 791 | ||
788 | /* no bit flipping */ | 792 | /* no bit flipping */ |
789 | if (likely(num_err == 0)) | 793 | if (likely(num_err == 0)) |
@@ -826,10 +830,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, | |||
826 | * uint64_t array and error offset indexes are populated in err_idx | 830 | * uint64_t array and error offset indexes are populated in err_idx |
827 | * array | 831 | * array |
828 | */ | 832 | */ |
829 | ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1)); | 833 | ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); |
830 | ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2)); | 834 | ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); |
831 | ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3)); | 835 | ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); |
832 | ecc4 = readl(FSMC_NAND_REG(regs, bank, STS)); | 836 | ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); |
833 | 837 | ||
834 | err_idx[0] = (ecc1 >> 0) & 0x1FFF; | 838 | err_idx[0] = (ecc1 >> 0) & 0x1FFF; |
835 | err_idx[1] = (ecc1 >> 13) & 0x1FFF; | 839 | err_idx[1] = (ecc1 >> 13) & 0x1FFF; |
@@ -860,7 +864,7 @@ static bool filter(struct dma_chan *chan, void *slave) | |||
860 | } | 864 | } |
861 | 865 | ||
862 | #ifdef CONFIG_OF | 866 | #ifdef CONFIG_OF |
863 | static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, | 867 | static int fsmc_nand_probe_config_dt(struct platform_device *pdev, |
864 | struct device_node *np) | 868 | struct device_node *np) |
865 | { | 869 | { |
866 | struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); | 870 | struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); |
@@ -876,15 +880,13 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, | |||
876 | return -EINVAL; | 880 | return -EINVAL; |
877 | } | 881 | } |
878 | } | 882 | } |
879 | of_property_read_u32(np, "st,ale-off", &pdata->ale_off); | ||
880 | of_property_read_u32(np, "st,cle-off", &pdata->cle_off); | ||
881 | if (of_get_property(np, "nand-skip-bbtscan", NULL)) | 883 | if (of_get_property(np, "nand-skip-bbtscan", NULL)) |
882 | pdata->options = NAND_SKIP_BBTSCAN; | 884 | pdata->options = NAND_SKIP_BBTSCAN; |
883 | 885 | ||
884 | return 0; | 886 | return 0; |
885 | } | 887 | } |
886 | #else | 888 | #else |
887 | static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, | 889 | static int fsmc_nand_probe_config_dt(struct platform_device *pdev, |
888 | struct device_node *np) | 890 | struct device_node *np) |
889 | { | 891 | { |
890 | return -ENOSYS; | 892 | return -ENOSYS; |
@@ -935,41 +937,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
935 | if (!res) | 937 | if (!res) |
936 | return -EINVAL; | 938 | return -EINVAL; |
937 | 939 | ||
938 | if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), | 940 | host->data_va = devm_request_and_ioremap(&pdev->dev, res); |
939 | pdev->name)) { | ||
940 | dev_err(&pdev->dev, "Failed to get memory data resourse\n"); | ||
941 | return -ENOENT; | ||
942 | } | ||
943 | |||
944 | host->data_pa = (dma_addr_t)res->start; | ||
945 | host->data_va = devm_ioremap(&pdev->dev, res->start, | ||
946 | resource_size(res)); | ||
947 | if (!host->data_va) { | 941 | if (!host->data_va) { |
948 | dev_err(&pdev->dev, "data ioremap failed\n"); | 942 | dev_err(&pdev->dev, "data ioremap failed\n"); |
949 | return -ENOMEM; | 943 | return -ENOMEM; |
950 | } | 944 | } |
945 | host->data_pa = (dma_addr_t)res->start; | ||
951 | 946 | ||
952 | if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off, | 947 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); |
953 | resource_size(res), pdev->name)) { | 948 | if (!res) |
954 | dev_err(&pdev->dev, "Failed to get memory ale resourse\n"); | 949 | return -EINVAL; |
955 | return -ENOENT; | ||
956 | } | ||
957 | 950 | ||
958 | host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off, | 951 | host->addr_va = devm_request_and_ioremap(&pdev->dev, res); |
959 | resource_size(res)); | ||
960 | if (!host->addr_va) { | 952 | if (!host->addr_va) { |
961 | dev_err(&pdev->dev, "ale ioremap failed\n"); | 953 | dev_err(&pdev->dev, "ale ioremap failed\n"); |
962 | return -ENOMEM; | 954 | return -ENOMEM; |
963 | } | 955 | } |
964 | 956 | ||
965 | if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off, | 957 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); |
966 | resource_size(res), pdev->name)) { | 958 | if (!res) |
967 | dev_err(&pdev->dev, "Failed to get memory cle resourse\n"); | 959 | return -EINVAL; |
968 | return -ENOENT; | ||
969 | } | ||
970 | 960 | ||
971 | host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off, | 961 | host->cmd_va = devm_request_and_ioremap(&pdev->dev, res); |
972 | resource_size(res)); | ||
973 | if (!host->cmd_va) { | 962 | if (!host->cmd_va) { |
974 | dev_err(&pdev->dev, "ale ioremap failed\n"); | 963 | dev_err(&pdev->dev, "ale ioremap failed\n"); |
975 | return -ENOMEM; | 964 | return -ENOMEM; |
@@ -979,14 +968,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
979 | if (!res) | 968 | if (!res) |
980 | return -EINVAL; | 969 | return -EINVAL; |
981 | 970 | ||
982 | if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), | 971 | host->regs_va = devm_request_and_ioremap(&pdev->dev, res); |
983 | pdev->name)) { | ||
984 | dev_err(&pdev->dev, "Failed to get memory regs resourse\n"); | ||
985 | return -ENOENT; | ||
986 | } | ||
987 | |||
988 | host->regs_va = devm_ioremap(&pdev->dev, res->start, | ||
989 | resource_size(res)); | ||
990 | if (!host->regs_va) { | 972 | if (!host->regs_va) { |
991 | dev_err(&pdev->dev, "regs ioremap failed\n"); | 973 | dev_err(&pdev->dev, "regs ioremap failed\n"); |
992 | return -ENOMEM; | 974 | return -ENOMEM; |
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index bc73bc5f2713..e789e3f51710 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c | |||
@@ -90,14 +90,14 @@ static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len) | |||
90 | { | 90 | { |
91 | struct nand_chip *this = mtd->priv; | 91 | struct nand_chip *this = mtd->priv; |
92 | 92 | ||
93 | writesb(this->IO_ADDR_W, buf, len); | 93 | iowrite8_rep(this->IO_ADDR_W, buf, len); |
94 | } | 94 | } |
95 | 95 | ||
96 | static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) | 96 | static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) |
97 | { | 97 | { |
98 | struct nand_chip *this = mtd->priv; | 98 | struct nand_chip *this = mtd->priv; |
99 | 99 | ||
100 | readsb(this->IO_ADDR_R, buf, len); | 100 | ioread8_rep(this->IO_ADDR_R, buf, len); |
101 | } | 101 | } |
102 | 102 | ||
103 | static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, | 103 | static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, |
@@ -106,7 +106,7 @@ static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, | |||
106 | struct nand_chip *this = mtd->priv; | 106 | struct nand_chip *this = mtd->priv; |
107 | 107 | ||
108 | if (IS_ALIGNED((unsigned long)buf, 2)) { | 108 | if (IS_ALIGNED((unsigned long)buf, 2)) { |
109 | writesw(this->IO_ADDR_W, buf, len>>1); | 109 | iowrite16_rep(this->IO_ADDR_W, buf, len>>1); |
110 | } else { | 110 | } else { |
111 | int i; | 111 | int i; |
112 | unsigned short *ptr = (unsigned short *)buf; | 112 | unsigned short *ptr = (unsigned short *)buf; |
@@ -121,7 +121,7 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) | |||
121 | struct nand_chip *this = mtd->priv; | 121 | struct nand_chip *this = mtd->priv; |
122 | 122 | ||
123 | if (IS_ALIGNED((unsigned long)buf, 2)) { | 123 | if (IS_ALIGNED((unsigned long)buf, 2)) { |
124 | readsw(this->IO_ADDR_R, buf, len>>1); | 124 | ioread16_rep(this->IO_ADDR_R, buf, len>>1); |
125 | } else { | 125 | } else { |
126 | int i; | 126 | int i; |
127 | unsigned short *ptr = (unsigned short *)buf; | 127 | unsigned short *ptr = (unsigned short *)buf; |
@@ -134,7 +134,11 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) | |||
134 | static int gpio_nand_devready(struct mtd_info *mtd) | 134 | static int gpio_nand_devready(struct mtd_info *mtd) |
135 | { | 135 | { |
136 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); | 136 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); |
137 | return gpio_get_value(gpiomtd->plat.gpio_rdy); | 137 | |
138 | if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) | ||
139 | return gpio_get_value(gpiomtd->plat.gpio_rdy); | ||
140 | |||
141 | return 1; | ||
138 | } | 142 | } |
139 | 143 | ||
140 | #ifdef CONFIG_OF | 144 | #ifdef CONFIG_OF |
@@ -227,7 +231,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev) | |||
227 | return platform_get_resource(pdev, IORESOURCE_MEM, 1); | 231 | return platform_get_resource(pdev, IORESOURCE_MEM, 1); |
228 | } | 232 | } |
229 | 233 | ||
230 | static int __devexit gpio_nand_remove(struct platform_device *dev) | 234 | static int gpio_nand_remove(struct platform_device *dev) |
231 | { | 235 | { |
232 | struct gpiomtd *gpiomtd = platform_get_drvdata(dev); | 236 | struct gpiomtd *gpiomtd = platform_get_drvdata(dev); |
233 | struct resource *res; | 237 | struct resource *res; |
@@ -252,7 +256,8 @@ static int __devexit gpio_nand_remove(struct platform_device *dev) | |||
252 | gpio_free(gpiomtd->plat.gpio_nce); | 256 | gpio_free(gpiomtd->plat.gpio_nce); |
253 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | 257 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) |
254 | gpio_free(gpiomtd->plat.gpio_nwp); | 258 | gpio_free(gpiomtd->plat.gpio_nwp); |
255 | gpio_free(gpiomtd->plat.gpio_rdy); | 259 | if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) |
260 | gpio_free(gpiomtd->plat.gpio_rdy); | ||
256 | 261 | ||
257 | kfree(gpiomtd); | 262 | kfree(gpiomtd); |
258 | 263 | ||
@@ -277,7 +282,7 @@ static void __iomem *request_and_remap(struct resource *res, size_t size, | |||
277 | return ptr; | 282 | return ptr; |
278 | } | 283 | } |
279 | 284 | ||
280 | static int __devinit gpio_nand_probe(struct platform_device *dev) | 285 | static int gpio_nand_probe(struct platform_device *dev) |
281 | { | 286 | { |
282 | struct gpiomtd *gpiomtd; | 287 | struct gpiomtd *gpiomtd; |
283 | struct nand_chip *this; | 288 | struct nand_chip *this; |
@@ -336,10 +341,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
336 | if (ret) | 341 | if (ret) |
337 | goto err_cle; | 342 | goto err_cle; |
338 | gpio_direction_output(gpiomtd->plat.gpio_cle, 0); | 343 | gpio_direction_output(gpiomtd->plat.gpio_cle, 0); |
339 | ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); | 344 | if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { |
340 | if (ret) | 345 | ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); |
341 | goto err_rdy; | 346 | if (ret) |
342 | gpio_direction_input(gpiomtd->plat.gpio_rdy); | 347 | goto err_rdy; |
348 | gpio_direction_input(gpiomtd->plat.gpio_rdy); | ||
349 | } | ||
343 | 350 | ||
344 | 351 | ||
345 | this->IO_ADDR_W = this->IO_ADDR_R; | 352 | this->IO_ADDR_W = this->IO_ADDR_R; |
@@ -386,7 +393,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
386 | err_wp: | 393 | err_wp: |
387 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | 394 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) |
388 | gpio_set_value(gpiomtd->plat.gpio_nwp, 0); | 395 | gpio_set_value(gpiomtd->plat.gpio_nwp, 0); |
389 | gpio_free(gpiomtd->plat.gpio_rdy); | 396 | if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) |
397 | gpio_free(gpiomtd->plat.gpio_rdy); | ||
390 | err_rdy: | 398 | err_rdy: |
391 | gpio_free(gpiomtd->plat.gpio_cle); | 399 | gpio_free(gpiomtd->plat.gpio_cle); |
392 | err_cle: | 400 | err_cle: |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 3502accd4bc3..d84699c7968e 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | */ | 20 | */ |
21 | #include <linux/mtd/gpmi-nand.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
24 | 23 | ||
@@ -166,6 +165,15 @@ int gpmi_init(struct gpmi_nand_data *this) | |||
166 | if (ret) | 165 | if (ret) |
167 | goto err_out; | 166 | goto err_out; |
168 | 167 | ||
168 | /* | ||
169 | * Reset BCH here, too. We got failures otherwise :( | ||
170 | * See later BCH reset for explanation of MX23 handling | ||
171 | */ | ||
172 | ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); | ||
173 | if (ret) | ||
174 | goto err_out; | ||
175 | |||
176 | |||
169 | /* Choose NAND mode. */ | 177 | /* Choose NAND mode. */ |
170 | writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); | 178 | writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); |
171 | 179 | ||
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d79696b2f19b..5cd141f7bfc2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/mtd/gpmi-nand.h> | ||
29 | #include <linux/mtd/partitions.h> | 28 | #include <linux/mtd/partitions.h> |
30 | #include <linux/pinctrl/consumer.h> | 29 | #include <linux/pinctrl/consumer.h> |
31 | #include <linux/of.h> | 30 | #include <linux/of.h> |
@@ -33,6 +32,12 @@ | |||
33 | #include <linux/of_mtd.h> | 32 | #include <linux/of_mtd.h> |
34 | #include "gpmi-nand.h" | 33 | #include "gpmi-nand.h" |
35 | 34 | ||
35 | /* Resource names for the GPMI NAND driver. */ | ||
36 | #define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" | ||
37 | #define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch" | ||
38 | #define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch" | ||
39 | #define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma" | ||
40 | |||
36 | /* add our owner bbt descriptor */ | 41 | /* add our owner bbt descriptor */ |
37 | static uint8_t scan_ff_pattern[] = { 0xff }; | 42 | static uint8_t scan_ff_pattern[] = { 0xff }; |
38 | static struct nand_bbt_descr gpmi_bbt_descr = { | 43 | static struct nand_bbt_descr gpmi_bbt_descr = { |
@@ -222,7 +227,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) | |||
222 | 227 | ||
223 | ret = dma_map_sg(this->dev, sgl, 1, dr); | 228 | ret = dma_map_sg(this->dev, sgl, 1, dr); |
224 | if (ret == 0) | 229 | if (ret == 0) |
225 | pr_err("map failed.\n"); | 230 | pr_err("DMA mapping failed.\n"); |
226 | 231 | ||
227 | this->direct_dma_map_ok = false; | 232 | this->direct_dma_map_ok = false; |
228 | } | 233 | } |
@@ -314,7 +319,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, | |||
314 | return 0; | 319 | return 0; |
315 | } | 320 | } |
316 | 321 | ||
317 | static int __devinit | 322 | static int |
318 | acquire_register_block(struct gpmi_nand_data *this, const char *res_name) | 323 | acquire_register_block(struct gpmi_nand_data *this, const char *res_name) |
319 | { | 324 | { |
320 | struct platform_device *pdev = this->pdev; | 325 | struct platform_device *pdev = this->pdev; |
@@ -355,7 +360,7 @@ static void release_register_block(struct gpmi_nand_data *this) | |||
355 | res->bch_regs = NULL; | 360 | res->bch_regs = NULL; |
356 | } | 361 | } |
357 | 362 | ||
358 | static int __devinit | 363 | static int |
359 | acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) | 364 | acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) |
360 | { | 365 | { |
361 | struct platform_device *pdev = this->pdev; | 366 | struct platform_device *pdev = this->pdev; |
@@ -422,7 +427,7 @@ static void release_dma_channels(struct gpmi_nand_data *this) | |||
422 | } | 427 | } |
423 | } | 428 | } |
424 | 429 | ||
425 | static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) | 430 | static int acquire_dma_channels(struct gpmi_nand_data *this) |
426 | { | 431 | { |
427 | struct platform_device *pdev = this->pdev; | 432 | struct platform_device *pdev = this->pdev; |
428 | struct resource *r_dma; | 433 | struct resource *r_dma; |
@@ -456,7 +461,7 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) | |||
456 | 461 | ||
457 | dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); | 462 | dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); |
458 | if (!dma_chan) { | 463 | if (!dma_chan) { |
459 | pr_err("dma_request_channel failed.\n"); | 464 | pr_err("Failed to request DMA channel.\n"); |
460 | goto acquire_err; | 465 | goto acquire_err; |
461 | } | 466 | } |
462 | 467 | ||
@@ -487,7 +492,7 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { | |||
487 | "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", | 492 | "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", |
488 | }; | 493 | }; |
489 | 494 | ||
490 | static int __devinit gpmi_get_clks(struct gpmi_nand_data *this) | 495 | static int gpmi_get_clks(struct gpmi_nand_data *this) |
491 | { | 496 | { |
492 | struct resources *r = &this->resources; | 497 | struct resources *r = &this->resources; |
493 | char **extra_clks = NULL; | 498 | char **extra_clks = NULL; |
@@ -533,7 +538,7 @@ err_clock: | |||
533 | return -ENOMEM; | 538 | return -ENOMEM; |
534 | } | 539 | } |
535 | 540 | ||
536 | static int __devinit acquire_resources(struct gpmi_nand_data *this) | 541 | static int acquire_resources(struct gpmi_nand_data *this) |
537 | { | 542 | { |
538 | struct pinctrl *pinctrl; | 543 | struct pinctrl *pinctrl; |
539 | int ret; | 544 | int ret; |
@@ -583,7 +588,7 @@ static void release_resources(struct gpmi_nand_data *this) | |||
583 | release_dma_channels(this); | 588 | release_dma_channels(this); |
584 | } | 589 | } |
585 | 590 | ||
586 | static int __devinit init_hardware(struct gpmi_nand_data *this) | 591 | static int init_hardware(struct gpmi_nand_data *this) |
587 | { | 592 | { |
588 | int ret; | 593 | int ret; |
589 | 594 | ||
@@ -625,7 +630,8 @@ static int read_page_prepare(struct gpmi_nand_data *this, | |||
625 | length, DMA_FROM_DEVICE); | 630 | length, DMA_FROM_DEVICE); |
626 | if (dma_mapping_error(dev, dest_phys)) { | 631 | if (dma_mapping_error(dev, dest_phys)) { |
627 | if (alt_size < length) { | 632 | if (alt_size < length) { |
628 | pr_err("Alternate buffer is too small\n"); | 633 | pr_err("%s, Alternate buffer is too small\n", |
634 | __func__); | ||
629 | return -ENOMEM; | 635 | return -ENOMEM; |
630 | } | 636 | } |
631 | goto map_failed; | 637 | goto map_failed; |
@@ -675,7 +681,8 @@ static int send_page_prepare(struct gpmi_nand_data *this, | |||
675 | DMA_TO_DEVICE); | 681 | DMA_TO_DEVICE); |
676 | if (dma_mapping_error(dev, source_phys)) { | 682 | if (dma_mapping_error(dev, source_phys)) { |
677 | if (alt_size < length) { | 683 | if (alt_size < length) { |
678 | pr_err("Alternate buffer is too small\n"); | 684 | pr_err("%s, Alternate buffer is too small\n", |
685 | __func__); | ||
679 | return -ENOMEM; | 686 | return -ENOMEM; |
680 | } | 687 | } |
681 | goto map_failed; | 688 | goto map_failed; |
@@ -763,7 +770,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) | |||
763 | 770 | ||
764 | error_alloc: | 771 | error_alloc: |
765 | gpmi_free_dma_buffer(this); | 772 | gpmi_free_dma_buffer(this); |
766 | pr_err("allocate DMA buffer ret!!\n"); | 773 | pr_err("Error allocating DMA buffers!\n"); |
767 | return -ENOMEM; | 774 | return -ENOMEM; |
768 | } | 775 | } |
769 | 776 | ||
@@ -1474,7 +1481,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) | |||
1474 | /* Set up the NFC geometry which is used by BCH. */ | 1481 | /* Set up the NFC geometry which is used by BCH. */ |
1475 | ret = bch_set_geometry(this); | 1482 | ret = bch_set_geometry(this); |
1476 | if (ret) { | 1483 | if (ret) { |
1477 | pr_err("set geometry ret : %d\n", ret); | 1484 | pr_err("Error setting BCH geometry : %d\n", ret); |
1478 | return ret; | 1485 | return ret; |
1479 | } | 1486 | } |
1480 | 1487 | ||
@@ -1535,7 +1542,7 @@ static void gpmi_nfc_exit(struct gpmi_nand_data *this) | |||
1535 | gpmi_free_dma_buffer(this); | 1542 | gpmi_free_dma_buffer(this); |
1536 | } | 1543 | } |
1537 | 1544 | ||
1538 | static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) | 1545 | static int gpmi_nfc_init(struct gpmi_nand_data *this) |
1539 | { | 1546 | { |
1540 | struct mtd_info *mtd = &this->mtd; | 1547 | struct mtd_info *mtd = &this->mtd; |
1541 | struct nand_chip *chip = &this->nand; | 1548 | struct nand_chip *chip = &this->nand; |
@@ -1618,7 +1625,7 @@ static const struct of_device_id gpmi_nand_id_table[] = { | |||
1618 | }; | 1625 | }; |
1619 | MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); | 1626 | MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); |
1620 | 1627 | ||
1621 | static int __devinit gpmi_nand_probe(struct platform_device *pdev) | 1628 | static int gpmi_nand_probe(struct platform_device *pdev) |
1622 | { | 1629 | { |
1623 | struct gpmi_nand_data *this; | 1630 | struct gpmi_nand_data *this; |
1624 | const struct of_device_id *of_id; | 1631 | const struct of_device_id *of_id; |
@@ -1668,7 +1675,7 @@ exit_acquire_resources: | |||
1668 | return ret; | 1675 | return ret; |
1669 | } | 1676 | } |
1670 | 1677 | ||
1671 | static int __devexit gpmi_nand_remove(struct platform_device *pdev) | 1678 | static int gpmi_nand_remove(struct platform_device *pdev) |
1672 | { | 1679 | { |
1673 | struct gpmi_nand_data *this = platform_get_drvdata(pdev); | 1680 | struct gpmi_nand_data *this = platform_get_drvdata(pdev); |
1674 | 1681 | ||
@@ -1685,7 +1692,7 @@ static struct platform_driver gpmi_nand_driver = { | |||
1685 | .of_match_table = gpmi_nand_id_table, | 1692 | .of_match_table = gpmi_nand_id_table, |
1686 | }, | 1693 | }, |
1687 | .probe = gpmi_nand_probe, | 1694 | .probe = gpmi_nand_probe, |
1688 | .remove = __devexit_p(gpmi_nand_remove), | 1695 | .remove = gpmi_nand_remove, |
1689 | .id_table = gpmi_ids, | 1696 | .id_table = gpmi_ids, |
1690 | }; | 1697 | }; |
1691 | module_platform_driver(gpmi_nand_driver); | 1698 | module_platform_driver(gpmi_nand_driver); |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 7ac25c1e58f9..3d93a5e39090 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h | |||
@@ -130,7 +130,6 @@ struct gpmi_nand_data { | |||
130 | /* System Interface */ | 130 | /* System Interface */ |
131 | struct device *dev; | 131 | struct device *dev; |
132 | struct platform_device *pdev; | 132 | struct platform_device *pdev; |
133 | struct gpmi_nand_platform_data *pdata; | ||
134 | 133 | ||
135 | /* Resources */ | 134 | /* Resources */ |
136 | struct resources resources; | 135 | struct resources resources; |
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 100b6775e175..8d415f014e1d 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c | |||
@@ -316,13 +316,17 @@ err: | |||
316 | return ret; | 316 | return ret; |
317 | } | 317 | } |
318 | 318 | ||
319 | static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) | 319 | static inline void jz_nand_iounmap_resource(struct resource *res, |
320 | void __iomem *base) | ||
320 | { | 321 | { |
321 | iounmap(base); | 322 | iounmap(base); |
322 | release_mem_region(res->start, resource_size(res)); | 323 | release_mem_region(res->start, resource_size(res)); |
323 | } | 324 | } |
324 | 325 | ||
325 | static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { | 326 | static int jz_nand_detect_bank(struct platform_device *pdev, |
327 | struct jz_nand *nand, unsigned char bank, | ||
328 | size_t chipnr, uint8_t *nand_maf_id, | ||
329 | uint8_t *nand_dev_id) { | ||
326 | int ret; | 330 | int ret; |
327 | int gpio; | 331 | int gpio; |
328 | char gpio_name[9]; | 332 | char gpio_name[9]; |
@@ -400,7 +404,7 @@ notfound_gpio: | |||
400 | return ret; | 404 | return ret; |
401 | } | 405 | } |
402 | 406 | ||
403 | static int __devinit jz_nand_probe(struct platform_device *pdev) | 407 | static int jz_nand_probe(struct platform_device *pdev) |
404 | { | 408 | { |
405 | int ret; | 409 | int ret; |
406 | struct jz_nand *nand; | 410 | struct jz_nand *nand; |
@@ -541,7 +545,7 @@ err_free: | |||
541 | return ret; | 545 | return ret; |
542 | } | 546 | } |
543 | 547 | ||
544 | static int __devexit jz_nand_remove(struct platform_device *pdev) | 548 | static int jz_nand_remove(struct platform_device *pdev) |
545 | { | 549 | { |
546 | struct jz_nand *nand = platform_get_drvdata(pdev); | 550 | struct jz_nand *nand = platform_get_drvdata(pdev); |
547 | struct jz_nand_platform_data *pdata = pdev->dev.platform_data; | 551 | struct jz_nand_platform_data *pdata = pdev->dev.platform_data; |
@@ -573,7 +577,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) | |||
573 | 577 | ||
574 | static struct platform_driver jz_nand_driver = { | 578 | static struct platform_driver jz_nand_driver = { |
575 | .probe = jz_nand_probe, | 579 | .probe = jz_nand_probe, |
576 | .remove = __devexit_p(jz_nand_remove), | 580 | .remove = jz_nand_remove, |
577 | .driver = { | 581 | .driver = { |
578 | .name = "jz4740-nand", | 582 | .name = "jz4740-nand", |
579 | .owner = THIS_MODULE, | 583 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index c29b7ac1f6af..f182befa7360 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c | |||
@@ -655,7 +655,7 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) | |||
655 | /* | 655 | /* |
656 | * Probe for NAND controller | 656 | * Probe for NAND controller |
657 | */ | 657 | */ |
658 | static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) | 658 | static int lpc32xx_nand_probe(struct platform_device *pdev) |
659 | { | 659 | { |
660 | struct lpc32xx_nand_host *host; | 660 | struct lpc32xx_nand_host *host; |
661 | struct mtd_info *mtd; | 661 | struct mtd_info *mtd; |
@@ -845,7 +845,7 @@ err_exit1: | |||
845 | /* | 845 | /* |
846 | * Remove NAND device | 846 | * Remove NAND device |
847 | */ | 847 | */ |
848 | static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) | 848 | static int lpc32xx_nand_remove(struct platform_device *pdev) |
849 | { | 849 | { |
850 | struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); | 850 | struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); |
851 | struct mtd_info *mtd = &host->mtd; | 851 | struct mtd_info *mtd = &host->mtd; |
@@ -907,7 +907,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); | |||
907 | 907 | ||
908 | static struct platform_driver lpc32xx_nand_driver = { | 908 | static struct platform_driver lpc32xx_nand_driver = { |
909 | .probe = lpc32xx_nand_probe, | 909 | .probe = lpc32xx_nand_probe, |
910 | .remove = __devexit_p(lpc32xx_nand_remove), | 910 | .remove = lpc32xx_nand_remove, |
911 | .resume = lpc32xx_nand_resume, | 911 | .resume = lpc32xx_nand_resume, |
912 | .suspend = lpc32xx_nand_suspend, | 912 | .suspend = lpc32xx_nand_suspend, |
913 | .driver = { | 913 | .driver = { |
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 32409c45d479..030b78c62895 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c | |||
@@ -755,7 +755,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) | |||
755 | /* | 755 | /* |
756 | * Probe for NAND controller | 756 | * Probe for NAND controller |
757 | */ | 757 | */ |
758 | static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) | 758 | static int lpc32xx_nand_probe(struct platform_device *pdev) |
759 | { | 759 | { |
760 | struct lpc32xx_nand_host *host; | 760 | struct lpc32xx_nand_host *host; |
761 | struct mtd_info *mtd; | 761 | struct mtd_info *mtd; |
@@ -949,7 +949,7 @@ err_exit1: | |||
949 | /* | 949 | /* |
950 | * Remove NAND device. | 950 | * Remove NAND device. |
951 | */ | 951 | */ |
952 | static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) | 952 | static int lpc32xx_nand_remove(struct platform_device *pdev) |
953 | { | 953 | { |
954 | uint32_t tmp; | 954 | uint32_t tmp; |
955 | struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); | 955 | struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); |
@@ -1021,7 +1021,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); | |||
1021 | 1021 | ||
1022 | static struct platform_driver lpc32xx_nand_driver = { | 1022 | static struct platform_driver lpc32xx_nand_driver = { |
1023 | .probe = lpc32xx_nand_probe, | 1023 | .probe = lpc32xx_nand_probe, |
1024 | .remove = __devexit_p(lpc32xx_nand_remove), | 1024 | .remove = lpc32xx_nand_remove, |
1025 | .resume = lpc32xx_nand_resume, | 1025 | .resume = lpc32xx_nand_resume, |
1026 | .suspend = lpc32xx_nand_suspend, | 1026 | .suspend = lpc32xx_nand_suspend, |
1027 | .driver = { | 1027 | .driver = { |
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index f776c8577b8c..3c9cdcbc4cba 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c | |||
@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) | |||
626 | iounmap(prv->csreg); | 626 | iounmap(prv->csreg); |
627 | } | 627 | } |
628 | 628 | ||
629 | static int __devinit mpc5121_nfc_probe(struct platform_device *op) | 629 | static int mpc5121_nfc_probe(struct platform_device *op) |
630 | { | 630 | { |
631 | struct device_node *rootnode, *dn = op->dev.of_node; | 631 | struct device_node *rootnode, *dn = op->dev.of_node; |
632 | struct device *dev = &op->dev; | 632 | struct device *dev = &op->dev; |
@@ -827,7 +827,7 @@ error: | |||
827 | return retval; | 827 | return retval; |
828 | } | 828 | } |
829 | 829 | ||
830 | static int __devexit mpc5121_nfc_remove(struct platform_device *op) | 830 | static int mpc5121_nfc_remove(struct platform_device *op) |
831 | { | 831 | { |
832 | struct device *dev = &op->dev; | 832 | struct device *dev = &op->dev; |
833 | struct mtd_info *mtd = dev_get_drvdata(dev); | 833 | struct mtd_info *mtd = dev_get_drvdata(dev); |
@@ -841,14 +841,14 @@ static int __devexit mpc5121_nfc_remove(struct platform_device *op) | |||
841 | return 0; | 841 | return 0; |
842 | } | 842 | } |
843 | 843 | ||
844 | static struct of_device_id mpc5121_nfc_match[] __devinitdata = { | 844 | static struct of_device_id mpc5121_nfc_match[] = { |
845 | { .compatible = "fsl,mpc5121-nfc", }, | 845 | { .compatible = "fsl,mpc5121-nfc", }, |
846 | {}, | 846 | {}, |
847 | }; | 847 | }; |
848 | 848 | ||
849 | static struct platform_driver mpc5121_nfc_driver = { | 849 | static struct platform_driver mpc5121_nfc_driver = { |
850 | .probe = mpc5121_nfc_probe, | 850 | .probe = mpc5121_nfc_probe, |
851 | .remove = __devexit_p(mpc5121_nfc_remove), | 851 | .remove = mpc5121_nfc_remove, |
852 | .driver = { | 852 | .driver = { |
853 | .name = DRV_NAME, | 853 | .name = DRV_NAME, |
854 | .owner = THIS_MODULE, | 854 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 022dcdc256fb..45204e41a028 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -266,7 +266,8 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { | |||
266 | } | 266 | } |
267 | }; | 267 | }; |
268 | 268 | ||
269 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL }; | 269 | static const char const *part_probes[] = { |
270 | "cmdlinepart", "RedBoot", "ofpart", NULL }; | ||
270 | 271 | ||
271 | static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) | 272 | static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) |
272 | { | 273 | { |
@@ -1378,7 +1379,7 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host) | |||
1378 | } | 1379 | } |
1379 | #endif | 1380 | #endif |
1380 | 1381 | ||
1381 | static int __devinit mxcnd_probe(struct platform_device *pdev) | 1382 | static int mxcnd_probe(struct platform_device *pdev) |
1382 | { | 1383 | { |
1383 | struct nand_chip *this; | 1384 | struct nand_chip *this; |
1384 | struct mtd_info *mtd; | 1385 | struct mtd_info *mtd; |
@@ -1556,12 +1557,13 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) | |||
1556 | return 0; | 1557 | return 0; |
1557 | 1558 | ||
1558 | escan: | 1559 | escan: |
1559 | clk_disable_unprepare(host->clk); | 1560 | if (host->clk_act) |
1561 | clk_disable_unprepare(host->clk); | ||
1560 | 1562 | ||
1561 | return err; | 1563 | return err; |
1562 | } | 1564 | } |
1563 | 1565 | ||
1564 | static int __devexit mxcnd_remove(struct platform_device *pdev) | 1566 | static int mxcnd_remove(struct platform_device *pdev) |
1565 | { | 1567 | { |
1566 | struct mxc_nand_host *host = platform_get_drvdata(pdev); | 1568 | struct mxc_nand_host *host = platform_get_drvdata(pdev); |
1567 | 1569 | ||
@@ -1580,7 +1582,7 @@ static struct platform_driver mxcnd_driver = { | |||
1580 | }, | 1582 | }, |
1581 | .id_table = mxcnd_devtype, | 1583 | .id_table = mxcnd_devtype, |
1582 | .probe = mxcnd_probe, | 1584 | .probe = mxcnd_probe, |
1583 | .remove = __devexit_p(mxcnd_remove), | 1585 | .remove = mxcnd_remove, |
1584 | }; | 1586 | }; |
1585 | module_platform_driver(mxcnd_driver); | 1587 | module_platform_driver(mxcnd_driver); |
1586 | 1588 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1a03b7f673ce..8323ac991ad1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = { | |||
93 | .length = 78} } | 93 | .length = 78} } |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, | 96 | static int nand_get_device(struct mtd_info *mtd, int new_state); |
97 | int new_state); | ||
98 | 97 | ||
99 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | 98 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, |
100 | struct mtd_oob_ops *ops); | 99 | struct mtd_oob_ops *ops); |
@@ -130,15 +129,12 @@ static int check_offs_len(struct mtd_info *mtd, | |||
130 | * nand_release_device - [GENERIC] release chip | 129 | * nand_release_device - [GENERIC] release chip |
131 | * @mtd: MTD device structure | 130 | * @mtd: MTD device structure |
132 | * | 131 | * |
133 | * Deselect, release chip lock and wake up anyone waiting on the device. | 132 | * Release chip lock and wake up anyone waiting on the device. |
134 | */ | 133 | */ |
135 | static void nand_release_device(struct mtd_info *mtd) | 134 | static void nand_release_device(struct mtd_info *mtd) |
136 | { | 135 | { |
137 | struct nand_chip *chip = mtd->priv; | 136 | struct nand_chip *chip = mtd->priv; |
138 | 137 | ||
139 | /* De-select the NAND device */ | ||
140 | chip->select_chip(mtd, -1); | ||
141 | |||
142 | /* Release the controller and the chip */ | 138 | /* Release the controller and the chip */ |
143 | spin_lock(&chip->controller->lock); | 139 | spin_lock(&chip->controller->lock); |
144 | chip->controller->active = NULL; | 140 | chip->controller->active = NULL; |
@@ -160,7 +156,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) | |||
160 | } | 156 | } |
161 | 157 | ||
162 | /** | 158 | /** |
163 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip | 159 | * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip |
164 | * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip | 160 | * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip |
165 | * @mtd: MTD device structure | 161 | * @mtd: MTD device structure |
166 | * | 162 | * |
@@ -303,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
303 | if (getchip) { | 299 | if (getchip) { |
304 | chipnr = (int)(ofs >> chip->chip_shift); | 300 | chipnr = (int)(ofs >> chip->chip_shift); |
305 | 301 | ||
306 | nand_get_device(chip, mtd, FL_READING); | 302 | nand_get_device(mtd, FL_READING); |
307 | 303 | ||
308 | /* Select the NAND device */ | 304 | /* Select the NAND device */ |
309 | chip->select_chip(mtd, chipnr); | 305 | chip->select_chip(mtd, chipnr); |
@@ -333,8 +329,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
333 | i++; | 329 | i++; |
334 | } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); | 330 | } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); |
335 | 331 | ||
336 | if (getchip) | 332 | if (getchip) { |
333 | chip->select_chip(mtd, -1); | ||
337 | nand_release_device(mtd); | 334 | nand_release_device(mtd); |
335 | } | ||
338 | 336 | ||
339 | return res; | 337 | return res; |
340 | } | 338 | } |
@@ -383,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
383 | struct mtd_oob_ops ops; | 381 | struct mtd_oob_ops ops; |
384 | loff_t wr_ofs = ofs; | 382 | loff_t wr_ofs = ofs; |
385 | 383 | ||
386 | nand_get_device(chip, mtd, FL_WRITING); | 384 | nand_get_device(mtd, FL_WRITING); |
387 | 385 | ||
388 | ops.datbuf = NULL; | 386 | ops.datbuf = NULL; |
389 | ops.oobbuf = buf; | 387 | ops.oobbuf = buf; |
@@ -492,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) | |||
492 | void nand_wait_ready(struct mtd_info *mtd) | 490 | void nand_wait_ready(struct mtd_info *mtd) |
493 | { | 491 | { |
494 | struct nand_chip *chip = mtd->priv; | 492 | struct nand_chip *chip = mtd->priv; |
495 | unsigned long timeo = jiffies + 2; | 493 | unsigned long timeo = jiffies + msecs_to_jiffies(20); |
496 | 494 | ||
497 | /* 400ms timeout */ | 495 | /* 400ms timeout */ |
498 | if (in_interrupt() || oops_in_progress) | 496 | if (in_interrupt() || oops_in_progress) |
@@ -750,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip, | |||
750 | 748 | ||
751 | /** | 749 | /** |
752 | * nand_get_device - [GENERIC] Get chip for selected access | 750 | * nand_get_device - [GENERIC] Get chip for selected access |
753 | * @chip: the nand chip descriptor | ||
754 | * @mtd: MTD device structure | 751 | * @mtd: MTD device structure |
755 | * @new_state: the state which is requested | 752 | * @new_state: the state which is requested |
756 | * | 753 | * |
757 | * Get the device and lock it for exclusive access | 754 | * Get the device and lock it for exclusive access |
758 | */ | 755 | */ |
759 | static int | 756 | static int |
760 | nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | 757 | nand_get_device(struct mtd_info *mtd, int new_state) |
761 | { | 758 | { |
759 | struct nand_chip *chip = mtd->priv; | ||
762 | spinlock_t *lock = &chip->controller->lock; | 760 | spinlock_t *lock = &chip->controller->lock; |
763 | wait_queue_head_t *wq = &chip->controller->wq; | 761 | wait_queue_head_t *wq = &chip->controller->wq; |
764 | DECLARE_WAITQUEUE(wait, current); | 762 | DECLARE_WAITQUEUE(wait, current); |
@@ -865,6 +863,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
865 | led_trigger_event(nand_led_trigger, LED_OFF); | 863 | led_trigger_event(nand_led_trigger, LED_OFF); |
866 | 864 | ||
867 | status = (int)chip->read_byte(mtd); | 865 | status = (int)chip->read_byte(mtd); |
866 | /* This can happen if in case of timeout or buggy dev_ready */ | ||
867 | WARN_ON(!(status & NAND_STATUS_READY)); | ||
868 | return status; | 868 | return status; |
869 | } | 869 | } |
870 | 870 | ||
@@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, | |||
899 | /* Call wait ready function */ | 899 | /* Call wait ready function */ |
900 | status = chip->waitfunc(mtd, chip); | 900 | status = chip->waitfunc(mtd, chip); |
901 | /* See if device thinks it succeeded */ | 901 | /* See if device thinks it succeeded */ |
902 | if (status & 0x01) { | 902 | if (status & NAND_STATUS_FAIL) { |
903 | pr_debug("%s: error status = 0x%08x\n", | 903 | pr_debug("%s: error status = 0x%08x\n", |
904 | __func__, status); | 904 | __func__, status); |
905 | ret = -EIO; | 905 | ret = -EIO; |
@@ -932,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
932 | if (ofs + len == mtd->size) | 932 | if (ofs + len == mtd->size) |
933 | len -= mtd->erasesize; | 933 | len -= mtd->erasesize; |
934 | 934 | ||
935 | nand_get_device(chip, mtd, FL_UNLOCKING); | 935 | nand_get_device(mtd, FL_UNLOCKING); |
936 | 936 | ||
937 | /* Shift to get chip number */ | 937 | /* Shift to get chip number */ |
938 | chipnr = ofs >> chip->chip_shift; | 938 | chipnr = ofs >> chip->chip_shift; |
@@ -950,6 +950,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
950 | ret = __nand_unlock(mtd, ofs, len, 0); | 950 | ret = __nand_unlock(mtd, ofs, len, 0); |
951 | 951 | ||
952 | out: | 952 | out: |
953 | chip->select_chip(mtd, -1); | ||
953 | nand_release_device(mtd); | 954 | nand_release_device(mtd); |
954 | 955 | ||
955 | return ret; | 956 | return ret; |
@@ -981,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
981 | if (check_offs_len(mtd, ofs, len)) | 982 | if (check_offs_len(mtd, ofs, len)) |
982 | ret = -EINVAL; | 983 | ret = -EINVAL; |
983 | 984 | ||
984 | nand_get_device(chip, mtd, FL_LOCKING); | 985 | nand_get_device(mtd, FL_LOCKING); |
985 | 986 | ||
986 | /* Shift to get chip number */ | 987 | /* Shift to get chip number */ |
987 | chipnr = ofs >> chip->chip_shift; | 988 | chipnr = ofs >> chip->chip_shift; |
@@ -1004,7 +1005,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
1004 | /* Call wait ready function */ | 1005 | /* Call wait ready function */ |
1005 | status = chip->waitfunc(mtd, chip); | 1006 | status = chip->waitfunc(mtd, chip); |
1006 | /* See if device thinks it succeeded */ | 1007 | /* See if device thinks it succeeded */ |
1007 | if (status & 0x01) { | 1008 | if (status & NAND_STATUS_FAIL) { |
1008 | pr_debug("%s: error status = 0x%08x\n", | 1009 | pr_debug("%s: error status = 0x%08x\n", |
1009 | __func__, status); | 1010 | __func__, status); |
1010 | ret = -EIO; | 1011 | ret = -EIO; |
@@ -1014,6 +1015,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
1014 | ret = __nand_unlock(mtd, ofs, len, 0x1); | 1015 | ret = __nand_unlock(mtd, ofs, len, 0x1); |
1015 | 1016 | ||
1016 | out: | 1017 | out: |
1018 | chip->select_chip(mtd, -1); | ||
1017 | nand_release_device(mtd); | 1019 | nand_release_device(mtd); |
1018 | 1020 | ||
1019 | return ret; | 1021 | return ret; |
@@ -1550,6 +1552,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1550 | chip->select_chip(mtd, chipnr); | 1552 | chip->select_chip(mtd, chipnr); |
1551 | } | 1553 | } |
1552 | } | 1554 | } |
1555 | chip->select_chip(mtd, -1); | ||
1553 | 1556 | ||
1554 | ops->retlen = ops->len - (size_t) readlen; | 1557 | ops->retlen = ops->len - (size_t) readlen; |
1555 | if (oob) | 1558 | if (oob) |
@@ -1577,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1577 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | 1580 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, |
1578 | size_t *retlen, uint8_t *buf) | 1581 | size_t *retlen, uint8_t *buf) |
1579 | { | 1582 | { |
1580 | struct nand_chip *chip = mtd->priv; | ||
1581 | struct mtd_oob_ops ops; | 1583 | struct mtd_oob_ops ops; |
1582 | int ret; | 1584 | int ret; |
1583 | 1585 | ||
1584 | nand_get_device(chip, mtd, FL_READING); | 1586 | nand_get_device(mtd, FL_READING); |
1585 | ops.len = len; | 1587 | ops.len = len; |
1586 | ops.datbuf = buf; | 1588 | ops.datbuf = buf; |
1587 | ops.oobbuf = NULL; | 1589 | ops.oobbuf = NULL; |
@@ -1804,6 +1806,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1804 | chip->select_chip(mtd, chipnr); | 1806 | chip->select_chip(mtd, chipnr); |
1805 | } | 1807 | } |
1806 | } | 1808 | } |
1809 | chip->select_chip(mtd, -1); | ||
1807 | 1810 | ||
1808 | ops->oobretlen = ops->ooblen - readlen; | 1811 | ops->oobretlen = ops->ooblen - readlen; |
1809 | 1812 | ||
@@ -1827,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1827 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, | 1830 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, |
1828 | struct mtd_oob_ops *ops) | 1831 | struct mtd_oob_ops *ops) |
1829 | { | 1832 | { |
1830 | struct nand_chip *chip = mtd->priv; | ||
1831 | int ret = -ENOTSUPP; | 1833 | int ret = -ENOTSUPP; |
1832 | 1834 | ||
1833 | ops->retlen = 0; | 1835 | ops->retlen = 0; |
@@ -1839,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1839 | return -EINVAL; | 1841 | return -EINVAL; |
1840 | } | 1842 | } |
1841 | 1843 | ||
1842 | nand_get_device(chip, mtd, FL_READING); | 1844 | nand_get_device(mtd, FL_READING); |
1843 | 1845 | ||
1844 | switch (ops->mode) { | 1846 | switch (ops->mode) { |
1845 | case MTD_OPS_PLACE_OOB: | 1847 | case MTD_OPS_PLACE_OOB: |
@@ -2186,8 +2188,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
2186 | chip->select_chip(mtd, chipnr); | 2188 | chip->select_chip(mtd, chipnr); |
2187 | 2189 | ||
2188 | /* Check, if it is write protected */ | 2190 | /* Check, if it is write protected */ |
2189 | if (nand_check_wp(mtd)) | 2191 | if (nand_check_wp(mtd)) { |
2190 | return -EIO; | 2192 | ret = -EIO; |
2193 | goto err_out; | ||
2194 | } | ||
2191 | 2195 | ||
2192 | realpage = (int)(to >> chip->page_shift); | 2196 | realpage = (int)(to >> chip->page_shift); |
2193 | page = realpage & chip->pagemask; | 2197 | page = realpage & chip->pagemask; |
@@ -2199,8 +2203,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
2199 | chip->pagebuf = -1; | 2203 | chip->pagebuf = -1; |
2200 | 2204 | ||
2201 | /* Don't allow multipage oob writes with offset */ | 2205 | /* Don't allow multipage oob writes with offset */ |
2202 | if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) | 2206 | if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { |
2203 | return -EINVAL; | 2207 | ret = -EINVAL; |
2208 | goto err_out; | ||
2209 | } | ||
2204 | 2210 | ||
2205 | while (1) { | 2211 | while (1) { |
2206 | int bytes = mtd->writesize; | 2212 | int bytes = mtd->writesize; |
@@ -2251,6 +2257,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
2251 | ops->retlen = ops->len - writelen; | 2257 | ops->retlen = ops->len - writelen; |
2252 | if (unlikely(oob)) | 2258 | if (unlikely(oob)) |
2253 | ops->oobretlen = ops->ooblen; | 2259 | ops->oobretlen = ops->ooblen; |
2260 | |||
2261 | err_out: | ||
2262 | chip->select_chip(mtd, -1); | ||
2254 | return ret; | 2263 | return ret; |
2255 | } | 2264 | } |
2256 | 2265 | ||
@@ -2302,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
2302 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | 2311 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, |
2303 | size_t *retlen, const uint8_t *buf) | 2312 | size_t *retlen, const uint8_t *buf) |
2304 | { | 2313 | { |
2305 | struct nand_chip *chip = mtd->priv; | ||
2306 | struct mtd_oob_ops ops; | 2314 | struct mtd_oob_ops ops; |
2307 | int ret; | 2315 | int ret; |
2308 | 2316 | ||
2309 | nand_get_device(chip, mtd, FL_WRITING); | 2317 | nand_get_device(mtd, FL_WRITING); |
2310 | ops.len = len; | 2318 | ops.len = len; |
2311 | ops.datbuf = (uint8_t *)buf; | 2319 | ops.datbuf = (uint8_t *)buf; |
2312 | ops.oobbuf = NULL; | 2320 | ops.oobbuf = NULL; |
@@ -2377,8 +2385,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
2377 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | 2385 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
2378 | 2386 | ||
2379 | /* Check, if it is write protected */ | 2387 | /* Check, if it is write protected */ |
2380 | if (nand_check_wp(mtd)) | 2388 | if (nand_check_wp(mtd)) { |
2389 | chip->select_chip(mtd, -1); | ||
2381 | return -EROFS; | 2390 | return -EROFS; |
2391 | } | ||
2382 | 2392 | ||
2383 | /* Invalidate the page cache, if we write to the cached page */ | 2393 | /* Invalidate the page cache, if we write to the cached page */ |
2384 | if (page == chip->pagebuf) | 2394 | if (page == chip->pagebuf) |
@@ -2391,6 +2401,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
2391 | else | 2401 | else |
2392 | status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); | 2402 | status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); |
2393 | 2403 | ||
2404 | chip->select_chip(mtd, -1); | ||
2405 | |||
2394 | if (status) | 2406 | if (status) |
2395 | return status; | 2407 | return status; |
2396 | 2408 | ||
@@ -2408,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
2408 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, | 2420 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, |
2409 | struct mtd_oob_ops *ops) | 2421 | struct mtd_oob_ops *ops) |
2410 | { | 2422 | { |
2411 | struct nand_chip *chip = mtd->priv; | ||
2412 | int ret = -ENOTSUPP; | 2423 | int ret = -ENOTSUPP; |
2413 | 2424 | ||
2414 | ops->retlen = 0; | 2425 | ops->retlen = 0; |
@@ -2420,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, | |||
2420 | return -EINVAL; | 2431 | return -EINVAL; |
2421 | } | 2432 | } |
2422 | 2433 | ||
2423 | nand_get_device(chip, mtd, FL_WRITING); | 2434 | nand_get_device(mtd, FL_WRITING); |
2424 | 2435 | ||
2425 | switch (ops->mode) { | 2436 | switch (ops->mode) { |
2426 | case MTD_OPS_PLACE_OOB: | 2437 | case MTD_OPS_PLACE_OOB: |
@@ -2513,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2513 | return -EINVAL; | 2524 | return -EINVAL; |
2514 | 2525 | ||
2515 | /* Grab the lock and see if the device is available */ | 2526 | /* Grab the lock and see if the device is available */ |
2516 | nand_get_device(chip, mtd, FL_ERASING); | 2527 | nand_get_device(mtd, FL_ERASING); |
2517 | 2528 | ||
2518 | /* Shift to get first page */ | 2529 | /* Shift to get first page */ |
2519 | page = (int)(instr->addr >> chip->page_shift); | 2530 | page = (int)(instr->addr >> chip->page_shift); |
@@ -2623,6 +2634,7 @@ erase_exit: | |||
2623 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; | 2634 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; |
2624 | 2635 | ||
2625 | /* Deselect and wake up anyone waiting on the device */ | 2636 | /* Deselect and wake up anyone waiting on the device */ |
2637 | chip->select_chip(mtd, -1); | ||
2626 | nand_release_device(mtd); | 2638 | nand_release_device(mtd); |
2627 | 2639 | ||
2628 | /* Do call back function */ | 2640 | /* Do call back function */ |
@@ -2658,12 +2670,10 @@ erase_exit: | |||
2658 | */ | 2670 | */ |
2659 | static void nand_sync(struct mtd_info *mtd) | 2671 | static void nand_sync(struct mtd_info *mtd) |
2660 | { | 2672 | { |
2661 | struct nand_chip *chip = mtd->priv; | ||
2662 | |||
2663 | pr_debug("%s: called\n", __func__); | 2673 | pr_debug("%s: called\n", __func__); |
2664 | 2674 | ||
2665 | /* Grab the lock and see if the device is available */ | 2675 | /* Grab the lock and see if the device is available */ |
2666 | nand_get_device(chip, mtd, FL_SYNCING); | 2676 | nand_get_device(mtd, FL_SYNCING); |
2667 | /* Release it and go back */ | 2677 | /* Release it and go back */ |
2668 | nand_release_device(mtd); | 2678 | nand_release_device(mtd); |
2669 | } | 2679 | } |
@@ -2749,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, | |||
2749 | */ | 2759 | */ |
2750 | static int nand_suspend(struct mtd_info *mtd) | 2760 | static int nand_suspend(struct mtd_info *mtd) |
2751 | { | 2761 | { |
2752 | struct nand_chip *chip = mtd->priv; | 2762 | return nand_get_device(mtd, FL_PM_SUSPENDED); |
2753 | |||
2754 | return nand_get_device(chip, mtd, FL_PM_SUSPENDED); | ||
2755 | } | 2763 | } |
2756 | 2764 | ||
2757 | /** | 2765 | /** |
@@ -2849,6 +2857,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
2849 | int i; | 2857 | int i; |
2850 | int val; | 2858 | int val; |
2851 | 2859 | ||
2860 | /* ONFI need to be probed in 8 bits mode */ | ||
2861 | WARN_ON(chip->options & NAND_BUSWIDTH_16); | ||
2852 | /* Try ONFI for unknown chip or LP */ | 2862 | /* Try ONFI for unknown chip or LP */ |
2853 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); | 2863 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); |
2854 | if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || | 2864 | if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || |
@@ -2913,7 +2923,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
2913 | * | 2923 | * |
2914 | * Check if an ID string is repeated within a given sequence of bytes at | 2924 | * Check if an ID string is repeated within a given sequence of bytes at |
2915 | * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a | 2925 | * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a |
2916 | * period of 2). This is a helper function for nand_id_len(). Returns non-zero | 2926 | * period of 3). This is a helper function for nand_id_len(). Returns non-zero |
2917 | * if the repetition has a period of @period; otherwise, returns zero. | 2927 | * if the repetition has a period of @period; otherwise, returns zero. |
2918 | */ | 2928 | */ |
2919 | static int nand_id_has_period(u8 *id_data, int arrlen, int period) | 2929 | static int nand_id_has_period(u8 *id_data, int arrlen, int period) |
@@ -3242,11 +3252,15 @@ ident_done: | |||
3242 | break; | 3252 | break; |
3243 | } | 3253 | } |
3244 | 3254 | ||
3245 | /* | 3255 | if (chip->options & NAND_BUSWIDTH_AUTO) { |
3246 | * Check, if buswidth is correct. Hardware drivers should set | 3256 | WARN_ON(chip->options & NAND_BUSWIDTH_16); |
3247 | * chip correct! | 3257 | chip->options |= busw; |
3248 | */ | 3258 | nand_set_defaults(chip, busw); |
3249 | if (busw != (chip->options & NAND_BUSWIDTH_16)) { | 3259 | } else if (busw != (chip->options & NAND_BUSWIDTH_16)) { |
3260 | /* | ||
3261 | * Check, if buswidth is correct. Hardware drivers should set | ||
3262 | * chip correct! | ||
3263 | */ | ||
3250 | pr_info("NAND device: Manufacturer ID:" | 3264 | pr_info("NAND device: Manufacturer ID:" |
3251 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, | 3265 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, |
3252 | *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); | 3266 | *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); |
@@ -3285,10 +3299,10 @@ ident_done: | |||
3285 | chip->cmdfunc = nand_command_lp; | 3299 | chip->cmdfunc = nand_command_lp; |
3286 | 3300 | ||
3287 | pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," | 3301 | pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," |
3288 | " page size: %d, OOB size: %d\n", | 3302 | " %dMiB, page size: %d, OOB size: %d\n", |
3289 | *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, | 3303 | *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, |
3290 | chip->onfi_version ? chip->onfi_params.model : type->name, | 3304 | chip->onfi_version ? chip->onfi_params.model : type->name, |
3291 | mtd->writesize, mtd->oobsize); | 3305 | (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize); |
3292 | 3306 | ||
3293 | return type; | 3307 | return type; |
3294 | } | 3308 | } |
@@ -3327,6 +3341,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
3327 | return PTR_ERR(type); | 3341 | return PTR_ERR(type); |
3328 | } | 3342 | } |
3329 | 3343 | ||
3344 | chip->select_chip(mtd, -1); | ||
3345 | |||
3330 | /* Check for a chip array */ | 3346 | /* Check for a chip array */ |
3331 | for (i = 1; i < maxchips; i++) { | 3347 | for (i = 1; i < maxchips; i++) { |
3332 | chip->select_chip(mtd, i); | 3348 | chip->select_chip(mtd, i); |
@@ -3336,8 +3352,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
3336 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 3352 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
3337 | /* Read manufacturer and device IDs */ | 3353 | /* Read manufacturer and device IDs */ |
3338 | if (nand_maf_id != chip->read_byte(mtd) || | 3354 | if (nand_maf_id != chip->read_byte(mtd) || |
3339 | nand_dev_id != chip->read_byte(mtd)) | 3355 | nand_dev_id != chip->read_byte(mtd)) { |
3356 | chip->select_chip(mtd, -1); | ||
3340 | break; | 3357 | break; |
3358 | } | ||
3359 | chip->select_chip(mtd, -1); | ||
3341 | } | 3360 | } |
3342 | if (i > 1) | 3361 | if (i > 1) |
3343 | pr_info("%d NAND chips detected\n", i); | 3362 | pr_info("%d NAND chips detected\n", i); |
@@ -3596,9 +3615,6 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
3596 | /* Initialize state */ | 3615 | /* Initialize state */ |
3597 | chip->state = FL_READY; | 3616 | chip->state = FL_READY; |
3598 | 3617 | ||
3599 | /* De-select the device */ | ||
3600 | chip->select_chip(mtd, -1); | ||
3601 | |||
3602 | /* Invalidate the pagebuffer reference */ | 3618 | /* Invalidate the pagebuffer reference */ |
3603 | chip->pagebuf = -1; | 3619 | chip->pagebuf = -1; |
3604 | 3620 | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c3c13e64a2f0..818b65c85d12 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/sched.h> | 42 | #include <linux/sched.h> |
43 | #include <linux/fs.h> | 43 | #include <linux/fs.h> |
44 | #include <linux/pagemap.h> | 44 | #include <linux/pagemap.h> |
45 | #include <linux/seq_file.h> | ||
46 | #include <linux/debugfs.h> | ||
45 | 47 | ||
46 | /* Default simulator parameters values */ | 48 | /* Default simulator parameters values */ |
47 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 49 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -105,7 +107,6 @@ static char *weakblocks = NULL; | |||
105 | static char *weakpages = NULL; | 107 | static char *weakpages = NULL; |
106 | static unsigned int bitflips = 0; | 108 | static unsigned int bitflips = 0; |
107 | static char *gravepages = NULL; | 109 | static char *gravepages = NULL; |
108 | static unsigned int rptwear = 0; | ||
109 | static unsigned int overridesize = 0; | 110 | static unsigned int overridesize = 0; |
110 | static char *cache_file = NULL; | 111 | static char *cache_file = NULL; |
111 | static unsigned int bbt; | 112 | static unsigned int bbt; |
@@ -130,7 +131,6 @@ module_param(weakblocks, charp, 0400); | |||
130 | module_param(weakpages, charp, 0400); | 131 | module_param(weakpages, charp, 0400); |
131 | module_param(bitflips, uint, 0400); | 132 | module_param(bitflips, uint, 0400); |
132 | module_param(gravepages, charp, 0400); | 133 | module_param(gravepages, charp, 0400); |
133 | module_param(rptwear, uint, 0400); | ||
134 | module_param(overridesize, uint, 0400); | 134 | module_param(overridesize, uint, 0400); |
135 | module_param(cache_file, charp, 0400); | 135 | module_param(cache_file, charp, 0400); |
136 | module_param(bbt, uint, 0400); | 136 | module_param(bbt, uint, 0400); |
@@ -162,7 +162,6 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z | |||
162 | MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" | 162 | MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" |
163 | " separated by commas e.g. 1401:2 means page 1401" | 163 | " separated by commas e.g. 1401:2 means page 1401" |
164 | " can be read only twice before failing"); | 164 | " can be read only twice before failing"); |
165 | MODULE_PARM_DESC(rptwear, "Number of erases between reporting wear, if not zero"); | ||
166 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | 165 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " |
167 | "The size is specified in erase blocks and as the exponent of a power of two" | 166 | "The size is specified in erase blocks and as the exponent of a power of two" |
168 | " e.g. 5 means a size of 32 erase blocks"); | 167 | " e.g. 5 means a size of 32 erase blocks"); |
@@ -286,6 +285,11 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " | |||
286 | /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ | 285 | /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ |
287 | #define NS_MAX_HELD_PAGES 16 | 286 | #define NS_MAX_HELD_PAGES 16 |
288 | 287 | ||
288 | struct nandsim_debug_info { | ||
289 | struct dentry *dfs_root; | ||
290 | struct dentry *dfs_wear_report; | ||
291 | }; | ||
292 | |||
289 | /* | 293 | /* |
290 | * A union to represent flash memory contents and flash buffer. | 294 | * A union to represent flash memory contents and flash buffer. |
291 | */ | 295 | */ |
@@ -365,6 +369,8 @@ struct nandsim { | |||
365 | void *file_buf; | 369 | void *file_buf; |
366 | struct page *held_pages[NS_MAX_HELD_PAGES]; | 370 | struct page *held_pages[NS_MAX_HELD_PAGES]; |
367 | int held_cnt; | 371 | int held_cnt; |
372 | |||
373 | struct nandsim_debug_info dbg; | ||
368 | }; | 374 | }; |
369 | 375 | ||
370 | /* | 376 | /* |
@@ -442,11 +448,123 @@ static LIST_HEAD(grave_pages); | |||
442 | static unsigned long *erase_block_wear = NULL; | 448 | static unsigned long *erase_block_wear = NULL; |
443 | static unsigned int wear_eb_count = 0; | 449 | static unsigned int wear_eb_count = 0; |
444 | static unsigned long total_wear = 0; | 450 | static unsigned long total_wear = 0; |
445 | static unsigned int rptwear_cnt = 0; | ||
446 | 451 | ||
447 | /* MTD structure for NAND controller */ | 452 | /* MTD structure for NAND controller */ |
448 | static struct mtd_info *nsmtd; | 453 | static struct mtd_info *nsmtd; |
449 | 454 | ||
455 | static int nandsim_debugfs_show(struct seq_file *m, void *private) | ||
456 | { | ||
457 | unsigned long wmin = -1, wmax = 0, avg; | ||
458 | unsigned long deciles[10], decile_max[10], tot = 0; | ||
459 | unsigned int i; | ||
460 | |||
461 | /* Calc wear stats */ | ||
462 | for (i = 0; i < wear_eb_count; ++i) { | ||
463 | unsigned long wear = erase_block_wear[i]; | ||
464 | if (wear < wmin) | ||
465 | wmin = wear; | ||
466 | if (wear > wmax) | ||
467 | wmax = wear; | ||
468 | tot += wear; | ||
469 | } | ||
470 | |||
471 | for (i = 0; i < 9; ++i) { | ||
472 | deciles[i] = 0; | ||
473 | decile_max[i] = (wmax * (i + 1) + 5) / 10; | ||
474 | } | ||
475 | deciles[9] = 0; | ||
476 | decile_max[9] = wmax; | ||
477 | for (i = 0; i < wear_eb_count; ++i) { | ||
478 | int d; | ||
479 | unsigned long wear = erase_block_wear[i]; | ||
480 | for (d = 0; d < 10; ++d) | ||
481 | if (wear <= decile_max[d]) { | ||
482 | deciles[d] += 1; | ||
483 | break; | ||
484 | } | ||
485 | } | ||
486 | avg = tot / wear_eb_count; | ||
487 | |||
488 | /* Output wear report */ | ||
489 | seq_printf(m, "Total numbers of erases: %lu\n", tot); | ||
490 | seq_printf(m, "Number of erase blocks: %u\n", wear_eb_count); | ||
491 | seq_printf(m, "Average number of erases: %lu\n", avg); | ||
492 | seq_printf(m, "Maximum number of erases: %lu\n", wmax); | ||
493 | seq_printf(m, "Minimum number of erases: %lu\n", wmin); | ||
494 | for (i = 0; i < 10; ++i) { | ||
495 | unsigned long from = (i ? decile_max[i - 1] + 1 : 0); | ||
496 | if (from > decile_max[i]) | ||
497 | continue; | ||
498 | seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n", | ||
499 | from, | ||
500 | decile_max[i], | ||
501 | deciles[i]); | ||
502 | } | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static int nandsim_debugfs_open(struct inode *inode, struct file *file) | ||
508 | { | ||
509 | return single_open(file, nandsim_debugfs_show, inode->i_private); | ||
510 | } | ||
511 | |||
512 | static const struct file_operations dfs_fops = { | ||
513 | .open = nandsim_debugfs_open, | ||
514 | .read = seq_read, | ||
515 | .llseek = seq_lseek, | ||
516 | .release = single_release, | ||
517 | }; | ||
518 | |||
519 | /** | ||
520 | * nandsim_debugfs_create - initialize debugfs | ||
521 | * @dev: nandsim device description object | ||
522 | * | ||
523 | * This function creates all debugfs files for UBI device @ubi. Returns zero in | ||
524 | * case of success and a negative error code in case of failure. | ||
525 | */ | ||
526 | static int nandsim_debugfs_create(struct nandsim *dev) | ||
527 | { | ||
528 | struct nandsim_debug_info *dbg = &dev->dbg; | ||
529 | struct dentry *dent; | ||
530 | int err; | ||
531 | |||
532 | if (!IS_ENABLED(CONFIG_DEBUG_FS)) | ||
533 | return 0; | ||
534 | |||
535 | dent = debugfs_create_dir("nandsim", NULL); | ||
536 | if (IS_ERR_OR_NULL(dent)) { | ||
537 | int err = dent ? -ENODEV : PTR_ERR(dent); | ||
538 | |||
539 | NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n", | ||
540 | err); | ||
541 | return err; | ||
542 | } | ||
543 | dbg->dfs_root = dent; | ||
544 | |||
545 | dent = debugfs_create_file("wear_report", S_IRUSR, | ||
546 | dbg->dfs_root, dev, &dfs_fops); | ||
547 | if (IS_ERR_OR_NULL(dent)) | ||
548 | goto out_remove; | ||
549 | dbg->dfs_wear_report = dent; | ||
550 | |||
551 | return 0; | ||
552 | |||
553 | out_remove: | ||
554 | debugfs_remove_recursive(dbg->dfs_root); | ||
555 | err = dent ? PTR_ERR(dent) : -ENODEV; | ||
556 | return err; | ||
557 | } | ||
558 | |||
559 | /** | ||
560 | * nandsim_debugfs_remove - destroy all debugfs files | ||
561 | */ | ||
562 | static void nandsim_debugfs_remove(struct nandsim *ns) | ||
563 | { | ||
564 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | ||
565 | debugfs_remove_recursive(ns->dbg.dfs_root); | ||
566 | } | ||
567 | |||
450 | /* | 568 | /* |
451 | * Allocate array of page pointers, create slab allocation for an array | 569 | * Allocate array of page pointers, create slab allocation for an array |
452 | * and initialize the array by NULL pointers. | 570 | * and initialize the array by NULL pointers. |
@@ -911,8 +1029,6 @@ static int setup_wear_reporting(struct mtd_info *mtd) | |||
911 | { | 1029 | { |
912 | size_t mem; | 1030 | size_t mem; |
913 | 1031 | ||
914 | if (!rptwear) | ||
915 | return 0; | ||
916 | wear_eb_count = div_u64(mtd->size, mtd->erasesize); | 1032 | wear_eb_count = div_u64(mtd->size, mtd->erasesize); |
917 | mem = wear_eb_count * sizeof(unsigned long); | 1033 | mem = wear_eb_count * sizeof(unsigned long); |
918 | if (mem / sizeof(unsigned long) != wear_eb_count) { | 1034 | if (mem / sizeof(unsigned long) != wear_eb_count) { |
@@ -929,64 +1045,18 @@ static int setup_wear_reporting(struct mtd_info *mtd) | |||
929 | 1045 | ||
930 | static void update_wear(unsigned int erase_block_no) | 1046 | static void update_wear(unsigned int erase_block_no) |
931 | { | 1047 | { |
932 | unsigned long wmin = -1, wmax = 0, avg; | ||
933 | unsigned long deciles[10], decile_max[10], tot = 0; | ||
934 | unsigned int i; | ||
935 | |||
936 | if (!erase_block_wear) | 1048 | if (!erase_block_wear) |
937 | return; | 1049 | return; |
938 | total_wear += 1; | 1050 | total_wear += 1; |
1051 | /* | ||
1052 | * TODO: Notify this through a debugfs entry, | ||
1053 | * instead of showing an error message. | ||
1054 | */ | ||
939 | if (total_wear == 0) | 1055 | if (total_wear == 0) |
940 | NS_ERR("Erase counter total overflow\n"); | 1056 | NS_ERR("Erase counter total overflow\n"); |
941 | erase_block_wear[erase_block_no] += 1; | 1057 | erase_block_wear[erase_block_no] += 1; |
942 | if (erase_block_wear[erase_block_no] == 0) | 1058 | if (erase_block_wear[erase_block_no] == 0) |
943 | NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); | 1059 | NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); |
944 | rptwear_cnt += 1; | ||
945 | if (rptwear_cnt < rptwear) | ||
946 | return; | ||
947 | rptwear_cnt = 0; | ||
948 | /* Calc wear stats */ | ||
949 | for (i = 0; i < wear_eb_count; ++i) { | ||
950 | unsigned long wear = erase_block_wear[i]; | ||
951 | if (wear < wmin) | ||
952 | wmin = wear; | ||
953 | if (wear > wmax) | ||
954 | wmax = wear; | ||
955 | tot += wear; | ||
956 | } | ||
957 | for (i = 0; i < 9; ++i) { | ||
958 | deciles[i] = 0; | ||
959 | decile_max[i] = (wmax * (i + 1) + 5) / 10; | ||
960 | } | ||
961 | deciles[9] = 0; | ||
962 | decile_max[9] = wmax; | ||
963 | for (i = 0; i < wear_eb_count; ++i) { | ||
964 | int d; | ||
965 | unsigned long wear = erase_block_wear[i]; | ||
966 | for (d = 0; d < 10; ++d) | ||
967 | if (wear <= decile_max[d]) { | ||
968 | deciles[d] += 1; | ||
969 | break; | ||
970 | } | ||
971 | } | ||
972 | avg = tot / wear_eb_count; | ||
973 | /* Output wear report */ | ||
974 | NS_INFO("*** Wear Report ***\n"); | ||
975 | NS_INFO("Total numbers of erases: %lu\n", tot); | ||
976 | NS_INFO("Number of erase blocks: %u\n", wear_eb_count); | ||
977 | NS_INFO("Average number of erases: %lu\n", avg); | ||
978 | NS_INFO("Maximum number of erases: %lu\n", wmax); | ||
979 | NS_INFO("Minimum number of erases: %lu\n", wmin); | ||
980 | for (i = 0; i < 10; ++i) { | ||
981 | unsigned long from = (i ? decile_max[i - 1] + 1 : 0); | ||
982 | if (from > decile_max[i]) | ||
983 | continue; | ||
984 | NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", | ||
985 | from, | ||
986 | decile_max[i], | ||
987 | deciles[i]); | ||
988 | } | ||
989 | NS_INFO("*** End of Wear Report ***\n"); | ||
990 | } | 1060 | } |
991 | 1061 | ||
992 | /* | 1062 | /* |
@@ -2327,6 +2397,9 @@ static int __init ns_init_module(void) | |||
2327 | if ((retval = setup_wear_reporting(nsmtd)) != 0) | 2397 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |
2328 | goto err_exit; | 2398 | goto err_exit; |
2329 | 2399 | ||
2400 | if ((retval = nandsim_debugfs_create(nand)) != 0) | ||
2401 | goto err_exit; | ||
2402 | |||
2330 | if ((retval = init_nandsim(nsmtd)) != 0) | 2403 | if ((retval = init_nandsim(nsmtd)) != 0) |
2331 | goto err_exit; | 2404 | goto err_exit; |
2332 | 2405 | ||
@@ -2366,6 +2439,7 @@ static void __exit ns_cleanup_module(void) | |||
2366 | struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv; | 2439 | struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv; |
2367 | int i; | 2440 | int i; |
2368 | 2441 | ||
2442 | nandsim_debugfs_remove(ns); | ||
2369 | free_nandsim(ns); /* Free nandsim private resources */ | 2443 | free_nandsim(ns); /* Free nandsim private resources */ |
2370 | nand_release(nsmtd); /* Unregister driver */ | 2444 | nand_release(nsmtd); /* Unregister driver */ |
2371 | for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) | 2445 | for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 5fd3f010e3ae..8e148f1478fd 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -197,7 +197,7 @@ err: | |||
197 | return ret; | 197 | return ret; |
198 | } | 198 | } |
199 | 199 | ||
200 | static int __devinit ndfc_probe(struct platform_device *ofdev) | 200 | static int ndfc_probe(struct platform_device *ofdev) |
201 | { | 201 | { |
202 | struct ndfc_controller *ndfc; | 202 | struct ndfc_controller *ndfc; |
203 | const __be32 *reg; | 203 | const __be32 *reg; |
@@ -256,7 +256,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev) | |||
256 | return 0; | 256 | return 0; |
257 | } | 257 | } |
258 | 258 | ||
259 | static int __devexit ndfc_remove(struct platform_device *ofdev) | 259 | static int ndfc_remove(struct platform_device *ofdev) |
260 | { | 260 | { |
261 | struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); | 261 | struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); |
262 | 262 | ||
@@ -279,7 +279,7 @@ static struct platform_driver ndfc_driver = { | |||
279 | .of_match_table = ndfc_match, | 279 | .of_match_table = ndfc_match, |
280 | }, | 280 | }, |
281 | .probe = ndfc_probe, | 281 | .probe = ndfc_probe, |
282 | .remove = __devexit_p(ndfc_remove), | 282 | .remove = ndfc_remove, |
283 | }; | 283 | }; |
284 | 284 | ||
285 | module_platform_driver(ndfc_driver); | 285 | module_platform_driver(ndfc_driver); |
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c deleted file mode 100644 index 9ee0c4edfacf..000000000000 --- a/drivers/mtd/nand/nomadik_nand.c +++ /dev/null | |||
@@ -1,235 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/nomadik_nand.c | ||
3 | * | ||
4 | * Overview: | ||
5 | * Driver for on-board NAND flash on Nomadik Platforms | ||
6 | * | ||
7 | * Copyright © 2007 STMicroelectronics Pvt. Ltd. | ||
8 | * Author: Sachin Verma <sachin.verma@st.com> | ||
9 | * | ||
10 | * Copyright © 2009 Alessandro Rubini | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/mtd/mtd.h> | ||
28 | #include <linux/mtd/nand.h> | ||
29 | #include <linux/mtd/nand_ecc.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/mtd/partitions.h> | ||
32 | #include <linux/io.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/platform_data/mtd-nomadik-nand.h> | ||
35 | #include <mach/fsmc.h> | ||
36 | |||
37 | #include <mtd/mtd-abi.h> | ||
38 | |||
39 | struct nomadik_nand_host { | ||
40 | struct mtd_info mtd; | ||
41 | struct nand_chip nand; | ||
42 | void __iomem *data_va; | ||
43 | void __iomem *cmd_va; | ||
44 | void __iomem *addr_va; | ||
45 | struct nand_bbt_descr *bbt_desc; | ||
46 | }; | ||
47 | |||
48 | static struct nand_ecclayout nomadik_ecc_layout = { | ||
49 | .eccbytes = 3 * 4, | ||
50 | .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */ | ||
51 | 0x02, 0x03, 0x04, | ||
52 | 0x12, 0x13, 0x14, | ||
53 | 0x22, 0x23, 0x24, | ||
54 | 0x32, 0x33, 0x34}, | ||
55 | /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */ | ||
56 | .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, | ||
57 | }; | ||
58 | |||
59 | static void nomadik_ecc_control(struct mtd_info *mtd, int mode) | ||
60 | { | ||
61 | /* No need to enable hw ecc, it's on by default */ | ||
62 | } | ||
63 | |||
64 | static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
65 | { | ||
66 | struct nand_chip *nand = mtd->priv; | ||
67 | struct nomadik_nand_host *host = nand->priv; | ||
68 | |||
69 | if (cmd == NAND_CMD_NONE) | ||
70 | return; | ||
71 | |||
72 | if (ctrl & NAND_CLE) | ||
73 | writeb(cmd, host->cmd_va); | ||
74 | else | ||
75 | writeb(cmd, host->addr_va); | ||
76 | } | ||
77 | |||
78 | static int nomadik_nand_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; | ||
81 | struct nomadik_nand_host *host; | ||
82 | struct mtd_info *mtd; | ||
83 | struct nand_chip *nand; | ||
84 | struct resource *res; | ||
85 | int ret = 0; | ||
86 | |||
87 | /* Allocate memory for the device structure (and zero it) */ | ||
88 | host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL); | ||
89 | if (!host) { | ||
90 | dev_err(&pdev->dev, "Failed to allocate device structure.\n"); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | /* Call the client's init function, if any */ | ||
95 | if (pdata->init) | ||
96 | ret = pdata->init(); | ||
97 | if (ret < 0) { | ||
98 | dev_err(&pdev->dev, "Init function failed\n"); | ||
99 | goto err; | ||
100 | } | ||
101 | |||
102 | /* ioremap three regions */ | ||
103 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); | ||
104 | if (!res) { | ||
105 | ret = -EIO; | ||
106 | goto err_unmap; | ||
107 | } | ||
108 | host->addr_va = ioremap(res->start, resource_size(res)); | ||
109 | |||
110 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); | ||
111 | if (!res) { | ||
112 | ret = -EIO; | ||
113 | goto err_unmap; | ||
114 | } | ||
115 | host->data_va = ioremap(res->start, resource_size(res)); | ||
116 | |||
117 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); | ||
118 | if (!res) { | ||
119 | ret = -EIO; | ||
120 | goto err_unmap; | ||
121 | } | ||
122 | host->cmd_va = ioremap(res->start, resource_size(res)); | ||
123 | |||
124 | if (!host->addr_va || !host->data_va || !host->cmd_va) { | ||
125 | ret = -ENOMEM; | ||
126 | goto err_unmap; | ||
127 | } | ||
128 | |||
129 | /* Link all private pointers */ | ||
130 | mtd = &host->mtd; | ||
131 | nand = &host->nand; | ||
132 | mtd->priv = nand; | ||
133 | nand->priv = host; | ||
134 | |||
135 | host->mtd.owner = THIS_MODULE; | ||
136 | nand->IO_ADDR_R = host->data_va; | ||
137 | nand->IO_ADDR_W = host->data_va; | ||
138 | nand->cmd_ctrl = nomadik_cmd_ctrl; | ||
139 | |||
140 | /* | ||
141 | * This stanza declares ECC_HW but uses soft routines. It's because | ||
142 | * HW claims to make the calculation but not the correction. However, | ||
143 | * I haven't managed to get the desired data out of it until now. | ||
144 | */ | ||
145 | nand->ecc.mode = NAND_ECC_SOFT; | ||
146 | nand->ecc.layout = &nomadik_ecc_layout; | ||
147 | nand->ecc.hwctl = nomadik_ecc_control; | ||
148 | nand->ecc.size = 512; | ||
149 | nand->ecc.bytes = 3; | ||
150 | |||
151 | nand->options = pdata->options; | ||
152 | |||
153 | /* | ||
154 | * Scan to find existence of the device | ||
155 | */ | ||
156 | if (nand_scan(&host->mtd, 1)) { | ||
157 | ret = -ENXIO; | ||
158 | goto err_unmap; | ||
159 | } | ||
160 | |||
161 | mtd_device_register(&host->mtd, pdata->parts, pdata->nparts); | ||
162 | |||
163 | platform_set_drvdata(pdev, host); | ||
164 | return 0; | ||
165 | |||
166 | err_unmap: | ||
167 | if (host->cmd_va) | ||
168 | iounmap(host->cmd_va); | ||
169 | if (host->data_va) | ||
170 | iounmap(host->data_va); | ||
171 | if (host->addr_va) | ||
172 | iounmap(host->addr_va); | ||
173 | err: | ||
174 | kfree(host); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Clean up routine | ||
180 | */ | ||
181 | static int nomadik_nand_remove(struct platform_device *pdev) | ||
182 | { | ||
183 | struct nomadik_nand_host *host = platform_get_drvdata(pdev); | ||
184 | struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; | ||
185 | |||
186 | if (pdata->exit) | ||
187 | pdata->exit(); | ||
188 | |||
189 | if (host) { | ||
190 | nand_release(&host->mtd); | ||
191 | iounmap(host->cmd_va); | ||
192 | iounmap(host->data_va); | ||
193 | iounmap(host->addr_va); | ||
194 | kfree(host); | ||
195 | } | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int nomadik_nand_suspend(struct device *dev) | ||
200 | { | ||
201 | struct nomadik_nand_host *host = dev_get_drvdata(dev); | ||
202 | int ret = 0; | ||
203 | if (host) | ||
204 | ret = mtd_suspend(&host->mtd); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static int nomadik_nand_resume(struct device *dev) | ||
209 | { | ||
210 | struct nomadik_nand_host *host = dev_get_drvdata(dev); | ||
211 | if (host) | ||
212 | mtd_resume(&host->mtd); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static const struct dev_pm_ops nomadik_nand_pm_ops = { | ||
217 | .suspend = nomadik_nand_suspend, | ||
218 | .resume = nomadik_nand_resume, | ||
219 | }; | ||
220 | |||
221 | static struct platform_driver nomadik_nand_driver = { | ||
222 | .probe = nomadik_nand_probe, | ||
223 | .remove = nomadik_nand_remove, | ||
224 | .driver = { | ||
225 | .owner = THIS_MODULE, | ||
226 | .name = "nomadik_nand", | ||
227 | .pm = &nomadik_nand_pm_ops, | ||
228 | }, | ||
229 | }; | ||
230 | |||
231 | module_platform_driver(nomadik_nand_driver); | ||
232 | |||
233 | MODULE_LICENSE("GPL"); | ||
234 | MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)"); | ||
235 | MODULE_DESCRIPTION("NAND driver for Nomadik Platform"); | ||
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 94dc46bc118c..a6191198d259 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c | |||
@@ -246,7 +246,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand) | |||
246 | spin_unlock(&nand->lock); | 246 | spin_unlock(&nand->lock); |
247 | } | 247 | } |
248 | 248 | ||
249 | static int __devinit nuc900_nand_probe(struct platform_device *pdev) | 249 | static int nuc900_nand_probe(struct platform_device *pdev) |
250 | { | 250 | { |
251 | struct nuc900_nand *nuc900_nand; | 251 | struct nuc900_nand *nuc900_nand; |
252 | struct nand_chip *chip; | 252 | struct nand_chip *chip; |
@@ -317,7 +317,7 @@ fail1: kfree(nuc900_nand); | |||
317 | return retval; | 317 | return retval; |
318 | } | 318 | } |
319 | 319 | ||
320 | static int __devexit nuc900_nand_remove(struct platform_device *pdev) | 320 | static int nuc900_nand_remove(struct platform_device *pdev) |
321 | { | 321 | { |
322 | struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); | 322 | struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); |
323 | struct resource *res; | 323 | struct resource *res; |
@@ -340,7 +340,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev) | |||
340 | 340 | ||
341 | static struct platform_driver nuc900_nand_driver = { | 341 | static struct platform_driver nuc900_nand_driver = { |
342 | .probe = nuc900_nand_probe, | 342 | .probe = nuc900_nand_probe, |
343 | .remove = __devexit_p(nuc900_nand_remove), | 343 | .remove = nuc900_nand_remove, |
344 | .driver = { | 344 | .driver = { |
345 | .name = "nuc900-fmi", | 345 | .name = "nuc900-fmi", |
346 | .owner = THIS_MODULE, | 346 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1f34ba104ef4..0002d5e94f0d 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -1323,7 +1323,7 @@ static void omap3_free_bch(struct mtd_info *mtd) | |||
1323 | } | 1323 | } |
1324 | #endif /* CONFIG_MTD_NAND_OMAP_BCH */ | 1324 | #endif /* CONFIG_MTD_NAND_OMAP_BCH */ |
1325 | 1325 | ||
1326 | static int __devinit omap_nand_probe(struct platform_device *pdev) | 1326 | static int omap_nand_probe(struct platform_device *pdev) |
1327 | { | 1327 | { |
1328 | struct omap_nand_info *info; | 1328 | struct omap_nand_info *info; |
1329 | struct omap_nand_platform_data *pdata; | 1329 | struct omap_nand_platform_data *pdata; |
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index aefaf8cd31ef..cd72b9299f6b 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c | |||
@@ -194,7 +194,7 @@ no_res: | |||
194 | return ret; | 194 | return ret; |
195 | } | 195 | } |
196 | 196 | ||
197 | static int __devexit orion_nand_remove(struct platform_device *pdev) | 197 | static int orion_nand_remove(struct platform_device *pdev) |
198 | { | 198 | { |
199 | struct mtd_info *mtd = platform_get_drvdata(pdev); | 199 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
200 | struct nand_chip *nc = mtd->priv; | 200 | struct nand_chip *nc = mtd->priv; |
@@ -223,7 +223,7 @@ static struct of_device_id orion_nand_of_match_table[] = { | |||
223 | #endif | 223 | #endif |
224 | 224 | ||
225 | static struct platform_driver orion_nand_driver = { | 225 | static struct platform_driver orion_nand_driver = { |
226 | .remove = __devexit_p(orion_nand_remove), | 226 | .remove = orion_nand_remove, |
227 | .driver = { | 227 | .driver = { |
228 | .name = "orion_nand", | 228 | .name = "orion_nand", |
229 | .owner = THIS_MODULE, | 229 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 1440e51cedcc..5a67082c07ee 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c | |||
@@ -89,7 +89,7 @@ int pasemi_device_ready(struct mtd_info *mtd) | |||
89 | return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); | 89 | return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); |
90 | } | 90 | } |
91 | 91 | ||
92 | static int __devinit pasemi_nand_probe(struct platform_device *ofdev) | 92 | static int pasemi_nand_probe(struct platform_device *ofdev) |
93 | { | 93 | { |
94 | struct pci_dev *pdev; | 94 | struct pci_dev *pdev; |
95 | struct device_node *np = ofdev->dev.of_node; | 95 | struct device_node *np = ofdev->dev.of_node; |
@@ -184,7 +184,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) | |||
184 | return err; | 184 | return err; |
185 | } | 185 | } |
186 | 186 | ||
187 | static int __devexit pasemi_nand_remove(struct platform_device *ofdev) | 187 | static int pasemi_nand_remove(struct platform_device *ofdev) |
188 | { | 188 | { |
189 | struct nand_chip *chip; | 189 | struct nand_chip *chip; |
190 | 190 | ||
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index a47ee68a0cfa..c004566a9ad2 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c | |||
@@ -28,7 +28,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL }; | |||
28 | /* | 28 | /* |
29 | * Probe for the NAND device. | 29 | * Probe for the NAND device. |
30 | */ | 30 | */ |
31 | static int __devinit plat_nand_probe(struct platform_device *pdev) | 31 | static int plat_nand_probe(struct platform_device *pdev) |
32 | { | 32 | { |
33 | struct platform_nand_data *pdata = pdev->dev.platform_data; | 33 | struct platform_nand_data *pdata = pdev->dev.platform_data; |
34 | struct mtd_part_parser_data ppdata; | 34 | struct mtd_part_parser_data ppdata; |
@@ -134,7 +134,7 @@ out_free: | |||
134 | /* | 134 | /* |
135 | * Remove a NAND device. | 135 | * Remove a NAND device. |
136 | */ | 136 | */ |
137 | static int __devexit plat_nand_remove(struct platform_device *pdev) | 137 | static int plat_nand_remove(struct platform_device *pdev) |
138 | { | 138 | { |
139 | struct plat_nand_data *data = platform_get_drvdata(pdev); | 139 | struct plat_nand_data *data = platform_get_drvdata(pdev); |
140 | struct platform_nand_data *pdata = pdev->dev.platform_data; | 140 | struct platform_nand_data *pdata = pdev->dev.platform_data; |
@@ -160,7 +160,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match); | |||
160 | 160 | ||
161 | static struct platform_driver plat_nand_driver = { | 161 | static struct platform_driver plat_nand_driver = { |
162 | .probe = plat_nand_probe, | 162 | .probe = plat_nand_probe, |
163 | .remove = __devexit_p(plat_nand_remove), | 163 | .remove = plat_nand_remove, |
164 | .driver = { | 164 | .driver = { |
165 | .name = "gen_nand", | 165 | .name = "gen_nand", |
166 | .owner = THIS_MODULE, | 166 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 79ded48e7427..df954b4dcba2 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -730,11 +730,14 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
730 | struct s3c2410_nand_mtd *mtd, | 730 | struct s3c2410_nand_mtd *mtd, |
731 | struct s3c2410_nand_set *set) | 731 | struct s3c2410_nand_set *set) |
732 | { | 732 | { |
733 | if (set) | 733 | if (set) { |
734 | mtd->mtd.name = set->name; | 734 | mtd->mtd.name = set->name; |
735 | 735 | ||
736 | return mtd_device_parse_register(&mtd->mtd, NULL, NULL, | 736 | return mtd_device_parse_register(&mtd->mtd, NULL, NULL, |
737 | set->partitions, set->nr_partitions); | 737 | set->partitions, set->nr_partitions); |
738 | } | ||
739 | |||
740 | return -ENODEV; | ||
738 | } | 741 | } |
739 | 742 | ||
740 | /** | 743 | /** |
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index f48ac5d80bbf..57b3971c9c0a 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -23,11 +23,18 @@ | |||
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/completion.h> | ||
26 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/dmaengine.h> | ||
29 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
28 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/of.h> | ||
33 | #include <linux/of_device.h> | ||
34 | #include <linux/of_mtd.h> | ||
29 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
30 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
37 | #include <linux/sh_dma.h> | ||
31 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
32 | #include <linux/string.h> | 39 | #include <linux/string.h> |
33 | 40 | ||
@@ -106,6 +113,84 @@ static void wait_completion(struct sh_flctl *flctl) | |||
106 | writeb(0x0, FLTRCR(flctl)); | 113 | writeb(0x0, FLTRCR(flctl)); |
107 | } | 114 | } |
108 | 115 | ||
116 | static void flctl_dma_complete(void *param) | ||
117 | { | ||
118 | struct sh_flctl *flctl = param; | ||
119 | |||
120 | complete(&flctl->dma_complete); | ||
121 | } | ||
122 | |||
123 | static void flctl_release_dma(struct sh_flctl *flctl) | ||
124 | { | ||
125 | if (flctl->chan_fifo0_rx) { | ||
126 | dma_release_channel(flctl->chan_fifo0_rx); | ||
127 | flctl->chan_fifo0_rx = NULL; | ||
128 | } | ||
129 | if (flctl->chan_fifo0_tx) { | ||
130 | dma_release_channel(flctl->chan_fifo0_tx); | ||
131 | flctl->chan_fifo0_tx = NULL; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static void flctl_setup_dma(struct sh_flctl *flctl) | ||
136 | { | ||
137 | dma_cap_mask_t mask; | ||
138 | struct dma_slave_config cfg; | ||
139 | struct platform_device *pdev = flctl->pdev; | ||
140 | struct sh_flctl_platform_data *pdata = pdev->dev.platform_data; | ||
141 | int ret; | ||
142 | |||
143 | if (!pdata) | ||
144 | return; | ||
145 | |||
146 | if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0) | ||
147 | return; | ||
148 | |||
149 | /* We can only either use DMA for both Tx and Rx or not use it at all */ | ||
150 | dma_cap_zero(mask); | ||
151 | dma_cap_set(DMA_SLAVE, mask); | ||
152 | |||
153 | flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter, | ||
154 | (void *)pdata->slave_id_fifo0_tx); | ||
155 | dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__, | ||
156 | flctl->chan_fifo0_tx); | ||
157 | |||
158 | if (!flctl->chan_fifo0_tx) | ||
159 | return; | ||
160 | |||
161 | memset(&cfg, 0, sizeof(cfg)); | ||
162 | cfg.slave_id = pdata->slave_id_fifo0_tx; | ||
163 | cfg.direction = DMA_MEM_TO_DEV; | ||
164 | cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl); | ||
165 | cfg.src_addr = 0; | ||
166 | ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg); | ||
167 | if (ret < 0) | ||
168 | goto err; | ||
169 | |||
170 | flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter, | ||
171 | (void *)pdata->slave_id_fifo0_rx); | ||
172 | dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__, | ||
173 | flctl->chan_fifo0_rx); | ||
174 | |||
175 | if (!flctl->chan_fifo0_rx) | ||
176 | goto err; | ||
177 | |||
178 | cfg.slave_id = pdata->slave_id_fifo0_rx; | ||
179 | cfg.direction = DMA_DEV_TO_MEM; | ||
180 | cfg.dst_addr = 0; | ||
181 | cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl); | ||
182 | ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg); | ||
183 | if (ret < 0) | ||
184 | goto err; | ||
185 | |||
186 | init_completion(&flctl->dma_complete); | ||
187 | |||
188 | return; | ||
189 | |||
190 | err: | ||
191 | flctl_release_dma(flctl); | ||
192 | } | ||
193 | |||
109 | static void set_addr(struct mtd_info *mtd, int column, int page_addr) | 194 | static void set_addr(struct mtd_info *mtd, int column, int page_addr) |
110 | { | 195 | { |
111 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 196 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
@@ -225,7 +310,7 @@ static enum flctl_ecc_res_t wait_recfifo_ready | |||
225 | 310 | ||
226 | for (i = 0; i < 3; i++) { | 311 | for (i = 0; i < 3; i++) { |
227 | uint8_t org; | 312 | uint8_t org; |
228 | int index; | 313 | unsigned int index; |
229 | 314 | ||
230 | data = readl(ecc_reg[i]); | 315 | data = readl(ecc_reg[i]); |
231 | 316 | ||
@@ -261,6 +346,70 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl) | |||
261 | timeout_error(flctl, __func__); | 346 | timeout_error(flctl, __func__); |
262 | } | 347 | } |
263 | 348 | ||
349 | static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, | ||
350 | int len, enum dma_data_direction dir) | ||
351 | { | ||
352 | struct dma_async_tx_descriptor *desc = NULL; | ||
353 | struct dma_chan *chan; | ||
354 | enum dma_transfer_direction tr_dir; | ||
355 | dma_addr_t dma_addr; | ||
356 | dma_cookie_t cookie = -EINVAL; | ||
357 | uint32_t reg; | ||
358 | int ret; | ||
359 | |||
360 | if (dir == DMA_FROM_DEVICE) { | ||
361 | chan = flctl->chan_fifo0_rx; | ||
362 | tr_dir = DMA_DEV_TO_MEM; | ||
363 | } else { | ||
364 | chan = flctl->chan_fifo0_tx; | ||
365 | tr_dir = DMA_MEM_TO_DEV; | ||
366 | } | ||
367 | |||
368 | dma_addr = dma_map_single(chan->device->dev, buf, len, dir); | ||
369 | |||
370 | if (dma_addr) | ||
371 | desc = dmaengine_prep_slave_single(chan, dma_addr, len, | ||
372 | tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
373 | |||
374 | if (desc) { | ||
375 | reg = readl(FLINTDMACR(flctl)); | ||
376 | reg |= DREQ0EN; | ||
377 | writel(reg, FLINTDMACR(flctl)); | ||
378 | |||
379 | desc->callback = flctl_dma_complete; | ||
380 | desc->callback_param = flctl; | ||
381 | cookie = dmaengine_submit(desc); | ||
382 | |||
383 | dma_async_issue_pending(chan); | ||
384 | } else { | ||
385 | /* DMA failed, fall back to PIO */ | ||
386 | flctl_release_dma(flctl); | ||
387 | dev_warn(&flctl->pdev->dev, | ||
388 | "DMA failed, falling back to PIO\n"); | ||
389 | ret = -EIO; | ||
390 | goto out; | ||
391 | } | ||
392 | |||
393 | ret = | ||
394 | wait_for_completion_timeout(&flctl->dma_complete, | ||
395 | msecs_to_jiffies(3000)); | ||
396 | |||
397 | if (ret <= 0) { | ||
398 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); | ||
399 | dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n"); | ||
400 | } | ||
401 | |||
402 | out: | ||
403 | reg = readl(FLINTDMACR(flctl)); | ||
404 | reg &= ~DREQ0EN; | ||
405 | writel(reg, FLINTDMACR(flctl)); | ||
406 | |||
407 | dma_unmap_single(chan->device->dev, dma_addr, len, dir); | ||
408 | |||
409 | /* ret > 0 is success */ | ||
410 | return ret; | ||
411 | } | ||
412 | |||
264 | static void read_datareg(struct sh_flctl *flctl, int offset) | 413 | static void read_datareg(struct sh_flctl *flctl, int offset) |
265 | { | 414 | { |
266 | unsigned long data; | 415 | unsigned long data; |
@@ -279,11 +428,20 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | |||
279 | 428 | ||
280 | len_4align = (rlen + 3) / 4; | 429 | len_4align = (rlen + 3) / 4; |
281 | 430 | ||
431 | /* initiate DMA transfer */ | ||
432 | if (flctl->chan_fifo0_rx && rlen >= 32 && | ||
433 | flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0) | ||
434 | goto convert; /* DMA success */ | ||
435 | |||
436 | /* do polling transfer */ | ||
282 | for (i = 0; i < len_4align; i++) { | 437 | for (i = 0; i < len_4align; i++) { |
283 | wait_rfifo_ready(flctl); | 438 | wait_rfifo_ready(flctl); |
284 | buf[i] = readl(FLDTFIFO(flctl)); | 439 | buf[i] = readl(FLDTFIFO(flctl)); |
285 | buf[i] = be32_to_cpu(buf[i]); | ||
286 | } | 440 | } |
441 | |||
442 | convert: | ||
443 | for (i = 0; i < len_4align; i++) | ||
444 | buf[i] = be32_to_cpu(buf[i]); | ||
287 | } | 445 | } |
288 | 446 | ||
289 | static enum flctl_ecc_res_t read_ecfiforeg | 447 | static enum flctl_ecc_res_t read_ecfiforeg |
@@ -305,28 +463,39 @@ static enum flctl_ecc_res_t read_ecfiforeg | |||
305 | return res; | 463 | return res; |
306 | } | 464 | } |
307 | 465 | ||
308 | static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | 466 | static void write_fiforeg(struct sh_flctl *flctl, int rlen, |
467 | unsigned int offset) | ||
309 | { | 468 | { |
310 | int i, len_4align; | 469 | int i, len_4align; |
311 | unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; | 470 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; |
312 | void *fifo_addr = (void *)FLDTFIFO(flctl); | ||
313 | 471 | ||
314 | len_4align = (rlen + 3) / 4; | 472 | len_4align = (rlen + 3) / 4; |
315 | for (i = 0; i < len_4align; i++) { | 473 | for (i = 0; i < len_4align; i++) { |
316 | wait_wfifo_ready(flctl); | 474 | wait_wfifo_ready(flctl); |
317 | writel(cpu_to_be32(data[i]), fifo_addr); | 475 | writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl)); |
318 | } | 476 | } |
319 | } | 477 | } |
320 | 478 | ||
321 | static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | 479 | static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, |
480 | unsigned int offset) | ||
322 | { | 481 | { |
323 | int i, len_4align; | 482 | int i, len_4align; |
324 | unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; | 483 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; |
325 | 484 | ||
326 | len_4align = (rlen + 3) / 4; | 485 | len_4align = (rlen + 3) / 4; |
486 | |||
487 | for (i = 0; i < len_4align; i++) | ||
488 | buf[i] = cpu_to_be32(buf[i]); | ||
489 | |||
490 | /* initiate DMA transfer */ | ||
491 | if (flctl->chan_fifo0_tx && rlen >= 32 && | ||
492 | flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0) | ||
493 | return; /* DMA success */ | ||
494 | |||
495 | /* do polling transfer */ | ||
327 | for (i = 0; i < len_4align; i++) { | 496 | for (i = 0; i < len_4align; i++) { |
328 | wait_wecfifo_ready(flctl); | 497 | wait_wecfifo_ready(flctl); |
329 | writel(cpu_to_be32(data[i]), FLECFIFO(flctl)); | 498 | writel(buf[i], FLECFIFO(flctl)); |
330 | } | 499 | } |
331 | } | 500 | } |
332 | 501 | ||
@@ -750,41 +919,35 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) | |||
750 | static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 919 | static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
751 | { | 920 | { |
752 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 921 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
753 | int index = flctl->index; | ||
754 | 922 | ||
755 | memcpy(&flctl->done_buff[index], buf, len); | 923 | memcpy(&flctl->done_buff[flctl->index], buf, len); |
756 | flctl->index += len; | 924 | flctl->index += len; |
757 | } | 925 | } |
758 | 926 | ||
759 | static uint8_t flctl_read_byte(struct mtd_info *mtd) | 927 | static uint8_t flctl_read_byte(struct mtd_info *mtd) |
760 | { | 928 | { |
761 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 929 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
762 | int index = flctl->index; | ||
763 | uint8_t data; | 930 | uint8_t data; |
764 | 931 | ||
765 | data = flctl->done_buff[index]; | 932 | data = flctl->done_buff[flctl->index]; |
766 | flctl->index++; | 933 | flctl->index++; |
767 | return data; | 934 | return data; |
768 | } | 935 | } |
769 | 936 | ||
770 | static uint16_t flctl_read_word(struct mtd_info *mtd) | 937 | static uint16_t flctl_read_word(struct mtd_info *mtd) |
771 | { | 938 | { |
772 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 939 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
773 | int index = flctl->index; | 940 | uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index]; |
774 | uint16_t data; | ||
775 | uint16_t *buf = (uint16_t *)&flctl->done_buff[index]; | ||
776 | 941 | ||
777 | data = *buf; | 942 | flctl->index += 2; |
778 | flctl->index += 2; | 943 | return *buf; |
779 | return data; | ||
780 | } | 944 | } |
781 | 945 | ||
782 | static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | 946 | static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
783 | { | 947 | { |
784 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 948 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
785 | int index = flctl->index; | ||
786 | 949 | ||
787 | memcpy(buf, &flctl->done_buff[index], len); | 950 | memcpy(buf, &flctl->done_buff[flctl->index], len); |
788 | flctl->index += len; | 951 | flctl->index += len; |
789 | } | 952 | } |
790 | 953 | ||
@@ -858,7 +1021,74 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id) | |||
858 | return IRQ_HANDLED; | 1021 | return IRQ_HANDLED; |
859 | } | 1022 | } |
860 | 1023 | ||
861 | static int __devinit flctl_probe(struct platform_device *pdev) | 1024 | #ifdef CONFIG_OF |
1025 | struct flctl_soc_config { | ||
1026 | unsigned long flcmncr_val; | ||
1027 | unsigned has_hwecc:1; | ||
1028 | unsigned use_holden:1; | ||
1029 | }; | ||
1030 | |||
1031 | static struct flctl_soc_config flctl_sh7372_config = { | ||
1032 | .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL, | ||
1033 | .has_hwecc = 1, | ||
1034 | .use_holden = 1, | ||
1035 | }; | ||
1036 | |||
1037 | static const struct of_device_id of_flctl_match[] = { | ||
1038 | { .compatible = "renesas,shmobile-flctl-sh7372", | ||
1039 | .data = &flctl_sh7372_config }, | ||
1040 | {}, | ||
1041 | }; | ||
1042 | MODULE_DEVICE_TABLE(of, of_flctl_match); | ||
1043 | |||
1044 | static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) | ||
1045 | { | ||
1046 | const struct of_device_id *match; | ||
1047 | struct flctl_soc_config *config; | ||
1048 | struct sh_flctl_platform_data *pdata; | ||
1049 | struct device_node *dn = dev->of_node; | ||
1050 | int ret; | ||
1051 | |||
1052 | match = of_match_device(of_flctl_match, dev); | ||
1053 | if (match) | ||
1054 | config = (struct flctl_soc_config *)match->data; | ||
1055 | else { | ||
1056 | dev_err(dev, "%s: no OF configuration attached\n", __func__); | ||
1057 | return NULL; | ||
1058 | } | ||
1059 | |||
1060 | pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data), | ||
1061 | GFP_KERNEL); | ||
1062 | if (!pdata) { | ||
1063 | dev_err(dev, "%s: failed to allocate config data\n", __func__); | ||
1064 | return NULL; | ||
1065 | } | ||
1066 | |||
1067 | /* set SoC specific options */ | ||
1068 | pdata->flcmncr_val = config->flcmncr_val; | ||
1069 | pdata->has_hwecc = config->has_hwecc; | ||
1070 | pdata->use_holden = config->use_holden; | ||
1071 | |||
1072 | /* parse user defined options */ | ||
1073 | ret = of_get_nand_bus_width(dn); | ||
1074 | if (ret == 16) | ||
1075 | pdata->flcmncr_val |= SEL_16BIT; | ||
1076 | else if (ret != 8) { | ||
1077 | dev_err(dev, "%s: invalid bus width\n", __func__); | ||
1078 | return NULL; | ||
1079 | } | ||
1080 | |||
1081 | return pdata; | ||
1082 | } | ||
1083 | #else /* CONFIG_OF */ | ||
1084 | #define of_flctl_match NULL | ||
1085 | static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) | ||
1086 | { | ||
1087 | return NULL; | ||
1088 | } | ||
1089 | #endif /* CONFIG_OF */ | ||
1090 | |||
1091 | static int flctl_probe(struct platform_device *pdev) | ||
862 | { | 1092 | { |
863 | struct resource *res; | 1093 | struct resource *res; |
864 | struct sh_flctl *flctl; | 1094 | struct sh_flctl *flctl; |
@@ -867,12 +1097,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
867 | struct sh_flctl_platform_data *pdata; | 1097 | struct sh_flctl_platform_data *pdata; |
868 | int ret = -ENXIO; | 1098 | int ret = -ENXIO; |
869 | int irq; | 1099 | int irq; |
870 | 1100 | struct mtd_part_parser_data ppdata = {}; | |
871 | pdata = pdev->dev.platform_data; | ||
872 | if (pdata == NULL) { | ||
873 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
874 | return -EINVAL; | ||
875 | } | ||
876 | 1101 | ||
877 | flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); | 1102 | flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); |
878 | if (!flctl) { | 1103 | if (!flctl) { |
@@ -904,6 +1129,17 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
904 | goto err_flste; | 1129 | goto err_flste; |
905 | } | 1130 | } |
906 | 1131 | ||
1132 | if (pdev->dev.of_node) | ||
1133 | pdata = flctl_parse_dt(&pdev->dev); | ||
1134 | else | ||
1135 | pdata = pdev->dev.platform_data; | ||
1136 | |||
1137 | if (!pdata) { | ||
1138 | dev_err(&pdev->dev, "no setup data defined\n"); | ||
1139 | ret = -EINVAL; | ||
1140 | goto err_pdata; | ||
1141 | } | ||
1142 | |||
907 | platform_set_drvdata(pdev, flctl); | 1143 | platform_set_drvdata(pdev, flctl); |
908 | flctl_mtd = &flctl->mtd; | 1144 | flctl_mtd = &flctl->mtd; |
909 | nand = &flctl->chip; | 1145 | nand = &flctl->chip; |
@@ -932,6 +1168,8 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
932 | pm_runtime_enable(&pdev->dev); | 1168 | pm_runtime_enable(&pdev->dev); |
933 | pm_runtime_resume(&pdev->dev); | 1169 | pm_runtime_resume(&pdev->dev); |
934 | 1170 | ||
1171 | flctl_setup_dma(flctl); | ||
1172 | |||
935 | ret = nand_scan_ident(flctl_mtd, 1, NULL); | 1173 | ret = nand_scan_ident(flctl_mtd, 1, NULL); |
936 | if (ret) | 1174 | if (ret) |
937 | goto err_chip; | 1175 | goto err_chip; |
@@ -944,12 +1182,16 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
944 | if (ret) | 1182 | if (ret) |
945 | goto err_chip; | 1183 | goto err_chip; |
946 | 1184 | ||
947 | mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); | 1185 | ppdata.of_node = pdev->dev.of_node; |
1186 | ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts, | ||
1187 | pdata->nr_parts); | ||
948 | 1188 | ||
949 | return 0; | 1189 | return 0; |
950 | 1190 | ||
951 | err_chip: | 1191 | err_chip: |
1192 | flctl_release_dma(flctl); | ||
952 | pm_runtime_disable(&pdev->dev); | 1193 | pm_runtime_disable(&pdev->dev); |
1194 | err_pdata: | ||
953 | free_irq(irq, flctl); | 1195 | free_irq(irq, flctl); |
954 | err_flste: | 1196 | err_flste: |
955 | iounmap(flctl->reg); | 1197 | iounmap(flctl->reg); |
@@ -958,10 +1200,11 @@ err_iomap: | |||
958 | return ret; | 1200 | return ret; |
959 | } | 1201 | } |
960 | 1202 | ||
961 | static int __devexit flctl_remove(struct platform_device *pdev) | 1203 | static int flctl_remove(struct platform_device *pdev) |
962 | { | 1204 | { |
963 | struct sh_flctl *flctl = platform_get_drvdata(pdev); | 1205 | struct sh_flctl *flctl = platform_get_drvdata(pdev); |
964 | 1206 | ||
1207 | flctl_release_dma(flctl); | ||
965 | nand_release(&flctl->mtd); | 1208 | nand_release(&flctl->mtd); |
966 | pm_runtime_disable(&pdev->dev); | 1209 | pm_runtime_disable(&pdev->dev); |
967 | free_irq(platform_get_irq(pdev, 0), flctl); | 1210 | free_irq(platform_get_irq(pdev, 0), flctl); |
@@ -976,6 +1219,7 @@ static struct platform_driver flctl_driver = { | |||
976 | .driver = { | 1219 | .driver = { |
977 | .name = "sh_flctl", | 1220 | .name = "sh_flctl", |
978 | .owner = THIS_MODULE, | 1221 | .owner = THIS_MODULE, |
1222 | .of_match_table = of_flctl_match, | ||
979 | }, | 1223 | }, |
980 | }; | 1224 | }; |
981 | 1225 | ||
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 3421e3762a5a..127bc4271821 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -106,7 +106,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, | |||
106 | /* | 106 | /* |
107 | * Main initialization routine | 107 | * Main initialization routine |
108 | */ | 108 | */ |
109 | static int __devinit sharpsl_nand_probe(struct platform_device *pdev) | 109 | static int sharpsl_nand_probe(struct platform_device *pdev) |
110 | { | 110 | { |
111 | struct nand_chip *this; | 111 | struct nand_chip *this; |
112 | struct resource *r; | 112 | struct resource *r; |
@@ -205,7 +205,7 @@ err_get_res: | |||
205 | /* | 205 | /* |
206 | * Clean up routine | 206 | * Clean up routine |
207 | */ | 207 | */ |
208 | static int __devexit sharpsl_nand_remove(struct platform_device *pdev) | 208 | static int sharpsl_nand_remove(struct platform_device *pdev) |
209 | { | 209 | { |
210 | struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); | 210 | struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); |
211 | 211 | ||
@@ -228,7 +228,7 @@ static struct platform_driver sharpsl_nand_driver = { | |||
228 | .owner = THIS_MODULE, | 228 | .owner = THIS_MODULE, |
229 | }, | 229 | }, |
230 | .probe = sharpsl_nand_probe, | 230 | .probe = sharpsl_nand_probe, |
231 | .remove = __devexit_p(sharpsl_nand_remove), | 231 | .remove = sharpsl_nand_remove, |
232 | }; | 232 | }; |
233 | 233 | ||
234 | module_platform_driver(sharpsl_nand_driver); | 234 | module_platform_driver(sharpsl_nand_driver); |
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index f3f28fafbf7a..09dde7d27178 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c | |||
@@ -140,7 +140,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd) | |||
140 | /* | 140 | /* |
141 | * Probe for the NAND device. | 141 | * Probe for the NAND device. |
142 | */ | 142 | */ |
143 | static int __devinit socrates_nand_probe(struct platform_device *ofdev) | 143 | static int socrates_nand_probe(struct platform_device *ofdev) |
144 | { | 144 | { |
145 | struct socrates_nand_host *host; | 145 | struct socrates_nand_host *host; |
146 | struct mtd_info *mtd; | 146 | struct mtd_info *mtd; |
@@ -220,7 +220,7 @@ out: | |||
220 | /* | 220 | /* |
221 | * Remove a NAND device. | 221 | * Remove a NAND device. |
222 | */ | 222 | */ |
223 | static int __devexit socrates_nand_remove(struct platform_device *ofdev) | 223 | static int socrates_nand_remove(struct platform_device *ofdev) |
224 | { | 224 | { |
225 | struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); | 225 | struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); |
226 | struct mtd_info *mtd = &host->mtd; | 226 | struct mtd_info *mtd = &host->mtd; |
@@ -251,7 +251,7 @@ static struct platform_driver socrates_nand_driver = { | |||
251 | .of_match_table = socrates_nand_match, | 251 | .of_match_table = socrates_nand_match, |
252 | }, | 252 | }, |
253 | .probe = socrates_nand_probe, | 253 | .probe = socrates_nand_probe, |
254 | .remove = __devexit_p(socrates_nand_remove), | 254 | .remove = socrates_nand_remove, |
255 | }; | 255 | }; |
256 | 256 | ||
257 | module_platform_driver(socrates_nand_driver); | 257 | module_platform_driver(socrates_nand_driver); |