Received: from milmhbs1.lsil.com (147.145.21.209) by coscas01.lsi.com
 (172.21.36.60) with Microsoft SMTP Server id 8.1.393.1; Mon, 12 Oct 2009
 20:49:31 -0600
Received: from mail1.lsil.com (mail1.lsil.com [147.145.40.21])	by
 milmhbs1.lsil.com (8.12.11/8.12.11) with ESMTP id n9D2nVkW025392	for
 <andy.sharp@lsi.com>; Mon, 12 Oct 2009 19:49:31 -0700
Received: from psmtp.com (na3sys009amx243.postini.com [74.125.149.127])	by
 mail1.lsil.com (8.12.11/8.12.11) with SMTP id n9D2nUCK013262	for
 <andy.sharp@lsi.com>; Mon, 12 Oct 2009 19:49:30 -0700 (PDT)
Received: from source ([78.24.191.182]) by na3sys009amx243.postini.com
 ([74.125.148.14]) with SMTP;	Tue, 13 Oct 2009 02:49:30 GMT
Received: from localhost.localdomain ([127.0.0.1]:48098 "EHLO
	eddie.linux-mips.org" rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org	with
 ESMTP id S1491925AbZJMCt2 (ORCPT <rfc822;andy.sharp@lsi.com>);	Tue, 13 Oct
 2009 04:49:28 +0200
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 13 Oct 2009 04:49:11
 +0200 (CEST)
Received: from TYO201.gate.nec.co.jp ([202.32.8.193]:43589 "EHLO
	tyo201.gate.nec.co.jp" rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org	with
 ESMTP id S1491849AbZJMCs6 (ORCPT	<rfc822;linux-mips@linux-mips.org>); Tue, 13
 Oct 2009 04:48:58 +0200
Received: from relay31.aps.necel.com ([10.29.19.54])	by tyo201.gate.nec.co.jp
 (8.13.8/8.13.4) with ESMTP id n9D2mkJo007096;	Tue, 13 Oct 2009 11:48:46 +0900
 (JST)
Received: from realmbox31.aps.necel.com ([10.29.19.28] [10.29.19.28]) by
 relay31.aps.necel.com with ESMTP; Tue, 13 Oct 2009 11:48:46 +0900
Received: from [10.114.180.134] ([10.114.180.134] [10.114.180.134]) by
 mbox02.aps.necel.com with ESMTP; Tue, 13 Oct 2009 11:48:46 +0900
From: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
To: "baruch@tkos.co.il" <baruch@tkos.co.il>, "linux-i2c@vger.kernel.org"
	<linux-i2c@vger.kernel.org>
CC: "ben-linux@fluff.org" <ben-linux@fluff.org>, "linux-mips@linux-mips.org"
	<linux-mips@linux-mips.org>, "linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>
Sender: "linux-mips-bounce@linux-mips.org" <linux-mips-bounce@linux-mips.org>
Date: Mon, 12 Oct 2009 20:48:54 -0600
Subject: [PATCH 02/16] i2c-designware: Don't use the IC_CLR_INTR register to
 clear interrupts
Thread-Topic: [PATCH 02/16] i2c-designware: Don't use the IC_CLR_INTR
 register to clear interrupts
Thread-Index: AcpLr8qBt+xvd0z3RHy34j3mot9gCg==
Message-ID: <4AD3EA96.9060704@necel.com>
References: <4AD3E974.8080200@necel.com>
In-Reply-To: <4AD3E974.8080200@necel.com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Anonymous
X-MS-Exchange-Organization-AuthSource: coscas01.lsi.com
X-MS-Has-Attach:
X-Auto-Response-Suppress: All
X-MS-TNEF-Correlator:
x-scanned-by: MIMEDefang 2.39
errors-to: linux-mips-bounce@linux-mips.org
x-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390
 R:95.9108 P:95.9108 M:97.0282 C:98.6951 )
x-pstn-settings: 3 (1.0000:1.0000) s cv gt3 gt2 gt1 r p m c 
x-pstn-addresses: from <shinya.kuribayashi@necel.com> [db-null] 
x-pstn-neptune: 0/0/0.00/0
user-agent: Thunderbird 2.0.0.23 (Windows/20090812)
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0

We're strongly discouraged from using the IC_CLR_INTR register because
it clears all software-clearable interrupts asserted at the moment.

stat =3D read(IC_INTR_STAT);
  :
  :  <=3D=3D=3D Interrupts asserted during this period will be lost
  :
read(IC_CLR_INTR);

Use the separately-prepared IC_CLR_* registers, instead.

At the same time, this patch adds all remaining interrupt definitions
available in the DesignWare I2C hardware.

Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
---
 drivers/i2c/busses/i2c-designware.c |   77 +++++++++++++++++++++++++++++++=
++--
 1 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-d=
esignware.c
index a4f928e..efddae1 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -49,7 +49,18 @@
 #define DW_IC_FS_SCL_LCNT	0x20
 #define DW_IC_INTR_STAT		0x2c
 #define DW_IC_INTR_MASK		0x30
+#define DW_IC_RAW_INTR_STAT	0x34
 #define DW_IC_CLR_INTR		0x40
+#define DW_IC_CLR_RX_UNDER	0x44
+#define DW_IC_CLR_RX_OVER	0x48
+#define DW_IC_CLR_TX_OVER	0x4c
+#define DW_IC_CLR_RD_REQ	0x50
+#define DW_IC_CLR_TX_ABRT	0x54
+#define DW_IC_CLR_RX_DONE	0x58
+#define DW_IC_CLR_ACTIVITY	0x5c
+#define DW_IC_CLR_STOP_DET	0x60
+#define DW_IC_CLR_START_DET	0x64
+#define DW_IC_CLR_GEN_CALL	0x68
 #define DW_IC_ENABLE		0x6c
 #define DW_IC_STATUS		0x70
 #define DW_IC_TXFLR		0x74
@@ -64,9 +75,18 @@
 #define DW_IC_CON_RESTART_EN		0x20
 #define DW_IC_CON_SLAVE_DISABLE		0x40
=20
-#define DW_IC_INTR_TX_EMPTY	0x10
-#define DW_IC_INTR_TX_ABRT	0x40
+#define DW_IC_INTR_RX_UNDER	0x001
+#define DW_IC_INTR_RX_OVER	0x002
+#define DW_IC_INTR_RX_FULL	0x004
+#define DW_IC_INTR_TX_OVER	0x008
+#define DW_IC_INTR_TX_EMPTY	0x010
+#define DW_IC_INTR_RD_REQ	0x020
+#define DW_IC_INTR_TX_ABRT	0x040
+#define DW_IC_INTR_RX_DONE	0x080
+#define DW_IC_INTR_ACTIVITY	0x100
 #define DW_IC_INTR_STOP_DET	0x200
+#define DW_IC_INTR_START_DET	0x400
+#define DW_IC_INTR_GEN_CALL	0x800
=20
 #define DW_IC_STATUS_ACTIVITY	0x1
=20
@@ -439,6 +459,55 @@ static void dw_i2c_pump_msg(unsigned long data)
 	writel(intr_mask, dev->base + DW_IC_INTR_MASK);
 }
=20
+static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+{
+	u32 stat;
+
+	/*
+	 * The IC_INTR_STAT register just indicates "enabled" interrupts.
+	 * Ths unmasked raw version of interrupt status bits are available
+	 * in the IC_RAW_INTR_STAT register.
+	 *
+	 * That is,
+	 *   stat =3D readl(IC_INTR_STAT);
+	 * equals to,
+	 *   stat =3D readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
+	 *
+	 * The raw version might be useful for debugging purposes.
+	 */
+	stat =3D readl(dev->base + DW_IC_INTR_STAT);
+
+	/*
+	 * Do not use the IC_CLR_INTR register to clear interrupts, or
+	 * you'll miss some interrupts, triggered during the period from
+	 * reading IC_INTR_STAT to reading IC_CLR_INTR.
+	 *
+	 * Use the separately-prepared IC_CLR_* registers instead.
+	 */
+	if (stat & DW_IC_INTR_RX_UNDER)
+		readl(dev->base + DW_IC_CLR_RX_UNDER);
+	if (stat & DW_IC_INTR_RX_OVER)
+		readl(dev->base + DW_IC_CLR_RX_OVER);
+	if (stat & DW_IC_INTR_TX_OVER)
+		readl(dev->base + DW_IC_CLR_TX_OVER);
+	if (stat & DW_IC_INTR_RD_REQ)
+		readl(dev->base + DW_IC_CLR_RD_REQ);
+	if (stat & DW_IC_INTR_TX_ABRT)
+		readl(dev->base + DW_IC_CLR_TX_ABRT);
+	if (stat & DW_IC_INTR_RX_DONE)
+		readl(dev->base + DW_IC_CLR_RX_DONE);
+	if (stat & DW_IC_INTR_ACTIVITY)
+		readl(dev->base + DW_IC_CLR_ACTIVITY);
+	if (stat & DW_IC_INTR_STOP_DET)
+		readl(dev->base + DW_IC_CLR_STOP_DET);
+	if (stat & DW_IC_INTR_START_DET)
+		readl(dev->base + DW_IC_CLR_START_DET);
+	if (stat & DW_IC_INTR_GEN_CALL)
+		readl(dev->base + DW_IC_CLR_GEN_CALL);
+
+	return stat;
+}
+
 /*
  * Interrupt service routine. This gets called whenever an I2C interrupt
  * occurs.
@@ -448,8 +517,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_i=
d)
 	struct dw_i2c_dev *dev =3D dev_id;
 	u32 stat;
=20
-	stat =3D readl(dev->base + DW_IC_INTR_STAT);
+	stat =3D i2c_dw_read_clear_intrbits(dev);
 	dev_dbg(dev->dev, "%s: stat=3D0x%x\n", __func__, stat);
+
 	if (stat & DW_IC_INTR_TX_ABRT) {
 		dev->abort_source =3D readl(dev->base + DW_IC_TX_ABRT_SOURCE);
 		dev->cmd_err |=3D DW_IC_ERR_TX_ABRT;
@@ -457,7 +527,6 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_i=
d)
 	} else if (stat & DW_IC_INTR_TX_EMPTY)
 		tasklet_schedule(&dev->pump_msg);
=20
-	readl(dev->base + DW_IC_CLR_INTR);	/* clear interrupts */
 	writel(0, dev->base + DW_IC_INTR_MASK);	/* disable interrupts */
 	if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
 		complete(&dev->cmd_complete);
--=20
1.6.5


