summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorShreesha Rajashekar <shreesha@broadcom.com>2019-04-02 21:18:22 -0400
committerWolfram Sang <wsa@the-dreams.de>2019-04-03 16:35:07 -0400
commitc24b8d574b7c6f9cc2c50ed1e674f4333cc53736 (patch)
treec77f432001ef1a27b95862a6201eec5779d34b4e /drivers/i2c
parentf6ac28d61675e05cb1227cbba44ff538f8671e54 (diff)
i2c: iproc: Extend I2C read up to 255 bytes
Add support to allow I2C master read transfer up to 255 bytes. Signed-off-by: Shreesha Rajashekar <shreesha@broadcom.com> Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com> Signed-off-by: Ray Jui <ray.jui@broadcom.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c96
1 files changed, 74 insertions, 22 deletions
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index 4c8c3bc4669c..4c31f4e178b6 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -80,6 +80,10 @@
80 80
81#define I2C_TIMEOUT_MSEC 50000 81#define I2C_TIMEOUT_MSEC 50000
82#define M_TX_RX_FIFO_SIZE 64 82#define M_TX_RX_FIFO_SIZE 64
83#define M_RX_FIFO_MAX_THLD_VALUE (M_TX_RX_FIFO_SIZE - 1)
84
85#define M_RX_MAX_READ_LEN 255
86#define M_RX_FIFO_THLD_VALUE 50
83 87
84enum bus_speed_index { 88enum bus_speed_index {
85 I2C_SPD_100K = 0, 89 I2C_SPD_100K = 0,
@@ -102,17 +106,39 @@ struct bcm_iproc_i2c_dev {
102 106
103 /* bytes that have been transferred */ 107 /* bytes that have been transferred */
104 unsigned int tx_bytes; 108 unsigned int tx_bytes;
109 /* bytes that have been read */
110 unsigned int rx_bytes;
111 unsigned int thld_bytes;
105}; 112};
106 113
107/* 114/*
108 * Can be expanded in the future if more interrupt status bits are utilized 115 * Can be expanded in the future if more interrupt status bits are utilized
109 */ 116 */
110#define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT)) 117#define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT)\
118 | BIT(IS_M_RX_THLD_SHIFT))
119
120static void bcm_iproc_i2c_read_valid_bytes(struct bcm_iproc_i2c_dev *iproc_i2c)
121{
122 struct i2c_msg *msg = iproc_i2c->msg;
123
124 /* Read valid data from RX FIFO */
125 while (iproc_i2c->rx_bytes < msg->len) {
126 if (!((readl(iproc_i2c->base + M_FIFO_CTRL_OFFSET) >> M_FIFO_RX_CNT_SHIFT)
127 & M_FIFO_RX_CNT_MASK))
128 break;
129
130 msg->buf[iproc_i2c->rx_bytes] =
131 (readl(iproc_i2c->base + M_RX_OFFSET) >>
132 M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
133 iproc_i2c->rx_bytes++;
134 }
135}
111 136
112static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) 137static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
113{ 138{
114 struct bcm_iproc_i2c_dev *iproc_i2c = data; 139 struct bcm_iproc_i2c_dev *iproc_i2c = data;
115 u32 status = readl(iproc_i2c->base + IS_OFFSET); 140 u32 status = readl(iproc_i2c->base + IS_OFFSET);
141 u32 tmp;
116 142
117 status &= ISR_MASK; 143 status &= ISR_MASK;
118 144
@@ -136,8 +162,6 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
136 162
137 /* mark the last byte */ 163 /* mark the last byte */
138 if (idx == msg->len - 1) { 164 if (idx == msg->len - 1) {
139 u32 tmp;
140
141 val |= BIT(M_TX_WR_STATUS_SHIFT); 165 val |= BIT(M_TX_WR_STATUS_SHIFT);
142 166
143 /* 167 /*
@@ -156,6 +180,32 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
156 iproc_i2c->tx_bytes += tx_bytes; 180 iproc_i2c->tx_bytes += tx_bytes;
157 } 181 }
158 182
183 if (status & BIT(IS_M_RX_THLD_SHIFT)) {
184 struct i2c_msg *msg = iproc_i2c->msg;
185 u32 bytes_left;
186
187 bcm_iproc_i2c_read_valid_bytes(iproc_i2c);
188 bytes_left = msg->len - iproc_i2c->rx_bytes;
189 if (bytes_left == 0) {
190 /* finished reading all data, disable rx thld event */
191 tmp = readl(iproc_i2c->base + IE_OFFSET);
192 tmp &= ~BIT(IS_M_RX_THLD_SHIFT);
193 writel(tmp, iproc_i2c->base + IE_OFFSET);
194 } else if (bytes_left < iproc_i2c->thld_bytes) {
195 /* set bytes left as threshold */
196 tmp = readl(iproc_i2c->base + M_FIFO_CTRL_OFFSET);
197 tmp &= ~(M_FIFO_RX_THLD_MASK << M_FIFO_RX_THLD_SHIFT);
198 tmp |= (bytes_left << M_FIFO_RX_THLD_SHIFT);
199 writel(tmp, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
200 iproc_i2c->thld_bytes = bytes_left;
201 }
202 /*
203 * bytes_left >= iproc_i2c->thld_bytes,
204 * hence no need to change the THRESHOLD SET.
205 * It will remain as iproc_i2c->thld_bytes itself
206 */
207 }
208
159 if (status & BIT(IS_M_START_BUSY_SHIFT)) { 209 if (status & BIT(IS_M_START_BUSY_SHIFT)) {
160 iproc_i2c->xfer_is_done = 1; 210 iproc_i2c->xfer_is_done = 1;
161 complete(&iproc_i2c->done); 211 complete(&iproc_i2c->done);
@@ -253,7 +303,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
253{ 303{
254 int ret, i; 304 int ret, i;
255 u8 addr; 305 u8 addr;
256 u32 val; 306 u32 val, tmp, val_intr_en;
257 unsigned int tx_bytes; 307 unsigned int tx_bytes;
258 unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC); 308 unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC);
259 309
@@ -298,7 +348,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
298 * transaction is done, i.e., the internal start_busy bit, transitions 348 * transaction is done, i.e., the internal start_busy bit, transitions
299 * from 1 to 0. 349 * from 1 to 0.
300 */ 350 */
301 val = BIT(IE_M_START_BUSY_SHIFT); 351 val_intr_en = BIT(IE_M_START_BUSY_SHIFT);
302 352
303 /* 353 /*
304 * If TX data size is larger than the TX FIFO, need to enable TX 354 * If TX data size is larger than the TX FIFO, need to enable TX
@@ -307,9 +357,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
307 */ 357 */
308 if (!(msg->flags & I2C_M_RD) && 358 if (!(msg->flags & I2C_M_RD) &&
309 msg->len > iproc_i2c->tx_bytes) 359 msg->len > iproc_i2c->tx_bytes)
310 val |= BIT(IE_M_TX_UNDERRUN_SHIFT); 360 val_intr_en |= BIT(IE_M_TX_UNDERRUN_SHIFT);
311
312 writel(val, iproc_i2c->base + IE_OFFSET);
313 361
314 /* 362 /*
315 * Now we can activate the transfer. For a read operation, specify the 363 * Now we can activate the transfer. For a read operation, specify the
@@ -317,11 +365,27 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
317 */ 365 */
318 val = BIT(M_CMD_START_BUSY_SHIFT); 366 val = BIT(M_CMD_START_BUSY_SHIFT);
319 if (msg->flags & I2C_M_RD) { 367 if (msg->flags & I2C_M_RD) {
368 iproc_i2c->rx_bytes = 0;
369 if (msg->len > M_RX_FIFO_MAX_THLD_VALUE)
370 iproc_i2c->thld_bytes = M_RX_FIFO_THLD_VALUE;
371 else
372 iproc_i2c->thld_bytes = msg->len;
373
374 /* set threshold value */
375 tmp = readl(iproc_i2c->base + M_FIFO_CTRL_OFFSET);
376 tmp &= ~(M_FIFO_RX_THLD_MASK << M_FIFO_RX_THLD_SHIFT);
377 tmp |= iproc_i2c->thld_bytes << M_FIFO_RX_THLD_SHIFT;
378 writel(tmp, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
379
380 /* enable the RX threshold interrupt */
381 val_intr_en |= BIT(IE_M_RX_THLD_SHIFT);
382
320 val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | 383 val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
321 (msg->len << M_CMD_RD_CNT_SHIFT); 384 (msg->len << M_CMD_RD_CNT_SHIFT);
322 } else { 385 } else {
323 val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT); 386 val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
324 } 387 }
388 writel(val_intr_en, iproc_i2c->base + IE_OFFSET);
325 writel(val, iproc_i2c->base + M_CMD_OFFSET); 389 writel(val, iproc_i2c->base + M_CMD_OFFSET);
326 390
327 time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); 391 time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
@@ -353,17 +417,6 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
353 return ret; 417 return ret;
354 } 418 }
355 419
356 /*
357 * For a read operation, we now need to load the data from FIFO
358 * into the memory buffer
359 */
360 if (msg->flags & I2C_M_RD) {
361 for (i = 0; i < msg->len; i++) {
362 msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
363 M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
364 }
365 }
366
367 return 0; 420 return 0;
368} 421}
369 422
@@ -395,9 +448,8 @@ static const struct i2c_algorithm bcm_iproc_algo = {
395 .functionality = bcm_iproc_i2c_functionality, 448 .functionality = bcm_iproc_i2c_functionality,
396}; 449};
397 450
398static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { 451static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
399 /* need to reserve one byte in the FIFO for the slave address */ 452 .max_read_len = M_RX_MAX_READ_LEN,
400 .max_read_len = M_TX_RX_FIFO_SIZE - 1,
401}; 453};
402 454
403static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) 455static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)