drd.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /**
  2. * drd.c - DesignWare USB3 DRD Controller Dual-role support
  3. *
  4. * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
  5. *
  6. * Authors: Roger Quadros <rogerq@ti.com>
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 of
  10. * the License as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <linux/extcon.h>
  21. #include "debug.h"
  22. #include "core.h"
  23. #include "gadget.h"
  24. static void dwc3_drd_update(struct dwc3 *dwc)
  25. {
  26. int id;
  27. id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
  28. if (id < 0)
  29. id = 0;
  30. dwc3_set_mode(dwc, id ?
  31. DWC3_GCTL_PRTCAP_HOST :
  32. DWC3_GCTL_PRTCAP_DEVICE);
  33. }
  34. static int dwc3_drd_notifier(struct notifier_block *nb,
  35. unsigned long event, void *ptr)
  36. {
  37. struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
  38. dwc3_set_mode(dwc, event ?
  39. DWC3_GCTL_PRTCAP_HOST :
  40. DWC3_GCTL_PRTCAP_DEVICE);
  41. return NOTIFY_DONE;
  42. }
  43. int dwc3_drd_init(struct dwc3 *dwc)
  44. {
  45. int ret;
  46. if (dwc->dev->of_node) {
  47. if (of_property_read_bool(dwc->dev->of_node, "extcon"))
  48. dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
  49. if (IS_ERR(dwc->edev))
  50. return PTR_ERR(dwc->edev);
  51. dwc->edev_nb.notifier_call = dwc3_drd_notifier;
  52. ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
  53. &dwc->edev_nb);
  54. if (ret < 0) {
  55. dev_err(dwc->dev, "couldn't register cable notifier\n");
  56. return ret;
  57. }
  58. }
  59. dwc3_drd_update(dwc);
  60. return 0;
  61. }
  62. void dwc3_drd_exit(struct dwc3 *dwc)
  63. {
  64. extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
  65. &dwc->edev_nb);
  66. dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
  67. flush_work(&dwc->drd_work);
  68. dwc3_gadget_exit(dwc);
  69. }