phy-pistachio-usb.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * IMG Pistachio USB PHY driver
  4. *
  5. * Copyright (C) 2015 Google, Inc.
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/delay.h>
  9. #include <linux/io.h>
  10. #include <linux/kernel.h>
  11. #include <linux/mfd/syscon.h>
  12. #include <linux/module.h>
  13. #include <linux/of.h>
  14. #include <linux/phy/phy.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/regmap.h>
  17. #include <dt-bindings/phy/phy-pistachio-usb.h>
  18. #define USB_PHY_CONTROL1 0x04
  19. #define USB_PHY_CONTROL1_FSEL_SHIFT 2
  20. #define USB_PHY_CONTROL1_FSEL_MASK 0x7
  21. #define USB_PHY_STRAP_CONTROL 0x10
  22. #define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT 4
  23. #define USB_PHY_STRAP_CONTROL_REFCLK_MASK 0x3
  24. #define USB_PHY_STATUS 0x14
  25. #define USB_PHY_STATUS_RX_PHY_CLK BIT(9)
  26. #define USB_PHY_STATUS_RX_UTMI_CLK BIT(8)
  27. #define USB_PHY_STATUS_VBUS_FAULT BIT(7)
  28. struct pistachio_usb_phy {
  29. struct device *dev;
  30. struct regmap *cr_top;
  31. struct clk *phy_clk;
  32. unsigned int refclk;
  33. };
  34. static const unsigned long fsel_rate_map[] = {
  35. 9600000,
  36. 10000000,
  37. 12000000,
  38. 19200000,
  39. 20000000,
  40. 24000000,
  41. 0,
  42. 50000000,
  43. };
  44. static int pistachio_usb_phy_power_on(struct phy *phy)
  45. {
  46. struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
  47. unsigned long timeout, rate;
  48. unsigned int i;
  49. int ret;
  50. ret = clk_prepare_enable(p_phy->phy_clk);
  51. if (ret < 0) {
  52. dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
  53. return ret;
  54. }
  55. regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
  56. USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
  57. USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
  58. p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);
  59. rate = clk_get_rate(p_phy->phy_clk);
  60. if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
  61. dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
  62. rate);
  63. ret = -EINVAL;
  64. goto disable_clk;
  65. }
  66. for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
  67. if (rate == fsel_rate_map[i])
  68. break;
  69. }
  70. if (i == ARRAY_SIZE(fsel_rate_map)) {
  71. dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
  72. ret = -EINVAL;
  73. goto disable_clk;
  74. }
  75. regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
  76. USB_PHY_CONTROL1_FSEL_MASK <<
  77. USB_PHY_CONTROL1_FSEL_SHIFT,
  78. i << USB_PHY_CONTROL1_FSEL_SHIFT);
  79. timeout = jiffies + msecs_to_jiffies(200);
  80. while (time_before(jiffies, timeout)) {
  81. unsigned int val;
  82. regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
  83. if (val & USB_PHY_STATUS_VBUS_FAULT) {
  84. dev_err(p_phy->dev, "VBUS fault detected\n");
  85. ret = -EIO;
  86. goto disable_clk;
  87. }
  88. if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
  89. (val & USB_PHY_STATUS_RX_UTMI_CLK))
  90. return 0;
  91. usleep_range(1000, 1500);
  92. }
  93. dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
  94. ret = -ETIMEDOUT;
  95. disable_clk:
  96. clk_disable_unprepare(p_phy->phy_clk);
  97. return ret;
  98. }
  99. static int pistachio_usb_phy_power_off(struct phy *phy)
  100. {
  101. struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
  102. clk_disable_unprepare(p_phy->phy_clk);
  103. return 0;
  104. }
  105. static const struct phy_ops pistachio_usb_phy_ops = {
  106. .power_on = pistachio_usb_phy_power_on,
  107. .power_off = pistachio_usb_phy_power_off,
  108. .owner = THIS_MODULE,
  109. };
  110. static int pistachio_usb_phy_probe(struct platform_device *pdev)
  111. {
  112. struct pistachio_usb_phy *p_phy;
  113. struct phy_provider *provider;
  114. struct phy *phy;
  115. int ret;
  116. p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
  117. if (!p_phy)
  118. return -ENOMEM;
  119. p_phy->dev = &pdev->dev;
  120. platform_set_drvdata(pdev, p_phy);
  121. p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node,
  122. "img,cr-top");
  123. if (IS_ERR(p_phy->cr_top)) {
  124. dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n",
  125. PTR_ERR(p_phy->cr_top));
  126. return PTR_ERR(p_phy->cr_top);
  127. }
  128. p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy");
  129. if (IS_ERR(p_phy->phy_clk)) {
  130. dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n",
  131. PTR_ERR(p_phy->phy_clk));
  132. return PTR_ERR(p_phy->phy_clk);
  133. }
  134. ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk",
  135. &p_phy->refclk);
  136. if (ret < 0) {
  137. dev_err(p_phy->dev, "No reference clock selector specified\n");
  138. return ret;
  139. }
  140. phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops);
  141. if (IS_ERR(phy)) {
  142. dev_err(p_phy->dev, "Failed to create PHY: %ld\n",
  143. PTR_ERR(phy));
  144. return PTR_ERR(phy);
  145. }
  146. phy_set_drvdata(phy, p_phy);
  147. provider = devm_of_phy_provider_register(p_phy->dev,
  148. of_phy_simple_xlate);
  149. if (IS_ERR(provider)) {
  150. dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n",
  151. PTR_ERR(provider));
  152. return PTR_ERR(provider);
  153. }
  154. return 0;
  155. }
  156. static const struct of_device_id pistachio_usb_phy_of_match[] = {
  157. { .compatible = "img,pistachio-usb-phy", },
  158. { },
  159. };
  160. MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match);
  161. static struct platform_driver pistachio_usb_phy_driver = {
  162. .probe = pistachio_usb_phy_probe,
  163. .driver = {
  164. .name = "pistachio-usb-phy",
  165. .of_match_table = pistachio_usb_phy_of_match,
  166. },
  167. };
  168. module_platform_driver(pistachio_usb_phy_driver);
  169. MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
  170. MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver");
  171. MODULE_LICENSE("GPL v2");