diff options
author | Nishanth Menon <nm@ti.com> | 2008-11-21 16:39:46 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2008-11-21 16:39:46 -0500 |
commit | b6ee52c39999b2f3bcd9e26f0edf1f07599cf40e (patch) | |
tree | 9bae229905eb207fe2c01fa6b9bfb6d623b96384 /drivers/i2c | |
parent | 4574eb6892a13bc91aac8676457d46798935d653 (diff) |
i2c-omap: FIFO handling support and broken hw workaround for i2c-omap
Based on an earlier patch from Nishant Menon:
- Transfers can use FIFO on FIFO capable devices
- Prevents errors for HSI2C if FIFO is not used
- Implemented errenous handling of STT-STP handling on SDP2430
Also merged in is a fix from Jaron Marini to fix occasional i2c
hang if OMAP_I2C_CON_STT remains asserted.
Signed-off-by: Jason P Marini <jason.marini@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 190 |
1 files changed, 150 insertions, 40 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b0aa0f8b564b..9ae4b74f3d1a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -55,8 +55,11 @@ | |||
55 | #define OMAP_I2C_SCLL_REG 0x34 | 55 | #define OMAP_I2C_SCLL_REG 0x34 |
56 | #define OMAP_I2C_SCLH_REG 0x38 | 56 | #define OMAP_I2C_SCLH_REG 0x38 |
57 | #define OMAP_I2C_SYSTEST_REG 0x3c | 57 | #define OMAP_I2C_SYSTEST_REG 0x3c |
58 | #define OMAP_I2C_BUFSTAT_REG 0x40 | ||
58 | 59 | ||
59 | /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ | 60 | /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ |
61 | #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ | ||
62 | #define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */ | ||
60 | #define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */ | 63 | #define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */ |
61 | #define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */ | 64 | #define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */ |
62 | #define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */ | 65 | #define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */ |
@@ -64,7 +67,8 @@ | |||
64 | #define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */ | 67 | #define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */ |
65 | 68 | ||
66 | /* I2C Status Register (OMAP_I2C_STAT): */ | 69 | /* I2C Status Register (OMAP_I2C_STAT): */ |
67 | #define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */ | 70 | #define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */ |
71 | #define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */ | ||
68 | #define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */ | 72 | #define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */ |
69 | #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ | 73 | #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ |
70 | #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ | 74 | #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ |
@@ -78,12 +82,14 @@ | |||
78 | 82 | ||
79 | /* I2C Buffer Configuration Register (OMAP_I2C_BUF): */ | 83 | /* I2C Buffer Configuration Register (OMAP_I2C_BUF): */ |
80 | #define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */ | 84 | #define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */ |
85 | #define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */ | ||
81 | #define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */ | 86 | #define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */ |
87 | #define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */ | ||
82 | 88 | ||
83 | /* I2C Configuration Register (OMAP_I2C_CON): */ | 89 | /* I2C Configuration Register (OMAP_I2C_CON): */ |
84 | #define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */ | 90 | #define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */ |
85 | #define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */ | 91 | #define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */ |
86 | #define OMAP_I2C_CON_OPMODE (1 << 12) /* High Speed support */ | 92 | #define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */ |
87 | #define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */ | 93 | #define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */ |
88 | #define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */ | 94 | #define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */ |
89 | #define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */ | 95 | #define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */ |
@@ -127,7 +133,12 @@ struct omap_i2c_dev { | |||
127 | u8 *buf; | 133 | u8 *buf; |
128 | size_t buf_len; | 134 | size_t buf_len; |
129 | struct i2c_adapter adapter; | 135 | struct i2c_adapter adapter; |
136 | u8 fifo_size; /* use as flag and value | ||
137 | * fifo_size==0 implies no fifo | ||
138 | * if set, should be trsh+1 | ||
139 | */ | ||
130 | unsigned rev1:1; | 140 | unsigned rev1:1; |
141 | unsigned b_hw:1; /* bad h/w fixes */ | ||
131 | unsigned idle:1; | 142 | unsigned idle:1; |
132 | u16 iestate; /* Saved interrupt register */ | 143 | u16 iestate; /* Saved interrupt register */ |
133 | }; | 144 | }; |
@@ -297,6 +308,14 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | |||
297 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); | 308 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); |
298 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); | 309 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); |
299 | 310 | ||
311 | if (dev->fifo_size) | ||
312 | /* Note: setup required fifo size - 1 */ | ||
313 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, | ||
314 | (dev->fifo_size - 1) << 8 | /* RTRSH */ | ||
315 | OMAP_I2C_BUF_RXFIF_CLR | | ||
316 | (dev->fifo_size - 1) | /* XTRSH */ | ||
317 | OMAP_I2C_BUF_TXFIF_CLR); | ||
318 | |||
300 | /* Take the I2C module out of reset: */ | 319 | /* Take the I2C module out of reset: */ |
301 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); | 320 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); |
302 | 321 | ||
@@ -304,7 +323,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | |||
304 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, | 323 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, |
305 | (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | | 324 | (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | |
306 | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | | 325 | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | |
307 | OMAP_I2C_IE_AL)); | 326 | OMAP_I2C_IE_AL) | ((dev->fifo_size) ? |
327 | (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0)); | ||
308 | return 0; | 328 | return 0; |
309 | } | 329 | } |
310 | 330 | ||
@@ -351,6 +371,11 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, | |||
351 | 371 | ||
352 | omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); | 372 | omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); |
353 | 373 | ||
374 | /* Clear the FIFO Buffers */ | ||
375 | w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); | ||
376 | w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; | ||
377 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); | ||
378 | |||
354 | init_completion(&dev->cmd_complete); | 379 | init_completion(&dev->cmd_complete); |
355 | dev->cmd_err = 0; | 380 | dev->cmd_err = 0; |
356 | 381 | ||
@@ -358,17 +383,40 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, | |||
358 | 383 | ||
359 | /* High speed configuration */ | 384 | /* High speed configuration */ |
360 | if (dev->speed > 400) | 385 | if (dev->speed > 400) |
361 | w |= OMAP_I2C_CON_OPMODE; | 386 | w |= OMAP_I2C_CON_OPMODE_HS; |
362 | 387 | ||
363 | if (msg->flags & I2C_M_TEN) | 388 | if (msg->flags & I2C_M_TEN) |
364 | w |= OMAP_I2C_CON_XA; | 389 | w |= OMAP_I2C_CON_XA; |
365 | if (!(msg->flags & I2C_M_RD)) | 390 | if (!(msg->flags & I2C_M_RD)) |
366 | w |= OMAP_I2C_CON_TRX; | 391 | w |= OMAP_I2C_CON_TRX; |
367 | if (stop) | 392 | if (!dev->b_hw && stop) |
368 | w |= OMAP_I2C_CON_STP; | 393 | w |= OMAP_I2C_CON_STP; |
369 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); | 394 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); |
370 | 395 | ||
371 | /* | 396 | /* |
397 | * Don't write stt and stp together on some hardware. | ||
398 | */ | ||
399 | if (dev->b_hw && stop) { | ||
400 | unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; | ||
401 | u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); | ||
402 | while (con & OMAP_I2C_CON_STT) { | ||
403 | con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); | ||
404 | |||
405 | /* Let the user know if i2c is in a bad state */ | ||
406 | if (time_after(jiffies, delay)) { | ||
407 | dev_err(dev->dev, "controller timed out " | ||
408 | "waiting for start condition to finish\n"); | ||
409 | return -ETIMEDOUT; | ||
410 | } | ||
411 | cpu_relax(); | ||
412 | } | ||
413 | |||
414 | w |= OMAP_I2C_CON_STP; | ||
415 | w &= ~OMAP_I2C_CON_STT; | ||
416 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); | ||
417 | } | ||
418 | |||
419 | /* | ||
372 | * REVISIT: We should abort the transfer on signals, but the bus goes | 420 | * REVISIT: We should abort the transfer on signals, but the bus goes |
373 | * into arbitration and we're currently unable to recover from it. | 421 | * into arbitration and we're currently unable to recover from it. |
374 | */ | 422 | */ |
@@ -516,7 +564,7 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
516 | struct omap_i2c_dev *dev = dev_id; | 564 | struct omap_i2c_dev *dev = dev_id; |
517 | u16 bits; | 565 | u16 bits; |
518 | u16 stat, w; | 566 | u16 stat, w; |
519 | int count = 0; | 567 | int err, count = 0; |
520 | 568 | ||
521 | if (dev->idle) | 569 | if (dev->idle) |
522 | return IRQ_NONE; | 570 | return IRQ_NONE; |
@@ -531,39 +579,94 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
531 | 579 | ||
532 | omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); | 580 | omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); |
533 | 581 | ||
534 | if (stat & OMAP_I2C_STAT_ARDY) { | 582 | err = 0; |
535 | omap_i2c_complete_cmd(dev, 0); | 583 | if (stat & OMAP_I2C_STAT_NACK) { |
536 | continue; | 584 | err |= OMAP_I2C_STAT_NACK; |
585 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, | ||
586 | OMAP_I2C_CON_STP); | ||
537 | } | 587 | } |
538 | if (stat & OMAP_I2C_STAT_RRDY) { | 588 | if (stat & OMAP_I2C_STAT_AL) { |
539 | w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); | 589 | dev_err(dev->dev, "Arbitration lost\n"); |
540 | if (dev->buf_len) { | 590 | err |= OMAP_I2C_STAT_AL; |
541 | *dev->buf++ = w; | 591 | } |
542 | dev->buf_len--; | 592 | if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | |
593 | OMAP_I2C_STAT_AL)) | ||
594 | omap_i2c_complete_cmd(dev, err); | ||
595 | if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { | ||
596 | u8 num_bytes = 1; | ||
597 | if (dev->fifo_size) { | ||
598 | if (stat & OMAP_I2C_STAT_RRDY) | ||
599 | num_bytes = dev->fifo_size; | ||
600 | else | ||
601 | num_bytes = omap_i2c_read_reg(dev, | ||
602 | OMAP_I2C_BUFSTAT_REG); | ||
603 | } | ||
604 | while (num_bytes) { | ||
605 | num_bytes--; | ||
606 | w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); | ||
543 | if (dev->buf_len) { | 607 | if (dev->buf_len) { |
544 | *dev->buf++ = w >> 8; | 608 | *dev->buf++ = w; |
545 | dev->buf_len--; | 609 | dev->buf_len--; |
610 | /* Data reg from 2430 is 8 bit wide */ | ||
611 | if (!cpu_is_omap2430()) { | ||
612 | if (dev->buf_len) { | ||
613 | *dev->buf++ = w >> 8; | ||
614 | dev->buf_len--; | ||
615 | } | ||
616 | } | ||
617 | } else { | ||
618 | if (stat & OMAP_I2C_STAT_RRDY) | ||
619 | dev_err(dev->dev, | ||
620 | "RRDY IRQ while no data" | ||
621 | " requested\n"); | ||
622 | if (stat & OMAP_I2C_STAT_RDR) | ||
623 | dev_err(dev->dev, | ||
624 | "RDR IRQ while no data" | ||
625 | " requested\n"); | ||
626 | break; | ||
546 | } | 627 | } |
547 | } else | 628 | } |
548 | dev_err(dev->dev, "RRDY IRQ while no data " | 629 | omap_i2c_ack_stat(dev, |
549 | "requested\n"); | 630 | stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); |
550 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); | ||
551 | continue; | 631 | continue; |
552 | } | 632 | } |
553 | if (stat & OMAP_I2C_STAT_XRDY) { | 633 | if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { |
554 | w = 0; | 634 | u8 num_bytes = 1; |
555 | if (dev->buf_len) { | 635 | if (dev->fifo_size) { |
556 | w = *dev->buf++; | 636 | if (stat & OMAP_I2C_STAT_XRDY) |
557 | dev->buf_len--; | 637 | num_bytes = dev->fifo_size; |
638 | else | ||
639 | num_bytes = omap_i2c_read_reg(dev, | ||
640 | OMAP_I2C_BUFSTAT_REG); | ||
641 | } | ||
642 | while (num_bytes) { | ||
643 | num_bytes--; | ||
644 | w = 0; | ||
558 | if (dev->buf_len) { | 645 | if (dev->buf_len) { |
559 | w |= *dev->buf++ << 8; | 646 | w = *dev->buf++; |
560 | dev->buf_len--; | 647 | dev->buf_len--; |
648 | /* Data reg from 2430 is 8 bit wide */ | ||
649 | if (!cpu_is_omap2430()) { | ||
650 | if (dev->buf_len) { | ||
651 | w |= *dev->buf++ << 8; | ||
652 | dev->buf_len--; | ||
653 | } | ||
654 | } | ||
655 | } else { | ||
656 | if (stat & OMAP_I2C_STAT_XRDY) | ||
657 | dev_err(dev->dev, | ||
658 | "XRDY IRQ while no " | ||
659 | "data to send\n"); | ||
660 | if (stat & OMAP_I2C_STAT_XDR) | ||
661 | dev_err(dev->dev, | ||
662 | "XDR IRQ while no " | ||
663 | "data to send\n"); | ||
664 | break; | ||
561 | } | 665 | } |
562 | } else | 666 | omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); |
563 | dev_err(dev->dev, "XRDY IRQ while no " | 667 | } |
564 | "data to send\n"); | 668 | omap_i2c_ack_stat(dev, |
565 | omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); | 669 | stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); |
566 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); | ||
567 | continue; | 670 | continue; |
568 | } | 671 | } |
569 | if (stat & OMAP_I2C_STAT_ROVR) { | 672 | if (stat & OMAP_I2C_STAT_ROVR) { |
@@ -571,18 +674,9 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
571 | dev->cmd_err |= OMAP_I2C_STAT_ROVR; | 674 | dev->cmd_err |= OMAP_I2C_STAT_ROVR; |
572 | } | 675 | } |
573 | if (stat & OMAP_I2C_STAT_XUDF) { | 676 | if (stat & OMAP_I2C_STAT_XUDF) { |
574 | dev_err(dev->dev, "Transmit overflow\n"); | 677 | dev_err(dev->dev, "Transmit underflow\n"); |
575 | dev->cmd_err |= OMAP_I2C_STAT_XUDF; | 678 | dev->cmd_err |= OMAP_I2C_STAT_XUDF; |
576 | } | 679 | } |
577 | if (stat & OMAP_I2C_STAT_NACK) { | ||
578 | omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK); | ||
579 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, | ||
580 | OMAP_I2C_CON_STP); | ||
581 | } | ||
582 | if (stat & OMAP_I2C_STAT_AL) { | ||
583 | dev_err(dev->dev, "Arbitration lost\n"); | ||
584 | omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL); | ||
585 | } | ||
586 | } | 680 | } |
587 | 681 | ||
588 | return count ? IRQ_HANDLED : IRQ_NONE; | 682 | return count ? IRQ_HANDLED : IRQ_NONE; |
@@ -651,6 +745,22 @@ omap_i2c_probe(struct platform_device *pdev) | |||
651 | if (cpu_is_omap15xx()) | 745 | if (cpu_is_omap15xx()) |
652 | dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20; | 746 | dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20; |
653 | 747 | ||
748 | if (cpu_is_omap2430()) { | ||
749 | u16 s; | ||
750 | |||
751 | /* Set up the fifo size - Get total size */ | ||
752 | s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; | ||
753 | dev->fifo_size = 0x8 << s; | ||
754 | |||
755 | /* | ||
756 | * Set up notification threshold as half the total available | ||
757 | * size. This is to ensure that we can handle the status on int | ||
758 | * call back latencies. | ||
759 | */ | ||
760 | dev->fifo_size = (dev->fifo_size / 2); | ||
761 | dev->b_hw = 1; /* Enable hardware fixes */ | ||
762 | } | ||
763 | |||
654 | /* reset ASAP, clearing any IRQs */ | 764 | /* reset ASAP, clearing any IRQs */ |
655 | omap_i2c_init(dev); | 765 | omap_i2c_init(dev); |
656 | 766 | ||