1 // SPDX-License-Identifier: GPL-2.0 2 /** 3 * drd.c - DesignWare USB3 DRD Controller Dual-role support 4 * 5 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com 6 * 7 * Authors: Roger Quadros <rogerq@ti.com> 8 */ 9 10 #include <linux/extcon.h> 11 12 #include "debug.h" 13 #include "core.h" 14 #include "gadget.h" 15 16 static void dwc3_drd_update(struct dwc3 *dwc) 17 { 18 int id; 19 20 id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); 21 if (id < 0) 22 id = 0; 23 24 dwc3_set_mode(dwc, id ? 25 DWC3_GCTL_PRTCAP_HOST : 26 DWC3_GCTL_PRTCAP_DEVICE); 27 } 28 29 static int dwc3_drd_notifier(struct notifier_block *nb, 30 unsigned long event, void *ptr) 31 { 32 struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); 33 34 dwc3_set_mode(dwc, event ? 35 DWC3_GCTL_PRTCAP_HOST : 36 DWC3_GCTL_PRTCAP_DEVICE); 37 38 return NOTIFY_DONE; 39 } 40 41 int dwc3_drd_init(struct dwc3 *dwc) 42 { 43 int ret; 44 45 if (dwc->dev->of_node) { 46 if (of_property_read_bool(dwc->dev->of_node, "extcon")) 47 dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0); 48 49 if (IS_ERR(dwc->edev)) 50 return PTR_ERR(dwc->edev); 51 52 dwc->edev_nb.notifier_call = dwc3_drd_notifier; 53 ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, 54 &dwc->edev_nb); 55 if (ret < 0) { 56 dev_err(dwc->dev, "couldn't register cable notifier\n"); 57 return ret; 58 } 59 } 60 61 dwc3_drd_update(dwc); 62 63 return 0; 64 } 65 66 void dwc3_drd_exit(struct dwc3 *dwc) 67 { 68 extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, 69 &dwc->edev_nb); 70 71 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 72 flush_work(&dwc->drd_work); 73 dwc3_gadget_exit(dwc); 74 } 75