1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
4 | * |
5 | * National Semiconductor SCx200 support. |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/errno.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> |
12 | #include <linux/mutex.h> |
13 | #include <linux/pci.h> |
14 | |
15 | #include <linux/scx200.h> |
16 | #include <linux/scx200_gpio.h> |
17 | |
18 | /* Verify that the configuration block really is there */ |
19 | #define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base)) |
20 | |
21 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>" ); |
22 | MODULE_DESCRIPTION("NatSemi SCx200 Driver" ); |
23 | MODULE_LICENSE("GPL" ); |
24 | |
25 | unsigned scx200_gpio_base = 0; |
26 | unsigned long scx200_gpio_shadow[2]; |
27 | |
28 | unsigned scx200_cb_base = 0; |
29 | |
30 | static struct pci_device_id scx200_tbl[] = { |
31 | { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, |
32 | { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, |
33 | { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_XBUS) }, |
34 | { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_XBUS) }, |
35 | { }, |
36 | }; |
37 | MODULE_DEVICE_TABLE(pci,scx200_tbl); |
38 | |
39 | static int scx200_probe(struct pci_dev *, const struct pci_device_id *); |
40 | |
41 | static struct pci_driver scx200_pci_driver = { |
42 | .name = "scx200" , |
43 | .id_table = scx200_tbl, |
44 | .probe = scx200_probe, |
45 | }; |
46 | |
47 | static DEFINE_MUTEX(scx200_gpio_config_lock); |
48 | |
49 | static void scx200_init_shadow(void) |
50 | { |
51 | int bank; |
52 | |
53 | /* read the current values driven on the GPIO signals */ |
54 | for (bank = 0; bank < 2; ++bank) |
55 | scx200_gpio_shadow[bank] = inl(port: scx200_gpio_base + 0x10 * bank); |
56 | } |
57 | |
58 | static int scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
59 | { |
60 | unsigned base; |
61 | |
62 | if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE || |
63 | pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) { |
64 | base = pci_resource_start(pdev, 0); |
65 | pr_info("GPIO base 0x%x\n" , base); |
66 | |
67 | if (!request_region(base, SCx200_GPIO_SIZE, |
68 | "NatSemi SCx200 GPIO" )) { |
69 | pr_err("can't allocate I/O for GPIOs\n" ); |
70 | return -EBUSY; |
71 | } |
72 | |
73 | scx200_gpio_base = base; |
74 | scx200_init_shadow(); |
75 | |
76 | } else { |
77 | /* find the base of the Configuration Block */ |
78 | if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) { |
79 | scx200_cb_base = SCx200_CB_BASE_FIXED; |
80 | } else { |
81 | pci_read_config_dword(dev: pdev, SCx200_CBA_SCRATCH, val: &base); |
82 | if (scx200_cb_probe(base)) { |
83 | scx200_cb_base = base; |
84 | } else { |
85 | pr_warn("Configuration Block not found\n" ); |
86 | return -ENODEV; |
87 | } |
88 | } |
89 | pr_info("Configuration Block base 0x%x\n" , scx200_cb_base); |
90 | } |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits) |
96 | { |
97 | u32 config, new_config; |
98 | |
99 | mutex_lock(&scx200_gpio_config_lock); |
100 | |
101 | outl(value: index, port: scx200_gpio_base + 0x20); |
102 | config = inl(port: scx200_gpio_base + 0x24); |
103 | |
104 | new_config = (config & mask) | bits; |
105 | outl(value: new_config, port: scx200_gpio_base + 0x24); |
106 | |
107 | mutex_unlock(lock: &scx200_gpio_config_lock); |
108 | |
109 | return config; |
110 | } |
111 | |
112 | static int __init scx200_init(void) |
113 | { |
114 | pr_info("NatSemi SCx200 Driver\n" ); |
115 | return pci_register_driver(&scx200_pci_driver); |
116 | } |
117 | |
118 | static void __exit scx200_cleanup(void) |
119 | { |
120 | pci_unregister_driver(dev: &scx200_pci_driver); |
121 | release_region(scx200_gpio_base, SCx200_GPIO_SIZE); |
122 | } |
123 | |
124 | module_init(scx200_init); |
125 | module_exit(scx200_cleanup); |
126 | |
127 | EXPORT_SYMBOL(scx200_gpio_base); |
128 | EXPORT_SYMBOL(scx200_gpio_shadow); |
129 | EXPORT_SYMBOL(scx200_gpio_configure); |
130 | EXPORT_SYMBOL(scx200_cb_base); |
131 | |