diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 249 |
1 files changed, 166 insertions, 83 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 611b57192c96..8f5c686123b8 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -22,12 +22,12 @@ | |||
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) |
30 | 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) | 30 | 82801EB 24D3 (HW PEC supported) |
31 | 6300ESB 25A4 | 31 | 6300ESB 25A4 |
32 | ICH6 266A | 32 | ICH6 266A |
33 | ICH7 27DA | 33 | ICH7 27DA |
@@ -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; |
@@ -102,7 +114,7 @@ static struct pci_driver i801_driver; | |||
102 | static struct pci_dev *I801_dev; | 114 | static struct pci_dev *I801_dev; |
103 | static int isich4; | 115 | static int isich4; |
104 | 116 | ||
105 | static int i801_transaction(void) | 117 | static int i801_transaction(int xact) |
106 | { | 118 | { |
107 | int temp; | 119 | int temp; |
108 | int result = 0; | 120 | int result = 0; |
@@ -127,33 +139,40 @@ static int i801_transaction(void) | |||
127 | } | 139 | } |
128 | } | 140 | } |
129 | 141 | ||
130 | outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); | 142 | /* the current contents of SMBHSTCNT can be overwritten, since PEC, |
143 | * INTREN, SMBSCMD are passed in xact */ | ||
144 | outb_p(xact | I801_START, SMBHSTCNT); | ||
131 | 145 | ||
132 | /* We will always wait for a fraction of a second! */ | 146 | /* We will always wait for a fraction of a second! */ |
133 | do { | 147 | do { |
134 | msleep(1); | 148 | msleep(1); |
135 | temp = inb_p(SMBHSTSTS); | 149 | temp = inb_p(SMBHSTSTS); |
136 | } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); | 150 | } while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); |
137 | 151 | ||
138 | /* If the SMBus is still busy, we give up */ | 152 | /* If the SMBus is still busy, we give up */ |
139 | if (timeout >= MAX_TIMEOUT) { | 153 | if (timeout >= MAX_TIMEOUT) { |
140 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | 154 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); |
141 | result = -1; | 155 | result = -1; |
156 | /* try to stop the current command */ | ||
157 | dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); | ||
158 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | ||
159 | msleep(1); | ||
160 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); | ||
142 | } | 161 | } |
143 | 162 | ||
144 | if (temp & 0x10) { | 163 | if (temp & SMBHSTSTS_FAILED) { |
145 | result = -1; | 164 | result = -1; |
146 | dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); | 165 | dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); |
147 | } | 166 | } |
148 | 167 | ||
149 | if (temp & 0x08) { | 168 | if (temp & SMBHSTSTS_BUS_ERR) { |
150 | result = -1; | 169 | result = -1; |
151 | dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " | 170 | dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " |
152 | "until next hard reset. (sorry!)\n"); | 171 | "until next hard reset. (sorry!)\n"); |
153 | /* Clock stops and slave is stuck in mid-transmission */ | 172 | /* Clock stops and slave is stuck in mid-transmission */ |
154 | } | 173 | } |
155 | 174 | ||
156 | if (temp & 0x04) { | 175 | if (temp & SMBHSTSTS_DEV_ERR) { |
157 | result = -1; | 176 | result = -1; |
158 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 177 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); |
159 | } | 178 | } |
@@ -172,44 +191,70 @@ static int i801_transaction(void) | |||
172 | return result; | 191 | return result; |
173 | } | 192 | } |
174 | 193 | ||
175 | /* All-inclusive block transaction function */ | 194 | /* wait for INTR bit as advised by Intel */ |
176 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | 195 | static void i801_wait_hwpec(void) |
177 | int command, int hwpec) | 196 | { |
197 | int timeout = 0; | ||
198 | int temp; | ||
199 | |||
200 | do { | ||
201 | msleep(1); | ||
202 | temp = inb_p(SMBHSTSTS); | ||
203 | } while ((!(temp & SMBHSTSTS_INTR)) | ||
204 | && (timeout++ < MAX_TIMEOUT)); | ||
205 | |||
206 | if (timeout >= MAX_TIMEOUT) { | ||
207 | dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); | ||
208 | } | ||
209 | outb_p(temp, SMBHSTSTS); | ||
210 | } | ||
211 | |||
212 | static int i801_block_transaction_by_block(union i2c_smbus_data *data, | ||
213 | char read_write, int hwpec) | ||
214 | { | ||
215 | int i, len; | ||
216 | |||
217 | inb_p(SMBHSTCNT); /* reset the data buffer index */ | ||
218 | |||
219 | /* Use 32-byte buffer to process this transaction */ | ||
220 | if (read_write == I2C_SMBUS_WRITE) { | ||
221 | len = data->block[0]; | ||
222 | outb_p(len, SMBHSTDAT0); | ||
223 | for (i = 0; i < len; i++) | ||
224 | outb_p(data->block[i+1], SMBBLKDAT); | ||
225 | } | ||
226 | |||
227 | if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 | | ||
228 | I801_PEC_EN * hwpec)) | ||
229 | return -1; | ||
230 | |||
231 | if (read_write == I2C_SMBUS_READ) { | ||
232 | len = inb_p(SMBHSTDAT0); | ||
233 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) | ||
234 | return -1; | ||
235 | |||
236 | data->block[0] = len; | ||
237 | for (i = 0; i < len; i++) | ||
238 | data->block[i + 1] = inb_p(SMBBLKDAT); | ||
239 | } | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | ||
244 | char read_write, int hwpec) | ||
178 | { | 245 | { |
179 | int i, len; | 246 | int i, len; |
180 | int smbcmd; | 247 | int smbcmd; |
181 | int temp; | 248 | int temp; |
182 | int result = 0; | 249 | int result = 0; |
183 | int timeout; | 250 | int timeout; |
184 | unsigned char hostc, errmask; | 251 | unsigned char errmask; |
185 | 252 | ||
186 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { | 253 | len = data->block[0]; |
187 | if (read_write == I2C_SMBUS_WRITE) { | ||
188 | /* set I2C_EN bit in configuration register */ | ||
189 | pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); | ||
190 | pci_write_config_byte(I801_dev, SMBHSTCFG, | ||
191 | hostc | SMBHSTCFG_I2C_EN); | ||
192 | } else { | ||
193 | dev_err(&I801_dev->dev, | ||
194 | "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); | ||
195 | return -1; | ||
196 | } | ||
197 | } | ||
198 | 254 | ||
199 | if (read_write == I2C_SMBUS_WRITE) { | 255 | if (read_write == I2C_SMBUS_WRITE) { |
200 | len = data->block[0]; | ||
201 | if (len < 1) | ||
202 | len = 1; | ||
203 | if (len > 32) | ||
204 | len = 32; | ||
205 | outb_p(len, SMBHSTDAT0); | 256 | outb_p(len, SMBHSTDAT0); |
206 | outb_p(data->block[1], SMBBLKDAT); | 257 | outb_p(data->block[1], SMBBLKDAT); |
207 | } else { | ||
208 | len = 32; /* max for reads */ | ||
209 | } | ||
210 | |||
211 | if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) { | ||
212 | /* set 32 byte buffer */ | ||
213 | } | 258 | } |
214 | 259 | ||
215 | for (i = 1; i <= len; i++) { | 260 | for (i = 1; i <= len; i++) { |
@@ -227,13 +272,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 */ | 272 | /* Make sure the SMBus host is ready to start transmitting */ |
228 | temp = inb_p(SMBHSTSTS); | 273 | temp = inb_p(SMBHSTSTS); |
229 | if (i == 1) { | 274 | if (i == 1) { |
230 | /* Erronenous conditions before transaction: | 275 | /* Erronenous conditions before transaction: |
231 | * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ | 276 | * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ |
232 | errmask=0x9f; | 277 | errmask = 0x9f; |
233 | } else { | 278 | } else { |
234 | /* Erronenous conditions during transaction: | 279 | /* Erronenous conditions during transaction: |
235 | * Failed, Bus_Err, Dev_Err, Intr */ | 280 | * Failed, Bus_Err, Dev_Err, Intr */ |
236 | errmask=0x1e; | 281 | errmask = 0x1e; |
237 | } | 282 | } |
238 | if (temp & errmask) { | 283 | if (temp & errmask) { |
239 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " | 284 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " |
@@ -242,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
242 | if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { | 287 | if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { |
243 | dev_err(&I801_dev->dev, | 288 | dev_err(&I801_dev->dev, |
244 | "Reset failed! (%02x)\n", temp); | 289 | "Reset failed! (%02x)\n", temp); |
245 | result = -1; | 290 | return -1; |
246 | goto END; | ||
247 | } | 291 | } |
248 | if (i != 1) { | 292 | if (i != 1) |
249 | /* if die in middle of block transaction, fail */ | 293 | /* if die in middle of block transaction, fail */ |
250 | result = -1; | 294 | return -1; |
251 | goto END; | ||
252 | } | ||
253 | } | 295 | } |
254 | 296 | ||
255 | if (i == 1) | 297 | if (i == 1) |
@@ -261,33 +303,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
261 | msleep(1); | 303 | msleep(1); |
262 | temp = inb_p(SMBHSTSTS); | 304 | temp = inb_p(SMBHSTSTS); |
263 | } | 305 | } |
264 | while ((!(temp & 0x80)) | 306 | while ((!(temp & SMBHSTSTS_BYTE_DONE)) |
265 | && (timeout++ < MAX_TIMEOUT)); | 307 | && (timeout++ < MAX_TIMEOUT)); |
266 | 308 | ||
267 | /* If the SMBus is still busy, we give up */ | 309 | /* If the SMBus is still busy, we give up */ |
268 | if (timeout >= MAX_TIMEOUT) { | 310 | if (timeout >= MAX_TIMEOUT) { |
311 | /* try to stop the current command */ | ||
312 | dev_dbg(&I801_dev->dev, "Terminating the current " | ||
313 | "operation\n"); | ||
314 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | ||
315 | msleep(1); | ||
316 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), | ||
317 | SMBHSTCNT); | ||
269 | result = -1; | 318 | result = -1; |
270 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | 319 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); |
271 | } | 320 | } |
272 | 321 | ||
273 | if (temp & 0x10) { | 322 | if (temp & SMBHSTSTS_FAILED) { |
274 | result = -1; | 323 | result = -1; |
275 | dev_dbg(&I801_dev->dev, | 324 | dev_dbg(&I801_dev->dev, |
276 | "Error: Failed bus transaction\n"); | 325 | "Error: Failed bus transaction\n"); |
277 | } else if (temp & 0x08) { | 326 | } else if (temp & SMBHSTSTS_BUS_ERR) { |
278 | result = -1; | 327 | result = -1; |
279 | dev_err(&I801_dev->dev, "Bus collision!\n"); | 328 | dev_err(&I801_dev->dev, "Bus collision!\n"); |
280 | } else if (temp & 0x04) { | 329 | } else if (temp & SMBHSTSTS_DEV_ERR) { |
281 | result = -1; | 330 | result = -1; |
282 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 331 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); |
283 | } | 332 | } |
284 | 333 | ||
285 | if (i == 1 && read_write == I2C_SMBUS_READ) { | 334 | if (i == 1 && read_write == I2C_SMBUS_READ) { |
286 | len = inb_p(SMBHSTDAT0); | 335 | len = inb_p(SMBHSTDAT0); |
287 | if (len < 1) | 336 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) |
288 | len = 1; | 337 | return -1; |
289 | if (len > 32) | ||
290 | len = 32; | ||
291 | data->block[0] = len; | 338 | data->block[0] = len; |
292 | } | 339 | } |
293 | 340 | ||
@@ -310,25 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
310 | inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); | 357 | inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); |
311 | 358 | ||
312 | if (result < 0) | 359 | if (result < 0) |
313 | goto END; | 360 | return result; |
314 | } | 361 | } |
362 | return result; | ||
363 | } | ||
315 | 364 | ||
316 | if (hwpec) { | 365 | static int i801_set_block_buffer_mode(void) |
317 | /* wait for INTR bit as advised by Intel */ | 366 | { |
318 | timeout = 0; | 367 | outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL); |
319 | do { | 368 | if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0) |
320 | msleep(1); | 369 | return -1; |
321 | temp = inb_p(SMBHSTSTS); | 370 | return 0; |
322 | } while ((!(temp & 0x02)) | 371 | } |
323 | && (timeout++ < MAX_TIMEOUT)); | ||
324 | 372 | ||
325 | if (timeout >= MAX_TIMEOUT) { | 373 | /* Block transaction function */ |
326 | dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); | 374 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, |
375 | int command, int hwpec) | ||
376 | { | ||
377 | int result = 0; | ||
378 | unsigned char hostc; | ||
379 | |||
380 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { | ||
381 | if (read_write == I2C_SMBUS_WRITE) { | ||
382 | /* set I2C_EN bit in configuration register */ | ||
383 | pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); | ||
384 | pci_write_config_byte(I801_dev, SMBHSTCFG, | ||
385 | hostc | SMBHSTCFG_I2C_EN); | ||
386 | } else { | ||
387 | dev_err(&I801_dev->dev, | ||
388 | "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); | ||
389 | return -1; | ||
327 | } | 390 | } |
328 | outb_p(temp, SMBHSTSTS); | ||
329 | } | 391 | } |
330 | result = 0; | 392 | |
331 | END: | 393 | if (read_write == I2C_SMBUS_WRITE) { |
394 | if (data->block[0] < 1) | ||
395 | data->block[0] = 1; | ||
396 | if (data->block[0] > I2C_SMBUS_BLOCK_MAX) | ||
397 | data->block[0] = I2C_SMBUS_BLOCK_MAX; | ||
398 | } else { | ||
399 | data->block[0] = 32; /* max for reads */ | ||
400 | } | ||
401 | |||
402 | if (isich4 && i801_set_block_buffer_mode() == 0 ) | ||
403 | result = i801_block_transaction_by_block(data, read_write, | ||
404 | hwpec); | ||
405 | else | ||
406 | result = i801_block_transaction_byte_by_byte(data, read_write, | ||
407 | hwpec); | ||
408 | |||
409 | if (result == 0 && hwpec) | ||
410 | i801_wait_hwpec(); | ||
411 | |||
332 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { | 412 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { |
333 | /* restore saved configuration register value */ | 413 | /* restore saved configuration register value */ |
334 | pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); | 414 | pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); |
@@ -393,19 +473,22 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, | |||
393 | return -1; | 473 | return -1; |
394 | } | 474 | } |
395 | 475 | ||
396 | outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ | 476 | if (hwpec) /* enable/disable hardware PEC */ |
477 | outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL); | ||
478 | else | ||
479 | outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); | ||
397 | 480 | ||
398 | if(block) | 481 | if(block) |
399 | ret = i801_block_transaction(data, read_write, size, hwpec); | 482 | ret = i801_block_transaction(data, read_write, size, hwpec); |
400 | else { | 483 | else |
401 | outb_p(xact | ENABLE_INT9, SMBHSTCNT); | 484 | ret = i801_transaction(xact | ENABLE_INT9); |
402 | ret = i801_transaction(); | ||
403 | } | ||
404 | 485 | ||
405 | /* Some BIOSes don't like it when PEC is enabled at reboot or resume | 486 | /* Some BIOSes don't like it when PEC is enabled at reboot or resume |
406 | time, so we forcibly disable it after every transaction. */ | 487 | time, so we forcibly disable it after every transaction. Turn off |
488 | E32B for the same reason. */ | ||
407 | if (hwpec) | 489 | if (hwpec) |
408 | outb_p(0, SMBAUXCTL); | 490 | outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), |
491 | SMBAUXCTL); | ||
409 | 492 | ||
410 | if(block) | 493 | if(block) |
411 | return ret; | 494 | return ret; |