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 | |
| 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>
| -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 | ||
