aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorAndres Salomon <dilinger@queued.net>2010-12-30 23:27:33 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2011-01-14 06:38:15 -0500
commitde8255ccd219267cfd34139022b197c1ef8f032f (patch)
treebe7744be209561f07d41bde109897de7dbd20bbf /drivers/i2c
parent419cdc54ea597d307fade607a65e4885634eb8c8 (diff)
i2c: Convert SCx200 driver from using raw PCI to platform device
The SCx200 ACB driver supports ISA hardware as well as PCI. The PCI hardware is CS5535/CS5536 based, and the device that it grabs is handled by the cs5535-mfd driver. This converts the SCx200 driver to use a platform_driver rather than the previous PCI hackery. The driver used to manually track the iface list (via linked list); now it only does this for ISA devices. PCI ifaces are handled through standard driver model lists. It's unclear what happens in case of errors in the old ISA code; rather than pretending the code actually cares, I've dropped the (implicit) ignorance of return values and marked it with a comment. Signed-off-by: Andres Salomon <dilinger@queued.net> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/scx200_acb.c200
1 files changed, 80 insertions, 120 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 53fab518b3d..986e5f62deb 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -29,6 +29,7 @@
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/i2c.h> 30#include <linux/i2c.h>
31#include <linux/pci.h> 31#include <linux/pci.h>
32#include <linux/platform_device.h>
32#include <linux/delay.h> 33#include <linux/delay.h>
33#include <linux/mutex.h> 34#include <linux/mutex.h>
34#include <linux/slab.h> 35#include <linux/slab.h>
@@ -40,6 +41,7 @@
40 41
41MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); 42MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
42MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); 43MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
44MODULE_ALIAS("platform:cs5535-smb");
43MODULE_LICENSE("GPL"); 45MODULE_LICENSE("GPL");
44 46
45#define MAX_DEVICES 4 47#define MAX_DEVICES 4
@@ -84,10 +86,6 @@ struct scx200_acb_iface {
84 u8 *ptr; 86 u8 *ptr;
85 char needs_reset; 87 char needs_reset;
86 unsigned len; 88 unsigned len;
87
88 /* PCI device info */
89 struct pci_dev *pdev;
90 int bar;
91}; 89};
92 90
93/* Register Definitions */ 91/* Register Definitions */
@@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
391static struct scx200_acb_iface *scx200_acb_list; 389static struct scx200_acb_iface *scx200_acb_list;
392static DEFINE_MUTEX(scx200_acb_list_mutex); 390static DEFINE_MUTEX(scx200_acb_list_mutex);
393 391
394static __init int scx200_acb_probe(struct scx200_acb_iface *iface) 392static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
395{ 393{
396 u8 val; 394 u8 val;
397 395
@@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
427 return 0; 425 return 0;
428} 426}
429 427
430static __init struct scx200_acb_iface *scx200_create_iface(const char *text, 428static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
431 struct device *dev, int index) 429 struct device *dev, int index)
432{ 430{
433 struct scx200_acb_iface *iface; 431 struct scx200_acb_iface *iface;
@@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
452 return iface; 450 return iface;
453} 451}
454 452
455static int __init scx200_acb_create(struct scx200_acb_iface *iface) 453static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
456{ 454{
457 struct i2c_adapter *adapter; 455 struct i2c_adapter *adapter;
458 int rc; 456 int rc;
@@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
472 return -ENODEV; 470 return -ENODEV;
473 } 471 }
474 472
475 mutex_lock(&scx200_acb_list_mutex); 473 if (!adapter->dev.parent) {
476 iface->next = scx200_acb_list; 474 /* If there's no dev, we're tracking (ISA) ifaces manually */
477 scx200_acb_list = iface; 475 mutex_lock(&scx200_acb_list_mutex);
478 mutex_unlock(&scx200_acb_list_mutex); 476 iface->next = scx200_acb_list;
477 scx200_acb_list = iface;
478 mutex_unlock(&scx200_acb_list_mutex);
479 }
479 480
480 return 0; 481 return 0;
481} 482}
482 483
483static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, 484static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
484 int bar) 485 unsigned long base, int index, struct device *dev)
485{ 486{
486 struct scx200_acb_iface *iface; 487 struct scx200_acb_iface *iface;
487 int rc; 488 int rc;
488 489
489 iface = scx200_create_iface(text, &pdev->dev, 0); 490 iface = scx200_create_iface(text, dev, index);
490 491
491 if (iface == NULL) 492 if (iface == NULL)
492 return -ENOMEM; 493 return NULL;
493
494 iface->pdev = pdev;
495 iface->bar = bar;
496
497 rc = pci_enable_device_io(iface->pdev);
498 if (rc)
499 goto errout_free;
500 494
501 rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); 495 if (!request_region(base, 8, iface->adapter.name)) {
502 if (rc) { 496 printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
503 printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", 497 base, base + 8 - 1);
504 iface->bar);
505 goto errout_free; 498 goto errout_free;
506 } 499 }
507 500
508 iface->base = pci_resource_start(iface->pdev, iface->bar); 501 iface->base = base;
509 rc = scx200_acb_create(iface); 502 rc = scx200_acb_create(iface);
510 503
511 if (rc == 0) 504 if (rc == 0)
512 return 0; 505 return iface;
513 506
514 pci_release_region(iface->pdev, iface->bar); 507 release_region(base, 8);
515 pci_dev_put(iface->pdev);
516 errout_free: 508 errout_free:
517 kfree(iface); 509 kfree(iface);
518 return rc; 510 return NULL;
519} 511}
520 512
521static int __init scx200_create_isa(const char *text, unsigned long base, 513static int __devinit scx200_probe(struct platform_device *pdev)
522 int index)
523{ 514{
524 struct scx200_acb_iface *iface; 515 struct scx200_acb_iface *iface;
525 int rc; 516 struct resource *res;
526
527 iface = scx200_create_iface(text, NULL, index);
528
529 if (iface == NULL)
530 return -ENOMEM;
531 517
532 if (!request_region(base, 8, iface->adapter.name)) { 518 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
533 printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", 519 if (!res) {
534 base, base + 8 - 1); 520 dev_err(&pdev->dev, "can't fetch device resource info\n");
535 rc = -EBUSY; 521 return -ENODEV;
536 goto errout_free;
537 } 522 }
538 523
539 iface->base = base; 524 iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
540 rc = scx200_acb_create(iface); 525 if (!iface)
526 return -EIO;
541 527
542 if (rc == 0) 528 dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
543 return 0; 529 iface->adapter.name);
530 platform_set_drvdata(pdev, iface);
544 531
545 release_region(base, 8); 532 return 0;
546 errout_free:
547 kfree(iface);
548 return rc;
549} 533}
550 534
551/* Driver data is an index into the scx200_data array that indicates 535static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
552 * the name and the BAR where the I/O address resource is located. ISA 536{
553 * devices are flagged with a bar value of -1 */ 537 i2c_del_adapter(&iface->adapter);
554 538 release_region(iface->base, 8);
555static const struct pci_device_id scx200_pci[] __initconst = { 539 kfree(iface);
556 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE), 540}
557 .driver_data = 0 },
558 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
559 .driver_data = 0 },
560 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
561 .driver_data = 1 },
562 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
563 .driver_data = 2 },
564 { 0, }
565};
566
567static struct {
568 const char *name;
569 int bar;
570} scx200_data[] = {
571 { "SCx200", -1 },
572 { "CS5535", 0 },
573 { "CS5536", 0 }
574};
575 541
576static __init int scx200_scan_pci(void) 542static int __devexit scx200_remove(struct platform_device *pdev)
577{ 543{
578 int data, dev; 544 struct scx200_acb_iface *iface;
579 int rc = -ENODEV;
580 struct pci_dev *pdev;
581 545
582 for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) { 546 iface = platform_get_drvdata(pdev);
583 pdev = pci_get_device(scx200_pci[dev].vendor, 547 platform_set_drvdata(pdev, NULL);
584 scx200_pci[dev].device, NULL); 548 scx200_cleanup_iface(iface);
585 549
586 if (pdev == NULL) 550 return 0;
587 continue; 551}
588 552
589 data = scx200_pci[dev].driver_data; 553static struct platform_driver scx200_pci_drv = {
554 .driver = {
555 .name = "cs5535-smb",
556 .owner = THIS_MODULE,
557 },
558 .probe = scx200_probe,
559 .remove = __devexit_p(scx200_remove),
560};
590 561
591 /* if .bar is greater or equal to zero, this is a 562static const struct pci_device_id scx200_isa[] __initconst = {
592 * PCI device - otherwise, we assume 563 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
593 that the ports are ISA based 564 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
594 */ 565 { 0, }
566};
595 567
596 if (scx200_data[data].bar >= 0) 568static __init void scx200_scan_isa(void)
597 rc = scx200_create_pci(scx200_data[data].name, pdev, 569{
598 scx200_data[data].bar); 570 int i;
599 else {
600 int i;
601 571
602 pci_dev_put(pdev); 572 if (!pci_dev_present(scx200_isa))
603 for (i = 0; i < MAX_DEVICES; ++i) { 573 return;
604 if (base[i] == 0)
605 continue;
606 574
607 rc = scx200_create_isa(scx200_data[data].name, 575 for (i = 0; i < MAX_DEVICES; ++i) {
608 base[i], 576 if (base[i] == 0)
609 i); 577 continue;
610 }
611 }
612 578
613 break; 579 /* XXX: should we care about failures? */
580 scx200_create_dev("SCx200", base[i], i, NULL);
614 } 581 }
615
616 return rc;
617} 582}
618 583
619static int __init scx200_acb_init(void) 584static int __init scx200_acb_init(void)
620{ 585{
621 int rc;
622
623 pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); 586 pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
624 587
625 rc = scx200_scan_pci(); 588 /* First scan for ISA-based devices */
589 scx200_scan_isa(); /* XXX: should we care about errors? */
626 590
627 /* If at least one bus was created, init must succeed */ 591 /* If at least one bus was created, init must succeed */
628 if (scx200_acb_list) 592 if (scx200_acb_list)
629 return 0; 593 return 0;
630 return rc; 594
595 /* No ISA devices; register the platform driver for PCI-based devices */
596 return platform_driver_register(&scx200_pci_drv);
631} 597}
632 598
633static void __exit scx200_acb_cleanup(void) 599static void __exit scx200_acb_cleanup(void)
634{ 600{
635 struct scx200_acb_iface *iface; 601 struct scx200_acb_iface *iface;
636 602
603 platform_driver_unregister(&scx200_pci_drv);
604
637 mutex_lock(&scx200_acb_list_mutex); 605 mutex_lock(&scx200_acb_list_mutex);
638 while ((iface = scx200_acb_list) != NULL) { 606 while ((iface = scx200_acb_list) != NULL) {
639 scx200_acb_list = iface->next; 607 scx200_acb_list = iface->next;
640 mutex_unlock(&scx200_acb_list_mutex); 608 mutex_unlock(&scx200_acb_list_mutex);
641 609
642 i2c_del_adapter(&iface->adapter); 610 scx200_cleanup_iface(iface);
643
644 if (iface->pdev) {
645 pci_release_region(iface->pdev, iface->bar);
646 pci_dev_put(iface->pdev);
647 }
648 else
649 release_region(iface->base, 8);
650 611
651 kfree(iface);
652 mutex_lock(&scx200_acb_list_mutex); 612 mutex_lock(&scx200_acb_list_mutex);
653 } 613 }
654 mutex_unlock(&scx200_acb_list_mutex); 614 mutex_unlock(&scx200_acb_list_mutex);