aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2012-11-15 07:13:32 -0500
committerWolfram Sang <w.sang@pengutronix.de>2012-11-16 07:09:33 -0500
commitfe724bf9f023384eb14431c0e49ec46017ba8e30 (patch)
tree8d860dd007fdf966375260697a1f5a1e6ed5400b
parent0da2e7768b4c2b4dbbb148ebe1606b6b4698fca2 (diff)
i2c: s3c2410: use exponential back off while polling for bus idle
Usually, the i2c controller has finished emitting the i2c STOP before the driver reaches the bus idle polling loop. Optimize for this most common case by reading IICSTAT first and potentially skipping the loop. If the cpu is faster than the hardware, we wait for bus idle in a polling loop. However, since the duration of one iteration of the loop is dependent on cpu freq, and this i2c IP is used on many different systems, use a time based loop timeout (5 ms). We would like very low latencies to detect bus idle for the normal 'fast' case. However, if a device is slow to release the bus for some reason, it could hold off the STOP generation for up to several milliseconds. Rapidly polling for bus idle would seriously load the CPU while waiting for it to release the bus. So, use a partial exponential backoff as a compromise between idle detection latency and cpu load. Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index a44e2130d3e0..dd93d3d6510a 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -50,6 +50,9 @@
50#define QUIRK_HDMIPHY (1 << 1) 50#define QUIRK_HDMIPHY (1 << 1)
51#define QUIRK_NO_GPIO (1 << 2) 51#define QUIRK_NO_GPIO (1 << 2)
52 52
53/* Max time to wait for bus to become idle after a xfer (in us) */
54#define S3C2410_IDLE_TIMEOUT 5000
55
53/* i2c controller state */ 56/* i2c controller state */
54enum s3c24xx_i2c_state { 57enum s3c24xx_i2c_state {
55 STATE_IDLE, 58 STATE_IDLE,
@@ -557,6 +560,48 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
557 return -ETIMEDOUT; 560 return -ETIMEDOUT;
558} 561}
559 562
563/* s3c24xx_i2c_wait_idle
564 *
565 * wait for the i2c bus to become idle.
566*/
567
568static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
569{
570 unsigned long iicstat;
571 ktime_t start, now;
572 unsigned long delay;
573
574 /* ensure the stop has been through the bus */
575
576 dev_dbg(i2c->dev, "waiting for bus idle\n");
577
578 start = now = ktime_get();
579
580 /*
581 * Most of the time, the bus is already idle within a few usec of the
582 * end of a transaction. However, really slow i2c devices can stretch
583 * the clock, delaying STOP generation.
584 *
585 * As a compromise between idle detection latency for the normal, fast
586 * case, and system load in the slow device case, use an exponential
587 * back off in the polling loop, up to 1/10th of the total timeout,
588 * then continue to poll at a constant rate up to the timeout.
589 */
590 iicstat = readl(i2c->regs + S3C2410_IICSTAT);
591 delay = 1;
592 while ((iicstat & S3C2410_IICSTAT_START) &&
593 ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) {
594 usleep_range(delay, 2 * delay);
595 if (delay < S3C2410_IDLE_TIMEOUT / 10)
596 delay <<= 1;
597 now = ktime_get();
598 iicstat = readl(i2c->regs + S3C2410_IICSTAT);
599 }
600
601 if (iicstat & S3C2410_IICSTAT_START)
602 dev_warn(i2c->dev, "timeout waiting for bus idle\n");
603}
604
560/* s3c24xx_i2c_doxfer 605/* s3c24xx_i2c_doxfer
561 * 606 *
562 * this starts an i2c transfer 607 * this starts an i2c transfer
@@ -565,8 +610,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
565static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, 610static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
566 struct i2c_msg *msgs, int num) 611 struct i2c_msg *msgs, int num)
567{ 612{
568 unsigned long iicstat, timeout; 613 unsigned long timeout;
569 int spins = 20;
570 int ret; 614 int ret;
571 615
572 if (i2c->suspended) 616 if (i2c->suspended)
@@ -604,24 +648,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
604 if (i2c->quirks & QUIRK_HDMIPHY) 648 if (i2c->quirks & QUIRK_HDMIPHY)
605 goto out; 649 goto out;
606 650
607 /* ensure the stop has been through the bus */ 651 s3c24xx_i2c_wait_idle(i2c);
608
609 dev_dbg(i2c->dev, "waiting for bus idle\n");
610
611 /* first, try busy waiting briefly */
612 do {
613 cpu_relax();
614 iicstat = readl(i2c->regs + S3C2410_IICSTAT);
615 } while ((iicstat & S3C2410_IICSTAT_START) && --spins);
616
617 /* if that timed out sleep */
618 if (!spins) {
619 msleep(1);
620 iicstat = readl(i2c->regs + S3C2410_IICSTAT);
621 }
622
623 if (iicstat & S3C2410_IICSTAT_START)
624 dev_warn(i2c->dev, "timeout waiting for bus idle\n");
625 652
626 out: 653 out:
627 return ret; 654 return ret;