static int i2c_fsl_start(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; unsigned int temp = 0; int result; writeb(i2c_fsl->ifdr, base + FSL_I2C_IFDR); if (i2c_fsl->dfsrr != -1) writeb(i2c_fsl->dfsrr, base + FSL_I2C_DFSRR); /* Enable I2C controller */ writeb(0, base + FSL_I2C_I2SR); writeb(I2CR_IEN, base + FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); /* Start I2C transaction */ temp = readb(base + FSL_I2C_I2CR); temp |= I2CR_MSTA; writeb(temp, base + FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) return result; i2c_fsl->stopped = 0; temp |= I2CR_MTX | I2CR_TXAK; writeb(temp, base + FSL_I2C_I2CR); return result; }
static int i2c_fsl_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; unsigned int i, temp; int result; /* Start I2C transfer */ for (i = 0; i < 3; i++) { result = i2c_fsl_start(adapter); if (!result) break; if (result == -EAGAIN) continue; return result; } /* read/write data */ for (i = 0; i < num; i++) { if (i && !(msgs[i].flags & I2C_M_DATA_ONLY)) { temp = readb(base + FSL_I2C_I2CR); temp |= I2CR_RSTA; writeb(temp, base + FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) goto fail0; } i2c_fsl_dump_reg(adapter); /* write/read data */ if (msgs[i].flags & I2C_M_RD) result = i2c_fsl_read(adapter, &msgs[i]); else result = i2c_fsl_write(adapter, &msgs[i]); if (result) goto fail0; } fail0: /* Stop I2C transfer */ i2c_fsl_stop(adapter); return (result < 0) ? result : num; }
static int i2c_fsl_acked(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); uint64_t start; start = get_time_ns(); while (1) { unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (!(reg & I2SR_RXAK)) break; if (is_timeout(start, MSECOND)) { dev_dbg(&adapter->dev, "<%s> No ACK\n", __func__); return -EIO; } } return 0; }
static int i2c_fsl_start(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); unsigned int temp = 0; int result; fsl_i2c_write_reg(i2c_fsl->ifdr, i2c_fsl, FSL_I2C_IFDR); #ifdef CONFIG_PPC if (i2c_fsl->dfsrr != -1) fsl_i2c_write_reg(i2c_fsl->dfsrr, i2c_fsl, FSL_I2C_DFSRR); #endif /* Enable I2C controller */ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR); fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode, i2c_fsl, FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); /* Start I2C transaction */ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_MSTA; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) { result = i2c_recover_bus(&i2c_fsl->adapter); if (result) return result; return -EAGAIN; } i2c_fsl->stopped = 0; temp |= I2CR_MTX | I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); return result; }
static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; uint64_t start; start = get_time_ns(); while (1) { unsigned int reg = readb(base + FSL_I2C_I2SR); if (reg & I2SR_IIF) break; if (is_timeout(start, 100 * MSECOND)) { dev_err(&adapter->dev, "<%s> TXR timeout\n", __func__); return -EIO; } } writeb(0, base + FSL_I2C_I2SR); return 0; }
static void i2c_fsl_dump_reg(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); u32 reg_cr, reg_sr; reg_cr = readb(i2c_fsl->base + FSL_I2C_I2CR); reg_sr = readb(i2c_fsl->base + FSL_I2C_I2SR); dev_dbg(adapter->dev, "CONTROL:\t" "IEN =%d, IIEN=%d, MSTA=%d, MTX =%d, TXAK=%d, RSTA=%d\n", (reg_cr & I2CR_IEN ? 1 : 0), (reg_cr & I2CR_IIEN ? 1 : 0), (reg_cr & I2CR_MSTA ? 1 : 0), (reg_cr & I2CR_MTX ? 1 : 0), (reg_cr & I2CR_TXAK ? 1 : 0), (reg_cr & I2CR_RSTA ? 1 : 0)); dev_dbg(adapter->dev, "STATUS:\t" "ICF =%d, IAAS=%d, IB =%d, IAL =%d, SRW =%d, IIF =%d, RXAK=%d\n", (reg_sr & I2SR_ICF ? 1 : 0), (reg_sr & I2SR_IAAS ? 1 : 0), (reg_sr & I2SR_IBB ? 1 : 0), (reg_sr & I2SR_IAL ? 1 : 0), (reg_sr & I2SR_SRW ? 1 : 0), (reg_sr & I2SR_IIF ? 1 : 0), (reg_sr & I2SR_RXAK ? 1 : 0)); }
static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); uint64_t start; start = get_time_ns(); while (1) { unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (reg & I2SR_IIF) break; if (is_timeout(start, 100 * MSECOND)) { dev_err(&adapter->dev, "<%s> TXR timeout\n", __func__); return -EIO; } } fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR); return 0; }
static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; int i, result; if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { dev_dbg(&adapter->dev, "<%s> write slave address: addr=0x%02x\n", __func__, msgs->addr << 1); /* write slave address */ writeb(msgs->addr << 1, base + FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) return result; result = i2c_fsl_acked(adapter); if (result) return result; } /* write data */ for (i = 0; i < msgs->len; i++) { dev_dbg(&adapter->dev, "<%s> write byte: B%d=0x%02X\n", __func__, i, msgs->buf[i]); writeb(msgs->buf[i], base + FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) return result; result = i2c_fsl_acked(adapter); if (result) return result; } return 0; }
static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); uint64_t start; unsigned int temp; start = get_time_ns(); while (1) { temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (for_busy && (temp & I2SR_IBB)) break; if (!for_busy && !(temp & I2SR_IBB)) break; if (is_timeout(start, 500 * MSECOND)) { dev_err(&adapter->dev, "<%s> timeout waiting for I2C bus %s\n", __func__,for_busy ? "busy" : "not busy"); return -EIO; } } return 0; }
static void i2c_fsl_stop(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; unsigned int temp = 0; if (!i2c_fsl->stopped) { /* Stop I2C transaction */ temp = readb(base + FSL_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, base + FSL_I2C_I2CR); /* wait for the stop condition to be send, otherwise the i2c * controller is disabled before the STOP is sent completely */ i2c_fsl->stopped = i2c_fsl_bus_busy(adapter, 0) ? 0 : 1; } if (!i2c_fsl->stopped) { i2c_fsl_bus_busy(adapter, 0); i2c_fsl->stopped = 1; } /* Disable I2C controller, and force our state to stopped */ writeb(0, base + FSL_I2C_I2CR); }
static void i2c_fsl_stop(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); unsigned int temp = 0; if (!i2c_fsl->stopped) { /* Stop I2C transaction */ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); /* wait for the stop condition to be send, otherwise the i2c * controller is disabled before the STOP is sent completely */ i2c_fsl->stopped = i2c_fsl_bus_busy(adapter, 0) ? 0 : 1; } if (!i2c_fsl->stopped) { i2c_fsl_bus_busy(adapter, 0); i2c_fsl->stopped = 1; } /* Disable I2C controller, and force our state to stopped */ temp = i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN, fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); }
static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; int i, result; unsigned int temp; /* clear IIF */ writeb(0x0, base + FSL_I2C_I2SR); if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { dev_dbg(&adapter->dev, "<%s> write slave address: addr=0x%02x\n", __func__, (msgs->addr << 1) | 0x01); /* write slave address */ writeb((msgs->addr << 1) | 0x01, base + FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) return result; result = i2c_fsl_acked(adapter); if (result) return result; } /* setup bus to read data */ temp = readb(base + FSL_I2C_I2CR); temp &= ~I2CR_MTX; if (msgs->len - 1) temp &= ~I2CR_TXAK; writeb(temp, base + FSL_I2C_I2CR); readb(base + FSL_I2C_I2DR); /* dummy read */ /* read data */ for (i = 0; i < msgs->len; i++) { result = i2c_fsl_trx_complete(adapter); if (result) return result; if (i == (msgs->len - 1)) { /* * It must generate STOP before read I2DR to prevent * controller from generating another clock cycle */ temp = readb(base + FSL_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, base + FSL_I2C_I2CR); /* * adding this delay helps on low bitrates */ udelay(i2c_fsl->disable_delay); i2c_fsl_bus_busy(adapter, 0); i2c_fsl->stopped = 1; } else if (i == (msgs->len - 2)) { temp = readb(base + FSL_I2C_I2CR); temp |= I2CR_TXAK; writeb(temp, base + FSL_I2C_I2CR); } msgs->buf[i] = readb(base + FSL_I2C_I2DR); dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n", __func__, i, msgs->buf[i]); } return 0; }