0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/errno.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/mutex.h>
0013 #include <linux/pci.h>
0014
0015 #include <linux/scx200.h>
0016 #include <linux/scx200_gpio.h>
0017
0018
0019 #define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
0020
0021 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
0022 MODULE_DESCRIPTION("NatSemi SCx200 Driver");
0023 MODULE_LICENSE("GPL");
0024
0025 unsigned scx200_gpio_base = 0;
0026 unsigned long scx200_gpio_shadow[2];
0027
0028 unsigned scx200_cb_base = 0;
0029
0030 static struct pci_device_id scx200_tbl[] = {
0031 { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
0032 { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
0033 { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_XBUS) },
0034 { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_XBUS) },
0035 { },
0036 };
0037 MODULE_DEVICE_TABLE(pci,scx200_tbl);
0038
0039 static int scx200_probe(struct pci_dev *, const struct pci_device_id *);
0040
0041 static struct pci_driver scx200_pci_driver = {
0042 .name = "scx200",
0043 .id_table = scx200_tbl,
0044 .probe = scx200_probe,
0045 };
0046
0047 static DEFINE_MUTEX(scx200_gpio_config_lock);
0048
0049 static void scx200_init_shadow(void)
0050 {
0051 int bank;
0052
0053
0054 for (bank = 0; bank < 2; ++bank)
0055 scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
0056 }
0057
0058 static int scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
0059 {
0060 unsigned base;
0061
0062 if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
0063 pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) {
0064 base = pci_resource_start(pdev, 0);
0065 pr_info("GPIO base 0x%x\n", base);
0066
0067 if (!request_region(base, SCx200_GPIO_SIZE,
0068 "NatSemi SCx200 GPIO")) {
0069 pr_err("can't allocate I/O for GPIOs\n");
0070 return -EBUSY;
0071 }
0072
0073 scx200_gpio_base = base;
0074 scx200_init_shadow();
0075
0076 } else {
0077
0078 if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) {
0079 scx200_cb_base = SCx200_CB_BASE_FIXED;
0080 } else {
0081 pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base);
0082 if (scx200_cb_probe(base)) {
0083 scx200_cb_base = base;
0084 } else {
0085 pr_warn("Configuration Block not found\n");
0086 return -ENODEV;
0087 }
0088 }
0089 pr_info("Configuration Block base 0x%x\n", scx200_cb_base);
0090 }
0091
0092 return 0;
0093 }
0094
0095 u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)
0096 {
0097 u32 config, new_config;
0098
0099 mutex_lock(&scx200_gpio_config_lock);
0100
0101 outl(index, scx200_gpio_base + 0x20);
0102 config = inl(scx200_gpio_base + 0x24);
0103
0104 new_config = (config & mask) | bits;
0105 outl(new_config, scx200_gpio_base + 0x24);
0106
0107 mutex_unlock(&scx200_gpio_config_lock);
0108
0109 return config;
0110 }
0111
0112 static int __init scx200_init(void)
0113 {
0114 pr_info("NatSemi SCx200 Driver\n");
0115 return pci_register_driver(&scx200_pci_driver);
0116 }
0117
0118 static void __exit scx200_cleanup(void)
0119 {
0120 pci_unregister_driver(&scx200_pci_driver);
0121 release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
0122 }
0123
0124 module_init(scx200_init);
0125 module_exit(scx200_cleanup);
0126
0127 EXPORT_SYMBOL(scx200_gpio_base);
0128 EXPORT_SYMBOL(scx200_gpio_shadow);
0129 EXPORT_SYMBOL(scx200_gpio_configure);
0130 EXPORT_SYMBOL(scx200_cb_base);