xref: /linux/drivers/usb/cdns3/cdns3-plat.c (revision 55311a92bc9564b058a036074f85200a5954ccd2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cadence USBSS DRD Driver.
4  *
5  * Copyright (C) 2018-2020 Cadence.
6  * Copyright (C) 2017-2018 NXP
7  * Copyright (C) 2019 Texas Instruments
8  *
9  *
10  * Author: Peter Chen <peter.chen@nxp.com>
11  *         Pawel Laszczak <pawell@cadence.com>
12  *         Roger Quadros <rogerq@ti.com>
13  */
14 
15 #include <linux/module.h>
16 #include <linux/irq.h>
17 #include <linux/kernel.h>
18 #include <linux/of.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
21 
22 #include "core.h"
23 #include "gadget-export.h"
24 #include "host-export.h"
25 #include "drd.h"
26 
27 static int set_phy_power_on(struct cdns *cdns)
28 {
29 	int ret;
30 
31 	ret = phy_power_on(cdns->usb2_phy);
32 	if (ret)
33 		return ret;
34 
35 	ret = phy_power_on(cdns->usb3_phy);
36 	if (ret)
37 		phy_power_off(cdns->usb2_phy);
38 
39 	return ret;
40 }
41 
42 static void set_phy_power_off(struct cdns *cdns)
43 {
44 	phy_power_off(cdns->usb3_phy);
45 	phy_power_off(cdns->usb2_phy);
46 }
47 
48 static int cdns3_plat_gadget_init(struct cdns *cdns)
49 {
50 	if (cdns->version < CDNSP_CONTROLLER_V2)
51 		return cdns3_gadget_init(cdns);
52 	else
53 		return cdnsp_gadget_init(cdns);
54 }
55 
56 static int cdns3_plat_host_init(struct cdns *cdns)
57 {
58 	return cdns_host_init(cdns);
59 }
60 
61 /**
62  * cdns3_plat_probe - probe for cdns3 core device
63  * @pdev: Pointer to cdns3 core platform device
64  *
65  * Returns 0 on success otherwise negative errno
66  */
67 static int cdns3_plat_probe(struct platform_device *pdev)
68 {
69 	struct device *dev = &pdev->dev;
70 	struct resource	*res;
71 	struct cdns *cdns;
72 	void __iomem *regs;
73 	int ret;
74 
75 	cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
76 	if (!cdns)
77 		return -ENOMEM;
78 
79 	cdns->dev = dev;
80 	cdns->pdata = dev_get_platdata(dev);
81 	if (cdns->pdata && cdns->pdata->override_apb_timeout)
82 		cdns->override_apb_timeout = cdns->pdata->override_apb_timeout;
83 
84 	if (device_is_compatible(dev, "cdns,cdnsp")) {
85 		cdns->no_drd = true;
86 		cdns->version = CDNSP_CONTROLLER_V2;
87 		dev_dbg(dev, "No DRD support\n");
88 	}
89 
90 	platform_set_drvdata(pdev, cdns);
91 
92 	ret = platform_get_irq_byname(pdev, "host");
93 	if (ret < 0)
94 		return ret;
95 
96 	cdns->xhci_res[0].start = ret;
97 	cdns->xhci_res[0].end = ret;
98 	cdns->xhci_res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(ret);
99 	cdns->xhci_res[0].name = "host";
100 
101 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "xhci");
102 	if (!res) {
103 		dev_err(dev, "couldn't get xhci resource\n");
104 		return -ENXIO;
105 	}
106 
107 	cdns->xhci_res[1] = *res;
108 
109 	cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral");
110 
111 	if (cdns->dev_irq < 0)
112 		return dev_err_probe(dev, cdns->dev_irq,
113 				     "Failed to get peripheral IRQ\n");
114 
115 	regs = devm_platform_ioremap_resource_byname(pdev, "dev");
116 	if (IS_ERR(regs))
117 		return dev_err_probe(dev, PTR_ERR(regs),
118 				     "Failed to get dev base\n");
119 
120 	cdns->dev_regs	= regs;
121 
122 	if (!cdns->no_drd) {
123 		cdns->otg_irq = platform_get_irq_byname(pdev, "otg");
124 		if (cdns->otg_irq < 0)
125 			return dev_err_probe(dev, cdns->otg_irq,
126 					     "Failed to get otg IRQ\n");
127 
128 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg");
129 		if (!res) {
130 			dev_err(dev, "couldn't get otg resource\n");
131 			return -ENXIO;
132 		}
133 		cdns->otg_res = *res;
134 	}
135 
136 	cdns->phyrst_a_enable = device_property_read_bool(dev, "cdns,phyrst-a-enable");
137 
138 	cdns->wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup");
139 	if (cdns->wakeup_irq == -EPROBE_DEFER)
140 		return cdns->wakeup_irq;
141 
142 	if (cdns->wakeup_irq < 0) {
143 		dev_dbg(dev, "couldn't get wakeup irq\n");
144 		cdns->wakeup_irq = 0x0;
145 	}
146 
147 	cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy");
148 	if (IS_ERR(cdns->usb2_phy))
149 		return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy),
150 				     "Failed to get cdn3,usb2-phy\n");
151 
152 	cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy");
153 	if (IS_ERR(cdns->usb3_phy))
154 		return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy),
155 				     "Failed to get cdn3,usb3-phy\n");
156 
157 	ret = phy_init(cdns->usb2_phy);
158 	if (ret)
159 		return ret;
160 
161 	ret = phy_init(cdns->usb3_phy);
162 	if (ret)
163 		goto err_phy3_init;
164 
165 	ret = set_phy_power_on(cdns);
166 	if (ret)
167 		goto err_phy_power_on;
168 
169 	ret = cdns_init(cdns);
170 	if (ret)
171 		goto err_cdns_init;
172 
173 	cdns->gadget_init = cdns3_plat_gadget_init;
174 	cdns->host_init = cdns3_plat_host_init;
175 	ret = cdns_core_init_role(cdns);
176 	if (ret)
177 		goto err_cdns_init_role;
178 
179 	device_set_wakeup_capable(dev, true);
180 	pm_runtime_set_active(dev);
181 	pm_runtime_enable(dev);
182 	if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)))
183 		pm_runtime_forbid(dev);
184 
185 	/*
186 	 * The controller needs less time between bus and controller suspend,
187 	 * and we also needs a small delay to avoid frequently entering low
188 	 * power mode.
189 	 */
190 	pm_runtime_set_autosuspend_delay(dev, 20);
191 	pm_runtime_mark_last_busy(dev);
192 	pm_runtime_use_autosuspend(dev);
193 
194 	return 0;
195 
196 err_cdns_init_role:
197 	if (cdns->role_sw)
198 		usb_role_switch_unregister(cdns->role_sw);
199 err_cdns_init:
200 	set_phy_power_off(cdns);
201 err_phy_power_on:
202 	phy_exit(cdns->usb3_phy);
203 err_phy3_init:
204 	phy_exit(cdns->usb2_phy);
205 
206 	return ret;
207 }
208 
209 /**
210  * cdns3_plat_remove() - unbind drd driver and clean up
211  * @pdev: Pointer to Linux platform device
212  */
213 static void cdns3_plat_remove(struct platform_device *pdev)
214 {
215 	struct cdns *cdns = platform_get_drvdata(pdev);
216 	struct device *dev = cdns->dev;
217 
218 	pm_runtime_get_sync(dev);
219 	if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)))
220 		pm_runtime_allow(dev);
221 
222 	pm_runtime_disable(dev);
223 	pm_runtime_put_noidle(dev);
224 	cdns_remove(cdns);
225 	set_phy_power_off(cdns);
226 	phy_exit(cdns->usb2_phy);
227 	phy_exit(cdns->usb3_phy);
228 }
229 
230 #ifdef CONFIG_PM
231 
232 static int cdns3_set_platform_suspend(struct device *dev,
233 				      bool suspend, bool wakeup)
234 {
235 	struct cdns *cdns = dev_get_drvdata(dev);
236 	int ret = 0;
237 
238 	if (cdns->pdata && cdns->pdata->platform_suspend)
239 		ret = cdns->pdata->platform_suspend(dev, suspend, wakeup);
240 
241 	return ret;
242 }
243 
244 static int cdns3_controller_suspend(struct device *dev, pm_message_t msg)
245 {
246 	struct cdns *cdns = dev_get_drvdata(dev);
247 	bool wakeup;
248 	unsigned long flags;
249 
250 	if (cdns->in_lpm)
251 		return 0;
252 
253 	if (PMSG_IS_AUTO(msg))
254 		wakeup = true;
255 	else
256 		wakeup = device_may_wakeup(dev);
257 
258 	cdns3_set_platform_suspend(cdns->dev, true, wakeup);
259 	set_phy_power_off(cdns);
260 	spin_lock_irqsave(&cdns->lock, flags);
261 	cdns->in_lpm = true;
262 	spin_unlock_irqrestore(&cdns->lock, flags);
263 	dev_dbg(cdns->dev, "%s ends\n", __func__);
264 
265 	return 0;
266 }
267 
268 static int cdns3_controller_resume(struct device *dev, pm_message_t msg)
269 {
270 	struct cdns *cdns = dev_get_drvdata(dev);
271 	int ret;
272 	unsigned long flags;
273 
274 	if (!cdns->in_lpm)
275 		return 0;
276 
277 	if (cdns_power_is_lost(cdns)) {
278 		phy_exit(cdns->usb2_phy);
279 		ret = phy_init(cdns->usb2_phy);
280 		if (ret)
281 			return ret;
282 
283 		phy_exit(cdns->usb3_phy);
284 		ret = phy_init(cdns->usb3_phy);
285 		if (ret)
286 			return ret;
287 	}
288 
289 	ret = set_phy_power_on(cdns);
290 	if (ret)
291 		return ret;
292 
293 	cdns3_set_platform_suspend(cdns->dev, false, false);
294 
295 	spin_lock_irqsave(&cdns->lock, flags);
296 	cdns_resume(cdns);
297 	cdns->in_lpm = false;
298 	spin_unlock_irqrestore(&cdns->lock, flags);
299 	cdns_set_active(cdns, !PMSG_IS_AUTO(msg));
300 	if (cdns->wakeup_pending) {
301 		cdns->wakeup_pending = false;
302 		enable_irq(cdns->wakeup_irq);
303 	}
304 	dev_dbg(cdns->dev, "%s ends\n", __func__);
305 
306 	return ret;
307 }
308 
309 static int cdns3_plat_runtime_suspend(struct device *dev)
310 {
311 	return cdns3_controller_suspend(dev, PMSG_AUTO_SUSPEND);
312 }
313 
314 static int cdns3_plat_runtime_resume(struct device *dev)
315 {
316 	return cdns3_controller_resume(dev, PMSG_AUTO_RESUME);
317 }
318 
319 #ifdef CONFIG_PM_SLEEP
320 
321 static int cdns3_plat_suspend(struct device *dev)
322 {
323 	struct cdns *cdns = dev_get_drvdata(dev);
324 	int ret;
325 
326 	cdns_suspend(cdns);
327 
328 	ret = cdns3_controller_suspend(dev, PMSG_SUSPEND);
329 	if (ret)
330 		return ret;
331 
332 	if (device_may_wakeup(dev) && cdns->wakeup_irq)
333 		enable_irq_wake(cdns->wakeup_irq);
334 
335 	return ret;
336 }
337 
338 static int cdns3_plat_resume(struct device *dev)
339 {
340 	return cdns3_controller_resume(dev, PMSG_RESUME);
341 }
342 #endif /* CONFIG_PM_SLEEP */
343 #endif /* CONFIG_PM */
344 
345 static const struct dev_pm_ops cdns3_pm_ops = {
346 	SET_SYSTEM_SLEEP_PM_OPS(cdns3_plat_suspend, cdns3_plat_resume)
347 	SET_RUNTIME_PM_OPS(cdns3_plat_runtime_suspend,
348 			   cdns3_plat_runtime_resume, NULL)
349 };
350 
351 #ifdef CONFIG_OF
352 static const struct of_device_id of_cdns3_match[] = {
353 	{ .compatible = "cdns,usb3" },
354 	{ .compatible = "cdns,cdnsp" },
355 	{ },
356 };
357 MODULE_DEVICE_TABLE(of, of_cdns3_match);
358 #endif
359 
360 static struct platform_driver cdns3_driver = {
361 	.probe		= cdns3_plat_probe,
362 	.remove		= cdns3_plat_remove,
363 	.driver		= {
364 		.name	= "cdns-usb3",
365 		.of_match_table	= of_match_ptr(of_cdns3_match),
366 		.pm	= &cdns3_pm_ops,
367 	},
368 };
369 
370 module_platform_driver(cdns3_driver);
371 
372 MODULE_ALIAS("platform:cdns3");
373