[PATCH] [MTD] S3C24XX NAND: Use interrupt based RnB

Harald Welte laforge at openmoko.org
Tue Oct 21 22:49:07 CEST 2008


With this patch, you can define USE_IRQ and switch the driver
from busy-waiting for RnB to an interrupt + completion based
method.

Signed-off-by: Harald Welte <laforge at openmoko.org>
---
 drivers/mtd/nand/s3c2410.c |   73 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 72 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index eeb48ed..cb4c00e 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -52,6 +52,8 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -119,6 +121,7 @@ struct s3c2410_nand_info {
 	void __iomem			*sel_reg;
 	int				sel_bit;
 	int				mtd_count;
+	struct completion		rnb_completion;
 
 	enum s3c_cpu_type		cpu_type;
 };
@@ -225,9 +228,14 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
 		cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
 		cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
 
+#ifdef USE_IRQ
+		/* enable the controller, enable RnB IRQ and de-assert nFCE */
+		writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_RNBINT_EN,
+		       info->regs + S3C2440_NFCONT);
+#else
 		/* enable the controller and de-assert nFCE */
-
 		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
+#endif
 	}
 
 	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
@@ -505,12 +513,56 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int
 	writesl(info->regs + S3C2440_NFDATA, buf, len / 4);
 }
 
+#ifdef USE_IRQ
+static irqreturn_t s3c2440_nand_irq(int irq, void *dev_id)
+{
+	struct s3c2410_nand_info *info = dev_id;
+	u_int8_t stat = readb(info->regs + S3C2440_NFSTAT);
+	
+	if (stat & S3C2440_NFSTAT_RnB_CHANGE) {
+		//dev_err(info->device, "RnB IRQ\n");
+		/* clear the RnB change status */
+		writeb(stat | S3C2440_NFSTAT_RnB_CHANGE,
+		       info->regs + S3C2440_NFSTAT);
+		/* FIXME: should we check RnB status ? */
+		complete(&info->rnb_completion);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void s3c2440_nand_wait_ready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	/* FIXME: do we have a race condition? How to solve it? */
+	if (s3c2440_nand_devready(mtd)) {
+		dev_err(info->device, "immediately ready\n");
+		return;
+	}
+
+	//dev_err(info->device, "waiting for completion\n");
+	wait_for_completion(&info->rnb_completion);
+	//dev_err(info->device, "completed\n");
+}
+#endif /* USE_IRQ */
+
 /* device management functions */
 
 static int s3c2410_nand_remove(struct platform_device *pdev)
 {
 	struct s3c2410_nand_info *info = to_nand_info(pdev);
 
+	switch (info->cpu_type) {
+	case TYPE_S3C2440:
+#ifdef USE_IRQ
+		free_irq(IRQ_NFCON, s3c2440_nand_irq);
+#endif /* USE_IRQ */
+		break;
+	default:
+		break;
+	}
+
 	platform_set_drvdata(pdev, NULL);
 
 	if (info == NULL)
@@ -633,6 +685,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 		info->sel_bit	= S3C2440_NFCONT_nFCE;
 		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
 		chip->dev_ready = s3c2440_nand_devready;
+#ifdef USE_IRQ
+		chip->wait_ready= s3c2440_nand_wait_ready;
+#endif
 		chip->read_buf  = s3c2440_nand_read_buf;
 		chip->write_buf	= s3c2440_nand_write_buf;
 		break;
@@ -777,6 +832,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
 	info->platform   = plat;
 	info->regs       = ioremap(res->start, size);
 	info->cpu_type   = cpu_type;
+	init_completion(&info->rnb_completion);
 
 	if (info->regs == NULL) {
 		dev_err(&pdev->dev, "cannot reserve register region\n");
@@ -786,6 +842,21 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
 
 	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
+	switch (cpu_type) {
+	case TYPE_S3C2440:
+#ifdef USE_IRQ
+		if (request_irq(IRQ_NFCON, s3c2440_nand_irq, 0,
+				"s3c2440_nand", info)) {
+			dev_err(&pdev->dev, "cannot request interrupt");
+			err = -EIO;
+			goto exit_error;
+		}
+#endif
+		break;
+	default:
+		break;
+	}
+
 	/* initialise the hardware */
 
 	err = s3c2410_nand_inithw(info, pdev);
-- 
1.5.6.5


--8t9RHnE3ZwKMSgU+--



More information about the openmoko-kernel mailing list