From e3b93dcee88ff2c782790f8ad556d12f142efc4e Mon Sep 17 00:00:00 2001 From: Jun Chen Date: Wed, 5 Jun 2019 15:23:16 +0800 Subject: [PATCH 1/5] i2c: designware_i2c: Restore enable state after set speed Before calling __dw_i2c_set_bus_speed(), the I2C could already be set as ether enable or disable, we should restore the original setting instead of enable i2c anyway. This patch fix a bug happened in init function: __dw_i2c_init(){ /* Disable i2c */ ... __dw_i2c_set_bus_speed(i2c_base, NULL, speed); writel(slaveaddr, &i2c_base->ic_sar); /* Enable i2c */ } In this case, enable i2c inside __dw_i2c_set_bus_speed() function will cause ic_sar write fail. Signed-off-by: Jun Chen --- drivers/i2c/designware_i2c.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 9ccc2411a6..d11d47d246 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -82,6 +82,7 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, { unsigned int cntl; unsigned int hcnt, lcnt; + unsigned int ena; int i2c_spd; if (speed >= I2C_MAX_SPEED) @@ -91,6 +92,9 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, else i2c_spd = IC_SPEED_MODE_STANDARD; + /* Get enable setting for restore later */ + ena = readl(&i2c_base->ic_enable) & IC_ENABLE_0B; + /* to set speed cltr must be disabled */ dw_i2c_enable(i2c_base, false); @@ -146,8 +150,9 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, if (scl_sda_cfg) writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold); - /* Enable back i2c now speed set */ - dw_i2c_enable(i2c_base, true); + /* Restore back i2c now speed set */ + if (ena == IC_ENABLE_0B) + dw_i2c_enable(i2c_base, true); return 0; } From 2d1e879c79f922a2d4c18c09c9363b76ce9e5643 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Wed, 12 Jun 2019 09:48:04 +0800 Subject: [PATCH 2/5] i2c: designware: Get clock rate from clock DM Get clock rate from clock DM if CONFIG_CLK is enabled. Otherwise, uses IC_CLK define. Signed-off-by: Ley Foon Tan Acked-by: Marek Vasut --- drivers/i2c/designware_i2c.c | 55 +++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index d11d47d246..6daa90e744 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -4,6 +4,7 @@ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. */ +#include #include #include #include @@ -35,6 +36,9 @@ struct dw_i2c { struct i2c_regs *regs; struct dw_scl_sda_cfg *scl_sda_cfg; struct reset_ctl_bulk resets; +#if CONFIG_IS_ENABLED(CLK) + struct clk clk; +#endif }; #ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED @@ -78,7 +82,8 @@ static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) */ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, struct dw_scl_sda_cfg *scl_sda_cfg, - unsigned int speed) + unsigned int speed, + unsigned int bus_mhz) { unsigned int cntl; unsigned int hcnt, lcnt; @@ -108,8 +113,8 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, hcnt = scl_sda_cfg->fs_hcnt; lcnt = scl_sda_cfg->fs_lcnt; } else { - hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; - lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; + hcnt = (bus_mhz * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (bus_mhz * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; } writel(hcnt, &i2c_base->ic_hs_scl_hcnt); writel(lcnt, &i2c_base->ic_hs_scl_lcnt); @@ -122,8 +127,8 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, hcnt = scl_sda_cfg->ss_hcnt; lcnt = scl_sda_cfg->ss_lcnt; } else { - hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; - lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; + hcnt = (bus_mhz * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (bus_mhz * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; } writel(hcnt, &i2c_base->ic_ss_scl_hcnt); writel(lcnt, &i2c_base->ic_ss_scl_lcnt); @@ -136,8 +141,8 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base, hcnt = scl_sda_cfg->fs_hcnt; lcnt = scl_sda_cfg->fs_lcnt; } else { - hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; - lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; + hcnt = (bus_mhz * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; + lcnt = (bus_mhz * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; } writel(hcnt, &i2c_base->ic_fs_scl_hcnt); writel(lcnt, &i2c_base->ic_fs_scl_lcnt); @@ -393,7 +398,7 @@ static int __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr) writel(IC_TX_TL, &i2c_base->ic_tx_tl); writel(IC_STOP_DET, &i2c_base->ic_intr_mask); #ifndef CONFIG_DM_I2C - __dw_i2c_set_bus_speed(i2c_base, NULL, speed); + __dw_i2c_set_bus_speed(i2c_base, NULL, speed, IC_CLK); writel(slaveaddr, &i2c_base->ic_sar); #endif @@ -438,7 +443,7 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, unsigned int speed) { adap->speed = speed; - return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed); + return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed, IC_CLK); } static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) @@ -528,8 +533,20 @@ static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct dw_i2c *i2c = dev_get_priv(bus); + ulong rate; - return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed); +#if CONFIG_IS_ENABLED(CLK) + rate = clk_get_rate(&i2c->clk); + if (IS_ERR_VALUE(rate)) + return -EINVAL; + + /* Convert to MHz */ + rate /= 1000000; +#else + rate = IC_CLK; +#endif + return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed, + rate); } static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, @@ -573,6 +590,19 @@ static int designware_i2c_probe(struct udevice *bus) else reset_deassert_bulk(&priv->resets); +#if CONFIG_IS_ENABLED(CLK) + ret = clk_get_by_index(bus, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + clk_free(&priv->clk); + dev_err(bus, "failed to enable clock\n"); + return ret; + } +#endif + return __dw_i2c_init(priv->regs, 0, 0); } @@ -580,6 +610,11 @@ static int designware_i2c_remove(struct udevice *dev) { struct dw_i2c *priv = dev_get_priv(dev); +#if CONFIG_IS_ENABLED(CLK) + clk_disable(&priv->clk); + clk_free(&priv->clk); +#endif + return reset_release_bulk(&priv->resets); } From 5324e8ef6c3d6b6183b3aadeadeeb7822b4fd68a Mon Sep 17 00:00:00 2001 From: Melin Tomas Date: Fri, 28 Jun 2019 12:08:31 +0000 Subject: [PATCH 3/5] xilinx_xiic: Fix fill tx fifo loop Comparison should be against the actual message length, not loop index. len is used for stopping while loop, pos is position in message. stop should be sent when entire message is sent, not when len and pos meet. hs: fixed DOS line endings Signed-off-by: Tomas Melin --- drivers/i2c/xilinx_xiic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/xilinx_xiic.c b/drivers/i2c/xilinx_xiic.c index 83114ed510..e4ca0ab936 100644 --- a/drivers/i2c/xilinx_xiic.c +++ b/drivers/i2c/xilinx_xiic.c @@ -149,7 +149,7 @@ static void xiic_fill_tx_fifo(struct xilinx_xiic_priv *priv, while (len--) { u16 data = msg->buf[pos++]; - if (pos == len && nmsgs == 1) { + if ((msg->len - pos == 0) && nmsgs == 1) { /* last message in transfer -> STOP */ data |= XIIC_TX_DYN_STOP_MASK; } From d3826fb052af9e6df22abaefb1b0c7496e469f9e Mon Sep 17 00:00:00 2001 From: Melin Tomas Date: Fri, 28 Jun 2019 12:08:40 +0000 Subject: [PATCH 4/5] xilinx_xiic: Fix transfer initialisation Prior to starting a new transfer, conditionally wait for bus to not be busy. Reinitialise controller as otherwise operation is not stable. For reference, see linux kernel commit 9656eeebf3f1 ("i2c: Revert i2c: xiic: Do not reset controller before every transfer") hs: Fixed DOS line endings added missing '\n' Fixed git commit description style Signed-off-by: Tomas Melin --- drivers/i2c/xilinx_xiic.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/i2c/xilinx_xiic.c b/drivers/i2c/xilinx_xiic.c index e4ca0ab936..5ce0f869c7 100644 --- a/drivers/i2c/xilinx_xiic.c +++ b/drivers/i2c/xilinx_xiic.c @@ -266,8 +266,20 @@ static void xiic_reinit(struct xilinx_xiic_priv *priv) static int xilinx_xiic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) { + struct xilinx_xiic_priv *priv = dev_get_priv(dev); int ret = 0; + ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET, + XIIC_SR_BUS_BUSY_MASK, false, 1000, true); + + if (ret == -ETIMEDOUT) + dev_err(dev, "timeout waiting for bus not busy condition\n"); + + if (ret) + return ret; + + xiic_reinit(priv); + for (; nmsgs > 0; nmsgs--, msg++) { if (msg->flags & I2C_M_RD) ret = xilinx_xiic_read_common(dev, msg, nmsgs); From ef6c26d338a168110b7688b07e319ff46c73748d Mon Sep 17 00:00:00 2001 From: Chuanhua Han Date: Mon, 8 Jul 2019 11:45:25 +0800 Subject: [PATCH 5/5] rtc: pcf2127: Fixed bug with rtc settings and getting error time The previous pcf2127 RTC chip could not read and set the correct time. When reading the data of internal registers, the read address was the value of register plus 1. This is because this chip requires the host to send a stop signal after setting the register address and before reading the register data. This patch sets the register address using dm_i2c_write and reads the register data using the original dm_i2c_xfer in order to generate a stop signal after the register address is set, and fixes the bug of the original read and write time. Signed-off-by: Biwen Li Signed-off-by: Chuanhua Han Reviewed-by: Lukasz Majewski Reviewed-by: Heiko Schocher --- drivers/rtc/pcf2127.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/pcf2127.c b/drivers/rtc/pcf2127.c index dcf0340b4d..f6953505a5 100644 --- a/drivers/rtc/pcf2127.c +++ b/drivers/rtc/pcf2127.c @@ -22,14 +22,32 @@ #define PCF2127_REG_MO 0x08 #define PCF2127_REG_YR 0x09 +static int pcf2127_read_reg(struct udevice *dev, uint offset, + u8 *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + struct i2c_msg msg; + int ret; + + /* Set the address of the start register to be read */ + ret = dm_i2c_write(dev, offset, NULL, 0); + if (ret < 0) + return ret; + + /* Read register's data */ + msg.addr = chip->chip_addr; + msg.flags |= I2C_M_RD; + msg.len = len; + msg.buf = buffer; + + return dm_i2c_xfer(dev, &msg, 1); +} + static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm) { - uchar buf[8]; + uchar buf[7] = {0}; int i = 0, ret; - /* start register address */ - buf[i++] = PCF2127_REG_SC; - /* hours, minutes and seconds */ buf[i++] = bin2bcd(tm->tm_sec); buf[i++] = bin2bcd(tm->tm_min); @@ -44,7 +62,7 @@ static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm) buf[i++] = bin2bcd(tm->tm_year % 100); /* write register's data */ - ret = dm_i2c_write(dev, PCF2127_REG_CTRL1, buf, sizeof(buf)); + ret = dm_i2c_write(dev, PCF2127_REG_SC, buf, i); return ret; } @@ -54,10 +72,7 @@ static int pcf2127_rtc_get(struct udevice *dev, struct rtc_time *tm) int ret = 0; uchar buf[10] = { PCF2127_REG_CTRL1 }; - ret = dm_i2c_write(dev, PCF2127_REG_CTRL1, buf, 1); - if (ret < 0) - return ret; - ret = dm_i2c_read(dev, PCF2127_REG_CTRL1, buf, sizeof(buf)); + ret = pcf2127_read_reg(dev, PCF2127_REG_CTRL1, buf, sizeof(buf)); if (ret < 0) return ret;