redriver.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * USB Super Speed (Plus) redriver core module
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #define pr_fmt(fmt) "redriver-core: " fmt
  7. #include <linux/module.h>
  8. #include <linux/usb/redriver.h>
  9. static LIST_HEAD(usb_redriver_list);
  10. static DEFINE_SPINLOCK(usb_rediver_lock);
  11. /**
  12. * usb_add_redriver() - register a redriver from a specific chip driver.
  13. * @redriver: redriver allocated by specific chip driver.
  14. *
  15. * Return:
  16. * -EINVAL - if of node not exist
  17. * 0 - if exist, add redriver to global list.
  18. */
  19. int usb_add_redriver(struct usb_redriver *redriver)
  20. {
  21. struct usb_redriver *iter;
  22. if (!redriver->of_node || redriver->bounded)
  23. return -EINVAL;
  24. spin_lock(&usb_rediver_lock);
  25. list_for_each_entry(iter, &usb_redriver_list, list) {
  26. if (iter == redriver) {
  27. spin_unlock(&usb_rediver_lock);
  28. return -EEXIST;
  29. }
  30. }
  31. pr_debug("add redriver %s\n", of_node_full_name(redriver->of_node));
  32. list_add_tail(&redriver->list, &usb_redriver_list);
  33. spin_unlock(&usb_rediver_lock);
  34. return 0;
  35. }
  36. EXPORT_SYMBOL(usb_add_redriver);
  37. /**
  38. * usb_remove_redriver() - remove a redriver from a specific chip driver.
  39. * @redriver: redriver allocated by specific chip driver.
  40. *
  41. * remove redriver from global list.
  42. * if redriver rmmod, it is better change to default state inside it's driver,
  43. * no unbind operation here.
  44. *
  45. * Return:
  46. * -EINVAL - redriver still used by uppper layer.
  47. * 0 - redriver removed.
  48. */
  49. int usb_remove_redriver(struct usb_redriver *redriver)
  50. {
  51. spin_lock(&usb_rediver_lock);
  52. if (redriver->bounded) {
  53. spin_unlock(&usb_rediver_lock);
  54. return -EINVAL;
  55. }
  56. pr_debug("remove redriver %s\n", of_node_full_name(redriver->of_node));
  57. list_del(&redriver->list);
  58. spin_unlock(&usb_rediver_lock);
  59. return 0;
  60. }
  61. EXPORT_SYMBOL(usb_remove_redriver);
  62. /**
  63. * usb_get_redriver_by_phandle() - find redriver to be used.
  64. * @np: device node of device which use the redriver
  65. * @phandle_name: phandle name which refer to the redriver
  66. * @index: phandle index which refer to the redriver
  67. *
  68. * Return:
  69. * NULL - if no phandle or redriver device tree status is disabled.
  70. * ERR_PTR(-EPROBE_DEFER) - if redriver is not registered
  71. * if redriver registered, return pointer of it.
  72. */
  73. struct usb_redriver *usb_get_redriver_by_phandle(const struct device_node *np,
  74. const char *phandle_name, int index)
  75. {
  76. struct usb_redriver *redriver;
  77. struct device_node *node;
  78. bool found = false;
  79. node = of_parse_phandle(np, phandle_name, index);
  80. if (!of_device_is_available(node)) {
  81. of_node_put(node);
  82. return NULL;
  83. }
  84. spin_lock(&usb_rediver_lock);
  85. list_for_each_entry(redriver, &usb_redriver_list, list) {
  86. if (redriver->of_node == node) {
  87. found = true;
  88. break;
  89. }
  90. }
  91. if (!found) {
  92. of_node_put(node);
  93. spin_unlock(&usb_rediver_lock);
  94. return ERR_PTR(-EPROBE_DEFER);
  95. }
  96. pr_debug("get redriver %s\n", of_node_full_name(redriver->of_node));
  97. redriver->bounded = true;
  98. spin_unlock(&usb_rediver_lock);
  99. return redriver;
  100. }
  101. EXPORT_SYMBOL(usb_get_redriver_by_phandle);
  102. /**
  103. * usb_put_redriver() - redriver will not be used.
  104. * @redriver: redriver allocated by specific chip driver.
  105. *
  106. * when user module exit, unbind redriver.
  107. */
  108. void usb_put_redriver(struct usb_redriver *redriver)
  109. {
  110. if (!redriver)
  111. return;
  112. spin_lock(&usb_rediver_lock);
  113. of_node_put(redriver->of_node);
  114. pr_debug("put redriver %s\n", of_node_full_name(redriver->of_node));
  115. redriver->bounded = false;
  116. spin_unlock(&usb_rediver_lock);
  117. if (redriver->unbind)
  118. redriver->unbind(redriver);
  119. }
  120. EXPORT_SYMBOL(usb_put_redriver);
  121. /* note: following exported symbol can be inlined in header file,
  122. * export here to avoid unexpected CFI(Clang Control Flow Integrity) issue.
  123. */
  124. void usb_redriver_release_lanes(struct usb_redriver *ur, int ort, int num)
  125. {
  126. if (ur && ur->release_usb_lanes)
  127. ur->release_usb_lanes(ur, ort, num);
  128. }
  129. EXPORT_SYMBOL(usb_redriver_release_lanes);
  130. void usb_redriver_notify_connect(struct usb_redriver *ur, int ort)
  131. {
  132. if (ur && ur->notify_connect)
  133. ur->notify_connect(ur, ort);
  134. }
  135. EXPORT_SYMBOL(usb_redriver_notify_connect);
  136. void usb_redriver_notify_disconnect(struct usb_redriver *ur)
  137. {
  138. if (ur && ur->notify_disconnect)
  139. ur->notify_disconnect(ur);
  140. }
  141. EXPORT_SYMBOL(usb_redriver_notify_disconnect);
  142. void usb_redriver_gadget_pullup_enter(struct usb_redriver *ur,
  143. int is_on)
  144. {
  145. if (ur && ur->gadget_pullup_enter)
  146. ur->gadget_pullup_enter(ur, is_on);
  147. }
  148. EXPORT_SYMBOL(usb_redriver_gadget_pullup_enter);
  149. void usb_redriver_gadget_pullup_exit(struct usb_redriver *ur,
  150. int is_on)
  151. {
  152. if (ur && ur->gadget_pullup_exit)
  153. ur->gadget_pullup_exit(ur, is_on);
  154. }
  155. EXPORT_SYMBOL(usb_redriver_gadget_pullup_exit);
  156. void usb_redriver_host_powercycle(struct usb_redriver *ur)
  157. {
  158. if (ur && ur->host_powercycle)
  159. ur->host_powercycle(ur);
  160. }
  161. EXPORT_SYMBOL(usb_redriver_host_powercycle);
  162. MODULE_LICENSE("GPL");
  163. MODULE_DESCRIPTION("USB Super Speed (Plus) redriver core module");