i2c: aspeed: Retain delay/setup/hold values when configuring bus frequency
authorAndrew Jeffery <andrew@aj.id.au>
Tue, 15 Aug 2017 07:21:02 +0000 (16:51 +0930)
committerWolfram Sang <wsa@the-dreams.de>
Mon, 28 Aug 2017 16:05:03 +0000 (18:05 +0200)
In addition to the base, low and high clock configuration, the AC timing
register #1 on the AST2400 houses fields controlling:

1. tBUF: Minimum delay between Stop and Start conditions
2. tHDSTA: Hold time for the Start condition
3. tACST: Setup time for Start and Stop conditions, and hold time for the
   Repeated Start condition

These values are defined in hardware on the AST2500 and therefore don't
need to be set.

aspeed_i2c_init_clk() was performing a direct write of the generated
clock values rather than a read/mask/modify/update sequence to retain
tBUF, tHDSTA and tACST, and therefore cleared the tBUF, tHDSTA and tACST
fields on the AST2400. This resulted in a delay/setup/hold time of 1
base clock, which in some configurations is not enough for some devices
(e.g. the MAX31785 fan controller, with an APB of 48MHz and a desired
bus speed of 100kHz).

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Brendan Higgins <brendanhiggins@google.com>
Tested-by: Brendan Higgins <brendanhiggins@google.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-aspeed.c

index 60afab8664948440e1709d63923ea2c66d86b645..645e0076f723777ca54ba5ceb9052acf02a67d86 100644 (file)
@@ -53,6 +53,9 @@
 #define ASPEED_I2CD_MASTER_EN                          BIT(0)
 
 /* 0x04 : I2CD Clock and AC Timing Control Register #1 */
+#define ASPEED_I2CD_TIME_TBUF_MASK                     GENMASK(31, 28)
+#define ASPEED_I2CD_TIME_THDSTA_MASK                   GENMASK(27, 24)
+#define ASPEED_I2CD_TIME_TACST_MASK                    GENMASK(23, 20)
 #define ASPEED_I2CD_TIME_SCL_HIGH_SHIFT                        16
 #define ASPEED_I2CD_TIME_SCL_HIGH_MASK                 GENMASK(19, 16)
 #define ASPEED_I2CD_TIME_SCL_LOW_SHIFT                 12
@@ -743,7 +746,11 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
        u32 divisor, clk_reg_val;
 
        divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency);
-       clk_reg_val = bus->get_clk_reg_val(divisor);
+       clk_reg_val = readl(bus->base + ASPEED_I2C_AC_TIMING_REG1);
+       clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
+                       ASPEED_I2CD_TIME_THDSTA_MASK |
+                       ASPEED_I2CD_TIME_TACST_MASK);
+       clk_reg_val |= bus->get_clk_reg_val(divisor);
        writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
        writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);