diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-imx.c')
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 272 |
1 files changed, 86 insertions, 186 deletions
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 67937da73a..4c7346063c 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -49,61 +49,7 @@ #include <i2c/i2c.h> #include <mach/clock.h> -/* This will be the driver name */ -#define DRIVER_NAME "i2c-fsl" - -/* Default value */ -#define FSL_I2C_BIT_RATE 100000 /* 100kHz */ - -/* IMX I2C registers: - * the I2C register offset is different between SoCs, - * to provid support for all these chips, split the - * register offset into a fixed base address and a - * variable shift value, then the full register offset - * will be calculated by - * reg_off = ( reg_base_addr << reg_shift) - */ -#define FSL_I2C_IADR 0x00 /* i2c slave address */ -#define FSL_I2C_IFDR 0x01 /* i2c frequency divider */ -#define FSL_I2C_I2CR 0x02 /* i2c control */ -#define FSL_I2C_I2SR 0x03 /* i2c status */ -#define FSL_I2C_I2DR 0x04 /* i2c transfer data */ -#define FSL_I2C_DFSRR 0x14 /* i2c digital filter sampling rate */ - -#define IMX_I2C_REGSHIFT 2 -#define VF610_I2C_REGSHIFT 0 - - -/* Bits of FSL I2C registers */ -#define I2SR_RXAK 0x01 -#define I2SR_IIF 0x02 -#define I2SR_SRW 0x04 -#define I2SR_IAL 0x10 -#define I2SR_IBB 0x20 -#define I2SR_IAAS 0x40 -#define I2SR_ICF 0x80 -#define I2CR_RSTA 0x04 -#define I2CR_TXAK 0x08 -#define I2CR_MTX 0x10 -#define I2CR_MSTA 0x20 -#define I2CR_IIEN 0x40 -#define I2CR_IEN 0x80 - -/* register bits different operating codes definition: - * 1) I2SR: Interrupt flags clear operation differ between SoCs: - * - write zero to clear(w0c) INT flag on i.MX, - * - but write one to clear(w1c) INT flag on Vybrid. - * 2) I2CR: I2C module enable operation also differ between SoCs: - * - set I2CR_IEN bit enable the module on i.MX, - * - but clear I2CR_IEN bit enable the module on Vybrid. - */ -#define I2SR_CLR_OPCODE_W0C 0x0 -#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF) -#define I2CR_IEN_OPCODE_0 0x0 -#define I2CR_IEN_OPCODE_1 I2CR_IEN - -#define I2C_PM_TIMEOUT 10 /* ms */ - +#include "i2c-imx.h" /* * sorted list of clock divider, register value pairs @@ -168,7 +114,6 @@ struct fsl_i2c_struct { struct clk *clk; struct i2c_adapter adapter; unsigned int disable_delay; - int stopped; unsigned int ifdr; /* FSL_I2C_IFDR */ unsigned int dfsrr; /* FSL_I2C_DFSRR */ struct i2c_bus_recovery_info rinfo; @@ -191,7 +136,6 @@ static inline unsigned char fsl_i2c_read_reg(struct fsl_i2c_struct *i2c_fsl, return readb(i2c_fsl->base + reg); } -#ifdef CONFIG_I2C_DEBUG static void i2c_fsl_dump_reg(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); @@ -213,54 +157,51 @@ static void i2c_fsl_dump_reg(struct i2c_adapter *adapter) (reg_sr & I2SR_SRW ? 1 : 0), (reg_sr & I2SR_IIF ? 1 : 0), (reg_sr & I2SR_RXAK ? 1 : 0)); } -#else -static inline void i2c_fsl_dump_reg(struct i2c_adapter *adapter) -{ - return; -} -#endif - -static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy) +static int i2c_fsl_poll_status(struct i2c_adapter *adapter, int timeout_ms, + uint8_t set, uint8_t clear) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); uint64_t start; - unsigned int temp; + uint8_t 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"); + if (temp & set) + return 0; + if (~temp & clear) + return 0; + + if (is_timeout(start, timeout_ms * MSECOND)) { + dev_dbg(&adapter->dev, + "timeout waiting for status %s 0x%02x, cur status: 0x%02x\n", + set ? "set" : "clear", + set ? set : clear, + temp); return -EIO; } } +} - return 0; +static int i2c_fsl_bus_busy(struct i2c_adapter *adapter) +{ + return i2c_fsl_poll_status(adapter, 500, I2SR_IBB, 0); +} + +static int i2c_fsl_bus_idle(struct i2c_adapter *adapter) +{ + return i2c_fsl_poll_status(adapter, 500, 0, I2SR_IBB); } 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; + int ret; - if (is_timeout(start, 100 * MSECOND)) { - dev_err(&adapter->dev, "<%s> TXR timeout\n", __func__); - return -EIO; - } - } + ret = i2c_fsl_poll_status(adapter, 100, I2SR_IIF, 0); + if (ret) + return ret; fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR); @@ -270,22 +211,7 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) 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; + return i2c_fsl_poll_status(adapter, 1, 0, I2SR_RXAK); } static int i2c_fsl_start(struct i2c_adapter *adapter) @@ -314,7 +240,7 @@ static int i2c_fsl_start(struct i2c_adapter *adapter) temp |= I2CR_MSTA; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); - result = i2c_fsl_bus_busy(adapter, 1); + result = i2c_fsl_bus_busy(adapter); if (result) { result = i2c_recover_bus(&i2c_fsl->adapter); if (result) @@ -322,8 +248,6 @@ static int i2c_fsl_start(struct i2c_adapter *adapter) return -EAGAIN; } - i2c_fsl->stopped = 0; - temp |= I2CR_MTX | I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); @@ -335,24 +259,20 @@ 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; - } + /* Stop I2C transaction */ + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); + if (!(temp & I2CR_MSTA)) + return; - /* Disable I2C controller, and force our state to stopped */ - temp = i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN, + 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 */ + + /* adding this delay helps on low bitrates */ + udelay(i2c_fsl->disable_delay); + + i2c_fsl_bus_idle(adapter); } #ifdef CONFIG_PPC @@ -462,45 +382,44 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, } #endif -static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) +static int i2c_fsl_send(struct i2c_adapter *adapter, uint8_t data) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - int i, result; + int result; - if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { - dev_dbg(&adapter->dev, - "<%s> write slave address: addr=0x%02x\n", - __func__, msgs->addr << 1); + dev_dbg(&adapter->dev, "<%s> send 0x%02x\n", __func__, data); - /* write slave address */ - fsl_i2c_write_reg(msgs->addr << 1, i2c_fsl, FSL_I2C_I2DR); + fsl_i2c_write_reg(data, i2c_fsl, FSL_I2C_I2DR); - result = i2c_fsl_trx_complete(adapter); - if (result) - return result; - result = i2c_fsl_acked(adapter); + result = i2c_fsl_trx_complete(adapter); + if (result) + return result; + + return i2c_fsl_acked(adapter); +} + +static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msg) +{ + int i, result; + + if (!(msg->flags & I2C_M_DATA_ONLY)) { + result = i2c_fsl_send(adapter, msg->addr << 1); 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]); - fsl_i2c_write_reg(msgs->buf[i], i2c_fsl, FSL_I2C_I2DR); - - result = i2c_fsl_trx_complete(adapter); - if (result) - return result; - result = i2c_fsl_acked(adapter); + for (i = 0; i < msg->len; i++) { + result = i2c_fsl_send(adapter, msg->buf[i]); if (result) return result; } + return 0; } -static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) +static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msg, + bool is_last) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); int i, result; @@ -510,18 +429,8 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, 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 */ - fsl_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_fsl, FSL_I2C_I2DR); - - result = i2c_fsl_trx_complete(adapter); - if (result) - return result; - result = i2c_fsl_acked(adapter); + if (!(msg->flags & I2C_M_DATA_ONLY)) { + result = i2c_fsl_send(adapter, (msg->addr << 1) | 1); if (result) return result; } @@ -529,43 +438,29 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) /* setup bus to read data */ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp &= ~I2CR_MTX; - if (msgs->len - 1) + if (msg->len - 1) temp &= ~I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); /* dummy read */ /* read data */ - for (i = 0; i < msgs->len; i++) { + for (i = 0; i < msg->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 = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); - temp &= ~(I2CR_MSTA | I2CR_MTX); - fsl_i2c_write_reg(temp, i2c_fsl, 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)) { + if (is_last && i == msg->len - 1) { + i2c_fsl_stop(adapter); + } else if (i == (msg->len - 2)) { temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); } - msgs->buf[i] = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); + msg->buf[i] = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n", - __func__, i, msgs->buf[i]); + __func__, i, msg->buf[i]); } return 0; } @@ -594,7 +489,7 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter, temp |= I2CR_RSTA; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); - result = i2c_fsl_bus_busy(adapter, 1); + result = i2c_fsl_bus_busy(adapter); if (result) goto fail0; } @@ -602,7 +497,7 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter, /* write/read data */ if (msgs[i].flags & I2C_M_RD) - result = i2c_fsl_read(adapter, &msgs[i]); + result = i2c_fsl_read(adapter, &msgs[i], i == num - 1); else result = i2c_fsl_write(adapter, &msgs[i]); if (result) @@ -613,6 +508,10 @@ fail0: /* Stop I2C transfer */ i2c_fsl_stop(adapter); + /* 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); + return (result < 0) ? result : num; } @@ -664,6 +563,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev) struct fsl_i2c_struct *i2c_fsl; struct i2c_platform_data *pdata; int ret; + int bitrate; pdata = pdev->platform_data; @@ -705,10 +605,12 @@ static int __init i2c_fsl_probe(struct device_d *pdev) i2c_fsl->dfsrr = -1; /* Set up clock divider */ + bitrate = 100000; + of_property_read_u32(pdev->device_node, "clock-frequency", &bitrate); if (pdata && pdata->bitrate) - i2c_fsl_set_clk(i2c_fsl, pdata->bitrate); - else - i2c_fsl_set_clk(i2c_fsl, FSL_I2C_BIT_RATE); + bitrate = pdata->bitrate; + + i2c_fsl_set_clk(i2c_fsl, bitrate); /* Set up chip registers to defaults */ fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN, @@ -753,9 +655,7 @@ static __maybe_unused struct of_device_id imx_i2c_dt_ids[] = { static struct driver_d i2c_fsl_driver = { .probe = i2c_fsl_probe, - .name = DRIVER_NAME, -#ifndef CONFIG_PPC + .name = "i2c-fsl", .of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids), -#endif }; coredevice_platform_driver(i2c_fsl_driver); |