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 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 of 11 * the License as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <linux/extcon.h> 23 24 #include "debug.h" 25 #include "core.h" 26 #include "gadget.h" 27 28 static void dwc3_drd_update(struct dwc3 *dwc) 29 { 30 int id; 31 32 id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); 33 if (id < 0) 34 id = 0; 35 36 dwc3_set_mode(dwc, id ? 37 DWC3_GCTL_PRTCAP_HOST : 38 DWC3_GCTL_PRTCAP_DEVICE); 39 } 40 41 static int dwc3_drd_notifier(struct notifier_block *nb, 42 unsigned long event, void *ptr) 43 { 44 struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); 45 46 dwc3_set_mode(dwc, event ? 47 DWC3_GCTL_PRTCAP_HOST : 48 DWC3_GCTL_PRTCAP_DEVICE); 49 50 return NOTIFY_DONE; 51 } 52 53 int dwc3_drd_init(struct dwc3 *dwc) 54 { 55 int ret; 56 57 if (dwc->dev->of_node) { 58 if (of_property_read_bool(dwc->dev->of_node, "extcon")) 59 dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0); 60 61 if (IS_ERR(dwc->edev)) 62 return PTR_ERR(dwc->edev); 63 64 dwc->edev_nb.notifier_call = dwc3_drd_notifier; 65 ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, 66 &dwc->edev_nb); 67 if (ret < 0) { 68 dev_err(dwc->dev, "couldn't register cable notifier\n"); 69 return ret; 70 } 71 } 72 73 dwc3_drd_update(dwc); 74 75 return 0; 76 } 77 78 void dwc3_drd_exit(struct dwc3 *dwc) 79 { 80 extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, 81 &dwc->edev_nb); 82 83 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 84 flush_work(&dwc->drd_work); 85 dwc3_gadget_exit(dwc); 86 } 87