mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			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);
 | |
|  }
 | |
|  
 |