aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2006-11-15 21:23:48 -0500
committerKyungmin Park <kyungmin.park@samsung.com>2006-11-15 21:23:48 -0500
commit2c22120fbd017d78ad2b6825ba573db3ef539bca (patch)
tree017c70446ff2a985e138a1352f0bad34f503bddd
parentff0dab64b4e9ce3a073365342297e76ddaae9697 (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.c1
-rw-r--r--drivers/mtd/onenand/onenand_base.c109
-rw-r--r--include/linux/mtd/onenand.h4
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 */
350static 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 */
368static 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 */
387static 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 */
421static 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;