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 | ||
41 | /** | |
42 | * ci13xxx_pci_probe: PCI probe | |
43 | * @pdev: USB device controller being probed | |
44 | * @id: PCI hotplug ID connecting controller to UDC framework | |
45 | * | |
46 | * This function returns an error code | |
47 | * Allocates basic PCI resources for this USB device controller, and then | |
48 | * invokes the udc_probe() method to start the UDC associated with it | |
49 | */ | |
50 | static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, | |
51 | const struct pci_device_id *id) | |
52 | { | |
53 | void __iomem *regs = NULL; | |
54 | int retval = 0; | |
55 | ||
56 | if (id == NULL) | |
57 | return -EINVAL; | |
58 | ||
59 | retval = pci_enable_device(pdev); | |
60 | if (retval) | |
61 | goto done; | |
62 | ||
63 | if (!pdev->irq) { | |
64 | dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); | |
65 | retval = -ENODEV; | |
66 | goto disable_device; | |
67 | } | |
68 | ||
69 | retval = pci_request_regions(pdev, UDC_DRIVER_NAME); | |
70 | if (retval) | |
71 | goto disable_device; | |
72 | ||
73 | /* BAR 0 holds all the registers */ | |
74 | regs = pci_iomap(pdev, 0, 0); | |
75 | if (!regs) { | |
76 | dev_err(&pdev->dev, "Error mapping memory!"); | |
77 | retval = -EFAULT; | |
78 | goto release_regions; | |
79 | } | |
80 | pci_set_drvdata(pdev, (__force void *)regs); | |
81 | ||
82 | pci_set_master(pdev); | |
83 | pci_try_set_mwi(pdev); | |
84 | ||
85 | retval = udc_probe(&pdev->dev, regs, UDC_DRIVER_NAME); | |
86 | if (retval) | |
87 | goto iounmap; | |
88 | ||
89 | /* our device does not have MSI capability */ | |
90 | ||
91 | retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, | |
92 | UDC_DRIVER_NAME, pdev); | |
93 | if (retval) | |
94 | goto gadget_remove; | |
95 | ||
96 | return 0; | |
97 | ||
98 | gadget_remove: | |
99 | udc_remove(); | |
100 | iounmap: | |
101 | pci_iounmap(pdev, regs); | |
102 | release_regions: | |
103 | pci_release_regions(pdev); | |
104 | disable_device: | |
105 | pci_disable_device(pdev); | |
106 | done: | |
107 | return retval; | |
108 | } | |
109 | ||
110 | /** | |
111 | * ci13xxx_pci_remove: PCI remove | |
112 | * @pdev: USB Device Controller being removed | |
113 | * | |
114 | * Reverses the effect of ci13xxx_pci_probe(), | |
115 | * first invoking the udc_remove() and then releases | |
116 | * all PCI resources allocated for this USB device controller | |
117 | */ | |
118 | static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) | |
119 | { | |
120 | free_irq(pdev->irq, pdev); | |
121 | udc_remove(); | |
122 | pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); | |
123 | pci_release_regions(pdev); | |
124 | pci_disable_device(pdev); | |
125 | } | |
126 | ||
127 | /** | |
128 | * PCI device table | |
129 | * PCI device structure | |
130 | * | |
131 | * Check "pci.h" for details | |
132 | */ | |
133 | static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { | |
134 | { PCI_DEVICE(0x153F, 0x1004) }, | |
135 | { PCI_DEVICE(0x153F, 0x1006) }, | |
136 | { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } | |
137 | }; | |
138 | MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); | |
139 | ||
140 | static struct pci_driver ci13xxx_pci_driver = { | |
141 | .name = UDC_DRIVER_NAME, | |
142 | .id_table = ci13xxx_pci_id_table, | |
143 | .probe = ci13xxx_pci_probe, | |
144 | .remove = __devexit_p(ci13xxx_pci_remove), | |
145 | }; | |
146 | ||
147 | /** | |
148 | * ci13xxx_pci_init: module init | |
149 | * | |
150 | * Driver load | |
151 | */ | |
152 | static int __init ci13xxx_pci_init(void) | |
153 | { | |
154 | return pci_register_driver(&ci13xxx_pci_driver); | |
155 | } | |
156 | module_init(ci13xxx_pci_init); | |
157 | ||
158 | /** | |
159 | * ci13xxx_pci_exit: module exit | |
160 | * | |
161 | * Driver unload | |
162 | */ | |
163 | static void __exit ci13xxx_pci_exit(void) | |
164 | { | |
165 | pci_unregister_driver(&ci13xxx_pci_driver); | |
166 | } | |
167 | module_exit(ci13xxx_pci_exit); | |
168 | ||
169 | MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); | |
170 | MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); | |
171 | MODULE_LICENSE("GPL"); | |
172 | MODULE_VERSION("June 2008"); |