phy.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * A wrapper for multiple PHYs which passes all phy_* function calls to
  4. * multiple (actual) PHY devices. This is comes handy when initializing
  5. * all PHYs on a HCD and to keep them all in the same state.
  6. *
  7. * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
  8. */
  9. #include <linux/device.h>
  10. #include <linux/list.h>
  11. #include <linux/phy/phy.h>
  12. #include <linux/of.h>
  13. #include "phy.h"
  14. struct usb_phy_roothub {
  15. struct phy *phy;
  16. struct list_head list;
  17. };
  18. /* Allocate the roothub_entry by specific name of phy */
  19. static int usb_phy_roothub_add_phy_by_name(struct device *dev, const char *name,
  20. struct list_head *list)
  21. {
  22. struct usb_phy_roothub *roothub_entry;
  23. struct phy *phy;
  24. phy = devm_of_phy_get(dev, dev->of_node, name);
  25. if (IS_ERR(phy))
  26. return PTR_ERR(phy);
  27. roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
  28. if (!roothub_entry)
  29. return -ENOMEM;
  30. INIT_LIST_HEAD(&roothub_entry->list);
  31. roothub_entry->phy = phy;
  32. list_add_tail(&roothub_entry->list, list);
  33. return 0;
  34. }
  35. static int usb_phy_roothub_add_phy(struct device *dev, int index,
  36. struct list_head *list)
  37. {
  38. struct usb_phy_roothub *roothub_entry;
  39. struct phy *phy;
  40. phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
  41. if (IS_ERR(phy)) {
  42. if (PTR_ERR(phy) == -ENODEV)
  43. return 0;
  44. else
  45. return PTR_ERR(phy);
  46. }
  47. roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
  48. if (!roothub_entry)
  49. return -ENOMEM;
  50. INIT_LIST_HEAD(&roothub_entry->list);
  51. roothub_entry->phy = phy;
  52. list_add_tail(&roothub_entry->list, list);
  53. return 0;
  54. }
  55. struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
  56. {
  57. struct usb_phy_roothub *phy_roothub;
  58. int i, num_phys, err;
  59. if (!IS_ENABLED(CONFIG_GENERIC_PHY))
  60. return NULL;
  61. num_phys = of_count_phandle_with_args(dev->of_node, "phys",
  62. "#phy-cells");
  63. if (num_phys <= 0)
  64. return NULL;
  65. phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
  66. if (!phy_roothub)
  67. return ERR_PTR(-ENOMEM);
  68. INIT_LIST_HEAD(&phy_roothub->list);
  69. if (!usb_phy_roothub_add_phy_by_name(dev, "usb2-phy", &phy_roothub->list))
  70. return phy_roothub;
  71. for (i = 0; i < num_phys; i++) {
  72. err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
  73. if (err)
  74. return ERR_PTR(err);
  75. }
  76. return phy_roothub;
  77. }
  78. EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
  79. /**
  80. * usb_phy_roothub_alloc_usb3_phy - alloc the roothub
  81. * @dev: the device of the host controller
  82. *
  83. * Allocate the usb phy roothub if the host use a generic usb3-phy.
  84. *
  85. * Return: On success, a pointer to the usb_phy_roothub. Otherwise,
  86. * %NULL if no use usb3 phy or %-ENOMEM if out of memory.
  87. */
  88. struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
  89. {
  90. struct usb_phy_roothub *phy_roothub;
  91. int num_phys, usb2_phy_index;
  92. if (!IS_ENABLED(CONFIG_GENERIC_PHY))
  93. return NULL;
  94. num_phys = of_count_phandle_with_args(dev->of_node, "phys",
  95. "#phy-cells");
  96. if (num_phys <= 0)
  97. return NULL;
  98. /*
  99. * If 'usb2-phy' is not present, usb_phy_roothub_alloc() added
  100. * all PHYs to the primary HCD's phy_roothub already, so skip
  101. * adding 'usb3-phy' here to avoid double use of that.
  102. */
  103. usb2_phy_index = of_property_match_string(dev->of_node, "phy-names",
  104. "usb2-phy");
  105. if (usb2_phy_index < 0)
  106. return NULL;
  107. phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
  108. if (!phy_roothub)
  109. return ERR_PTR(-ENOMEM);
  110. INIT_LIST_HEAD(&phy_roothub->list);
  111. if (!usb_phy_roothub_add_phy_by_name(dev, "usb3-phy", &phy_roothub->list))
  112. return phy_roothub;
  113. return NULL;
  114. }
  115. EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc_usb3_phy);
  116. int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
  117. {
  118. struct usb_phy_roothub *roothub_entry;
  119. struct list_head *head;
  120. int err;
  121. if (!phy_roothub)
  122. return 0;
  123. head = &phy_roothub->list;
  124. list_for_each_entry(roothub_entry, head, list) {
  125. err = phy_init(roothub_entry->phy);
  126. if (err)
  127. goto err_exit_phys;
  128. }
  129. return 0;
  130. err_exit_phys:
  131. list_for_each_entry_continue_reverse(roothub_entry, head, list)
  132. phy_exit(roothub_entry->phy);
  133. return err;
  134. }
  135. EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
  136. int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
  137. {
  138. struct usb_phy_roothub *roothub_entry;
  139. struct list_head *head;
  140. int err, ret = 0;
  141. if (!phy_roothub)
  142. return 0;
  143. head = &phy_roothub->list;
  144. list_for_each_entry(roothub_entry, head, list) {
  145. err = phy_exit(roothub_entry->phy);
  146. if (err)
  147. ret = err;
  148. }
  149. return ret;
  150. }
  151. EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
  152. int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
  153. enum phy_mode mode)
  154. {
  155. struct usb_phy_roothub *roothub_entry;
  156. struct list_head *head;
  157. int err;
  158. if (!phy_roothub)
  159. return 0;
  160. head = &phy_roothub->list;
  161. list_for_each_entry(roothub_entry, head, list) {
  162. err = phy_set_mode(roothub_entry->phy, mode);
  163. if (err)
  164. return err;
  165. }
  166. return 0;
  167. }
  168. EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
  169. int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
  170. {
  171. struct usb_phy_roothub *roothub_entry;
  172. struct list_head *head;
  173. int err;
  174. if (!phy_roothub)
  175. return 0;
  176. head = &phy_roothub->list;
  177. list_for_each_entry(roothub_entry, head, list) {
  178. err = phy_calibrate(roothub_entry->phy);
  179. if (err)
  180. return err;
  181. }
  182. return 0;
  183. }
  184. EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
  185. /**
  186. * usb_phy_roothub_notify_connect() - connect notification
  187. * @phy_roothub: the phy of roothub, if the host use a generic phy.
  188. * @port: the port index for connect
  189. *
  190. * If the phy needs to get connection status, the callback can be used.
  191. * Returns: %0 if successful, a negative error code otherwise
  192. */
  193. int usb_phy_roothub_notify_connect(struct usb_phy_roothub *phy_roothub, int port)
  194. {
  195. struct usb_phy_roothub *roothub_entry;
  196. struct list_head *head;
  197. int err;
  198. if (!phy_roothub)
  199. return 0;
  200. head = &phy_roothub->list;
  201. list_for_each_entry(roothub_entry, head, list) {
  202. err = phy_notify_connect(roothub_entry->phy, port);
  203. if (err)
  204. return err;
  205. }
  206. return 0;
  207. }
  208. EXPORT_SYMBOL_GPL(usb_phy_roothub_notify_connect);
  209. /**
  210. * usb_phy_roothub_notify_disconnect() - disconnect notification
  211. * @phy_roothub: the phy of roothub, if the host use a generic phy.
  212. * @port: the port index for disconnect
  213. *
  214. * If the phy needs to get connection status, the callback can be used.
  215. * Returns: %0 if successful, a negative error code otherwise
  216. */
  217. int usb_phy_roothub_notify_disconnect(struct usb_phy_roothub *phy_roothub, int port)
  218. {
  219. struct usb_phy_roothub *roothub_entry;
  220. struct list_head *head;
  221. int err;
  222. if (!phy_roothub)
  223. return 0;
  224. head = &phy_roothub->list;
  225. list_for_each_entry(roothub_entry, head, list) {
  226. err = phy_notify_disconnect(roothub_entry->phy, port);
  227. if (err)
  228. return err;
  229. }
  230. return 0;
  231. }
  232. EXPORT_SYMBOL_GPL(usb_phy_roothub_notify_disconnect);
  233. int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
  234. {
  235. struct usb_phy_roothub *roothub_entry;
  236. struct list_head *head;
  237. int err;
  238. if (!phy_roothub)
  239. return 0;
  240. head = &phy_roothub->list;
  241. list_for_each_entry(roothub_entry, head, list) {
  242. err = phy_power_on(roothub_entry->phy);
  243. if (err)
  244. goto err_out;
  245. }
  246. return 0;
  247. err_out:
  248. list_for_each_entry_continue_reverse(roothub_entry, head, list)
  249. phy_power_off(roothub_entry->phy);
  250. return err;
  251. }
  252. EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
  253. void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
  254. {
  255. struct usb_phy_roothub *roothub_entry;
  256. if (!phy_roothub)
  257. return;
  258. list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
  259. phy_power_off(roothub_entry->phy);
  260. }
  261. EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
  262. int usb_phy_roothub_suspend(struct device *controller_dev,
  263. struct usb_phy_roothub *phy_roothub)
  264. {
  265. usb_phy_roothub_power_off(phy_roothub);
  266. /* keep the PHYs initialized so the device can wake up the system */
  267. if (device_may_wakeup(controller_dev))
  268. return 0;
  269. return usb_phy_roothub_exit(phy_roothub);
  270. }
  271. EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
  272. int usb_phy_roothub_resume(struct device *controller_dev,
  273. struct usb_phy_roothub *phy_roothub)
  274. {
  275. int err;
  276. /* if the device can't wake up the system _exit was called */
  277. if (!device_may_wakeup(controller_dev)) {
  278. err = usb_phy_roothub_init(phy_roothub);
  279. if (err)
  280. return err;
  281. }
  282. err = usb_phy_roothub_power_on(phy_roothub);
  283. /* undo _init if _power_on failed */
  284. if (err && !device_may_wakeup(controller_dev))
  285. usb_phy_roothub_exit(phy_roothub);
  286. return err;
  287. }
  288. EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);