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
335 if (dwc->dr_mode != USB_DR_MODE_OTG) in dwc3_otg_update()
338 /* don't do anything if debug user changed role to not OTG */ in dwc3_otg_update()
339 if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG) in dwc3_otg_update()
343 reg = dwc3_readl(dwc->regs, DWC3_OSTS); in dwc3_otg_update()
344 id = !!(reg & DWC3_OSTS_CONIDSTS); in dwc3_otg_update()
346 dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE : in dwc3_otg_update()
350 if (dwc->desired_otg_role == dwc->current_otg_role) in dwc3_otg_update()
353 switch (dwc->current_otg_role) { in dwc3_otg_update()
356 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
358 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
362 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
365 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
371 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
373 dwc->current_otg_role = dwc->desired_otg_role; in dwc3_otg_update()
375 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
377 switch (dwc->desired_otg_role) { in dwc3_otg_update()
379 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
382 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
385 dev_err(dwc->dev, "failed to initialize host\n"); in dwc3_otg_update()
387 if (dwc->usb2_phy) in dwc3_otg_update()
388 otg_set_vbus(dwc->usb2_phy->otg, true); in dwc3_otg_update()
389 if (dwc->usb2_generic_phy) in dwc3_otg_update()
390 phy_set_mode(dwc->usb2_generic_phy, in dwc3_otg_update()
395 spin_lock_irqsave(&dwc->lock, flags); in dwc3_otg_update()
399 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_otg_update()
401 if (dwc->usb2_phy) in dwc3_otg_update()
402 otg_set_vbus(dwc->usb2_phy->otg, false); in dwc3_otg_update()
403 if (dwc->usb2_generic_phy) in dwc3_otg_update()
404 phy_set_mode(dwc->usb2_generic_phy, in dwc3_otg_update()
408 dev_err(dwc->dev, "failed to initialize peripheral\n"); in dwc3_otg_update()
417 int id; in dwc3_drd_update() local
419 if (dwc->edev) { in dwc3_drd_update()
420 id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); in dwc3_drd_update()
421 if (id < 0) in dwc3_drd_update()
422 id = 0; in dwc3_drd_update()
423 dwc3_set_mode(dwc, id ? in dwc3_drd_update()
443 struct device *dev = dwc->dev; in dwc3_get_extcon()
457 if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { in dwc3_get_extcon()
460 return ERR_PTR(-EPROBE_DEFER); in dwc3_get_extcon()
465 np_phy = of_parse_phandle(dev->of_node, "phys", 0); in dwc3_get_extcon()
466 np_conn = of_graph_get_remote_node(np_phy, -1, -1); in dwc3_get_extcon()
495 if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) in dwc3_usb_role_switch_set()
512 spin_lock_irqsave(&dwc->lock, flags); in dwc3_usb_role_switch_get()
513 switch (dwc->current_dr_role) { in dwc3_usb_role_switch_get()
521 role = dwc->current_otg_role; in dwc3_usb_role_switch_get()
524 if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) in dwc3_usb_role_switch_get()
530 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_usb_role_switch_get()
541 ret = device_property_read_string(dwc->dev, "role-switch-default-mode", in dwc3_setup_role_switch()
544 dwc->role_switch_default_mode = USB_DR_MODE_HOST; in dwc3_setup_role_switch()
547 dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; in dwc3_setup_role_switch()
551 dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); in dwc3_setup_role_switch()
555 dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); in dwc3_setup_role_switch()
556 if (IS_ERR(dwc->role_sw)) in dwc3_setup_role_switch()
557 return PTR_ERR(dwc->role_sw); in dwc3_setup_role_switch()
571 dwc->edev = dwc3_get_extcon(dwc); in dwc3_drd_init()
572 if (IS_ERR(dwc->edev)) in dwc3_drd_init()
573 return PTR_ERR(dwc->edev); in dwc3_drd_init()
576 device_property_read_bool(dwc->dev, "usb-role-switch")) { in dwc3_drd_init()
580 } else if (dwc->edev) { in dwc3_drd_init()
581 dwc->edev_nb.notifier_call = dwc3_drd_notifier; in dwc3_drd_init()
582 ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, in dwc3_drd_init()
583 &dwc->edev_nb); in dwc3_drd_init()
585 dev_err(dwc->dev, "couldn't register cable notifier\n"); in dwc3_drd_init()
592 dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG; in dwc3_drd_init()
594 /* use OTG block to get ID event */ in dwc3_drd_init()
599 dwc->otg_irq = irq; in dwc3_drd_init()
601 /* disable all OTG IRQs */ in dwc3_drd_init()
606 ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq, in dwc3_drd_init()
608 IRQF_SHARED, "dwc3-otg", dwc); in dwc3_drd_init()
610 dev_err(dwc->dev, "failed to request irq #%d --> %d\n", in dwc3_drd_init()
611 dwc->otg_irq, ret); in dwc3_drd_init()
612 ret = -ENODEV; in dwc3_drd_init()
627 if (dwc->role_sw) in dwc3_drd_exit()
628 usb_role_switch_unregister(dwc->role_sw); in dwc3_drd_exit()
630 if (dwc->edev) in dwc3_drd_exit()
631 extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, in dwc3_drd_exit()
632 &dwc->edev_nb); in dwc3_drd_exit()
634 cancel_work_sync(&dwc->drd_work); in dwc3_drd_exit()
637 switch (dwc->current_dr_role) { in dwc3_drd_exit()
647 spin_lock_irqsave(&dwc->lock, flags); in dwc3_drd_exit()
648 dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; in dwc3_drd_exit()
649 spin_unlock_irqrestore(&dwc->lock, flags); in dwc3_drd_exit()
656 if (dwc->otg_irq) in dwc3_drd_exit()
657 free_irq(dwc->otg_irq, dwc); in dwc3_drd_exit()