diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 200 |
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 | |||
124 | static unsigned long i801_smba; | 128 | static unsigned long i801_smba; |
125 | static unsigned char i801_original_hstcfg; | 129 | static unsigned char i801_original_hstcfg; |
126 | static struct pci_driver i801_driver; | 130 | static 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) |
133 | static unsigned int i801_features; | 137 | static unsigned int i801_features; |
134 | 138 | ||
135 | static 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. */ | ||
141 | static 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 { | 169 | static 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 | ||
219 | static 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 */ |
202 | static void i801_wait_hwpec(void) | 248 | static 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 | ||
375 | static int i801_set_block_buffer_mode(void) | 379 | static int i801_set_block_buffer_mode(void) |