diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-06-08 07:21:27 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-06-08 07:21:27 -0400 |
commit | e635a01ea0a16cf7cd31ecd2305870385dca9be6 (patch) | |
tree | c7153e7dee5caf6ac90d85694ff27e4d0b606290 /drivers/mtd/nand | |
parent | 143070e74630b9557e1bb64d899ff2cc5a1dcb48 (diff) | |
parent | 947391cfbaa3b08558844c0b187bcd0223c3f660 (diff) |
Merge branch 'next-mtd' of git://aeryn.fluff.org.uk/bjdooks/linux
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 40 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 259 |
2 files changed, 199 insertions, 100 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index da41ea82941a..76beea40d2cf 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -842,6 +842,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
842 | break; | 842 | break; |
843 | 843 | ||
844 | case NAND_CMD_READID: | 844 | case NAND_CMD_READID: |
845 | host->col_addr = 0; | ||
845 | send_read_id(host); | 846 | send_read_id(host); |
846 | break; | 847 | break; |
847 | 848 | ||
@@ -878,6 +879,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
878 | mtd->priv = this; | 879 | mtd->priv = this; |
879 | mtd->owner = THIS_MODULE; | 880 | mtd->owner = THIS_MODULE; |
880 | mtd->dev.parent = &pdev->dev; | 881 | mtd->dev.parent = &pdev->dev; |
882 | mtd->name = "mxc_nand"; | ||
881 | 883 | ||
882 | /* 50 us command delay time */ | 884 | /* 50 us command delay time */ |
883 | this->chip_delay = 5; | 885 | this->chip_delay = 5; |
@@ -893,8 +895,10 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
893 | this->verify_buf = mxc_nand_verify_buf; | 895 | this->verify_buf = mxc_nand_verify_buf; |
894 | 896 | ||
895 | host->clk = clk_get(&pdev->dev, "nfc"); | 897 | host->clk = clk_get(&pdev->dev, "nfc"); |
896 | if (IS_ERR(host->clk)) | 898 | if (IS_ERR(host->clk)) { |
899 | err = PTR_ERR(host->clk); | ||
897 | goto eclk; | 900 | goto eclk; |
901 | } | ||
898 | 902 | ||
899 | clk_enable(host->clk); | 903 | clk_enable(host->clk); |
900 | host->clk_act = 1; | 904 | host->clk_act = 1; |
@@ -907,7 +911,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
907 | 911 | ||
908 | host->regs = ioremap(res->start, res->end - res->start + 1); | 912 | host->regs = ioremap(res->start, res->end - res->start + 1); |
909 | if (!host->regs) { | 913 | if (!host->regs) { |
910 | err = -EIO; | 914 | err = -ENOMEM; |
911 | goto eres; | 915 | goto eres; |
912 | } | 916 | } |
913 | 917 | ||
@@ -1053,25 +1057,35 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
1053 | #ifdef CONFIG_PM | 1057 | #ifdef CONFIG_PM |
1054 | static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) | 1058 | static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) |
1055 | { | 1059 | { |
1056 | struct mtd_info *info = platform_get_drvdata(pdev); | 1060 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
1061 | struct nand_chip *nand_chip = mtd->priv; | ||
1062 | struct mxc_nand_host *host = nand_chip->priv; | ||
1057 | int ret = 0; | 1063 | int ret = 0; |
1058 | 1064 | ||
1059 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n"); | 1065 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n"); |
1060 | 1066 | if (mtd) { | |
1061 | /* Disable the NFC clock */ | 1067 | ret = mtd->suspend(mtd); |
1062 | clk_disable(nfc_clk); /* FIXME */ | 1068 | /* Disable the NFC clock */ |
1069 | clk_disable(host->clk); | ||
1070 | } | ||
1063 | 1071 | ||
1064 | return ret; | 1072 | return ret; |
1065 | } | 1073 | } |
1066 | 1074 | ||
1067 | static int mxcnd_resume(struct platform_device *pdev) | 1075 | static int mxcnd_resume(struct platform_device *pdev) |
1068 | { | 1076 | { |
1069 | struct mtd_info *info = platform_get_drvdata(pdev); | 1077 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
1078 | struct nand_chip *nand_chip = mtd->priv; | ||
1079 | struct mxc_nand_host *host = nand_chip->priv; | ||
1070 | int ret = 0; | 1080 | int ret = 0; |
1071 | 1081 | ||
1072 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n"); | 1082 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n"); |
1073 | /* Enable the NFC clock */ | 1083 | |
1074 | clk_enable(nfc_clk); /* FIXME */ | 1084 | if (mtd) { |
1085 | /* Enable the NFC clock */ | ||
1086 | clk_enable(host->clk); | ||
1087 | mtd->resume(mtd); | ||
1088 | } | ||
1075 | 1089 | ||
1076 | return ret; | 1090 | return ret; |
1077 | } | 1091 | } |
@@ -1092,13 +1106,7 @@ static struct platform_driver mxcnd_driver = { | |||
1092 | 1106 | ||
1093 | static int __init mxc_nd_init(void) | 1107 | static int __init mxc_nd_init(void) |
1094 | { | 1108 | { |
1095 | /* Register the device driver structure. */ | 1109 | return platform_driver_probe(&mxcnd_driver, mxcnd_probe); |
1096 | pr_info("MXC MTD nand Driver\n"); | ||
1097 | if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) { | ||
1098 | printk(KERN_ERR "Driver register failed for mxcnd_driver\n"); | ||
1099 | return -ENODEV; | ||
1100 | } | ||
1101 | return 0; | ||
1102 | } | 1110 | } |
1103 | 1111 | ||
1104 | static void __exit mxc_nd_cleanup(void) | 1112 | static void __exit mxc_nd_cleanup(void) |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 776756e4ebe5..01a105eda3f4 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -74,6 +74,14 @@ static struct nand_ecclayout nand_hw_eccoob = { | |||
74 | 74 | ||
75 | struct s3c2410_nand_info; | 75 | struct s3c2410_nand_info; |
76 | 76 | ||
77 | /** | ||
78 | * struct s3c2410_nand_mtd - driver MTD structure | ||
79 | * @mtd: The MTD instance to pass to the MTD layer. | ||
80 | * @chip: The NAND chip information. | ||
81 | * @set: The platform information supplied for this set of NAND chips. | ||
82 | * @info: Link back to the hardware information. | ||
83 | * @scan_res: The result from calling nand_scan_ident(). | ||
84 | */ | ||
77 | struct s3c2410_nand_mtd { | 85 | struct s3c2410_nand_mtd { |
78 | struct mtd_info mtd; | 86 | struct mtd_info mtd; |
79 | struct nand_chip chip; | 87 | struct nand_chip chip; |
@@ -90,6 +98,21 @@ enum s3c_cpu_type { | |||
90 | 98 | ||
91 | /* overview of the s3c2410 nand state */ | 99 | /* overview of the s3c2410 nand state */ |
92 | 100 | ||
101 | /** | ||
102 | * struct s3c2410_nand_info - NAND controller state. | ||
103 | * @mtds: An array of MTD instances on this controoler. | ||
104 | * @platform: The platform data for this board. | ||
105 | * @device: The platform device we bound to. | ||
106 | * @area: The IO area resource that came from request_mem_region(). | ||
107 | * @clk: The clock resource for this controller. | ||
108 | * @regs: The area mapped for the hardware registers described by @area. | ||
109 | * @sel_reg: Pointer to the register controlling the NAND selection. | ||
110 | * @sel_bit: The bit in @sel_reg to select the NAND chip. | ||
111 | * @mtd_count: The number of MTDs created from this controller. | ||
112 | * @save_sel: The contents of @sel_reg to be saved over suspend. | ||
113 | * @clk_rate: The clock rate from @clk. | ||
114 | * @cpu_type: The exact type of this controller. | ||
115 | */ | ||
93 | struct s3c2410_nand_info { | 116 | struct s3c2410_nand_info { |
94 | /* mtd info */ | 117 | /* mtd info */ |
95 | struct nand_hw_control controller; | 118 | struct nand_hw_control controller; |
@@ -145,12 +168,19 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info) | |||
145 | 168 | ||
146 | #define NS_IN_KHZ 1000000 | 169 | #define NS_IN_KHZ 1000000 |
147 | 170 | ||
171 | /** | ||
172 | * s3c_nand_calc_rate - calculate timing data. | ||
173 | * @wanted: The cycle time in nanoseconds. | ||
174 | * @clk: The clock rate in kHz. | ||
175 | * @max: The maximum divider value. | ||
176 | * | ||
177 | * Calculate the timing value from the given parameters. | ||
178 | */ | ||
148 | static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) | 179 | static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) |
149 | { | 180 | { |
150 | int result; | 181 | int result; |
151 | 182 | ||
152 | result = (wanted * clk) / NS_IN_KHZ; | 183 | result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ); |
153 | result++; | ||
154 | 184 | ||
155 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); | 185 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); |
156 | 186 | ||
@@ -169,13 +199,21 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
169 | 199 | ||
170 | /* controller setup */ | 200 | /* controller setup */ |
171 | 201 | ||
202 | /** | ||
203 | * s3c2410_nand_setrate - setup controller timing information. | ||
204 | * @info: The controller instance. | ||
205 | * | ||
206 | * Given the information supplied by the platform, calculate and set | ||
207 | * the necessary timing registers in the hardware to generate the | ||
208 | * necessary timing cycles to the hardware. | ||
209 | */ | ||
172 | static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) | 210 | static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) |
173 | { | 211 | { |
174 | struct s3c2410_platform_nand *plat = info->platform; | 212 | struct s3c2410_platform_nand *plat = info->platform; |
175 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; | 213 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; |
176 | int tacls, twrph0, twrph1; | 214 | int tacls, twrph0, twrph1; |
177 | unsigned long clkrate = clk_get_rate(info->clk); | 215 | unsigned long clkrate = clk_get_rate(info->clk); |
178 | unsigned long set, cfg, mask; | 216 | unsigned long uninitialized_var(set), cfg, uninitialized_var(mask); |
179 | unsigned long flags; | 217 | unsigned long flags; |
180 | 218 | ||
181 | /* calculate the timing information for the controller */ | 219 | /* calculate the timing information for the controller */ |
@@ -225,14 +263,9 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) | |||
225 | break; | 263 | break; |
226 | 264 | ||
227 | default: | 265 | default: |
228 | /* keep compiler happy */ | ||
229 | mask = 0; | ||
230 | set = 0; | ||
231 | BUG(); | 266 | BUG(); |
232 | } | 267 | } |
233 | 268 | ||
234 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
235 | |||
236 | local_irq_save(flags); | 269 | local_irq_save(flags); |
237 | 270 | ||
238 | cfg = readl(info->regs + S3C2410_NFCONF); | 271 | cfg = readl(info->regs + S3C2410_NFCONF); |
@@ -242,9 +275,18 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) | |||
242 | 275 | ||
243 | local_irq_restore(flags); | 276 | local_irq_restore(flags); |
244 | 277 | ||
278 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
279 | |||
245 | return 0; | 280 | return 0; |
246 | } | 281 | } |
247 | 282 | ||
283 | /** | ||
284 | * s3c2410_nand_inithw - basic hardware initialisation | ||
285 | * @info: The hardware state. | ||
286 | * | ||
287 | * Do the basic initialisation of the hardware, using s3c2410_nand_setrate() | ||
288 | * to setup the hardware access speeds and set the controller to be enabled. | ||
289 | */ | ||
248 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) | 290 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) |
249 | { | 291 | { |
250 | int ret; | 292 | int ret; |
@@ -268,8 +310,19 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) | |||
268 | return 0; | 310 | return 0; |
269 | } | 311 | } |
270 | 312 | ||
271 | /* select chip */ | 313 | /** |
272 | 314 | * s3c2410_nand_select_chip - select the given nand chip | |
315 | * @mtd: The MTD instance for this chip. | ||
316 | * @chip: The chip number. | ||
317 | * | ||
318 | * This is called by the MTD layer to either select a given chip for the | ||
319 | * @mtd instance, or to indicate that the access has finished and the | ||
320 | * chip can be de-selected. | ||
321 | * | ||
322 | * The routine ensures that the nFCE line is correctly setup, and any | ||
323 | * platform specific selection code is called to route nFCE to the specific | ||
324 | * chip. | ||
325 | */ | ||
273 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | 326 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) |
274 | { | 327 | { |
275 | struct s3c2410_nand_info *info; | 328 | struct s3c2410_nand_info *info; |
@@ -530,7 +583,16 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
530 | static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | 583 | static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
531 | { | 584 | { |
532 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 585 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
533 | readsl(info->regs + S3C2440_NFDATA, buf, len / 4); | 586 | |
587 | readsl(info->regs + S3C2440_NFDATA, buf, len >> 2); | ||
588 | |||
589 | /* cleanup if we've got less than a word to do */ | ||
590 | if (len & 3) { | ||
591 | buf += len & ~3; | ||
592 | |||
593 | for (; len & 3; len--) | ||
594 | *buf++ = readb(info->regs + S3C2440_NFDATA); | ||
595 | } | ||
534 | } | 596 | } |
535 | 597 | ||
536 | static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 598 | static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
@@ -542,7 +604,16 @@ static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int | |||
542 | static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 604 | static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
543 | { | 605 | { |
544 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 606 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
545 | writesl(info->regs + S3C2440_NFDATA, buf, len / 4); | 607 | |
608 | writesl(info->regs + S3C2440_NFDATA, buf, len >> 2); | ||
609 | |||
610 | /* cleanup any fractional write */ | ||
611 | if (len & 3) { | ||
612 | buf += len & ~3; | ||
613 | |||
614 | for (; len & 3; len--, buf++) | ||
615 | writeb(*buf, info->regs + S3C2440_NFDATA); | ||
616 | } | ||
546 | } | 617 | } |
547 | 618 | ||
548 | /* cpufreq driver support */ | 619 | /* cpufreq driver support */ |
@@ -593,7 +664,7 @@ static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *inf | |||
593 | 664 | ||
594 | /* device management functions */ | 665 | /* device management functions */ |
595 | 666 | ||
596 | static int s3c2410_nand_remove(struct platform_device *pdev) | 667 | static int s3c24xx_nand_remove(struct platform_device *pdev) |
597 | { | 668 | { |
598 | struct s3c2410_nand_info *info = to_nand_info(pdev); | 669 | struct s3c2410_nand_info *info = to_nand_info(pdev); |
599 | 670 | ||
@@ -645,17 +716,31 @@ static int s3c2410_nand_remove(struct platform_device *pdev) | |||
645 | } | 716 | } |
646 | 717 | ||
647 | #ifdef CONFIG_MTD_PARTITIONS | 718 | #ifdef CONFIG_MTD_PARTITIONS |
719 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
648 | static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | 720 | static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, |
649 | struct s3c2410_nand_mtd *mtd, | 721 | struct s3c2410_nand_mtd *mtd, |
650 | struct s3c2410_nand_set *set) | 722 | struct s3c2410_nand_set *set) |
651 | { | 723 | { |
724 | struct mtd_partition *part_info; | ||
725 | int nr_part = 0; | ||
726 | |||
652 | if (set == NULL) | 727 | if (set == NULL) |
653 | return add_mtd_device(&mtd->mtd); | 728 | return add_mtd_device(&mtd->mtd); |
654 | 729 | ||
655 | if (set->nr_partitions > 0 && set->partitions != NULL) { | 730 | if (set->nr_partitions == 0) { |
656 | return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions); | 731 | mtd->mtd.name = set->name; |
732 | nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, | ||
733 | &part_info, 0); | ||
734 | } else { | ||
735 | if (set->nr_partitions > 0 && set->partitions != NULL) { | ||
736 | nr_part = set->nr_partitions; | ||
737 | part_info = set->partitions; | ||
738 | } | ||
657 | } | 739 | } |
658 | 740 | ||
741 | if (nr_part > 0 && part_info) | ||
742 | return add_mtd_partitions(&mtd->mtd, part_info, nr_part); | ||
743 | |||
659 | return add_mtd_device(&mtd->mtd); | 744 | return add_mtd_device(&mtd->mtd); |
660 | } | 745 | } |
661 | #else | 746 | #else |
@@ -667,11 +752,16 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
667 | } | 752 | } |
668 | #endif | 753 | #endif |
669 | 754 | ||
670 | /* s3c2410_nand_init_chip | 755 | /** |
756 | * s3c2410_nand_init_chip - initialise a single instance of an chip | ||
757 | * @info: The base NAND controller the chip is on. | ||
758 | * @nmtd: The new controller MTD instance to fill in. | ||
759 | * @set: The information passed from the board specific platform data. | ||
671 | * | 760 | * |
672 | * init a single instance of an chip | 761 | * Initialise the given @nmtd from the information in @info and @set. This |
673 | */ | 762 | * readies the structure for use with the MTD layer functions by ensuring |
674 | 763 | * all pointers are setup and the necessary control routines selected. | |
764 | */ | ||
675 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | 765 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, |
676 | struct s3c2410_nand_mtd *nmtd, | 766 | struct s3c2410_nand_mtd *nmtd, |
677 | struct s3c2410_nand_set *set) | 767 | struct s3c2410_nand_set *set) |
@@ -757,14 +847,40 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
757 | 847 | ||
758 | if (set->disable_ecc) | 848 | if (set->disable_ecc) |
759 | chip->ecc.mode = NAND_ECC_NONE; | 849 | chip->ecc.mode = NAND_ECC_NONE; |
850 | |||
851 | switch (chip->ecc.mode) { | ||
852 | case NAND_ECC_NONE: | ||
853 | dev_info(info->device, "NAND ECC disabled\n"); | ||
854 | break; | ||
855 | case NAND_ECC_SOFT: | ||
856 | dev_info(info->device, "NAND soft ECC\n"); | ||
857 | break; | ||
858 | case NAND_ECC_HW: | ||
859 | dev_info(info->device, "NAND hardware ECC\n"); | ||
860 | break; | ||
861 | default: | ||
862 | dev_info(info->device, "NAND ECC UNKNOWN\n"); | ||
863 | break; | ||
864 | } | ||
865 | |||
866 | /* If you use u-boot BBT creation code, specifying this flag will | ||
867 | * let the kernel fish out the BBT from the NAND, and also skip the | ||
868 | * full NAND scan that can take 1/2s or so. Little things... */ | ||
869 | if (set->flash_bbt) | ||
870 | chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; | ||
760 | } | 871 | } |
761 | 872 | ||
762 | /* s3c2410_nand_update_chip | 873 | /** |
874 | * s3c2410_nand_update_chip - post probe update | ||
875 | * @info: The controller instance. | ||
876 | * @nmtd: The driver version of the MTD instance. | ||
763 | * | 877 | * |
764 | * post-probe chip update, to change any items, such as the | 878 | * This routine is called after the chip probe has succesfully completed |
765 | * layout for large page nand | 879 | * and the relevant per-chip information updated. This call ensure that |
766 | */ | 880 | * we update the internal state accordingly. |
767 | 881 | * | |
882 | * The internal state is currently limited to the ECC state information. | ||
883 | */ | ||
768 | static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, | 884 | static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, |
769 | struct s3c2410_nand_mtd *nmtd) | 885 | struct s3c2410_nand_mtd *nmtd) |
770 | { | 886 | { |
@@ -773,33 +889,33 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, | |||
773 | dev_dbg(info->device, "chip %p => page shift %d\n", | 889 | dev_dbg(info->device, "chip %p => page shift %d\n", |
774 | chip, chip->page_shift); | 890 | chip, chip->page_shift); |
775 | 891 | ||
776 | if (hardware_ecc) { | 892 | if (chip->ecc.mode != NAND_ECC_HW) |
893 | return; | ||
894 | |||
777 | /* change the behaviour depending on wether we are using | 895 | /* change the behaviour depending on wether we are using |
778 | * the large or small page nand device */ | 896 | * the large or small page nand device */ |
779 | 897 | ||
780 | if (chip->page_shift > 10) { | 898 | if (chip->page_shift > 10) { |
781 | chip->ecc.size = 256; | 899 | chip->ecc.size = 256; |
782 | chip->ecc.bytes = 3; | 900 | chip->ecc.bytes = 3; |
783 | } else { | 901 | } else { |
784 | chip->ecc.size = 512; | 902 | chip->ecc.size = 512; |
785 | chip->ecc.bytes = 3; | 903 | chip->ecc.bytes = 3; |
786 | chip->ecc.layout = &nand_hw_eccoob; | 904 | chip->ecc.layout = &nand_hw_eccoob; |
787 | } | ||
788 | } | 905 | } |
789 | } | 906 | } |
790 | 907 | ||
791 | /* s3c2410_nand_probe | 908 | /* s3c24xx_nand_probe |
792 | * | 909 | * |
793 | * called by device layer when it finds a device matching | 910 | * called by device layer when it finds a device matching |
794 | * one our driver can handled. This code checks to see if | 911 | * one our driver can handled. This code checks to see if |
795 | * it can allocate all necessary resources then calls the | 912 | * it can allocate all necessary resources then calls the |
796 | * nand layer to look for devices | 913 | * nand layer to look for devices |
797 | */ | 914 | */ |
798 | 915 | static int s3c24xx_nand_probe(struct platform_device *pdev) | |
799 | static int s3c24xx_nand_probe(struct platform_device *pdev, | ||
800 | enum s3c_cpu_type cpu_type) | ||
801 | { | 916 | { |
802 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); | 917 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); |
918 | enum s3c_cpu_type cpu_type; | ||
803 | struct s3c2410_nand_info *info; | 919 | struct s3c2410_nand_info *info; |
804 | struct s3c2410_nand_mtd *nmtd; | 920 | struct s3c2410_nand_mtd *nmtd; |
805 | struct s3c2410_nand_set *sets; | 921 | struct s3c2410_nand_set *sets; |
@@ -809,6 +925,8 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
809 | int nr_sets; | 925 | int nr_sets; |
810 | int setno; | 926 | int setno; |
811 | 927 | ||
928 | cpu_type = platform_get_device_id(pdev)->driver_data; | ||
929 | |||
812 | pr_debug("s3c2410_nand_probe(%p)\n", pdev); | 930 | pr_debug("s3c2410_nand_probe(%p)\n", pdev); |
813 | 931 | ||
814 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 932 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
@@ -922,7 +1040,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
922 | return 0; | 1040 | return 0; |
923 | 1041 | ||
924 | exit_error: | 1042 | exit_error: |
925 | s3c2410_nand_remove(pdev); | 1043 | s3c24xx_nand_remove(pdev); |
926 | 1044 | ||
927 | if (err == 0) | 1045 | if (err == 0) |
928 | err = -EINVAL; | 1046 | err = -EINVAL; |
@@ -983,50 +1101,30 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
983 | 1101 | ||
984 | /* driver device registration */ | 1102 | /* driver device registration */ |
985 | 1103 | ||
986 | static int s3c2410_nand_probe(struct platform_device *dev) | 1104 | static struct platform_device_id s3c24xx_driver_ids[] = { |
987 | { | 1105 | { |
988 | return s3c24xx_nand_probe(dev, TYPE_S3C2410); | 1106 | .name = "s3c2410-nand", |
989 | } | 1107 | .driver_data = TYPE_S3C2410, |
990 | 1108 | }, { | |
991 | static int s3c2440_nand_probe(struct platform_device *dev) | 1109 | .name = "s3c2440-nand", |
992 | { | 1110 | .driver_data = TYPE_S3C2440, |
993 | return s3c24xx_nand_probe(dev, TYPE_S3C2440); | 1111 | }, { |
994 | } | 1112 | .name = "s3c2412-nand", |
995 | 1113 | .driver_data = TYPE_S3C2412, | |
996 | static int s3c2412_nand_probe(struct platform_device *dev) | ||
997 | { | ||
998 | return s3c24xx_nand_probe(dev, TYPE_S3C2412); | ||
999 | } | ||
1000 | |||
1001 | static struct platform_driver s3c2410_nand_driver = { | ||
1002 | .probe = s3c2410_nand_probe, | ||
1003 | .remove = s3c2410_nand_remove, | ||
1004 | .suspend = s3c24xx_nand_suspend, | ||
1005 | .resume = s3c24xx_nand_resume, | ||
1006 | .driver = { | ||
1007 | .name = "s3c2410-nand", | ||
1008 | .owner = THIS_MODULE, | ||
1009 | }, | 1114 | }, |
1115 | { } | ||
1010 | }; | 1116 | }; |
1011 | 1117 | ||
1012 | static struct platform_driver s3c2440_nand_driver = { | 1118 | MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); |
1013 | .probe = s3c2440_nand_probe, | ||
1014 | .remove = s3c2410_nand_remove, | ||
1015 | .suspend = s3c24xx_nand_suspend, | ||
1016 | .resume = s3c24xx_nand_resume, | ||
1017 | .driver = { | ||
1018 | .name = "s3c2440-nand", | ||
1019 | .owner = THIS_MODULE, | ||
1020 | }, | ||
1021 | }; | ||
1022 | 1119 | ||
1023 | static struct platform_driver s3c2412_nand_driver = { | 1120 | static struct platform_driver s3c24xx_nand_driver = { |
1024 | .probe = s3c2412_nand_probe, | 1121 | .probe = s3c24xx_nand_probe, |
1025 | .remove = s3c2410_nand_remove, | 1122 | .remove = s3c24xx_nand_remove, |
1026 | .suspend = s3c24xx_nand_suspend, | 1123 | .suspend = s3c24xx_nand_suspend, |
1027 | .resume = s3c24xx_nand_resume, | 1124 | .resume = s3c24xx_nand_resume, |
1125 | .id_table = s3c24xx_driver_ids, | ||
1028 | .driver = { | 1126 | .driver = { |
1029 | .name = "s3c2412-nand", | 1127 | .name = "s3c24xx-nand", |
1030 | .owner = THIS_MODULE, | 1128 | .owner = THIS_MODULE, |
1031 | }, | 1129 | }, |
1032 | }; | 1130 | }; |
@@ -1035,16 +1133,12 @@ static int __init s3c2410_nand_init(void) | |||
1035 | { | 1133 | { |
1036 | printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); | 1134 | printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); |
1037 | 1135 | ||
1038 | platform_driver_register(&s3c2412_nand_driver); | 1136 | return platform_driver_register(&s3c24xx_nand_driver); |
1039 | platform_driver_register(&s3c2440_nand_driver); | ||
1040 | return platform_driver_register(&s3c2410_nand_driver); | ||
1041 | } | 1137 | } |
1042 | 1138 | ||
1043 | static void __exit s3c2410_nand_exit(void) | 1139 | static void __exit s3c2410_nand_exit(void) |
1044 | { | 1140 | { |
1045 | platform_driver_unregister(&s3c2412_nand_driver); | 1141 | platform_driver_unregister(&s3c24xx_nand_driver); |
1046 | platform_driver_unregister(&s3c2440_nand_driver); | ||
1047 | platform_driver_unregister(&s3c2410_nand_driver); | ||
1048 | } | 1142 | } |
1049 | 1143 | ||
1050 | module_init(s3c2410_nand_init); | 1144 | module_init(s3c2410_nand_init); |
@@ -1053,6 +1147,3 @@ module_exit(s3c2410_nand_exit); | |||
1053 | MODULE_LICENSE("GPL"); | 1147 | MODULE_LICENSE("GPL"); |
1054 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 1148 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
1055 | MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); | 1149 | MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); |
1056 | MODULE_ALIAS("platform:s3c2410-nand"); | ||
1057 | MODULE_ALIAS("platform:s3c2412-nand"); | ||
1058 | MODULE_ALIAS("platform:s3c2440-nand"); | ||