aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJordan Crouse <jordan.crouse@amd.com>2006-06-12 15:44:28 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-22 14:10:35 -0400
commit80cd3a8769c66203d55cdf635390bdcebd742091 (patch)
treede8b6e47ffb2651dd75ddce036dee9b5732199fa /drivers
parent46f5ed753fac512f73069bd07455555b41a8a06e (diff)
[PATCH] scx200_acb: Use PCI I/O resource when appropriate
On the CS5535 and CS5536, the I/O resource is allocated through PCI, so use that instead of using the MSR backdoor. Signed-off-by: Jordan Crouse <jordan.crouse@amd.com> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/scx200_acb.c200
1 files changed, 147 insertions, 53 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 766cc969c4d0..09b4586f3bd3 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -33,7 +33,6 @@
33#include <linux/delay.h> 33#include <linux/delay.h>
34#include <linux/mutex.h> 34#include <linux/mutex.h>
35#include <asm/io.h> 35#include <asm/io.h>
36#include <asm/msr.h>
37 36
38#include <linux/scx200.h> 37#include <linux/scx200.h>
39 38
@@ -85,6 +84,10 @@ struct scx200_acb_iface {
85 u8 *ptr; 84 u8 *ptr;
86 char needs_reset; 85 char needs_reset;
87 unsigned len; 86 unsigned len;
87
88 /* PCI device info */
89 struct pci_dev *pdev;
90 int bar;
88}; 91};
89 92
90/* Register Definitions */ 93/* Register Definitions */
@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface)
417 return 0; 420 return 0;
418} 421}
419 422
420static int __init scx200_acb_create(const char *text, int base, int index) 423static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
424 int index)
421{ 425{
422 struct scx200_acb_iface *iface; 426 struct scx200_acb_iface *iface;
423 struct i2c_adapter *adapter; 427 struct i2c_adapter *adapter;
424 int rc;
425 428
426 iface = kzalloc(sizeof(*iface), GFP_KERNEL); 429 iface = kzalloc(sizeof(*iface), GFP_KERNEL);
427 if (!iface) { 430 if (!iface) {
428 printk(KERN_ERR NAME ": can't allocate memory\n"); 431 printk(KERN_ERR NAME ": can't allocate memory\n");
429 rc = -ENOMEM; 432 return NULL;
430 goto errout;
431 } 433 }
432 434
433 adapter = &iface->adapter; 435 adapter = &iface->adapter;
@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index)
440 442
441 mutex_init(&iface->mutex); 443 mutex_init(&iface->mutex);
442 444
443 if (!request_region(base, 8, adapter->name)) { 445 return iface;
444 printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", 446}
445 base, base + 8-1); 447
446 rc = -EBUSY; 448static int __init scx200_acb_create(struct scx200_acb_iface *iface)
447 goto errout_free; 449{
448 } 450 struct i2c_adapter *adapter;
449 iface->base = base; 451 int rc;
452
453 adapter = &iface->adapter;
450 454
451 rc = scx200_acb_probe(iface); 455 rc = scx200_acb_probe(iface);
452 if (rc) { 456 if (rc) {
453 printk(KERN_WARNING NAME ": probe failed\n"); 457 printk(KERN_WARNING NAME ": probe failed\n");
454 goto errout_release; 458 return rc;
455 } 459 }
456 460
457 scx200_acb_reset(iface); 461 scx200_acb_reset(iface);
458 462
459 if (i2c_add_adapter(adapter) < 0) { 463 if (i2c_add_adapter(adapter) < 0) {
460 printk(KERN_ERR NAME ": failed to register\n"); 464 printk(KERN_ERR NAME ": failed to register\n");
461 rc = -ENODEV; 465 return -ENODEV;
462 goto errout_release;
463 } 466 }
464 467
465 down(&scx200_acb_list_mutex); 468 down(&scx200_acb_list_mutex);
@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index)
468 up(&scx200_acb_list_mutex); 471 up(&scx200_acb_list_mutex);
469 472
470 return 0; 473 return 0;
474}
471 475
472 errout_release: 476static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
473 release_region(iface->base, 8); 477 int bar)
478{
479 struct scx200_acb_iface *iface;
480 int rc;
481
482 iface = scx200_create_iface(text, 0);
483
484 if (iface == NULL)
485 return -ENOMEM;
486
487 iface->pdev = pdev;
488 iface->bar = bar;
489
490 pci_enable_device_bars(iface->pdev, 1 << iface->bar);
491
492 rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
493
494 if (rc != 0) {
495 printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
496 iface->bar);
497 goto errout_free;
498 }
499
500 iface->base = pci_resource_start(iface->pdev, iface->bar);
501 rc = scx200_acb_create(iface);
502
503 if (rc == 0)
504 return 0;
505
506 pci_release_region(iface->pdev, iface->bar);
507 pci_dev_put(iface->pdev);
474 errout_free: 508 errout_free:
475 kfree(iface); 509 kfree(iface);
476 errout:
477 return rc; 510 return rc;
478} 511}
479 512
480static struct pci_device_id scx200[] = { 513static int __init scx200_create_isa(const char *text, unsigned long base,
481 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, 514 int index)
482 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, 515{
483 { }, 516 struct scx200_acb_iface *iface;
484}; 517 int rc;
518
519 iface = scx200_create_iface(text, index);
520
521 if (iface == NULL)
522 return -ENOMEM;
523
524 if (request_region(base, 8, iface->adapter.name) == 0) {
525 printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
526 base, base + 8 - 1);
527 rc = -EBUSY;
528 goto errout_free;
529 }
530
531 iface->base = base;
532 rc = scx200_acb_create(iface);
533
534 if (rc == 0)
535 return 0;
485 536
486static struct pci_device_id divil_pci[] = { 537 release_region(base, 8);
487 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, 538 errout_free:
488 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, 539 kfree(iface);
489 { } /* NULL entry */ 540 return rc;
541}
542
543/* Driver data is an index into the scx200_data array that indicates
544 * the name and the BAR where the I/O address resource is located. ISA
545 * devices are flagged with a bar value of -1 */
546
547static struct pci_device_id scx200_pci[] = {
548 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
549 .driver_data = 0 },
550 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
551 .driver_data = 0 },
552 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
553 .driver_data = 1 },
554 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
555 .driver_data = 2 }
490}; 556};
491 557
492#define MSR_LBAR_SMB 0x5140000B 558static struct {
559 const char *name;
560 int bar;
561} scx200_data[] = {
562 { "SCx200", -1 },
563 { "CS5535", 0 },
564 { "CS5536", 0 }
565};
493 566
494static __init int scx200_add_cs553x(void) 567static __init int scx200_scan_pci(void)
495{ 568{
496 u32 low, hi; 569 int data, dev;
497 u32 smb_base; 570 int rc = -ENODEV;
498 571 struct pci_dev *pdev;
499 /* Grab & reserve the SMB I/O range */ 572
500 rdmsr(MSR_LBAR_SMB, low, hi); 573 for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
574 pdev = pci_get_device(scx200_pci[dev].vendor,
575 scx200_pci[dev].device, NULL);
576
577 if (pdev == NULL)
578 continue;
579
580 data = scx200_pci[dev].driver_data;
581
582 /* if .bar is greater or equal to zero, this is a
583 * PCI device - otherwise, we assume
584 that the ports are ISA based
585 */
586
587 if (scx200_data[data].bar >= 0)
588 rc = scx200_create_pci(scx200_data[data].name, pdev,
589 scx200_data[data].bar);
590 else {
591 int i;
592
593 for (i = 0; i < MAX_DEVICES; ++i) {
594 if (base[i] == 0)
595 continue;
596
597 rc = scx200_create_isa(scx200_data[data].name,
598 base[i],
599 i);
600 }
601 }
501 602
502 /* Check the IO mask and whether SMB is enabled */ 603 break;
503 if (hi != 0x0000F001) {
504 printk(KERN_WARNING NAME ": SMBus not enabled\n");
505 return -ENODEV;
506 } 604 }
507 605
508 /* SMBus IO size is 8 bytes */ 606 return rc;
509 smb_base = low & 0x0000FFF8;
510
511 return scx200_acb_create("CS5535", smb_base, 0);
512} 607}
513 608
514static int __init scx200_acb_init(void) 609static int __init scx200_acb_init(void)
515{ 610{
516 int i; 611 int rc;
517 int rc = -ENODEV;
518 612
519 pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); 613 pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
520 614
521 /* Verify that this really is a SCx200 processor */ 615 rc = scx200_scan_pci();
522 if (pci_dev_present(scx200)) {
523 for (i = 0; i < MAX_DEVICES; ++i) {
524 if (base[i] > 0)
525 rc = scx200_acb_create("SCx200", base[i], i);
526 }
527 } else if (pci_dev_present(divil_pci))
528 rc = scx200_add_cs553x();
529 616
530 /* If at least one bus was created, init must succeed */ 617 /* If at least one bus was created, init must succeed */
531 if (scx200_acb_list) 618 if (scx200_acb_list)
@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void)
543 up(&scx200_acb_list_mutex); 630 up(&scx200_acb_list_mutex);
544 631
545 i2c_del_adapter(&iface->adapter); 632 i2c_del_adapter(&iface->adapter);
546 release_region(iface->base, 8); 633
634 if (iface->pdev) {
635 pci_release_region(iface->pdev, iface->bar);
636 pci_dev_put(iface->pdev);
637 }
638 else
639 release_region(iface->base, 8);
640
547 kfree(iface); 641 kfree(iface);
548 down(&scx200_acb_list_mutex); 642 down(&scx200_acb_list_mutex);
549 } 643 }