diff options
author | Shreesha Rajashekar <shreesha@broadcom.com> | 2019-04-02 21:18:22 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2019-04-03 16:35:07 -0400 |
commit | c24b8d574b7c6f9cc2c50ed1e674f4333cc53736 (patch) | |
tree | c77f432001ef1a27b95862a6201eec5779d34b4e /drivers/i2c | |
parent | f6ac28d61675e05cb1227cbba44ff538f8671e54 (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.c | 96 |
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 | ||
84 | enum bus_speed_index { | 88 | enum 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 | |||
120 | static 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 | ||
112 | static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) | 137 | static 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 | ||
398 | static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { | 451 | static 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 | ||
403 | static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) | 455 | static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) |