diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 154 |
1 files changed, 64 insertions, 90 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index dfca74933625..3e0d04d5a800 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | i801.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware |
| 3 | monitoring | 3 | monitoring |
| 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 |
| @@ -36,7 +36,7 @@ | |||
| 36 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). | 36 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). |
| 37 | For SMBus support, they are similar to the PIIX4 and are part | 37 | For SMBus support, they are similar to the PIIX4 and are part |
| 38 | of Intel's '810' and other chipsets. | 38 | of Intel's '810' and other chipsets. |
| 39 | See the doc/busses/i2c-i801 file for details. | 39 | See the file Documentation/i2c/busses/i2c-i801 for details. |
| 40 | I2C Block Read and Process Call are not supported. | 40 | I2C Block Read and Process Call are not supported. |
| 41 | */ | 41 | */ |
| 42 | 42 | ||
| @@ -66,9 +66,8 @@ | |||
| 66 | #define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ | 66 | #define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ |
| 67 | 67 | ||
| 68 | /* PCI Address Constants */ | 68 | /* PCI Address Constants */ |
| 69 | #define SMBBA 0x020 | 69 | #define SMBBAR 4 |
| 70 | #define SMBHSTCFG 0x040 | 70 | #define SMBHSTCFG 0x040 |
| 71 | #define SMBREV 0x008 | ||
| 72 | 71 | ||
| 73 | /* Host configuration bits for SMBHSTCFG */ | 72 | /* Host configuration bits for SMBHSTCFG */ |
| 74 | #define SMBHSTCFG_HST_EN 1 | 73 | #define SMBHSTCFG_HST_EN 1 |
| @@ -92,92 +91,16 @@ | |||
| 92 | #define I801_START 0x40 | 91 | #define I801_START 0x40 |
| 93 | #define I801_PEC_EN 0x80 /* ICH4 only */ | 92 | #define I801_PEC_EN 0x80 /* ICH4 only */ |
| 94 | 93 | ||
| 95 | /* insmod parameters */ | ||
| 96 | |||
| 97 | /* If force_addr is set to anything different from 0, we forcibly enable | ||
| 98 | the I801 at the given address. VERY DANGEROUS! */ | ||
| 99 | static u16 force_addr; | ||
| 100 | module_param(force_addr, ushort, 0); | ||
| 101 | MODULE_PARM_DESC(force_addr, | ||
| 102 | "Forcibly enable the I801 at the given address. " | ||
| 103 | "EXTREMELY DANGEROUS!"); | ||
| 104 | 94 | ||
| 105 | static int i801_transaction(void); | 95 | static int i801_transaction(void); |
| 106 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | 96 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, |
| 107 | int command, int hwpec); | 97 | int command, int hwpec); |
| 108 | 98 | ||
| 109 | static unsigned short i801_smba; | 99 | static unsigned long i801_smba; |
| 110 | static struct pci_driver i801_driver; | 100 | static struct pci_driver i801_driver; |
| 111 | static struct pci_dev *I801_dev; | 101 | static struct pci_dev *I801_dev; |
| 112 | static int isich4; | 102 | static int isich4; |
| 113 | 103 | ||
| 114 | static int i801_setup(struct pci_dev *dev) | ||
| 115 | { | ||
| 116 | int error_return = 0; | ||
| 117 | unsigned char temp; | ||
| 118 | |||
| 119 | /* Note: we keep on searching until we have found 'function 3' */ | ||
| 120 | if(PCI_FUNC(dev->devfn) != 3) | ||
| 121 | return -ENODEV; | ||
| 122 | |||
| 123 | I801_dev = dev; | ||
| 124 | if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || | ||
| 125 | (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) || | ||
| 126 | (dev->device == PCI_DEVICE_ID_INTEL_ESB_4)) | ||
| 127 | isich4 = 1; | ||
| 128 | else | ||
| 129 | isich4 = 0; | ||
| 130 | |||
| 131 | /* Determine the address of the SMBus areas */ | ||
| 132 | if (force_addr) { | ||
| 133 | i801_smba = force_addr & 0xfff0; | ||
| 134 | } else { | ||
| 135 | pci_read_config_word(I801_dev, SMBBA, &i801_smba); | ||
| 136 | i801_smba &= 0xfff0; | ||
| 137 | if(i801_smba == 0) { | ||
| 138 | dev_err(&dev->dev, "SMB base address uninitialized " | ||
| 139 | "- upgrade BIOS or use force_addr=0xaddr\n"); | ||
| 140 | return -ENODEV; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) { | ||
| 145 | dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n", | ||
| 146 | i801_smba); | ||
| 147 | error_return = -EBUSY; | ||
| 148 | goto END; | ||
| 149 | } | ||
| 150 | |||
| 151 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); | ||
| 152 | temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ | ||
| 153 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp); | ||
| 154 | |||
| 155 | /* If force_addr is set, we program the new address here. Just to make | ||
| 156 | sure, we disable the device first. */ | ||
| 157 | if (force_addr) { | ||
| 158 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe); | ||
| 159 | pci_write_config_word(I801_dev, SMBBA, i801_smba); | ||
| 160 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01); | ||
| 161 | dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to " | ||
| 162 | "new address %04x!\n", i801_smba); | ||
| 163 | } else if ((temp & 1) == 0) { | ||
| 164 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1); | ||
| 165 | dev_warn(&dev->dev, "enabling SMBus device\n"); | ||
| 166 | } | ||
| 167 | |||
| 168 | if (temp & 0x02) | ||
| 169 | dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n"); | ||
| 170 | else | ||
| 171 | dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n"); | ||
| 172 | |||
| 173 | pci_read_config_byte(I801_dev, SMBREV, &temp); | ||
| 174 | dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); | ||
| 175 | dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba); | ||
| 176 | |||
| 177 | END: | ||
| 178 | return error_return; | ||
| 179 | } | ||
| 180 | |||
| 181 | static int i801_transaction(void) | 104 | static int i801_transaction(void) |
| 182 | { | 105 | { |
| 183 | int temp; | 106 | int temp; |
| @@ -334,8 +257,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
| 334 | /* We will always wait for a fraction of a second! */ | 257 | /* We will always wait for a fraction of a second! */ |
| 335 | timeout = 0; | 258 | timeout = 0; |
| 336 | do { | 259 | do { |
| 337 | temp = inb_p(SMBHSTSTS); | ||
| 338 | msleep(1); | 260 | msleep(1); |
| 261 | temp = inb_p(SMBHSTSTS); | ||
| 339 | } | 262 | } |
| 340 | while ((!(temp & 0x80)) | 263 | while ((!(temp & 0x80)) |
| 341 | && (timeout++ < MAX_TIMEOUT)); | 264 | && (timeout++ < MAX_TIMEOUT)); |
| @@ -393,8 +316,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
| 393 | /* wait for INTR bit as advised by Intel */ | 316 | /* wait for INTR bit as advised by Intel */ |
| 394 | timeout = 0; | 317 | timeout = 0; |
| 395 | do { | 318 | do { |
| 396 | temp = inb_p(SMBHSTSTS); | ||
| 397 | msleep(1); | 319 | msleep(1); |
| 320 | temp = inb_p(SMBHSTSTS); | ||
| 398 | } while ((!(temp & 0x02)) | 321 | } while ((!(temp & 0x02)) |
| 399 | && (timeout++ < MAX_TIMEOUT)); | 322 | && (timeout++ < MAX_TIMEOUT)); |
| 400 | 323 | ||
| @@ -541,25 +464,76 @@ MODULE_DEVICE_TABLE (pci, i801_ids); | |||
| 541 | 464 | ||
| 542 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | 465 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) |
| 543 | { | 466 | { |
| 467 | unsigned char temp; | ||
| 468 | int err; | ||
| 469 | |||
| 470 | I801_dev = dev; | ||
| 471 | if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || | ||
| 472 | (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) || | ||
| 473 | (dev->device == PCI_DEVICE_ID_INTEL_ESB_4)) | ||
| 474 | isich4 = 1; | ||
| 475 | else | ||
| 476 | isich4 = 0; | ||
| 477 | |||
| 478 | err = pci_enable_device(dev); | ||
| 479 | if (err) { | ||
| 480 | dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", | ||
| 481 | err); | ||
| 482 | goto exit; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* Determine the address of the SMBus area */ | ||
| 486 | i801_smba = pci_resource_start(dev, SMBBAR); | ||
| 487 | if (!i801_smba) { | ||
| 488 | dev_err(&dev->dev, "SMBus base address uninitialized, " | ||
| 489 | "upgrade BIOS\n"); | ||
| 490 | err = -ENODEV; | ||
| 491 | goto exit_disable; | ||
| 492 | } | ||
| 493 | |||
| 494 | err = pci_request_region(dev, SMBBAR, i801_driver.name); | ||
| 495 | if (err) { | ||
| 496 | dev_err(&dev->dev, "Failed to request SMBus region " | ||
| 497 | "0x%lx-0x%lx\n", i801_smba, | ||
| 498 | pci_resource_end(dev, SMBBAR)); | ||
| 499 | goto exit_disable; | ||
| 500 | } | ||
| 544 | 501 | ||
| 545 | if (i801_setup(dev)) { | 502 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); |
| 546 | dev_warn(&dev->dev, | 503 | temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ |
| 547 | "I801 not detected, module not inserted.\n"); | 504 | if (!(temp & SMBHSTCFG_HST_EN)) { |
| 548 | return -ENODEV; | 505 | dev_info(&dev->dev, "Enabling SMBus device\n"); |
| 506 | temp |= SMBHSTCFG_HST_EN; | ||
| 549 | } | 507 | } |
| 508 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp); | ||
| 509 | |||
| 510 | if (temp & SMBHSTCFG_SMB_SMI_EN) | ||
| 511 | dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); | ||
| 512 | else | ||
| 513 | dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); | ||
| 550 | 514 | ||
| 551 | /* set up the driverfs linkage to our parent device */ | 515 | /* set up the driverfs linkage to our parent device */ |
| 552 | i801_adapter.dev.parent = &dev->dev; | 516 | i801_adapter.dev.parent = &dev->dev; |
| 553 | 517 | ||
| 554 | snprintf(i801_adapter.name, I2C_NAME_SIZE, | 518 | snprintf(i801_adapter.name, I2C_NAME_SIZE, |
| 555 | "SMBus I801 adapter at %04x", i801_smba); | 519 | "SMBus I801 adapter at %04lx", i801_smba); |
| 556 | return i2c_add_adapter(&i801_adapter); | 520 | err = i2c_add_adapter(&i801_adapter); |
| 521 | if (err) { | ||
| 522 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); | ||
| 523 | goto exit_disable; | ||
| 524 | } | ||
| 525 | |||
| 526 | exit_disable: | ||
| 527 | pci_disable_device(dev); | ||
| 528 | exit: | ||
| 529 | return err; | ||
| 557 | } | 530 | } |
| 558 | 531 | ||
| 559 | static void __devexit i801_remove(struct pci_dev *dev) | 532 | static void __devexit i801_remove(struct pci_dev *dev) |
| 560 | { | 533 | { |
| 561 | i2c_del_adapter(&i801_adapter); | 534 | i2c_del_adapter(&i801_adapter); |
| 562 | release_region(i801_smba, (isich4 ? 16 : 8)); | 535 | pci_release_region(dev, SMBBAR); |
| 536 | pci_disable_device(dev); | ||
| 563 | } | 537 | } |
| 564 | 538 | ||
| 565 | static struct pci_driver i801_driver = { | 539 | static struct pci_driver i801_driver = { |
