| From ae7304c3ea28a3ba47a7a8312c76c654ef24967e Mon Sep 17 00:00:00 2001 |
| From: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com> |
| Date: Mon, 3 Sep 2018 15:11:11 +0530 |
| Subject: i2c: xiic: Make the start and the byte count write atomic |
| |
| From: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com> |
| |
| commit ae7304c3ea28a3ba47a7a8312c76c654ef24967e upstream. |
| |
| 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 |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/i2c/busses/i2c-xiic.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/drivers/i2c/busses/i2c-xiic.c |
| +++ b/drivers/i2c/busses/i2c-xiic.c |
| @@ -538,6 +538,7 @@ static void xiic_start_recv(struct xiic_ |
| { |
| 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); |
| @@ -553,6 +554,7 @@ static void xiic_start_recv(struct xiic_ |
| 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, |
| @@ -563,6 +565,8 @@ static void xiic_start_recv(struct xiic_ |
| |
| 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); |