1 // SPDX-License-Identifier: GPL-2.0
3 * Cadence USBSS DRD Driver.
5 * Copyright (C) 2018-2020 Cadence.
6 * Copyright (C) 2017-2018 NXP
7 * Copyright (C) 2019 Texas Instruments
10 * Author: Peter Chen <peter.chen@nxp.com>
11 * Pawel Laszczak <pawell@cadence.com>
12 * Roger Quadros <rogerq@ti.com>
15 #include <linux/module.h>
16 #include <linux/irq.h>
17 #include <linux/kernel.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
23 #include "gadget-export.h"
26 static int set_phy_power_on(struct cdns
*cdns
)
30 ret
= phy_power_on(cdns
->usb2_phy
);
34 ret
= phy_power_on(cdns
->usb3_phy
);
36 phy_power_off(cdns
->usb2_phy
);
41 static void set_phy_power_off(struct cdns
*cdns
)
43 phy_power_off(cdns
->usb3_phy
);
44 phy_power_off(cdns
->usb2_phy
);
48 * cdns3_plat_probe - probe for cdns3 core device
49 * @pdev: Pointer to cdns3 core platform device
51 * Returns 0 on success otherwise negative errno
53 static int cdns3_plat_probe(struct platform_device
*pdev
)
55 struct device
*dev
= &pdev
->dev
;
61 cdns
= devm_kzalloc(dev
, sizeof(*cdns
), GFP_KERNEL
);
66 cdns
->pdata
= dev_get_platdata(dev
);
68 platform_set_drvdata(pdev
, cdns
);
70 ret
= platform_get_irq_byname(pdev
, "host");
74 cdns
->xhci_res
[0].start
= ret
;
75 cdns
->xhci_res
[0].end
= ret
;
76 cdns
->xhci_res
[0].flags
= IORESOURCE_IRQ
| irq_get_trigger_type(ret
);
77 cdns
->xhci_res
[0].name
= "host";
79 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "xhci");
81 dev_err(dev
, "couldn't get xhci resource\n");
85 cdns
->xhci_res
[1] = *res
;
87 cdns
->dev_irq
= platform_get_irq_byname(pdev
, "peripheral");
89 if (cdns
->dev_irq
< 0)
90 return dev_err_probe(dev
, cdns
->dev_irq
,
91 "Failed to get peripheral IRQ\n");
93 regs
= devm_platform_ioremap_resource_byname(pdev
, "dev");
95 return dev_err_probe(dev
, PTR_ERR(regs
),
96 "Failed to get dev base\n");
98 cdns
->dev_regs
= regs
;
100 cdns
->otg_irq
= platform_get_irq_byname(pdev
, "otg");
101 if (cdns
->otg_irq
< 0)
102 return dev_err_probe(dev
, cdns
->otg_irq
,
103 "Failed to get otg IRQ\n");
105 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "otg");
107 dev_err(dev
, "couldn't get otg resource\n");
111 cdns
->phyrst_a_enable
= device_property_read_bool(dev
, "cdns,phyrst-a-enable");
113 cdns
->otg_res
= *res
;
115 cdns
->wakeup_irq
= platform_get_irq_byname_optional(pdev
, "wakeup");
116 if (cdns
->wakeup_irq
== -EPROBE_DEFER
)
117 return cdns
->wakeup_irq
;
119 if (cdns
->wakeup_irq
< 0) {
120 dev_dbg(dev
, "couldn't get wakeup irq\n");
121 cdns
->wakeup_irq
= 0x0;
124 cdns
->usb2_phy
= devm_phy_optional_get(dev
, "cdns3,usb2-phy");
125 if (IS_ERR(cdns
->usb2_phy
))
126 return dev_err_probe(dev
, PTR_ERR(cdns
->usb2_phy
),
127 "Failed to get cdn3,usb2-phy\n");
129 ret
= phy_init(cdns
->usb2_phy
);
133 cdns
->usb3_phy
= devm_phy_optional_get(dev
, "cdns3,usb3-phy");
134 if (IS_ERR(cdns
->usb3_phy
))
135 return dev_err_probe(dev
, PTR_ERR(cdns
->usb3_phy
),
136 "Failed to get cdn3,usb3-phy\n");
138 ret
= phy_init(cdns
->usb3_phy
);
142 ret
= set_phy_power_on(cdns
);
144 goto err_phy_power_on
;
146 cdns
->gadget_init
= cdns3_gadget_init
;
148 ret
= cdns_init(cdns
);
152 device_set_wakeup_capable(dev
, true);
153 pm_runtime_set_active(dev
);
154 pm_runtime_enable(dev
);
155 if (!(cdns
->pdata
&& (cdns
->pdata
->quirks
& CDNS3_DEFAULT_PM_RUNTIME_ALLOW
)))
156 pm_runtime_forbid(dev
);
159 * The controller needs less time between bus and controller suspend,
160 * and we also needs a small delay to avoid frequently entering low
163 pm_runtime_set_autosuspend_delay(dev
, 20);
164 pm_runtime_mark_last_busy(dev
);
165 pm_runtime_use_autosuspend(dev
);
170 set_phy_power_off(cdns
);
172 phy_exit(cdns
->usb3_phy
);
174 phy_exit(cdns
->usb2_phy
);
180 * cdns3_plat_remove() - unbind drd driver and clean up
181 * @pdev: Pointer to Linux platform device
183 * Returns 0 on success otherwise negative errno
185 static void cdns3_plat_remove(struct platform_device
*pdev
)
187 struct cdns
*cdns
= platform_get_drvdata(pdev
);
188 struct device
*dev
= cdns
->dev
;
190 pm_runtime_get_sync(dev
);
191 pm_runtime_disable(dev
);
192 pm_runtime_put_noidle(dev
);
194 set_phy_power_off(cdns
);
195 phy_exit(cdns
->usb2_phy
);
196 phy_exit(cdns
->usb3_phy
);
201 static int cdns3_set_platform_suspend(struct device
*dev
,
202 bool suspend
, bool wakeup
)
204 struct cdns
*cdns
= dev_get_drvdata(dev
);
207 if (cdns
->pdata
&& cdns
->pdata
->platform_suspend
)
208 ret
= cdns
->pdata
->platform_suspend(dev
, suspend
, wakeup
);
213 static int cdns3_controller_suspend(struct device
*dev
, pm_message_t msg
)
215 struct cdns
*cdns
= dev_get_drvdata(dev
);
222 if (PMSG_IS_AUTO(msg
))
225 wakeup
= device_may_wakeup(dev
);
227 cdns3_set_platform_suspend(cdns
->dev
, true, wakeup
);
228 set_phy_power_off(cdns
);
229 spin_lock_irqsave(&cdns
->lock
, flags
);
231 spin_unlock_irqrestore(&cdns
->lock
, flags
);
232 dev_dbg(cdns
->dev
, "%s ends\n", __func__
);
237 static int cdns3_controller_resume(struct device
*dev
, pm_message_t msg
)
239 struct cdns
*cdns
= dev_get_drvdata(dev
);
246 if (cdns_power_is_lost(cdns
)) {
247 phy_exit(cdns
->usb2_phy
);
248 ret
= phy_init(cdns
->usb2_phy
);
252 phy_exit(cdns
->usb3_phy
);
253 ret
= phy_init(cdns
->usb3_phy
);
258 ret
= set_phy_power_on(cdns
);
262 cdns3_set_platform_suspend(cdns
->dev
, false, false);
264 spin_lock_irqsave(&cdns
->lock
, flags
);
266 cdns
->in_lpm
= false;
267 spin_unlock_irqrestore(&cdns
->lock
, flags
);
268 cdns_set_active(cdns
, !PMSG_IS_AUTO(msg
));
269 if (cdns
->wakeup_pending
) {
270 cdns
->wakeup_pending
= false;
271 enable_irq(cdns
->wakeup_irq
);
273 dev_dbg(cdns
->dev
, "%s ends\n", __func__
);
278 static int cdns3_plat_runtime_suspend(struct device
*dev
)
280 return cdns3_controller_suspend(dev
, PMSG_AUTO_SUSPEND
);
283 static int cdns3_plat_runtime_resume(struct device
*dev
)
285 return cdns3_controller_resume(dev
, PMSG_AUTO_RESUME
);
288 #ifdef CONFIG_PM_SLEEP
290 static int cdns3_plat_suspend(struct device
*dev
)
292 struct cdns
*cdns
= dev_get_drvdata(dev
);
297 ret
= cdns3_controller_suspend(dev
, PMSG_SUSPEND
);
301 if (device_may_wakeup(dev
) && cdns
->wakeup_irq
)
302 enable_irq_wake(cdns
->wakeup_irq
);
307 static int cdns3_plat_resume(struct device
*dev
)
309 return cdns3_controller_resume(dev
, PMSG_RESUME
);
311 #endif /* CONFIG_PM_SLEEP */
312 #endif /* CONFIG_PM */
314 static const struct dev_pm_ops cdns3_pm_ops
= {
315 SET_SYSTEM_SLEEP_PM_OPS(cdns3_plat_suspend
, cdns3_plat_resume
)
316 SET_RUNTIME_PM_OPS(cdns3_plat_runtime_suspend
,
317 cdns3_plat_runtime_resume
, NULL
)
321 static const struct of_device_id of_cdns3_match
[] = {
322 { .compatible
= "cdns,usb3" },
325 MODULE_DEVICE_TABLE(of
, of_cdns3_match
);
328 static struct platform_driver cdns3_driver
= {
329 .probe
= cdns3_plat_probe
,
330 .remove
= cdns3_plat_remove
,
333 .of_match_table
= of_match_ptr(of_cdns3_match
),
338 module_platform_driver(cdns3_driver
);
340 MODULE_ALIAS("platform:cdns3");
341 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
342 MODULE_LICENSE("GPL v2");
343 MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");