Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright © 2004-2008 Simtec Electronics
0004  *  http://armlinux.simtec.co.uk/
0005  *  Ben Dooks <ben@simtec.co.uk>
0006  *
0007  * Samsung S3C2410/S3C2440/S3C2412 NAND driver
0008 */
0009 
0010 #define pr_fmt(fmt) "nand-s3c2410: " fmt
0011 
0012 #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
0013 #define DEBUG
0014 #endif
0015 
0016 #include <linux/module.h>
0017 #include <linux/types.h>
0018 #include <linux/kernel.h>
0019 #include <linux/string.h>
0020 #include <linux/io.h>
0021 #include <linux/ioport.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/delay.h>
0024 #include <linux/err.h>
0025 #include <linux/slab.h>
0026 #include <linux/clk.h>
0027 #include <linux/cpufreq.h>
0028 #include <linux/of.h>
0029 #include <linux/of_device.h>
0030 
0031 #include <linux/mtd/mtd.h>
0032 #include <linux/mtd/rawnand.h>
0033 #include <linux/mtd/partitions.h>
0034 
0035 #include <linux/platform_data/mtd-nand-s3c2410.h>
0036 
0037 #define S3C2410_NFREG(x) (x)
0038 
0039 #define S3C2410_NFCONF      S3C2410_NFREG(0x00)
0040 #define S3C2410_NFCMD       S3C2410_NFREG(0x04)
0041 #define S3C2410_NFADDR      S3C2410_NFREG(0x08)
0042 #define S3C2410_NFDATA      S3C2410_NFREG(0x0C)
0043 #define S3C2410_NFSTAT      S3C2410_NFREG(0x10)
0044 #define S3C2410_NFECC       S3C2410_NFREG(0x14)
0045 #define S3C2440_NFCONT      S3C2410_NFREG(0x04)
0046 #define S3C2440_NFCMD       S3C2410_NFREG(0x08)
0047 #define S3C2440_NFADDR      S3C2410_NFREG(0x0C)
0048 #define S3C2440_NFDATA      S3C2410_NFREG(0x10)
0049 #define S3C2440_NFSTAT      S3C2410_NFREG(0x20)
0050 #define S3C2440_NFMECC0     S3C2410_NFREG(0x2C)
0051 #define S3C2412_NFSTAT      S3C2410_NFREG(0x28)
0052 #define S3C2412_NFMECC0     S3C2410_NFREG(0x34)
0053 #define S3C2410_NFCONF_EN       (1<<15)
0054 #define S3C2410_NFCONF_INITECC      (1<<12)
0055 #define S3C2410_NFCONF_nFCE     (1<<11)
0056 #define S3C2410_NFCONF_TACLS(x)     ((x)<<8)
0057 #define S3C2410_NFCONF_TWRPH0(x)    ((x)<<4)
0058 #define S3C2410_NFCONF_TWRPH1(x)    ((x)<<0)
0059 #define S3C2410_NFSTAT_BUSY     (1<<0)
0060 #define S3C2440_NFCONF_TACLS(x)     ((x)<<12)
0061 #define S3C2440_NFCONF_TWRPH0(x)    ((x)<<8)
0062 #define S3C2440_NFCONF_TWRPH1(x)    ((x)<<4)
0063 #define S3C2440_NFCONT_INITECC      (1<<4)
0064 #define S3C2440_NFCONT_nFCE     (1<<1)
0065 #define S3C2440_NFCONT_ENABLE       (1<<0)
0066 #define S3C2440_NFSTAT_READY        (1<<0)
0067 #define S3C2412_NFCONF_NANDBOOT     (1<<31)
0068 #define S3C2412_NFCONT_INIT_MAIN_ECC    (1<<5)
0069 #define S3C2412_NFCONT_nFCE0        (1<<1)
0070 #define S3C2412_NFSTAT_READY        (1<<0)
0071 
0072 /* new oob placement block for use with hardware ecc generation
0073  */
0074 static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
0075                  struct mtd_oob_region *oobregion)
0076 {
0077     if (section)
0078         return -ERANGE;
0079 
0080     oobregion->offset = 0;
0081     oobregion->length = 3;
0082 
0083     return 0;
0084 }
0085 
0086 static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
0087                   struct mtd_oob_region *oobregion)
0088 {
0089     if (section)
0090         return -ERANGE;
0091 
0092     oobregion->offset = 8;
0093     oobregion->length = 8;
0094 
0095     return 0;
0096 }
0097 
0098 static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
0099     .ecc = s3c2410_ooblayout_ecc,
0100     .free = s3c2410_ooblayout_free,
0101 };
0102 
0103 /* controller and mtd information */
0104 
0105 struct s3c2410_nand_info;
0106 
0107 /**
0108  * struct s3c2410_nand_mtd - driver MTD structure
0109  * @mtd: The MTD instance to pass to the MTD layer.
0110  * @chip: The NAND chip information.
0111  * @set: The platform information supplied for this set of NAND chips.
0112  * @info: Link back to the hardware information.
0113 */
0114 struct s3c2410_nand_mtd {
0115     struct nand_chip        chip;
0116     struct s3c2410_nand_set     *set;
0117     struct s3c2410_nand_info    *info;
0118 };
0119 
0120 enum s3c_cpu_type {
0121     TYPE_S3C2410,
0122     TYPE_S3C2412,
0123     TYPE_S3C2440,
0124 };
0125 
0126 enum s3c_nand_clk_state {
0127     CLOCK_DISABLE   = 0,
0128     CLOCK_ENABLE,
0129     CLOCK_SUSPEND,
0130 };
0131 
0132 /* overview of the s3c2410 nand state */
0133 
0134 /**
0135  * struct s3c2410_nand_info - NAND controller state.
0136  * @controller: Base controller structure.
0137  * @mtds: An array of MTD instances on this controller.
0138  * @platform: The platform data for this board.
0139  * @device: The platform device we bound to.
0140  * @clk: The clock resource for this controller.
0141  * @regs: The area mapped for the hardware registers.
0142  * @sel_reg: Pointer to the register controlling the NAND selection.
0143  * @sel_bit: The bit in @sel_reg to select the NAND chip.
0144  * @mtd_count: The number of MTDs created from this controller.
0145  * @save_sel: The contents of @sel_reg to be saved over suspend.
0146  * @clk_rate: The clock rate from @clk.
0147  * @clk_state: The current clock state.
0148  * @cpu_type: The exact type of this controller.
0149  * @freq_transition: CPUFreq notifier block
0150  */
0151 struct s3c2410_nand_info {
0152     /* mtd info */
0153     struct nand_controller      controller;
0154     struct s3c2410_nand_mtd     *mtds;
0155     struct s3c2410_platform_nand    *platform;
0156 
0157     /* device info */
0158     struct device           *device;
0159     struct clk          *clk;
0160     void __iomem            *regs;
0161     void __iomem            *sel_reg;
0162     int             sel_bit;
0163     int             mtd_count;
0164     unsigned long           save_sel;
0165     unsigned long           clk_rate;
0166     enum s3c_nand_clk_state     clk_state;
0167 
0168     enum s3c_cpu_type       cpu_type;
0169 
0170 #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
0171     struct notifier_block   freq_transition;
0172 #endif
0173 };
0174 
0175 struct s3c24XX_nand_devtype_data {
0176     enum s3c_cpu_type type;
0177 };
0178 
0179 static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
0180     .type = TYPE_S3C2410,
0181 };
0182 
0183 static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
0184     .type = TYPE_S3C2412,
0185 };
0186 
0187 static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
0188     .type = TYPE_S3C2440,
0189 };
0190 
0191 /* conversion functions */
0192 
0193 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
0194 {
0195     return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
0196                 chip);
0197 }
0198 
0199 static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
0200 {
0201     return s3c2410_nand_mtd_toours(mtd)->info;
0202 }
0203 
0204 static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
0205 {
0206     return platform_get_drvdata(dev);
0207 }
0208 
0209 static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
0210 {
0211     return dev_get_platdata(&dev->dev);
0212 }
0213 
0214 static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
0215 {
0216 #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
0217     return 1;
0218 #else
0219     return 0;
0220 #endif
0221 }
0222 
0223 /**
0224  * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
0225  * @info: The controller instance.
0226  * @new_state: State to which clock should be set.
0227  */
0228 static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
0229         enum s3c_nand_clk_state new_state)
0230 {
0231     if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
0232         return;
0233 
0234     if (info->clk_state == CLOCK_ENABLE) {
0235         if (new_state != CLOCK_ENABLE)
0236             clk_disable_unprepare(info->clk);
0237     } else {
0238         if (new_state == CLOCK_ENABLE)
0239             clk_prepare_enable(info->clk);
0240     }
0241 
0242     info->clk_state = new_state;
0243 }
0244 
0245 /* timing calculations */
0246 
0247 #define NS_IN_KHZ 1000000
0248 
0249 /**
0250  * s3c_nand_calc_rate - calculate timing data.
0251  * @wanted: The cycle time in nanoseconds.
0252  * @clk: The clock rate in kHz.
0253  * @max: The maximum divider value.
0254  *
0255  * Calculate the timing value from the given parameters.
0256  */
0257 static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
0258 {
0259     int result;
0260 
0261     result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
0262 
0263     pr_debug("result %d from %ld, %d\n", result, clk, wanted);
0264 
0265     if (result > max) {
0266         pr_err("%d ns is too big for current clock rate %ld\n",
0267             wanted, clk);
0268         return -1;
0269     }
0270 
0271     if (result < 1)
0272         result = 1;
0273 
0274     return result;
0275 }
0276 
0277 #define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
0278 
0279 /* controller setup */
0280 
0281 /**
0282  * s3c2410_nand_setrate - setup controller timing information.
0283  * @info: The controller instance.
0284  *
0285  * Given the information supplied by the platform, calculate and set
0286  * the necessary timing registers in the hardware to generate the
0287  * necessary timing cycles to the hardware.
0288  */
0289 static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
0290 {
0291     struct s3c2410_platform_nand *plat = info->platform;
0292     int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
0293     int tacls, twrph0, twrph1;
0294     unsigned long clkrate = clk_get_rate(info->clk);
0295     unsigned long set, cfg, mask;
0296     unsigned long flags;
0297 
0298     /* calculate the timing information for the controller */
0299 
0300     info->clk_rate = clkrate;
0301     clkrate /= 1000;    /* turn clock into kHz for ease of use */
0302 
0303     if (plat != NULL) {
0304         tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
0305         twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
0306         twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
0307     } else {
0308         /* default timings */
0309         tacls = tacls_max;
0310         twrph0 = 8;
0311         twrph1 = 8;
0312     }
0313 
0314     if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
0315         dev_err(info->device, "cannot get suitable timings\n");
0316         return -EINVAL;
0317     }
0318 
0319     dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
0320         tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
0321                         twrph1, to_ns(twrph1, clkrate));
0322 
0323     switch (info->cpu_type) {
0324     case TYPE_S3C2410:
0325         mask = (S3C2410_NFCONF_TACLS(3) |
0326             S3C2410_NFCONF_TWRPH0(7) |
0327             S3C2410_NFCONF_TWRPH1(7));
0328         set = S3C2410_NFCONF_EN;
0329         set |= S3C2410_NFCONF_TACLS(tacls - 1);
0330         set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
0331         set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
0332         break;
0333 
0334     case TYPE_S3C2440:
0335     case TYPE_S3C2412:
0336         mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
0337             S3C2440_NFCONF_TWRPH0(7) |
0338             S3C2440_NFCONF_TWRPH1(7));
0339 
0340         set = S3C2440_NFCONF_TACLS(tacls - 1);
0341         set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
0342         set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
0343         break;
0344 
0345     default:
0346         BUG();
0347     }
0348 
0349     local_irq_save(flags);
0350 
0351     cfg = readl(info->regs + S3C2410_NFCONF);
0352     cfg &= ~mask;
0353     cfg |= set;
0354     writel(cfg, info->regs + S3C2410_NFCONF);
0355 
0356     local_irq_restore(flags);
0357 
0358     dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
0359 
0360     return 0;
0361 }
0362 
0363 /**
0364  * s3c2410_nand_inithw - basic hardware initialisation
0365  * @info: The hardware state.
0366  *
0367  * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
0368  * to setup the hardware access speeds and set the controller to be enabled.
0369 */
0370 static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
0371 {
0372     int ret;
0373 
0374     ret = s3c2410_nand_setrate(info);
0375     if (ret < 0)
0376         return ret;
0377 
0378     switch (info->cpu_type) {
0379     case TYPE_S3C2410:
0380     default:
0381         break;
0382 
0383     case TYPE_S3C2440:
0384     case TYPE_S3C2412:
0385         /* enable the controller and de-assert nFCE */
0386 
0387         writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
0388     }
0389 
0390     return 0;
0391 }
0392 
0393 /**
0394  * s3c2410_nand_select_chip - select the given nand chip
0395  * @this: NAND chip object.
0396  * @chip: The chip number.
0397  *
0398  * This is called by the MTD layer to either select a given chip for the
0399  * @mtd instance, or to indicate that the access has finished and the
0400  * chip can be de-selected.
0401  *
0402  * The routine ensures that the nFCE line is correctly setup, and any
0403  * platform specific selection code is called to route nFCE to the specific
0404  * chip.
0405  */
0406 static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
0407 {
0408     struct s3c2410_nand_info *info;
0409     struct s3c2410_nand_mtd *nmtd;
0410     unsigned long cur;
0411 
0412     nmtd = nand_get_controller_data(this);
0413     info = nmtd->info;
0414 
0415     if (chip != -1)
0416         s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
0417 
0418     cur = readl(info->sel_reg);
0419 
0420     if (chip == -1) {
0421         cur |= info->sel_bit;
0422     } else {
0423         if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
0424             dev_err(info->device, "invalid chip %d\n", chip);
0425             return;
0426         }
0427 
0428         if (info->platform != NULL) {
0429             if (info->platform->select_chip != NULL)
0430                 (info->platform->select_chip) (nmtd->set, chip);
0431         }
0432 
0433         cur &= ~info->sel_bit;
0434     }
0435 
0436     writel(cur, info->sel_reg);
0437 
0438     if (chip == -1)
0439         s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
0440 }
0441 
0442 /* s3c2410_nand_hwcontrol
0443  *
0444  * Issue command and address cycles to the chip
0445 */
0446 
0447 static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
0448                    unsigned int ctrl)
0449 {
0450     struct mtd_info *mtd = nand_to_mtd(chip);
0451     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0452 
0453     if (cmd == NAND_CMD_NONE)
0454         return;
0455 
0456     if (ctrl & NAND_CLE)
0457         writeb(cmd, info->regs + S3C2410_NFCMD);
0458     else
0459         writeb(cmd, info->regs + S3C2410_NFADDR);
0460 }
0461 
0462 /* command and control functions */
0463 
0464 static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
0465                    unsigned int ctrl)
0466 {
0467     struct mtd_info *mtd = nand_to_mtd(chip);
0468     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0469 
0470     if (cmd == NAND_CMD_NONE)
0471         return;
0472 
0473     if (ctrl & NAND_CLE)
0474         writeb(cmd, info->regs + S3C2440_NFCMD);
0475     else
0476         writeb(cmd, info->regs + S3C2440_NFADDR);
0477 }
0478 
0479 /* s3c2410_nand_devready()
0480  *
0481  * returns 0 if the nand is busy, 1 if it is ready
0482 */
0483 
0484 static int s3c2410_nand_devready(struct nand_chip *chip)
0485 {
0486     struct mtd_info *mtd = nand_to_mtd(chip);
0487     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0488     return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
0489 }
0490 
0491 static int s3c2440_nand_devready(struct nand_chip *chip)
0492 {
0493     struct mtd_info *mtd = nand_to_mtd(chip);
0494     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0495     return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
0496 }
0497 
0498 static int s3c2412_nand_devready(struct nand_chip *chip)
0499 {
0500     struct mtd_info *mtd = nand_to_mtd(chip);
0501     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0502     return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
0503 }
0504 
0505 /* ECC handling functions */
0506 
0507 static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
0508                      u_char *read_ecc, u_char *calc_ecc)
0509 {
0510     struct mtd_info *mtd = nand_to_mtd(chip);
0511     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0512     unsigned int diff0, diff1, diff2;
0513     unsigned int bit, byte;
0514 
0515     pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
0516 
0517     diff0 = read_ecc[0] ^ calc_ecc[0];
0518     diff1 = read_ecc[1] ^ calc_ecc[1];
0519     diff2 = read_ecc[2] ^ calc_ecc[2];
0520 
0521     pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
0522          __func__, 3, read_ecc, 3, calc_ecc,
0523          diff0, diff1, diff2);
0524 
0525     if (diff0 == 0 && diff1 == 0 && diff2 == 0)
0526         return 0;       /* ECC is ok */
0527 
0528     /* sometimes people do not think about using the ECC, so check
0529      * to see if we have an 0xff,0xff,0xff read ECC and then ignore
0530      * the error, on the assumption that this is an un-eccd page.
0531      */
0532     if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
0533         && info->platform->ignore_unset_ecc)
0534         return 0;
0535 
0536     /* Can we correct this ECC (ie, one row and column change).
0537      * Note, this is similar to the 256 error code on smartmedia */
0538 
0539     if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
0540         ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
0541         ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
0542         /* calculate the bit position of the error */
0543 
0544         bit  = ((diff2 >> 3) & 1) |
0545                ((diff2 >> 4) & 2) |
0546                ((diff2 >> 5) & 4);
0547 
0548         /* calculate the byte position of the error */
0549 
0550         byte = ((diff2 << 7) & 0x100) |
0551                ((diff1 << 0) & 0x80)  |
0552                ((diff1 << 1) & 0x40)  |
0553                ((diff1 << 2) & 0x20)  |
0554                ((diff1 << 3) & 0x10)  |
0555                ((diff0 >> 4) & 0x08)  |
0556                ((diff0 >> 3) & 0x04)  |
0557                ((diff0 >> 2) & 0x02)  |
0558                ((diff0 >> 1) & 0x01);
0559 
0560         dev_dbg(info->device, "correcting error bit %d, byte %d\n",
0561             bit, byte);
0562 
0563         dat[byte] ^= (1 << bit);
0564         return 1;
0565     }
0566 
0567     /* if there is only one bit difference in the ECC, then
0568      * one of only a row or column parity has changed, which
0569      * means the error is most probably in the ECC itself */
0570 
0571     diff0 |= (diff1 << 8);
0572     diff0 |= (diff2 << 16);
0573 
0574     /* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
0575     if ((diff0 & (diff0 - 1)) == 0)
0576         return 1;
0577 
0578     return -1;
0579 }
0580 
0581 /* ECC functions
0582  *
0583  * These allow the s3c2410 and s3c2440 to use the controller's ECC
0584  * generator block to ECC the data as it passes through]
0585 */
0586 
0587 static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
0588 {
0589     struct s3c2410_nand_info *info;
0590     unsigned long ctrl;
0591 
0592     info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
0593     ctrl = readl(info->regs + S3C2410_NFCONF);
0594     ctrl |= S3C2410_NFCONF_INITECC;
0595     writel(ctrl, info->regs + S3C2410_NFCONF);
0596 }
0597 
0598 static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
0599 {
0600     struct s3c2410_nand_info *info;
0601     unsigned long ctrl;
0602 
0603     info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
0604     ctrl = readl(info->regs + S3C2440_NFCONT);
0605     writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
0606            info->regs + S3C2440_NFCONT);
0607 }
0608 
0609 static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
0610 {
0611     struct s3c2410_nand_info *info;
0612     unsigned long ctrl;
0613 
0614     info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
0615     ctrl = readl(info->regs + S3C2440_NFCONT);
0616     writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
0617 }
0618 
0619 static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
0620                       const u_char *dat, u_char *ecc_code)
0621 {
0622     struct mtd_info *mtd = nand_to_mtd(chip);
0623     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0624 
0625     ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
0626     ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
0627     ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
0628 
0629     pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
0630 
0631     return 0;
0632 }
0633 
0634 static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
0635                       const u_char *dat, u_char *ecc_code)
0636 {
0637     struct mtd_info *mtd = nand_to_mtd(chip);
0638     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0639     unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
0640 
0641     ecc_code[0] = ecc;
0642     ecc_code[1] = ecc >> 8;
0643     ecc_code[2] = ecc >> 16;
0644 
0645     pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
0646 
0647     return 0;
0648 }
0649 
0650 static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
0651                       const u_char *dat, u_char *ecc_code)
0652 {
0653     struct mtd_info *mtd = nand_to_mtd(chip);
0654     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0655     unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
0656 
0657     ecc_code[0] = ecc;
0658     ecc_code[1] = ecc >> 8;
0659     ecc_code[2] = ecc >> 16;
0660 
0661     pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
0662 
0663     return 0;
0664 }
0665 
0666 /* over-ride the standard functions for a little more speed. We can
0667  * use read/write block to move the data buffers to/from the controller
0668 */
0669 
0670 static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
0671 {
0672     readsb(this->legacy.IO_ADDR_R, buf, len);
0673 }
0674 
0675 static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
0676 {
0677     struct mtd_info *mtd = nand_to_mtd(this);
0678     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0679 
0680     readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
0681 
0682     /* cleanup if we've got less than a word to do */
0683     if (len & 3) {
0684         buf += len & ~3;
0685 
0686         for (; len & 3; len--)
0687             *buf++ = readb(info->regs + S3C2440_NFDATA);
0688     }
0689 }
0690 
0691 static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
0692                    int len)
0693 {
0694     writesb(this->legacy.IO_ADDR_W, buf, len);
0695 }
0696 
0697 static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
0698                    int len)
0699 {
0700     struct mtd_info *mtd = nand_to_mtd(this);
0701     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0702 
0703     writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
0704 
0705     /* cleanup any fractional write */
0706     if (len & 3) {
0707         buf += len & ~3;
0708 
0709         for (; len & 3; len--, buf++)
0710             writeb(*buf, info->regs + S3C2440_NFDATA);
0711     }
0712 }
0713 
0714 /* cpufreq driver support */
0715 
0716 #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
0717 
0718 static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
0719                       unsigned long val, void *data)
0720 {
0721     struct s3c2410_nand_info *info;
0722     unsigned long newclk;
0723 
0724     info = container_of(nb, struct s3c2410_nand_info, freq_transition);
0725     newclk = clk_get_rate(info->clk);
0726 
0727     if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
0728         (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
0729         s3c2410_nand_setrate(info);
0730     }
0731 
0732     return 0;
0733 }
0734 
0735 static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
0736 {
0737     info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
0738 
0739     return cpufreq_register_notifier(&info->freq_transition,
0740                      CPUFREQ_TRANSITION_NOTIFIER);
0741 }
0742 
0743 static inline void
0744 s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
0745 {
0746     cpufreq_unregister_notifier(&info->freq_transition,
0747                     CPUFREQ_TRANSITION_NOTIFIER);
0748 }
0749 
0750 #else
0751 static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
0752 {
0753     return 0;
0754 }
0755 
0756 static inline void
0757 s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
0758 {
0759 }
0760 #endif
0761 
0762 /* device management functions */
0763 
0764 static int s3c24xx_nand_remove(struct platform_device *pdev)
0765 {
0766     struct s3c2410_nand_info *info = to_nand_info(pdev);
0767 
0768     if (info == NULL)
0769         return 0;
0770 
0771     s3c2410_nand_cpufreq_deregister(info);
0772 
0773     /* Release all our mtds  and their partitions, then go through
0774      * freeing the resources used
0775      */
0776 
0777     if (info->mtds != NULL) {
0778         struct s3c2410_nand_mtd *ptr = info->mtds;
0779         int mtdno;
0780 
0781         for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
0782             pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
0783             WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip)));
0784             nand_cleanup(&ptr->chip);
0785         }
0786     }
0787 
0788     /* free the common resources */
0789 
0790     if (!IS_ERR(info->clk))
0791         s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
0792 
0793     return 0;
0794 }
0795 
0796 static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
0797                       struct s3c2410_nand_mtd *mtd,
0798                       struct s3c2410_nand_set *set)
0799 {
0800     if (set) {
0801         struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
0802 
0803         mtdinfo->name = set->name;
0804 
0805         return mtd_device_register(mtdinfo, set->partitions,
0806                        set->nr_partitions);
0807     }
0808 
0809     return -ENODEV;
0810 }
0811 
0812 static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,
0813                     const struct nand_interface_config *conf)
0814 {
0815     struct mtd_info *mtd = nand_to_mtd(chip);
0816     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0817     struct s3c2410_platform_nand *pdata = info->platform;
0818     const struct nand_sdr_timings *timings;
0819     int tacls;
0820 
0821     timings = nand_get_sdr_timings(conf);
0822     if (IS_ERR(timings))
0823         return -ENOTSUPP;
0824 
0825     tacls = timings->tCLS_min - timings->tWP_min;
0826     if (tacls < 0)
0827         tacls = 0;
0828 
0829     pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
0830     pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
0831     pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
0832 
0833     return s3c2410_nand_setrate(info);
0834 }
0835 
0836 /**
0837  * s3c2410_nand_init_chip - initialise a single instance of an chip
0838  * @info: The base NAND controller the chip is on.
0839  * @nmtd: The new controller MTD instance to fill in.
0840  * @set: The information passed from the board specific platform data.
0841  *
0842  * Initialise the given @nmtd from the information in @info and @set. This
0843  * readies the structure for use with the MTD layer functions by ensuring
0844  * all pointers are setup and the necessary control routines selected.
0845  */
0846 static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
0847                    struct s3c2410_nand_mtd *nmtd,
0848                    struct s3c2410_nand_set *set)
0849 {
0850     struct device_node *np = info->device->of_node;
0851     struct nand_chip *chip = &nmtd->chip;
0852     void __iomem *regs = info->regs;
0853 
0854     nand_set_flash_node(chip, set->of_node);
0855 
0856     chip->legacy.write_buf    = s3c2410_nand_write_buf;
0857     chip->legacy.read_buf     = s3c2410_nand_read_buf;
0858     chip->legacy.select_chip  = s3c2410_nand_select_chip;
0859     chip->legacy.chip_delay   = 50;
0860     nand_set_controller_data(chip, nmtd);
0861     chip->options      = set->options;
0862     chip->controller   = &info->controller;
0863 
0864     /*
0865      * let's keep behavior unchanged for legacy boards booting via pdata and
0866      * auto-detect timings only when booting with a device tree.
0867      */
0868     if (!np)
0869         chip->options |= NAND_KEEP_TIMINGS;
0870 
0871     switch (info->cpu_type) {
0872     case TYPE_S3C2410:
0873         chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
0874         info->sel_reg   = regs + S3C2410_NFCONF;
0875         info->sel_bit   = S3C2410_NFCONF_nFCE;
0876         chip->legacy.cmd_ctrl  = s3c2410_nand_hwcontrol;
0877         chip->legacy.dev_ready = s3c2410_nand_devready;
0878         break;
0879 
0880     case TYPE_S3C2440:
0881         chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
0882         info->sel_reg   = regs + S3C2440_NFCONT;
0883         info->sel_bit   = S3C2440_NFCONT_nFCE;
0884         chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
0885         chip->legacy.dev_ready = s3c2440_nand_devready;
0886         chip->legacy.read_buf  = s3c2440_nand_read_buf;
0887         chip->legacy.write_buf  = s3c2440_nand_write_buf;
0888         break;
0889 
0890     case TYPE_S3C2412:
0891         chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
0892         info->sel_reg   = regs + S3C2440_NFCONT;
0893         info->sel_bit   = S3C2412_NFCONT_nFCE0;
0894         chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
0895         chip->legacy.dev_ready = s3c2412_nand_devready;
0896 
0897         if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
0898             dev_info(info->device, "System booted from NAND\n");
0899 
0900         break;
0901     }
0902 
0903     chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
0904 
0905     nmtd->info     = info;
0906     nmtd->set      = set;
0907 
0908     chip->ecc.engine_type = info->platform->engine_type;
0909 
0910     /*
0911      * If you use u-boot BBT creation code, specifying this flag will
0912      * let the kernel fish out the BBT from the NAND.
0913      */
0914     if (set->flash_bbt)
0915         chip->bbt_options |= NAND_BBT_USE_FLASH;
0916 }
0917 
0918 /**
0919  * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
0920  * @chip: The NAND chip
0921  *
0922  * This hook is called by the core after the identification of the NAND chip,
0923  * once the relevant per-chip information is up to date.. This call ensure that
0924  * we update the internal state accordingly.
0925  *
0926  * The internal state is currently limited to the ECC state information.
0927 */
0928 static int s3c2410_nand_attach_chip(struct nand_chip *chip)
0929 {
0930     struct mtd_info *mtd = nand_to_mtd(chip);
0931     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
0932 
0933     switch (chip->ecc.engine_type) {
0934 
0935     case NAND_ECC_ENGINE_TYPE_NONE:
0936         dev_info(info->device, "ECC disabled\n");
0937         break;
0938 
0939     case NAND_ECC_ENGINE_TYPE_SOFT:
0940         /*
0941          * This driver expects Hamming based ECC when engine_type is set
0942          * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
0943          * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field
0944          * to s3c2410_platform_nand.
0945          */
0946         chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
0947         dev_info(info->device, "soft ECC\n");
0948         break;
0949 
0950     case NAND_ECC_ENGINE_TYPE_ON_HOST:
0951         chip->ecc.calculate = s3c2410_nand_calculate_ecc;
0952         chip->ecc.correct   = s3c2410_nand_correct_data;
0953         chip->ecc.strength  = 1;
0954 
0955         switch (info->cpu_type) {
0956         case TYPE_S3C2410:
0957             chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
0958             chip->ecc.calculate = s3c2410_nand_calculate_ecc;
0959             break;
0960 
0961         case TYPE_S3C2412:
0962             chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
0963             chip->ecc.calculate = s3c2412_nand_calculate_ecc;
0964             break;
0965 
0966         case TYPE_S3C2440:
0967             chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
0968             chip->ecc.calculate = s3c2440_nand_calculate_ecc;
0969             break;
0970         }
0971 
0972         dev_dbg(info->device, "chip %p => page shift %d\n",
0973             chip, chip->page_shift);
0974 
0975         /* change the behaviour depending on whether we are using
0976          * the large or small page nand device */
0977         if (chip->page_shift > 10) {
0978             chip->ecc.size      = 256;
0979             chip->ecc.bytes     = 3;
0980         } else {
0981             chip->ecc.size      = 512;
0982             chip->ecc.bytes     = 3;
0983             mtd_set_ooblayout(nand_to_mtd(chip),
0984                       &s3c2410_ooblayout_ops);
0985         }
0986 
0987         dev_info(info->device, "hardware ECC\n");
0988         break;
0989 
0990     default:
0991         dev_err(info->device, "invalid ECC mode!\n");
0992         return -EINVAL;
0993     }
0994 
0995     if (chip->bbt_options & NAND_BBT_USE_FLASH)
0996         chip->options |= NAND_SKIP_BBTSCAN;
0997 
0998     return 0;
0999 }
1000 
1001 static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
1002     .attach_chip = s3c2410_nand_attach_chip,
1003     .setup_interface = s3c2410_nand_setup_interface,
1004 };
1005 
1006 static const struct of_device_id s3c24xx_nand_dt_ids[] = {
1007     {
1008         .compatible = "samsung,s3c2410-nand",
1009         .data = &s3c2410_nand_devtype_data,
1010     }, {
1011         /* also compatible with s3c6400 */
1012         .compatible = "samsung,s3c2412-nand",
1013         .data = &s3c2412_nand_devtype_data,
1014     }, {
1015         .compatible = "samsung,s3c2440-nand",
1016         .data = &s3c2440_nand_devtype_data,
1017     },
1018     { /* sentinel */ }
1019 };
1020 MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
1021 
1022 static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
1023 {
1024     const struct s3c24XX_nand_devtype_data *devtype_data;
1025     struct s3c2410_platform_nand *pdata;
1026     struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
1027     struct device_node *np = pdev->dev.of_node, *child;
1028     struct s3c2410_nand_set *sets;
1029 
1030     devtype_data = of_device_get_match_data(&pdev->dev);
1031     if (!devtype_data)
1032         return -ENODEV;
1033 
1034     info->cpu_type = devtype_data->type;
1035 
1036     pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1037     if (!pdata)
1038         return -ENOMEM;
1039 
1040     pdev->dev.platform_data = pdata;
1041 
1042     pdata->nr_sets = of_get_child_count(np);
1043     if (!pdata->nr_sets)
1044         return 0;
1045 
1046     sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets),
1047                 GFP_KERNEL);
1048     if (!sets)
1049         return -ENOMEM;
1050 
1051     pdata->sets = sets;
1052 
1053     for_each_available_child_of_node(np, child) {
1054         sets->name = (char *)child->name;
1055         sets->of_node = child;
1056         sets->nr_chips = 1;
1057 
1058         of_node_get(child);
1059 
1060         sets++;
1061     }
1062 
1063     return 0;
1064 }
1065 
1066 static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
1067 {
1068     struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
1069 
1070     info->cpu_type = platform_get_device_id(pdev)->driver_data;
1071 
1072     return 0;
1073 }
1074 
1075 /* s3c24xx_nand_probe
1076  *
1077  * called by device layer when it finds a device matching
1078  * one our driver can handled. This code checks to see if
1079  * it can allocate all necessary resources then calls the
1080  * nand layer to look for devices
1081 */
1082 static int s3c24xx_nand_probe(struct platform_device *pdev)
1083 {
1084     struct s3c2410_platform_nand *plat;
1085     struct s3c2410_nand_info *info;
1086     struct s3c2410_nand_mtd *nmtd;
1087     struct s3c2410_nand_set *sets;
1088     struct resource *res;
1089     int err = 0;
1090     int size;
1091     int nr_sets;
1092     int setno;
1093 
1094     info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
1095     if (info == NULL) {
1096         err = -ENOMEM;
1097         goto exit_error;
1098     }
1099 
1100     platform_set_drvdata(pdev, info);
1101 
1102     nand_controller_init(&info->controller);
1103     info->controller.ops = &s3c24xx_nand_controller_ops;
1104 
1105     /* get the clock source and enable it */
1106 
1107     info->clk = devm_clk_get(&pdev->dev, "nand");
1108     if (IS_ERR(info->clk)) {
1109         dev_err(&pdev->dev, "failed to get clock\n");
1110         err = -ENOENT;
1111         goto exit_error;
1112     }
1113 
1114     s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
1115 
1116     if (pdev->dev.of_node)
1117         err = s3c24xx_nand_probe_dt(pdev);
1118     else
1119         err = s3c24xx_nand_probe_pdata(pdev);
1120 
1121     if (err)
1122         goto exit_error;
1123 
1124     plat = to_nand_plat(pdev);
1125 
1126     /* allocate and map the resource */
1127 
1128     /* currently we assume we have the one resource */
1129     res = pdev->resource;
1130     size = resource_size(res);
1131 
1132     info->device    = &pdev->dev;
1133     info->platform  = plat;
1134 
1135     info->regs = devm_ioremap_resource(&pdev->dev, res);
1136     if (IS_ERR(info->regs)) {
1137         err = PTR_ERR(info->regs);
1138         goto exit_error;
1139     }
1140 
1141     dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
1142 
1143     if (!plat->sets || plat->nr_sets < 1) {
1144         err = -EINVAL;
1145         goto exit_error;
1146     }
1147 
1148     sets = plat->sets;
1149     nr_sets = plat->nr_sets;
1150 
1151     info->mtd_count = nr_sets;
1152 
1153     /* allocate our information */
1154 
1155     size = nr_sets * sizeof(*info->mtds);
1156     info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
1157     if (info->mtds == NULL) {
1158         err = -ENOMEM;
1159         goto exit_error;
1160     }
1161 
1162     /* initialise all possible chips */
1163 
1164     nmtd = info->mtds;
1165 
1166     for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) {
1167         struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
1168 
1169         pr_debug("initialising set %d (%p, info %p)\n",
1170              setno, nmtd, info);
1171 
1172         mtd->dev.parent = &pdev->dev;
1173         s3c2410_nand_init_chip(info, nmtd, sets);
1174 
1175         err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
1176         if (err)
1177             goto exit_error;
1178 
1179         s3c2410_nand_add_partition(info, nmtd, sets);
1180     }
1181 
1182     /* initialise the hardware */
1183     err = s3c2410_nand_inithw(info);
1184     if (err != 0)
1185         goto exit_error;
1186 
1187     err = s3c2410_nand_cpufreq_register(info);
1188     if (err < 0) {
1189         dev_err(&pdev->dev, "failed to init cpufreq support\n");
1190         goto exit_error;
1191     }
1192 
1193     if (allow_clk_suspend(info)) {
1194         dev_info(&pdev->dev, "clock idle support enabled\n");
1195         s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
1196     }
1197 
1198     return 0;
1199 
1200  exit_error:
1201     s3c24xx_nand_remove(pdev);
1202 
1203     if (err == 0)
1204         err = -EINVAL;
1205     return err;
1206 }
1207 
1208 /* PM Support */
1209 #ifdef CONFIG_PM
1210 
1211 static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
1212 {
1213     struct s3c2410_nand_info *info = platform_get_drvdata(dev);
1214 
1215     if (info) {
1216         info->save_sel = readl(info->sel_reg);
1217 
1218         /* For the moment, we must ensure nFCE is high during
1219          * the time we are suspended. This really should be
1220          * handled by suspending the MTDs we are using, but
1221          * that is currently not the case. */
1222 
1223         writel(info->save_sel | info->sel_bit, info->sel_reg);
1224 
1225         s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
1226     }
1227 
1228     return 0;
1229 }
1230 
1231 static int s3c24xx_nand_resume(struct platform_device *dev)
1232 {
1233     struct s3c2410_nand_info *info = platform_get_drvdata(dev);
1234     unsigned long sel;
1235 
1236     if (info) {
1237         s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
1238         s3c2410_nand_inithw(info);
1239 
1240         /* Restore the state of the nFCE line. */
1241 
1242         sel = readl(info->sel_reg);
1243         sel &= ~info->sel_bit;
1244         sel |= info->save_sel & info->sel_bit;
1245         writel(sel, info->sel_reg);
1246 
1247         s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
1248     }
1249 
1250     return 0;
1251 }
1252 
1253 #else
1254 #define s3c24xx_nand_suspend NULL
1255 #define s3c24xx_nand_resume NULL
1256 #endif
1257 
1258 /* driver device registration */
1259 
1260 static const struct platform_device_id s3c24xx_driver_ids[] = {
1261     {
1262         .name       = "s3c2410-nand",
1263         .driver_data    = TYPE_S3C2410,
1264     }, {
1265         .name       = "s3c2440-nand",
1266         .driver_data    = TYPE_S3C2440,
1267     }, {
1268         .name       = "s3c2412-nand",
1269         .driver_data    = TYPE_S3C2412,
1270     }, {
1271         .name       = "s3c6400-nand",
1272         .driver_data    = TYPE_S3C2412, /* compatible with 2412 */
1273     },
1274     { }
1275 };
1276 
1277 MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
1278 
1279 static struct platform_driver s3c24xx_nand_driver = {
1280     .probe      = s3c24xx_nand_probe,
1281     .remove     = s3c24xx_nand_remove,
1282     .suspend    = s3c24xx_nand_suspend,
1283     .resume     = s3c24xx_nand_resume,
1284     .id_table   = s3c24xx_driver_ids,
1285     .driver     = {
1286         .name   = "s3c24xx-nand",
1287         .of_match_table = s3c24xx_nand_dt_ids,
1288     },
1289 };
1290 
1291 module_platform_driver(s3c24xx_nand_driver);
1292 
1293 MODULE_LICENSE("GPL");
1294 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1295 MODULE_DESCRIPTION("S3C24XX MTD NAND driver");