Path: blob/master/arch/x86/platform/scx200/scx200_32.c
10819 views
/*1* Copyright (c) 2001,2002 Christer Weinigel <[email protected]>2*3* National Semiconductor SCx200 support.4*/56#include <linux/module.h>7#include <linux/errno.h>8#include <linux/kernel.h>9#include <linux/init.h>10#include <linux/mutex.h>11#include <linux/pci.h>1213#include <linux/scx200.h>14#include <linux/scx200_gpio.h>1516/* Verify that the configuration block really is there */17#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))1819#define NAME "scx200"2021MODULE_AUTHOR("Christer Weinigel <[email protected]>");22MODULE_DESCRIPTION("NatSemi SCx200 Driver");23MODULE_LICENSE("GPL");2425unsigned scx200_gpio_base = 0;26unsigned long scx200_gpio_shadow[2];2728unsigned scx200_cb_base = 0;2930static struct pci_device_id scx200_tbl[] = {31{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },32{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },33{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS) },34{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS) },35{ },36};37MODULE_DEVICE_TABLE(pci,scx200_tbl);3839static int __devinit scx200_probe(struct pci_dev *, const struct pci_device_id *);4041static struct pci_driver scx200_pci_driver = {42.name = "scx200",43.id_table = scx200_tbl,44.probe = scx200_probe,45};4647static DEFINE_MUTEX(scx200_gpio_config_lock);4849static void __devinit scx200_init_shadow(void)50{51int bank;5253/* read the current values driven on the GPIO signals */54for (bank = 0; bank < 2; ++bank)55scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);56}5758static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)59{60unsigned base;6162if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||63pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) {64base = pci_resource_start(pdev, 0);65printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);6667if (!request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) {68printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");69return -EBUSY;70}7172scx200_gpio_base = base;73scx200_init_shadow();7475} else {76/* find the base of the Configuration Block */77if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) {78scx200_cb_base = SCx200_CB_BASE_FIXED;79} else {80pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base);81if (scx200_cb_probe(base)) {82scx200_cb_base = base;83} else {84printk(KERN_WARNING NAME ": Configuration Block not found\n");85return -ENODEV;86}87}88printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base);89}9091return 0;92}9394u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)95{96u32 config, new_config;9798mutex_lock(&scx200_gpio_config_lock);99100outl(index, scx200_gpio_base + 0x20);101config = inl(scx200_gpio_base + 0x24);102103new_config = (config & mask) | bits;104outl(new_config, scx200_gpio_base + 0x24);105106mutex_unlock(&scx200_gpio_config_lock);107108return config;109}110111static int __init scx200_init(void)112{113printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");114115return pci_register_driver(&scx200_pci_driver);116}117118static void __exit scx200_cleanup(void)119{120pci_unregister_driver(&scx200_pci_driver);121release_region(scx200_gpio_base, SCx200_GPIO_SIZE);122}123124module_init(scx200_init);125module_exit(scx200_cleanup);126127EXPORT_SYMBOL(scx200_gpio_base);128EXPORT_SYMBOL(scx200_gpio_shadow);129EXPORT_SYMBOL(scx200_gpio_configure);130EXPORT_SYMBOL(scx200_cb_base);131132133