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  */
ci13xxx_pci_irq(int irq,void * pdev)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 static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
42 	.name		= UDC_DRIVER_NAME,
43 };
44 
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  */
ci13xxx_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)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 
89 	retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
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  */
ci13xxx_pci_remove(struct pci_dev * pdev)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  */
ci13xxx_pci_init(void)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  */
ci13xxx_pci_exit(void)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");
177