PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/phy/marvell/phy-mmp3-usb.c

https://github.com/penberg/linux
C | 291 lines | 211 code | 55 blank | 25 comment | 11 complexity | 4b5615fd72a6b994f48325acd6827da5 MD5 | raw file
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
  4. * Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>
  5. */
  6. #include <linux/delay.h>
  7. #include <linux/io.h>
  8. #include <linux/module.h>
  9. #include <linux/phy/phy.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/soc/mmp/cputype.h>
  12. #define USB2_PLL_REG0 0x4
  13. #define USB2_PLL_REG1 0x8
  14. #define USB2_TX_REG0 0x10
  15. #define USB2_TX_REG1 0x14
  16. #define USB2_TX_REG2 0x18
  17. #define USB2_RX_REG0 0x20
  18. #define USB2_RX_REG1 0x24
  19. #define USB2_RX_REG2 0x28
  20. #define USB2_ANA_REG0 0x30
  21. #define USB2_ANA_REG1 0x34
  22. #define USB2_ANA_REG2 0x38
  23. #define USB2_DIG_REG0 0x3C
  24. #define USB2_DIG_REG1 0x40
  25. #define USB2_DIG_REG2 0x44
  26. #define USB2_DIG_REG3 0x48
  27. #define USB2_TEST_REG0 0x4C
  28. #define USB2_TEST_REG1 0x50
  29. #define USB2_TEST_REG2 0x54
  30. #define USB2_CHARGER_REG0 0x58
  31. #define USB2_OTG_REG0 0x5C
  32. #define USB2_PHY_MON0 0x60
  33. #define USB2_RESETVE_REG0 0x64
  34. #define USB2_ICID_REG0 0x78
  35. #define USB2_ICID_REG1 0x7C
  36. /* USB2_PLL_REG0 */
  37. /* This is for Ax stepping */
  38. #define USB2_PLL_FBDIV_SHIFT_MMP3 0
  39. #define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)
  40. #define USB2_PLL_REFDIV_SHIFT_MMP3 8
  41. #define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)
  42. #define USB2_PLL_VDD12_SHIFT_MMP3 12
  43. #define USB2_PLL_VDD18_SHIFT_MMP3 14
  44. /* This is for B0 stepping */
  45. #define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0
  46. #define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9
  47. #define USB2_PLL_VDD18_SHIFT_MMP3_B0 14
  48. #define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF
  49. #define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00
  50. #define USB2_PLL_CAL12_SHIFT_MMP3 0
  51. #define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)
  52. #define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2
  53. #define USB2_PLL_KVCO_SHIFT_MMP3 4
  54. #define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)
  55. #define USB2_PLL_ICP_SHIFT_MMP3 8
  56. #define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)
  57. #define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12
  58. #define USB2_PLL_PU_PLL_SHIFT_MMP3 13
  59. #define USB2_PLL_PU_PLL_MASK (0x1 << 13)
  60. #define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)
  61. /* USB2_TX_REG0 */
  62. #define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8
  63. #define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)
  64. #define USB2_TX_RCAL_START_SHIFT_MMP3 13
  65. /* USB2_TX_REG1 */
  66. #define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0
  67. #define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)
  68. #define USB2_TX_AMP_SHIFT_MMP3 4
  69. #define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)
  70. #define USB2_TX_VDD12_SHIFT_MMP3 8
  71. #define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)
  72. /* USB2_TX_REG2 */
  73. #define USB2_TX_DRV_SLEWRATE_SHIFT 10
  74. /* USB2_RX_REG0 */
  75. #define USB2_RX_SQ_THRESH_SHIFT_MMP3 4
  76. #define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)
  77. #define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10
  78. #define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)
  79. /* USB2_ANA_REG1*/
  80. #define USB2_ANA_PU_ANA_SHIFT_MMP3 14
  81. /* USB2_OTG_REG0 */
  82. #define USB2_OTG_PU_OTG_SHIFT_MMP3 3
  83. struct mmp3_usb_phy {
  84. struct phy *phy;
  85. void __iomem *base;
  86. };
  87. static unsigned int u2o_get(void __iomem *base, unsigned int offset)
  88. {
  89. return readl_relaxed(base + offset);
  90. }
  91. static void u2o_set(void __iomem *base, unsigned int offset,
  92. unsigned int value)
  93. {
  94. u32 reg;
  95. reg = readl_relaxed(base + offset);
  96. reg |= value;
  97. writel_relaxed(reg, base + offset);
  98. readl_relaxed(base + offset);
  99. }
  100. static void u2o_clear(void __iomem *base, unsigned int offset,
  101. unsigned int value)
  102. {
  103. u32 reg;
  104. reg = readl_relaxed(base + offset);
  105. reg &= ~value;
  106. writel_relaxed(reg, base + offset);
  107. readl_relaxed(base + offset);
  108. }
  109. static int mmp3_usb_phy_init(struct phy *phy)
  110. {
  111. struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
  112. void __iomem *base = mmp3_usb_phy->base;
  113. if (cpu_is_mmp3_a0()) {
  114. u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3
  115. | USB2_PLL_REFDIV_MASK_MMP3));
  116. u2o_set(base, USB2_PLL_REG0,
  117. 0xd << USB2_PLL_REFDIV_SHIFT_MMP3
  118. | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);
  119. } else if (cpu_is_mmp3_b0()) {
  120. u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0
  121. | USB2_PLL_FBDIV_MASK_MMP3_B0);
  122. u2o_set(base, USB2_PLL_REG0,
  123. 0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0
  124. | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);
  125. } else {
  126. dev_err(&phy->dev, "unsupported silicon revision\n");
  127. return -ENODEV;
  128. }
  129. u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK
  130. | USB2_PLL_ICP_MASK_MMP3
  131. | USB2_PLL_KVCO_MASK_MMP3
  132. | USB2_PLL_CALI12_MASK_MMP3);
  133. u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3
  134. | 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3
  135. | 3 << USB2_PLL_ICP_SHIFT_MMP3
  136. | 3 << USB2_PLL_KVCO_SHIFT_MMP3
  137. | 3 << USB2_PLL_CAL12_SHIFT_MMP3);
  138. u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);
  139. u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);
  140. u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3
  141. | USB2_TX_AMP_MASK_MMP3
  142. | USB2_TX_CK60_PHSEL_MASK_MMP3);
  143. u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3
  144. | 4 << USB2_TX_AMP_SHIFT_MMP3
  145. | 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);
  146. u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);
  147. u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);
  148. u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);
  149. u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);
  150. u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);
  151. u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);
  152. return 0;
  153. }
  154. static int mmp3_usb_phy_calibrate(struct phy *phy)
  155. {
  156. struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
  157. void __iomem *base = mmp3_usb_phy->base;
  158. int loops;
  159. /*
  160. * PLL VCO and TX Impedance Calibration Timing:
  161. *
  162. * _____________________________________
  163. * PU __________|
  164. * _____________________________
  165. * VCOCAL START _________|
  166. * ___
  167. * REG_RCAL_START ________________| |________|_______
  168. * | 200us | 400us | 40| 400us | USB PHY READY
  169. */
  170. udelay(200);
  171. u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);
  172. udelay(400);
  173. u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
  174. udelay(40);
  175. u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
  176. udelay(400);
  177. loops = 0;
  178. while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {
  179. mdelay(1);
  180. loops++;
  181. if (loops > 100) {
  182. dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");
  183. return -ETIMEDOUT;
  184. }
  185. }
  186. return 0;
  187. }
  188. static const struct phy_ops mmp3_usb_phy_ops = {
  189. .init = mmp3_usb_phy_init,
  190. .calibrate = mmp3_usb_phy_calibrate,
  191. .owner = THIS_MODULE,
  192. };
  193. static const struct of_device_id mmp3_usb_phy_of_match[] = {
  194. { .compatible = "marvell,mmp3-usb-phy", },
  195. { },
  196. };
  197. MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);
  198. static int mmp3_usb_phy_probe(struct platform_device *pdev)
  199. {
  200. struct device *dev = &pdev->dev;
  201. struct resource *resource;
  202. struct mmp3_usb_phy *mmp3_usb_phy;
  203. struct phy_provider *provider;
  204. mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);
  205. if (!mmp3_usb_phy)
  206. return -ENOMEM;
  207. resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  208. mmp3_usb_phy->base = devm_ioremap_resource(dev, resource);
  209. if (IS_ERR(mmp3_usb_phy->base)) {
  210. dev_err(dev, "failed to remap PHY regs\n");
  211. return PTR_ERR(mmp3_usb_phy->base);
  212. }
  213. mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);
  214. if (IS_ERR(mmp3_usb_phy->phy)) {
  215. dev_err(dev, "failed to create PHY\n");
  216. return PTR_ERR(mmp3_usb_phy->phy);
  217. }
  218. phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);
  219. provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
  220. if (IS_ERR(provider)) {
  221. dev_err(dev, "failed to register PHY provider\n");
  222. return PTR_ERR(provider);
  223. }
  224. return 0;
  225. }
  226. static struct platform_driver mmp3_usb_phy_driver = {
  227. .probe = mmp3_usb_phy_probe,
  228. .driver = {
  229. .name = "mmp3-usb-phy",
  230. .of_match_table = mmp3_usb_phy_of_match,
  231. },
  232. };
  233. module_platform_driver(mmp3_usb_phy_driver);
  234. MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
  235. MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");
  236. MODULE_LICENSE("GPL v2");