diff options
author | Jordan Crouse <jordan.crouse@amd.com> | 2006-06-12 15:44:28 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-22 14:10:35 -0400 |
commit | 80cd3a8769c66203d55cdf635390bdcebd742091 (patch) | |
tree | de8b6e47ffb2651dd75ddce036dee9b5732199fa /drivers/i2c/busses | |
parent | 46f5ed753fac512f73069bd07455555b41a8a06e (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/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 200 |
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 | ||
420 | static int __init scx200_acb_create(const char *text, int base, int index) | 423 | static __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; | 448 | static 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: | 476 | static __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 | ||
480 | static struct pci_device_id scx200[] = { | 513 | static 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 | ||
486 | static 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 | |||
547 | static 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 | 558 | static struct { |
559 | const char *name; | ||
560 | int bar; | ||
561 | } scx200_data[] = { | ||
562 | { "SCx200", -1 }, | ||
563 | { "CS5535", 0 }, | ||
564 | { "CS5536", 0 } | ||
565 | }; | ||
493 | 566 | ||
494 | static __init int scx200_add_cs553x(void) | 567 | static __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 | ||
514 | static int __init scx200_acb_init(void) | 609 | static 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 | } |