diff --git a/drivers/i2c/busses/i2c-lantiq.c b/drivers/i2c/busses/i2c-lantiq.c index 907d53eddb67f228792ab66dbb8217352e3ed82b..a0ff6a61321cb27d8d070c2e8c324dc1e06f9ee0 100644 --- a/drivers/i2c/busses/i2c-lantiq.c +++ b/drivers/i2c/busses/i2c-lantiq.c @@ -330,7 +330,7 @@ static irqreturn_t ltq_i2c_isr(int irq, void *dev_id); * handler). For this reason we avoid using last-burst in rx, and rely on * tx-end instead to end transfer. */ -static inline void enable_burst_irq(struct ltq_i2c *priv) +static void enable_burst_irq(struct ltq_i2c *priv) { int mask; @@ -342,7 +342,8 @@ static inline void enable_burst_irq(struct ltq_i2c *priv) i2c_w32_mask(0, mask, imsc); } -static inline void disable_burst_irq(struct ltq_i2c *priv) + +static void disable_burst_irq(struct ltq_i2c *priv) { i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN | @@ -479,8 +480,8 @@ static int ltq_i2c_hw_init(struct i2c_adapter *adap) /* configure fifo */ i2c_w32(I2C_FIFO_CFG_TXFC | /* tx fifo as flow controller */ I2C_FIFO_CFG_RXFC | /* rx fifo as flow controller */ - I2C_FIFO_CFG_TXFA_TXFA2 | /* tx fifo 4-byte aligned */ - I2C_FIFO_CFG_RXFA_RXFA2 | /* rx fifo 4-byte aligned */ + I2C_FIFO_CFG_TXFA_TXFA0 | /* tx fifo byte aligned */ + I2C_FIFO_CFG_RXFA_RXFA0 | /* rx fifo byte aligned */ I2C_FIFO_CFG_TXBS_TXBS0 | /* tx fifo burst size is 1 word */ I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */ fifo_cfg); @@ -530,21 +531,57 @@ static int ltq_i2c_wait_bus_not_busy(struct ltq_i2c *priv) return -ETIMEDOUT; } -static inline void ltq_i2c_tx(struct ltq_i2c *priv) +/** + * Send addr and tx in word (LSB first) + * + * Address and tx data are sent together in word (4-bytes), to eliminate/reduce + * the dependency on tx interrupt. + */ +static void ltq_i2c_tx(struct ltq_i2c *priv) { + struct i2c_msg *msg = priv->current_msg; + u16 addr = msg->addr; + u32 word = 0; + u32 tmp; + const int bytes_per_word = 4; + int i = 0; + + if (priv->status == STATUS_ADDR) { + /* new i2c_msg */ + priv->msg_buf = msg->buf; + priv->msg_buf_len = msg->len; + pr_debug("ADDR: msg->flags[%d] addr 0x%x\n", msg->flags, addr); + + /* send slave address */ + if (msg->flags & I2C_M_TEN) { + word = 0xf0 | ((addr & 0x300) >> 7); + word |= ((addr & 0xff) << 8); + i += 2; + } else { + word = (addr & 0x7f) << 1; + i += 1; + } + priv->status = STATUS_WRITE; + } - if (priv->msg_buf_len && priv->msg_buf) { - i2c_w32(*priv->msg_buf, txd); - if (--priv->msg_buf_len) - priv->msg_buf++; - else - priv->msg_buf = NULL; - } else - priv->last_burst = LAST_BURST; + for (; i < bytes_per_word; i++) { + if (priv->msg_buf_len && priv->msg_buf) { + tmp = ((u32)*priv->msg_buf) << (8 * i); + word |= tmp; + if (--priv->msg_buf_len) + priv->msg_buf++; + else + priv->msg_buf = NULL; + } else { + priv->last_burst = LAST_BURST; + } + } + + /* write as word */ + i2c_w32(word, txd); if (priv->last_burst) disable_burst_irq(priv); - } /** @@ -554,7 +591,7 @@ static inline void ltq_i2c_tx(struct ltq_i2c *priv) * sometimes ffs increased without rps being increased. Therefore here we * ignore rps and rely solely on ffs. */ -static inline int ltq_i2c_rx(struct ltq_i2c *priv) +static int ltq_i2c_rx(struct ltq_i2c *priv) { u32 fifo_filled; int ret = 0; @@ -683,6 +720,7 @@ static int ltq_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret = ltq_i2c_wait_bus_not_busy(priv); if (ret) { dev_err(priv->dev, "%s: bus is busy %x\n", __func__, ret); + ltq_i2c_hw_init(adap); goto done; } @@ -716,6 +754,7 @@ static int ltq_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], dev_err(priv->dev, " rx underflow\n"); ret = -EREMOTEIO; + ltq_i2c_hw_init(adap); } goto done; @@ -805,9 +844,6 @@ static irqreturn_t ltq_i2c_isr_burst(int irq, void *dev_id) } else { switch (priv->status) { case STATUS_ADDR: - pr_debug("===x===\n"); - prepare_msg_send_addr(priv); - break; case STATUS_WRITE: pr_debug("===w===\n"); ltq_i2c_tx(priv); @@ -823,7 +859,7 @@ static irqreturn_t ltq_i2c_isr_burst(int irq, void *dev_id) return ret; } -static inline irqreturn_t ltq_i2c_isr_prot(struct ltq_i2c *priv) +static irqreturn_t ltq_i2c_isr_prot(struct ltq_i2c *priv) { u32 i_pro = i2c_r32(p_irqss); int ret = IRQ_HANDLED; diff --git a/drivers/i2c/busses/i2c-lantiq.h b/drivers/i2c/busses/i2c-lantiq.h index 9e1e3bb9e2fc0744e7ba22ff488f50a07d83b10b..7f84dcdd56a36826a97654449c2e53cdd2e933e2 100644 --- a/drivers/i2c/busses/i2c-lantiq.h +++ b/drivers/i2c/busses/i2c-lantiq.h @@ -173,10 +173,22 @@ struct lantiq_reg_i2c { #define I2C_FIFO_CFG_TXFC 0x00020000 /* RX FIFO Flow Control */ #define I2C_FIFO_CFG_RXFC 0x00010000 +/* Byte aligned (character alignment) */ +#define I2C_FIFO_CFG_TXFA_TXFA0 0x00000000 +/* Half word aligned (character alignment of two characters) */ +#define I2C_FIFO_CFG_TXFA_TXFA1 0x00001000 /* Word aligned (character alignment of four characters) */ #define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000 +/* Double word aligned (character alignment of eight */ +#define I2C_FIFO_CFG_TXFA_TXFA3 0x00003000 +/* Byte aligned (character alignment) */ +#define I2C_FIFO_CFG_RXFA_RXFA0 0x00000000 +/* Half word aligned (character alignment of two characters) */ +#define I2C_FIFO_CFG_RXFA_RXFA1 0x00000100 /* Word aligned (character alignment of four characters) */ -#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000000 +#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200 +/* Double word aligned (character alignment of eight */ +#define I2C_FIFO_CFG_RXFA_RXFA3 0x00000300 /* 1 word: 0 for 1 word, 2 for 4 words, prevent txunder */ #define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000