aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authormokopatches <mokopatches@openmoko.org>2008-11-19 17:03:09 +0000
committerwarmcat <andy@warmcat.com>2008-11-19 17:03:09 +0000
commit22eed212f2eb365f1a99b2fbad1ad35379623ec0 (patch)
tree0d5ec2e4ab161216e5c0796c3a15b9cc74c85fbb /drivers
parent6f9153da18b2f9180b4381cff3785e3dba01c7e7 (diff)
fix-i2c-s3c2410-resume-race.patch
fix-i2c-s3c2410-resume-race.patch There is a nasty race between i2c-s3c2410 resume and resume of I2C driver and the client drivers -- the watchdog device actually gets to use the dead I2C bus before it is reinitialized by the I2C driver resume! This patch makes sure any customers get turned away until the shopkeeper has woken up. Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index ba0006666b3..3a86f23cf44 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -76,6 +76,8 @@ struct s3c24xx_i2c {
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
+
+ int suspended;
};
/* default platform data removed, dev should always carry data. */
@@ -135,6 +137,14 @@ static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
unsigned long tmp;
tmp = readl(i2c->regs + S3C2410_IICCON);
+
+/* S3c2442 datasheet
+ *
+ * If the IICCON[5]=0, IICCON[4] does not operate correctly.
+ * So, It is recommended that you should set IICCON[5]=1,
+ * although you does not use the IIC interrupt.
+ */
+
writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
@@ -480,6 +490,14 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
if (i2c->suspended)
return -EIO;
+ if (i2c->suspended) {
+ dev_err(i2c->dev,
+ "Hey I am still asleep (suspended: %d), retry later\n",
+ i2c->suspended);
+ ret = -EAGAIN;
+ goto out;
+ }
+
ret = s3c24xx_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
@@ -973,6 +991,8 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)
i2c->suspended = 0;
s3c24xx_i2c_init(i2c);
+ i2c->suspended--;
+
return 0;
}