phy-k1-usb2.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * SpacemiT K1 USB 2.0 PHY driver
  4. *
  5. * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
  6. * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
  7. */
  8. #include <linux/bitfield.h>
  9. #include <linux/clk.h>
  10. #include <linux/iopoll.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/regmap.h>
  13. #include <linux/usb/of.h>
  14. #define PHY_RST_MODE_CTRL 0x04
  15. #define PHY_PLL_RDY BIT(0)
  16. #define PHY_CLK_CDR_EN BIT(1)
  17. #define PHY_CLK_PLL_EN BIT(2)
  18. #define PHY_CLK_MAC_EN BIT(3)
  19. #define PHY_MAC_RSTN BIT(5)
  20. #define PHY_CDR_RSTN BIT(6)
  21. #define PHY_PLL_RSTN BIT(7)
  22. /*
  23. * hs line state sel (Bit 13):
  24. * - 1 (Default): Internal HS line state is set to 01 when usb_hs_tx_en is valid.
  25. * - 0: Internal HS line state is always driven by usb_hs_lstate.
  26. *
  27. * fs line state sel (Bit 14):
  28. * - 1 (Default): FS line state is determined by the output data
  29. * (usb_fs_datain/b).
  30. * - 0: FS line state is always determined by the input data (dmo/dpo).
  31. */
  32. #define PHY_HS_LINE_TX_MODE BIT(13)
  33. #define PHY_FS_LINE_TX_MODE BIT(14)
  34. #define PHY_INIT_MODE_BITS (PHY_FS_LINE_TX_MODE | PHY_HS_LINE_TX_MODE)
  35. #define PHY_CLK_ENABLE_BITS (PHY_CLK_PLL_EN | PHY_CLK_CDR_EN | \
  36. PHY_CLK_MAC_EN)
  37. #define PHY_DEASSERT_RST_BITS (PHY_PLL_RSTN | PHY_CDR_RSTN | \
  38. PHY_MAC_RSTN)
  39. #define PHY_TX_HOST_CTRL 0x10
  40. #define PHY_HST_DISC_AUTO_CLR BIT(2) /* autoclear hs host disc when re-connect */
  41. #define PHY_HSTXP_HW_CTRL 0x34
  42. #define PHY_HSTXP_RSTN BIT(2) /* generate reset for clock hstxp */
  43. #define PHY_CLK_HSTXP_EN BIT(3) /* clock hstxp enable */
  44. #define PHY_HSTXP_MODE BIT(4) /* 0: force en_txp to be 1; 1: no force */
  45. #define PHY_K1_HS_HOST_DISC 0x40
  46. #define PHY_K1_HS_HOST_DISC_CLR BIT(0)
  47. #define PHY_PLL_DIV_CFG 0x98
  48. #define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
  49. #define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
  50. #define PHY_FDIV_FRACT_20_21 BIT(12) /* fdiv_reg<21>, <20>, bit21 == bit20 */
  51. /*
  52. * freq_sel<1:0>
  53. * if ref clk freq=24.0MHz-->freq_sel<2:0> == 3b'001, then internal divider value == 80
  54. */
  55. #define PHY_FDIV_FRACT_0_1 GENMASK(14, 13)
  56. /*
  57. * pll divider value selection
  58. * 1: divider value will choose internal default value ,dependent on freq_sel<1:0>
  59. * 0: divider value will be over ride by fdiv_reg<21:0>
  60. */
  61. #define PHY_DIV_LOCAL_EN BIT(15)
  62. #define PHY_SEL_FREQ_24MHZ 0x01
  63. #define FDIV_REG_MASK (PHY_FDIV_FRACT_20_21 | PHY_FDIV_FRACT_16_19 | \
  64. PHY_FDIV_FRACT_8_15)
  65. #define FDIV_REG_VAL 0x1ec4 /* 0x100 selects 24MHz, rest are default */
  66. #define K1_USB2PHY_RESET_TIME_MS 50
  67. struct spacemit_usb2phy {
  68. struct phy *phy;
  69. struct clk *clk;
  70. struct regmap *regmap_base;
  71. };
  72. static const struct regmap_config phy_regmap_config = {
  73. .reg_bits = 32,
  74. .val_bits = 32,
  75. .reg_stride = 4,
  76. .max_register = 0x200,
  77. };
  78. static int spacemit_usb2phy_init(struct phy *phy)
  79. {
  80. struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
  81. struct regmap *map = sphy->regmap_base;
  82. u32 val;
  83. int ret;
  84. ret = clk_enable(sphy->clk);
  85. if (ret) {
  86. dev_err(&phy->dev, "failed to enable clock\n");
  87. clk_disable(sphy->clk);
  88. return ret;
  89. }
  90. /*
  91. * make sure the usb controller is not under reset process before
  92. * any configuration
  93. */
  94. usleep_range(150, 200);
  95. /* 24M ref clk */
  96. val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
  97. FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
  98. PHY_DIV_LOCAL_EN;
  99. regmap_write(map, PHY_PLL_DIV_CFG, val);
  100. ret = regmap_read_poll_timeout(map, PHY_RST_MODE_CTRL, val,
  101. (val & PHY_PLL_RDY),
  102. 500, K1_USB2PHY_RESET_TIME_MS * 1000);
  103. if (ret) {
  104. dev_err(&phy->dev, "wait PLLREADY timeout\n");
  105. clk_disable(sphy->clk);
  106. return ret;
  107. }
  108. /* release usb2 phy internal reset and enable clock gating */
  109. val = (PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS);
  110. regmap_write(map, PHY_RST_MODE_CTRL, val);
  111. val = (PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE);
  112. regmap_write(map, PHY_HSTXP_HW_CTRL, val);
  113. /* auto clear host disc */
  114. regmap_update_bits(map, PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR,
  115. PHY_HST_DISC_AUTO_CLR);
  116. return 0;
  117. }
  118. static int spacemit_usb2phy_exit(struct phy *phy)
  119. {
  120. struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
  121. clk_disable(sphy->clk);
  122. return 0;
  123. }
  124. static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
  125. {
  126. struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
  127. regmap_update_bits(sphy->regmap_base, PHY_K1_HS_HOST_DISC,
  128. PHY_K1_HS_HOST_DISC_CLR, PHY_K1_HS_HOST_DISC_CLR);
  129. return 0;
  130. }
  131. static const struct phy_ops spacemit_usb2phy_ops = {
  132. .init = spacemit_usb2phy_init,
  133. .exit = spacemit_usb2phy_exit,
  134. .disconnect = spacemit_usb2phy_disconnect,
  135. .owner = THIS_MODULE,
  136. };
  137. static int spacemit_usb2phy_probe(struct platform_device *pdev)
  138. {
  139. struct phy_provider *phy_provider;
  140. struct device *dev = &pdev->dev;
  141. struct spacemit_usb2phy *sphy;
  142. void __iomem *base;
  143. sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
  144. if (!sphy)
  145. return -ENOMEM;
  146. sphy->clk = devm_clk_get_prepared(&pdev->dev, NULL);
  147. if (IS_ERR(sphy->clk))
  148. return dev_err_probe(dev, PTR_ERR(sphy->clk), "Failed to get clock\n");
  149. base = devm_platform_ioremap_resource(pdev, 0);
  150. if (IS_ERR(base))
  151. return PTR_ERR(base);
  152. sphy->regmap_base = devm_regmap_init_mmio(dev, base, &phy_regmap_config);
  153. if (IS_ERR(sphy->regmap_base))
  154. return dev_err_probe(dev, PTR_ERR(sphy->regmap_base), "Failed to init regmap\n");
  155. sphy->phy = devm_phy_create(dev, NULL, &spacemit_usb2phy_ops);
  156. if (IS_ERR(sphy->phy))
  157. return dev_err_probe(dev, PTR_ERR(sphy->phy), "Failed to create phy\n");
  158. phy_set_drvdata(sphy->phy, sphy);
  159. phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
  160. return PTR_ERR_OR_ZERO(phy_provider);
  161. }
  162. static const struct of_device_id spacemit_usb2phy_dt_match[] = {
  163. { .compatible = "spacemit,k1-usb2-phy", },
  164. { /* sentinel */ }
  165. };
  166. MODULE_DEVICE_TABLE(of, spacemit_usb2phy_dt_match);
  167. static struct platform_driver spacemit_usb2_phy_driver = {
  168. .probe = spacemit_usb2phy_probe,
  169. .driver = {
  170. .name = "spacemit-usb2-phy",
  171. .of_match_table = spacemit_usb2phy_dt_match,
  172. },
  173. };
  174. module_platform_driver(spacemit_usb2_phy_driver);
  175. MODULE_DESCRIPTION("Spacemit USB 2.0 PHY driver");
  176. MODULE_LICENSE("GPL");