diff options
author | Andrew Armenia <andrew@asquaredlabs.com> | 2012-07-24 08:13:56 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-07-24 08:13:56 -0400 |
commit | e154bf6fbfc167426ee938111a5ffa36bd8541a1 (patch) | |
tree | 0526266126b19aead836d4dc8897893fc3ba7a49 /drivers/i2c/busses/i2c-piix4.c | |
parent | 14a8086d27ad9761d505489d5a239f21cd67ef0f (diff) |
i2c-piix4: Separate registration and probing code
Some chipsets have multiple sets of SMBus registers each controlling a
separate SMBus. Supporting these chipsets properly will require registering
multiple I2C adapters for one piix4.
The code to initialize and register the i2c_adapter structure has been
separated from piix4_probe and allows registration of a piix4 adapter
given its base address. Note that the i2c_adapter and i2c_piix4_adapdata
structures are now dynamically allocated.
Signed-off-by: Andrew Armenia <andrew@asquaredlabs.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-piix4.c')
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 111 |
1 files changed, 71 insertions, 40 deletions
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 822e868e2ab4..42ed0af10efd 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c | |||
@@ -96,7 +96,6 @@ MODULE_PARM_DESC(force_addr, | |||
96 | 96 | ||
97 | static int srvrworks_csb5_delay; | 97 | static int srvrworks_csb5_delay; |
98 | static struct pci_driver piix4_driver; | 98 | static struct pci_driver piix4_driver; |
99 | static struct i2c_adapter piix4_adapter; | ||
100 | 99 | ||
101 | static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = { | 100 | static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = { |
102 | { | 101 | { |
@@ -294,27 +293,29 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, | |||
294 | return piix4_smba; | 293 | return piix4_smba; |
295 | } | 294 | } |
296 | 295 | ||
297 | static int piix4_transaction(unsigned short piix4_smba) | 296 | static int piix4_transaction(struct i2c_adapter *piix4_adapter) |
298 | { | 297 | { |
298 | struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); | ||
299 | unsigned short piix4_smba = adapdata->smba; | ||
299 | int temp; | 300 | int temp; |
300 | int result = 0; | 301 | int result = 0; |
301 | int timeout = 0; | 302 | int timeout = 0; |
302 | 303 | ||
303 | dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " | 304 | dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, " |
304 | "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), | 305 | "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), |
305 | inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), | 306 | inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), |
306 | inb_p(SMBHSTDAT1)); | 307 | inb_p(SMBHSTDAT1)); |
307 | 308 | ||
308 | /* Make sure the SMBus host is ready to start transmitting */ | 309 | /* Make sure the SMBus host is ready to start transmitting */ |
309 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { | 310 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { |
310 | dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " | 311 | dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). " |
311 | "Resetting...\n", temp); | 312 | "Resetting...\n", temp); |
312 | outb_p(temp, SMBHSTSTS); | 313 | outb_p(temp, SMBHSTSTS); |
313 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { | 314 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { |
314 | dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); | 315 | dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp); |
315 | return -EBUSY; | 316 | return -EBUSY; |
316 | } else { | 317 | } else { |
317 | dev_dbg(&piix4_adapter.dev, "Successful!\n"); | 318 | dev_dbg(&piix4_adapter->dev, "Successful!\n"); |
318 | } | 319 | } |
319 | } | 320 | } |
320 | 321 | ||
@@ -333,35 +334,35 @@ static int piix4_transaction(unsigned short piix4_smba) | |||
333 | 334 | ||
334 | /* If the SMBus is still busy, we give up */ | 335 | /* If the SMBus is still busy, we give up */ |
335 | if (timeout == MAX_TIMEOUT) { | 336 | if (timeout == MAX_TIMEOUT) { |
336 | dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); | 337 | dev_err(&piix4_adapter->dev, "SMBus Timeout!\n"); |
337 | result = -ETIMEDOUT; | 338 | result = -ETIMEDOUT; |
338 | } | 339 | } |
339 | 340 | ||
340 | if (temp & 0x10) { | 341 | if (temp & 0x10) { |
341 | result = -EIO; | 342 | result = -EIO; |
342 | dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); | 343 | dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n"); |
343 | } | 344 | } |
344 | 345 | ||
345 | if (temp & 0x08) { | 346 | if (temp & 0x08) { |
346 | result = -EIO; | 347 | result = -EIO; |
347 | dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " | 348 | dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be " |
348 | "locked until next hard reset. (sorry!)\n"); | 349 | "locked until next hard reset. (sorry!)\n"); |
349 | /* Clock stops and slave is stuck in mid-transmission */ | 350 | /* Clock stops and slave is stuck in mid-transmission */ |
350 | } | 351 | } |
351 | 352 | ||
352 | if (temp & 0x04) { | 353 | if (temp & 0x04) { |
353 | result = -ENXIO; | 354 | result = -ENXIO; |
354 | dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); | 355 | dev_dbg(&piix4_adapter->dev, "Error: no response!\n"); |
355 | } | 356 | } |
356 | 357 | ||
357 | if (inb_p(SMBHSTSTS) != 0x00) | 358 | if (inb_p(SMBHSTSTS) != 0x00) |
358 | outb_p(inb(SMBHSTSTS), SMBHSTSTS); | 359 | outb_p(inb(SMBHSTSTS), SMBHSTSTS); |
359 | 360 | ||
360 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { | 361 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { |
361 | dev_err(&piix4_adapter.dev, "Failed reset at end of " | 362 | dev_err(&piix4_adapter->dev, "Failed reset at end of " |
362 | "transaction (%02x)\n", temp); | 363 | "transaction (%02x)\n", temp); |
363 | } | 364 | } |
364 | dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " | 365 | dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, " |
365 | "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), | 366 | "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), |
366 | inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), | 367 | inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), |
367 | inb_p(SMBHSTDAT1)); | 368 | inb_p(SMBHSTDAT1)); |
@@ -431,7 +432,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | |||
431 | 432 | ||
432 | outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); | 433 | outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); |
433 | 434 | ||
434 | status = piix4_transaction(piix4_smba); | 435 | status = piix4_transaction(adap); |
435 | if (status) | 436 | if (status) |
436 | return status; | 437 | return status; |
437 | 438 | ||
@@ -471,14 +472,6 @@ static const struct i2c_algorithm smbus_algorithm = { | |||
471 | .functionality = piix4_func, | 472 | .functionality = piix4_func, |
472 | }; | 473 | }; |
473 | 474 | ||
474 | static struct i2c_adapter piix4_adapter = { | ||
475 | .owner = THIS_MODULE, | ||
476 | .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, | ||
477 | .algo = &smbus_algorithm, | ||
478 | }; | ||
479 | |||
480 | static struct i2c_piix4_adapdata piix4_adapter_data; | ||
481 | |||
482 | static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { | 475 | static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { |
483 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, | 476 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, |
484 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, | 477 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, |
@@ -503,6 +496,56 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { | |||
503 | 496 | ||
504 | MODULE_DEVICE_TABLE (pci, piix4_ids); | 497 | MODULE_DEVICE_TABLE (pci, piix4_ids); |
505 | 498 | ||
499 | static struct i2c_adapter *piix4_main_adapter; | ||
500 | |||
501 | static int __devinit piix4_add_adapter(struct pci_dev *dev, | ||
502 | unsigned short smba, | ||
503 | struct i2c_adapter **padap) | ||
504 | { | ||
505 | struct i2c_adapter *adap; | ||
506 | struct i2c_piix4_adapdata *adapdata; | ||
507 | int retval; | ||
508 | |||
509 | adap = kzalloc(sizeof(*adap), GFP_KERNEL); | ||
510 | if (adap == NULL) { | ||
511 | release_region(smba, SMBIOSIZE); | ||
512 | return -ENOMEM; | ||
513 | } | ||
514 | |||
515 | adap->owner = THIS_MODULE; | ||
516 | adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | ||
517 | adap->algo = &smbus_algorithm; | ||
518 | |||
519 | adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL); | ||
520 | if (adapdata == NULL) { | ||
521 | kfree(adap); | ||
522 | release_region(smba, SMBIOSIZE); | ||
523 | return -ENOMEM; | ||
524 | } | ||
525 | |||
526 | adapdata->smba = smba; | ||
527 | |||
528 | /* set up the sysfs linkage to our parent device */ | ||
529 | adap->dev.parent = &dev->dev; | ||
530 | |||
531 | snprintf(adap->name, sizeof(adap->name), | ||
532 | "SMBus PIIX4 adapter at %04x", smba); | ||
533 | |||
534 | i2c_set_adapdata(adap, adapdata); | ||
535 | |||
536 | retval = i2c_add_adapter(adap); | ||
537 | if (retval) { | ||
538 | dev_err(&dev->dev, "Couldn't register adapter!\n"); | ||
539 | kfree(adapdata); | ||
540 | kfree(adap); | ||
541 | release_region(smba, SMBIOSIZE); | ||
542 | return retval; | ||
543 | } | ||
544 | |||
545 | *padap = adap; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
506 | static int __devinit piix4_probe(struct pci_dev *dev, | 549 | static int __devinit piix4_probe(struct pci_dev *dev, |
507 | const struct pci_device_id *id) | 550 | const struct pci_device_id *id) |
508 | { | 551 | { |
@@ -520,23 +563,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, | |||
520 | if (retval < 0) | 563 | if (retval < 0) |
521 | return retval; | 564 | return retval; |
522 | 565 | ||
523 | piix4_adapter_data.smba = retval; | 566 | return piix4_add_adapter(dev, retval, &piix4_main_adapter); |
524 | |||
525 | /* set up the sysfs linkage to our parent device */ | ||
526 | piix4_adapter.dev.parent = &dev->dev; | ||
527 | |||
528 | snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), | ||
529 | "SMBus PIIX4 adapter at %04x", piix4_adapter_data.smba); | ||
530 | |||
531 | i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data); | ||
532 | |||
533 | if ((retval = i2c_add_adapter(&piix4_adapter))) { | ||
534 | dev_err(&dev->dev, "Couldn't register adapter!\n"); | ||
535 | release_region(piix4_adapter_data.smba, SMBIOSIZE); | ||
536 | piix4_adapter_data.smba = 0; | ||
537 | } | ||
538 | |||
539 | return retval; | ||
540 | } | 567 | } |
541 | 568 | ||
542 | static void __devexit piix4_adap_remove(struct i2c_adapter *adap) | 569 | static void __devexit piix4_adap_remove(struct i2c_adapter *adap) |
@@ -546,13 +573,17 @@ static void __devexit piix4_adap_remove(struct i2c_adapter *adap) | |||
546 | if (adapdata->smba) { | 573 | if (adapdata->smba) { |
547 | i2c_del_adapter(adap); | 574 | i2c_del_adapter(adap); |
548 | release_region(adapdata->smba, SMBIOSIZE); | 575 | release_region(adapdata->smba, SMBIOSIZE); |
549 | adapdata->smba = 0; | 576 | kfree(adapdata); |
577 | kfree(adap); | ||
550 | } | 578 | } |
551 | } | 579 | } |
552 | 580 | ||
553 | static void __devexit piix4_remove(struct pci_dev *dev) | 581 | static void __devexit piix4_remove(struct pci_dev *dev) |
554 | { | 582 | { |
555 | piix4_adap_remove(&piix4_adapter); | 583 | if (piix4_main_adapter) { |
584 | piix4_adap_remove(piix4_main_adapter); | ||
585 | piix4_main_adapter = NULL; | ||
586 | } | ||
556 | } | 587 | } |
557 | 588 | ||
558 | static struct pci_driver piix4_driver = { | 589 | static struct pci_driver piix4_driver = { |