Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
0004  *
0005  *  National Semiconductor SCx200 support.
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 /* Verify that the configuration block really is there */
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     /* read the current values driven on the GPIO signals */
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         /* find the base of the Configuration Block */
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);