aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorManuel Lauss <mano@roarinelk.homelinux.net>2008-01-27 12:14:52 -0500
committerJean Delvare <khali@hyperion.delvare>2008-01-27 12:14:52 -0500
commit91f27958d686da713c3b0a1dc205288898e44124 (patch)
treeb59d826d3972f8cc58e587b437e4993bfe7da2b8 /drivers/i2c
parent4bd28ebda2d48f16c1f16ff936a6927a4ef2194d (diff)
i2c-au1550: properly terminate zero-byte transfers
Zero-bytes transfers would leave the bus transaction unfinished (no i2c stop is sent), with the following transfer actually sending the slave address to the previously addressed device, resulting in weird device failures (e.g. reset minute register values in my RTC). This patch instructs the controller to send an I2C STOP right after the slave address in case of a zero-byte transfer. Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-au1550.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 2f684166c43d..7d51a43b38d3 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -105,7 +105,7 @@ wait_master_done(struct i2c_au1550_data *adap)
105} 105}
106 106
107static int 107static int
108do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) 108do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
109{ 109{
110 volatile psc_smb_t *sp; 110 volatile psc_smb_t *sp;
111 u32 stat; 111 u32 stat;
@@ -134,6 +134,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
134 if (rd) 134 if (rd)
135 addr |= 1; 135 addr |= 1;
136 136
137 /* zero-byte xfers stop immediately */
138 if (q)
139 addr |= PSC_SMBTXRX_STP;
140
137 /* Put byte into fifo, start up master. 141 /* Put byte into fifo, start up master.
138 */ 142 */
139 sp->psc_smbtxrx = addr; 143 sp->psc_smbtxrx = addr;
@@ -142,7 +146,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
142 au_sync(); 146 au_sync();
143 if (wait_ack(adap)) 147 if (wait_ack(adap))
144 return -EIO; 148 return -EIO;
145 return 0; 149 return (q) ? wait_master_done(adap) : 0;
146} 150}
147 151
148static u32 152static u32
@@ -262,7 +266,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
262 266
263 for (i = 0; !err && i < num; i++) { 267 for (i = 0; !err && i < num; i++) {
264 p = &msgs[i]; 268 p = &msgs[i];
265 err = do_address(adap, p->addr, p->flags & I2C_M_RD); 269 err = do_address(adap, p->addr, p->flags & I2C_M_RD,
270 (p->len == 0));
266 if (err || !p->len) 271 if (err || !p->len)
267 continue; 272 continue;
268 if (p->flags & I2C_M_RD) 273 if (p->flags & I2C_M_RD)