X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fi2c%2Fppc4xx_i2c.c;h=8a38d11fb9f42489e4d5566c271adf1a8f06795b;hb=cfa414aefd530bba4dd5105c77615104c96367bf;hp=e7a15ba6448a7600ac5f8a077840e2e98533d2e3;hpb=326ea986ac150acdc7656d57fca647db80b50158;p=oweals%2Fu-boot.git diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c index e7a15ba644..8a38d11fb9 100644 --- a/drivers/i2c/ppc4xx_i2c.c +++ b/drivers/i2c/ppc4xx_i2c.c @@ -8,6 +8,9 @@ * Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net * * SPDX-License-Identifier: GPL-2.0+ + * + * NOTE: This driver should be converted to driver model before June 2017. + * Please see doc/driver-model/i2c-howto.txt for instructions. */ #include @@ -158,8 +161,7 @@ static void ppc4xx_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) * * Typical case is a Write of an addr followd by a Read. The * IBM FAQ does not cover this. On the last byte of the write - * we don't set the creg CHT bit, and on the first bytes of the - * read we set the RPST bit. + * we don't set the creg CHT bit but the RPST bit. * * It does not support address only transfers, there must be * a data part. If you want to write the address yourself, put @@ -247,6 +249,10 @@ static int _i2c_transfer(struct i2c_adapter *adap, if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt)) creg |= IIC_CNTL_CHT; + /* last part of address, prepare for repeated start on read */ + if (cmd_type && (ptr == addr) && ((tran + bc) == cnt)) + creg |= IIC_CNTL_RPST; + if (reading) { creg |= IIC_CNTL_READ; } else { @@ -286,6 +292,27 @@ static int _i2c_transfer(struct i2c_adapter *adap, /* Transfer aborted? */ if (status & IIC_EXTSTS_XFRA) result = IIC_NOK_XFRA; + /* Is bus free? + * If error happened during combined xfer + * IIC interface is usually stuck in some strange + * state without a valid stop condition. + * Brute, but working: generate stop, then soft reset. + */ + if ((status & IIC_EXTSTS_BCS_MASK) + != IIC_EXTSTS_BCS_FREE){ + u8 mdcntl = in_8(&i2c->mdcntl); + + /* Generate valid stop condition */ + out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST); + out_8(&i2c->directcntl, IIC_DIRCNTL_SCC); + udelay(10); + out_8(&i2c->directcntl, + IIC_DIRCNTL_SCC | IIC_DIRCNTL_SDAC); + out_8(&i2c->xtcntlss, 0); + + ppc4xx_i2c_init(adap, (mdcntl & IIC_MDCNTL_FSM) + ? 400000 : 100000, 0); + } } else if ( status & IIC_STS_PT) { result = IIC_NOK_TOUT; } @@ -314,8 +341,6 @@ static int _i2c_transfer(struct i2c_adapter *adap, cnt = data_len; tran = 0; reading = cmd_type; - if (reading) - creg = IIC_CNTL_RPST; } } return result;