summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorShubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>2018-09-03 11:41:11 +0200
committerWolfram Sang <wsa@the-dreams.de>2018-09-06 20:49:09 +0200
commitae7304c3ea28a3ba47a7a8312c76c654ef24967e (patch)
tree4c61d7881ff1dc2a59c66ddc63b89887a165e5f0 /drivers/i2c
parenti2c: i801: fix DNV's SMBCTRL register offset (diff)
downloadlinux-ae7304c3ea28a3ba47a7a8312c76c654ef24967e.tar.xz
linux-ae7304c3ea28a3ba47a7a8312c76c654ef24967e.zip
i2c: xiic: Make the start and the byte count write atomic
Disable interrupts while configuring the transfer and enable them back. We have below as the programming sequence 1. start and slave address 2. byte count and stop In some customer platform there was a lot of interrupts between 1 and 2 and after slave address (around 7 clock cyles) if 2 is not executed then the transaction is nacked. To fix this case make the 2 writes atomic. Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> [wsa: added a newline for better readability] Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Cc: stable@kernel.org
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-xiic.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 9a71e50d21f1..0c51c0ffdda9 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -532,6 +532,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
{
u8 rx_watermark;
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+ unsigned long flags;
/* Clear and enable Rx full interrupt. */
xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
@@ -547,6 +548,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
rx_watermark = IIC_RX_FIFO_DEPTH;
xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
+ local_irq_save(flags);
if (!(msg->flags & I2C_M_NOSTART))
/* write the address */
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
@@ -556,6 +558,8 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ local_irq_restore(flags);
+
if (i2c->nmsgs == 1)
/* very last, enable bus not busy as well */
xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);