Lines Matching +full:otg +full:- +full:id
1 // SPDX-License-Identifier: GPL-2.0
3 * drd.c - DesignWare USB3 DRD Controller Dual-role support
5 * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com
21 u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); in dwc3_otg_disable_events()
24 dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); in dwc3_otg_disable_events()
29 u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); in dwc3_otg_enable_events()
32 dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); in dwc3_otg_enable_events()
37 u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT); in dwc3_otg_clear_events()
39 dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); in dwc3_otg_clear_events()
56 spin_lock(&dwc->lock); in dwc3_otg_thread_irq()
57 if (dwc->otg_restart_host) { in dwc3_otg_thread_irq()
59 dwc->otg_restart_host = false; in dwc3_otg_thread_irq()
62 spin_unlock(&dwc->lock); in dwc3_otg_thread_irq()
75 reg = dwc3_readl(dwc->regs, DWC3_OEVT); in dwc3_otg_irq()
77 /* ignore non OTG events, we can't disable them in OEVTEN */ in dwc3_otg_irq()
79 dwc3_writel(dwc->regs, DWC3_OEVT, reg); in dwc3_otg_irq()
83 if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST && in dwc3_otg_irq()
85 dwc->otg_restart_host = true; in dwc3_otg_irq()
86 dwc3_writel(dwc->regs, DWC3_OEVT, reg); in dwc3_otg_irq()
98 * Prevent host/device reset from resetting OTG core. in dwc3_otgregs_init()
100 * the signal outputs sent to the PHY, the OTG FSM logic of the in dwc3_otgregs_init()
103 reg = dwc3_readl(dwc->regs, DWC3_OCFG); in dwc3_otgregs_init()
105 dwc3_writel(dwc->regs, DWC3_OCFG, reg); in dwc3_otgregs_init()
108 reg = dwc3_readl(dwc->regs, DWC3_GCTL); in dwc3_otgregs_init()
110 dwc3_writel(dwc->regs, DWC3_GCTL, reg); in dwc3_otgregs_init()
113 * Initialize OTG registers as per in dwc3_otgregs_init()
114 * Figure 11-4 OTG Driver Overall Programming Flow in dwc3_otgregs_init()
117 reg = dwc3_readl(dwc->regs, DWC3_OCFG); in dwc3_otgregs_init()
119 dwc3_writel(dwc->regs, DWC3_OCFG, reg); in dwc3_otgregs_init()
130 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otgregs_init()
134 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otgregs_init()
139 struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); in dwc3_otg_get_irq()
142 irq = platform_get_irq_byname_optional(dwc3_pdev, "otg"); in dwc3_otg_get_irq()
146 if (irq == -EPROBE_DEFER) in dwc3_otg_get_irq()
153 if (irq == -EPROBE_DEFER) in dwc3_otg_get_irq()
161 irq = -EINVAL; in dwc3_otg_get_irq()
172 * As per Figure 11-4 OTG Driver Overall Programming Flow, in dwc3_otg_init()
173 * block "Initialize GCTL for OTG operation". in dwc3_otg_init()
178 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); in dwc3_otg_init()
180 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); in dwc3_otg_init()
182 /* Initialize OTG registers */ in dwc3_otg_init()
188 /* disable all OTG IRQs */ in dwc3_otg_exit()
199 /* As per Figure 11-10 A-Device Flow Diagram */ in dwc3_otg_host_init()
206 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otg_host_init()
209 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otg_host_init()
214 reg = dwc3_readl(dwc->regs, DWC3_OCFG); in dwc3_otg_host_init()
216 dwc3_writel(dwc->regs, DWC3_OCFG, reg); in dwc3_otg_host_init()
220 * We don't want SRP/HNP for simple dual-role so leave in dwc3_otg_host_init()
227 * We don't want HNP/role-swap so leave these disabled. in dwc3_otg_host_init()
231 if (!dwc->dis_u2_susphy_quirk) { in dwc3_otg_host_init()
232 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); in dwc3_otg_host_init()
234 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); in dwc3_otg_host_init()
238 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otg_host_init()
240 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otg_host_init()
249 * Exit from A-device flow as per in dwc3_otg_host_exit()
250 * Figure 11-4 OTG Driver Overall Programming Flow in dwc3_otg_host_exit()
257 * But we don't disable any OTG events in dwc3_otg_host_exit()
261 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otg_host_exit()
263 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otg_host_exit()
271 /* As per Figure 11-20 B-Device Flow Diagram */ in dwc3_otg_device_init()
275 * but we keep them 0 for simple dual-role operation. in dwc3_otg_device_init()
277 reg = dwc3_readl(dwc->regs, DWC3_OCFG); in dwc3_otg_device_init()
280 dwc3_writel(dwc->regs, DWC3_OCFG, reg); in dwc3_otg_device_init()
286 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otg_device_init()
290 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otg_device_init()
294 if (!dwc->dis_u2_susphy_quirk) { in dwc3_otg_device_init()
295 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); in dwc3_otg_device_init()
297 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); in dwc3_otg_device_init()
308 * Exit from B-device flow as per in dwc3_otg_device_exit()
309 * Figure 11-4 OTG Driver Overall Programming Flow in dwc3_otg_device_exit()
322 reg = dwc3_readl(dwc->regs, DWC3_OCTL); in dwc3_otg_device_exit()
325 dwc3_writel(dwc->regs, DWC3_OCTL, reg); in dwc3_otg_device_exit()
332 int id; in dwc3_otg_update() local
336 if (dwc->dr_mode != USB_DR_MODE_OTG) in dwc3_otg_update()
339 /* don't do anything if debug user changed role to not OTG */ in dwc3_otg_update()
340 if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG) in dwc3_otg_update()
344 reg = dwc3_readl(dwc->regs, DWC3_OSTS); in dwc3_otg_update()
345 id = !!(reg & DWC3_OSTS_CONIDSTS); in dwc3_otg_update()
347 dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE : in dwc3_otg_update()
351 if (dwc->desired_otg_role == dwc->current_otg_role) in dwc3_otg_update()
354 switch (dwc->current_otg_role) { in dwc3_otg_update()
357 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
359 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
363 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
366 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
372 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
374 dwc->current_otg_role = dwc->desired_otg_role; in dwc3_otg_update()
376 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
378 switch (dwc->desired_otg_role) { in dwc3_otg_update()
380 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
383 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
386 dev_err(dwc->dev, "failed to initialize host\n"); in dwc3_otg_update()
388 if (dwc->usb2_phy) in dwc3_otg_update()
389 otg_set_vbus(dwc->usb2_phy->otg, true); in dwc3_otg_update()
390 for (i = 0; i < dwc->num_usb2_ports; i++) { in dwc3_otg_update()
391 if (dwc->usb2_generic_phy[i]) { in dwc3_otg_update()
392 phy_set_mode(dwc->usb2_generic_phy[i], in dwc3_otg_update()
399 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
403 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
405 if (dwc->usb2_phy) in dwc3_otg_update()
406 otg_set_vbus(dwc->usb2_phy->otg, false); in dwc3_otg_update()
407 if (dwc->usb2_generic_phy[0]) in dwc3_otg_update()
408 phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); in dwc3_otg_update()
411 dev_err(dwc->dev, "failed to initialize peripheral\n"); in dwc3_otg_update()
420 int id; in dwc3_drd_update() local
422 if (dwc->edev) { in dwc3_drd_update()
423 id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); in dwc3_drd_update()
424 if (id < 0) in dwc3_drd_update()
425 id = 0; in dwc3_drd_update()
426 dwc3_set_mode(dwc, id ? in dwc3_drd_update()
460 if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) in dwc3_usb_role_switch_set()
477 spin_lock_irqsave(&dwc->lock, flags); in dwc3_usb_role_switch_get()
478 switch (dwc->current_dr_role) { in dwc3_usb_role_switch_get()
486 role = dwc->current_otg_role; in dwc3_usb_role_switch_get()
489 if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) in dwc3_usb_role_switch_get()
495 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_usb_role_switch_get()
504 dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev); in dwc3_setup_role_switch()
505 if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) { in dwc3_setup_role_switch()
508 dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; in dwc3_setup_role_switch()
513 dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); in dwc3_setup_role_switch()
517 dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); in dwc3_setup_role_switch()
518 if (IS_ERR(dwc->role_sw)) in dwc3_setup_role_switch()
519 return PTR_ERR(dwc->role_sw); in dwc3_setup_role_switch()
521 if (dwc->dev->of_node) { in dwc3_setup_role_switch()
523 int ret = devm_of_platform_populate(dwc->dev); in dwc3_setup_role_switch()
526 usb_role_switch_unregister(dwc->role_sw); in dwc3_setup_role_switch()
527 dwc->role_sw = NULL; in dwc3_setup_role_switch()
528 dev_err(dwc->dev, "DWC3 platform devices creation failed: %i\n", ret); in dwc3_setup_role_switch()
545 device_property_read_bool(dwc->dev, "usb-role-switch")) in dwc3_drd_init()
548 if (dwc->edev) { in dwc3_drd_init()
549 dwc->edev_nb.notifier_call = dwc3_drd_notifier; in dwc3_drd_init()
550 ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, in dwc3_drd_init()
551 &dwc->edev_nb); in dwc3_drd_init()
553 dev_err(dwc->dev, "couldn't register cable notifier\n"); in dwc3_drd_init()
561 /* use OTG block to get ID event */ in dwc3_drd_init()
566 dwc->otg_irq = irq; in dwc3_drd_init()
568 /* disable all OTG IRQs */ in dwc3_drd_init()
573 ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq, in dwc3_drd_init()
575 IRQF_SHARED, "dwc3-otg", dwc); in dwc3_drd_init()
577 dev_err(dwc->dev, "failed to request irq #%d --> %d\n", in dwc3_drd_init()
578 dwc->otg_irq, ret); in dwc3_drd_init()
579 ret = -ENODEV; in dwc3_drd_init()
594 if (dwc->role_sw) in dwc3_drd_exit()
595 usb_role_switch_unregister(dwc->role_sw); in dwc3_drd_exit()
597 if (dwc->edev) in dwc3_drd_exit()
598 extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, in dwc3_drd_exit()
599 &dwc->edev_nb); in dwc3_drd_exit()
601 cancel_work_sync(&dwc->drd_work); in dwc3_drd_exit()
604 switch (dwc->current_dr_role) { in dwc3_drd_exit()
614 spin_lock_irqsave(&dwc->lock, flags); in dwc3_drd_exit()
615 dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; in dwc3_drd_exit()
616 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_drd_exit()
623 if (dwc->otg_irq) in dwc3_drd_exit()
624 free_irq(dwc->otg_irq, dwc); in dwc3_drd_exit()