aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/s3c2410.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/s3c2410.c')
-rw-r--r--drivers/mtd/nand/s3c2410.c297
1 files changed, 161 insertions, 136 deletions
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d05e9b97947d..891e3a1b9110 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -1,17 +1,24 @@
1/* linux/drivers/mtd/nand/s3c2410.c 1/* linux/drivers/mtd/nand/s3c2410.c
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004,2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * http://www.simtec.co.uk/products/SWLINUX/
5 * Ben Dooks <ben@simtec.co.uk>
5 * 6 *
6 * Samsung S3C2410 NAND driver 7 * Samsung S3C2410/S3C240 NAND driver
7 * 8 *
8 * Changelog: 9 * Changelog:
9 * 21-Sep-2004 BJD Initial version 10 * 21-Sep-2004 BJD Initial version
10 * 23-Sep-2004 BJD Mulitple device support 11 * 23-Sep-2004 BJD Mulitple device support
11 * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode 12 * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
12 * 12-Oct-2004 BJD Fixed errors in use of platform data 13 * 12-Oct-2004 BJD Fixed errors in use of platform data
14 * 18-Feb-2005 BJD Fix sparse errors
15 * 14-Mar-2005 BJD Applied tglx's code reduction patch
16 * 02-May-2005 BJD Fixed s3c2440 support
17 * 02-May-2005 BJD Reduced hwcontrol decode
18 * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
19 * 08-Jul-2005 BJD Fix OOPS when no platform data supplied
13 * 20 *
14 * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $ 21 * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $
15 * 22 *
16 * This program is free software; you can redistribute it and/or modify 23 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
@@ -69,10 +76,10 @@ static int hardware_ecc = 0;
69 */ 76 */
70 77
71static struct nand_oobinfo nand_hw_eccoob = { 78static struct nand_oobinfo nand_hw_eccoob = {
72 .useecc = MTD_NANDECC_AUTOPLACE, 79 .useecc = MTD_NANDECC_AUTOPLACE,
73 .eccbytes = 3, 80 .eccbytes = 3,
74 .eccpos = {0, 1, 2 }, 81 .eccpos = {0, 1, 2 },
75 .oobfree = { {8, 8} } 82 .oobfree = { {8, 8} }
76}; 83};
77 84
78/* controller and mtd information */ 85/* controller and mtd information */
@@ -99,8 +106,10 @@ struct s3c2410_nand_info {
99 struct device *device; 106 struct device *device;
100 struct resource *area; 107 struct resource *area;
101 struct clk *clk; 108 struct clk *clk;
102 void *regs; 109 void __iomem *regs;
103 int mtd_count; 110 int mtd_count;
111
112 unsigned char is_s3c2440;
104}; 113};
105 114
106/* conversion functions */ 115/* conversion functions */
@@ -165,12 +174,12 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
165 /* calculate the timing information for the controller */ 174 /* calculate the timing information for the controller */
166 175
167 if (plat != NULL) { 176 if (plat != NULL) {
168 tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8); 177 tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
169 twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); 178 twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
170 twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); 179 twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
171 } else { 180 } else {
172 /* default timings */ 181 /* default timings */
173 tacls = 8; 182 tacls = 4;
174 twrph0 = 8; 183 twrph0 = 8;
175 twrph1 = 8; 184 twrph1 = 8;
176 } 185 }
@@ -185,10 +194,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
185 to_ns(twrph0, clkrate), 194 to_ns(twrph0, clkrate),
186 to_ns(twrph1, clkrate)); 195 to_ns(twrph1, clkrate));
187 196
188 cfg = S3C2410_NFCONF_EN; 197 if (!info->is_s3c2440) {
189 cfg |= S3C2410_NFCONF_TACLS(tacls-1); 198 cfg = S3C2410_NFCONF_EN;
190 cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); 199 cfg |= S3C2410_NFCONF_TACLS(tacls-1);
191 cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); 200 cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
201 cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
202 } else {
203 cfg = S3C2440_NFCONF_TACLS(tacls-1);
204 cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1);
205 cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1);
206 }
192 207
193 pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); 208 pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
194 209
@@ -203,17 +218,22 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
203 struct s3c2410_nand_info *info; 218 struct s3c2410_nand_info *info;
204 struct s3c2410_nand_mtd *nmtd; 219 struct s3c2410_nand_mtd *nmtd;
205 struct nand_chip *this = mtd->priv; 220 struct nand_chip *this = mtd->priv;
221 void __iomem *reg;
206 unsigned long cur; 222 unsigned long cur;
223 unsigned long bit;
207 224
208 nmtd = this->priv; 225 nmtd = this->priv;
209 info = nmtd->info; 226 info = nmtd->info;
210 227
211 cur = readl(info->regs + S3C2410_NFCONF); 228 bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
229 reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF);
230
231 cur = readl(reg);
212 232
213 if (chip == -1) { 233 if (chip == -1) {
214 cur |= S3C2410_NFCONF_nFCE; 234 cur |= bit;
215 } else { 235 } else {
216 if (chip > nmtd->set->nr_chips) { 236 if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
217 printk(KERN_ERR PFX "chip %d out of range\n", chip); 237 printk(KERN_ERR PFX "chip %d out of range\n", chip);
218 return; 238 return;
219 } 239 }
@@ -223,143 +243,76 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
223 (info->platform->select_chip)(nmtd->set, chip); 243 (info->platform->select_chip)(nmtd->set, chip);
224 } 244 }
225 245
226 cur &= ~S3C2410_NFCONF_nFCE; 246 cur &= ~bit;
227 } 247 }
228 248
229 writel(cur, info->regs + S3C2410_NFCONF); 249 writel(cur, reg);
230} 250}
231 251
232/* command and control functions */ 252/* command and control functions
253 *
254 * Note, these all use tglx's method of changing the IO_ADDR_W field
255 * to make the code simpler, and use the nand layer's code to issue the
256 * command and address sequences via the proper IO ports.
257 *
258*/
233 259
234static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) 260static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
235{ 261{
236 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); 262 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
237 unsigned long cur; 263 struct nand_chip *chip = mtd->priv;
238 264
239 switch (cmd) { 265 switch (cmd) {
240 case NAND_CTL_SETNCE: 266 case NAND_CTL_SETNCE:
241 cur = readl(info->regs + S3C2410_NFCONF);
242 cur &= ~S3C2410_NFCONF_nFCE;
243 writel(cur, info->regs + S3C2410_NFCONF);
244 break;
245
246 case NAND_CTL_CLRNCE: 267 case NAND_CTL_CLRNCE:
247 cur = readl(info->regs + S3C2410_NFCONF); 268 printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
248 cur |= S3C2410_NFCONF_nFCE;
249 writel(cur, info->regs + S3C2410_NFCONF);
250 break; 269 break;
251 270
252 /* we don't need to implement these */
253 case NAND_CTL_SETCLE: 271 case NAND_CTL_SETCLE:
254 case NAND_CTL_CLRCLE: 272 chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;
273 break;
274
255 case NAND_CTL_SETALE: 275 case NAND_CTL_SETALE:
256 case NAND_CTL_CLRALE: 276 chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;
257 pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd); 277 break;
278
279 /* NAND_CTL_CLRCLE: */
280 /* NAND_CTL_CLRALE: */
281 default:
282 chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
258 break; 283 break;
259 } 284 }
260} 285}
261 286
262/* s3c2410_nand_command 287/* command and control functions */
263 *
264 * This function implements sending commands and the relevant address
265 * information to the chip, via the hardware controller. Since the
266 * S3C2410 generates the correct ALE/CLE signaling automatically, we
267 * do not need to use hwcontrol.
268*/
269 288
270static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command, 289static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
271 int column, int page_addr)
272{ 290{
273 register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); 291 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
274 register struct nand_chip *this = mtd->priv; 292 struct nand_chip *chip = mtd->priv;
275 293
276 /* 294 switch (cmd) {
277 * Write out the command to the device. 295 case NAND_CTL_SETNCE:
278 */ 296 case NAND_CTL_CLRNCE:
279 if (command == NAND_CMD_SEQIN) { 297 printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
280 int readcmd; 298 break;
281
282 if (column >= mtd->oobblock) {
283 /* OOB area */
284 column -= mtd->oobblock;
285 readcmd = NAND_CMD_READOOB;
286 } else if (column < 256) {
287 /* First 256 bytes --> READ0 */
288 readcmd = NAND_CMD_READ0;
289 } else {
290 column -= 256;
291 readcmd = NAND_CMD_READ1;
292 }
293
294 writeb(readcmd, info->regs + S3C2410_NFCMD);
295 }
296 writeb(command, info->regs + S3C2410_NFCMD);
297 299
298 /* Set ALE and clear CLE to start address cycle */ 300 case NAND_CTL_SETCLE:
301 chip->IO_ADDR_W = info->regs + S3C2440_NFCMD;
302 break;
299 303
300 if (column != -1 || page_addr != -1) { 304 case NAND_CTL_SETALE:
305 chip->IO_ADDR_W = info->regs + S3C2440_NFADDR;
306 break;
301 307
302 /* Serially input address */ 308 /* NAND_CTL_CLRCLE: */
303 if (column != -1) { 309 /* NAND_CTL_CLRALE: */
304 /* Adjust columns for 16 bit buswidth */
305 if (this->options & NAND_BUSWIDTH_16)
306 column >>= 1;
307 writeb(column, info->regs + S3C2410_NFADDR);
308 }
309 if (page_addr != -1) {
310 writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
311 writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
312 /* One more address cycle for higher density devices */
313 if (this->chipsize & 0x0c000000)
314 writeb((unsigned char) ((page_addr >> 16) & 0x0f),
315 info->regs + S3C2410_NFADDR);
316 }
317 /* Latch in address */
318 }
319
320 /*
321 * program and erase have their own busy handlers
322 * status and sequential in needs no delay
323 */
324 switch (command) {
325
326 case NAND_CMD_PAGEPROG:
327 case NAND_CMD_ERASE1:
328 case NAND_CMD_ERASE2:
329 case NAND_CMD_SEQIN:
330 case NAND_CMD_STATUS:
331 return;
332
333 case NAND_CMD_RESET:
334 if (this->dev_ready)
335 break;
336
337 udelay(this->chip_delay);
338 writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
339
340 while ( !(this->read_byte(mtd) & 0x40));
341 return;
342
343 /* This applies to read commands */
344 default: 310 default:
345 /* 311 chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
346 * If we don't have access to the busy pin, we apply the given 312 break;
347 * command delay
348 */
349 if (!this->dev_ready) {
350 udelay (this->chip_delay);
351 return;
352 }
353 } 313 }
354
355 /* Apply this short delay always to ensure that we do wait tWB in
356 * any case on any machine. */
357 ndelay (100);
358 /* wait until command is processed */
359 while (!this->dev_ready(mtd));
360} 314}
361 315
362
363/* s3c2410_nand_devready() 316/* s3c2410_nand_devready()
364 * 317 *
365 * returns 0 if the nand is busy, 1 if it is ready 318 * returns 0 if the nand is busy, 1 if it is ready
@@ -369,9 +322,12 @@ static int s3c2410_nand_devready(struct mtd_info *mtd)
369{ 322{
370 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); 323 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
371 324
325 if (info->is_s3c2440)
326 return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
372 return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; 327 return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
373} 328}
374 329
330
375/* ECC handling functions */ 331/* ECC handling functions */
376 332
377static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, 333static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
@@ -394,6 +350,12 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
394 return -1; 350 return -1;
395} 351}
396 352
353/* ECC functions
354 *
355 * These allow the s3c2410 and s3c2440 to use the controller's ECC
356 * generator block to ECC the data as it passes through]
357*/
358
397static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) 359static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
398{ 360{
399 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); 361 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -404,6 +366,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
404 writel(ctrl, info->regs + S3C2410_NFCONF); 366 writel(ctrl, info->regs + S3C2410_NFCONF);
405} 367}
406 368
369static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
370{
371 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
372 unsigned long ctrl;
373
374 ctrl = readl(info->regs + S3C2440_NFCONT);
375 writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
376}
377
407static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, 378static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
408 const u_char *dat, u_char *ecc_code) 379 const u_char *dat, u_char *ecc_code)
409{ 380{
@@ -420,7 +391,26 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
420} 391}
421 392
422 393
423/* over-ride the standard functions for a little more speed? */ 394static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd,
395 const u_char *dat, u_char *ecc_code)
396{
397 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
398 unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
399
400 ecc_code[0] = ecc;
401 ecc_code[1] = ecc >> 8;
402 ecc_code[2] = ecc >> 16;
403
404 pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
405 ecc_code[0], ecc_code[1], ecc_code[2]);
406
407 return 0;
408}
409
410
411/* over-ride the standard functions for a little more speed. We can
412 * use read/write block to move the data buffers to/from the controller
413*/
424 414
425static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) 415static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
426{ 416{
@@ -523,11 +513,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
523{ 513{
524 struct nand_chip *chip = &nmtd->chip; 514 struct nand_chip *chip = &nmtd->chip;
525 515
526 chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA; 516 chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
527 chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA; 517 chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
528 chip->hwcontrol = s3c2410_nand_hwcontrol; 518 chip->hwcontrol = s3c2410_nand_hwcontrol;
529 chip->dev_ready = s3c2410_nand_devready; 519 chip->dev_ready = s3c2410_nand_devready;
530 chip->cmdfunc = s3c2410_nand_command;
531 chip->write_buf = s3c2410_nand_write_buf; 520 chip->write_buf = s3c2410_nand_write_buf;
532 chip->read_buf = s3c2410_nand_read_buf; 521 chip->read_buf = s3c2410_nand_read_buf;
533 chip->select_chip = s3c2410_nand_select_chip; 522 chip->select_chip = s3c2410_nand_select_chip;
@@ -536,6 +525,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
536 chip->options = 0; 525 chip->options = 0;
537 chip->controller = &info->controller; 526 chip->controller = &info->controller;
538 527
528 if (info->is_s3c2440) {
529 chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;
530 chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
531 chip->hwcontrol = s3c2440_nand_hwcontrol;
532 }
533
539 nmtd->info = info; 534 nmtd->info = info;
540 nmtd->mtd.priv = chip; 535 nmtd->mtd.priv = chip;
541 nmtd->set = set; 536 nmtd->set = set;
@@ -546,6 +541,11 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
546 chip->calculate_ecc = s3c2410_nand_calculate_ecc; 541 chip->calculate_ecc = s3c2410_nand_calculate_ecc;
547 chip->eccmode = NAND_ECC_HW3_512; 542 chip->eccmode = NAND_ECC_HW3_512;
548 chip->autooob = &nand_hw_eccoob; 543 chip->autooob = &nand_hw_eccoob;
544
545 if (info->is_s3c2440) {
546 chip->enable_hwecc = s3c2440_nand_enable_hwecc;
547 chip->calculate_ecc = s3c2440_nand_calculate_ecc;
548 }
549 } else { 549 } else {
550 chip->eccmode = NAND_ECC_SOFT; 550 chip->eccmode = NAND_ECC_SOFT;
551 } 551 }
@@ -559,7 +559,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
559 * nand layer to look for devices 559 * nand layer to look for devices
560*/ 560*/
561 561
562static int s3c2410_nand_probe(struct device *dev) 562static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
563{ 563{
564 struct platform_device *pdev = to_platform_device(dev); 564 struct platform_device *pdev = to_platform_device(dev);
565 struct s3c2410_platform_nand *plat = to_nand_plat(dev); 565 struct s3c2410_platform_nand *plat = to_nand_plat(dev);
@@ -585,6 +585,7 @@ static int s3c2410_nand_probe(struct device *dev)
585 dev_set_drvdata(dev, info); 585 dev_set_drvdata(dev, info);
586 586
587 spin_lock_init(&info->controller.lock); 587 spin_lock_init(&info->controller.lock);
588 init_waitqueue_head(&info->controller.wq);
588 589
589 /* get the clock source and enable it */ 590 /* get the clock source and enable it */
590 591
@@ -600,7 +601,8 @@ static int s3c2410_nand_probe(struct device *dev)
600 601
601 /* allocate and map the resource */ 602 /* allocate and map the resource */
602 603
603 res = pdev->resource; /* assume that the flash has one resource */ 604 /* currently we assume we have the one resource */
605 res = pdev->resource;
604 size = res->end - res->start + 1; 606 size = res->end - res->start + 1;
605 607
606 info->area = request_mem_region(res->start, size, pdev->name); 608 info->area = request_mem_region(res->start, size, pdev->name);
@@ -611,9 +613,10 @@ static int s3c2410_nand_probe(struct device *dev)
611 goto exit_error; 613 goto exit_error;
612 } 614 }
613 615
614 info->device = dev; 616 info->device = dev;
615 info->platform = plat; 617 info->platform = plat;
616 info->regs = ioremap(res->start, size); 618 info->regs = ioremap(res->start, size);
619 info->is_s3c2440 = is_s3c2440;
617 620
618 if (info->regs == NULL) { 621 if (info->regs == NULL) {
619 printk(KERN_ERR PFX "cannot reserve register region\n"); 622 printk(KERN_ERR PFX "cannot reserve register region\n");
@@ -678,6 +681,18 @@ static int s3c2410_nand_probe(struct device *dev)
678 return err; 681 return err;
679} 682}
680 683
684/* driver device registration */
685
686static int s3c2410_nand_probe(struct device *dev)
687{
688 return s3c24xx_nand_probe(dev, 0);
689}
690
691static int s3c2440_nand_probe(struct device *dev)
692{
693 return s3c24xx_nand_probe(dev, 1);
694}
695
681static struct device_driver s3c2410_nand_driver = { 696static struct device_driver s3c2410_nand_driver = {
682 .name = "s3c2410-nand", 697 .name = "s3c2410-nand",
683 .bus = &platform_bus_type, 698 .bus = &platform_bus_type,
@@ -685,14 +700,24 @@ static struct device_driver s3c2410_nand_driver = {
685 .remove = s3c2410_nand_remove, 700 .remove = s3c2410_nand_remove,
686}; 701};
687 702
703static struct device_driver s3c2440_nand_driver = {
704 .name = "s3c2440-nand",
705 .bus = &platform_bus_type,
706 .probe = s3c2440_nand_probe,
707 .remove = s3c2410_nand_remove,
708};
709
688static int __init s3c2410_nand_init(void) 710static int __init s3c2410_nand_init(void)
689{ 711{
690 printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n"); 712 printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
713
714 driver_register(&s3c2440_nand_driver);
691 return driver_register(&s3c2410_nand_driver); 715 return driver_register(&s3c2410_nand_driver);
692} 716}
693 717
694static void __exit s3c2410_nand_exit(void) 718static void __exit s3c2410_nand_exit(void)
695{ 719{
720 driver_unregister(&s3c2440_nand_driver);
696 driver_unregister(&s3c2410_nand_driver); 721 driver_unregister(&s3c2410_nand_driver);
697} 722}
698 723
@@ -701,4 +726,4 @@ module_exit(s3c2410_nand_exit);
701 726
702MODULE_LICENSE("GPL"); 727MODULE_LICENSE("GPL");
703MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 728MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
704MODULE_DESCRIPTION("S3C2410 MTD NAND driver"); 729MODULE_DESCRIPTION("S3C24XX MTD NAND driver");