aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorFrank Shew <fshew@geometrics.com>2009-05-19 07:23:49 -0400
committerBen Dooks <ben-linux@fluff.org>2009-06-13 05:39:25 -0400
commit94327d009e3aa20214e9dfa486a1fd14445fe736 (patch)
treebb34db58161a22f60c73bcea08fefbde1db6b5a9 /drivers/i2c
parent57a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2 (diff)
i2c: Blackfin TWI: fix transfer errors with repeat start
We have a custom BF537 board with an I2C RTC (MAX DS3231) running uclinux 2007R1 for some time. Recently during migration to 2008R1.5-RC3 we losted access to the RTC. The RTC driver calls 'i2c_transfer()' which in turns calls 'bfin_twi_master_xfer()' in i2c-bfin-twi.c. Compared with 2007R1, it looks like the 2008R1.5 version of i2c-bin-twi.c has a new mode 'TWI_I2C-MODE_REPEAT' which corresponds to the Repeat Start Condition described in the HRM. However, according to the HRM, at XMIT or RECV interrupt and when the data count is 0, not only is the RESTART bit supposed to be set, but MDIR must also be set if the next operation is a receive sequence, and cleared if not. Currently there is no code that looks at the I2C_M_RD bit in the flag from the next cur_msg and set/clear the MDIR flag accordingly at the same time that the RSTART bit is set. Instead, MDIR is set or cleared (by OR'ing with 0?) after the RESTART bit has been cleared during handling of MCOMP interrupt. It appears that this is causing our failure with reading the RTC, as a quick patch to set/clear MDIR when RESTART is set seem to solve our problem. Signed-off-by: Frank Shew <fshew@geometrics.com> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Bryan Wu <cooloney@kernel.org> [ben-linux@fluff.org: shorted subject] Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 4d73ad7b5703..40136ea7a46f 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
104 write_MASTER_CTL(iface, 104 write_MASTER_CTL(iface,
105 read_MASTER_CTL(iface) | STOP); 105 read_MASTER_CTL(iface) | STOP);
106 else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 106 else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
107 iface->cur_msg+1 < iface->msg_num) 107 iface->cur_msg + 1 < iface->msg_num) {
108 write_MASTER_CTL(iface, 108 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
109 read_MASTER_CTL(iface) | RSTART); 109 write_MASTER_CTL(iface,
110 read_MASTER_CTL(iface) | RSTART | MDIR);
111 else
112 write_MASTER_CTL(iface,
113 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
114 }
110 SSYNC(); 115 SSYNC();
111 /* Clear status */ 116 /* Clear status */
112 write_INT_STAT(iface, XMTSERV); 117 write_INT_STAT(iface, XMTSERV);
@@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
134 read_MASTER_CTL(iface) | STOP); 139 read_MASTER_CTL(iface) | STOP);
135 SSYNC(); 140 SSYNC();
136 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 141 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
137 iface->cur_msg+1 < iface->msg_num) { 142 iface->cur_msg + 1 < iface->msg_num) {
138 write_MASTER_CTL(iface, 143 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
139 read_MASTER_CTL(iface) | RSTART); 144 write_MASTER_CTL(iface,
145 read_MASTER_CTL(iface) | RSTART | MDIR);
146 else
147 write_MASTER_CTL(iface,
148 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
140 SSYNC(); 149 SSYNC();
141 } 150 }
142 /* Clear interrupt source */ 151 /* Clear interrupt source */