diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 761f9dd53620..63d5e5978046 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c | |||
| @@ -226,6 +226,70 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, | ||
| 230 | const struct pci_device_id *id) | ||
| 231 | { | ||
| 232 | unsigned short smba_idx = 0xcd6; | ||
| 233 | u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c; | ||
| 234 | |||
| 235 | /* SB800 SMBus does not support forcing address */ | ||
| 236 | if (force || force_addr) { | ||
| 237 | dev_err(&PIIX4_dev->dev, "SB800 SMBus does not support " | ||
| 238 | "forcing address!\n"); | ||
| 239 | return -EINVAL; | ||
| 240 | } | ||
| 241 | |||
| 242 | /* Determine the address of the SMBus areas */ | ||
| 243 | if (!request_region(smba_idx, 2, "smba_idx")) { | ||
| 244 | dev_err(&PIIX4_dev->dev, "SMBus base address index region " | ||
| 245 | "0x%x already in use!\n", smba_idx); | ||
| 246 | return -EBUSY; | ||
| 247 | } | ||
| 248 | outb_p(smb_en, smba_idx); | ||
| 249 | smba_en_lo = inb_p(smba_idx + 1); | ||
| 250 | outb_p(smb_en + 1, smba_idx); | ||
| 251 | smba_en_hi = inb_p(smba_idx + 1); | ||
| 252 | release_region(smba_idx, 2); | ||
| 253 | |||
| 254 | if ((smba_en_lo & 1) == 0) { | ||
| 255 | dev_err(&PIIX4_dev->dev, | ||
| 256 | "Host SMBus controller not enabled!\n"); | ||
| 257 | return -ENODEV; | ||
| 258 | } | ||
| 259 | |||
| 260 | piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; | ||
| 261 | if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) | ||
| 262 | return -EBUSY; | ||
| 263 | |||
| 264 | if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { | ||
| 265 | dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n", | ||
| 266 | piix4_smba); | ||
| 267 | return -EBUSY; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* Request the SMBus I2C bus config region */ | ||
| 271 | if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) { | ||
| 272 | dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region " | ||
| 273 | "0x%x already in use!\n", piix4_smba + i2ccfg_offset); | ||
| 274 | release_region(piix4_smba, SMBIOSIZE); | ||
| 275 | piix4_smba = 0; | ||
| 276 | return -EBUSY; | ||
| 277 | } | ||
| 278 | i2ccfg = inb_p(piix4_smba + i2ccfg_offset); | ||
| 279 | release_region(piix4_smba + i2ccfg_offset, 1); | ||
| 280 | |||
| 281 | if (i2ccfg & 1) | ||
| 282 | dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n"); | ||
| 283 | else | ||
| 284 | dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus.\n"); | ||
| 285 | |||
| 286 | dev_info(&PIIX4_dev->dev, | ||
| 287 | "SMBus Host Controller at 0x%x, revision %d\n", | ||
| 288 | piix4_smba, i2ccfg >> 4); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 229 | static int piix4_transaction(void) | 293 | static int piix4_transaction(void) |
| 230 | { | 294 | { |
| 231 | int temp; | 295 | int temp; |
| @@ -433,7 +497,14 @@ static int __devinit piix4_probe(struct pci_dev *dev, | |||
| 433 | { | 497 | { |
| 434 | int retval; | 498 | int retval; |
| 435 | 499 | ||
| 436 | retval = piix4_setup(dev, id); | 500 | if ((dev->vendor == PCI_VENDOR_ID_ATI) && |
| 501 | (dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) && | ||
| 502 | (dev->revision >= 0x40)) | ||
| 503 | /* base address location etc changed in SB800 */ | ||
| 504 | retval = piix4_setup_sb800(dev, id); | ||
| 505 | else | ||
| 506 | retval = piix4_setup(dev, id); | ||
| 507 | |||
| 437 | if (retval) | 508 | if (retval) |
| 438 | return retval; | 509 | return retval; |
| 439 | 510 | ||
