aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorHarini Katakam <harinik@xilinx.com>2014-12-11 23:18:26 -0500
committerWolfram Sang <wsa@the-dreams.de>2015-01-13 10:21:03 -0500
commit9fae82e1acda8d4a6881be63cc38521b84007ba9 (patch)
tree3428a6789cd91a82785a15af9d3e6ff960944820 /drivers/i2c
parent1c57499361c403f18e5423969b9aa2446bdbe622 (diff)
i2c: cadence: Handle > 252 byte transfers
The I2C controller sends a NACK to the slave when transfer size register reaches zero, irrespective of the hold bit. So, in order to handle transfers greater than 252 bytes, the transfer size register has to be maintained at a value >= 1. This patch implements the same. The interrupt status is cleared at the beginning of the isr instead of the end, to avoid missing any interrupts. Signed-off-by: Harini Katakam <harinik@xilinx.com> [wsa: added braces around else branch] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-cadence.c175
1 files changed, 102 insertions, 73 deletions
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 626f74ecd4be..871cb58aaa06 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -128,6 +128,7 @@
128 * @suspended: Flag holding the device's PM status 128 * @suspended: Flag holding the device's PM status
129 * @send_count: Number of bytes still expected to send 129 * @send_count: Number of bytes still expected to send
130 * @recv_count: Number of bytes still expected to receive 130 * @recv_count: Number of bytes still expected to receive
131 * @curr_recv_count: Number of bytes to be received in current transfer
131 * @irq: IRQ number 132 * @irq: IRQ number
132 * @input_clk: Input clock to I2C controller 133 * @input_clk: Input clock to I2C controller
133 * @i2c_clk: Maximum I2C clock speed 134 * @i2c_clk: Maximum I2C clock speed
@@ -146,6 +147,7 @@ struct cdns_i2c {
146 u8 suspended; 147 u8 suspended;
147 unsigned int send_count; 148 unsigned int send_count;
148 unsigned int recv_count; 149 unsigned int recv_count;
150 unsigned int curr_recv_count;
149 int irq; 151 int irq;
150 unsigned long input_clk; 152 unsigned long input_clk;
151 unsigned int i2c_clk; 153 unsigned int i2c_clk;
@@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
182 */ 184 */
183static irqreturn_t cdns_i2c_isr(int irq, void *ptr) 185static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
184{ 186{
185 unsigned int isr_status, avail_bytes; 187 unsigned int isr_status, avail_bytes, updatetx;
186 unsigned int bytes_to_recv, bytes_to_send; 188 unsigned int bytes_to_send;
187 struct cdns_i2c *id = ptr; 189 struct cdns_i2c *id = ptr;
188 /* Signal completion only after everything is updated */ 190 /* Signal completion only after everything is updated */
189 int done_flag = 0; 191 int done_flag = 0;
190 irqreturn_t status = IRQ_NONE; 192 irqreturn_t status = IRQ_NONE;
191 193
192 isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); 194 isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
195 cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
193 196
194 /* Handling nack and arbitration lost interrupt */ 197 /* Handling nack and arbitration lost interrupt */
195 if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) { 198 if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
@@ -197,89 +200,112 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
197 status = IRQ_HANDLED; 200 status = IRQ_HANDLED;
198 } 201 }
199 202
200 /* Handling Data interrupt */ 203 /*
201 if ((isr_status & CDNS_I2C_IXR_DATA) && 204 * Check if transfer size register needs to be updated again for a
202 (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) { 205 * large data receive operation.
203 /* Always read data interrupt threshold bytes */ 206 */
204 bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH; 207 updatetx = 0;
205 id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH; 208 if (id->recv_count > id->curr_recv_count)
206 avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); 209 updatetx = 1;
207 210
208 /* 211 /* When receiving, handle data interrupt and completion interrupt */
209 * if the tranfer size register value is zero, then 212 if (id->p_recv_buf &&
210 * check for the remaining bytes and update the 213 ((isr_status & CDNS_I2C_IXR_COMP) ||
211 * transfer size register. 214 (isr_status & CDNS_I2C_IXR_DATA))) {
212 */ 215 /* Read data if receive data valid is set */
213 if (!avail_bytes) { 216 while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
214 if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) 217 CDNS_I2C_SR_RXDV) {
215 cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, 218 /*
216 CDNS_I2C_XFER_SIZE_OFFSET); 219 * Clear hold bit that was set for FIFO control if
217 else 220 * RX data left is less than FIFO depth, unless
218 cdns_i2c_writereg(id->recv_count, 221 * repeated start is selected.
219 CDNS_I2C_XFER_SIZE_OFFSET); 222 */
220 } 223 if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
224 !id->bus_hold_flag)
225 cdns_i2c_clear_bus_hold(id);
221 226
222 /* Process the data received */
223 while (bytes_to_recv--)
224 *(id->p_recv_buf)++ = 227 *(id->p_recv_buf)++ =
225 cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); 228 cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
229 id->recv_count--;
230 id->curr_recv_count--;
226 231
227 if (!id->bus_hold_flag && 232 if (updatetx &&
228 (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) 233 (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
229 cdns_i2c_clear_bus_hold(id); 234 break;
235 }
230 236
231 status = IRQ_HANDLED; 237 /*
232 } 238 * The controller sends NACK to the slave when transfer size
239 * register reaches zero without considering the HOLD bit.
240 * This workaround is implemented for large data transfers to
241 * maintain transfer size non-zero while performing a large
242 * receive operation.
243 */
244 if (updatetx &&
245 (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
246 /* wait while fifo is full */
247 while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
248 (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
249 ;
233 250
234 /* Handling Transfer Complete interrupt */
235 if (isr_status & CDNS_I2C_IXR_COMP) {
236 if (!id->p_recv_buf) {
237 /* 251 /*
238 * If the device is sending data If there is further 252 * Check number of bytes to be received against maximum
239 * data to be sent. Calculate the available space 253 * transfer size and update register accordingly.
240 * in FIFO and fill the FIFO with that many bytes.
241 */ 254 */
242 if (id->send_count) { 255 if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
243 avail_bytes = CDNS_I2C_FIFO_DEPTH - 256 CDNS_I2C_TRANSFER_SIZE) {
244 cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); 257 cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
245 if (id->send_count > avail_bytes) 258 CDNS_I2C_XFER_SIZE_OFFSET);
246 bytes_to_send = avail_bytes; 259 id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
247 else 260 CDNS_I2C_FIFO_DEPTH;
248 bytes_to_send = id->send_count;
249
250 while (bytes_to_send--) {
251 cdns_i2c_writereg(
252 (*(id->p_send_buf)++),
253 CDNS_I2C_DATA_OFFSET);
254 id->send_count--;
255 }
256 } else { 261 } else {
257 /* 262 cdns_i2c_writereg(id->recv_count -
258 * Signal the completion of transaction and 263 CDNS_I2C_FIFO_DEPTH,
259 * clear the hold bus bit if there are no 264 CDNS_I2C_XFER_SIZE_OFFSET);
260 * further messages to be processed. 265 id->curr_recv_count = id->recv_count;
261 */
262 done_flag = 1;
263 } 266 }
264 if (!id->send_count && !id->bus_hold_flag) 267 }
265 cdns_i2c_clear_bus_hold(id); 268
266 } else { 269 /* Clear hold (if not repeated start) and signal completion */
270 if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
267 if (!id->bus_hold_flag) 271 if (!id->bus_hold_flag)
268 cdns_i2c_clear_bus_hold(id); 272 cdns_i2c_clear_bus_hold(id);
273 done_flag = 1;
274 }
275
276 status = IRQ_HANDLED;
277 }
278
279 /* When sending, handle transfer complete interrupt */
280 if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
281 /*
282 * If there is more data to be sent, calculate the
283 * space available in FIFO and fill with that many bytes.
284 */
285 if (id->send_count) {
286 avail_bytes = CDNS_I2C_FIFO_DEPTH -
287 cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
288 if (id->send_count > avail_bytes)
289 bytes_to_send = avail_bytes;
290 else
291 bytes_to_send = id->send_count;
292
293 while (bytes_to_send--) {
294 cdns_i2c_writereg(
295 (*(id->p_send_buf)++),
296 CDNS_I2C_DATA_OFFSET);
297 id->send_count--;
298 }
299 } else {
269 /* 300 /*
270 * If the device is receiving data, then signal 301 * Signal the completion of transaction and
271 * the completion of transaction and read the data 302 * clear the hold bus bit if there are no
272 * present in the FIFO. Signal the completion of 303 * further messages to be processed.
273 * transaction.
274 */ 304 */
275 while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
276 CDNS_I2C_SR_RXDV) {
277 *(id->p_recv_buf)++ =
278 cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
279 id->recv_count--;
280 }
281 done_flag = 1; 305 done_flag = 1;
282 } 306 }
307 if (!id->send_count && !id->bus_hold_flag)
308 cdns_i2c_clear_bus_hold(id);
283 309
284 status = IRQ_HANDLED; 310 status = IRQ_HANDLED;
285 } 311 }
@@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
289 if (id->err_status) 315 if (id->err_status)
290 status = IRQ_HANDLED; 316 status = IRQ_HANDLED;
291 317
292 cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
293
294 if (done_flag) 318 if (done_flag)
295 complete(&id->xfer_done); 319 complete(&id->xfer_done);
296 320
@@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
316 if (id->p_msg->flags & I2C_M_RECV_LEN) 340 if (id->p_msg->flags & I2C_M_RECV_LEN)
317 id->recv_count = I2C_SMBUS_BLOCK_MAX + 1; 341 id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
318 342
343 id->curr_recv_count = id->recv_count;
344
319 /* 345 /*
320 * Check for the message size against FIFO depth and set the 346 * Check for the message size against FIFO depth and set the
321 * 'hold bus' bit if it is greater than FIFO depth. 347 * 'hold bus' bit if it is greater than FIFO depth.
@@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
335 * receive if it is less than transfer size and transfer size if 361 * receive if it is less than transfer size and transfer size if
336 * it is more. Enable the interrupts. 362 * it is more. Enable the interrupts.
337 */ 363 */
338 if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) 364 if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
339 cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, 365 cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
340 CDNS_I2C_XFER_SIZE_OFFSET); 366 CDNS_I2C_XFER_SIZE_OFFSET);
341 else 367 id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
368 } else {
342 cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); 369 cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
370 }
371
343 /* Clear the bus hold flag if bytes to receive is less than FIFO size */ 372 /* Clear the bus hold flag if bytes to receive is less than FIFO size */
344 if (!id->bus_hold_flag && 373 if (!id->bus_hold_flag &&
345 ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && 374 ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&