aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2008-07-14 16:38:33 -0400
committerJean Delvare <khali@mahadeva.delvare>2008-07-14 16:38:33 -0400
commitcf898dc5e9dfd1487b28ca0176b68722f05d4d48 (patch)
tree9369f5cc37f1013058187d79b370541e7ad8dc3e /drivers
parent2b73809d06649fe6c7f4294b051ca4934a34bb91 (diff)
i2c-i801: Fix handling of error conditions
Move the check of pre-transaction and post-transaction conditions to separate functions, and adjust them a bit. Having dedicated functions for that ensures that errors are handled in a consistent way. Bit HOST_BUSY of the status register is read-only, so writing to it is certainly not going to clear it. If this bit is set then we simply don't want to start the transaction, as it means that somebody else (ACPI, SMM?) is already using the controller. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-i801.c200
1 files changed, 102 insertions, 98 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 73bd8552734c..46aa41f73fdd 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -4,7 +4,7 @@
4 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, 4 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
5 Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker 5 Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
6 <mdsxyz123@yahoo.com> 6 <mdsxyz123@yahoo.com>
7 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> 7 Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
8 8
9 This program is free software; you can redistribute it and/or modify 9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by 10 it under the terms of the GNU General Public License as published by
@@ -121,6 +121,10 @@
121#define SMBHSTSTS_INTR 0x02 121#define SMBHSTSTS_INTR 0x02
122#define SMBHSTSTS_HOST_BUSY 0x01 122#define SMBHSTSTS_HOST_BUSY 0x01
123 123
124#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
125 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
126 SMBHSTSTS_INTR)
127
124static unsigned long i801_smba; 128static unsigned long i801_smba;
125static unsigned char i801_original_hstcfg; 129static unsigned char i801_original_hstcfg;
126static struct pci_driver i801_driver; 130static struct pci_driver i801_driver;
@@ -132,72 +136,114 @@ static struct pci_dev *I801_dev;
132#define FEATURE_I2C_BLOCK_READ (1 << 3) 136#define FEATURE_I2C_BLOCK_READ (1 << 3)
133static unsigned int i801_features; 137static unsigned int i801_features;
134 138
135static int i801_transaction(int xact) 139/* Make sure the SMBus host is ready to start transmitting.
140 Return 0 if it is, -EBUSY if it is not. */
141static int i801_check_pre(void)
136{ 142{
137 int status; 143 int status;
138 int result = 0;
139 int timeout = 0;
140 144
141 /* Make sure the SMBus host is ready to start transmitting */ 145 status = inb_p(SMBHSTSTS);
142 /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ 146 if (status & SMBHSTSTS_HOST_BUSY) {
143 if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { 147 dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
144 dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n", 148 return -EBUSY;
149 }
150
151 status &= STATUS_FLAGS;
152 if (status) {
153 dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
145 status); 154 status);
146 outb_p(status, SMBHSTSTS); 155 outb_p(status, SMBHSTSTS);
147 if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { 156 status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
148 dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", status); 157 if (status) {
158 dev_err(&I801_dev->dev,
159 "Failed clearing status flags (%02x)\n",
160 status);
149 return -EBUSY; 161 return -EBUSY;
150 } else {
151 dev_dbg(&I801_dev->dev, "Successful!\n");
152 } 162 }
153 } 163 }
154 164
155 /* the current contents of SMBHSTCNT can be overwritten, since PEC, 165 return 0;
156 * INTREN, SMBSCMD are passed in xact */ 166}
157 outb_p(xact | I801_START, SMBHSTCNT);
158 167
159 /* We will always wait for a fraction of a second! */ 168/* Convert the status register to an error code, and clear it. */
160 do { 169static int i801_check_post(int status, int timeout)
161 msleep(1); 170{
162 status = inb_p(SMBHSTSTS); 171 int result = 0;
163 } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
164 172
165 /* If the SMBus is still busy, we give up */ 173 /* If the SMBus is still busy, we give up */
166 if (timeout >= MAX_TIMEOUT) { 174 if (timeout) {
167 dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); 175 dev_err(&I801_dev->dev, "Transaction timeout\n");
168 result = -ETIMEDOUT;
169 /* try to stop the current command */ 176 /* try to stop the current command */
170 dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); 177 dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
171 outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); 178 outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
172 msleep(1); 179 msleep(1);
173 outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); 180 outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
181
182 /* Check if it worked */
183 status = inb_p(SMBHSTSTS);
184 if ((status & SMBHSTSTS_HOST_BUSY) ||
185 !(status & SMBHSTSTS_FAILED))
186 dev_err(&I801_dev->dev,
187 "Failed terminating the transaction\n");
188 outb_p(STATUS_FLAGS, SMBHSTSTS);
189 return -ETIMEDOUT;
174 } 190 }
175 191
176 if (status & SMBHSTSTS_FAILED) { 192 if (status & SMBHSTSTS_FAILED) {
177 result = -EIO; 193 result = -EIO;
178 dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); 194 dev_err(&I801_dev->dev, "Transaction failed\n");
195 }
196 if (status & SMBHSTSTS_DEV_ERR) {
197 result = -ENXIO;
198 dev_dbg(&I801_dev->dev, "No response\n");
179 } 199 }
180
181 if (status & SMBHSTSTS_BUS_ERR) { 200 if (status & SMBHSTSTS_BUS_ERR) {
182 result = -EAGAIN; 201 result = -EAGAIN;
183 dev_dbg(&I801_dev->dev, "Lost arbitration\n"); 202 dev_dbg(&I801_dev->dev, "Lost arbitration\n");
184 } 203 }
185 204
186 if (status & SMBHSTSTS_DEV_ERR) { 205 if (result) {
187 result = -ENXIO; 206 /* Clear error flags */
188 dev_dbg(&I801_dev->dev, "Error: no response!\n"); 207 outb_p(status & STATUS_FLAGS, SMBHSTSTS);
208 status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
209 if (status) {
210 dev_warn(&I801_dev->dev, "Failed clearing status "
211 "flags at end of transaction (%02x)\n",
212 status);
213 }
189 } 214 }
190 215
191 if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
192 outb_p(inb(SMBHSTSTS), SMBHSTSTS);
193
194 if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
195 dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
196 "(%02x)\n", status);
197 }
198 return result; 216 return result;
199} 217}
200 218
219static int i801_transaction(int xact)
220{
221 int status;
222 int result;
223 int timeout = 0;
224
225 result = i801_check_pre();
226 if (result < 0)
227 return result;
228
229 /* the current contents of SMBHSTCNT can be overwritten, since PEC,
230 * INTREN, SMBSCMD are passed in xact */
231 outb_p(xact | I801_START, SMBHSTCNT);
232
233 /* We will always wait for a fraction of a second! */
234 do {
235 msleep(1);
236 status = inb_p(SMBHSTSTS);
237 } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
238
239 result = i801_check_post(status, timeout >= MAX_TIMEOUT);
240 if (result < 0)
241 return result;
242
243 outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
244 return 0;
245}
246
201/* wait for INTR bit as advised by Intel */ 247/* wait for INTR bit as advised by Intel */
202static void i801_wait_hwpec(void) 248static void i801_wait_hwpec(void)
203{ 249{
@@ -256,9 +302,12 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
256 int i, len; 302 int i, len;
257 int smbcmd; 303 int smbcmd;
258 int status; 304 int status;
259 int result = 0; 305 int result;
260 int timeout; 306 int timeout;
261 unsigned char errmask; 307
308 result = i801_check_pre();
309 if (result < 0)
310 return result;
262 311
263 len = data->block[0]; 312 len = data->block[0];
264 313
@@ -282,31 +331,6 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
282 } 331 }
283 outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); 332 outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
284 333
285 /* Make sure the SMBus host is ready to start transmitting */
286 status = inb_p(SMBHSTSTS);
287 if (i == 1) {
288 /* Erroneous conditions before transaction:
289 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
290 errmask = 0x9f;
291 } else {
292 /* Erroneous conditions during transaction:
293 * Failed, Bus_Err, Dev_Err, Intr */
294 errmask = 0x1e;
295 }
296 if (status & errmask) {
297 dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
298 "Resetting...\n", status);
299 outb_p(status, SMBHSTSTS);
300 if (((status = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
301 dev_err(&I801_dev->dev,
302 "Reset failed! (%02x)\n", status);
303 return -EBUSY;
304 }
305 if (i != 1)
306 /* if die in middle of block transaction, fail */
307 return -EIO;
308 }
309
310 if (i == 1) 334 if (i == 1)
311 outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); 335 outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
312 336
@@ -319,36 +343,23 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
319 while ((!(status & SMBHSTSTS_BYTE_DONE)) 343 while ((!(status & SMBHSTSTS_BYTE_DONE))
320 && (timeout++ < MAX_TIMEOUT)); 344 && (timeout++ < MAX_TIMEOUT));
321 345
322 /* If the SMBus is still busy, we give up */ 346 result = i801_check_post(status, timeout >= MAX_TIMEOUT);
323 if (timeout >= MAX_TIMEOUT) { 347 if (result < 0)
324 /* try to stop the current command */ 348 return result;
325 dev_dbg(&I801_dev->dev, "Terminating the current "
326 "operation\n");
327 outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
328 msleep(1);
329 outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL),
330 SMBHSTCNT);
331 result = -ETIMEDOUT;
332 dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
333 }
334
335 if (status & SMBHSTSTS_FAILED) {
336 result = -EIO;
337 dev_dbg(&I801_dev->dev,
338 "Error: Failed bus transaction\n");
339 } else if (status & SMBHSTSTS_BUS_ERR) {
340 result = -EAGAIN;
341 dev_dbg(&I801_dev->dev, "Lost arbitration\n");
342 } else if (status & SMBHSTSTS_DEV_ERR) {
343 result = -ENXIO;
344 dev_dbg(&I801_dev->dev, "Error: no response!\n");
345 }
346 349
347 if (i == 1 && read_write == I2C_SMBUS_READ 350 if (i == 1 && read_write == I2C_SMBUS_READ
348 && command != I2C_SMBUS_I2C_BLOCK_DATA) { 351 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
349 len = inb_p(SMBHSTDAT0); 352 len = inb_p(SMBHSTDAT0);
350 if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) 353 if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
354 dev_err(&I801_dev->dev,
355 "Illegal SMBus block read size %d\n",
356 len);
357 /* Recover */
358 while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
359 outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
360 outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
351 return -EPROTO; 361 return -EPROTO;
362 }
352 data->block[0] = len; 363 data->block[0] = len;
353 } 364 }
354 365
@@ -357,19 +368,12 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
357 data->block[i] = inb_p(SMBBLKDAT); 368 data->block[i] = inb_p(SMBBLKDAT);
358 if (read_write == I2C_SMBUS_WRITE && i+1 <= len) 369 if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
359 outb_p(data->block[i+1], SMBBLKDAT); 370 outb_p(data->block[i+1], SMBBLKDAT);
360 if ((status & 0x9e) != 0x00)
361 outb_p(status, SMBHSTSTS); /* signals SMBBLKDAT ready */
362 371
363 if ((status = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { 372 /* signals SMBBLKDAT ready */
364 dev_dbg(&I801_dev->dev, 373 outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
365 "Bad status (%02x) at end of transaction\n",
366 status);
367 }
368
369 if (result < 0)
370 return result;
371 } 374 }
372 return result; 375
376 return 0;
373} 377}
374 378
375static int i801_set_block_buffer_mode(void) 379static int i801_set_block_buffer_mode(void)