15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-1.0+
2495a678fSSylvain Munaut /*
3495a678fSSylvain Munaut * OHCI HCD (Host Controller Driver) for USB.
4495a678fSSylvain Munaut *
5495a678fSSylvain Munaut * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
6495a678fSSylvain Munaut * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
7495a678fSSylvain Munaut * (C) Copyright 2002 Hewlett-Packard Company
8495a678fSSylvain Munaut * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
9495a678fSSylvain Munaut *
10495a678fSSylvain Munaut * Bus glue for OHCI HC on the of_platform bus
11495a678fSSylvain Munaut *
12495a678fSSylvain Munaut * Modified for of_platform bus from ohci-sa1111.c
13495a678fSSylvain Munaut *
14495a678fSSylvain Munaut * This file is licenced under the GPL.
15495a678fSSylvain Munaut */
16495a678fSSylvain Munaut
17495a678fSSylvain Munaut #include <linux/signal.h>
18*484468fbSRob Herring #include <linux/of.h>
195af50730SRob Herring #include <linux/of_address.h>
205af50730SRob Herring #include <linux/of_irq.h>
21*484468fbSRob Herring #include <linux/platform_device.h>
22495a678fSSylvain Munaut
2341ac7b3aSBill Pemberton static int
ohci_ppc_of_start(struct usb_hcd * hcd)24495a678fSSylvain Munaut ohci_ppc_of_start(struct usb_hcd *hcd)
25495a678fSSylvain Munaut {
26495a678fSSylvain Munaut struct ohci_hcd *ohci = hcd_to_ohci(hcd);
27495a678fSSylvain Munaut int ret;
28495a678fSSylvain Munaut
29495a678fSSylvain Munaut if ((ret = ohci_init(ohci)) < 0)
30495a678fSSylvain Munaut return ret;
31495a678fSSylvain Munaut
32495a678fSSylvain Munaut if ((ret = ohci_run(ohci)) < 0) {
331d55b768SGreg Kroah-Hartman dev_err(hcd->self.controller, "can't start %s\n",
341d55b768SGreg Kroah-Hartman hcd->self.bus_name);
35495a678fSSylvain Munaut ohci_stop(hcd);
36495a678fSSylvain Munaut return ret;
37495a678fSSylvain Munaut }
38495a678fSSylvain Munaut
39495a678fSSylvain Munaut return 0;
40495a678fSSylvain Munaut }
41495a678fSSylvain Munaut
42495a678fSSylvain Munaut static const struct hc_driver ohci_ppc_of_hc_driver = {
43495a678fSSylvain Munaut .description = hcd_name,
44495a678fSSylvain Munaut .product_desc = "OF OHCI",
45495a678fSSylvain Munaut .hcd_priv_size = sizeof(struct ohci_hcd),
46495a678fSSylvain Munaut
47495a678fSSylvain Munaut /*
48495a678fSSylvain Munaut * generic hardware linkage
49495a678fSSylvain Munaut */
50495a678fSSylvain Munaut .irq = ohci_irq,
517b81cb6bSChristoph Hellwig .flags = HCD_USB11 | HCD_DMA | HCD_MEMORY,
52495a678fSSylvain Munaut
53495a678fSSylvain Munaut /*
54495a678fSSylvain Munaut * basic lifecycle operations
55495a678fSSylvain Munaut */
56495a678fSSylvain Munaut .start = ohci_ppc_of_start,
57495a678fSSylvain Munaut .stop = ohci_stop,
58495a678fSSylvain Munaut .shutdown = ohci_shutdown,
59495a678fSSylvain Munaut
60495a678fSSylvain Munaut /*
61495a678fSSylvain Munaut * managing i/o requests and associated device resources
62495a678fSSylvain Munaut */
63495a678fSSylvain Munaut .urb_enqueue = ohci_urb_enqueue,
64495a678fSSylvain Munaut .urb_dequeue = ohci_urb_dequeue,
65495a678fSSylvain Munaut .endpoint_disable = ohci_endpoint_disable,
66495a678fSSylvain Munaut
67495a678fSSylvain Munaut /*
68495a678fSSylvain Munaut * scheduling support
69495a678fSSylvain Munaut */
70495a678fSSylvain Munaut .get_frame_number = ohci_get_frame,
71495a678fSSylvain Munaut
72495a678fSSylvain Munaut /*
73495a678fSSylvain Munaut * root hub support
74495a678fSSylvain Munaut */
75495a678fSSylvain Munaut .hub_status_data = ohci_hub_status_data,
76495a678fSSylvain Munaut .hub_control = ohci_hub_control,
77495a678fSSylvain Munaut #ifdef CONFIG_PM
78495a678fSSylvain Munaut .bus_suspend = ohci_bus_suspend,
79495a678fSSylvain Munaut .bus_resume = ohci_bus_resume,
80495a678fSSylvain Munaut #endif
81495a678fSSylvain Munaut .start_port_reset = ohci_start_port_reset,
82495a678fSSylvain Munaut };
83495a678fSSylvain Munaut
84495a678fSSylvain Munaut
ohci_hcd_ppc_of_probe(struct platform_device * op)8541ac7b3aSBill Pemberton static int ohci_hcd_ppc_of_probe(struct platform_device *op)
86495a678fSSylvain Munaut {
8761c7a080SGrant Likely struct device_node *dn = op->dev.of_node;
88495a678fSSylvain Munaut struct usb_hcd *hcd;
89495a678fSSylvain Munaut struct ohci_hcd *ohci;
90495a678fSSylvain Munaut struct resource res;
91495a678fSSylvain Munaut int irq;
92495a678fSSylvain Munaut
93495a678fSSylvain Munaut int rv;
94495a678fSSylvain Munaut int is_bigendian;
95796bcae7SVitaly Bordug struct device_node *np;
96495a678fSSylvain Munaut
97495a678fSSylvain Munaut if (usb_disabled())
98495a678fSSylvain Munaut return -ENODEV;
99495a678fSSylvain Munaut
100495a678fSSylvain Munaut is_bigendian =
10155b61fecSStephen Rothwell of_device_is_compatible(dn, "ohci-bigendian") ||
10255b61fecSStephen Rothwell of_device_is_compatible(dn, "ohci-be");
103495a678fSSylvain Munaut
104495a678fSSylvain Munaut dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
105495a678fSSylvain Munaut
106495a678fSSylvain Munaut rv = of_address_to_resource(dn, 0, &res);
107495a678fSSylvain Munaut if (rv)
108495a678fSSylvain Munaut return rv;
109495a678fSSylvain Munaut
110495a678fSSylvain Munaut hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
111495a678fSSylvain Munaut if (!hcd)
112495a678fSSylvain Munaut return -ENOMEM;
113495a678fSSylvain Munaut
114495a678fSSylvain Munaut hcd->rsrc_start = res.start;
11528f65c11SJoe Perches hcd->rsrc_len = resource_size(&res);
116495a678fSSylvain Munaut
1173e2e714eSJingoo Han hcd->regs = devm_ioremap_resource(&op->dev, &res);
1183e2e714eSJingoo Han if (IS_ERR(hcd->regs)) {
1193e2e714eSJingoo Han rv = PTR_ERR(hcd->regs);
120495a678fSSylvain Munaut goto err_rmr;
121495a678fSSylvain Munaut }
122495a678fSSylvain Munaut
123495a678fSSylvain Munaut irq = irq_of_parse_and_map(dn, 0);
1248836402dSChristophe Leroy if (!irq) {
12563c9b9d3SJingoo Han dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
12663c9b9d3SJingoo Han __FILE__);
127495a678fSSylvain Munaut rv = -EBUSY;
1283e2e714eSJingoo Han goto err_rmr;
129495a678fSSylvain Munaut }
130495a678fSSylvain Munaut
131495a678fSSylvain Munaut ohci = hcd_to_ohci(hcd);
1324f45426cSValentine Barshak if (is_bigendian) {
133495a678fSSylvain Munaut ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
13466ffbe49SGrant Likely if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
13566ffbe49SGrant Likely ohci->flags |= OHCI_QUIRK_FRAME_NO;
1364f45426cSValentine Barshak if (of_device_is_compatible(dn, "mpc5200-ohci"))
1374f45426cSValentine Barshak ohci->flags |= OHCI_QUIRK_FRAME_NO;
1384f45426cSValentine Barshak }
139495a678fSSylvain Munaut
140495a678fSSylvain Munaut ohci_hcd_init(ohci);
141495a678fSSylvain Munaut
142b5dd18d8SYong Zhang rv = usb_add_hcd(hcd, irq, 0);
1433c9740a1SPeter Chen if (rv == 0) {
1443c9740a1SPeter Chen device_wakeup_enable(hcd->self.controller);
145495a678fSSylvain Munaut return 0;
1463c9740a1SPeter Chen }
147495a678fSSylvain Munaut
148796bcae7SVitaly Bordug /* by now, 440epx is known to show usb_23 erratum */
149796bcae7SVitaly Bordug np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
150796bcae7SVitaly Bordug
151796bcae7SVitaly Bordug /* Work around - At this point ohci_run has executed, the
152796bcae7SVitaly Bordug * controller is running, everything, the root ports, etc., is
153796bcae7SVitaly Bordug * set up. If the ehci driver is loaded, put the ohci core in
154796bcae7SVitaly Bordug * the suspended state. The ehci driver will bring it out of
155796bcae7SVitaly Bordug * suspended state when / if a non-high speed USB device is
156796bcae7SVitaly Bordug * attached to the USB Host port. If the ehci driver is not
157796bcae7SVitaly Bordug * loaded, do nothing. request_mem_region is used to test if
158796bcae7SVitaly Bordug * the ehci driver is loaded.
159796bcae7SVitaly Bordug */
160796bcae7SVitaly Bordug if (np != NULL) {
161796bcae7SVitaly Bordug if (!of_address_to_resource(np, 0, &res)) {
162796bcae7SVitaly Bordug if (!request_mem_region(res.start, 0x4, hcd_name)) {
163796bcae7SVitaly Bordug writel_be((readl_be(&ohci->regs->control) |
164796bcae7SVitaly Bordug OHCI_USB_SUSPEND), &ohci->regs->control);
165796bcae7SVitaly Bordug (void) readl_be(&ohci->regs->control);
166796bcae7SVitaly Bordug } else
167796bcae7SVitaly Bordug release_mem_region(res.start, 0x4);
168796bcae7SVitaly Bordug } else
169f45ba776SJoe Perches pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
17040a959d7SLiang He of_node_put(np);
171796bcae7SVitaly Bordug }
172796bcae7SVitaly Bordug
173495a678fSSylvain Munaut irq_dispose_mapping(irq);
174495a678fSSylvain Munaut err_rmr:
175495a678fSSylvain Munaut usb_put_hcd(hcd);
176495a678fSSylvain Munaut
177495a678fSSylvain Munaut return rv;
178495a678fSSylvain Munaut }
179495a678fSSylvain Munaut
ohci_hcd_ppc_of_remove(struct platform_device * op)1807b0b8100SUwe Kleine-König static void ohci_hcd_ppc_of_remove(struct platform_device *op)
181495a678fSSylvain Munaut {
182477527baSJingoo Han struct usb_hcd *hcd = platform_get_drvdata(op);
183495a678fSSylvain Munaut
184495a678fSSylvain Munaut dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
185495a678fSSylvain Munaut
186495a678fSSylvain Munaut usb_remove_hcd(hcd);
187495a678fSSylvain Munaut
188495a678fSSylvain Munaut irq_dispose_mapping(hcd->irq);
189495a678fSSylvain Munaut
190495a678fSSylvain Munaut usb_put_hcd(hcd);
191495a678fSSylvain Munaut }
192495a678fSSylvain Munaut
193c4386ad0SNémeth Márton static const struct of_device_id ohci_hcd_ppc_of_match[] = {
194495a678fSSylvain Munaut #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
195495a678fSSylvain Munaut {
196495a678fSSylvain Munaut .name = "usb",
197495a678fSSylvain Munaut .compatible = "ohci-bigendian",
198495a678fSSylvain Munaut },
199495a678fSSylvain Munaut {
200495a678fSSylvain Munaut .name = "usb",
201495a678fSSylvain Munaut .compatible = "ohci-be",
202495a678fSSylvain Munaut },
203495a678fSSylvain Munaut #endif
204495a678fSSylvain Munaut #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
205495a678fSSylvain Munaut {
206495a678fSSylvain Munaut .name = "usb",
207495a678fSSylvain Munaut .compatible = "ohci-littledian",
208495a678fSSylvain Munaut },
209495a678fSSylvain Munaut {
210495a678fSSylvain Munaut .name = "usb",
211495a678fSSylvain Munaut .compatible = "ohci-le",
212495a678fSSylvain Munaut },
213495a678fSSylvain Munaut #endif
214495a678fSSylvain Munaut {},
215495a678fSSylvain Munaut };
216495a678fSSylvain Munaut MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
217495a678fSSylvain Munaut
218495a678fSSylvain Munaut #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
219495a678fSSylvain Munaut !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
2201c1301ddSMasanari Iida #error "No endianness selected for ppc-of-ohci"
221495a678fSSylvain Munaut #endif
222495a678fSSylvain Munaut
223495a678fSSylvain Munaut
224d35fb641SGrant Likely static struct platform_driver ohci_hcd_ppc_of_driver = {
225495a678fSSylvain Munaut .probe = ohci_hcd_ppc_of_probe,
2267b0b8100SUwe Kleine-König .remove_new = ohci_hcd_ppc_of_remove,
227aaf6b52dSRoger Quadros .shutdown = usb_hcd_platform_shutdown,
228495a678fSSylvain Munaut .driver = {
229495a678fSSylvain Munaut .name = "ppc-of-ohci",
2304018294bSGrant Likely .of_match_table = ohci_hcd_ppc_of_match,
231495a678fSSylvain Munaut },
232495a678fSSylvain Munaut };
233495a678fSSylvain Munaut
234