phy-qcom-usb-hs.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /**
  2. * Copyright (C) 2016 Linaro Ltd
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. */
  8. #include <linux/module.h>
  9. #include <linux/ulpi/driver.h>
  10. #include <linux/ulpi/regs.h>
  11. #include <linux/clk.h>
  12. #include <linux/regulator/consumer.h>
  13. #include <linux/of_device.h>
  14. #include <linux/phy/phy.h>
  15. #include <linux/reset.h>
  16. #include <linux/extcon.h>
  17. #include <linux/notifier.h>
  18. #define ULPI_PWR_CLK_MNG_REG 0x88
  19. # define ULPI_PWR_OTG_COMP_DISABLE BIT(0)
  20. #define ULPI_MISC_A 0x96
  21. # define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1)
  22. # define ULPI_MISC_A_VBUSVLDEXT BIT(0)
  23. struct ulpi_seq {
  24. u8 addr;
  25. u8 val;
  26. };
  27. struct qcom_usb_hs_phy {
  28. struct ulpi *ulpi;
  29. struct phy *phy;
  30. struct clk *ref_clk;
  31. struct clk *sleep_clk;
  32. struct regulator *v1p8;
  33. struct regulator *v3p3;
  34. struct reset_control *reset;
  35. struct ulpi_seq *init_seq;
  36. struct extcon_dev *vbus_edev;
  37. struct notifier_block vbus_notify;
  38. };
  39. static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode)
  40. {
  41. struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
  42. u8 addr;
  43. int ret;
  44. if (!uphy->vbus_edev) {
  45. u8 val = 0;
  46. switch (mode) {
  47. case PHY_MODE_USB_OTG:
  48. case PHY_MODE_USB_HOST:
  49. val |= ULPI_INT_IDGRD;
  50. case PHY_MODE_USB_DEVICE:
  51. val |= ULPI_INT_SESS_VALID;
  52. default:
  53. break;
  54. }
  55. ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val);
  56. if (ret)
  57. return ret;
  58. ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val);
  59. } else {
  60. switch (mode) {
  61. case PHY_MODE_USB_OTG:
  62. case PHY_MODE_USB_DEVICE:
  63. addr = ULPI_SET(ULPI_MISC_A);
  64. break;
  65. case PHY_MODE_USB_HOST:
  66. addr = ULPI_CLR(ULPI_MISC_A);
  67. break;
  68. default:
  69. return -EINVAL;
  70. }
  71. ret = ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG),
  72. ULPI_PWR_OTG_COMP_DISABLE);
  73. if (ret)
  74. return ret;
  75. ret = ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL);
  76. }
  77. return ret;
  78. }
  79. static int
  80. qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event,
  81. void *ptr)
  82. {
  83. struct qcom_usb_hs_phy *uphy;
  84. u8 addr;
  85. uphy = container_of(nb, struct qcom_usb_hs_phy, vbus_notify);
  86. if (event)
  87. addr = ULPI_SET(ULPI_MISC_A);
  88. else
  89. addr = ULPI_CLR(ULPI_MISC_A);
  90. return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT);
  91. }
  92. static int qcom_usb_hs_phy_power_on(struct phy *phy)
  93. {
  94. struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
  95. struct ulpi *ulpi = uphy->ulpi;
  96. const struct ulpi_seq *seq;
  97. int ret, state;
  98. ret = clk_prepare_enable(uphy->ref_clk);
  99. if (ret)
  100. return ret;
  101. ret = clk_prepare_enable(uphy->sleep_clk);
  102. if (ret)
  103. goto err_sleep;
  104. ret = regulator_set_load(uphy->v1p8, 50000);
  105. if (ret < 0)
  106. goto err_1p8;
  107. ret = regulator_enable(uphy->v1p8);
  108. if (ret)
  109. goto err_1p8;
  110. ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000,
  111. 3300000);
  112. if (ret)
  113. goto err_3p3;
  114. ret = regulator_set_load(uphy->v3p3, 50000);
  115. if (ret < 0)
  116. goto err_3p3;
  117. ret = regulator_enable(uphy->v3p3);
  118. if (ret)
  119. goto err_3p3;
  120. for (seq = uphy->init_seq; seq->addr; seq++) {
  121. ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr,
  122. seq->val);
  123. if (ret)
  124. goto err_ulpi;
  125. }
  126. if (uphy->reset) {
  127. ret = reset_control_reset(uphy->reset);
  128. if (ret)
  129. goto err_ulpi;
  130. }
  131. if (uphy->vbus_edev) {
  132. state = extcon_get_state(uphy->vbus_edev, EXTCON_USB);
  133. /* setup initial state */
  134. qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state,
  135. uphy->vbus_edev);
  136. ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB,
  137. &uphy->vbus_notify);
  138. if (ret)
  139. goto err_ulpi;
  140. }
  141. return 0;
  142. err_ulpi:
  143. regulator_disable(uphy->v3p3);
  144. err_3p3:
  145. regulator_disable(uphy->v1p8);
  146. err_1p8:
  147. clk_disable_unprepare(uphy->sleep_clk);
  148. err_sleep:
  149. clk_disable_unprepare(uphy->ref_clk);
  150. return ret;
  151. }
  152. static int qcom_usb_hs_phy_power_off(struct phy *phy)
  153. {
  154. struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
  155. if (uphy->vbus_edev)
  156. extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB,
  157. &uphy->vbus_notify);
  158. regulator_disable(uphy->v3p3);
  159. regulator_disable(uphy->v1p8);
  160. clk_disable_unprepare(uphy->sleep_clk);
  161. clk_disable_unprepare(uphy->ref_clk);
  162. return 0;
  163. }
  164. static const struct phy_ops qcom_usb_hs_phy_ops = {
  165. .power_on = qcom_usb_hs_phy_power_on,
  166. .power_off = qcom_usb_hs_phy_power_off,
  167. .set_mode = qcom_usb_hs_phy_set_mode,
  168. .owner = THIS_MODULE,
  169. };
  170. static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
  171. {
  172. struct qcom_usb_hs_phy *uphy;
  173. struct phy_provider *p;
  174. struct clk *clk;
  175. struct regulator *reg;
  176. struct reset_control *reset;
  177. int size;
  178. int ret;
  179. uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
  180. if (!uphy)
  181. return -ENOMEM;
  182. ulpi_set_drvdata(ulpi, uphy);
  183. uphy->ulpi = ulpi;
  184. size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq");
  185. if (size < 0)
  186. size = 0;
  187. uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1,
  188. sizeof(*uphy->init_seq), GFP_KERNEL);
  189. if (!uphy->init_seq)
  190. return -ENOMEM;
  191. ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq",
  192. (u8 *)uphy->init_seq, size);
  193. if (ret && size)
  194. return ret;
  195. /* NUL terminate */
  196. uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0;
  197. uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref");
  198. if (IS_ERR(clk))
  199. return PTR_ERR(clk);
  200. uphy->sleep_clk = clk = devm_clk_get(&ulpi->dev, "sleep");
  201. if (IS_ERR(clk))
  202. return PTR_ERR(clk);
  203. uphy->v1p8 = reg = devm_regulator_get(&ulpi->dev, "v1p8");
  204. if (IS_ERR(reg))
  205. return PTR_ERR(reg);
  206. uphy->v3p3 = reg = devm_regulator_get(&ulpi->dev, "v3p3");
  207. if (IS_ERR(reg))
  208. return PTR_ERR(reg);
  209. uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por");
  210. if (IS_ERR(reset)) {
  211. if (PTR_ERR(reset) == -EPROBE_DEFER)
  212. return PTR_ERR(reset);
  213. uphy->reset = NULL;
  214. }
  215. uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
  216. &qcom_usb_hs_phy_ops);
  217. if (IS_ERR(uphy->phy))
  218. return PTR_ERR(uphy->phy);
  219. uphy->vbus_edev = extcon_get_edev_by_phandle(&ulpi->dev, 0);
  220. if (IS_ERR(uphy->vbus_edev)) {
  221. if (PTR_ERR(uphy->vbus_edev) != -ENODEV)
  222. return PTR_ERR(uphy->vbus_edev);
  223. uphy->vbus_edev = NULL;
  224. }
  225. uphy->vbus_notify.notifier_call = qcom_usb_hs_phy_vbus_notifier;
  226. phy_set_drvdata(uphy->phy, uphy);
  227. p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
  228. return PTR_ERR_OR_ZERO(p);
  229. }
  230. static const struct of_device_id qcom_usb_hs_phy_match[] = {
  231. { .compatible = "qcom,usb-hs-phy", },
  232. { }
  233. };
  234. MODULE_DEVICE_TABLE(of, qcom_usb_hs_phy_match);
  235. static struct ulpi_driver qcom_usb_hs_phy_driver = {
  236. .probe = qcom_usb_hs_phy_probe,
  237. .driver = {
  238. .name = "qcom_usb_hs_phy",
  239. .of_match_table = qcom_usb_hs_phy_match,
  240. },
  241. };
  242. module_ulpi_driver(qcom_usb_hs_phy_driver);
  243. MODULE_DESCRIPTION("Qualcomm USB HS phy");
  244. MODULE_LICENSE("GPL v2");