xref: /openbmc/linux/drivers/usb/host/ohci-platform.c (revision ee89bd6b)
1 /*
2  * Generic platform ohci driver
3  *
4  * Copyright 2007 Michael Buesch <m@bues.ch>
5  * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
6  *
7  * Derived from the OCHI-SSB driver
8  * Derived from the OHCI-PCI driver
9  * Copyright 1999 Roman Weissgaerber
10  * Copyright 2000-2002 David Brownell
11  * Copyright 1999 Linus Torvalds
12  * Copyright 1999 Gregory P. Smith
13  *
14  * Licensed under the GNU/GPL. See COPYING for details.
15  */
16 #include <linux/err.h>
17 #include <linux/platform_device.h>
18 #include <linux/usb/ohci_pdriver.h>
19 
20 static int ohci_platform_reset(struct usb_hcd *hcd)
21 {
22 	struct platform_device *pdev = to_platform_device(hcd->self.controller);
23 	struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
24 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
25 	int err;
26 
27 	if (pdata->big_endian_desc)
28 		ohci->flags |= OHCI_QUIRK_BE_DESC;
29 	if (pdata->big_endian_mmio)
30 		ohci->flags |= OHCI_QUIRK_BE_MMIO;
31 	if (pdata->no_big_frame_no)
32 		ohci->flags |= OHCI_QUIRK_FRAME_NO;
33 
34 	ohci_hcd_init(ohci);
35 
36 	if (pdata->num_ports)
37 		ohci->num_ports = pdata->num_ports;
38 
39 	err = ohci_init(ohci);
40 
41 	return err;
42 }
43 
44 static int ohci_platform_start(struct usb_hcd *hcd)
45 {
46 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
47 	int err;
48 
49 	err = ohci_run(ohci);
50 	if (err < 0) {
51 		ohci_err(ohci, "can't start\n");
52 		ohci_stop(hcd);
53 	}
54 
55 	return err;
56 }
57 
58 static const struct hc_driver ohci_platform_hc_driver = {
59 	.description		= hcd_name,
60 	.product_desc		= "Generic Platform OHCI Controller",
61 	.hcd_priv_size		= sizeof(struct ohci_hcd),
62 
63 	.irq			= ohci_irq,
64 	.flags			= HCD_MEMORY | HCD_USB11,
65 
66 	.reset			= ohci_platform_reset,
67 	.start			= ohci_platform_start,
68 	.stop			= ohci_stop,
69 	.shutdown		= ohci_shutdown,
70 
71 	.urb_enqueue		= ohci_urb_enqueue,
72 	.urb_dequeue		= ohci_urb_dequeue,
73 	.endpoint_disable	= ohci_endpoint_disable,
74 
75 	.get_frame_number	= ohci_get_frame,
76 
77 	.hub_status_data	= ohci_hub_status_data,
78 	.hub_control		= ohci_hub_control,
79 #ifdef	CONFIG_PM
80 	.bus_suspend		= ohci_bus_suspend,
81 	.bus_resume		= ohci_bus_resume,
82 #endif
83 
84 	.start_port_reset	= ohci_start_port_reset,
85 };
86 
87 static int ohci_platform_probe(struct platform_device *dev)
88 {
89 	struct usb_hcd *hcd;
90 	struct resource *res_mem;
91 	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
92 	int irq;
93 	int err = -ENOMEM;
94 
95 	if (!pdata) {
96 		WARN_ON(1);
97 		return -ENODEV;
98 	}
99 
100 	if (usb_disabled())
101 		return -ENODEV;
102 
103 	irq = platform_get_irq(dev, 0);
104 	if (irq < 0) {
105 		dev_err(&dev->dev, "no irq provided");
106 		return irq;
107 	}
108 
109 	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
110 	if (!res_mem) {
111 		dev_err(&dev->dev, "no memory resource provided");
112 		return -ENXIO;
113 	}
114 
115 	if (pdata->power_on) {
116 		err = pdata->power_on(dev);
117 		if (err < 0)
118 			return err;
119 	}
120 
121 	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
122 			dev_name(&dev->dev));
123 	if (!hcd) {
124 		err = -ENOMEM;
125 		goto err_power;
126 	}
127 
128 	hcd->rsrc_start = res_mem->start;
129 	hcd->rsrc_len = resource_size(res_mem);
130 
131 	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
132 	if (IS_ERR(hcd->regs)) {
133 		err = PTR_ERR(hcd->regs);
134 		goto err_put_hcd;
135 	}
136 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
137 	if (err)
138 		goto err_put_hcd;
139 
140 	platform_set_drvdata(dev, hcd);
141 
142 	return err;
143 
144 err_put_hcd:
145 	usb_put_hcd(hcd);
146 err_power:
147 	if (pdata->power_off)
148 		pdata->power_off(dev);
149 
150 	return err;
151 }
152 
153 static int ohci_platform_remove(struct platform_device *dev)
154 {
155 	struct usb_hcd *hcd = platform_get_drvdata(dev);
156 	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
157 
158 	usb_remove_hcd(hcd);
159 	usb_put_hcd(hcd);
160 	platform_set_drvdata(dev, NULL);
161 
162 	if (pdata->power_off)
163 		pdata->power_off(dev);
164 
165 	return 0;
166 }
167 
168 #ifdef CONFIG_PM
169 
170 static int ohci_platform_suspend(struct device *dev)
171 {
172 	struct usb_ohci_pdata *pdata = dev->platform_data;
173 	struct platform_device *pdev =
174 		container_of(dev, struct platform_device, dev);
175 
176 	if (pdata->power_suspend)
177 		pdata->power_suspend(pdev);
178 
179 	return 0;
180 }
181 
182 static int ohci_platform_resume(struct device *dev)
183 {
184 	struct usb_hcd *hcd = dev_get_drvdata(dev);
185 	struct usb_ohci_pdata *pdata = dev->platform_data;
186 	struct platform_device *pdev =
187 		container_of(dev, struct platform_device, dev);
188 
189 	if (pdata->power_on) {
190 		int err = pdata->power_on(pdev);
191 		if (err < 0)
192 			return err;
193 	}
194 
195 	ohci_resume(hcd, false);
196 	return 0;
197 }
198 
199 #else /* !CONFIG_PM */
200 #define ohci_platform_suspend	NULL
201 #define ohci_platform_resume	NULL
202 #endif /* CONFIG_PM */
203 
204 static const struct platform_device_id ohci_platform_table[] = {
205 	{ "ohci-platform", 0 },
206 	{ }
207 };
208 MODULE_DEVICE_TABLE(platform, ohci_platform_table);
209 
210 static const struct dev_pm_ops ohci_platform_pm_ops = {
211 	.suspend	= ohci_platform_suspend,
212 	.resume		= ohci_platform_resume,
213 };
214 
215 static struct platform_driver ohci_platform_driver = {
216 	.id_table	= ohci_platform_table,
217 	.probe		= ohci_platform_probe,
218 	.remove		= ohci_platform_remove,
219 	.shutdown	= usb_hcd_platform_shutdown,
220 	.driver		= {
221 		.owner	= THIS_MODULE,
222 		.name	= "ohci-platform",
223 		.pm	= &ohci_platform_pm_ops,
224 	}
225 };
226