usb_dual_role.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (C) 2018 MediaTek Inc.
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 as
  5. * published by the Free Software Foundation.
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
  10. */
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/device.h>
  14. #include <linux/slab.h>
  15. #include <linux/usb/class-dual-role.h>
  16. #ifdef CONFIG_DUAL_ROLE_USB_INTF
  17. enum dualrole_state {
  18. DUALROLE_NONE,
  19. DUALROLE_DEVICE,
  20. DUALROLE_HOST,
  21. };
  22. static struct dual_role_phy_instance *dr_usb;
  23. static enum dualrole_state state = DUALROLE_NONE;
  24. static enum dual_role_property mt_dual_role_props[] = {
  25. DUAL_ROLE_PROP_MODE,
  26. DUAL_ROLE_PROP_PR,
  27. DUAL_ROLE_PROP_DR,
  28. /* DUAL_ROLE_PROP_VCONN_SUPPLY, */
  29. };
  30. static int mt_dual_role_get_prop(struct dual_role_phy_instance *dual_role,
  31. enum dual_role_property prop, unsigned int *val)
  32. {
  33. int ret = 0;
  34. int mode, pr, dr;
  35. if (state == DUALROLE_HOST) {
  36. mode = DUAL_ROLE_PROP_MODE_DFP;
  37. pr = DUAL_ROLE_PROP_PR_SRC;
  38. dr = DUAL_ROLE_PROP_DR_HOST;
  39. } else if (state == DUALROLE_DEVICE) {
  40. mode = DUAL_ROLE_PROP_MODE_UFP;
  41. pr = DUAL_ROLE_PROP_PR_SNK;
  42. dr = DUAL_ROLE_PROP_DR_DEVICE;
  43. } else if (state == DUALROLE_NONE) {
  44. mode = DUAL_ROLE_PROP_MODE_NONE;
  45. pr = DUAL_ROLE_PROP_PR_NONE;
  46. dr = DUAL_ROLE_PROP_DR_NONE;
  47. }
  48. switch (prop) {
  49. case DUAL_ROLE_PROP_MODE:
  50. *val = mode;
  51. break;
  52. case DUAL_ROLE_PROP_PR:
  53. *val = pr;
  54. break;
  55. case DUAL_ROLE_PROP_DR:
  56. *val = dr;
  57. break;
  58. case DUAL_ROLE_PROP_VCONN_SUPPLY:
  59. *val = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
  60. break;
  61. default:
  62. ret = -EINVAL;
  63. break;
  64. }
  65. return ret;
  66. }
  67. static int mt_dual_role_prop_is_writeable(
  68. struct dual_role_phy_instance *dual_role, enum dual_role_property prop)
  69. {
  70. /* not support writeable */
  71. return 0;
  72. }
  73. static int mt_dual_role_set_prop(struct dual_role_phy_instance *dual_role,
  74. enum dual_role_property prop, const unsigned int *val)
  75. {
  76. /* do nothing */
  77. return 0;
  78. }
  79. static int mt_usb_dual_role_changed(void)
  80. {
  81. if (dr_usb)
  82. dual_role_instance_changed(dr_usb);
  83. return 0;
  84. }
  85. void mt_usb_dual_role_to_none(void)
  86. {
  87. state = DUALROLE_NONE;
  88. mt_usb_dual_role_changed();
  89. }
  90. void mt_usb_dual_role_to_device(void)
  91. {
  92. state = DUALROLE_DEVICE;
  93. mt_usb_dual_role_changed();
  94. }
  95. void mt_usb_dual_role_to_host(void)
  96. {
  97. state = DUALROLE_HOST;
  98. mt_usb_dual_role_changed();
  99. }
  100. int mt_usb_dual_role_init(struct device *dev)
  101. {
  102. struct dual_role_phy_desc *dual_desc;
  103. dual_desc = devm_kzalloc(dev, sizeof(*dual_desc),
  104. GFP_KERNEL);
  105. if (!dual_desc)
  106. return -ENOMEM;
  107. dual_desc->name = "dual-role-usb20";
  108. dual_desc->supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
  109. dual_desc->properties = mt_dual_role_props;
  110. dual_desc->num_properties = ARRAY_SIZE(mt_dual_role_props);
  111. dual_desc->get_property = mt_dual_role_get_prop;
  112. dual_desc->set_property = mt_dual_role_set_prop;
  113. dual_desc->property_is_writeable = mt_dual_role_prop_is_writeable;
  114. dr_usb = devm_dual_role_instance_register(dev,
  115. dual_desc);
  116. if (IS_ERR(dr_usb)) {
  117. dev_info(dev, "fail to register dual role usb\n");
  118. return -EINVAL;
  119. }
  120. return 0;
  121. }
  122. #endif /* CONFIG_DUAL_ROLE_USB_INTF */