xref: /linux/drivers/usb/host/ohci-exynos.c (revision 22d9d8e8316d7f69046c8805ce9aa8d9c43d4e5b)
1 /*
2  * SAMSUNG EXYNOS USB HOST OHCI Controller
3  *
4  * Copyright (C) 2011 Samsung Electronics Co.Ltd
5  * Author: Jingoo Han <jg1.han@samsung.com>
6  *
7  * This program is free software; you can redistribute  it and/or modify it
8  * under  the terms of  the GNU General  Public License as published by the
9  * Free Software Foundation;  either version 2 of the  License, or (at your
10  * option) any later version.
11  *
12  */
13 
14 #include <linux/clk.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/platform_data/usb-ohci-exynos.h>
18 #include <linux/usb/phy.h>
19 #include <linux/usb/samsung_usb_phy.h>
20 
21 struct exynos_ohci_hcd {
22 	struct device *dev;
23 	struct usb_hcd *hcd;
24 	struct clk *clk;
25 	struct usb_phy *phy;
26 	struct usb_otg *otg;
27 	struct exynos4_ohci_platdata *pdata;
28 };
29 
30 static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci)
31 {
32 	struct platform_device *pdev = to_platform_device(exynos_ohci->dev);
33 
34 	if (exynos_ohci->phy)
35 		usb_phy_init(exynos_ohci->phy);
36 	else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init)
37 		exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
38 }
39 
40 static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci)
41 {
42 	struct platform_device *pdev = to_platform_device(exynos_ohci->dev);
43 
44 	if (exynos_ohci->phy)
45 		usb_phy_shutdown(exynos_ohci->phy);
46 	else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit)
47 		exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
48 }
49 
50 static int ohci_exynos_reset(struct usb_hcd *hcd)
51 {
52 	return ohci_init(hcd_to_ohci(hcd));
53 }
54 
55 static int ohci_exynos_start(struct usb_hcd *hcd)
56 {
57 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
58 	int ret;
59 
60 	ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
61 
62 	ret = ohci_run(ohci);
63 	if (ret < 0) {
64 		dev_err(hcd->self.controller, "can't start %s\n",
65 			hcd->self.bus_name);
66 		ohci_stop(hcd);
67 		return ret;
68 	}
69 
70 	return 0;
71 }
72 
73 static const struct hc_driver exynos_ohci_hc_driver = {
74 	.description		= hcd_name,
75 	.product_desc		= "EXYNOS OHCI Host Controller",
76 	.hcd_priv_size		= sizeof(struct ohci_hcd),
77 
78 	.irq			= ohci_irq,
79 	.flags			= HCD_MEMORY|HCD_USB11,
80 
81 	.reset			= ohci_exynos_reset,
82 	.start			= ohci_exynos_start,
83 	.stop			= ohci_stop,
84 	.shutdown		= ohci_shutdown,
85 
86 	.get_frame_number	= ohci_get_frame,
87 
88 	.urb_enqueue		= ohci_urb_enqueue,
89 	.urb_dequeue		= ohci_urb_dequeue,
90 	.endpoint_disable	= ohci_endpoint_disable,
91 
92 	.hub_status_data	= ohci_hub_status_data,
93 	.hub_control		= ohci_hub_control,
94 #ifdef	CONFIG_PM
95 	.bus_suspend		= ohci_bus_suspend,
96 	.bus_resume		= ohci_bus_resume,
97 #endif
98 	.start_port_reset	= ohci_start_port_reset,
99 };
100 
101 static int exynos_ohci_probe(struct platform_device *pdev)
102 {
103 	struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev);
104 	struct exynos_ohci_hcd *exynos_ohci;
105 	struct usb_hcd *hcd;
106 	struct ohci_hcd *ohci;
107 	struct resource *res;
108 	struct usb_phy *phy;
109 	int irq;
110 	int err;
111 
112 	/*
113 	 * Right now device-tree probed devices don't get dma_mask set.
114 	 * Since shared usb code relies on it, set it here for now.
115 	 * Once we move to full device tree support this will vanish off.
116 	 */
117 	if (!pdev->dev.dma_mask)
118 		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
119 	err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
120 	if (err)
121 		return err;
122 
123 	exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd),
124 					GFP_KERNEL);
125 	if (!exynos_ohci)
126 		return -ENOMEM;
127 
128 	if (of_device_is_compatible(pdev->dev.of_node,
129 					"samsung,exynos5440-ohci"))
130 		goto skip_phy;
131 
132 	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
133 	if (IS_ERR(phy)) {
134 		/* Fallback to pdata */
135 		if (!pdata) {
136 			dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
137 			return -EPROBE_DEFER;
138 		} else {
139 			exynos_ohci->pdata = pdata;
140 		}
141 	} else {
142 		exynos_ohci->phy = phy;
143 		exynos_ohci->otg = phy->otg;
144 	}
145 
146 skip_phy:
147 
148 	exynos_ohci->dev = &pdev->dev;
149 
150 	hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
151 					dev_name(&pdev->dev));
152 	if (!hcd) {
153 		dev_err(&pdev->dev, "Unable to create HCD\n");
154 		return -ENOMEM;
155 	}
156 
157 	exynos_ohci->hcd = hcd;
158 	exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost");
159 
160 	if (IS_ERR(exynos_ohci->clk)) {
161 		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
162 		err = PTR_ERR(exynos_ohci->clk);
163 		goto fail_clk;
164 	}
165 
166 	err = clk_prepare_enable(exynos_ohci->clk);
167 	if (err)
168 		goto fail_clk;
169 
170 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
171 	if (!res) {
172 		dev_err(&pdev->dev, "Failed to get I/O memory\n");
173 		err = -ENXIO;
174 		goto fail_io;
175 	}
176 
177 	hcd->rsrc_start = res->start;
178 	hcd->rsrc_len = resource_size(res);
179 	hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
180 	if (!hcd->regs) {
181 		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
182 		err = -ENOMEM;
183 		goto fail_io;
184 	}
185 
186 	irq = platform_get_irq(pdev, 0);
187 	if (!irq) {
188 		dev_err(&pdev->dev, "Failed to get IRQ\n");
189 		err = -ENODEV;
190 		goto fail_io;
191 	}
192 
193 	if (exynos_ohci->otg)
194 		exynos_ohci->otg->set_host(exynos_ohci->otg,
195 					&exynos_ohci->hcd->self);
196 
197 	exynos_ohci_phy_enable(exynos_ohci);
198 
199 	ohci = hcd_to_ohci(hcd);
200 	ohci_hcd_init(ohci);
201 
202 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
203 	if (err) {
204 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
205 		goto fail_add_hcd;
206 	}
207 
208 	platform_set_drvdata(pdev, exynos_ohci);
209 
210 	return 0;
211 
212 fail_add_hcd:
213 	exynos_ohci_phy_disable(exynos_ohci);
214 fail_io:
215 	clk_disable_unprepare(exynos_ohci->clk);
216 fail_clk:
217 	usb_put_hcd(hcd);
218 	return err;
219 }
220 
221 static int exynos_ohci_remove(struct platform_device *pdev)
222 {
223 	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
224 	struct usb_hcd *hcd = exynos_ohci->hcd;
225 
226 	usb_remove_hcd(hcd);
227 
228 	if (exynos_ohci->otg)
229 		exynos_ohci->otg->set_host(exynos_ohci->otg,
230 					&exynos_ohci->hcd->self);
231 
232 	exynos_ohci_phy_disable(exynos_ohci);
233 
234 	clk_disable_unprepare(exynos_ohci->clk);
235 
236 	usb_put_hcd(hcd);
237 
238 	return 0;
239 }
240 
241 static void exynos_ohci_shutdown(struct platform_device *pdev)
242 {
243 	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
244 	struct usb_hcd *hcd = exynos_ohci->hcd;
245 
246 	if (hcd->driver->shutdown)
247 		hcd->driver->shutdown(hcd);
248 }
249 
250 #ifdef CONFIG_PM
251 static int exynos_ohci_suspend(struct device *dev)
252 {
253 	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
254 	struct usb_hcd *hcd = exynos_ohci->hcd;
255 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
256 	unsigned long flags;
257 	int rc = 0;
258 
259 	/*
260 	 * Root hub was already suspended. Disable irq emission and
261 	 * mark HW unaccessible, bail out if RH has been resumed. Use
262 	 * the spinlock to properly synchronize with possible pending
263 	 * RH suspend or resume activity.
264 	 */
265 	spin_lock_irqsave(&ohci->lock, flags);
266 	if (ohci->rh_state != OHCI_RH_SUSPENDED &&
267 			ohci->rh_state != OHCI_RH_HALTED) {
268 		rc = -EINVAL;
269 		goto fail;
270 	}
271 
272 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
273 
274 	if (exynos_ohci->otg)
275 		exynos_ohci->otg->set_host(exynos_ohci->otg,
276 					&exynos_ohci->hcd->self);
277 
278 	exynos_ohci_phy_disable(exynos_ohci);
279 
280 	clk_disable_unprepare(exynos_ohci->clk);
281 
282 fail:
283 	spin_unlock_irqrestore(&ohci->lock, flags);
284 
285 	return rc;
286 }
287 
288 static int exynos_ohci_resume(struct device *dev)
289 {
290 	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
291 	struct usb_hcd *hcd = exynos_ohci->hcd;
292 
293 	clk_prepare_enable(exynos_ohci->clk);
294 
295 	if (exynos_ohci->otg)
296 		exynos_ohci->otg->set_host(exynos_ohci->otg,
297 					&exynos_ohci->hcd->self);
298 
299 	exynos_ohci_phy_enable(exynos_ohci);
300 
301 	ohci_resume(hcd, false);
302 
303 	return 0;
304 }
305 #else
306 #define exynos_ohci_suspend	NULL
307 #define exynos_ohci_resume	NULL
308 #endif
309 
310 static const struct dev_pm_ops exynos_ohci_pm_ops = {
311 	.suspend	= exynos_ohci_suspend,
312 	.resume		= exynos_ohci_resume,
313 };
314 
315 #ifdef CONFIG_OF
316 static const struct of_device_id exynos_ohci_match[] = {
317 	{ .compatible = "samsung,exynos4210-ohci" },
318 	{ .compatible = "samsung,exynos5440-ohci" },
319 	{},
320 };
321 MODULE_DEVICE_TABLE(of, exynos_ohci_match);
322 #endif
323 
324 static struct platform_driver exynos_ohci_driver = {
325 	.probe		= exynos_ohci_probe,
326 	.remove		= exynos_ohci_remove,
327 	.shutdown	= exynos_ohci_shutdown,
328 	.driver = {
329 		.name	= "exynos-ohci",
330 		.owner	= THIS_MODULE,
331 		.pm	= &exynos_ohci_pm_ops,
332 		.of_match_table	= of_match_ptr(exynos_ohci_match),
333 	}
334 };
335 
336 MODULE_ALIAS("platform:exynos-ohci");
337 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
338