summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-at91.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-at91.c')
-rw-r--r--drivers/i2c/busses/i2c-at91.c362
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;
}