summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorAlexander Kochetkov <al.kochet@gmail.com>2014-11-22 14:47:12 -0500
committerWolfram Sang <wsa@the-dreams.de>2014-11-23 11:27:47 -0500
commit0f5768bf894f853c21e5f336b5f495599172f39b (patch)
tree3434977e24f43ae4d32c07706864900bed8fd55c /drivers/i2c
parent9fd6ada84fd29c8115f2781b48a6ae7c8c4debe2 (diff)
i2c: omap: implement workaround for handling invalid BB-bit values
In a multimaster environment, after IP software reset, BB-bit value doesn't correspond to the current bus state. It may happen what BB-bit will be 0, while the bus is busy due to another I2C master activity. Any transfer started when BB=0 and bus is busy wouldn't be completed by IP and results in controller timeout. More over, in some cases IP could interrupt another master's transfer and corrupt data on wire. The commit implement method allowing to prevent IP from entering into "controller timeout" state and from "data corruption" state. The one drawback is the need to wait for 10ms before the first transfer. Tested on Beagleboard XM C. Tested on BBB and AM437x Starter Kit by Felipe Balbi. Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com> Tested-by: Felipe Balbi <balbi@ti.com> Reviewed-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-omap.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 5e79c0d294cd..4426e9970e8f 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -54,6 +54,9 @@
54/* timeout for pm runtime autosuspend */ 54/* timeout for pm runtime autosuspend */
55#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ 55#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */
56 56
57/* timeout for making decision on bus free status */
58#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10))
59
57/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ 60/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
58enum { 61enum {
59 OMAP_I2C_REV_REG = 0, 62 OMAP_I2C_REV_REG = 0,
@@ -206,6 +209,9 @@ struct omap_i2c_dev {
206 */ 209 */
207 u32 rev; 210 u32 rev;
208 unsigned b_hw:1; /* bad h/w fixes */ 211 unsigned b_hw:1; /* bad h/w fixes */
212 unsigned bb_valid:1; /* true when BB-bit reflects
213 * the I2C bus state
214 */
209 unsigned receiver:1; /* true when we're in receiver mode */ 215 unsigned receiver:1; /* true when we're in receiver mode */
210 u16 iestate; /* Saved interrupt register */ 216 u16 iestate; /* Saved interrupt register */
211 u16 pscstate; 217 u16 pscstate;
@@ -332,7 +338,10 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev)
332 /* SYSC register is cleared by the reset; rewrite it */ 338 /* SYSC register is cleared by the reset; rewrite it */
333 omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); 339 omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc);
334 340
341 /* Schedule I2C-bus monitoring on the next transfer */
342 dev->bb_valid = 0;
335 } 343 }
344
336 return 0; 345 return 0;
337} 346}
338 347
@@ -445,6 +454,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
445 dev->scllstate = scll; 454 dev->scllstate = scll;
446 dev->sclhstate = sclh; 455 dev->sclhstate = sclh;
447 456
457 if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
458 /* Not implemented */
459 dev->bb_valid = 1;
460 }
461
448 __omap_i2c_init(dev); 462 __omap_i2c_init(dev);
449 463
450 return 0; 464 return 0;
@@ -469,6 +483,91 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
469 return 0; 483 return 0;
470} 484}
471 485
486/*
487 * Wait while BB-bit doesn't reflect the I2C bus state
488 *
489 * In a multimaster environment, after IP software reset, BB-bit value doesn't
490 * correspond to the current bus state. It may happen what BB-bit will be 0,
491 * while the bus is busy due to another I2C master activity.
492 * Here are BB-bit values after reset:
493 * SDA SCL BB NOTES
494 * 0 0 0 1, 2
495 * 1 0 0 1, 2
496 * 0 1 1
497 * 1 1 0 3
498 * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START)
499 * combinations on the bus, it set BB-bit to 1.
500 * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus,
501 * it set BB-bit to 0 and BF to 1.
502 * BB and BF bits correctly tracks the bus state while IP is suspended
503 * BB bit became valid on the next FCLK clock after CON_EN bit set
504 *
505 * NOTES:
506 * 1. Any transfer started when BB=0 and bus is busy wouldn't be
507 * completed by IP and results in controller timeout.
508 * 2. Any transfer started when BB=0 and SCL=0 results in IP
509 * starting to drive SDA low. In that case IP corrupt data
510 * on the bus.
511 * 3. Any transfer started in the middle of another master's transfer
512 * results in unpredictable results and data corruption
513 */
514static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev)
515{
516 unsigned long bus_free_timeout = 0;
517 unsigned long timeout;
518 int bus_free = 0;
519 u16 stat, systest;
520
521 if (dev->bb_valid)
522 return 0;
523
524 timeout = jiffies + OMAP_I2C_TIMEOUT;
525 while (1) {
526 stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
527 /*
528 * We will see BB or BF event in a case IP had detected any
529 * activity on the I2C bus. Now IP correctly tracks the bus
530 * state. BB-bit value is valid.
531 */
532 if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF))
533 break;
534
535 /*
536 * Otherwise, we must look signals on the bus to make
537 * the right decision.
538 */
539 systest = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
540 if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
541 (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
542 if (!bus_free) {
543 bus_free_timeout = jiffies +
544 OMAP_I2C_BUS_FREE_TIMEOUT;
545 bus_free = 1;
546 }
547
548 /*
549 * SDA and SCL lines was high for 10 ms without bus
550 * activity detected. The bus is free. Consider
551 * BB-bit value is valid.
552 */
553 if (time_after(jiffies, bus_free_timeout))
554 break;
555 } else {
556 bus_free = 0;
557 }
558
559 if (time_after(jiffies, timeout)) {
560 dev_warn(dev->dev, "timeout waiting for bus ready\n");
561 return -ETIMEDOUT;
562 }
563
564 msleep(1);
565 }
566
567 dev->bb_valid = 1;
568 return 0;
569}
570
472static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) 571static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
473{ 572{
474 u16 buf; 573 u16 buf;
@@ -639,6 +738,10 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
639 if (r < 0) 738 if (r < 0)
640 goto out; 739 goto out;
641 740
741 r = omap_i2c_wait_for_bb_valid(dev);
742 if (r < 0)
743 goto out;
744
642 r = omap_i2c_wait_for_bb(dev); 745 r = omap_i2c_wait_for_bb(dev);
643 if (r < 0) 746 if (r < 0)
644 goto out; 747 goto out;