aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/scx200_acb.c
diff options
context:
space:
mode:
authorJordan Crouse <jordan.crouse@amd.com>2006-04-28 16:53:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-05-09 16:04:21 -0400
commit95563d343fec8d3e2f667c95230ac4ab7674b757 (patch)
tree4e0c4f18ff45abe5f691f860633ed0a6bfbcd65b /drivers/i2c/busses/scx200_acb.c
parentb33d0798e6cfae1fcee75afc808fe5690a48a814 (diff)
[PATCH] scx200_acb: Fix for the CS5535 errata
This is a fix for the CS5535 errata 111: When the SMBus controller tries to access a non-existing device, it sets the NEGACK bit, SMBus I/O offset 01h[4], to 1 after it detects no acknowledge at the ninth clock. The specification states that the bit can be cleared by writing a 1 to it, but under certain circumstances it is possible for this bit to not clear. Writing a 0 to the bit resets the internal state machine and clears the issue. Since all writable bits in ACBST are W1C bits (write-one-to-clear) the second write doesn't affect any other logic except the buggy NEGACK state machine. The second write clears an internal register which is responsible for "overwriting" the NEGACK bit in ACBST. Signed-off-by: Jordan Crouse <jordan.crouse@amd.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/i2c/busses/scx200_acb.c')
-rw-r--r--drivers/i2c/busses/scx200_acb.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 42e4e00d6c3..a140e4536a4 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -133,6 +133,9 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
133 133
134 outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); 134 outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
135 outb(ACBST_STASTR | ACBST_NEGACK, ACBST); 135 outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
136
137 /* Reset the status register */
138 outb(0, ACBST);
136 return; 139 return;
137 } 140 }
138 141
@@ -228,6 +231,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface)
228 timeout = jiffies + POLL_TIMEOUT; 231 timeout = jiffies + POLL_TIMEOUT;
229 while (time_before(jiffies, timeout)) { 232 while (time_before(jiffies, timeout)) {
230 status = inb(ACBST); 233 status = inb(ACBST);
234
235 /* Reset the status register to avoid the hang */
236 outb(0, ACBST);
237
231 if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) { 238 if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
232 scx200_acb_machine(iface, status); 239 scx200_acb_machine(iface, status);
233 return; 240 return;