diff options
author | Andres Salomon | 2010-12-30 20:27:33 -0800 |
---|---|---|
committer | Samuel Ortiz | 2011-01-14 12:38:15 +0100 |
commit | de8255ccd219267cfd34139022b197c1ef8f032f (patch) | |
tree | be7744be209561f07d41bde109897de7dbd20bbf | |
parent | 419cdc54ea597d307fade607a65e4885634eb8c8 (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>
-rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 200 |
1 files changed, 80 insertions, 120 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 53fab518b3da..986e5f62debe 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -29,6 +29,7 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/delay.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -40,6 +41,7 @@ MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); +MODULE_ALIAS("platform:cs5535-smb"); MODULE_LICENSE("GPL"); #define MAX_DEVICES 4 @@ -84,10 +86,6 @@ struct scx200_acb_iface { u8 *ptr; char needs_reset; unsigned len; - - /* PCI device info */ - struct pci_dev *pdev; - int bar; }; /* Register Definitions */ @@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = { static struct scx200_acb_iface *scx200_acb_list; static DEFINE_MUTEX(scx200_acb_list_mutex); -static __init int scx200_acb_probe(struct scx200_acb_iface *iface) +static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface) { u8 val; @@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface) return 0; } -static __init struct scx200_acb_iface *scx200_create_iface(const char *text, +static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text, struct device *dev, int index) { struct scx200_acb_iface *iface; @@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, return iface; } -static int __init scx200_acb_create(struct scx200_acb_iface *iface) +static int __devinit scx200_acb_create(struct scx200_acb_iface *iface) { struct i2c_adapter *adapter; int rc; @@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface) return -ENODEV; } - mutex_lock(&scx200_acb_list_mutex); - iface->next = scx200_acb_list; - scx200_acb_list = iface; - mutex_unlock(&scx200_acb_list_mutex); + if (!adapter->dev.parent) { + /* If there's no dev, we're tracking (ISA) ifaces manually */ + mutex_lock(&scx200_acb_list_mutex); + iface->next = scx200_acb_list; + scx200_acb_list = iface; + mutex_unlock(&scx200_acb_list_mutex); + } return 0; } -static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, - int bar) +static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text, + unsigned long base, int index, struct device *dev) { struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, &pdev->dev, 0); + iface = scx200_create_iface(text, dev, index); if (iface == NULL) - return -ENOMEM; - - iface->pdev = pdev; - iface->bar = bar; - - rc = pci_enable_device_io(iface->pdev); - if (rc) - goto errout_free; + return NULL; - rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); - if (rc) { - printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", - iface->bar); + if (!request_region(base, 8, iface->adapter.name)) { + printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", + base, base + 8 - 1); goto errout_free; } - iface->base = pci_resource_start(iface->pdev, iface->bar); + iface->base = base; rc = scx200_acb_create(iface); if (rc == 0) - return 0; + return iface; - pci_release_region(iface->pdev, iface->bar); - pci_dev_put(iface->pdev); + release_region(base, 8); errout_free: kfree(iface); - return rc; + return NULL; } -static int __init scx200_create_isa(const char *text, unsigned long base, - int index) +static int __devinit scx200_probe(struct platform_device *pdev) { struct scx200_acb_iface *iface; - int rc; - - iface = scx200_create_iface(text, NULL, index); - - if (iface == NULL) - return -ENOMEM; + struct resource *res; - if (!request_region(base, 8, iface->adapter.name)) { - printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", - base, base + 8 - 1); - rc = -EBUSY; - goto errout_free; + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); + return -ENODEV; } - iface->base = base; - rc = scx200_acb_create(iface); + iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev); + if (!iface) + return -EIO; - if (rc == 0) - return 0; + dev_info(&pdev->dev, "SCx200 device '%s' registered\n", + iface->adapter.name); + platform_set_drvdata(pdev, iface); - release_region(base, 8); - errout_free: - kfree(iface); - return rc; + return 0; } -/* Driver data is an index into the scx200_data array that indicates - * the name and the BAR where the I/O address resource is located. ISA - * devices are flagged with a bar value of -1 */ - -static const struct pci_device_id scx200_pci[] __initconst = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA), - .driver_data = 1 }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA), - .driver_data = 2 }, - { 0, } -}; - -static struct { - const char *name; - int bar; -} scx200_data[] = { - { "SCx200", -1 }, - { "CS5535", 0 }, - { "CS5536", 0 } -}; +static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface) +{ + i2c_del_adapter(&iface->adapter); + release_region(iface->base, 8); + kfree(iface); +} -static __init int scx200_scan_pci(void) +static int __devexit scx200_remove(struct platform_device *pdev) { - int data, dev; - int rc = -ENODEV; - struct pci_dev *pdev; + struct scx200_acb_iface *iface; - for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) { - pdev = pci_get_device(scx200_pci[dev].vendor, - scx200_pci[dev].device, NULL); + iface = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + scx200_cleanup_iface(iface); - if (pdev == NULL) - continue; + return 0; +} - data = scx200_pci[dev].driver_data; +static struct platform_driver scx200_pci_drv = { + .driver = { + .name = "cs5535-smb", + .owner = THIS_MODULE, + }, + .probe = scx200_probe, + .remove = __devexit_p(scx200_remove), +}; - /* if .bar is greater or equal to zero, this is a - * PCI device - otherwise, we assume - that the ports are ISA based - */ +static const struct pci_device_id scx200_isa[] __initconst = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, + { 0, } +}; - if (scx200_data[data].bar >= 0) - rc = scx200_create_pci(scx200_data[data].name, pdev, - scx200_data[data].bar); - else { - int i; +static __init void scx200_scan_isa(void) +{ + int i; - pci_dev_put(pdev); - for (i = 0; i < MAX_DEVICES; ++i) { - if (base[i] == 0) - continue; + if (!pci_dev_present(scx200_isa)) + return; - rc = scx200_create_isa(scx200_data[data].name, - base[i], - i); - } - } + for (i = 0; i < MAX_DEVICES; ++i) { + if (base[i] == 0) + continue; - break; + /* XXX: should we care about failures? */ + scx200_create_dev("SCx200", base[i], i, NULL); } - - return rc; } static int __init scx200_acb_init(void) { - int rc; - pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); - rc = scx200_scan_pci(); + /* First scan for ISA-based devices */ + scx200_scan_isa(); /* XXX: should we care about errors? */ /* If at least one bus was created, init must succeed */ if (scx200_acb_list) return 0; - return rc; + + /* No ISA devices; register the platform driver for PCI-based devices */ + return platform_driver_register(&scx200_pci_drv); } static void __exit scx200_acb_cleanup(void) { struct scx200_acb_iface *iface; + platform_driver_unregister(&scx200_pci_drv); + mutex_lock(&scx200_acb_list_mutex); while ((iface = scx200_acb_list) != NULL) { scx200_acb_list = iface->next; mutex_unlock(&scx200_acb_list_mutex); - i2c_del_adapter(&iface->adapter); - - if (iface->pdev) { - pci_release_region(iface->pdev, iface->bar); - pci_dev_put(iface->pdev); - } - else - release_region(iface->base, 8); + scx200_cleanup_iface(iface); - kfree(iface); mutex_lock(&scx200_acb_list_mutex); } mutex_unlock(&scx200_acb_list_mutex); |