1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 * Inspired by dwc3-of-simple.c
10 #include <linux/irq.h>
11 #include <linux/clk-provider.h>
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/extcon.h>
15 #include <linux/of_platform.h>
16 #include <linux/platform_device.h>
17 #include <linux/phy/phy.h>
18 #include <linux/usb/of.h>
19 #include <linux/reset.h>
20 #include <linux/iopoll.h>
24 /* USB QSCRATCH Hardware registers */
25 #define QSCRATCH_HS_PHY_CTRL 0x10
26 #define UTMI_OTG_VBUS_VALID BIT(20)
27 #define SW_SESSVLD_SEL BIT(28)
29 #define QSCRATCH_SS_PHY_CTRL 0x30
30 #define LANE0_PWR_PRESENT BIT(24)
32 #define QSCRATCH_GENERAL_CFG 0x08
33 #define PIPE_UTMI_CLK_SEL BIT(0)
34 #define PIPE3_PHYSTATUS_SW BIT(3)
35 #define PIPE_UTMI_CLK_DIS BIT(8)
37 #define PWR_EVNT_IRQ_STAT_REG 0x58
38 #define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
39 #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
43 void __iomem
*qscratch_base
;
44 struct platform_device
*dwc3
;
47 struct reset_control
*resets
;
54 struct extcon_dev
*edev
;
55 struct extcon_dev
*host_edev
;
56 struct notifier_block vbus_nb
;
57 struct notifier_block host_nb
;
59 enum usb_dr_mode mode
;
64 static inline void dwc3_qcom_setbits(void __iomem
*base
, u32 offset
, u32 val
)
68 reg
= readl(base
+ offset
);
70 writel(reg
, base
+ offset
);
72 /* ensure that above write is through */
76 static inline void dwc3_qcom_clrbits(void __iomem
*base
, u32 offset
, u32 val
)
80 reg
= readl(base
+ offset
);
82 writel(reg
, base
+ offset
);
84 /* ensure that above write is through */
88 static void dwc3_qcom_vbus_overrride_enable(struct dwc3_qcom
*qcom
, bool enable
)
91 dwc3_qcom_setbits(qcom
->qscratch_base
, QSCRATCH_SS_PHY_CTRL
,
93 dwc3_qcom_setbits(qcom
->qscratch_base
, QSCRATCH_HS_PHY_CTRL
,
94 UTMI_OTG_VBUS_VALID
| SW_SESSVLD_SEL
);
96 dwc3_qcom_clrbits(qcom
->qscratch_base
, QSCRATCH_SS_PHY_CTRL
,
98 dwc3_qcom_clrbits(qcom
->qscratch_base
, QSCRATCH_HS_PHY_CTRL
,
99 UTMI_OTG_VBUS_VALID
| SW_SESSVLD_SEL
);
103 static int dwc3_qcom_vbus_notifier(struct notifier_block
*nb
,
104 unsigned long event
, void *ptr
)
106 struct dwc3_qcom
*qcom
= container_of(nb
, struct dwc3_qcom
, vbus_nb
);
108 /* enable vbus override for device mode */
109 dwc3_qcom_vbus_overrride_enable(qcom
, event
);
110 qcom
->mode
= event
? USB_DR_MODE_PERIPHERAL
: USB_DR_MODE_HOST
;
115 static int dwc3_qcom_host_notifier(struct notifier_block
*nb
,
116 unsigned long event
, void *ptr
)
118 struct dwc3_qcom
*qcom
= container_of(nb
, struct dwc3_qcom
, host_nb
);
120 /* disable vbus override in host mode */
121 dwc3_qcom_vbus_overrride_enable(qcom
, !event
);
122 qcom
->mode
= event
? USB_DR_MODE_HOST
: USB_DR_MODE_PERIPHERAL
;
127 static int dwc3_qcom_register_extcon(struct dwc3_qcom
*qcom
)
129 struct device
*dev
= qcom
->dev
;
130 struct extcon_dev
*host_edev
;
133 if (!of_property_read_bool(dev
->of_node
, "extcon"))
136 qcom
->edev
= extcon_get_edev_by_phandle(dev
, 0);
137 if (IS_ERR(qcom
->edev
))
138 return PTR_ERR(qcom
->edev
);
140 qcom
->vbus_nb
.notifier_call
= dwc3_qcom_vbus_notifier
;
142 qcom
->host_edev
= extcon_get_edev_by_phandle(dev
, 1);
143 if (IS_ERR(qcom
->host_edev
))
144 qcom
->host_edev
= NULL
;
146 ret
= devm_extcon_register_notifier(dev
, qcom
->edev
, EXTCON_USB
,
149 dev_err(dev
, "VBUS notifier register failed\n");
154 host_edev
= qcom
->host_edev
;
156 host_edev
= qcom
->edev
;
158 qcom
->host_nb
.notifier_call
= dwc3_qcom_host_notifier
;
159 ret
= devm_extcon_register_notifier(dev
, host_edev
, EXTCON_USB_HOST
,
162 dev_err(dev
, "Host notifier register failed\n");
166 /* Update initial VBUS override based on extcon state */
167 if (extcon_get_state(qcom
->edev
, EXTCON_USB
) ||
168 !extcon_get_state(host_edev
, EXTCON_USB_HOST
))
169 dwc3_qcom_vbus_notifier(&qcom
->vbus_nb
, true, qcom
->edev
);
171 dwc3_qcom_vbus_notifier(&qcom
->vbus_nb
, false, qcom
->edev
);
176 static void dwc3_qcom_disable_interrupts(struct dwc3_qcom
*qcom
)
178 if (qcom
->hs_phy_irq
) {
179 disable_irq_wake(qcom
->hs_phy_irq
);
180 disable_irq_nosync(qcom
->hs_phy_irq
);
183 if (qcom
->dp_hs_phy_irq
) {
184 disable_irq_wake(qcom
->dp_hs_phy_irq
);
185 disable_irq_nosync(qcom
->dp_hs_phy_irq
);
188 if (qcom
->dm_hs_phy_irq
) {
189 disable_irq_wake(qcom
->dm_hs_phy_irq
);
190 disable_irq_nosync(qcom
->dm_hs_phy_irq
);
193 if (qcom
->ss_phy_irq
) {
194 disable_irq_wake(qcom
->ss_phy_irq
);
195 disable_irq_nosync(qcom
->ss_phy_irq
);
199 static void dwc3_qcom_enable_interrupts(struct dwc3_qcom
*qcom
)
201 if (qcom
->hs_phy_irq
) {
202 enable_irq(qcom
->hs_phy_irq
);
203 enable_irq_wake(qcom
->hs_phy_irq
);
206 if (qcom
->dp_hs_phy_irq
) {
207 enable_irq(qcom
->dp_hs_phy_irq
);
208 enable_irq_wake(qcom
->dp_hs_phy_irq
);
211 if (qcom
->dm_hs_phy_irq
) {
212 enable_irq(qcom
->dm_hs_phy_irq
);
213 enable_irq_wake(qcom
->dm_hs_phy_irq
);
216 if (qcom
->ss_phy_irq
) {
217 enable_irq(qcom
->ss_phy_irq
);
218 enable_irq_wake(qcom
->ss_phy_irq
);
222 static int dwc3_qcom_suspend(struct dwc3_qcom
*qcom
)
227 if (qcom
->is_suspended
)
230 val
= readl(qcom
->qscratch_base
+ PWR_EVNT_IRQ_STAT_REG
);
231 if (!(val
& PWR_EVNT_LPM_IN_L2_MASK
))
232 dev_err(qcom
->dev
, "HS-PHY not in L2\n");
234 for (i
= qcom
->num_clocks
- 1; i
>= 0; i
--)
235 clk_disable_unprepare(qcom
->clks
[i
]);
237 qcom
->is_suspended
= true;
238 dwc3_qcom_enable_interrupts(qcom
);
243 static int dwc3_qcom_resume(struct dwc3_qcom
*qcom
)
248 if (!qcom
->is_suspended
)
251 dwc3_qcom_disable_interrupts(qcom
);
253 for (i
= 0; i
< qcom
->num_clocks
; i
++) {
254 ret
= clk_prepare_enable(qcom
->clks
[i
]);
257 clk_disable_unprepare(qcom
->clks
[i
]);
262 /* Clear existing events from PHY related to L2 in/out */
263 dwc3_qcom_setbits(qcom
->qscratch_base
, PWR_EVNT_IRQ_STAT_REG
,
264 PWR_EVNT_LPM_IN_L2_MASK
| PWR_EVNT_LPM_OUT_L2_MASK
);
266 qcom
->is_suspended
= false;
271 static irqreturn_t
qcom_dwc3_resume_irq(int irq
, void *data
)
273 struct dwc3_qcom
*qcom
= data
;
274 struct dwc3
*dwc
= platform_get_drvdata(qcom
->dwc3
);
276 /* If pm_suspended then let pm_resume take care of resuming h/w */
277 if (qcom
->pm_suspended
)
281 pm_runtime_resume(&dwc
->xhci
->dev
);
286 static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom
*qcom
)
288 /* Configure dwc3 to use UTMI clock as PIPE clock not present */
289 dwc3_qcom_setbits(qcom
->qscratch_base
, QSCRATCH_GENERAL_CFG
,
292 usleep_range(100, 1000);
294 dwc3_qcom_setbits(qcom
->qscratch_base
, QSCRATCH_GENERAL_CFG
,
295 PIPE_UTMI_CLK_SEL
| PIPE3_PHYSTATUS_SW
);
297 usleep_range(100, 1000);
299 dwc3_qcom_clrbits(qcom
->qscratch_base
, QSCRATCH_GENERAL_CFG
,
303 static int dwc3_qcom_setup_irq(struct platform_device
*pdev
)
305 struct dwc3_qcom
*qcom
= platform_get_drvdata(pdev
);
308 irq
= platform_get_irq_byname(pdev
, "hs_phy_irq");
310 /* Keep wakeup interrupts disabled until suspend */
311 irq_set_status_flags(irq
, IRQ_NOAUTOEN
);
312 ret
= devm_request_threaded_irq(qcom
->dev
, irq
, NULL
,
313 qcom_dwc3_resume_irq
,
314 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
315 "qcom_dwc3 HS", qcom
);
317 dev_err(qcom
->dev
, "hs_phy_irq failed: %d\n", ret
);
320 qcom
->hs_phy_irq
= irq
;
323 irq
= platform_get_irq_byname(pdev
, "dp_hs_phy_irq");
325 irq_set_status_flags(irq
, IRQ_NOAUTOEN
);
326 ret
= devm_request_threaded_irq(qcom
->dev
, irq
, NULL
,
327 qcom_dwc3_resume_irq
,
328 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
329 "qcom_dwc3 DP_HS", qcom
);
331 dev_err(qcom
->dev
, "dp_hs_phy_irq failed: %d\n", ret
);
334 qcom
->dp_hs_phy_irq
= irq
;
337 irq
= platform_get_irq_byname(pdev
, "dm_hs_phy_irq");
339 irq_set_status_flags(irq
, IRQ_NOAUTOEN
);
340 ret
= devm_request_threaded_irq(qcom
->dev
, irq
, NULL
,
341 qcom_dwc3_resume_irq
,
342 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
343 "qcom_dwc3 DM_HS", qcom
);
345 dev_err(qcom
->dev
, "dm_hs_phy_irq failed: %d\n", ret
);
348 qcom
->dm_hs_phy_irq
= irq
;
351 irq
= platform_get_irq_byname(pdev
, "ss_phy_irq");
353 irq_set_status_flags(irq
, IRQ_NOAUTOEN
);
354 ret
= devm_request_threaded_irq(qcom
->dev
, irq
, NULL
,
355 qcom_dwc3_resume_irq
,
356 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
357 "qcom_dwc3 SS", qcom
);
359 dev_err(qcom
->dev
, "ss_phy_irq failed: %d\n", ret
);
362 qcom
->ss_phy_irq
= irq
;
368 static int dwc3_qcom_clk_init(struct dwc3_qcom
*qcom
, int count
)
370 struct device
*dev
= qcom
->dev
;
371 struct device_node
*np
= dev
->of_node
;
374 qcom
->num_clocks
= count
;
379 qcom
->clks
= devm_kcalloc(dev
, qcom
->num_clocks
,
380 sizeof(struct clk
*), GFP_KERNEL
);
384 for (i
= 0; i
< qcom
->num_clocks
; i
++) {
388 clk
= of_clk_get(np
, i
);
391 clk_put(qcom
->clks
[i
]);
395 ret
= clk_prepare_enable(clk
);
398 clk_disable_unprepare(qcom
->clks
[i
]);
399 clk_put(qcom
->clks
[i
]);
412 static int dwc3_qcom_probe(struct platform_device
*pdev
)
414 struct device_node
*np
= pdev
->dev
.of_node
, *dwc3_np
;
415 struct device
*dev
= &pdev
->dev
;
416 struct dwc3_qcom
*qcom
;
417 struct resource
*res
;
419 bool ignore_pipe_clk
;
421 qcom
= devm_kzalloc(&pdev
->dev
, sizeof(*qcom
), GFP_KERNEL
);
425 platform_set_drvdata(pdev
, qcom
);
426 qcom
->dev
= &pdev
->dev
;
428 qcom
->resets
= devm_reset_control_array_get_optional_exclusive(dev
);
429 if (IS_ERR(qcom
->resets
)) {
430 ret
= PTR_ERR(qcom
->resets
);
431 dev_err(&pdev
->dev
, "failed to get resets, err=%d\n", ret
);
435 ret
= reset_control_assert(qcom
->resets
);
437 dev_err(&pdev
->dev
, "failed to assert resets, err=%d\n", ret
);
441 usleep_range(10, 1000);
443 ret
= reset_control_deassert(qcom
->resets
);
445 dev_err(&pdev
->dev
, "failed to deassert resets, err=%d\n", ret
);
449 ret
= dwc3_qcom_clk_init(qcom
, of_count_phandle_with_args(np
,
450 "clocks", "#clock-cells"));
452 dev_err(dev
, "failed to get clocks\n");
456 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
457 qcom
->qscratch_base
= devm_ioremap_resource(dev
, res
);
458 if (IS_ERR(qcom
->qscratch_base
)) {
459 dev_err(dev
, "failed to map qscratch, err=%d\n", ret
);
460 ret
= PTR_ERR(qcom
->qscratch_base
);
464 ret
= dwc3_qcom_setup_irq(pdev
);
468 dwc3_np
= of_get_child_by_name(np
, "dwc3");
470 dev_err(dev
, "failed to find dwc3 core child\n");
476 * Disable pipe_clk requirement if specified. Used when dwc3
477 * operates without SSPHY and only HS/FS/LS modes are supported.
479 ignore_pipe_clk
= device_property_read_bool(dev
,
480 "qcom,select-utmi-as-pipe-clk");
482 dwc3_qcom_select_utmi_clk(qcom
);
484 ret
= of_platform_populate(np
, NULL
, NULL
, dev
);
486 dev_err(dev
, "failed to register dwc3 core - %d\n", ret
);
490 qcom
->dwc3
= of_find_device_by_node(dwc3_np
);
492 dev_err(&pdev
->dev
, "failed to get dwc3 platform device\n");
497 qcom
->mode
= usb_get_dr_mode(&qcom
->dwc3
->dev
);
499 /* enable vbus override for device mode */
500 if (qcom
->mode
== USB_DR_MODE_PERIPHERAL
)
501 dwc3_qcom_vbus_overrride_enable(qcom
, true);
503 /* register extcon to override sw_vbus on Vbus change later */
504 ret
= dwc3_qcom_register_extcon(qcom
);
508 device_init_wakeup(&pdev
->dev
, 1);
509 qcom
->is_suspended
= false;
510 pm_runtime_set_active(dev
);
511 pm_runtime_enable(dev
);
512 pm_runtime_forbid(dev
);
517 of_platform_depopulate(&pdev
->dev
);
519 for (i
= qcom
->num_clocks
- 1; i
>= 0; i
--) {
520 clk_disable_unprepare(qcom
->clks
[i
]);
521 clk_put(qcom
->clks
[i
]);
524 reset_control_assert(qcom
->resets
);
529 static int dwc3_qcom_remove(struct platform_device
*pdev
)
531 struct dwc3_qcom
*qcom
= platform_get_drvdata(pdev
);
532 struct device
*dev
= &pdev
->dev
;
535 of_platform_depopulate(dev
);
537 for (i
= qcom
->num_clocks
- 1; i
>= 0; i
--) {
538 clk_disable_unprepare(qcom
->clks
[i
]);
539 clk_put(qcom
->clks
[i
]);
541 qcom
->num_clocks
= 0;
543 reset_control_assert(qcom
->resets
);
545 pm_runtime_allow(dev
);
546 pm_runtime_disable(dev
);
551 static int __maybe_unused
dwc3_qcom_pm_suspend(struct device
*dev
)
553 struct dwc3_qcom
*qcom
= dev_get_drvdata(dev
);
556 ret
= dwc3_qcom_suspend(qcom
);
558 qcom
->pm_suspended
= true;
563 static int __maybe_unused
dwc3_qcom_pm_resume(struct device
*dev
)
565 struct dwc3_qcom
*qcom
= dev_get_drvdata(dev
);
568 ret
= dwc3_qcom_resume(qcom
);
570 qcom
->pm_suspended
= false;
575 static int __maybe_unused
dwc3_qcom_runtime_suspend(struct device
*dev
)
577 struct dwc3_qcom
*qcom
= dev_get_drvdata(dev
);
579 return dwc3_qcom_suspend(qcom
);
582 static int __maybe_unused
dwc3_qcom_runtime_resume(struct device
*dev
)
584 struct dwc3_qcom
*qcom
= dev_get_drvdata(dev
);
586 return dwc3_qcom_resume(qcom
);
589 static const struct dev_pm_ops dwc3_qcom_dev_pm_ops
= {
590 SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend
, dwc3_qcom_pm_resume
)
591 SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend
, dwc3_qcom_runtime_resume
,
595 static const struct of_device_id dwc3_qcom_of_match
[] = {
596 { .compatible
= "qcom,dwc3" },
597 { .compatible
= "qcom,msm8996-dwc3" },
598 { .compatible
= "qcom,sdm845-dwc3" },
601 MODULE_DEVICE_TABLE(of
, dwc3_qcom_of_match
);
603 static struct platform_driver dwc3_qcom_driver
= {
604 .probe
= dwc3_qcom_probe
,
605 .remove
= dwc3_qcom_remove
,
608 .pm
= &dwc3_qcom_dev_pm_ops
,
609 .of_match_table
= dwc3_qcom_of_match
,
613 module_platform_driver(dwc3_qcom_driver
);
615 MODULE_LICENSE("GPL v2");
616 MODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");