unsigned int            rx_fifo_depth;
 };
 
+static u32
+i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+{
+       /*
+        * DesignWare I2C core doesn't seem to have solid strategy to meet
+        * the tHD;STA timing spec.  Configuring _HCNT based on tHIGH spec
+        * will result in violation of the tHD;STA spec.
+        */
+       if (cond)
+               /*
+                * Conditional expression:
+                *
+                *   IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+                *
+                * This is based on the DW manuals, and represents an ideal
+                * configuration.  The resulting I2C bus speed will be
+                * faster than any of the others.
+                *
+                * If your hardware is free from tHD;STA issue, try this one.
+                */
+               return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+       else
+               /*
+                * Conditional expression:
+                *
+                *   IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+                *
+                * This is just experimental rule; the tHD;STA period turned
+                * out to be proportinal to (_HCNT + 3).  With this setting,
+                * we could meet both tHIGH and tHD;STA timing specs.
+                *
+                * If unsure, you'd better to take this alternative.
+                *
+                * The reason why we need to take into account "tf" here,
+                * is the same as described in i2c_dw_scl_lcnt().
+                */
+               return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+}
+
+static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+{
+       /*
+        * Conditional expression:
+        *
+        *   IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+        *
+        * DW I2C core starts counting the SCL CNTs for the LOW period
+        * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+        * In order to meet the tLOW timing spec, we need to take into
+        * account the fall time of SCL signal (tf).  Default tf value
+        * should be 0.3 us, for safety.
+        */
+       return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+}
+
 /**
  * i2c_dw_init() - initialize the designware i2c master hardware
  * @dev: device private data
 static void i2c_dw_init(struct dw_i2c_dev *dev)
 {
        u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
-       u32 ic_con;
+       u32 ic_con, hcnt, lcnt;
 
        /* Disable the adapter */
        writel(0, dev->base + DW_IC_ENABLE);
 
        /* set standard and fast speed deviders for high/low periods */
-       writel((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */
-                       dev->base + DW_IC_SS_SCL_HCNT);
-       writel((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */
-                       dev->base + DW_IC_SS_SCL_LCNT);
-       writel((input_clock_khz *  6 / 10000)+1, /* fast speed high, 0.6us */
-                       dev->base + DW_IC_FS_SCL_HCNT);
-       writel((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */
-                       dev->base + DW_IC_FS_SCL_LCNT);
+
+       /* Standard-mode */
+       hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+                               40,     /* tHD;STA = tHIGH = 4.0 us */
+                               3,      /* tf = 0.3 us */
+                               0,      /* 0: DW default, 1: Ideal */
+                               0);     /* No offset */
+       lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+                               47,     /* tLOW = 4.7 us */
+                               3,      /* tf = 0.3 us */
+                               0);     /* No offset */
+       writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT);
+       writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT);
+       dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+       /* Fast-mode */
+       hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+                               6,      /* tHD;STA = tHIGH = 0.6 us */
+                               3,      /* tf = 0.3 us */
+                               0,      /* 0: DW default, 1: Ideal */
+                               0);     /* No offset */
+       lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+                               13,     /* tLOW = 1.3 us */
+                               3,      /* tf = 0.3 us */
+                               0);     /* No offset */
+       writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT);
+       writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT);
+       dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
 
        /* configure the i2c master */
        ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |