Commit | Line | Data |
---|---|---|
409a15da PK |
1 | /* |
2 | * ci13xxx_pci.c - MIPS USB IP core family device controller | |
3 | * | |
4 | * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. | |
5 | * | |
6 | * Author: David Lopo | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/module.h> | |
14 | #include <linux/pci.h> | |
15 | ||
16 | #include "ci13xxx_udc.c" | |
17 | ||
18 | /* driver name */ | |
19 | #define UDC_DRIVER_NAME "ci13xxx_pci" | |
20 | ||
21 | /****************************************************************************** | |
22 | * PCI block | |
23 | *****************************************************************************/ | |
24 | /** | |
25 | * ci13xxx_pci_irq: interrut handler | |
26 | * @irq: irq number | |
27 | * @pdev: USB Device Controller interrupt source | |
28 | * | |
29 | * This function returns IRQ_HANDLED if the IRQ has been handled | |
30 | * This is an ISR don't trace, use attribute interface instead | |
31 | */ | |
32 | static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev) | |
33 | { | |
34 | if (irq == 0) { | |
35 | dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!"); | |
36 | return IRQ_HANDLED; | |
37 | } | |
38 | return udc_irq(); | |
39 | } | |
40 | ||
f01ef574 PK |
41 | static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = { |
42 | .name = UDC_DRIVER_NAME, | |
43 | }; | |
44 | ||
409a15da PK |
45 | /** |
46 | * ci13xxx_pci_probe: PCI probe | |
47 | * @pdev: USB device controller being probed | |
48 | * @id: PCI hotplug ID connecting controller to UDC framework | |
49 | * | |
50 | * This function returns an error code | |
51 | * Allocates basic PCI resources for this USB device controller, and then | |
52 | * invokes the udc_probe() method to start the UDC associated with it | |
53 | */ | |
54 | static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, | |
55 | const struct pci_device_id *id) | |
56 | { | |
57 | void __iomem *regs = NULL; | |
58 | int retval = 0; | |
59 | ||
60 | if (id == NULL) | |
61 | return -EINVAL; | |
62 | ||
63 | retval = pci_enable_device(pdev); | |
64 | if (retval) | |
65 | goto done; | |
66 | ||
67 | if (!pdev->irq) { | |
68 | dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); | |
69 | retval = -ENODEV; | |
70 | goto disable_device; | |
71 | } | |
72 | ||
73 | retval = pci_request_regions(pdev, UDC_DRIVER_NAME); | |
74 | if (retval) | |
75 | goto disable_device; | |
76 | ||
77 | /* BAR 0 holds all the registers */ | |
78 | regs = pci_iomap(pdev, 0, 0); | |
79 | if (!regs) { | |
80 | dev_err(&pdev->dev, "Error mapping memory!"); | |
81 | retval = -EFAULT; | |
82 | goto release_regions; | |
83 | } | |
84 | pci_set_drvdata(pdev, (__force void *)regs); | |
85 | ||
86 | pci_set_master(pdev); | |
87 | pci_try_set_mwi(pdev); | |
88 | ||
f01ef574 | 89 | retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs); |
409a15da PK |
90 | if (retval) |
91 | goto iounmap; | |
92 | ||
93 | /* our device does not have MSI capability */ | |
94 | ||
95 | retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, | |
96 | UDC_DRIVER_NAME, pdev); | |
97 | if (retval) | |
98 | goto gadget_remove; | |
99 | ||
100 | return 0; | |
101 | ||
102 | gadget_remove: | |
103 | udc_remove(); | |
104 | iounmap: | |
105 | pci_iounmap(pdev, regs); | |
106 | release_regions: | |
107 | pci_release_regions(pdev); | |
108 | disable_device: | |
109 | pci_disable_device(pdev); | |
110 | done: | |
111 | return retval; | |
112 | } | |
113 | ||
114 | /** | |
115 | * ci13xxx_pci_remove: PCI remove | |
116 | * @pdev: USB Device Controller being removed | |
117 | * | |
118 | * Reverses the effect of ci13xxx_pci_probe(), | |
119 | * first invoking the udc_remove() and then releases | |
120 | * all PCI resources allocated for this USB device controller | |
121 | */ | |
122 | static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) | |
123 | { | |
124 | free_irq(pdev->irq, pdev); | |
125 | udc_remove(); | |
126 | pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); | |
127 | pci_release_regions(pdev); | |
128 | pci_disable_device(pdev); | |
129 | } | |
130 | ||
131 | /** | |
132 | * PCI device table | |
133 | * PCI device structure | |
134 | * | |
135 | * Check "pci.h" for details | |
136 | */ | |
137 | static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { | |
138 | { PCI_DEVICE(0x153F, 0x1004) }, | |
139 | { PCI_DEVICE(0x153F, 0x1006) }, | |
140 | { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } | |
141 | }; | |
142 | MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); | |
143 | ||
144 | static struct pci_driver ci13xxx_pci_driver = { | |
145 | .name = UDC_DRIVER_NAME, | |
146 | .id_table = ci13xxx_pci_id_table, | |
147 | .probe = ci13xxx_pci_probe, | |
148 | .remove = __devexit_p(ci13xxx_pci_remove), | |
149 | }; | |
150 | ||
151 | /** | |
152 | * ci13xxx_pci_init: module init | |
153 | * | |
154 | * Driver load | |
155 | */ | |
156 | static int __init ci13xxx_pci_init(void) | |
157 | { | |
158 | return pci_register_driver(&ci13xxx_pci_driver); | |
159 | } | |
160 | module_init(ci13xxx_pci_init); | |
161 | ||
162 | /** | |
163 | * ci13xxx_pci_exit: module exit | |
164 | * | |
165 | * Driver unload | |
166 | */ | |
167 | static void __exit ci13xxx_pci_exit(void) | |
168 | { | |
169 | pci_unregister_driver(&ci13xxx_pci_driver); | |
170 | } | |
171 | module_exit(ci13xxx_pci_exit); | |
172 | ||
173 | MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); | |
174 | MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); | |
175 | MODULE_LICENSE("GPL"); | |
176 | MODULE_VERSION("June 2008"); |