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 | |
| 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>
| -rw-r--r-- | drivers/mtd/onenand/generic.c | 1 | ||||
| -rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 109 | ||||
| -rw-r--r-- | include/linux/mtd/onenand.h | 4 |
3 files changed, 112 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; |
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 6f045b586e76..df963f1f6f87 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #define __LINUX_MTD_ONENAND_H | 13 | #define __LINUX_MTD_ONENAND_H |
| 14 | 14 | ||
| 15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| 16 | #include <linux/completion.h> | ||
| 16 | #include <linux/mtd/onenand_regs.h> | 17 | #include <linux/mtd/onenand_regs.h> |
| 17 | #include <linux/mtd/bbm.h> | 18 | #include <linux/mtd/bbm.h> |
| 18 | 19 | ||
| @@ -120,6 +121,9 @@ struct onenand_chip { | |||
| 120 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); | 121 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); |
| 121 | int (*scan_bbt)(struct mtd_info *mtd); | 122 | int (*scan_bbt)(struct mtd_info *mtd); |
| 122 | 123 | ||
| 124 | struct completion complete; | ||
| 125 | int irq; | ||
| 126 | |||
| 123 | spinlock_t chip_lock; | 127 | spinlock_t chip_lock; |
| 124 | wait_queue_head_t wq; | 128 | wait_queue_head_t wq; |
| 125 | onenand_state_t state; | 129 | onenand_state_t state; |
