73 lines
2.6 KiB
Diff
73 lines
2.6 KiB
Diff
From 0262abfaac71799e3688285f1f30bead42b8ff7e Mon Sep 17 00:00:00 2001
|
|
From: cbeytas <cbeytas@shaw.ca>
|
|
Date: Mon, 24 Jun 2013 00:05:40 -0400
|
|
Subject: [PATCH 020/114] Perform I2C combined transactions when possible
|
|
|
|
Perform I2C combined transactions whenever possible, within the
|
|
restrictions of the Broadcomm Serial Controller.
|
|
|
|
Disable DONE interrupt during TA poll
|
|
|
|
Prevent interrupt from being triggered if poll is missed and transfer
|
|
starts and finishes.
|
|
|
|
i2c: Make combined transactions optional and disabled by default
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2708.c | 31 ++++++++++++++++++++++++++++++-
|
|
1 file changed, 30 insertions(+), 1 deletion(-)
|
|
|
|
--- a/drivers/i2c/busses/i2c-bcm2708.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2708.c
|
|
@@ -74,6 +74,9 @@ static unsigned int baudrate = CONFIG_I2
|
|
module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
MODULE_PARM_DESC(baudrate, "The I2C baudrate");
|
|
|
|
+static bool combined = false;
|
|
+module_param(combined, bool, 0644);
|
|
+MODULE_PARM_DESC(combined, "Use combined transactions");
|
|
|
|
struct bcm2708_i2c {
|
|
struct i2c_adapter adapter;
|
|
@@ -150,7 +153,7 @@ static inline void bcm2708_bsc_fifo_fill
|
|
static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
|
|
{
|
|
unsigned long bus_hz;
|
|
- u32 cdiv;
|
|
+ u32 cdiv, s;
|
|
u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
|
|
|
|
bus_hz = clk_get_rate(bi->clk);
|
|
@@ -166,6 +169,32 @@ static inline void bcm2708_bsc_setup(str
|
|
bcm2708_wr(bi, BSC_DIV, cdiv);
|
|
bcm2708_wr(bi, BSC_A, bi->msg->addr);
|
|
bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
|
|
+ if (combined)
|
|
+ {
|
|
+ /* Do the next two messages meet combined transaction criteria?
|
|
+ - Current message is a write, next message is a read
|
|
+ - Both messages to same slave address
|
|
+ - Write message can fit inside FIFO (16 bytes or less) */
|
|
+ if ( (bi->nmsgs > 1) &&
|
|
+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
|
|
+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
|
|
+ /* Fill FIFO with entire write message (16 byte FIFO) */
|
|
+ while (bi->pos < bi->msg->len)
|
|
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
|
|
+ /* Start write transfer (no interrupts, don't clear FIFO) */
|
|
+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
|
|
+ /* poll for transfer start bit (should only take 1-20 polls) */
|
|
+ do {
|
|
+ s = bcm2708_rd(bi, BSC_S);
|
|
+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)));
|
|
+ /* Send next read message before the write transfer finishes. */
|
|
+ bi->nmsgs--;
|
|
+ bi->msg++;
|
|
+ bi->pos = 0;
|
|
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
|
|
+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
|
|
+ }
|
|
+ }
|
|
bcm2708_wr(bi, BSC_C, c);
|
|
}
|
|
|