xref: /openbmc/linux/drivers/usb/host/ehci-grlib.c (revision 3ce7547e)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
4  *
5  * GRUSBHC is typically found on LEON/GRLIB SoCs
6  *
7  * (c) Jan Andersson <jan@gaisler.com>
8  *
9  * Based on ehci-ppc-of.c which is:
10  * (c) Valentine Barshak <vbarshak@ru.mvista.com>
11  * and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
12  * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
13  */
14 
15 #include <linux/err.h>
16 #include <linux/signal.h>
17 
18 #include <linux/of_irq.h>
19 #include <linux/of_address.h>
20 #include <linux/of_platform.h>
21 
22 #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
23 
24 static const struct hc_driver ehci_grlib_hc_driver = {
25 	.description		= hcd_name,
26 	.product_desc		= "GRLIB GRUSBHC EHCI",
27 	.hcd_priv_size		= sizeof(struct ehci_hcd),
28 
29 	/*
30 	 * generic hardware linkage
31 	 */
32 	.irq			= ehci_irq,
33 	.flags			= HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
34 
35 	/*
36 	 * basic lifecycle operations
37 	 */
38 	.reset			= ehci_setup,
39 	.start			= ehci_run,
40 	.stop			= ehci_stop,
41 	.shutdown		= ehci_shutdown,
42 
43 	/*
44 	 * managing i/o requests and associated device resources
45 	 */
46 	.urb_enqueue		= ehci_urb_enqueue,
47 	.urb_dequeue		= ehci_urb_dequeue,
48 	.endpoint_disable	= ehci_endpoint_disable,
49 	.endpoint_reset		= ehci_endpoint_reset,
50 
51 	/*
52 	 * scheduling support
53 	 */
54 	.get_frame_number	= ehci_get_frame,
55 
56 	/*
57 	 * root hub support
58 	 */
59 	.hub_status_data	= ehci_hub_status_data,
60 	.hub_control		= ehci_hub_control,
61 #ifdef	CONFIG_PM
62 	.bus_suspend		= ehci_bus_suspend,
63 	.bus_resume		= ehci_bus_resume,
64 #endif
65 	.relinquish_port	= ehci_relinquish_port,
66 	.port_handed_over	= ehci_port_handed_over,
67 
68 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
69 };
70 
71 
72 static int ehci_hcd_grlib_probe(struct platform_device *op)
73 {
74 	struct device_node *dn = op->dev.of_node;
75 	struct usb_hcd *hcd;
76 	struct ehci_hcd	*ehci = NULL;
77 	struct resource res;
78 	u32 hc_capbase;
79 	int irq;
80 	int rv;
81 
82 	if (usb_disabled())
83 		return -ENODEV;
84 
85 	dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
86 
87 	rv = of_address_to_resource(dn, 0, &res);
88 	if (rv)
89 		return rv;
90 
91 	/* usb_create_hcd requires dma_mask != NULL */
92 	op->dev.dma_mask = &op->dev.coherent_dma_mask;
93 	hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
94 			"GRUSBHC EHCI USB");
95 	if (!hcd)
96 		return -ENOMEM;
97 
98 	hcd->rsrc_start = res.start;
99 	hcd->rsrc_len = resource_size(&res);
100 
101 	irq = irq_of_parse_and_map(dn, 0);
102 	if (irq == NO_IRQ) {
103 		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
104 			__FILE__);
105 		rv = -EBUSY;
106 		goto err_irq;
107 	}
108 
109 	hcd->regs = devm_ioremap_resource(&op->dev, &res);
110 	if (IS_ERR(hcd->regs)) {
111 		rv = PTR_ERR(hcd->regs);
112 		goto err_ioremap;
113 	}
114 
115 	ehci = hcd_to_ehci(hcd);
116 
117 	ehci->caps = hcd->regs;
118 
119 	/* determine endianness of this implementation */
120 	hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
121 	if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
122 		ehci->big_endian_mmio = 1;
123 		ehci->big_endian_desc = 1;
124 		ehci->big_endian_capbase = 1;
125 	}
126 
127 	rv = usb_add_hcd(hcd, irq, 0);
128 	if (rv)
129 		goto err_ioremap;
130 
131 	device_wakeup_enable(hcd->self.controller);
132 	return 0;
133 
134 err_ioremap:
135 	irq_dispose_mapping(irq);
136 err_irq:
137 	usb_put_hcd(hcd);
138 
139 	return rv;
140 }
141 
142 
143 static int ehci_hcd_grlib_remove(struct platform_device *op)
144 {
145 	struct usb_hcd *hcd = platform_get_drvdata(op);
146 
147 	dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
148 
149 	usb_remove_hcd(hcd);
150 
151 	irq_dispose_mapping(hcd->irq);
152 
153 	usb_put_hcd(hcd);
154 
155 	return 0;
156 }
157 
158 
159 static const struct of_device_id ehci_hcd_grlib_of_match[] = {
160 	{
161 		.name = "GAISLER_EHCI",
162 	 },
163 	{
164 		.name = "01_026",
165 	 },
166 	{},
167 };
168 MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
169 
170 
171 static struct platform_driver ehci_grlib_driver = {
172 	.probe		= ehci_hcd_grlib_probe,
173 	.remove		= ehci_hcd_grlib_remove,
174 	.shutdown	= usb_hcd_platform_shutdown,
175 	.driver = {
176 		.name = "grlib-ehci",
177 		.of_match_table = ehci_hcd_grlib_of_match,
178 	},
179 };
180