ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pci / hotplug / cpcihp_zt5550.c
1 /*
2  * cpcihp_zt5550.c
3  *
4  * Intel/Ziatech ZT5550 CompactPCI Host Controller driver
5  *
6  * Copyright 2002 SOMA Networks, Inc.
7  * Copyright 2001 Intel San Luis Obispo
8  * Copyright 2000,2001 MontaVista Software Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version.
14  *
15  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
17  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
18  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
22  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
23  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.,
28  * 675 Mass Ave, Cambridge, MA 02139, USA.
29  *
30  * Send feedback to <scottm@somanetworks.com>
31  */
32
33 #include <linux/config.h>
34 #include <linux/module.h>
35 #include <linux/init.h>
36 #include <linux/errno.h>
37 #include <linux/pci.h>
38 #include "cpci_hotplug.h"
39 #include "cpcihp_zt5550.h"
40
41 #define DRIVER_VERSION  "0.2"
42 #define DRIVER_AUTHOR   "Scott Murray <scottm@somanetworks.com>"
43 #define DRIVER_DESC     "ZT5550 CompactPCI Hot Plug Driver"
44
45 #if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE)
46 #define MY_NAME "cpcihp_zt5550"
47 #else
48 #define MY_NAME THIS_MODULE->name
49 #endif
50
51 #define dbg(format, arg...)                                     \
52         do {                                                    \
53                 if(debug)                                       \
54                         printk (KERN_DEBUG "%s: " format "\n",  \
55                                 MY_NAME , ## arg);              \
56         } while(0)
57 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
58 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
59 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
60
61 /* local variables */
62 static int debug;
63 static int poll;
64 static struct cpci_hp_controller_ops zt5550_hpc_ops;
65 static struct cpci_hp_controller zt5550_hpc;
66
67 /* Primary cPCI bus bridge device */
68 static struct pci_dev *bus0_dev;
69 static struct pci_bus *bus0;
70
71 /* Host controller device */
72 static struct pci_dev *hc_dev;
73
74 /* Host controller register addresses */
75 static void *hc_registers;
76 static void *csr_hc_index;
77 static void *csr_hc_data;
78 static void *csr_int_status;
79 static void *csr_int_mask;
80
81
82 static int zt5550_hc_config(struct pci_dev *pdev)
83 {
84         /* Since we know that no boards exist with two HC chips, treat it as an error */
85         if(hc_dev) {
86                 err("too many host controller devices?");
87                 return -EBUSY;
88         }
89         hc_dev = pdev;
90         dbg("hc_dev = %p", hc_dev);
91         dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
92         dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
93
94         if(!request_mem_region(pci_resource_start(hc_dev, 1),
95                                 pci_resource_len(hc_dev, 1), MY_NAME)) {
96                 err("cannot reserve MMIO region");
97                 return -ENOMEM;
98         }
99
100         hc_registers =
101             ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
102         if(!hc_registers) {
103                 err("cannot remap MMIO region %lx @ %lx",
104                     pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
105                 release_mem_region(pci_resource_start(hc_dev, 1),
106                                    pci_resource_len(hc_dev, 1));
107                 return -ENODEV;
108         }
109
110         csr_hc_index = hc_registers + CSR_HCINDEX;
111         csr_hc_data = hc_registers + CSR_HCDATA;
112         csr_int_status = hc_registers + CSR_INTSTAT;
113         csr_int_mask = hc_registers + CSR_INTMASK;
114
115         /*
116          * Disable host control, fault and serial interrupts
117          */
118         dbg("disabling host control, fault and serial interrupts");
119         writeb((u8) HC_INT_MASK_REG, csr_hc_index);
120         writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data);
121         dbg("disabled host control, fault and serial interrupts");
122
123         /*
124          * Disable timer0, timer1 and ENUM interrupts
125          */
126         dbg("disabling timer0, timer1 and ENUM interrupts");
127         writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask);
128         dbg("disabled timer0, timer1 and ENUM interrupts");
129         return 0;
130 }
131
132 static int zt5550_hc_cleanup(void)
133 {
134         if(!hc_dev)
135                 return -ENODEV;
136
137         iounmap(hc_registers);
138         release_mem_region(pci_resource_start(hc_dev, 1),
139                            pci_resource_len(hc_dev, 1));
140         return 0;
141 }
142
143 static int zt5550_hc_query_enum(void)
144 {
145         u8 value;
146
147         value = inb_p(ENUM_PORT);
148         return ((value & ENUM_MASK) == ENUM_MASK);
149 }
150
151 static int zt5550_hc_check_irq(void *dev_id)
152 {
153         int ret;
154         u8 reg;
155
156         ret = 0;
157         if(dev_id == zt5550_hpc.dev_id) {
158                 reg = readb(csr_int_status);
159                 if(reg)
160                         ret = 1;
161         }
162         return ret;
163 }
164
165 static int zt5550_hc_enable_irq(void)
166 {
167         u8 reg;
168
169         if(hc_dev == NULL) {
170                 return -ENODEV;
171         }
172         reg = readb(csr_int_mask);
173         reg = reg & ~ENUM_INT_MASK;
174         writeb(reg, csr_int_mask);
175         return 0;
176 }
177
178 int zt5550_hc_disable_irq(void)
179 {
180         u8 reg;
181
182         if(hc_dev == NULL) {
183                 return -ENODEV;
184         }
185
186         reg = readb(csr_int_mask);
187         reg = reg | ENUM_INT_MASK;
188         writeb(reg, csr_int_mask);
189         return 0;
190 }
191
192 static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
193 {
194         int status;
195
196         status = zt5550_hc_config(pdev);
197         if(status != 0) {
198                 return status;
199         }
200         dbg("returned from zt5550_hc_config");
201
202         memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller));
203         zt5550_hpc_ops.query_enum = zt5550_hc_query_enum;
204         zt5550_hpc.ops = &zt5550_hpc_ops;
205         if(!poll) {
206                 zt5550_hpc.irq = hc_dev->irq;
207                 zt5550_hpc.irq_flags = SA_SHIRQ;
208                 zt5550_hpc.dev_id = hc_dev;
209
210                 zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq;
211                 zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq;
212                 zt5550_hpc_ops.check_irq = zt5550_hc_check_irq;
213         } else {
214                 info("using ENUM# polling mode");
215         }
216
217         status = cpci_hp_register_controller(&zt5550_hpc);
218         if(status != 0) {
219                 err("could not register cPCI hotplug controller");
220                 goto init_hc_error;
221         }
222         dbg("registered controller");
223
224         /* Look for first device matching cPCI bus's bridge vendor and device IDs */
225         if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC,
226                                          PCI_DEVICE_ID_DEC_21154, NULL))) {
227                 status = -ENODEV;
228                 goto init_register_error;
229         }
230         bus0 = bus0_dev->subordinate;
231
232         status = cpci_hp_register_bus(bus0, 0x0a, 0x0f);
233         if(status != 0) {
234                 err("could not register cPCI hotplug bus");
235                 goto init_register_error;
236         }
237         dbg("registered bus");
238
239         status = cpci_hp_start();
240         if(status != 0) {
241                 err("could not started cPCI hotplug system");
242                 cpci_hp_unregister_bus(bus0);
243                 goto init_register_error;
244         }
245         dbg("started cpci hp system");
246
247         return 0;
248 init_register_error:
249         cpci_hp_unregister_controller(&zt5550_hpc);
250 init_hc_error:
251         err("status = %d", status);
252         zt5550_hc_cleanup();
253         return status;
254
255 }
256
257 static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev)
258 {
259         cpci_hp_stop();
260         cpci_hp_unregister_bus(bus0);
261         cpci_hp_unregister_controller(&zt5550_hpc);
262         zt5550_hc_cleanup();
263 }
264
265
266 static struct pci_device_id zt5550_hc_pci_tbl[] = {
267         { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, },
268         { 0, }
269 };
270 MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl);
271         
272 static struct pci_driver zt5550_hc_driver = {
273         .name           = "zt5550_hc",
274         .id_table       = zt5550_hc_pci_tbl,
275         .probe          = zt5550_hc_init_one,
276         .remove         = __devexit_p(zt5550_hc_remove_one),
277 };
278
279 static int __init zt5550_init(void)
280 {
281         struct resource* r;
282
283         info(DRIVER_DESC " version: " DRIVER_VERSION);
284         r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
285         if(!r)
286                 return -EBUSY;
287
288         return pci_module_init(&zt5550_hc_driver);
289 }
290
291 static void __exit
292 zt5550_exit(void)
293 {
294         pci_unregister_driver(&zt5550_hc_driver);
295         release_region(ENUM_PORT, 1);
296 }
297
298 module_init(zt5550_init);
299 module_exit(zt5550_exit);
300
301 MODULE_AUTHOR(DRIVER_AUTHOR);
302 MODULE_DESCRIPTION(DRIVER_DESC);
303 MODULE_LICENSE("GPL");
304 MODULE_PARM(debug, "i");
305 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
306 MODULE_PARM(poll, "i");
307 MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not");