From 5afa9d35782890e8fbd972f12ee5183ba5feb81d Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 6 Jun 2011 11:25:19 -0600 Subject: [PATCH 1/4] i2c: tegra: Assign unused slave address On Tegra, we should always use the "new" I2C slave controller, to avoid issues with the old controller. This was implemented in commit 65a1a0a "i2c: tegra: Enable new slave mode." There is currently no driver for the Tegra I2C slave controller upstream. Additionally, the controller cannot be completely disabled. Instead, we need to: a) Set I2C_SL_CNFG_NACK to make the controller automatically NACK any incoming transactions. b) The controller's definition of NACK isn't identical to the I2C protocol's definition. Specifically, it will perform a standard NACK, but *also* continue to hold the clock line low in expectation of receiving more data. This can hang the bus, or at least cause transaction timeouts, if something starts a transaction that matches the controller's slave address. Since the default address is 0x00, the general call address, this does occur in practice. To avoid this, we explicitly program a slave address that is reserved for future expansion. For current boards, this guarantees the address will never be used. If a future board ever needs to use this address, we can add platform data to determine a board-specific safe address. 0xfc is picked by this patch. This patch is based on a change previously posted by: Wei Ni http://www.spinics.net/lists/linux-i2c/msg05437.html In turned based on internal changes by: Bharat Nihalani A semantically equivalent change has been contained in the various ChromeOS kernels for a while. I tested this change on top of 3.0-rc2 on Harmony, and interacted with the WM8903 I2C-based audio codec. Signed-off-by: Stephen Warren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-tegra.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 4d9319665e32..fb3b4f8f8152 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -40,8 +40,10 @@ #define I2C_CNFG_NEW_MASTER_FSM (1<<11) #define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 +#define I2C_SL_CNFG_NACK (1<<1) #define I2C_SL_CNFG_NEWSL (1<<2) #define I2C_SL_ADDR1 0x02c +#define I2C_SL_ADDR2 0x030 #define I2C_TX_FIFO 0x050 #define I2C_RX_FIFO 0x054 #define I2C_PACKET_TRANSFER_STATUS 0x058 @@ -337,7 +339,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); - i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG); + sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; + i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); + i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); + i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); + } val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | From 19820510c504d5ba572959c67a72d913afc187a6 Mon Sep 17 00:00:00 2001 From: Huisung Kang Date: Thu, 23 Jun 2011 21:37:33 +0900 Subject: [PATCH 2/4] i2c-s3c2410: Fix typo 'i2s' -> 'i2c' Signed-off-by: Huisung Kang Signed-off-by: Kukjin Kim Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-s3c2410.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6c00c107ebf3..9ad18509c0c2 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -248,12 +248,12 @@ static inline int is_msgend(struct s3c24xx_i2c *i2c) return i2c->msg_ptr >= i2c->msg->len; } -/* i2s_s3c_irq_nextbyte +/* i2c_s3c_irq_nextbyte * * process an interrupt and work out what to do */ -static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) +static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) { unsigned long tmp; unsigned char byte; @@ -444,7 +444,7 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) /* pretty much this leaves us with the fact that we've * transmitted or received whatever byte we last sent */ - i2s_s3c_irq_nextbyte(i2c, status); + i2c_s3c_irq_nextbyte(i2c, status); out: return IRQ_HANDLED; From b90ea76542c53300d39e76f72cf583cd0e0b1f68 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Thu, 23 Jun 2011 21:37:20 +0900 Subject: [PATCH 3/4] i2c-s3c2410: Remove useless break code Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-s3c2410.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 9ad18509c0c2..f84a63c6dd97 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -264,7 +264,6 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) case STATE_IDLE: dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__); goto out; - break; case STATE_STOP: dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__); From 4a65163e3b2190445c1d94daa21d09c5af604d97 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 23 Jun 2011 17:07:54 -0400 Subject: [PATCH 4/4] i2c-bfin-twi: abort transfer is MEM bit is reset unexpectedly Sometimes, the first I2C transmit interrupt is not serviced in time (like when higher priority interrupts take too long). Since the RESTART bit is not set before the next I2C clock, when the TWI handler is finally called, the I2C session is aborted (MEM bit is reset) and both SMITSERV and MCOMP int status bits are set. So when this happens, abort the transfer. Reported-by: Isabelle Leonardi Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 52b545a795f2..cbc98aea5b09 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -193,7 +193,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, return; } if (twi_int_status & MCOMP) { - if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if ((read_MASTER_CTL(iface) & MEN) == 0 && + (iface->cur_mode == TWI_I2C_MODE_REPEAT || + iface->cur_mode == TWI_I2C_MODE_COMBINED)) { + iface->result = -1; + write_INT_MASK(iface, 0); + write_MASTER_CTL(iface, 0); + } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { if (iface->readNum == 0) { /* set the read number to 1 and ask for manual * stop in block combine mode