diff options
author | Kyungmin Park <kyungmin.park@samsung.com> | 2006-11-15 21:23:48 -0500 |
---|---|---|
committer | Kyungmin Park <kyungmin.park@samsung.com> | 2006-11-15 21:23:48 -0500 |
commit | 2c22120fbd017d78ad2b6825ba573db3ef539bca (patch) | |
tree | 017c70446ff2a985e138a1352f0bad34f503bddd /drivers/mtd | |
parent | ff0dab64b4e9ce3a073365342297e76ddaae9697 (diff) |
MTD: OneNAND: interrupt based wait support
We can use the two methods to wait.
1. polling: read interrupt status register
2. interrupt: use kernel ineterrupt mechanism
To use interrupt method, you first connect onenand interrupt pin to your
platform and configure interrupt properly
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/onenand/generic.c | 1 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 109 |
2 files changed, 108 insertions, 2 deletions
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index af06a80f44de..cdf80c68160f 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c | |||
@@ -63,6 +63,7 @@ static int __devinit generic_onenand_probe(struct device *dev) | |||
63 | } | 63 | } |
64 | 64 | ||
65 | info->onenand.mmcontrol = pdata->mmcontrol; | 65 | info->onenand.mmcontrol = pdata->mmcontrol; |
66 | info->onenand.irq = platform_get_irq(pdev, 0); | ||
66 | 67 | ||
67 | info->mtd.name = pdev->dev.bus_id; | 68 | info->mtd.name = pdev->dev.bus_id; |
68 | info->mtd.priv = &info->onenand; | 69 | info->mtd.priv = &info->onenand; |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 8ed68b28afe3..aea13a388868 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/interrupt.h> | ||
16 | #include <linux/jiffies.h> | 17 | #include <linux/jiffies.h> |
17 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
18 | #include <linux/mtd/onenand.h> | 19 | #include <linux/mtd/onenand.h> |
@@ -339,6 +340,111 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
339 | return 0; | 340 | return 0; |
340 | } | 341 | } |
341 | 342 | ||
343 | /* | ||
344 | * onenand_interrupt - [DEFAULT] onenand interrupt handler | ||
345 | * @param irq onenand interrupt number | ||
346 | * @param dev_id interrupt data | ||
347 | * | ||
348 | * complete the work | ||
349 | */ | ||
350 | static irqreturn_t onenand_interrupt(int irq, void *data) | ||
351 | { | ||
352 | struct onenand_chip *this = (struct onenand_chip *) data; | ||
353 | |||
354 | /* To handle shared interrupt */ | ||
355 | if (!this->complete.done) | ||
356 | complete(&this->complete); | ||
357 | |||
358 | return IRQ_HANDLED; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * onenand_interrupt_wait - [DEFAULT] wait until the command is done | ||
363 | * @param mtd MTD device structure | ||
364 | * @param state state to select the max. timeout value | ||
365 | * | ||
366 | * Wait for command done. | ||
367 | */ | ||
368 | static int onenand_interrupt_wait(struct mtd_info *mtd, int state) | ||
369 | { | ||
370 | struct onenand_chip *this = mtd->priv; | ||
371 | |||
372 | /* To prevent soft lockup */ | ||
373 | touch_softlockup_watchdog(); | ||
374 | |||
375 | wait_for_completion(&this->complete); | ||
376 | |||
377 | return onenand_wait(mtd, state); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait | ||
382 | * @param mtd MTD device structure | ||
383 | * @param state state to select the max. timeout value | ||
384 | * | ||
385 | * Try interrupt based wait (It is used one-time) | ||
386 | */ | ||
387 | static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state) | ||
388 | { | ||
389 | struct onenand_chip *this = mtd->priv; | ||
390 | unsigned long remain, timeout; | ||
391 | |||
392 | /* We use interrupt wait first */ | ||
393 | this->wait = onenand_interrupt_wait; | ||
394 | |||
395 | /* To prevent soft lockup */ | ||
396 | touch_softlockup_watchdog(); | ||
397 | |||
398 | timeout = msecs_to_jiffies(100); | ||
399 | remain = wait_for_completion_timeout(&this->complete, timeout); | ||
400 | if (!remain) { | ||
401 | printk(KERN_INFO "OneNAND: There's no interrupt. " | ||
402 | "We use the normal wait\n"); | ||
403 | |||
404 | /* Release the irq */ | ||
405 | free_irq(this->irq, this); | ||
406 | |||
407 | this->wait = onenand_wait; | ||
408 | } | ||
409 | |||
410 | return onenand_wait(mtd, state); | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * onenand_setup_wait - [OneNAND Interface] setup onenand wait method | ||
415 | * @param mtd MTD device structure | ||
416 | * | ||
417 | * There's two method to wait onenand work | ||
418 | * 1. polling - read interrupt status register | ||
419 | * 2. interrupt - use the kernel interrupt method | ||
420 | */ | ||
421 | static void onenand_setup_wait(struct mtd_info *mtd) | ||
422 | { | ||
423 | struct onenand_chip *this = mtd->priv; | ||
424 | int syscfg; | ||
425 | |||
426 | init_completion(&this->complete); | ||
427 | |||
428 | if (this->irq <= 0) { | ||
429 | this->wait = onenand_wait; | ||
430 | return; | ||
431 | } | ||
432 | |||
433 | if (request_irq(this->irq, &onenand_interrupt, | ||
434 | IRQF_SHARED, "onenand", this)) { | ||
435 | /* If we can't get irq, use the normal wait */ | ||
436 | this->wait = onenand_wait; | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | /* Enable interrupt */ | ||
441 | syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); | ||
442 | syscfg |= ONENAND_SYS_CFG1_IOBE; | ||
443 | this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); | ||
444 | |||
445 | this->wait = onenand_try_interrupt_wait; | ||
446 | } | ||
447 | |||
342 | /** | 448 | /** |
343 | * onenand_bufferram_offset - [DEFAULT] BufferRAM offset | 449 | * onenand_bufferram_offset - [DEFAULT] BufferRAM offset |
344 | * @param mtd MTD data structure | 450 | * @param mtd MTD data structure |
@@ -1129,7 +1235,6 @@ static void onenand_sync(struct mtd_info *mtd) | |||
1129 | onenand_release_device(mtd); | 1235 | onenand_release_device(mtd); |
1130 | } | 1236 | } |
1131 | 1237 | ||
1132 | |||
1133 | /** | 1238 | /** |
1134 | * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad | 1239 | * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad |
1135 | * @param mtd MTD device structure | 1240 | * @param mtd MTD device structure |
@@ -1846,7 +1951,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
1846 | if (!this->command) | 1951 | if (!this->command) |
1847 | this->command = onenand_command; | 1952 | this->command = onenand_command; |
1848 | if (!this->wait) | 1953 | if (!this->wait) |
1849 | this->wait = onenand_wait; | 1954 | onenand_setup_wait(mtd); |
1850 | 1955 | ||
1851 | if (!this->read_bufferram) | 1956 | if (!this->read_bufferram) |
1852 | this->read_bufferram = onenand_read_bufferram; | 1957 | this->read_bufferram = onenand_read_bufferram; |