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; | |
f9df8395 | 58 | uintptr_t capoffset = DEF_CAPOFFSET; |
409a15da PK |
59 | int retval = 0; |
60 | ||
61 | if (id == NULL) | |
62 | return -EINVAL; | |
63 | ||
64 | retval = pci_enable_device(pdev); | |
65 | if (retval) | |
66 | goto done; | |
67 | ||
68 | if (!pdev->irq) { | |
69 | dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); | |
70 | retval = -ENODEV; | |
71 | goto disable_device; | |
72 | } | |
73 | ||
74 | retval = pci_request_regions(pdev, UDC_DRIVER_NAME); | |
75 | if (retval) | |
76 | goto disable_device; | |
77 | ||
78 | /* BAR 0 holds all the registers */ | |
79 | regs = pci_iomap(pdev, 0, 0); | |
80 | if (!regs) { | |
81 | dev_err(&pdev->dev, "Error mapping memory!"); | |
82 | retval = -EFAULT; | |
83 | goto release_regions; | |
84 | } | |
85 | pci_set_drvdata(pdev, (__force void *)regs); | |
86 | ||
87 | pci_set_master(pdev); | |
88 | pci_try_set_mwi(pdev); | |
89 | ||
f9df8395 AS |
90 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) |
91 | capoffset = 0; | |
92 | ||
93 | retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs, | |
94 | capoffset); | |
409a15da PK |
95 | if (retval) |
96 | goto iounmap; | |
97 | ||
98 | /* our device does not have MSI capability */ | |
99 | ||
100 | retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, | |
101 | UDC_DRIVER_NAME, pdev); | |
102 | if (retval) | |
103 | goto gadget_remove; | |
104 | ||
105 | return 0; | |
106 | ||
107 | gadget_remove: | |
108 | udc_remove(); | |
109 | iounmap: | |
110 | pci_iounmap(pdev, regs); | |
111 | release_regions: | |
112 | pci_release_regions(pdev); | |
113 | disable_device: | |
114 | pci_disable_device(pdev); | |
115 | done: | |
116 | return retval; | |
117 | } | |
118 | ||
119 | /** | |
120 | * ci13xxx_pci_remove: PCI remove | |
121 | * @pdev: USB Device Controller being removed | |
122 | * | |
123 | * Reverses the effect of ci13xxx_pci_probe(), | |
124 | * first invoking the udc_remove() and then releases | |
125 | * all PCI resources allocated for this USB device controller | |
126 | */ | |
127 | static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) | |
128 | { | |
129 | free_irq(pdev->irq, pdev); | |
130 | udc_remove(); | |
131 | pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); | |
132 | pci_release_regions(pdev); | |
133 | pci_disable_device(pdev); | |
134 | } | |
135 | ||
136 | /** | |
137 | * PCI device table | |
138 | * PCI device structure | |
139 | * | |
140 | * Check "pci.h" for details | |
141 | */ | |
142 | static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { | |
143 | { PCI_DEVICE(0x153F, 0x1004) }, | |
144 | { PCI_DEVICE(0x153F, 0x1006) }, | |
145 | { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } | |
146 | }; | |
147 | MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); | |
148 | ||
149 | static struct pci_driver ci13xxx_pci_driver = { | |
150 | .name = UDC_DRIVER_NAME, | |
151 | .id_table = ci13xxx_pci_id_table, | |
152 | .probe = ci13xxx_pci_probe, | |
153 | .remove = __devexit_p(ci13xxx_pci_remove), | |
154 | }; | |
155 | ||
3cdb7721 | 156 | module_pci_driver(ci13xxx_pci_driver); |
409a15da PK |
157 | |
158 | MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); | |
159 | MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); | |
160 | MODULE_LICENSE("GPL"); | |
161 | MODULE_VERSION("June 2008"); |