[U-Boot] [PATCH] OMAP24xx I2C: Add support for 'setspeed'

Hannes Petermaier hannes at petermaier.org
Sat Feb 1 20:56:36 CET 2014


supports changing the bus-speed of the OMAP24xx Adapter.
Signed-off-by: Hannes Petermaier <oe5hpm at oevsv.at>
---
  drivers/i2c/omap24xx_i2c.c |  122 
++++++++++++++++++++++++++++----------------
  1 file changed, 77 insertions(+), 45 deletions(-)

diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index c784004..51ceda1 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -32,6 +32,10 @@
   * - Status functions now read irqstatus_raw as per TRM guidelines
   *   (except for OMAP243X and OMAP34XX).
   * - Driver now supports up to I2C5 (OMAP5).
+ *
+ * Copyright (c) 2014 Hannes Petermaier <oe5hpm at oevsv.at>, B&R
+ * - Added support for set_speed
+ *
   */

  #include <common.h>
@@ -53,43 +57,65 @@ static int wait_for_bb(struct i2c_adapter *adap);
  static struct i2c *omap24_get_base(struct i2c_adapter *adap);
  static u16 wait_for_event(struct i2c_adapter *adap);
  static void flush_fifo(struct i2c_adapter *adap);
-
-static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int 
slaveadd)
+static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
  {
-    struct i2c *i2c_base = omap24_get_base(adap);
-    int psc, fsscll, fssclh;
-    int hsscll = 0, hssclh = 0;
-    u32 scll, sclh;
-    int timeout = I2C_TIMEOUT;
+    unsigned int sampleclk, psc;
+    int fsscll, fssclh;

-    /* Only handle standard, fast and high speeds */
-    if ((speed != OMAP_I2C_STANDARD) &&
-        (speed != OMAP_I2C_FAST_MODE) &&
-        (speed != OMAP_I2C_HIGH_SPEED)) {
-        printf("Error : I2C unsupported speed %d\n", speed);
-        return;
-    }
+    speed <<= 1;
+    psc = 0;
+    /* some divisors may cause a precission loss, but shouldn't
+     * be a big thing, because i2c_clk is then allready very slow.
+     */
+    while (psc <= 0xFF) {
+        sampleclk = I2C_IP_CLK / (psc+1);
+
+        fsscll = = sampleclk / speed;
+        fssclh = fsscll;
+        fsscll -= I2C_FASTSPEED_SCLL_TRIM;
+        fssclh -= I2C_FASTSPEED_SCLH_TRIM;
+
+        if (((fsscll > 0) && (fssclh > 0)) &&
+            ((fsscll <= (255-I2C_FASTSPEED_SCLL_TRIM)) &&
+            (fssclh <= (255-I2C_FASTSPEED_SCLH_TRIM)))) {

-    psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
-    psc -= 1;
-    if (psc < I2C_PSC_MIN) {
-        printf("Error : I2C unsupported prescalar %d\n", psc);
-        return;
+            if (pscl)
+                *pscl = fsscll;
+            if (psch)
+                *psch = fssclh;
+
+            return psc;
+        }
+        psc++;
      }
+    return -1;
+}
+static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+    struct i2c *i2c_base = omap24_get_base(adap);
+    int psc, fsscll = 0, fssclh = 0;
+    int hsscll = 0, hssclh = 0;
+    u32 scll = 0, sclh = 0;

-    if (speed == OMAP_I2C_HIGH_SPEED) {
+    if (speed >= OMAP_I2C_HIGH_SPEED) {
          /* High speed */
+        psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
+        psc -= 1;
+        if (psc < I2C_PSC_MIN) {
+            printf("Error : I2C unsupported prescaler %d\n", psc);
+            return -1;
+        }

          /* For first phase of HS mode */
-        fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK /
-            (2 * OMAP_I2C_FAST_MODE);
+        fsscll = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+        fssclh = fsscll;

          fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
          fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
          if (((fsscll < 0) || (fssclh < 0)) ||
              ((fsscll > 255) || (fssclh > 255))) {
              puts("Error : I2C initializing first phase clock\n");
-            return;
+            return -1;
          }

          /* For second phase of HS mode */
@@ -100,7 +126,7 @@ static void omap24_i2c_init(struct i2c_adapter 
*adap, int speed, int slaveadd)
          if (((fsscll < 0) || (fssclh < 0)) ||
              ((fsscll > 255) || (fssclh > 255))) {
              puts("Error : I2C initializing second phase clock\n");
-            return;
+            return -1;
          }

          scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
@@ -108,20 +134,29 @@ static void omap24_i2c_init(struct i2c_adapter 
*adap, int speed, int slaveadd)

      } else {
          /* Standard and fast speed */
-        fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
-
-        fsscll -= I2C_FASTSPEED_SCLL_TRIM;
-        fssclh -= I2C_FASTSPEED_SCLH_TRIM;
-        if (((fsscll < 0) || (fssclh < 0)) ||
-            ((fsscll > 255) || (fssclh > 255))) {
+        psc = omap24_i2c_findpsc(&scll, &sclh, speed);
+        if (0 > psc) {
              puts("Error : I2C initializing clock\n");
-            return;
+            return -1;
          }
-
-        scll = (unsigned int)fsscll;
-        sclh = (unsigned int)fssclh;
      }

+    adap->speed    = speed;
+    adap->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */
+    writew(0, &i2c_base->con);
+    writew(psc, &i2c_base->psc);
+    writew(scll, &i2c_base->scll);
+    writew(sclh, &i2c_base->sclh);
+    writew(I2C_CON_EN, &i2c_base->con);
+    writew(0xFFFF, &i2c_base->stat);    /* clear all pending status */
+
+    return 0;
+}
+static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int 
slaveadd)
+{
+    struct i2c *i2c_base = omap24_get_base(adap);
+    int timeout = I2C_TIMEOUT;
+
      if (readw(&i2c_base->con) & I2C_CON_EN) {
          writew(0, &i2c_base->con);
          udelay(50000);
@@ -139,14 +174,11 @@ static void omap24_i2c_init(struct i2c_adapter 
*adap, int speed, int slaveadd)
          udelay(1000);
      }

-    writew(0, &i2c_base->con);
-    writew(psc, &i2c_base->psc);
-    writew(scll, &i2c_base->scll);
-    writew(sclh, &i2c_base->sclh);
+    omap24_i2c_setspeed(adap, speed);

      /* own address */
      writew(slaveadd, &i2c_base->oa);
-    writew(I2C_CON_EN, &i2c_base->con);
+
  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
      /*
       * Have to enable interrupts for OMAP2/3, these IPs don't have
@@ -220,8 +252,8 @@ static int omap24_i2c_probe(struct i2c_adapter 
*adap, uchar chip)

      /* Check for ACK (!NAK) */
      if (!(status & I2C_STAT_NACK)) {
-        res = 0;            /* Device found */
-        udelay(I2C_WAIT);        /* Required by AM335X in SPL */
+        res = 0;                /* Device found */
+        udelay(adap->waitdelay);/* Required by AM335X in SPL */
          /* Abort transfer (force idle state) */
          writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
          udelay(1000);
@@ -490,7 +522,7 @@ static int wait_for_bb(struct i2c_adapter *adap)
          I2C_STAT_BB) && timeout--) {
  #endif
          writew(stat, &i2c_base->stat);
-        udelay(I2C_WAIT);
+        udelay(adap->waitdelay);
      }

      if (timeout <= 0) {
@@ -513,7 +545,7 @@ static u16 wait_for_event(struct i2c_adapter *adap)
      int timeout = I2C_TIMEOUT;

      do {
-        udelay(I2C_WAIT);
+        udelay(adap->waitdelay);
  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
          status = readw(&i2c_base->stat);
  #else
@@ -580,12 +612,12 @@ static struct i2c *omap24_get_base(struct 
i2c_adapter *adap)
  #endif

  U_BOOT_I2C_ADAP_COMPLETE(omap24_0, omap24_i2c_init, omap24_i2c_probe,
-             omap24_i2c_read, omap24_i2c_write, NULL,
+             omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
               CONFIG_SYS_OMAP24_I2C_SPEED,
               CONFIG_SYS_OMAP24_I2C_SLAVE,
               0)
  U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe,
-             omap24_i2c_read, omap24_i2c_write, NULL,
+             omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
               CONFIG_SYS_OMAP24_I2C_SPEED1,
               CONFIG_SYS_OMAP24_I2C_SLAVE1,
               1)
-- 
1.7.9.5



More information about the U-Boot mailing list