cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

s3c2410.c (33204B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright © 2004-2008 Simtec Electronics
      4 *	http://armlinux.simtec.co.uk/
      5 *	Ben Dooks <ben@simtec.co.uk>
      6 *
      7 * Samsung S3C2410/S3C2440/S3C2412 NAND driver
      8*/
      9
     10#define pr_fmt(fmt) "nand-s3c2410: " fmt
     11
     12#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
     13#define DEBUG
     14#endif
     15
     16#include <linux/module.h>
     17#include <linux/types.h>
     18#include <linux/kernel.h>
     19#include <linux/string.h>
     20#include <linux/io.h>
     21#include <linux/ioport.h>
     22#include <linux/platform_device.h>
     23#include <linux/delay.h>
     24#include <linux/err.h>
     25#include <linux/slab.h>
     26#include <linux/clk.h>
     27#include <linux/cpufreq.h>
     28#include <linux/of.h>
     29#include <linux/of_device.h>
     30
     31#include <linux/mtd/mtd.h>
     32#include <linux/mtd/rawnand.h>
     33#include <linux/mtd/partitions.h>
     34
     35#include <linux/platform_data/mtd-nand-s3c2410.h>
     36
     37#define S3C2410_NFREG(x) (x)
     38
     39#define S3C2410_NFCONF		S3C2410_NFREG(0x00)
     40#define S3C2410_NFCMD		S3C2410_NFREG(0x04)
     41#define S3C2410_NFADDR		S3C2410_NFREG(0x08)
     42#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
     43#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
     44#define S3C2410_NFECC		S3C2410_NFREG(0x14)
     45#define S3C2440_NFCONT		S3C2410_NFREG(0x04)
     46#define S3C2440_NFCMD		S3C2410_NFREG(0x08)
     47#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
     48#define S3C2440_NFDATA		S3C2410_NFREG(0x10)
     49#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
     50#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
     51#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
     52#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
     53#define S3C2410_NFCONF_EN		(1<<15)
     54#define S3C2410_NFCONF_INITECC		(1<<12)
     55#define S3C2410_NFCONF_nFCE		(1<<11)
     56#define S3C2410_NFCONF_TACLS(x)		((x)<<8)
     57#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
     58#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
     59#define S3C2410_NFSTAT_BUSY		(1<<0)
     60#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
     61#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
     62#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
     63#define S3C2440_NFCONT_INITECC		(1<<4)
     64#define S3C2440_NFCONT_nFCE		(1<<1)
     65#define S3C2440_NFCONT_ENABLE		(1<<0)
     66#define S3C2440_NFSTAT_READY		(1<<0)
     67#define S3C2412_NFCONF_NANDBOOT		(1<<31)
     68#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
     69#define S3C2412_NFCONT_nFCE0		(1<<1)
     70#define S3C2412_NFSTAT_READY		(1<<0)
     71
     72/* new oob placement block for use with hardware ecc generation
     73 */
     74static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
     75				 struct mtd_oob_region *oobregion)
     76{
     77	if (section)
     78		return -ERANGE;
     79
     80	oobregion->offset = 0;
     81	oobregion->length = 3;
     82
     83	return 0;
     84}
     85
     86static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
     87				  struct mtd_oob_region *oobregion)
     88{
     89	if (section)
     90		return -ERANGE;
     91
     92	oobregion->offset = 8;
     93	oobregion->length = 8;
     94
     95	return 0;
     96}
     97
     98static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
     99	.ecc = s3c2410_ooblayout_ecc,
    100	.free = s3c2410_ooblayout_free,
    101};
    102
    103/* controller and mtd information */
    104
    105struct s3c2410_nand_info;
    106
    107/**
    108 * struct s3c2410_nand_mtd - driver MTD structure
    109 * @mtd: The MTD instance to pass to the MTD layer.
    110 * @chip: The NAND chip information.
    111 * @set: The platform information supplied for this set of NAND chips.
    112 * @info: Link back to the hardware information.
    113*/
    114struct s3c2410_nand_mtd {
    115	struct nand_chip		chip;
    116	struct s3c2410_nand_set		*set;
    117	struct s3c2410_nand_info	*info;
    118};
    119
    120enum s3c_cpu_type {
    121	TYPE_S3C2410,
    122	TYPE_S3C2412,
    123	TYPE_S3C2440,
    124};
    125
    126enum s3c_nand_clk_state {
    127	CLOCK_DISABLE	= 0,
    128	CLOCK_ENABLE,
    129	CLOCK_SUSPEND,
    130};
    131
    132/* overview of the s3c2410 nand state */
    133
    134/**
    135 * struct s3c2410_nand_info - NAND controller state.
    136 * @controller: Base controller structure.
    137 * @mtds: An array of MTD instances on this controller.
    138 * @platform: The platform data for this board.
    139 * @device: The platform device we bound to.
    140 * @clk: The clock resource for this controller.
    141 * @regs: The area mapped for the hardware registers.
    142 * @sel_reg: Pointer to the register controlling the NAND selection.
    143 * @sel_bit: The bit in @sel_reg to select the NAND chip.
    144 * @mtd_count: The number of MTDs created from this controller.
    145 * @save_sel: The contents of @sel_reg to be saved over suspend.
    146 * @clk_rate: The clock rate from @clk.
    147 * @clk_state: The current clock state.
    148 * @cpu_type: The exact type of this controller.
    149 * @freq_transition: CPUFreq notifier block
    150 */
    151struct s3c2410_nand_info {
    152	/* mtd info */
    153	struct nand_controller		controller;
    154	struct s3c2410_nand_mtd		*mtds;
    155	struct s3c2410_platform_nand	*platform;
    156
    157	/* device info */
    158	struct device			*device;
    159	struct clk			*clk;
    160	void __iomem			*regs;
    161	void __iomem			*sel_reg;
    162	int				sel_bit;
    163	int				mtd_count;
    164	unsigned long			save_sel;
    165	unsigned long			clk_rate;
    166	enum s3c_nand_clk_state		clk_state;
    167
    168	enum s3c_cpu_type		cpu_type;
    169
    170#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
    171	struct notifier_block	freq_transition;
    172#endif
    173};
    174
    175struct s3c24XX_nand_devtype_data {
    176	enum s3c_cpu_type type;
    177};
    178
    179static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
    180	.type = TYPE_S3C2410,
    181};
    182
    183static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
    184	.type = TYPE_S3C2412,
    185};
    186
    187static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
    188	.type = TYPE_S3C2440,
    189};
    190
    191/* conversion functions */
    192
    193static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
    194{
    195	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
    196			    chip);
    197}
    198
    199static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
    200{
    201	return s3c2410_nand_mtd_toours(mtd)->info;
    202}
    203
    204static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
    205{
    206	return platform_get_drvdata(dev);
    207}
    208
    209static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
    210{
    211	return dev_get_platdata(&dev->dev);
    212}
    213
    214static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
    215{
    216#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
    217	return 1;
    218#else
    219	return 0;
    220#endif
    221}
    222
    223/**
    224 * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
    225 * @info: The controller instance.
    226 * @new_state: State to which clock should be set.
    227 */
    228static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
    229		enum s3c_nand_clk_state new_state)
    230{
    231	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
    232		return;
    233
    234	if (info->clk_state == CLOCK_ENABLE) {
    235		if (new_state != CLOCK_ENABLE)
    236			clk_disable_unprepare(info->clk);
    237	} else {
    238		if (new_state == CLOCK_ENABLE)
    239			clk_prepare_enable(info->clk);
    240	}
    241
    242	info->clk_state = new_state;
    243}
    244
    245/* timing calculations */
    246
    247#define NS_IN_KHZ 1000000
    248
    249/**
    250 * s3c_nand_calc_rate - calculate timing data.
    251 * @wanted: The cycle time in nanoseconds.
    252 * @clk: The clock rate in kHz.
    253 * @max: The maximum divider value.
    254 *
    255 * Calculate the timing value from the given parameters.
    256 */
    257static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
    258{
    259	int result;
    260
    261	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
    262
    263	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
    264
    265	if (result > max) {
    266		pr_err("%d ns is too big for current clock rate %ld\n",
    267			wanted, clk);
    268		return -1;
    269	}
    270
    271	if (result < 1)
    272		result = 1;
    273
    274	return result;
    275}
    276
    277#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
    278
    279/* controller setup */
    280
    281/**
    282 * s3c2410_nand_setrate - setup controller timing information.
    283 * @info: The controller instance.
    284 *
    285 * Given the information supplied by the platform, calculate and set
    286 * the necessary timing registers in the hardware to generate the
    287 * necessary timing cycles to the hardware.
    288 */
    289static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
    290{
    291	struct s3c2410_platform_nand *plat = info->platform;
    292	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
    293	int tacls, twrph0, twrph1;
    294	unsigned long clkrate = clk_get_rate(info->clk);
    295	unsigned long set, cfg, mask;
    296	unsigned long flags;
    297
    298	/* calculate the timing information for the controller */
    299
    300	info->clk_rate = clkrate;
    301	clkrate /= 1000;	/* turn clock into kHz for ease of use */
    302
    303	if (plat != NULL) {
    304		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
    305		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
    306		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
    307	} else {
    308		/* default timings */
    309		tacls = tacls_max;
    310		twrph0 = 8;
    311		twrph1 = 8;
    312	}
    313
    314	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
    315		dev_err(info->device, "cannot get suitable timings\n");
    316		return -EINVAL;
    317	}
    318
    319	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
    320		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
    321						twrph1, to_ns(twrph1, clkrate));
    322
    323	switch (info->cpu_type) {
    324	case TYPE_S3C2410:
    325		mask = (S3C2410_NFCONF_TACLS(3) |
    326			S3C2410_NFCONF_TWRPH0(7) |
    327			S3C2410_NFCONF_TWRPH1(7));
    328		set = S3C2410_NFCONF_EN;
    329		set |= S3C2410_NFCONF_TACLS(tacls - 1);
    330		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    331		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
    332		break;
    333
    334	case TYPE_S3C2440:
    335	case TYPE_S3C2412:
    336		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
    337			S3C2440_NFCONF_TWRPH0(7) |
    338			S3C2440_NFCONF_TWRPH1(7));
    339
    340		set = S3C2440_NFCONF_TACLS(tacls - 1);
    341		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
    342		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
    343		break;
    344
    345	default:
    346		BUG();
    347	}
    348
    349	local_irq_save(flags);
    350
    351	cfg = readl(info->regs + S3C2410_NFCONF);
    352	cfg &= ~mask;
    353	cfg |= set;
    354	writel(cfg, info->regs + S3C2410_NFCONF);
    355
    356	local_irq_restore(flags);
    357
    358	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
    359
    360	return 0;
    361}
    362
    363/**
    364 * s3c2410_nand_inithw - basic hardware initialisation
    365 * @info: The hardware state.
    366 *
    367 * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
    368 * to setup the hardware access speeds and set the controller to be enabled.
    369*/
    370static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
    371{
    372	int ret;
    373
    374	ret = s3c2410_nand_setrate(info);
    375	if (ret < 0)
    376		return ret;
    377
    378	switch (info->cpu_type) {
    379	case TYPE_S3C2410:
    380	default:
    381		break;
    382
    383	case TYPE_S3C2440:
    384	case TYPE_S3C2412:
    385		/* enable the controller and de-assert nFCE */
    386
    387		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
    388	}
    389
    390	return 0;
    391}
    392
    393/**
    394 * s3c2410_nand_select_chip - select the given nand chip
    395 * @this: NAND chip object.
    396 * @chip: The chip number.
    397 *
    398 * This is called by the MTD layer to either select a given chip for the
    399 * @mtd instance, or to indicate that the access has finished and the
    400 * chip can be de-selected.
    401 *
    402 * The routine ensures that the nFCE line is correctly setup, and any
    403 * platform specific selection code is called to route nFCE to the specific
    404 * chip.
    405 */
    406static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
    407{
    408	struct s3c2410_nand_info *info;
    409	struct s3c2410_nand_mtd *nmtd;
    410	unsigned long cur;
    411
    412	nmtd = nand_get_controller_data(this);
    413	info = nmtd->info;
    414
    415	if (chip != -1)
    416		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
    417
    418	cur = readl(info->sel_reg);
    419
    420	if (chip == -1) {
    421		cur |= info->sel_bit;
    422	} else {
    423		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
    424			dev_err(info->device, "invalid chip %d\n", chip);
    425			return;
    426		}
    427
    428		if (info->platform != NULL) {
    429			if (info->platform->select_chip != NULL)
    430				(info->platform->select_chip) (nmtd->set, chip);
    431		}
    432
    433		cur &= ~info->sel_bit;
    434	}
    435
    436	writel(cur, info->sel_reg);
    437
    438	if (chip == -1)
    439		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
    440}
    441
    442/* s3c2410_nand_hwcontrol
    443 *
    444 * Issue command and address cycles to the chip
    445*/
    446
    447static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
    448				   unsigned int ctrl)
    449{
    450	struct mtd_info *mtd = nand_to_mtd(chip);
    451	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    452
    453	if (cmd == NAND_CMD_NONE)
    454		return;
    455
    456	if (ctrl & NAND_CLE)
    457		writeb(cmd, info->regs + S3C2410_NFCMD);
    458	else
    459		writeb(cmd, info->regs + S3C2410_NFADDR);
    460}
    461
    462/* command and control functions */
    463
    464static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
    465				   unsigned int ctrl)
    466{
    467	struct mtd_info *mtd = nand_to_mtd(chip);
    468	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    469
    470	if (cmd == NAND_CMD_NONE)
    471		return;
    472
    473	if (ctrl & NAND_CLE)
    474		writeb(cmd, info->regs + S3C2440_NFCMD);
    475	else
    476		writeb(cmd, info->regs + S3C2440_NFADDR);
    477}
    478
    479/* s3c2410_nand_devready()
    480 *
    481 * returns 0 if the nand is busy, 1 if it is ready
    482*/
    483
    484static int s3c2410_nand_devready(struct nand_chip *chip)
    485{
    486	struct mtd_info *mtd = nand_to_mtd(chip);
    487	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    488	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
    489}
    490
    491static int s3c2440_nand_devready(struct nand_chip *chip)
    492{
    493	struct mtd_info *mtd = nand_to_mtd(chip);
    494	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    495	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
    496}
    497
    498static int s3c2412_nand_devready(struct nand_chip *chip)
    499{
    500	struct mtd_info *mtd = nand_to_mtd(chip);
    501	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    502	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
    503}
    504
    505/* ECC handling functions */
    506
    507static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
    508				     u_char *read_ecc, u_char *calc_ecc)
    509{
    510	struct mtd_info *mtd = nand_to_mtd(chip);
    511	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    512	unsigned int diff0, diff1, diff2;
    513	unsigned int bit, byte;
    514
    515	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
    516
    517	diff0 = read_ecc[0] ^ calc_ecc[0];
    518	diff1 = read_ecc[1] ^ calc_ecc[1];
    519	diff2 = read_ecc[2] ^ calc_ecc[2];
    520
    521	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
    522		 __func__, 3, read_ecc, 3, calc_ecc,
    523		 diff0, diff1, diff2);
    524
    525	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
    526		return 0;		/* ECC is ok */
    527
    528	/* sometimes people do not think about using the ECC, so check
    529	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
    530	 * the error, on the assumption that this is an un-eccd page.
    531	 */
    532	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
    533	    && info->platform->ignore_unset_ecc)
    534		return 0;
    535
    536	/* Can we correct this ECC (ie, one row and column change).
    537	 * Note, this is similar to the 256 error code on smartmedia */
    538
    539	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
    540	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
    541	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
    542		/* calculate the bit position of the error */
    543
    544		bit  = ((diff2 >> 3) & 1) |
    545		       ((diff2 >> 4) & 2) |
    546		       ((diff2 >> 5) & 4);
    547
    548		/* calculate the byte position of the error */
    549
    550		byte = ((diff2 << 7) & 0x100) |
    551		       ((diff1 << 0) & 0x80)  |
    552		       ((diff1 << 1) & 0x40)  |
    553		       ((diff1 << 2) & 0x20)  |
    554		       ((diff1 << 3) & 0x10)  |
    555		       ((diff0 >> 4) & 0x08)  |
    556		       ((diff0 >> 3) & 0x04)  |
    557		       ((diff0 >> 2) & 0x02)  |
    558		       ((diff0 >> 1) & 0x01);
    559
    560		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
    561			bit, byte);
    562
    563		dat[byte] ^= (1 << bit);
    564		return 1;
    565	}
    566
    567	/* if there is only one bit difference in the ECC, then
    568	 * one of only a row or column parity has changed, which
    569	 * means the error is most probably in the ECC itself */
    570
    571	diff0 |= (diff1 << 8);
    572	diff0 |= (diff2 << 16);
    573
    574	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
    575	if ((diff0 & (diff0 - 1)) == 0)
    576		return 1;
    577
    578	return -1;
    579}
    580
    581/* ECC functions
    582 *
    583 * These allow the s3c2410 and s3c2440 to use the controller's ECC
    584 * generator block to ECC the data as it passes through]
    585*/
    586
    587static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
    588{
    589	struct s3c2410_nand_info *info;
    590	unsigned long ctrl;
    591
    592	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
    593	ctrl = readl(info->regs + S3C2410_NFCONF);
    594	ctrl |= S3C2410_NFCONF_INITECC;
    595	writel(ctrl, info->regs + S3C2410_NFCONF);
    596}
    597
    598static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
    599{
    600	struct s3c2410_nand_info *info;
    601	unsigned long ctrl;
    602
    603	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
    604	ctrl = readl(info->regs + S3C2440_NFCONT);
    605	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
    606	       info->regs + S3C2440_NFCONT);
    607}
    608
    609static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
    610{
    611	struct s3c2410_nand_info *info;
    612	unsigned long ctrl;
    613
    614	info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
    615	ctrl = readl(info->regs + S3C2440_NFCONT);
    616	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
    617}
    618
    619static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
    620				      const u_char *dat, u_char *ecc_code)
    621{
    622	struct mtd_info *mtd = nand_to_mtd(chip);
    623	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    624
    625	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
    626	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
    627	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
    628
    629	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
    630
    631	return 0;
    632}
    633
    634static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
    635				      const u_char *dat, u_char *ecc_code)
    636{
    637	struct mtd_info *mtd = nand_to_mtd(chip);
    638	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    639	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
    640
    641	ecc_code[0] = ecc;
    642	ecc_code[1] = ecc >> 8;
    643	ecc_code[2] = ecc >> 16;
    644
    645	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
    646
    647	return 0;
    648}
    649
    650static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
    651				      const u_char *dat, u_char *ecc_code)
    652{
    653	struct mtd_info *mtd = nand_to_mtd(chip);
    654	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    655	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
    656
    657	ecc_code[0] = ecc;
    658	ecc_code[1] = ecc >> 8;
    659	ecc_code[2] = ecc >> 16;
    660
    661	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
    662
    663	return 0;
    664}
    665
    666/* over-ride the standard functions for a little more speed. We can
    667 * use read/write block to move the data buffers to/from the controller
    668*/
    669
    670static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
    671{
    672	readsb(this->legacy.IO_ADDR_R, buf, len);
    673}
    674
    675static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
    676{
    677	struct mtd_info *mtd = nand_to_mtd(this);
    678	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    679
    680	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
    681
    682	/* cleanup if we've got less than a word to do */
    683	if (len & 3) {
    684		buf += len & ~3;
    685
    686		for (; len & 3; len--)
    687			*buf++ = readb(info->regs + S3C2440_NFDATA);
    688	}
    689}
    690
    691static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
    692				   int len)
    693{
    694	writesb(this->legacy.IO_ADDR_W, buf, len);
    695}
    696
    697static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
    698				   int len)
    699{
    700	struct mtd_info *mtd = nand_to_mtd(this);
    701	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    702
    703	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
    704
    705	/* cleanup any fractional write */
    706	if (len & 3) {
    707		buf += len & ~3;
    708
    709		for (; len & 3; len--, buf++)
    710			writeb(*buf, info->regs + S3C2440_NFDATA);
    711	}
    712}
    713
    714/* cpufreq driver support */
    715
    716#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
    717
    718static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
    719					  unsigned long val, void *data)
    720{
    721	struct s3c2410_nand_info *info;
    722	unsigned long newclk;
    723
    724	info = container_of(nb, struct s3c2410_nand_info, freq_transition);
    725	newclk = clk_get_rate(info->clk);
    726
    727	if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
    728	    (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
    729		s3c2410_nand_setrate(info);
    730	}
    731
    732	return 0;
    733}
    734
    735static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
    736{
    737	info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
    738
    739	return cpufreq_register_notifier(&info->freq_transition,
    740					 CPUFREQ_TRANSITION_NOTIFIER);
    741}
    742
    743static inline void
    744s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
    745{
    746	cpufreq_unregister_notifier(&info->freq_transition,
    747				    CPUFREQ_TRANSITION_NOTIFIER);
    748}
    749
    750#else
    751static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
    752{
    753	return 0;
    754}
    755
    756static inline void
    757s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
    758{
    759}
    760#endif
    761
    762/* device management functions */
    763
    764static int s3c24xx_nand_remove(struct platform_device *pdev)
    765{
    766	struct s3c2410_nand_info *info = to_nand_info(pdev);
    767
    768	if (info == NULL)
    769		return 0;
    770
    771	s3c2410_nand_cpufreq_deregister(info);
    772
    773	/* Release all our mtds  and their partitions, then go through
    774	 * freeing the resources used
    775	 */
    776
    777	if (info->mtds != NULL) {
    778		struct s3c2410_nand_mtd *ptr = info->mtds;
    779		int mtdno;
    780
    781		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
    782			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
    783			WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip)));
    784			nand_cleanup(&ptr->chip);
    785		}
    786	}
    787
    788	/* free the common resources */
    789
    790	if (!IS_ERR(info->clk))
    791		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
    792
    793	return 0;
    794}
    795
    796static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
    797				      struct s3c2410_nand_mtd *mtd,
    798				      struct s3c2410_nand_set *set)
    799{
    800	if (set) {
    801		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
    802
    803		mtdinfo->name = set->name;
    804
    805		return mtd_device_register(mtdinfo, set->partitions,
    806					   set->nr_partitions);
    807	}
    808
    809	return -ENODEV;
    810}
    811
    812static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,
    813					const struct nand_interface_config *conf)
    814{
    815	struct mtd_info *mtd = nand_to_mtd(chip);
    816	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    817	struct s3c2410_platform_nand *pdata = info->platform;
    818	const struct nand_sdr_timings *timings;
    819	int tacls;
    820
    821	timings = nand_get_sdr_timings(conf);
    822	if (IS_ERR(timings))
    823		return -ENOTSUPP;
    824
    825	tacls = timings->tCLS_min - timings->tWP_min;
    826	if (tacls < 0)
    827		tacls = 0;
    828
    829	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
    830	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
    831	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
    832
    833	return s3c2410_nand_setrate(info);
    834}
    835
    836/**
    837 * s3c2410_nand_init_chip - initialise a single instance of an chip
    838 * @info: The base NAND controller the chip is on.
    839 * @nmtd: The new controller MTD instance to fill in.
    840 * @set: The information passed from the board specific platform data.
    841 *
    842 * Initialise the given @nmtd from the information in @info and @set. This
    843 * readies the structure for use with the MTD layer functions by ensuring
    844 * all pointers are setup and the necessary control routines selected.
    845 */
    846static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
    847				   struct s3c2410_nand_mtd *nmtd,
    848				   struct s3c2410_nand_set *set)
    849{
    850	struct device_node *np = info->device->of_node;
    851	struct nand_chip *chip = &nmtd->chip;
    852	void __iomem *regs = info->regs;
    853
    854	nand_set_flash_node(chip, set->of_node);
    855
    856	chip->legacy.write_buf    = s3c2410_nand_write_buf;
    857	chip->legacy.read_buf     = s3c2410_nand_read_buf;
    858	chip->legacy.select_chip  = s3c2410_nand_select_chip;
    859	chip->legacy.chip_delay   = 50;
    860	nand_set_controller_data(chip, nmtd);
    861	chip->options	   = set->options;
    862	chip->controller   = &info->controller;
    863
    864	/*
    865	 * let's keep behavior unchanged for legacy boards booting via pdata and
    866	 * auto-detect timings only when booting with a device tree.
    867	 */
    868	if (!np)
    869		chip->options |= NAND_KEEP_TIMINGS;
    870
    871	switch (info->cpu_type) {
    872	case TYPE_S3C2410:
    873		chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
    874		info->sel_reg   = regs + S3C2410_NFCONF;
    875		info->sel_bit	= S3C2410_NFCONF_nFCE;
    876		chip->legacy.cmd_ctrl  = s3c2410_nand_hwcontrol;
    877		chip->legacy.dev_ready = s3c2410_nand_devready;
    878		break;
    879
    880	case TYPE_S3C2440:
    881		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
    882		info->sel_reg   = regs + S3C2440_NFCONT;
    883		info->sel_bit	= S3C2440_NFCONT_nFCE;
    884		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
    885		chip->legacy.dev_ready = s3c2440_nand_devready;
    886		chip->legacy.read_buf  = s3c2440_nand_read_buf;
    887		chip->legacy.write_buf	= s3c2440_nand_write_buf;
    888		break;
    889
    890	case TYPE_S3C2412:
    891		chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
    892		info->sel_reg   = regs + S3C2440_NFCONT;
    893		info->sel_bit	= S3C2412_NFCONT_nFCE0;
    894		chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
    895		chip->legacy.dev_ready = s3c2412_nand_devready;
    896
    897		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
    898			dev_info(info->device, "System booted from NAND\n");
    899
    900		break;
    901	}
    902
    903	chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
    904
    905	nmtd->info	   = info;
    906	nmtd->set	   = set;
    907
    908	chip->ecc.engine_type = info->platform->engine_type;
    909
    910	/*
    911	 * If you use u-boot BBT creation code, specifying this flag will
    912	 * let the kernel fish out the BBT from the NAND.
    913	 */
    914	if (set->flash_bbt)
    915		chip->bbt_options |= NAND_BBT_USE_FLASH;
    916}
    917
    918/**
    919 * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
    920 * @chip: The NAND chip
    921 *
    922 * This hook is called by the core after the identification of the NAND chip,
    923 * once the relevant per-chip information is up to date.. This call ensure that
    924 * we update the internal state accordingly.
    925 *
    926 * The internal state is currently limited to the ECC state information.
    927*/
    928static int s3c2410_nand_attach_chip(struct nand_chip *chip)
    929{
    930	struct mtd_info *mtd = nand_to_mtd(chip);
    931	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
    932
    933	switch (chip->ecc.engine_type) {
    934
    935	case NAND_ECC_ENGINE_TYPE_NONE:
    936		dev_info(info->device, "ECC disabled\n");
    937		break;
    938
    939	case NAND_ECC_ENGINE_TYPE_SOFT:
    940		/*
    941		 * This driver expects Hamming based ECC when engine_type is set
    942		 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
    943		 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field
    944		 * to s3c2410_platform_nand.
    945		 */
    946		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
    947		dev_info(info->device, "soft ECC\n");
    948		break;
    949
    950	case NAND_ECC_ENGINE_TYPE_ON_HOST:
    951		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
    952		chip->ecc.correct   = s3c2410_nand_correct_data;
    953		chip->ecc.strength  = 1;
    954
    955		switch (info->cpu_type) {
    956		case TYPE_S3C2410:
    957			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
    958			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
    959			break;
    960
    961		case TYPE_S3C2412:
    962			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
    963			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
    964			break;
    965
    966		case TYPE_S3C2440:
    967			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
    968			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
    969			break;
    970		}
    971
    972		dev_dbg(info->device, "chip %p => page shift %d\n",
    973			chip, chip->page_shift);
    974
    975		/* change the behaviour depending on whether we are using
    976		 * the large or small page nand device */
    977		if (chip->page_shift > 10) {
    978			chip->ecc.size	    = 256;
    979			chip->ecc.bytes	    = 3;
    980		} else {
    981			chip->ecc.size	    = 512;
    982			chip->ecc.bytes	    = 3;
    983			mtd_set_ooblayout(nand_to_mtd(chip),
    984					  &s3c2410_ooblayout_ops);
    985		}
    986
    987		dev_info(info->device, "hardware ECC\n");
    988		break;
    989
    990	default:
    991		dev_err(info->device, "invalid ECC mode!\n");
    992		return -EINVAL;
    993	}
    994
    995	if (chip->bbt_options & NAND_BBT_USE_FLASH)
    996		chip->options |= NAND_SKIP_BBTSCAN;
    997
    998	return 0;
    999}
   1000
   1001static 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
   1006static 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};
   1020MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
   1021
   1022static 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
   1066static 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*/
   1082static 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
   1211static 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
   1231static 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
   1260static 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
   1277MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
   1278
   1279static 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
   1291module_platform_driver(s3c24xx_nand_driver);
   1292
   1293MODULE_LICENSE("GPL");
   1294MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
   1295MODULE_DESCRIPTION("S3C24XX MTD NAND driver");