aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-piix4.c
diff options
context:
space:
mode:
authorAndrew Armenia <andrew@asquaredlabs.com>2012-07-24 08:13:56 -0400
committerJean Delvare <khali@endymion.delvare>2012-07-24 08:13:56 -0400
commite154bf6fbfc167426ee938111a5ffa36bd8541a1 (patch)
tree0526266126b19aead836d4dc8897893fc3ba7a49 /drivers/i2c/busses/i2c-piix4.c
parent14a8086d27ad9761d505489d5a239f21cd67ef0f (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.c111
1 files changed, 71 insertions, 40 deletions
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 822e868e2ab..42ed0af10ef 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
97static int srvrworks_csb5_delay; 97static int srvrworks_csb5_delay;
98static struct pci_driver piix4_driver; 98static struct pci_driver piix4_driver;
99static struct i2c_adapter piix4_adapter;
100 99
101static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = { 100static 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
297static int piix4_transaction(unsigned short piix4_smba) 296static 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
474static struct i2c_adapter piix4_adapter = {
475 .owner = THIS_MODULE,
476 .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
477 .algo = &smbus_algorithm,
478};
479
480static struct i2c_piix4_adapdata piix4_adapter_data;
481
482static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { 475static 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
504MODULE_DEVICE_TABLE (pci, piix4_ids); 497MODULE_DEVICE_TABLE (pci, piix4_ids);
505 498
499static struct i2c_adapter *piix4_main_adapter;
500
501static 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
506static int __devinit piix4_probe(struct pci_dev *dev, 549static 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
542static void __devexit piix4_adap_remove(struct i2c_adapter *adap) 569static 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
553static void __devexit piix4_remove(struct pci_dev *dev) 581static 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
558static struct pci_driver piix4_driver = { 589static struct pci_driver piix4_driver = {