aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@atmel.com>2016-08-03 10:58:26 -0400
committerWolfram Sang <wsa@the-dreams.de>2016-08-14 18:55:30 -0400
commit434f14e745442a4230a40cf47f84deac1028f64f (patch)
treebf7cda9088b48db8bcd78a67d36ac12002cb23b9
parent97ccd4af120c6ee183f424f17672870809bd6efd (diff)
i2c: at91: fix support of the "alternative command" feature
The "alternative command" feature was introduced with sama5d2 SoCs. Its purpose is to let the hardware i2c controller automatically send the STOP condition on the i2c bus at the end of a data transfer. Without this feature, the i2c driver has to write the 'STOP' bit into the Control Register so the hardware i2c controller is triggered to send the STOP condition on the bus. Using the "alternative command" feature requires to set the transfer data length into the 8bit DATAL field of the Alternative Command Register. Hence only data transfers up to 255 bytes can take advantage of the "alternative command" feature. For greater data transfer sizes, the driver should use the previous implementation, when the "alternative command" support was not implemented yet. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-at91.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index f23372669f77..1bb97f658b47 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -38,6 +38,7 @@
38#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ 38#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
39#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ 39#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
40#define AUTOSUSPEND_TIMEOUT 2000 40#define AUTOSUSPEND_TIMEOUT 2000
41#define AT91_I2C_MAX_ALT_CMD_DATA_SIZE 256
41 42
42/* AT91 TWI register definitions */ 43/* AT91 TWI register definitions */
43#define AT91_TWI_CR 0x0000 /* Control Register */ 44#define AT91_TWI_CR 0x0000 /* Control Register */
@@ -141,6 +142,7 @@ struct at91_twi_dev {
141 unsigned twi_cwgr_reg; 142 unsigned twi_cwgr_reg;
142 struct at91_twi_pdata *pdata; 143 struct at91_twi_pdata *pdata;
143 bool use_dma; 144 bool use_dma;
145 bool use_alt_cmd;
144 bool recv_len_abort; 146 bool recv_len_abort;
145 u32 fifo_size; 147 u32 fifo_size;
146 struct at91_twi_dma dma; 148 struct at91_twi_dma dma;
@@ -269,7 +271,7 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
269 271
270 /* send stop when last byte has been written */ 272 /* send stop when last byte has been written */
271 if (--dev->buf_len == 0) 273 if (--dev->buf_len == 0)
272 if (!dev->pdata->has_alt_cmd) 274 if (!dev->use_alt_cmd)
273 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); 275 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
274 276
275 dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); 277 dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
@@ -292,7 +294,7 @@ static void at91_twi_write_data_dma_callback(void *data)
292 * we just have to enable TXCOMP one. 294 * we just have to enable TXCOMP one.
293 */ 295 */
294 at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); 296 at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
295 if (!dev->pdata->has_alt_cmd) 297 if (!dev->use_alt_cmd)
296 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); 298 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
297} 299}
298 300
@@ -410,7 +412,7 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
410 } 412 }
411 413
412 /* send stop if second but last byte has been read */ 414 /* send stop if second but last byte has been read */
413 if (!dev->pdata->has_alt_cmd && dev->buf_len == 1) 415 if (!dev->use_alt_cmd && dev->buf_len == 1)
414 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); 416 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
415 417
416 dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); 418 dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
@@ -426,7 +428,7 @@ static void at91_twi_read_data_dma_callback(void *data)
426 dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), 428 dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]),
427 dev->buf_len, DMA_FROM_DEVICE); 429 dev->buf_len, DMA_FROM_DEVICE);
428 430
429 if (!dev->pdata->has_alt_cmd) { 431 if (!dev->use_alt_cmd) {
430 /* The last two bytes have to be read without using dma */ 432 /* The last two bytes have to be read without using dma */
431 dev->buf += dev->buf_len - 2; 433 dev->buf += dev->buf_len - 2;
432 dev->buf_len = 2; 434 dev->buf_len = 2;
@@ -443,7 +445,7 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
443 struct dma_chan *chan_rx = dma->chan_rx; 445 struct dma_chan *chan_rx = dma->chan_rx;
444 size_t buf_len; 446 size_t buf_len;
445 447
446 buf_len = (dev->pdata->has_alt_cmd) ? dev->buf_len : dev->buf_len - 2; 448 buf_len = (dev->use_alt_cmd) ? dev->buf_len : dev->buf_len - 2;
447 dma->direction = DMA_FROM_DEVICE; 449 dma->direction = DMA_FROM_DEVICE;
448 450
449 /* Keep in mind that we won't use dma to read the last two bytes */ 451 /* Keep in mind that we won't use dma to read the last two bytes */
@@ -651,7 +653,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
651 unsigned start_flags = AT91_TWI_START; 653 unsigned start_flags = AT91_TWI_START;
652 654
653 /* if only one byte is to be read, immediately stop transfer */ 655 /* if only one byte is to be read, immediately stop transfer */
654 if (!has_alt_cmd && dev->buf_len <= 1 && 656 if (!dev->use_alt_cmd && dev->buf_len <= 1 &&
655 !(dev->msg->flags & I2C_M_RECV_LEN)) 657 !(dev->msg->flags & I2C_M_RECV_LEN))
656 start_flags |= AT91_TWI_STOP; 658 start_flags |= AT91_TWI_STOP;
657 at91_twi_write(dev, AT91_TWI_CR, start_flags); 659 at91_twi_write(dev, AT91_TWI_CR, start_flags);
@@ -745,7 +747,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
745 int ret; 747 int ret;
746 unsigned int_addr_flag = 0; 748 unsigned int_addr_flag = 0;
747 struct i2c_msg *m_start = msg; 749 struct i2c_msg *m_start = msg;
748 bool is_read, use_alt_cmd = false; 750 bool is_read;
749 751
750 dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); 752 dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
751 753
@@ -768,14 +770,16 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
768 at91_twi_write(dev, AT91_TWI_IADR, internal_address); 770 at91_twi_write(dev, AT91_TWI_IADR, internal_address);
769 } 771 }
770 772
773 dev->use_alt_cmd = false;
771 is_read = (m_start->flags & I2C_M_RD); 774 is_read = (m_start->flags & I2C_M_RD);
772 if (dev->pdata->has_alt_cmd) { 775 if (dev->pdata->has_alt_cmd) {
773 if (m_start->len > 0) { 776 if (m_start->len > 0 &&
777 m_start->len < AT91_I2C_MAX_ALT_CMD_DATA_SIZE) {
774 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN); 778 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN);
775 at91_twi_write(dev, AT91_TWI_ACR, 779 at91_twi_write(dev, AT91_TWI_ACR,
776 AT91_TWI_ACR_DATAL(m_start->len) | 780 AT91_TWI_ACR_DATAL(m_start->len) |
777 ((is_read) ? AT91_TWI_ACR_DIR : 0)); 781 ((is_read) ? AT91_TWI_ACR_DIR : 0));
778 use_alt_cmd = true; 782 dev->use_alt_cmd = true;
779 } else { 783 } else {
780 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS); 784 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS);
781 } 785 }
@@ -784,7 +788,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
784 at91_twi_write(dev, AT91_TWI_MMR, 788 at91_twi_write(dev, AT91_TWI_MMR,
785 (m_start->addr << 16) | 789 (m_start->addr << 16) |
786 int_addr_flag | 790 int_addr_flag |
787 ((!use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); 791 ((!dev->use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0));
788 792
789 dev->buf_len = m_start->len; 793 dev->buf_len = m_start->len;
790 dev->buf = m_start->buf; 794 dev->buf = m_start->buf;