Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: iproc: Support larger TX transfer

The current iProc I2C driver only allows each TX transfer up to 63
bytes (the TX FIFO has a size of 64 bytes, and one byte is reserved
for slave address). This patch enhances the driver to support TX
transfer in each I2C message for up to 65535 bytes (a practical
maximum, since member 'max_write_len' of 'struct i2c_adapter_quirks is
of type 'u16')

This works by loading up the I2C TX FIFO and enabling the TX underrun
interrupt for each burst. After each burst of TX data is finished,
i.e., when the TX FIFO becomes empty, the TX underrun interrupt will be
triggered and another burst of TX data can be loaded into the TX FIFO.
This repeats until all TX data are finished

Signed-off-by: Ray Jui <rjui@broadcom.com>
Tested-by: Icarus Chau <ichau@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Ray Jui and committed by
Wolfram Sang
4916eb69 ed36bfc3

+75 -9
+75 -9
drivers/i2c/busses/i2c-bcm-iproc.c
··· 58 58 #define IE_M_RX_FIFO_FULL_SHIFT 31 59 59 #define IE_M_RX_THLD_SHIFT 30 60 60 #define IE_M_START_BUSY_SHIFT 28 61 + #define IE_M_TX_UNDERRUN_SHIFT 27 61 62 62 63 #define IS_OFFSET 0x3c 63 64 #define IS_M_RX_FIFO_FULL_SHIFT 31 64 65 #define IS_M_RX_THLD_SHIFT 30 65 66 #define IS_M_START_BUSY_SHIFT 28 67 + #define IS_M_TX_UNDERRUN_SHIFT 27 66 68 67 69 #define M_TX_OFFSET 0x40 68 70 #define M_TX_WR_STATUS_SHIFT 31 ··· 78 76 #define M_RX_DATA_SHIFT 0 79 77 #define M_RX_DATA_MASK 0xff 80 78 81 - #define I2C_TIMEOUT_MSEC 100 79 + #define I2C_TIMEOUT_MSEC 50000 82 80 #define M_TX_RX_FIFO_SIZE 64 83 81 84 82 enum bus_speed_index { ··· 97 95 98 96 struct completion done; 99 97 int xfer_is_done; 98 + 99 + struct i2c_msg *msg; 100 + 101 + /* bytes that have been transferred */ 102 + unsigned int tx_bytes; 100 103 }; 101 104 102 105 /* 103 106 * Can be expanded in the future if more interrupt status bits are utilized 104 107 */ 105 - #define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) 108 + #define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT)) 106 109 107 110 static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) 108 111 { ··· 119 112 if (!status) 120 113 return IRQ_NONE; 121 114 115 + /* TX FIFO is empty and we have more data to send */ 116 + if (status & BIT(IS_M_TX_UNDERRUN_SHIFT)) { 117 + struct i2c_msg *msg = iproc_i2c->msg; 118 + unsigned int tx_bytes = msg->len - iproc_i2c->tx_bytes; 119 + unsigned int i; 120 + u32 val; 121 + 122 + /* can only fill up to the FIFO size */ 123 + tx_bytes = min_t(unsigned int, tx_bytes, M_TX_RX_FIFO_SIZE); 124 + for (i = 0; i < tx_bytes; i++) { 125 + /* start from where we left over */ 126 + unsigned int idx = iproc_i2c->tx_bytes + i; 127 + 128 + val = msg->buf[idx]; 129 + 130 + /* mark the last byte */ 131 + if (idx == msg->len - 1) { 132 + u32 tmp; 133 + 134 + val |= BIT(M_TX_WR_STATUS_SHIFT); 135 + 136 + /* 137 + * Since this is the last byte, we should 138 + * now disable TX FIFO underrun interrupt 139 + */ 140 + tmp = readl(iproc_i2c->base + IE_OFFSET); 141 + tmp &= ~BIT(IE_M_TX_UNDERRUN_SHIFT); 142 + writel(tmp, iproc_i2c->base + IE_OFFSET); 143 + } 144 + 145 + /* load data into TX FIFO */ 146 + writel(val, iproc_i2c->base + M_TX_OFFSET); 147 + } 148 + /* update number of transferred bytes */ 149 + iproc_i2c->tx_bytes += tx_bytes; 150 + } 151 + 152 + if (status & BIT(IS_M_START_BUSY_SHIFT)) { 153 + iproc_i2c->xfer_is_done = 1; 154 + complete_all(&iproc_i2c->done); 155 + } 156 + 122 157 writel(status, iproc_i2c->base + IS_OFFSET); 123 - iproc_i2c->xfer_is_done = 1; 124 - complete_all(&iproc_i2c->done); 125 158 126 159 return IRQ_HANDLED; 127 160 } ··· 254 207 int ret, i; 255 208 u8 addr; 256 209 u32 val; 210 + unsigned int tx_bytes; 257 211 unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC); 258 212 259 213 /* check if bus is busy */ ··· 264 216 return -EBUSY; 265 217 } 266 218 219 + iproc_i2c->msg = msg; 220 + 267 221 /* format and load slave address into the TX FIFO */ 268 222 addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0); 269 223 writel(addr, iproc_i2c->base + M_TX_OFFSET); 270 224 271 - /* for a write transaction, load data into the TX FIFO */ 225 + /* 226 + * For a write transaction, load data into the TX FIFO. Only allow 227 + * loading up to TX FIFO size - 1 bytes of data since the first byte 228 + * has been used up by the slave address 229 + */ 230 + tx_bytes = min_t(unsigned int, msg->len, M_TX_RX_FIFO_SIZE - 1); 272 231 if (!(msg->flags & I2C_M_RD)) { 273 - for (i = 0; i < msg->len; i++) { 232 + for (i = 0; i < tx_bytes; i++) { 274 233 val = msg->buf[i]; 275 234 276 235 /* mark the last byte */ ··· 286 231 287 232 writel(val, iproc_i2c->base + M_TX_OFFSET); 288 233 } 234 + iproc_i2c->tx_bytes = tx_bytes; 289 235 } 290 236 291 237 /* mark as incomplete before starting the transaction */ ··· 298 242 * transaction is done, i.e., the internal start_busy bit, transitions 299 243 * from 1 to 0. 300 244 */ 301 - writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET); 245 + val = BIT(IE_M_START_BUSY_SHIFT); 246 + 247 + /* 248 + * If TX data size is larger than the TX FIFO, need to enable TX 249 + * underrun interrupt, which will be triggerred when the TX FIFO is 250 + * empty. When that happens we can then pump more data into the FIFO 251 + */ 252 + if (!(msg->flags & I2C_M_RD) && 253 + msg->len > iproc_i2c->tx_bytes) 254 + val |= BIT(IE_M_TX_UNDERRUN_SHIFT); 255 + 256 + writel(val, iproc_i2c->base + IE_OFFSET); 302 257 303 258 /* 304 259 * Now we can activate the transfer. For a read operation, specify the 305 260 * number of bytes to read 306 261 */ 307 - val = 1 << M_CMD_START_BUSY_SHIFT; 262 + val = BIT(M_CMD_START_BUSY_SHIFT); 308 263 if (msg->flags & I2C_M_RD) { 309 264 val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | 310 265 (msg->len << M_CMD_RD_CNT_SHIFT); ··· 398 331 static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { 399 332 /* need to reserve one byte in the FIFO for the slave address */ 400 333 .max_read_len = M_TX_RX_FIFO_SIZE - 1, 401 - .max_write_len = M_TX_RX_FIFO_SIZE - 1, 402 334 }; 403 335 404 336 static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)