X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fi2c%2Fbusses%2Fscx200_acb.c;h=9b4f4ee4f6664ed0e4910cab70f15ccbe884ac0e;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=eae9e81be375acecb2a697fd23b7afdcab944b6a;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index eae9e81be..9b4f4ee4f 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -84,10 +85,6 @@ struct scx200_acb_iface { u8 *ptr; char needs_reset; unsigned len; - - /* PCI device info */ - struct pci_dev *pdev; - int bar; }; /* Register Definitions */ @@ -232,7 +229,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) unsigned long timeout; timeout = jiffies + POLL_TIMEOUT; - while (1) { + while (time_before(jiffies, timeout)) { status = inb(ACBST); /* Reset the status register to avoid the hang */ @@ -242,10 +239,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) scx200_acb_machine(iface, status); return; } - if (time_after(jiffies, timeout)) - break; - cpu_relax(); - cond_resched(); + yield(); } dev_err(&iface->adapter.dev, "timeout in state %s\n", @@ -391,7 +385,7 @@ static struct i2c_algorithm scx200_acb_algorithm = { static struct scx200_acb_iface *scx200_acb_list; static DECLARE_MUTEX(scx200_acb_list_mutex); -static __init int scx200_acb_probe(struct scx200_acb_iface *iface) +static int scx200_acb_probe(struct scx200_acb_iface *iface) { u8 val; @@ -427,16 +421,17 @@ 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, - int index) +static int __init scx200_acb_create(const char *text, int base, int index) { struct scx200_acb_iface *iface; struct i2c_adapter *adapter; + int rc; iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { printk(KERN_ERR NAME ": can't allocate memory\n"); - return NULL; + rc = -ENOMEM; + goto errout; } adapter = &iface->adapter; @@ -449,27 +444,26 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, mutex_init(&iface->mutex); - return iface; -} - -static int __init scx200_acb_create(struct scx200_acb_iface *iface) -{ - struct i2c_adapter *adapter; - int rc; - - adapter = &iface->adapter; + if (!request_region(base, 8, adapter->name)) { + printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", + base, base + 8-1); + rc = -EBUSY; + goto errout_free; + } + iface->base = base; rc = scx200_acb_probe(iface); if (rc) { printk(KERN_WARNING NAME ": probe failed\n"); - return rc; + goto errout_release; } scx200_acb_reset(iface); if (i2c_add_adapter(adapter) < 0) { printk(KERN_ERR NAME ": failed to register\n"); - return -ENODEV; + rc = -ENODEV; + goto errout_release; } down(&scx200_acb_list_mutex); @@ -478,148 +472,64 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface) up(&scx200_acb_list_mutex); return 0; -} -static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, - int bar) -{ - struct scx200_acb_iface *iface; - int rc; - - iface = scx200_create_iface(text, 0); - - if (iface == NULL) - return -ENOMEM; - - iface->pdev = pdev; - iface->bar = bar; - - pci_enable_device_bars(iface->pdev, 1 << iface->bar); - - rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); - - if (rc != 0) { - printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", - iface->bar); - goto errout_free; - } - - iface->base = pci_resource_start(iface->pdev, iface->bar); - rc = scx200_acb_create(iface); - - if (rc == 0) - return 0; - - pci_release_region(iface->pdev, iface->bar); - pci_dev_put(iface->pdev); + errout_release: + release_region(iface->base, 8); errout_free: kfree(iface); + errout: return rc; } -static int __init scx200_create_isa(const char *text, unsigned long base, - int index) -{ - struct scx200_acb_iface *iface; - int rc; - - iface = scx200_create_iface(text, index); - - if (iface == NULL) - return -ENOMEM; - - if (request_region(base, 8, iface->adapter.name) == 0) { - printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", - base, base + 8 - 1); - rc = -EBUSY; - goto errout_free; - } - - iface->base = base; - rc = scx200_acb_create(iface); - - if (rc == 0) - return 0; - - release_region(base, 8); - errout_free: - kfree(iface); - return rc; -} - -/* 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 struct pci_device_id scx200_pci[] = { - { 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 } +static struct pci_device_id scx200[] = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, + { }, }; -static struct { - const char *name; - int bar; -} scx200_data[] = { - { "SCx200", -1 }, - { "CS5535", 0 }, - { "CS5536", 0 } +static struct pci_device_id divil_pci[] = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, + { } /* NULL entry */ }; -static __init int scx200_scan_pci(void) +#define MSR_LBAR_SMB 0x5140000B + +static __init int scx200_add_cs553x(void) { - int data, dev; - int rc = -ENODEV; - struct pci_dev *pdev; - - for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) { - pdev = pci_get_device(scx200_pci[dev].vendor, - scx200_pci[dev].device, NULL); - - if (pdev == NULL) - continue; - - data = scx200_pci[dev].driver_data; - - /* if .bar is greater or equal to zero, this is a - * PCI device - otherwise, we assume - that the ports are ISA based - */ - - if (scx200_data[data].bar >= 0) - rc = scx200_create_pci(scx200_data[data].name, pdev, - scx200_data[data].bar); - else { - int i; - - for (i = 0; i < MAX_DEVICES; ++i) { - if (base[i] == 0) - continue; - - rc = scx200_create_isa(scx200_data[data].name, - base[i], - i); - } - } + u32 low, hi; + u32 smb_base; - break; + /* Grab & reserve the SMB I/O range */ + rdmsr(MSR_LBAR_SMB, low, hi); + + /* Check the IO mask and whether SMB is enabled */ + if (hi != 0x0000F001) { + printk(KERN_WARNING NAME ": SMBus not enabled\n"); + return -ENODEV; } - return rc; + /* SMBus IO size is 8 bytes */ + smb_base = low & 0x0000FFF8; + + return scx200_acb_create("CS5535", smb_base, 0); } static int __init scx200_acb_init(void) { - int rc; + int i; + int rc = -ENODEV; pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); - rc = scx200_scan_pci(); + /* Verify that this really is a SCx200 processor */ + if (pci_dev_present(scx200)) { + for (i = 0; i < MAX_DEVICES; ++i) { + if (base[i] > 0) + rc = scx200_acb_create("SCx200", base[i], i); + } + } else if (pci_dev_present(divil_pci)) + rc = scx200_add_cs553x(); /* If at least one bus was created, init must succeed */ if (scx200_acb_list) @@ -637,14 +547,7 @@ static void __exit scx200_acb_cleanup(void) up(&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); - + release_region(iface->base, 8); kfree(iface); down(&scx200_acb_list_mutex); }