From: Paul Walmsley <paul@pwsan.com>
To: linux-omap@vger.kernel.org
Subject: [PATCH 5/9] TWL4030: read and write module ISRs to clear them at init
Date: Thu, 17 Jul 2008 19:34:52 -0600 [thread overview]
Message-ID: <20080718013451.18943.18579.stgit@localhost.localdomain> (raw)
In-Reply-To: <20080718013205.18943.34047.stgit@localhost.localdomain>
TWL4030 interrupt status register bits can be cleared in one of two ways:
either by reading from the register, or by writing a 1 to the
appropriate bit(s) in the register. This behavior can be altered at any
time by the <twlmodule>_SIH_CTRL.COR register bit ("clear-on-read").
twl4030-core.c does not touch these *_SIH_CTRL registers during boot,
and the TWL4030 TRM is deeply confused as to whether COR=1 means that
the registers are cleared on reads, or cleared on writes.
So, take the cautious way out and both read from and write to the TWL4030
module ISRs to clear them at startup. Also, use WARN_ON() to warn if the
read/write failed, and don't skip the rest of the initialization on failure
either.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
drivers/i2c/chips/twl4030-core.c | 128 +++++++++++++++-----------------------
1 files changed, 51 insertions(+), 77 deletions(-)
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 9d93524..615fb84 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -712,6 +712,28 @@ static int power_companion_init(void)
return e;
}
+/**
+ * twl4030_i2c_clear_isr - clear TWL4030 SIH ISR regs via read + write
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ *
+ * Reads, then writes 0xff to a TWL4030 interrupt status register to ensure
+ * that interrupts are cleared. The read + write is necessary since we
+ * don't know whether the COR bit is set in <module>_SIH_CTRL. Returns
+ * the status from the I2C read operation.
+ */
+static int twl4030_i2c_clear_isr(u8 mod_no, u8 reg)
+{
+ int res;
+ u8 tmp;
+
+ res = twl4030_i2c_read_u8(mod_no, &tmp, reg);
+ if (res < 0)
+ return res;
+
+ return twl4030_i2c_write_u8(mod_no, 0xff, reg);
+}
+
static void twl_init_irq(void)
{
int i = 0;
@@ -719,6 +741,13 @@ static void twl_init_irq(void)
char *msg = "Unable to register interrupt subsystem";
unsigned int irq_num;
+ /*
+ * For each TWL4030 module with ISR/IMR registers, mask all
+ * interrupts and then clear any existing interrupt status bits,
+ * since we initially do not have any TWL4030 module interrupt
+ * handlers present.
+ */
+
/* PWR_IMR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
if (res < 0) {
@@ -735,19 +764,11 @@ static void twl_init_irq(void)
/* Clear off any other pending interrupts on power */
/* PWR_ISR1 */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INT, 0x00) < 0);
/* PWR_ISR2 */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
- /* POWER HACK (END) */
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INT, 0x02) < 0);
+
/* Slave address 0x4A */
/* BCIIMR1A */
@@ -779,32 +800,16 @@ static void twl_init_irq(void)
}
/* BCIISR1A */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x0);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INTERRUPTS, 0x0) < 0);
/* BCIISR2A */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x1);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INTERRUPTS, 0x1) < 0);
/* BCIISR1B */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INTERRUPTS, 0x4) < 0);
/* BCIISR2B */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x5);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_INTERRUPTS, 0x5) < 0);
/* MAD C */
/* MADC_IMR1 */
@@ -822,18 +827,10 @@ static void twl_init_irq(void)
}
/* MADC_ISR1 */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x61);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_MADC, 0x61) < 0);
/* MADC_ISR2 */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x63);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_MADC, 0x63) < 0);
/* key Pad */
/* KEYPAD - IMR1 */
@@ -842,12 +839,10 @@ static void twl_init_irq(void)
pr_err("%s[%d][%d]\n", msg, res, __LINE__);
return;
}
- {
- u8 clear;
- /* Clear ISR */
- twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
- twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);
- }
+
+ /* KEYPAD - ISR1 */
+ /* XXX does this still need to be done twice for some reason? */
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_KEYPAD, 0x11) < 0);
/* KEYPAD - IMR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));
@@ -856,6 +851,9 @@ static void twl_init_irq(void)
return;
}
+ /* KEYPAD - ISR2 */
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_KEYPAD, 0x13) < 0);
+
/* Slave address 0x49 */
/* GPIO_IMR1A */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));
@@ -900,46 +898,22 @@ static void twl_init_irq(void)
}
/* GPIO_ISR1A */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x19);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x19) < 0);
/* GPIO_ISR2A */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x1a);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x1a) < 0);
/* GPIO_ISR3A */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x1b);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x1b) < 0);
/* GPIO_ISR1B */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x1f);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x1f) < 0);
/* GPIO_ISR2B */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x20);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x20) < 0);
/* GPIO_ISR3B */
- res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xff, 0x21);
- if (res < 0) {
- pr_err("%s[%d][%d]\n", msg, res, __LINE__);
- return;
- }
+ WARN_ON(twl4030_i2c_clear_isr(TWL4030_MODULE_GPIO, 0x21) < 0);
/* install an irq handler for each of the PIH modules */
for (i = TWL4030_IRQ_BASE; i < TWL4030_IRQ_END; i++) {
next prev parent reply other threads:[~2008-07-18 1:35 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-07-18 1:34 [PATCH 0/9] TWL4030 bugfixes and cleanups Paul Walmsley
2008-07-18 1:34 ` [PATCH 1/9] TWL4030: remove superfluous PWR interrupt status clear before masking Paul Walmsley
2008-07-18 1:34 ` [PATCH 3/9] TWL4030: use correct register addresses for BCI IMR registers Paul Walmsley
2008-07-18 1:34 ` [PATCH 2/9] TWL4030: clear TWL GPIO interrupt status registers Paul Walmsley
2008-07-18 1:34 ` [PATCH 4/9] TWL4030: clear MADC interrupt status registers upon init Paul Walmsley
2008-07-18 1:34 ` Paul Walmsley [this message]
2008-07-18 9:12 ` [PATCH 5/9] TWL4030: read and write module ISRs to clear them at init Peter 'p2' De Schrijver
2008-07-22 0:30 ` Paul Walmsley
2008-07-18 1:34 ` [PATCH 6/9] TWL4030: change init-time IMR mask code to WARN if error Paul Walmsley
2008-07-18 1:34 ` [PATCH 7/9] TWL4030: move TWL module register defs into separate include files Paul Walmsley
2008-07-18 1:34 ` [PATCH 8/9] TWL4030: use symbolic ISR/IMR register names during twl_init_irq() Paul Walmsley
2008-07-18 1:34 ` [PATCH 9/9] TWL4030: convert early interrupt mask/clear funcs to use array Paul Walmsley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080718013451.18943.18579.stgit@localhost.localdomain \
--to=paul@pwsan.com \
--cc=linux-omap@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox