diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-at91.c')
-rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 362 |
1 files changed, 298 insertions, 64 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index ff23d1bdd230..1c758cd1e1ba 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -41,29 +41,41 @@ /* AT91 TWI register definitions */ #define AT91_TWI_CR 0x0000 /* Control Register */ -#define AT91_TWI_START 0x0001 /* Send a Start Condition */ -#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ -#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ -#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ -#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ -#define AT91_TWI_SWRST 0x0080 /* Software Reset */ +#define AT91_TWI_START BIT(0) /* Send a Start Condition */ +#define AT91_TWI_STOP BIT(1) /* Send a Stop Condition */ +#define AT91_TWI_MSEN BIT(2) /* Master Transfer Enable */ +#define AT91_TWI_MSDIS BIT(3) /* Master Transfer Disable */ +#define AT91_TWI_SVEN BIT(4) /* Slave Transfer Enable */ +#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */ +#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */ +#define AT91_TWI_SWRST BIT(7) /* Software Reset */ +#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */ +#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */ +#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */ +#define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */ +#define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */ +#define AT91_TWI_FIFOEN BIT(28) /* FIFO Enable */ +#define AT91_TWI_FIFODIS BIT(29) /* FIFO Disable */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ #define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ -#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */ +#define AT91_TWI_MREAD BIT(12) /* Master Read Direction */ #define AT91_TWI_IADR 0x000c /* Internal Address Register */ #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ #define AT91_TWI_SR 0x0020 /* Status Register */ -#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */ -#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */ -#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */ +#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */ +#define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */ +#define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */ +#define AT91_TWI_OVRE BIT(6) /* Overrun Error */ +#define AT91_TWI_UNRE BIT(7) /* Underrun Error */ +#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ +#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */ -#define AT91_TWI_OVRE 0x0040 /* Overrun Error */ -#define AT91_TWI_UNRE 0x0080 /* Underrun Error */ -#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ +#define AT91_TWI_INT_MASK \ + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) #define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ #define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ @@ -71,17 +83,40 @@ #define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */ +#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) +#define AT91_TWI_ACR_DIR BIT(8) + +#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */ +#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0) +#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0) +#define AT91_TWI_FMR_RXRDYM(mode) (((mode) & 0x3) << 4) +#define AT91_TWI_FMR_RXRDYM_MASK (0x3 << 4) +#define AT91_TWI_ONE_DATA 0x0 +#define AT91_TWI_TWO_DATA 0x1 +#define AT91_TWI_FOUR_DATA 0x2 + +#define AT91_TWI_FLR 0x0054 /* FIFO Level Register */ + +#define AT91_TWI_FSR 0x0060 /* FIFO Status Register */ +#define AT91_TWI_FIER 0x0064 /* FIFO Interrupt Enable Register */ +#define AT91_TWI_FIDR 0x0068 /* FIFO Interrupt Disable Register */ +#define AT91_TWI_FIMR 0x006c /* FIFO Interrupt Mask Register */ + +#define AT91_TWI_VER 0x00fc /* Version Register */ + struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_alt_cmd; struct at_dma_slave dma_slave; }; struct at91_twi_dma { struct dma_chan *chan_rx; struct dma_chan *chan_tx; - struct scatterlist sg; + struct scatterlist sg[2]; struct dma_async_tx_descriptor *data_desc; enum dma_data_direction direction; bool buf_mapped; @@ -104,6 +139,7 @@ struct at91_twi_dev { struct at91_twi_pdata *pdata; bool use_dma; bool recv_len_abort; + u32 fifo_size; struct at91_twi_dma dma; }; @@ -119,13 +155,12 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) { - at91_twi_write(dev, AT91_TWI_IDR, - AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); + at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK); } static void at91_twi_irq_save(struct at91_twi_dev *dev) { - dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7; + dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK; at91_disable_twi_interrupts(dev); } @@ -138,6 +173,9 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev) { at91_disable_twi_interrupts(dev); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); + /* FIFO should be enabled immediately after the software reset */ + if (dev->fifo_size) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); @@ -184,7 +222,7 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) dma->xfer_in_progress = false; } if (dma->buf_mapped) { - dma_unmap_single(dev->dev, sg_dma_address(&dma->sg), + dma_unmap_single(dev->dev, sg_dma_address(&dma->sg[0]), dev->buf_len, dma->direction); dma->buf_mapped = false; } @@ -194,14 +232,16 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) static void at91_twi_write_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + if (!dev->buf_len) return; - at91_twi_write(dev, AT91_TWI_THR, *dev->buf); + /* 8bit write works with and without FIFO */ + writeb_relaxed(*dev->buf, dev->base + AT91_TWI_THR); /* send stop when last byte has been written */ if (--dev->buf_len == 0) - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + if (!dev->pdata->has_alt_cmd) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); @@ -212,10 +252,19 @@ static void at91_twi_write_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_TO_DEVICE); - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + /* + * When this callback is called, THR/TX FIFO is likely not to be empty + * yet. So we have to wait for TXCOMP or NACK bits to be set into the + * Status Register to be sure that the STOP bit has been sent and the + * transfer is completed. The NACK interrupt has already been enabled, + * we just have to enable TXCOMP one. + */ + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + if (!dev->pdata->has_alt_cmd) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } static void at91_twi_write_data_dma(struct at91_twi_dev *dev) @@ -224,8 +273,9 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *txdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_tx = dma->chan_tx; + unsigned int sg_len = 1; - if (dev->buf_len <= 0) + if (!dev->buf_len) return; dma->direction = DMA_TO_DEVICE; @@ -239,10 +289,43 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) } dma->buf_mapped = true; at91_twi_irq_restore(dev); - sg_dma_len(&dma->sg) = dev->buf_len; - sg_dma_address(&dma->sg) = dma_addr; - txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV, + if (dev->fifo_size) { + size_t part1_len, part2_len; + struct scatterlist *sg; + unsigned fifo_mr; + + sg_len = 0; + + part1_len = dev->buf_len & ~0x3; + if (part1_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part1_len; + sg_dma_address(sg) = dma_addr; + } + + part2_len = dev->buf_len & 0x3; + if (part2_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part2_len; + sg_dma_address(sg) = dma_addr + part1_len; + } + + /* + * DMA controller is triggered when at least 4 data can be + * written into the TX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_TXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } else { + sg_dma_len(&dma->sg[0]) = dev->buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + } + + txdesc = dmaengine_prep_slave_sg(chan_tx, dma->sg, sg_len, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -264,10 +347,11 @@ error: static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + if (!dev->buf_len) return; - *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; + /* 8bit read works with and without FIFO */ + *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR); --dev->buf_len; /* return if aborting, we only needed to read RHR to clear RXRDY*/ @@ -291,7 +375,7 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) } /* send stop if second but last byte has been read */ - if (dev->buf_len == 1) + if (!dev->pdata->has_alt_cmd && dev->buf_len == 1) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); @@ -302,14 +386,18 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) static void at91_twi_read_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + unsigned ier = AT91_TWI_TXCOMP; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_FROM_DEVICE); - /* The last two bytes have to be read without using dma */ - dev->buf += dev->buf_len - 2; - dev->buf_len = 2; - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY); + if (!dev->pdata->has_alt_cmd) { + /* The last two bytes have to be read without using dma */ + dev->buf += dev->buf_len - 2; + dev->buf_len = 2; + ier |= AT91_TWI_RXRDY; + } + at91_twi_write(dev, AT91_TWI_IER, ier); } static void at91_twi_read_data_dma(struct at91_twi_dev *dev) @@ -318,23 +406,38 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *rxdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_rx = dma->chan_rx; + size_t buf_len; + buf_len = (dev->pdata->has_alt_cmd) ? dev->buf_len : dev->buf_len - 2; dma->direction = DMA_FROM_DEVICE; /* Keep in mind that we won't use dma to read the last two bytes */ at91_twi_irq_save(dev); - dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2, - DMA_FROM_DEVICE); + dma_addr = dma_map_single(dev->dev, dev->buf, buf_len, DMA_FROM_DEVICE); if (dma_mapping_error(dev->dev, dma_addr)) { dev_err(dev->dev, "dma map failed\n"); return; } dma->buf_mapped = true; at91_twi_irq_restore(dev); - dma->sg.dma_address = dma_addr; - sg_dma_len(&dma->sg) = dev->buf_len - 2; - rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, + if (dev->fifo_size && IS_ALIGNED(buf_len, 4)) { + unsigned fifo_mr; + + /* + * DMA controller is triggered when at least 4 data can be + * read from the RX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_RXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } + + sg_dma_len(&dma->sg[0]) = buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + + rxdesc = dmaengine_prep_slave_sg(chan_rx, dma->sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -370,7 +473,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) /* catch error flags */ dev->transfer_status |= status; - if (irqstatus & AT91_TWI_TXCOMP) { + if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); } @@ -383,6 +486,50 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) int ret; unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; + bool has_alt_cmd = dev->pdata->has_alt_cmd; + + /* + * WARNING: the TXCOMP bit in the Status Register is NOT a clear on + * read flag but shows the state of the transmission at the time the + * Status Register is read. According to the programmer datasheet, + * TXCOMP is set when both holding register and internal shifter are + * empty and STOP condition has been sent. + * Consequently, we should enable NACK interrupt rather than TXCOMP to + * detect transmission failure. + * Indeed let's take the case of an i2c write command using DMA. + * Whenever the slave doesn't acknowledge a byte, the LOCK, NACK and + * TXCOMP bits are set together into the Status Register. + * LOCK is a clear on write bit, which is set to prevent the DMA + * controller from sending new data on the i2c bus after a NACK + * condition has happened. Once locked, this i2c peripheral stops + * triggering the DMA controller for new data but it is more than + * likely that a new DMA transaction is already in progress, writing + * into the Transmit Holding Register. Since the peripheral is locked, + * these new data won't be sent to the i2c bus but they will remain + * into the Transmit Holding Register, so TXCOMP bit is cleared. + * Then when the interrupt handler is called, the Status Register is + * read: the TXCOMP bit is clear but NACK bit is still set. The driver + * manage the error properly, without waiting for timeout. + * This case can be reproduced easyly when writing into an at24 eeprom. + * + * Besides, the TXCOMP bit is already set before the i2c transaction + * has been started. For read transactions, this bit is cleared when + * writing the START bit into the Control Register. So the + * corresponding interrupt can safely be enabled just after. + * However for write transactions managed by the CPU, we first write + * into THR, so TXCOMP is cleared. Then we can safely enable TXCOMP + * interrupt. If TXCOMP interrupt were enabled before writing into THR, + * the interrupt handler would be called immediately and the i2c command + * would be reported as completed. + * Also when a write transaction is managed by the DMA controller, + * enabling the TXCOMP interrupt in this function may lead to a race + * condition since we don't know whether the TXCOMP interrupt is enabled + * before or after the DMA has started to write into THR. So the TXCOMP + * interrupt is enabled later by at91_twi_write_data_dma_callback(). + * Immediately after in that DMA callback, if the alternative command + * mode is not used, we still need to send the STOP condition manually + * writing the corresponding bit into the Control Register. + */ dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); @@ -390,6 +537,21 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; + if (dev->fifo_size) { + unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + + /* Reset FIFO mode register */ + fifo_mr &= ~(AT91_TWI_FMR_TXRDYM_MASK | + AT91_TWI_FMR_RXRDYM_MASK); + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_ONE_DATA); + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_ONE_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + + /* Flush FIFOs */ + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_RHRCLR); + } + if (!dev->buf_len) { at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); @@ -402,44 +564,45 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) } /* if only one byte is to be read, immediately stop transfer */ - if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) + if (!has_alt_cmd && dev->buf_len <= 1 && + !(dev->msg->flags & I2C_M_RECV_LEN)) start_flags |= AT91_TWI_STOP; at91_twi_write(dev, AT91_TWI_CR, start_flags); /* - * When using dma, the last byte has to be read manually in - * order to not send the stop command too late and then - * to receive extra data. In practice, there are some issues - * if you use the dma to read n-1 bytes because of latency. + * When using dma without alternative command mode, the last + * byte has to be read manually in order to not send the stop + * command too late and then to receive extra data. + * In practice, there are some issues if you use the dma to + * read n-1 bytes because of latency. * Reading n-2 bytes with dma and the two last ones manually * seems to be the best solution. */ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_read_data_dma(dev); - /* - * It is important to enable TXCOMP irq here because - * doing it only when transferring the last two bytes - * will mask NACK errors since TXCOMP is set when a - * NACK occurs. - */ - at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP); - } else + } else { at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_RXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_RXRDY); + } } else { if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_write_data_dma(dev); - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); } else { at91_twi_write_next_byte(dev); at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_TXRDY); } } time_left = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); if (time_left == 0) { + dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR); dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; @@ -460,6 +623,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO; goto error; } + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { + dev_err(dev->dev, "tx locked\n"); + ret = -EIO; + goto error; + } if (dev->recv_len_abort) { dev_err(dev->dev, "invalid smbus block length recvd\n"); ret = -EPROTO; @@ -471,7 +640,15 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) return 0; error: + /* first stop DMA transfer if still in progress */ at91_twi_dma_cleanup(dev); + /* then flush THR/FIFO and unlock TX if locked */ + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { + dev_dbg(dev->dev, "unlock tx\n"); + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_LOCKCLR); + } return ret; } @@ -481,6 +658,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) int ret; unsigned int_addr_flag = 0; struct i2c_msg *m_start = msg; + bool is_read, use_alt_cmd = false; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); @@ -503,8 +681,23 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) at91_twi_write(dev, AT91_TWI_IADR, internal_address); } - at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag - | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + is_read = (m_start->flags & I2C_M_RD); + if (dev->pdata->has_alt_cmd) { + if (m_start->len > 0) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN); + at91_twi_write(dev, AT91_TWI_ACR, + AT91_TWI_ACR_DATAL(m_start->len) | + ((is_read) ? AT91_TWI_ACR_DIR : 0)); + use_alt_cmd = true; + } else { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS); + } + } + + at91_twi_write(dev, AT91_TWI_MMR, + (m_start->addr << 16) | + int_addr_flag | + ((!use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); dev->buf_len = m_start->len; dev->buf = m_start->buf; @@ -545,30 +738,35 @@ static struct at91_twi_pdata at91rm9200_config = { .clk_max_div = 5, .clk_offset = 3, .has_unre_flag = true, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9261_config = { .clk_max_div = 5, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9260_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g20_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g10_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -597,6 +795,14 @@ static struct at91_twi_pdata at91sam9x5_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, +}; + +static struct at91_twi_pdata sama5d2_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = true, + .has_alt_cmd = true, }; static const struct of_device_id atmel_twi_dt_ids[] = { @@ -619,6 +825,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = { .compatible = "atmel,at91sam9x5-i2c", .data = &at91sam9x5_config, }, { + .compatible = "atmel,sama5d2-i2c", + .data = &sama5d2_config, + }, { /* sentinel */ } }; @@ -630,13 +839,32 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) int ret = 0; struct dma_slave_config slave_config; struct at91_twi_dma *dma = &dev->dma; + enum dma_slave_buswidth addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + /* + * The actual width of the access will be chosen in + * dmaengine_prep_slave_sg(): + * for each buffer in the scatter-gather list, if its size is aligned + * to addr_width then addr_width accesses will be performed to transfer + * the buffer. On the other hand, if the buffer size is not aligned to + * addr_width then the buffer is transferred using single byte accesses. + * Please refer to the Atmel eXtended DMA controller driver. + * When FIFOs are used, the TXRDYM threshold can always be set to + * trigger the XDMAC when at least 4 data can be written into the TX + * FIFO, even if single byte accesses are performed. + * However the RXRDYM threshold must be set to fit the access width, + * deduced from buffer length, so the XDMAC is triggered properly to + * read data from the RX FIFO. + */ + if (dev->fifo_size) + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; memset(&slave_config, 0, sizeof(slave_config)); slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; - slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = addr_width; slave_config.src_maxburst = 1; slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR; - slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr_width = addr_width; slave_config.dst_maxburst = 1; slave_config.device_fc = false; @@ -668,7 +896,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) goto error; } - sg_init_table(&dma->sg, 1); + sg_init_table(dma->sg, 2); dma->buf_mapped = false; dma->xfer_in_progress = false; dev->use_dma = true; @@ -754,6 +982,11 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &dev->fifo_size)) { + dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size); + } + rc = of_property_read_u32(dev->dev->of_node, "clock-frequency", &bus_clk_rate); if (rc) @@ -790,7 +1023,8 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } - dev_info(dev->dev, "AT91 i2c bus driver.\n"); + dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n", + at91_twi_read(dev, AT91_TWI_VER)); return 0; } |