diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 116 |
1 files changed, 75 insertions, 41 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 611b57192c96..d5e12a4f01b0 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -22,10 +22,10 @@ | |||
22 | 22 | ||
23 | /* | 23 | /* |
24 | SUPPORTED DEVICES PCI ID | 24 | SUPPORTED DEVICES PCI ID |
25 | 82801AA 2413 | 25 | 82801AA 2413 |
26 | 82801AB 2423 | 26 | 82801AB 2423 |
27 | 82801BA 2443 | 27 | 82801BA 2443 |
28 | 82801CA/CAM 2483 | 28 | 82801CA/CAM 2483 |
29 | 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) | 29 | 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) |
30 | 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) | 30 | 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) |
31 | 6300ESB 25A4 | 31 | 6300ESB 25A4 |
@@ -74,6 +74,13 @@ | |||
74 | #define SMBHSTCFG_SMB_SMI_EN 2 | 74 | #define SMBHSTCFG_SMB_SMI_EN 2 |
75 | #define SMBHSTCFG_I2C_EN 4 | 75 | #define SMBHSTCFG_I2C_EN 4 |
76 | 76 | ||
77 | /* Auxillary control register bits, ICH4+ only */ | ||
78 | #define SMBAUXCTL_CRC 1 | ||
79 | #define SMBAUXCTL_E32B 2 | ||
80 | |||
81 | /* kill bit for SMBHSTCNT */ | ||
82 | #define SMBHSTCNT_KILL 2 | ||
83 | |||
77 | /* Other settings */ | 84 | /* Other settings */ |
78 | #define MAX_TIMEOUT 100 | 85 | #define MAX_TIMEOUT 100 |
79 | #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ | 86 | #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ |
@@ -91,10 +98,15 @@ | |||
91 | #define I801_START 0x40 | 98 | #define I801_START 0x40 |
92 | #define I801_PEC_EN 0x80 /* ICH4 only */ | 99 | #define I801_PEC_EN 0x80 /* ICH4 only */ |
93 | 100 | ||
94 | 101 | /* I801 Hosts Status register bits */ | |
95 | static int i801_transaction(void); | 102 | #define SMBHSTSTS_BYTE_DONE 0x80 |
96 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | 103 | #define SMBHSTSTS_INUSE_STS 0x40 |
97 | int command, int hwpec); | 104 | #define SMBHSTSTS_SMBALERT_STS 0x20 |
105 | #define SMBHSTSTS_FAILED 0x10 | ||
106 | #define SMBHSTSTS_BUS_ERR 0x08 | ||
107 | #define SMBHSTSTS_DEV_ERR 0x04 | ||
108 | #define SMBHSTSTS_INTR 0x02 | ||
109 | #define SMBHSTSTS_HOST_BUSY 0x01 | ||
98 | 110 | ||
99 | static unsigned long i801_smba; | 111 | static unsigned long i801_smba; |
100 | static unsigned char i801_original_hstcfg; | 112 | static unsigned char i801_original_hstcfg; |
@@ -133,27 +145,32 @@ static int i801_transaction(void) | |||
133 | do { | 145 | do { |
134 | msleep(1); | 146 | msleep(1); |
135 | temp = inb_p(SMBHSTSTS); | 147 | temp = inb_p(SMBHSTSTS); |
136 | } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); | 148 | } while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); |
137 | 149 | ||
138 | /* If the SMBus is still busy, we give up */ | 150 | /* If the SMBus is still busy, we give up */ |
139 | if (timeout >= MAX_TIMEOUT) { | 151 | if (timeout >= MAX_TIMEOUT) { |
140 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | 152 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); |
141 | result = -1; | 153 | result = -1; |
154 | /* try to stop the current command */ | ||
155 | dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); | ||
156 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | ||
157 | msleep(1); | ||
158 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); | ||
142 | } | 159 | } |
143 | 160 | ||
144 | if (temp & 0x10) { | 161 | if (temp & SMBHSTSTS_FAILED) { |
145 | result = -1; | 162 | result = -1; |
146 | dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); | 163 | dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); |
147 | } | 164 | } |
148 | 165 | ||
149 | if (temp & 0x08) { | 166 | if (temp & SMBHSTSTS_BUS_ERR) { |
150 | result = -1; | 167 | result = -1; |
151 | dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " | 168 | dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " |
152 | "until next hard reset. (sorry!)\n"); | 169 | "until next hard reset. (sorry!)\n"); |
153 | /* Clock stops and slave is stuck in mid-transmission */ | 170 | /* Clock stops and slave is stuck in mid-transmission */ |
154 | } | 171 | } |
155 | 172 | ||
156 | if (temp & 0x04) { | 173 | if (temp & SMBHSTSTS_DEV_ERR) { |
157 | result = -1; | 174 | result = -1; |
158 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 175 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); |
159 | } | 176 | } |
@@ -172,6 +189,24 @@ static int i801_transaction(void) | |||
172 | return result; | 189 | return result; |
173 | } | 190 | } |
174 | 191 | ||
192 | /* wait for INTR bit as advised by Intel */ | ||
193 | static void i801_wait_hwpec(void) | ||
194 | { | ||
195 | int timeout = 0; | ||
196 | int temp; | ||
197 | |||
198 | do { | ||
199 | msleep(1); | ||
200 | temp = inb_p(SMBHSTSTS); | ||
201 | } while ((!(temp & SMBHSTSTS_INTR)) | ||
202 | && (timeout++ < MAX_TIMEOUT)); | ||
203 | |||
204 | if (timeout >= MAX_TIMEOUT) { | ||
205 | dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); | ||
206 | } | ||
207 | outb_p(temp, SMBHSTSTS); | ||
208 | } | ||
209 | |||
175 | /* All-inclusive block transaction function */ | 210 | /* All-inclusive block transaction function */ |
176 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | 211 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, |
177 | int command, int hwpec) | 212 | int command, int hwpec) |
@@ -227,13 +262,13 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
227 | /* Make sure the SMBus host is ready to start transmitting */ | 262 | /* Make sure the SMBus host is ready to start transmitting */ |
228 | temp = inb_p(SMBHSTSTS); | 263 | temp = inb_p(SMBHSTSTS); |
229 | if (i == 1) { | 264 | if (i == 1) { |
230 | /* Erronenous conditions before transaction: | 265 | /* Erronenous conditions before transaction: |
231 | * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ | 266 | * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ |
232 | errmask=0x9f; | 267 | errmask = 0x9f; |
233 | } else { | 268 | } else { |
234 | /* Erronenous conditions during transaction: | 269 | /* Erronenous conditions during transaction: |
235 | * Failed, Bus_Err, Dev_Err, Intr */ | 270 | * Failed, Bus_Err, Dev_Err, Intr */ |
236 | errmask=0x1e; | 271 | errmask = 0x1e; |
237 | } | 272 | } |
238 | if (temp & errmask) { | 273 | if (temp & errmask) { |
239 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " | 274 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " |
@@ -243,7 +278,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
243 | dev_err(&I801_dev->dev, | 278 | dev_err(&I801_dev->dev, |
244 | "Reset failed! (%02x)\n", temp); | 279 | "Reset failed! (%02x)\n", temp); |
245 | result = -1; | 280 | result = -1; |
246 | goto END; | 281 | goto END; |
247 | } | 282 | } |
248 | if (i != 1) { | 283 | if (i != 1) { |
249 | /* if die in middle of block transaction, fail */ | 284 | /* if die in middle of block transaction, fail */ |
@@ -261,33 +296,40 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
261 | msleep(1); | 296 | msleep(1); |
262 | temp = inb_p(SMBHSTSTS); | 297 | temp = inb_p(SMBHSTSTS); |
263 | } | 298 | } |
264 | while ((!(temp & 0x80)) | 299 | while ((!(temp & SMBHSTSTS_BYTE_DONE)) |
265 | && (timeout++ < MAX_TIMEOUT)); | 300 | && (timeout++ < MAX_TIMEOUT)); |
266 | 301 | ||
267 | /* If the SMBus is still busy, we give up */ | 302 | /* If the SMBus is still busy, we give up */ |
268 | if (timeout >= MAX_TIMEOUT) { | 303 | if (timeout >= MAX_TIMEOUT) { |
304 | /* try to stop the current command */ | ||
305 | dev_dbg(&I801_dev->dev, "Terminating the current " | ||
306 | "operation\n"); | ||
307 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | ||
308 | msleep(1); | ||
309 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), | ||
310 | SMBHSTCNT); | ||
269 | result = -1; | 311 | result = -1; |
270 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | 312 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); |
271 | } | 313 | } |
272 | 314 | ||
273 | if (temp & 0x10) { | 315 | if (temp & SMBHSTSTS_FAILED) { |
274 | result = -1; | 316 | result = -1; |
275 | dev_dbg(&I801_dev->dev, | 317 | dev_dbg(&I801_dev->dev, |
276 | "Error: Failed bus transaction\n"); | 318 | "Error: Failed bus transaction\n"); |
277 | } else if (temp & 0x08) { | 319 | } else if (temp & SMBHSTSTS_BUS_ERR) { |
278 | result = -1; | 320 | result = -1; |
279 | dev_err(&I801_dev->dev, "Bus collision!\n"); | 321 | dev_err(&I801_dev->dev, "Bus collision!\n"); |
280 | } else if (temp & 0x04) { | 322 | } else if (temp & SMBHSTSTS_DEV_ERR) { |
281 | result = -1; | 323 | result = -1; |
282 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 324 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); |
283 | } | 325 | } |
284 | 326 | ||
285 | if (i == 1 && read_write == I2C_SMBUS_READ) { | 327 | if (i == 1 && read_write == I2C_SMBUS_READ) { |
286 | len = inb_p(SMBHSTDAT0); | 328 | len = inb_p(SMBHSTDAT0); |
287 | if (len < 1) | 329 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { |
288 | len = 1; | 330 | result = -1; |
289 | if (len > 32) | 331 | goto END; |
290 | len = 32; | 332 | } |
291 | data->block[0] = len; | 333 | data->block[0] = len; |
292 | } | 334 | } |
293 | 335 | ||
@@ -313,20 +355,9 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
313 | goto END; | 355 | goto END; |
314 | } | 356 | } |
315 | 357 | ||
316 | if (hwpec) { | 358 | if (hwpec) |
317 | /* wait for INTR bit as advised by Intel */ | 359 | i801_wait_hwpec(); |
318 | timeout = 0; | ||
319 | do { | ||
320 | msleep(1); | ||
321 | temp = inb_p(SMBHSTSTS); | ||
322 | } while ((!(temp & 0x02)) | ||
323 | && (timeout++ < MAX_TIMEOUT)); | ||
324 | 360 | ||
325 | if (timeout >= MAX_TIMEOUT) { | ||
326 | dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); | ||
327 | } | ||
328 | outb_p(temp, SMBHSTSTS); | ||
329 | } | ||
330 | result = 0; | 361 | result = 0; |
331 | END: | 362 | END: |
332 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { | 363 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { |
@@ -393,7 +424,10 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, | |||
393 | return -1; | 424 | return -1; |
394 | } | 425 | } |
395 | 426 | ||
396 | outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ | 427 | if (hwpec) /* enable/disable hardware PEC */ |
428 | outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL); | ||
429 | else | ||
430 | outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); | ||
397 | 431 | ||
398 | if(block) | 432 | if(block) |
399 | ret = i801_block_transaction(data, read_write, size, hwpec); | 433 | ret = i801_block_transaction(data, read_write, size, hwpec); |
@@ -405,7 +439,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, | |||
405 | /* Some BIOSes don't like it when PEC is enabled at reboot or resume | 439 | /* Some BIOSes don't like it when PEC is enabled at reboot or resume |
406 | time, so we forcibly disable it after every transaction. */ | 440 | time, so we forcibly disable it after every transaction. */ |
407 | if (hwpec) | 441 | if (hwpec) |
408 | outb_p(0, SMBAUXCTL); | 442 | outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); |
409 | 443 | ||
410 | if(block) | 444 | if(block) |
411 | return ret; | 445 | return ret; |