diff options
author | Jean Delvare <khali@linux-fr.org> | 2008-01-27 12:14:50 -0500 |
---|---|---|
committer | Jean Delvare <khali@hyperion.delvare> | 2008-01-27 12:14:50 -0500 |
commit | 6342064cad7a28d10504128d028bc4ba379d489d (patch) | |
tree | c8a8b21672b5a09f0f357eb65ad4be08bfdde4ca /drivers | |
parent | a0921b6c07dfbb59ac2d497e96438adaf4940f16 (diff) |
i2c-i801: Implement I2C block read support
I2C block read is supported since the ICH5. I couldn't get it to work
using the block buffer, so it's using the old-style byte-by-byte mode
for now.
Note: I'm also updating the driver author... The i2c-i801 driver was
really written by Mark Studebaker, even though he based his work on
the i2c-piix4 driver which was written by Philip Edelbrock.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 0b1b1ae5e228..aa9157913b9a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -4,6 +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 | 8 | ||
8 | 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 |
9 | 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 |
@@ -46,7 +47,7 @@ | |||
46 | Hardware PEC yes | 47 | Hardware PEC yes |
47 | Block buffer yes | 48 | Block buffer yes |
48 | Block process call transaction no | 49 | Block process call transaction no |
49 | I2C block read transaction no | 50 | I2C block read transaction yes (doesn't use the block buffer) |
50 | 51 | ||
51 | See the file Documentation/i2c/busses/i2c-i801 for details. | 52 | See the file Documentation/i2c/busses/i2c-i801 for details. |
52 | */ | 53 | */ |
@@ -102,9 +103,9 @@ | |||
102 | #define I801_WORD_DATA 0x0C | 103 | #define I801_WORD_DATA 0x0C |
103 | #define I801_PROC_CALL 0x10 /* unimplemented */ | 104 | #define I801_PROC_CALL 0x10 /* unimplemented */ |
104 | #define I801_BLOCK_DATA 0x14 | 105 | #define I801_BLOCK_DATA 0x14 |
105 | #define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ | 106 | #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ |
106 | #define I801_BLOCK_LAST 0x34 | 107 | #define I801_BLOCK_LAST 0x34 |
107 | #define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ | 108 | #define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ |
108 | #define I801_START 0x40 | 109 | #define I801_START 0x40 |
109 | #define I801_PEC_EN 0x80 /* ICH3 and later */ | 110 | #define I801_PEC_EN 0x80 /* ICH3 and later */ |
110 | 111 | ||
@@ -256,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data, | |||
256 | } | 257 | } |
257 | 258 | ||
258 | static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | 259 | static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, |
259 | char read_write, int hwpec) | 260 | char read_write, int command, |
261 | int hwpec) | ||
260 | { | 262 | { |
261 | int i, len; | 263 | int i, len; |
262 | int smbcmd; | 264 | int smbcmd; |
@@ -273,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
273 | } | 275 | } |
274 | 276 | ||
275 | for (i = 1; i <= len; i++) { | 277 | for (i = 1; i <= len; i++) { |
276 | if (i == len && read_write == I2C_SMBUS_READ) | 278 | if (i == len && read_write == I2C_SMBUS_READ) { |
277 | smbcmd = I801_BLOCK_LAST; | 279 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) |
278 | else | 280 | smbcmd = I801_I2C_BLOCK_LAST; |
279 | smbcmd = I801_BLOCK_DATA; | 281 | else |
282 | smbcmd = I801_BLOCK_LAST; | ||
283 | } else { | ||
284 | if (command == I2C_SMBUS_I2C_BLOCK_DATA | ||
285 | && read_write == I2C_SMBUS_READ) | ||
286 | smbcmd = I801_I2C_BLOCK_DATA; | ||
287 | else | ||
288 | smbcmd = I801_BLOCK_DATA; | ||
289 | } | ||
280 | outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); | 290 | outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); |
281 | 291 | ||
282 | dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " | 292 | dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " |
283 | "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, | 293 | "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, |
284 | inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), | 294 | inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), |
285 | inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); | 295 | inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); |
286 | 296 | ||
287 | /* Make sure the SMBus host is ready to start transmitting */ | 297 | /* Make sure the SMBus host is ready to start transmitting */ |
288 | temp = inb_p(SMBHSTSTS); | 298 | temp = inb_p(SMBHSTSTS); |
@@ -346,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
346 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 356 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); |
347 | } | 357 | } |
348 | 358 | ||
349 | if (i == 1 && read_write == I2C_SMBUS_READ) { | 359 | if (i == 1 && read_write == I2C_SMBUS_READ |
360 | && command != I2C_SMBUS_I2C_BLOCK_DATA) { | ||
350 | len = inb_p(SMBHSTDAT0); | 361 | len = inb_p(SMBHSTDAT0); |
351 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) | 362 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) |
352 | return -1; | 363 | return -1; |
@@ -367,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
367 | temp); | 378 | temp); |
368 | } | 379 | } |
369 | dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " | 380 | dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " |
370 | "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, | 381 | "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, |
371 | inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), | 382 | inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), |
372 | inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); | 383 | inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); |
373 | 384 | ||
374 | if (result < 0) | 385 | if (result < 0) |
375 | return result; | 386 | return result; |
@@ -398,34 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
398 | pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); | 409 | pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); |
399 | pci_write_config_byte(I801_dev, SMBHSTCFG, | 410 | pci_write_config_byte(I801_dev, SMBHSTCFG, |
400 | hostc | SMBHSTCFG_I2C_EN); | 411 | hostc | SMBHSTCFG_I2C_EN); |
401 | } else { | 412 | } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) { |
402 | dev_err(&I801_dev->dev, | 413 | dev_err(&I801_dev->dev, |
403 | "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); | 414 | "I2C block read is unsupported!\n"); |
404 | return -1; | 415 | return -1; |
405 | } | 416 | } |
406 | } | 417 | } |
407 | 418 | ||
408 | if (read_write == I2C_SMBUS_WRITE) { | 419 | if (read_write == I2C_SMBUS_WRITE |
420 | || command == I2C_SMBUS_I2C_BLOCK_DATA) { | ||
409 | if (data->block[0] < 1) | 421 | if (data->block[0] < 1) |
410 | data->block[0] = 1; | 422 | data->block[0] = 1; |
411 | if (data->block[0] > I2C_SMBUS_BLOCK_MAX) | 423 | if (data->block[0] > I2C_SMBUS_BLOCK_MAX) |
412 | data->block[0] = I2C_SMBUS_BLOCK_MAX; | 424 | data->block[0] = I2C_SMBUS_BLOCK_MAX; |
413 | } else { | 425 | } else { |
414 | data->block[0] = 32; /* max for reads */ | 426 | data->block[0] = 32; /* max for SMBus block reads */ |
415 | } | 427 | } |
416 | 428 | ||
417 | if ((i801_features & FEATURE_BLOCK_BUFFER) | 429 | if ((i801_features & FEATURE_BLOCK_BUFFER) |
430 | && !(command == I2C_SMBUS_I2C_BLOCK_DATA | ||
431 | && read_write == I2C_SMBUS_READ) | ||
418 | && i801_set_block_buffer_mode() == 0) | 432 | && i801_set_block_buffer_mode() == 0) |
419 | result = i801_block_transaction_by_block(data, read_write, | 433 | result = i801_block_transaction_by_block(data, read_write, |
420 | hwpec); | 434 | hwpec); |
421 | else | 435 | else |
422 | result = i801_block_transaction_byte_by_byte(data, read_write, | 436 | result = i801_block_transaction_byte_by_byte(data, read_write, |
423 | hwpec); | 437 | command, hwpec); |
424 | 438 | ||
425 | if (result == 0 && hwpec) | 439 | if (result == 0 && hwpec) |
426 | i801_wait_hwpec(); | 440 | i801_wait_hwpec(); |
427 | 441 | ||
428 | if (command == I2C_SMBUS_I2C_BLOCK_DATA) { | 442 | if (command == I2C_SMBUS_I2C_BLOCK_DATA |
443 | && read_write == I2C_SMBUS_WRITE) { | ||
429 | /* restore saved configuration register value */ | 444 | /* restore saved configuration register value */ |
430 | pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); | 445 | pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); |
431 | } | 446 | } |
@@ -477,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, | |||
477 | xact = I801_WORD_DATA; | 492 | xact = I801_WORD_DATA; |
478 | break; | 493 | break; |
479 | case I2C_SMBUS_BLOCK_DATA: | 494 | case I2C_SMBUS_BLOCK_DATA: |
480 | case I2C_SMBUS_I2C_BLOCK_DATA: | ||
481 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 495 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), |
482 | SMBHSTADD); | 496 | SMBHSTADD); |
483 | outb_p(command, SMBHSTCMD); | 497 | outb_p(command, SMBHSTCMD); |
484 | block = 1; | 498 | block = 1; |
485 | break; | 499 | break; |
500 | case I2C_SMBUS_I2C_BLOCK_DATA: | ||
501 | /* NB: page 240 of ICH5 datasheet shows that the R/#W | ||
502 | * bit should be cleared here, even when reading */ | ||
503 | outb_p((addr & 0x7f) << 1, SMBHSTADD); | ||
504 | if (read_write == I2C_SMBUS_READ) { | ||
505 | /* NB: page 240 of ICH5 datasheet also shows | ||
506 | * that DATA1 is the cmd field when reading */ | ||
507 | outb_p(command, SMBHSTDAT1); | ||
508 | } else | ||
509 | outb_p(command, SMBHSTCMD); | ||
510 | block = 1; | ||
511 | break; | ||
486 | case I2C_SMBUS_PROC_CALL: | 512 | case I2C_SMBUS_PROC_CALL: |
487 | default: | 513 | default: |
488 | dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); | 514 | dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); |
@@ -531,7 +557,9 @@ static u32 i801_func(struct i2c_adapter *adapter) | |||
531 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | | 557 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
532 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | | 558 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
533 | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | | 559 | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | |
534 | ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0); | 560 | ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | |
561 | ((i801_features & FEATURE_I2C_BLOCK_READ) ? | ||
562 | I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); | ||
535 | } | 563 | } |
536 | 564 | ||
537 | static const struct i2c_algorithm smbus_algorithm = { | 565 | static const struct i2c_algorithm smbus_algorithm = { |
@@ -573,7 +601,6 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
573 | I801_dev = dev; | 601 | I801_dev = dev; |
574 | i801_features = 0; | 602 | i801_features = 0; |
575 | switch (dev->device) { | 603 | switch (dev->device) { |
576 | case PCI_DEVICE_ID_INTEL_82801DB_3: | ||
577 | case PCI_DEVICE_ID_INTEL_82801EB_3: | 604 | case PCI_DEVICE_ID_INTEL_82801EB_3: |
578 | case PCI_DEVICE_ID_INTEL_ESB_4: | 605 | case PCI_DEVICE_ID_INTEL_ESB_4: |
579 | case PCI_DEVICE_ID_INTEL_ICH6_16: | 606 | case PCI_DEVICE_ID_INTEL_ICH6_16: |
@@ -581,6 +608,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
581 | case PCI_DEVICE_ID_INTEL_ESB2_17: | 608 | case PCI_DEVICE_ID_INTEL_ESB2_17: |
582 | case PCI_DEVICE_ID_INTEL_ICH8_5: | 609 | case PCI_DEVICE_ID_INTEL_ICH8_5: |
583 | case PCI_DEVICE_ID_INTEL_ICH9_6: | 610 | case PCI_DEVICE_ID_INTEL_ICH9_6: |
611 | i801_features |= FEATURE_I2C_BLOCK_READ; | ||
612 | /* fall through */ | ||
613 | case PCI_DEVICE_ID_INTEL_82801DB_3: | ||
584 | case PCI_DEVICE_ID_INTEL_TOLAPAI_1: | 614 | case PCI_DEVICE_ID_INTEL_TOLAPAI_1: |
585 | i801_features |= FEATURE_SMBUS_PEC; | 615 | i801_features |= FEATURE_SMBUS_PEC; |
586 | i801_features |= FEATURE_BLOCK_BUFFER; | 616 | i801_features |= FEATURE_BLOCK_BUFFER; |
@@ -698,9 +728,8 @@ static void __exit i2c_i801_exit(void) | |||
698 | pci_unregister_driver(&i801_driver); | 728 | pci_unregister_driver(&i801_driver); |
699 | } | 729 | } |
700 | 730 | ||
701 | MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " | 731 | MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, " |
702 | "Philip Edelbrock <phil@netroedge.com>, " | 732 | "Jean Delvare <khali@linux-fr.org>"); |
703 | "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); | ||
704 | MODULE_DESCRIPTION("I801 SMBus driver"); | 733 | MODULE_DESCRIPTION("I801 SMBus driver"); |
705 | MODULE_LICENSE("GPL"); | 734 | MODULE_LICENSE("GPL"); |
706 | 735 | ||