]>
Commit | Line | Data |
---|---|---|
db11e47d SS |
1 | /* |
2 | * Glue code for the ISP1760 driver and bus | |
3 | * Currently there is support for | |
4 | * - OpenFirmware | |
5 | * - PCI | |
6 | * | |
7 | * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <linux/usb.h> | |
12 | #include <linux/io.h> | |
13 | ||
14 | #include "../core/hcd.h" | |
15 | #include "isp1760-hcd.h" | |
16 | ||
17 | #ifdef CONFIG_USB_ISP1760_OF | |
18 | #include <linux/of.h> | |
19 | #include <linux/of_platform.h> | |
20 | #endif | |
21 | ||
22 | #ifdef CONFIG_USB_ISP1760_PCI | |
23 | #include <linux/pci.h> | |
24 | #endif | |
25 | ||
26 | #ifdef CONFIG_USB_ISP1760_OF | |
27 | static int of_isp1760_probe(struct of_device *dev, | |
28 | const struct of_device_id *match) | |
29 | { | |
30 | struct usb_hcd *hcd; | |
31 | struct device_node *dp = dev->node; | |
32 | struct resource *res; | |
33 | struct resource memory; | |
34 | struct of_irq oirq; | |
35 | int virq; | |
36 | u64 res_len; | |
37 | int ret; | |
38 | ||
39 | ret = of_address_to_resource(dp, 0, &memory); | |
40 | if (ret) | |
41 | return -ENXIO; | |
42 | ||
43 | res = request_mem_region(memory.start, memory.end - memory.start + 1, | |
44 | dev->dev.bus_id); | |
45 | if (!res) | |
46 | return -EBUSY; | |
47 | ||
48 | res_len = memory.end - memory.start + 1; | |
49 | ||
50 | if (of_irq_map_one(dp, 0, &oirq)) { | |
51 | ret = -ENODEV; | |
52 | goto release_reg; | |
53 | } | |
54 | ||
55 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | |
56 | oirq.size); | |
57 | ||
58 | hcd = isp1760_register(memory.start, res_len, virq, | |
59 | IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); | |
60 | if (IS_ERR(hcd)) { | |
61 | ret = PTR_ERR(hcd); | |
62 | goto release_reg; | |
63 | } | |
64 | ||
65 | dev_set_drvdata(&dev->dev, hcd); | |
66 | return ret; | |
67 | ||
68 | release_reg: | |
69 | release_mem_region(memory.start, memory.end - memory.start + 1); | |
70 | return ret; | |
71 | } | |
72 | ||
73 | static int of_isp1760_remove(struct of_device *dev) | |
74 | { | |
75 | struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); | |
76 | ||
77 | dev_set_drvdata(&dev->dev, NULL); | |
78 | ||
79 | usb_remove_hcd(hcd); | |
80 | iounmap(hcd->regs); | |
81 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | |
82 | usb_put_hcd(hcd); | |
83 | return 0; | |
84 | } | |
85 | ||
86 | static struct of_device_id of_isp1760_match[] = { | |
87 | { | |
88 | .compatible = "nxp,usb-isp1760", | |
89 | }, | |
90 | { }, | |
91 | }; | |
92 | MODULE_DEVICE_TABLE(of, of_isp1760_match); | |
93 | ||
94 | static struct of_platform_driver isp1760_of_driver = { | |
95 | .name = "nxp-isp1760", | |
96 | .match_table = of_isp1760_match, | |
97 | .probe = of_isp1760_probe, | |
98 | .remove = of_isp1760_remove, | |
99 | }; | |
100 | #endif | |
101 | ||
102 | #ifdef CONFIG_USB_ISP1760_PCI | |
103 | static u32 nxp_pci_io_base; | |
104 | static u32 iolength; | |
105 | static u32 pci_mem_phy0; | |
106 | static u32 length; | |
6399e7ac AV |
107 | static u8 __iomem *chip_addr; |
108 | static u8 __iomem *iobase; | |
db11e47d SS |
109 | |
110 | static int __devinit isp1761_pci_probe(struct pci_dev *dev, | |
111 | const struct pci_device_id *id) | |
112 | { | |
113 | u8 latency, limit; | |
114 | __u32 reg_data; | |
115 | int retry_count; | |
116 | int length; | |
117 | int status = 1; | |
118 | struct usb_hcd *hcd; | |
119 | ||
120 | if (usb_disabled()) | |
121 | return -ENODEV; | |
122 | ||
123 | if (pci_enable_device(dev) < 0) | |
124 | return -ENODEV; | |
125 | ||
126 | if (!dev->irq) | |
127 | return -ENODEV; | |
128 | ||
129 | /* Grab the PLX PCI mem maped port start address we need */ | |
130 | nxp_pci_io_base = pci_resource_start(dev, 0); | |
131 | iolength = pci_resource_len(dev, 0); | |
132 | ||
133 | if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { | |
134 | printk(KERN_ERR "request region #1\n"); | |
135 | return -EBUSY; | |
136 | } | |
137 | ||
138 | iobase = ioremap_nocache(nxp_pci_io_base, iolength); | |
139 | if (!iobase) { | |
140 | printk(KERN_ERR "ioremap #1\n"); | |
141 | release_mem_region(nxp_pci_io_base, iolength); | |
142 | return -ENOMEM; | |
143 | } | |
144 | /* Grab the PLX PCI shared memory of the ISP 1761 we need */ | |
145 | pci_mem_phy0 = pci_resource_start(dev, 3); | |
146 | length = pci_resource_len(dev, 3); | |
147 | ||
148 | if (length < 0xffff) { | |
149 | printk(KERN_ERR "memory length for this resource is less than " | |
150 | "required\n"); | |
151 | release_mem_region(nxp_pci_io_base, iolength); | |
152 | iounmap(iobase); | |
153 | return -ENOMEM; | |
154 | } | |
155 | ||
156 | if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) { | |
157 | printk(KERN_ERR "host controller already in use\n"); | |
158 | release_mem_region(nxp_pci_io_base, iolength); | |
159 | iounmap(iobase); | |
160 | return -EBUSY; | |
161 | } | |
162 | ||
163 | /* bad pci latencies can contribute to overruns */ | |
164 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); | |
165 | if (latency) { | |
166 | pci_read_config_byte(dev, PCI_MAX_LAT, &limit); | |
167 | if (limit && limit < latency) | |
168 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); | |
169 | } | |
170 | ||
171 | /* Try to check whether we can access Scratch Register of | |
172 | * Host Controller or not. The initial PCI access is retried until | |
173 | * local init for the PCI bridge is completed | |
174 | */ | |
175 | retry_count = 20; | |
176 | reg_data = 0; | |
177 | while ((reg_data != 0xFACE) && retry_count) { | |
178 | /*by default host is in 16bit mode, so | |
179 | * io operations at this stage must be 16 bit | |
180 | * */ | |
181 | writel(0xface, chip_addr + HC_SCRATCH_REG); | |
182 | udelay(100); | |
183 | reg_data = readl(chip_addr + HC_SCRATCH_REG); | |
184 | retry_count--; | |
185 | } | |
186 | ||
187 | /* Host Controller presence is detected by writing to scratch register | |
188 | * and reading back and checking the contents are same or not | |
189 | */ | |
190 | if (reg_data != 0xFACE) { | |
191 | err("scratch register mismatch %x", reg_data); | |
192 | goto clean; | |
193 | } | |
194 | ||
195 | pci_set_master(dev); | |
196 | ||
197 | status = readl(iobase + 0x68); | |
198 | status |= 0x900; | |
199 | writel(status, iobase + 0x68); | |
200 | ||
201 | dev->dev.dma_mask = NULL; | |
202 | hcd = isp1760_register(pci_mem_phy0, length, dev->irq, | |
203 | IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); | |
204 | pci_set_drvdata(dev, hcd); | |
205 | if (!hcd) | |
206 | return 0; | |
207 | clean: | |
208 | status = -ENODEV; | |
209 | iounmap(iobase); | |
210 | release_mem_region(pci_mem_phy0, length); | |
211 | release_mem_region(nxp_pci_io_base, iolength); | |
212 | return status; | |
213 | } | |
214 | static void isp1761_pci_remove(struct pci_dev *dev) | |
215 | { | |
216 | struct usb_hcd *hcd; | |
217 | ||
218 | hcd = pci_get_drvdata(dev); | |
219 | ||
220 | usb_remove_hcd(hcd); | |
221 | iounmap(hcd->regs); | |
222 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | |
223 | usb_put_hcd(hcd); | |
224 | ||
225 | pci_disable_device(dev); | |
226 | ||
227 | iounmap(iobase); | |
228 | iounmap(chip_addr); | |
229 | ||
230 | release_mem_region(nxp_pci_io_base, iolength); | |
231 | release_mem_region(pci_mem_phy0, length); | |
232 | } | |
233 | ||
234 | static void isp1761_pci_shutdown(struct pci_dev *dev) | |
235 | { | |
236 | printk(KERN_ERR "ips1761_pci_shutdown\n"); | |
237 | } | |
238 | ||
239 | static const struct pci_device_id isp1760_plx [] = { { | |
240 | /* handle any USB 2.0 EHCI controller */ | |
241 | PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0), | |
242 | .driver_data = 0, | |
243 | }, | |
244 | { /* end: all zeroes */ } | |
245 | }; | |
246 | MODULE_DEVICE_TABLE(pci, isp1760_plx); | |
247 | ||
248 | static struct pci_driver isp1761_pci_driver = { | |
249 | .name = "isp1760", | |
250 | .id_table = isp1760_plx, | |
251 | .probe = isp1761_pci_probe, | |
252 | .remove = isp1761_pci_remove, | |
253 | .shutdown = isp1761_pci_shutdown, | |
254 | }; | |
255 | #endif | |
256 | ||
257 | static int __init isp1760_init(void) | |
258 | { | |
fe312e77 | 259 | int ret = -ENODEV; |
db11e47d SS |
260 | |
261 | init_kmem_once(); | |
262 | ||
263 | #ifdef CONFIG_USB_ISP1760_OF | |
264 | ret = of_register_platform_driver(&isp1760_of_driver); | |
265 | if (ret) { | |
266 | deinit_kmem_cache(); | |
267 | return ret; | |
268 | } | |
269 | #endif | |
270 | #ifdef CONFIG_USB_ISP1760_PCI | |
271 | ret = pci_register_driver(&isp1761_pci_driver); | |
272 | if (ret) | |
273 | goto unreg_of; | |
274 | #endif | |
275 | return ret; | |
276 | ||
277 | #ifdef CONFIG_USB_ISP1760_PCI | |
278 | unreg_of: | |
279 | #endif | |
280 | #ifdef CONFIG_USB_ISP1760_OF | |
281 | of_unregister_platform_driver(&isp1760_of_driver); | |
282 | #endif | |
283 | deinit_kmem_cache(); | |
284 | return ret; | |
285 | } | |
286 | module_init(isp1760_init); | |
287 | ||
288 | static void __exit isp1760_exit(void) | |
289 | { | |
290 | #ifdef CONFIG_USB_ISP1760_OF | |
291 | of_unregister_platform_driver(&isp1760_of_driver); | |
292 | #endif | |
293 | #ifdef CONFIG_USB_ISP1760_PCI | |
294 | pci_unregister_driver(&isp1761_pci_driver); | |
295 | #endif | |
296 | deinit_kmem_cache(); | |
297 | } | |
298 | module_exit(isp1760_exit); |