diff options
Diffstat (limited to 'drivers/mtd/nand/at91_nand.c')
-rw-r--r-- | drivers/mtd/nand/at91_nand.c | 370 |
1 files changed, 364 insertions, 6 deletions
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c index c9fb2acf4056..414ceaecdb3a 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/at91_nand.c | |||
@@ -9,6 +9,15 @@ | |||
9 | * Derived from drivers/mtd/spia.c | 9 | * Derived from drivers/mtd/spia.c |
10 | * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) | 10 | * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) |
11 | * | 11 | * |
12 | * | ||
13 | * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 | ||
14 | * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 | ||
15 | * | ||
16 | * Derived from Das U-Boot source code | ||
17 | * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) | ||
18 | * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas | ||
19 | * | ||
20 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | 21 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 22 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. | 23 | * published by the Free Software Foundation. |
@@ -29,11 +38,59 @@ | |||
29 | #include <asm/arch/board.h> | 38 | #include <asm/arch/board.h> |
30 | #include <asm/arch/gpio.h> | 39 | #include <asm/arch/gpio.h> |
31 | 40 | ||
41 | #ifdef CONFIG_MTD_NAND_AT91_ECC_HW | ||
42 | #define hard_ecc 1 | ||
43 | #else | ||
44 | #define hard_ecc 0 | ||
45 | #endif | ||
46 | |||
47 | #ifdef CONFIG_MTD_NAND_AT91_ECC_NONE | ||
48 | #define no_ecc 1 | ||
49 | #else | ||
50 | #define no_ecc 0 | ||
51 | #endif | ||
52 | |||
53 | /* Register access macros */ | ||
54 | #define ecc_readl(add, reg) \ | ||
55 | __raw_readl(add + AT91_ECC_##reg) | ||
56 | #define ecc_writel(add, reg, value) \ | ||
57 | __raw_writel((value), add + AT91_ECC_##reg) | ||
58 | |||
59 | #include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */ | ||
60 | |||
61 | /* oob layout for large page size | ||
62 | * bad block info is on bytes 0 and 1 | ||
63 | * the bytes have to be consecutives to avoid | ||
64 | * several NAND_CMD_RNDOUT during read | ||
65 | */ | ||
66 | static struct nand_ecclayout at91_oobinfo_large = { | ||
67 | .eccbytes = 4, | ||
68 | .eccpos = {60, 61, 62, 63}, | ||
69 | .oobfree = { | ||
70 | {2, 58} | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | /* oob layout for small page size | ||
75 | * bad block info is on bytes 4 and 5 | ||
76 | * the bytes have to be consecutives to avoid | ||
77 | * several NAND_CMD_RNDOUT during read | ||
78 | */ | ||
79 | static struct nand_ecclayout at91_oobinfo_small = { | ||
80 | .eccbytes = 4, | ||
81 | .eccpos = {0, 1, 2, 3}, | ||
82 | .oobfree = { | ||
83 | {6, 10} | ||
84 | }, | ||
85 | }; | ||
86 | |||
32 | struct at91_nand_host { | 87 | struct at91_nand_host { |
33 | struct nand_chip nand_chip; | 88 | struct nand_chip nand_chip; |
34 | struct mtd_info mtd; | 89 | struct mtd_info mtd; |
35 | void __iomem *io_base; | 90 | void __iomem *io_base; |
36 | struct at91_nand_data *board; | 91 | struct at91_nand_data *board; |
92 | struct device *dev; | ||
93 | void __iomem *ecc; | ||
37 | }; | 94 | }; |
38 | 95 | ||
39 | /* | 96 | /* |
@@ -44,6 +101,12 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
44 | struct nand_chip *nand_chip = mtd->priv; | 101 | struct nand_chip *nand_chip = mtd->priv; |
45 | struct at91_nand_host *host = nand_chip->priv; | 102 | struct at91_nand_host *host = nand_chip->priv; |
46 | 103 | ||
104 | if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) { | ||
105 | if (ctrl & NAND_NCE) | ||
106 | at91_set_gpio_value(host->board->enable_pin, 0); | ||
107 | else | ||
108 | at91_set_gpio_value(host->board->enable_pin, 1); | ||
109 | } | ||
47 | if (cmd == NAND_CMD_NONE) | 110 | if (cmd == NAND_CMD_NONE) |
48 | return; | 111 | return; |
49 | 112 | ||
@@ -82,8 +145,217 @@ static void at91_nand_disable(struct at91_nand_host *host) | |||
82 | at91_set_gpio_value(host->board->enable_pin, 1); | 145 | at91_set_gpio_value(host->board->enable_pin, 1); |
83 | } | 146 | } |
84 | 147 | ||
148 | /* | ||
149 | * write oob for small pages | ||
150 | */ | ||
151 | static int at91_nand_write_oob_512(struct mtd_info *mtd, | ||
152 | struct nand_chip *chip, int page) | ||
153 | { | ||
154 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
155 | int eccsize = chip->ecc.size, length = mtd->oobsize; | ||
156 | int len, pos, status = 0; | ||
157 | const uint8_t *bufpoi = chip->oob_poi; | ||
158 | |||
159 | pos = eccsize + chunk; | ||
160 | |||
161 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | ||
162 | len = min_t(int, length, chunk); | ||
163 | chip->write_buf(mtd, bufpoi, len); | ||
164 | bufpoi += len; | ||
165 | length -= len; | ||
166 | if (length > 0) | ||
167 | chip->write_buf(mtd, bufpoi, length); | ||
168 | |||
169 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
170 | status = chip->waitfunc(mtd, chip); | ||
171 | |||
172 | return status & NAND_STATUS_FAIL ? -EIO : 0; | ||
173 | |||
174 | } | ||
175 | |||
176 | /* | ||
177 | * read oob for small pages | ||
178 | */ | ||
179 | static int at91_nand_read_oob_512(struct mtd_info *mtd, | ||
180 | struct nand_chip *chip, int page, int sndcmd) | ||
181 | { | ||
182 | if (sndcmd) { | ||
183 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
184 | sndcmd = 0; | ||
185 | } | ||
186 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
187 | return sndcmd; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Calculate HW ECC | ||
192 | * | ||
193 | * function called after a write | ||
194 | * | ||
195 | * mtd: MTD block structure | ||
196 | * dat: raw data (unused) | ||
197 | * ecc_code: buffer for ECC | ||
198 | */ | ||
199 | static int at91_nand_calculate(struct mtd_info *mtd, | ||
200 | const u_char *dat, unsigned char *ecc_code) | ||
201 | { | ||
202 | struct nand_chip *nand_chip = mtd->priv; | ||
203 | struct at91_nand_host *host = nand_chip->priv; | ||
204 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; | ||
205 | unsigned int ecc_value; | ||
206 | |||
207 | /* get the first 2 ECC bytes */ | ||
208 | ecc_value = ecc_readl(host->ecc, PR); | ||
209 | |||
210 | ecc_code[eccpos[0]] = ecc_value & 0xFF; | ||
211 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | ||
212 | |||
213 | /* get the last 2 ECC bytes */ | ||
214 | ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; | ||
215 | |||
216 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | ||
217 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * HW ECC read page function | ||
224 | * | ||
225 | * mtd: mtd info structure | ||
226 | * chip: nand chip info structure | ||
227 | * buf: buffer to store read data | ||
228 | */ | ||
229 | static int at91_nand_read_page(struct mtd_info *mtd, | ||
230 | struct nand_chip *chip, uint8_t *buf) | ||
231 | { | ||
232 | int eccsize = chip->ecc.size; | ||
233 | int eccbytes = chip->ecc.bytes; | ||
234 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
235 | uint8_t *p = buf; | ||
236 | uint8_t *oob = chip->oob_poi; | ||
237 | uint8_t *ecc_pos; | ||
238 | int stat; | ||
239 | |||
240 | /* read the page */ | ||
241 | chip->read_buf(mtd, p, eccsize); | ||
242 | |||
243 | /* move to ECC position if needed */ | ||
244 | if (eccpos[0] != 0) { | ||
245 | /* This only works on large pages | ||
246 | * because the ECC controller waits for | ||
247 | * NAND_CMD_RNDOUTSTART after the | ||
248 | * NAND_CMD_RNDOUT. | ||
249 | * anyway, for small pages, the eccpos[0] == 0 | ||
250 | */ | ||
251 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | ||
252 | mtd->writesize + eccpos[0], -1); | ||
253 | } | ||
254 | |||
255 | /* the ECC controller needs to read the ECC just after the data */ | ||
256 | ecc_pos = oob + eccpos[0]; | ||
257 | chip->read_buf(mtd, ecc_pos, eccbytes); | ||
258 | |||
259 | /* check if there's an error */ | ||
260 | stat = chip->ecc.correct(mtd, p, oob, NULL); | ||
261 | |||
262 | if (stat < 0) | ||
263 | mtd->ecc_stats.failed++; | ||
264 | else | ||
265 | mtd->ecc_stats.corrected += stat; | ||
266 | |||
267 | /* get back to oob start (end of page) */ | ||
268 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | ||
269 | |||
270 | /* read the oob */ | ||
271 | chip->read_buf(mtd, oob, mtd->oobsize); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * HW ECC Correction | ||
278 | * | ||
279 | * function called after a read | ||
280 | * | ||
281 | * mtd: MTD block structure | ||
282 | * dat: raw data read from the chip | ||
283 | * read_ecc: ECC from the chip (unused) | ||
284 | * isnull: unused | ||
285 | * | ||
286 | * Detect and correct a 1 bit error for a page | ||
287 | */ | ||
288 | static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | ||
289 | u_char *read_ecc, u_char *isnull) | ||
290 | { | ||
291 | struct nand_chip *nand_chip = mtd->priv; | ||
292 | struct at91_nand_host *host = nand_chip->priv; | ||
293 | unsigned int ecc_status; | ||
294 | unsigned int ecc_word, ecc_bit; | ||
295 | |||
296 | /* get the status from the Status Register */ | ||
297 | ecc_status = ecc_readl(host->ecc, SR); | ||
298 | |||
299 | /* if there's no error */ | ||
300 | if (likely(!(ecc_status & AT91_ECC_RECERR))) | ||
301 | return 0; | ||
302 | |||
303 | /* get error bit offset (4 bits) */ | ||
304 | ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; | ||
305 | /* get word address (12 bits) */ | ||
306 | ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; | ||
307 | ecc_word >>= 4; | ||
308 | |||
309 | /* if there are multiple errors */ | ||
310 | if (ecc_status & AT91_ECC_MULERR) { | ||
311 | /* check if it is a freshly erased block | ||
312 | * (filled with 0xff) */ | ||
313 | if ((ecc_bit == AT91_ECC_BITADDR) | ||
314 | && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { | ||
315 | /* the block has just been erased, return OK */ | ||
316 | return 0; | ||
317 | } | ||
318 | /* it doesn't seems to be a freshly | ||
319 | * erased block. | ||
320 | * We can't correct so many errors */ | ||
321 | dev_dbg(host->dev, "at91_nand : multiple errors detected." | ||
322 | " Unable to correct.\n"); | ||
323 | return -EIO; | ||
324 | } | ||
325 | |||
326 | /* if there's a single bit error : we can correct it */ | ||
327 | if (ecc_status & AT91_ECC_ECCERR) { | ||
328 | /* there's nothing much to do here. | ||
329 | * the bit error is on the ECC itself. | ||
330 | */ | ||
331 | dev_dbg(host->dev, "at91_nand : one bit error on ECC code." | ||
332 | " Nothing to correct\n"); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | dev_dbg(host->dev, "at91_nand : one bit error on data." | ||
337 | " (word offset in the page :" | ||
338 | " 0x%x bit offset : 0x%x)\n", | ||
339 | ecc_word, ecc_bit); | ||
340 | /* correct the error */ | ||
341 | if (nand_chip->options & NAND_BUSWIDTH_16) { | ||
342 | /* 16 bits words */ | ||
343 | ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); | ||
344 | } else { | ||
345 | /* 8 bits words */ | ||
346 | dat[ecc_word] ^= (1 << ecc_bit); | ||
347 | } | ||
348 | dev_dbg(host->dev, "at91_nand : error corrected\n"); | ||
349 | return 1; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Enable HW ECC : unsused | ||
354 | */ | ||
355 | static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } | ||
356 | |||
85 | #ifdef CONFIG_MTD_PARTITIONS | 357 | #ifdef CONFIG_MTD_PARTITIONS |
86 | const char *part_probes[] = { "cmdlinepart", NULL }; | 358 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
87 | #endif | 359 | #endif |
88 | 360 | ||
89 | /* | 361 | /* |
@@ -94,6 +366,8 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
94 | struct at91_nand_host *host; | 366 | struct at91_nand_host *host; |
95 | struct mtd_info *mtd; | 367 | struct mtd_info *mtd; |
96 | struct nand_chip *nand_chip; | 368 | struct nand_chip *nand_chip; |
369 | struct resource *regs; | ||
370 | struct resource *mem; | ||
97 | int res; | 371 | int res; |
98 | 372 | ||
99 | #ifdef CONFIG_MTD_PARTITIONS | 373 | #ifdef CONFIG_MTD_PARTITIONS |
@@ -108,8 +382,13 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
108 | return -ENOMEM; | 382 | return -ENOMEM; |
109 | } | 383 | } |
110 | 384 | ||
111 | host->io_base = ioremap(pdev->resource[0].start, | 385 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
112 | pdev->resource[0].end - pdev->resource[0].start + 1); | 386 | if (!mem) { |
387 | printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); | ||
388 | return -ENXIO; | ||
389 | } | ||
390 | |||
391 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); | ||
113 | if (host->io_base == NULL) { | 392 | if (host->io_base == NULL) { |
114 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 393 | printk(KERN_ERR "at91_nand: ioremap failed\n"); |
115 | kfree(host); | 394 | kfree(host); |
@@ -119,6 +398,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
119 | mtd = &host->mtd; | 398 | mtd = &host->mtd; |
120 | nand_chip = &host->nand_chip; | 399 | nand_chip = &host->nand_chip; |
121 | host->board = pdev->dev.platform_data; | 400 | host->board = pdev->dev.platform_data; |
401 | host->dev = &pdev->dev; | ||
122 | 402 | ||
123 | nand_chip->priv = host; /* link the private data structures */ | 403 | nand_chip->priv = host; /* link the private data structures */ |
124 | mtd->priv = nand_chip; | 404 | mtd->priv = nand_chip; |
@@ -132,7 +412,32 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
132 | if (host->board->rdy_pin) | 412 | if (host->board->rdy_pin) |
133 | nand_chip->dev_ready = at91_nand_device_ready; | 413 | nand_chip->dev_ready = at91_nand_device_ready; |
134 | 414 | ||
415 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
416 | if (!regs && hard_ecc) { | ||
417 | printk(KERN_ERR "at91_nand: can't get I/O resource " | ||
418 | "regs\nFalling back on software ECC\n"); | ||
419 | } | ||
420 | |||
135 | nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ | 421 | nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ |
422 | if (no_ecc) | ||
423 | nand_chip->ecc.mode = NAND_ECC_NONE; | ||
424 | if (hard_ecc && regs) { | ||
425 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); | ||
426 | if (host->ecc == NULL) { | ||
427 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | ||
428 | res = -EIO; | ||
429 | goto err_ecc_ioremap; | ||
430 | } | ||
431 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | ||
432 | nand_chip->ecc.calculate = at91_nand_calculate; | ||
433 | nand_chip->ecc.correct = at91_nand_correct; | ||
434 | nand_chip->ecc.hwctl = at91_nand_hwctl; | ||
435 | nand_chip->ecc.read_page = at91_nand_read_page; | ||
436 | nand_chip->ecc.bytes = 4; | ||
437 | nand_chip->ecc.prepad = 0; | ||
438 | nand_chip->ecc.postpad = 0; | ||
439 | } | ||
440 | |||
136 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 441 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
137 | 442 | ||
138 | if (host->board->bus_width_16) /* 16-bit bus width */ | 443 | if (host->board->bus_width_16) /* 16-bit bus width */ |
@@ -149,8 +454,53 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
149 | } | 454 | } |
150 | } | 455 | } |
151 | 456 | ||
152 | /* Scan to find existance of the device */ | 457 | /* first scan to find the device and get the page size */ |
153 | if (nand_scan(mtd, 1)) { | 458 | if (nand_scan_ident(mtd, 1)) { |
459 | res = -ENXIO; | ||
460 | goto out; | ||
461 | } | ||
462 | |||
463 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | ||
464 | /* ECC is calculated for the whole page (1 step) */ | ||
465 | nand_chip->ecc.size = mtd->writesize; | ||
466 | |||
467 | /* set ECC page size and oob layout */ | ||
468 | switch (mtd->writesize) { | ||
469 | case 512: | ||
470 | nand_chip->ecc.layout = &at91_oobinfo_small; | ||
471 | nand_chip->ecc.read_oob = at91_nand_read_oob_512; | ||
472 | nand_chip->ecc.write_oob = at91_nand_write_oob_512; | ||
473 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); | ||
474 | break; | ||
475 | case 1024: | ||
476 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
477 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); | ||
478 | break; | ||
479 | case 2048: | ||
480 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
481 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); | ||
482 | break; | ||
483 | case 4096: | ||
484 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
485 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); | ||
486 | break; | ||
487 | default: | ||
488 | /* page size not handled by HW ECC */ | ||
489 | /* switching back to soft ECC */ | ||
490 | nand_chip->ecc.mode = NAND_ECC_SOFT; | ||
491 | nand_chip->ecc.calculate = NULL; | ||
492 | nand_chip->ecc.correct = NULL; | ||
493 | nand_chip->ecc.hwctl = NULL; | ||
494 | nand_chip->ecc.read_page = NULL; | ||
495 | nand_chip->ecc.postpad = 0; | ||
496 | nand_chip->ecc.prepad = 0; | ||
497 | nand_chip->ecc.bytes = 0; | ||
498 | break; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /* second phase scan */ | ||
503 | if (nand_scan_tail(mtd)) { | ||
154 | res = -ENXIO; | 504 | res = -ENXIO; |
155 | goto out; | 505 | goto out; |
156 | } | 506 | } |
@@ -179,9 +529,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
179 | if (!res) | 529 | if (!res) |
180 | return res; | 530 | return res; |
181 | 531 | ||
532 | #ifdef CONFIG_MTD_PARTITIONS | ||
182 | release: | 533 | release: |
534 | #endif | ||
183 | nand_release(mtd); | 535 | nand_release(mtd); |
536 | |||
184 | out: | 537 | out: |
538 | iounmap(host->ecc); | ||
539 | |||
540 | err_ecc_ioremap: | ||
185 | at91_nand_disable(host); | 541 | at91_nand_disable(host); |
186 | platform_set_drvdata(pdev, NULL); | 542 | platform_set_drvdata(pdev, NULL); |
187 | iounmap(host->io_base); | 543 | iounmap(host->io_base); |
@@ -202,6 +558,7 @@ static int __devexit at91_nand_remove(struct platform_device *pdev) | |||
202 | at91_nand_disable(host); | 558 | at91_nand_disable(host); |
203 | 559 | ||
204 | iounmap(host->io_base); | 560 | iounmap(host->io_base); |
561 | iounmap(host->ecc); | ||
205 | kfree(host); | 562 | kfree(host); |
206 | 563 | ||
207 | return 0; | 564 | return 0; |
@@ -233,4 +590,5 @@ module_exit(at91_nand_exit); | |||
233 | 590 | ||
234 | MODULE_LICENSE("GPL"); | 591 | MODULE_LICENSE("GPL"); |
235 | MODULE_AUTHOR("Rick Bronson"); | 592 | MODULE_AUTHOR("Rick Bronson"); |
236 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); | 593 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); |
594 | MODULE_ALIAS("platform:at91_nand"); | ||