phy-fsl-imx8mq-usb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /* Copyright (c) 2017 NXP. */
  3. #include <linux/bitfield.h>
  4. #include <linux/clk.h>
  5. #include <linux/delay.h>
  6. #include <linux/io.h>
  7. #include <linux/module.h>
  8. #include <linux/of.h>
  9. #include <linux/phy/phy.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/regulator/consumer.h>
  12. #include <linux/usb/typec_mux.h>
  13. #define PHY_CTRL0 0x0
  14. #define PHY_CTRL0_REF_SSP_EN BIT(2)
  15. #define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
  16. #define PHY_CTRL0_FSEL_24M 0x2a
  17. #define PHY_CTRL0_FSEL_100M 0x27
  18. #define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
  19. #define PHY_CTRL0_SSC_RANGE_4003PPM 0x2
  20. #define PHY_CTRL0_SSC_RANGE_4492PPM 0x1
  21. #define PHY_CTRL0_SSC_RANGE_4980PPM 0x0
  22. #define PHY_CTRL1 0x4
  23. #define PHY_CTRL1_RESET BIT(0)
  24. #define PHY_CTRL1_COMMONONN BIT(1)
  25. #define PHY_CTRL1_ATERESET BIT(3)
  26. #define PHY_CTRL1_VDATSRCENB0 BIT(19)
  27. #define PHY_CTRL1_VDATDETENB0 BIT(20)
  28. #define PHY_CTRL2 0x8
  29. #define PHY_CTRL2_TXENABLEN0 BIT(8)
  30. #define PHY_CTRL2_OTG_DISABLE BIT(9)
  31. #define PHY_CTRL3 0xc
  32. #define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
  33. #define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
  34. #define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
  35. #define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
  36. #define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
  37. #define PHY_CTRL4 0x10
  38. #define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
  39. #define PHY_CTRL5 0x14
  40. #define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
  41. #define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
  42. #define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
  43. #define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
  44. #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
  45. #define PHY_CTRL6 0x18
  46. #define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
  47. #define PHY_CTRL6_ALT_CLK_EN BIT(1)
  48. #define PHY_CTRL6_ALT_CLK_SEL BIT(0)
  49. #define PHY_TUNE_DEFAULT 0xffffffff
  50. #define TCA_CLK_RST 0x00
  51. #define TCA_CLK_RST_SW BIT(9)
  52. #define TCA_CLK_RST_REF_CLK_EN BIT(1)
  53. #define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0)
  54. #define TCA_INTR_EN 0x04
  55. #define TCA_INTR_STS 0x08
  56. #define TCA_GCFG 0x10
  57. #define TCA_GCFG_ROLE_HSTDEV BIT(4)
  58. #define TCA_GCFG_OP_MODE GENMASK(1, 0)
  59. #define TCA_GCFG_OP_MODE_SYSMODE 0
  60. #define TCA_GCFG_OP_MODE_SYNCMODE 1
  61. #define TCA_TCPC 0x14
  62. #define TCA_TCPC_VALID BIT(4)
  63. #define TCA_TCPC_LOW_POWER_EN BIT(3)
  64. #define TCA_TCPC_ORIENTATION_NORMAL BIT(2)
  65. #define TCA_TCPC_MUX_CONTRL GENMASK(1, 0)
  66. #define TCA_TCPC_MUX_CONTRL_NO_CONN 0
  67. #define TCA_TCPC_MUX_CONTRL_USB_CONN 1
  68. #define TCA_SYSMODE_CFG 0x18
  69. #define TCA_SYSMODE_TCPC_DISABLE BIT(3)
  70. #define TCA_SYSMODE_TCPC_FLIP BIT(2)
  71. #define TCA_CTRLSYNCMODE_CFG0 0x20
  72. #define TCA_CTRLSYNCMODE_CFG1 0x20
  73. #define TCA_PSTATE 0x30
  74. #define TCA_PSTATE_CM_STS BIT(4)
  75. #define TCA_PSTATE_TX_STS BIT(3)
  76. #define TCA_PSTATE_RX_PLL_STS BIT(2)
  77. #define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0)
  78. #define TCA_GEN_STATUS 0x34
  79. #define TCA_GEN_DEV_POR BIT(12)
  80. #define TCA_GEN_REF_CLK_SEL BIT(8)
  81. #define TCA_GEN_TYPEC_FLIP_INVERT BIT(4)
  82. #define TCA_GEN_PHY_TYPEC_DISABLE BIT(3)
  83. #define TCA_GEN_PHY_TYPEC_FLIP BIT(2)
  84. #define TCA_VBUS_CTRL 0x40
  85. #define TCA_VBUS_STATUS 0x44
  86. #define TCA_INFO 0xfc
  87. struct tca_blk {
  88. struct typec_switch_dev *sw;
  89. void __iomem *base;
  90. struct mutex mutex;
  91. enum typec_orientation orientation;
  92. };
  93. struct imx8mq_usb_phy {
  94. struct phy *phy;
  95. struct clk *clk;
  96. struct clk *alt_clk;
  97. void __iomem *base;
  98. struct regulator *vbus;
  99. struct tca_blk *tca;
  100. u32 pcs_tx_swing_full;
  101. u32 pcs_tx_deemph_3p5db;
  102. u32 tx_vref_tune;
  103. u32 tx_rise_tune;
  104. u32 tx_preemp_amp_tune;
  105. u32 tx_vboost_level;
  106. u32 comp_dis_tune;
  107. };
  108. static void tca_blk_orientation_set(struct tca_blk *tca,
  109. enum typec_orientation orientation);
  110. static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
  111. enum typec_orientation orientation)
  112. {
  113. struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
  114. struct tca_blk *tca = imx_phy->tca;
  115. int ret;
  116. if (tca->orientation == orientation)
  117. return 0;
  118. ret = clk_prepare_enable(imx_phy->clk);
  119. if (ret)
  120. return ret;
  121. tca_blk_orientation_set(tca, orientation);
  122. clk_disable_unprepare(imx_phy->clk);
  123. return 0;
  124. }
  125. static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
  126. struct imx8mq_usb_phy *imx_phy)
  127. {
  128. struct device *dev = &pdev->dev;
  129. struct typec_switch_dev *sw;
  130. struct typec_switch_desc sw_desc = { };
  131. sw_desc.drvdata = imx_phy;
  132. sw_desc.fwnode = dev->fwnode;
  133. sw_desc.set = tca_blk_typec_switch_set;
  134. sw_desc.name = NULL;
  135. sw = typec_switch_register(dev, &sw_desc);
  136. if (IS_ERR(sw)) {
  137. dev_err(dev, "Error register tca orientation switch: %ld",
  138. PTR_ERR(sw));
  139. return NULL;
  140. }
  141. return sw;
  142. }
  143. static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
  144. {
  145. typec_switch_unregister(sw);
  146. }
  147. static void tca_blk_orientation_set(struct tca_blk *tca,
  148. enum typec_orientation orientation)
  149. {
  150. u32 val;
  151. mutex_lock(&tca->mutex);
  152. if (orientation == TYPEC_ORIENTATION_NONE) {
  153. /*
  154. * use Controller Synced Mode for TCA low power enable and
  155. * put PHY to USB safe state.
  156. */
  157. val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE);
  158. writel(val, tca->base + TCA_GCFG);
  159. val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN;
  160. writel(val, tca->base + TCA_TCPC);
  161. goto out;
  162. }
  163. /* use System Configuration Mode for TCA mux control. */
  164. val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE);
  165. writel(val, tca->base + TCA_GCFG);
  166. /* Disable TCA module */
  167. val = readl(tca->base + TCA_SYSMODE_CFG);
  168. val |= TCA_SYSMODE_TCPC_DISABLE;
  169. writel(val, tca->base + TCA_SYSMODE_CFG);
  170. if (orientation == TYPEC_ORIENTATION_REVERSE)
  171. val |= TCA_SYSMODE_TCPC_FLIP;
  172. else if (orientation == TYPEC_ORIENTATION_NORMAL)
  173. val &= ~TCA_SYSMODE_TCPC_FLIP;
  174. writel(val, tca->base + TCA_SYSMODE_CFG);
  175. /* Enable TCA module */
  176. val &= ~TCA_SYSMODE_TCPC_DISABLE;
  177. writel(val, tca->base + TCA_SYSMODE_CFG);
  178. out:
  179. tca->orientation = orientation;
  180. mutex_unlock(&tca->mutex);
  181. }
  182. static void tca_blk_init(struct tca_blk *tca)
  183. {
  184. u32 val;
  185. /* reset XBar block */
  186. val = readl(tca->base + TCA_CLK_RST);
  187. val &= ~TCA_CLK_RST_SW;
  188. writel(val, tca->base + TCA_CLK_RST);
  189. udelay(100);
  190. /* clear reset */
  191. val |= TCA_CLK_RST_SW;
  192. writel(val, tca->base + TCA_CLK_RST);
  193. tca_blk_orientation_set(tca, tca->orientation);
  194. }
  195. static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
  196. struct imx8mq_usb_phy *imx_phy)
  197. {
  198. struct device *dev = &pdev->dev;
  199. struct resource *res;
  200. struct tca_blk *tca;
  201. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  202. if (!res)
  203. return NULL;
  204. tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
  205. if (!tca)
  206. return ERR_PTR(-ENOMEM);
  207. tca->base = devm_ioremap_resource(&pdev->dev, res);
  208. if (IS_ERR(tca->base))
  209. return ERR_CAST(tca->base);
  210. mutex_init(&tca->mutex);
  211. tca->orientation = TYPEC_ORIENTATION_NORMAL;
  212. tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
  213. return tca;
  214. }
  215. static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
  216. {
  217. struct tca_blk *tca = imx_phy->tca;
  218. if (!tca)
  219. return;
  220. tca_blk_put_typec_switch(tca->sw);
  221. }
  222. static u32 phy_tx_vref_tune_from_property(u32 percent)
  223. {
  224. percent = clamp(percent, 94U, 124U);
  225. return DIV_ROUND_CLOSEST(percent - 94U, 2);
  226. }
  227. static u32 imx95_phy_tx_vref_tune_from_property(u32 percent)
  228. {
  229. percent = clamp(percent, 90U, 108U);
  230. switch (percent) {
  231. case 90 ... 91:
  232. percent = 0;
  233. break;
  234. case 92 ... 96:
  235. percent -= 91;
  236. break;
  237. case 97 ... 104:
  238. percent -= 92;
  239. break;
  240. case 105 ... 108:
  241. percent -= 93;
  242. break;
  243. }
  244. return percent;
  245. }
  246. static u32 phy_tx_rise_tune_from_property(u32 percent)
  247. {
  248. switch (percent) {
  249. case 0 ... 98:
  250. return 3;
  251. case 99:
  252. return 2;
  253. case 100 ... 101:
  254. return 1;
  255. default:
  256. return 0;
  257. }
  258. }
  259. static u32 imx95_phy_tx_rise_tune_from_property(u32 percent)
  260. {
  261. percent = clamp(percent, 90U, 120U);
  262. switch (percent) {
  263. case 90 ... 99:
  264. return 3;
  265. case 101 ... 115:
  266. return 1;
  267. case 116 ... 120:
  268. return 0;
  269. default:
  270. return 2;
  271. }
  272. }
  273. static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
  274. {
  275. microamp = min(microamp, 1800U);
  276. return microamp / 600;
  277. }
  278. static u32 phy_tx_vboost_level_from_property(u32 microvolt)
  279. {
  280. switch (microvolt) {
  281. case 1156:
  282. return 5;
  283. case 844:
  284. return 3;
  285. default:
  286. return 4;
  287. }
  288. }
  289. static u32 phy_pcs_tx_deemph_3p5db_from_property(u32 decibel)
  290. {
  291. return min(decibel, 36U);
  292. }
  293. static u32 phy_comp_dis_tune_from_property(u32 percent)
  294. {
  295. switch (percent) {
  296. case 0 ... 92:
  297. return 0;
  298. case 93 ... 95:
  299. return 1;
  300. case 96 ... 97:
  301. return 2;
  302. case 98 ... 102:
  303. return 3;
  304. case 103 ... 105:
  305. return 4;
  306. case 106 ... 109:
  307. return 5;
  308. case 110 ... 113:
  309. return 6;
  310. default:
  311. return 7;
  312. }
  313. }
  314. static u32 imx95_phy_comp_dis_tune_from_property(u32 percent)
  315. {
  316. percent = clamp(percent, 94, 104);
  317. switch (percent) {
  318. case 94 ... 95:
  319. percent = 0;
  320. break;
  321. case 96 ... 98:
  322. percent -= 95;
  323. break;
  324. case 99 ... 102:
  325. percent -= 96;
  326. break;
  327. case 103 ... 104:
  328. percent -= 97;
  329. break;
  330. }
  331. return percent;
  332. }
  333. static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
  334. {
  335. percent = min(percent, 100U);
  336. return (percent * 127) / 100;
  337. }
  338. static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
  339. {
  340. struct device *dev = imx_phy->phy->dev.parent;
  341. bool is_imx95 = false;
  342. if (device_is_compatible(dev, "fsl,imx95-usb-phy"))
  343. is_imx95 = true;
  344. if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent",
  345. &imx_phy->tx_vref_tune))
  346. imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT;
  347. else if (is_imx95)
  348. imx_phy->tx_vref_tune =
  349. imx95_phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
  350. else
  351. imx_phy->tx_vref_tune =
  352. phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
  353. if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent",
  354. &imx_phy->tx_rise_tune))
  355. imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT;
  356. else if (is_imx95)
  357. imx_phy->tx_rise_tune =
  358. imx95_phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
  359. else
  360. imx_phy->tx_rise_tune =
  361. phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
  362. if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune-microamp",
  363. &imx_phy->tx_preemp_amp_tune))
  364. imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT;
  365. else
  366. imx_phy->tx_preemp_amp_tune =
  367. phy_tx_preemp_amp_tune_from_property(imx_phy->tx_preemp_amp_tune);
  368. if (device_property_read_u32(dev, "fsl,phy-tx-vboost-level-microvolt",
  369. &imx_phy->tx_vboost_level))
  370. imx_phy->tx_vboost_level = PHY_TUNE_DEFAULT;
  371. else
  372. imx_phy->tx_vboost_level =
  373. phy_tx_vboost_level_from_property(imx_phy->tx_vboost_level);
  374. if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent",
  375. &imx_phy->comp_dis_tune))
  376. imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT;
  377. else if (is_imx95)
  378. imx_phy->comp_dis_tune =
  379. imx95_phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
  380. else
  381. imx_phy->comp_dis_tune =
  382. phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
  383. if (device_property_read_u32(dev, "fsl,phy-pcs-tx-deemph-3p5db-attenuation-db",
  384. &imx_phy->pcs_tx_deemph_3p5db))
  385. imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT;
  386. else
  387. imx_phy->pcs_tx_deemph_3p5db =
  388. phy_pcs_tx_deemph_3p5db_from_property(imx_phy->pcs_tx_deemph_3p5db);
  389. if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full-percent",
  390. &imx_phy->pcs_tx_swing_full))
  391. imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT;
  392. else
  393. imx_phy->pcs_tx_swing_full =
  394. phy_pcs_tx_swing_full_from_property(imx_phy->pcs_tx_swing_full);
  395. }
  396. static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy)
  397. {
  398. u32 value;
  399. /* PHY tuning */
  400. if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) {
  401. value = readl(imx_phy->base + PHY_CTRL4);
  402. value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK;
  403. value |= FIELD_PREP(PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK,
  404. imx_phy->pcs_tx_deemph_3p5db);
  405. writel(value, imx_phy->base + PHY_CTRL4);
  406. }
  407. if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) {
  408. value = readl(imx_phy->base + PHY_CTRL5);
  409. value &= ~PHY_CTRL5_PCS_TX_SWING_FULL_MASK;
  410. value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK,
  411. imx_phy->pcs_tx_swing_full);
  412. writel(value, imx_phy->base + PHY_CTRL5);
  413. }
  414. if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune &
  415. imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune &
  416. imx_phy->tx_vboost_level) == PHY_TUNE_DEFAULT)
  417. /* If all are the default values, no need update. */
  418. return;
  419. value = readl(imx_phy->base + PHY_CTRL3);
  420. if (imx_phy->tx_vref_tune != PHY_TUNE_DEFAULT) {
  421. value &= ~PHY_CTRL3_TXVREF_TUNE_MASK;
  422. value |= FIELD_PREP(PHY_CTRL3_TXVREF_TUNE_MASK,
  423. imx_phy->tx_vref_tune);
  424. }
  425. if (imx_phy->tx_rise_tune != PHY_TUNE_DEFAULT) {
  426. value &= ~PHY_CTRL3_TXRISE_TUNE_MASK;
  427. value |= FIELD_PREP(PHY_CTRL3_TXRISE_TUNE_MASK,
  428. imx_phy->tx_rise_tune);
  429. }
  430. if (imx_phy->tx_preemp_amp_tune != PHY_TUNE_DEFAULT) {
  431. value &= ~PHY_CTRL3_TXPREEMP_TUNE_MASK;
  432. value |= FIELD_PREP(PHY_CTRL3_TXPREEMP_TUNE_MASK,
  433. imx_phy->tx_preemp_amp_tune);
  434. }
  435. if (imx_phy->comp_dis_tune != PHY_TUNE_DEFAULT) {
  436. value &= ~PHY_CTRL3_COMPDISTUNE_MASK;
  437. value |= FIELD_PREP(PHY_CTRL3_COMPDISTUNE_MASK,
  438. imx_phy->comp_dis_tune);
  439. }
  440. if (imx_phy->tx_vboost_level != PHY_TUNE_DEFAULT) {
  441. value &= ~PHY_CTRL3_TX_VBOOST_LEVEL_MASK;
  442. value |= FIELD_PREP(PHY_CTRL3_TX_VBOOST_LEVEL_MASK,
  443. imx_phy->tx_vboost_level);
  444. }
  445. writel(value, imx_phy->base + PHY_CTRL3);
  446. }
  447. static int imx8mq_usb_phy_init(struct phy *phy)
  448. {
  449. struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
  450. u32 value;
  451. value = readl(imx_phy->base + PHY_CTRL1);
  452. value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
  453. PHY_CTRL1_COMMONONN);
  454. value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
  455. writel(value, imx_phy->base + PHY_CTRL1);
  456. value = readl(imx_phy->base + PHY_CTRL0);
  457. value |= PHY_CTRL0_REF_SSP_EN;
  458. writel(value, imx_phy->base + PHY_CTRL0);
  459. value = readl(imx_phy->base + PHY_CTRL2);
  460. value |= PHY_CTRL2_TXENABLEN0;
  461. writel(value, imx_phy->base + PHY_CTRL2);
  462. value = readl(imx_phy->base + PHY_CTRL1);
  463. value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
  464. writel(value, imx_phy->base + PHY_CTRL1);
  465. return 0;
  466. }
  467. static int imx8mp_usb_phy_init(struct phy *phy)
  468. {
  469. struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
  470. u32 value;
  471. /* USB3.0 PHY signal fsel for 24M ref */
  472. value = readl(imx_phy->base + PHY_CTRL0);
  473. value &= ~PHY_CTRL0_FSEL_MASK;
  474. value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, imx_phy->alt_clk ?
  475. PHY_CTRL0_FSEL_100M : PHY_CTRL0_FSEL_24M);
  476. writel(value, imx_phy->base + PHY_CTRL0);
  477. /* Disable alt_clk_en and use internal MPLL clocks */
  478. value = readl(imx_phy->base + PHY_CTRL6);
  479. value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN);
  480. writel(value, imx_phy->base + PHY_CTRL6);
  481. value = readl(imx_phy->base + PHY_CTRL1);
  482. value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0);
  483. value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
  484. writel(value, imx_phy->base + PHY_CTRL1);
  485. value = readl(imx_phy->base + PHY_CTRL0);
  486. value |= PHY_CTRL0_REF_SSP_EN;
  487. value &= ~PHY_CTRL0_SSC_RANGE_MASK;
  488. value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
  489. PHY_CTRL0_SSC_RANGE_4003PPM);
  490. writel(value, imx_phy->base + PHY_CTRL0);
  491. value = readl(imx_phy->base + PHY_CTRL2);
  492. value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE;
  493. writel(value, imx_phy->base + PHY_CTRL2);
  494. udelay(10);
  495. value = readl(imx_phy->base + PHY_CTRL1);
  496. value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
  497. writel(value, imx_phy->base + PHY_CTRL1);
  498. imx8m_phy_tune(imx_phy);
  499. if (imx_phy->tca)
  500. tca_blk_init(imx_phy->tca);
  501. return 0;
  502. }
  503. static int imx8mq_phy_power_on(struct phy *phy)
  504. {
  505. struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
  506. u32 value;
  507. int ret;
  508. ret = regulator_enable(imx_phy->vbus);
  509. if (ret)
  510. return ret;
  511. ret = clk_prepare_enable(imx_phy->clk);
  512. if (ret)
  513. return ret;
  514. ret = clk_prepare_enable(imx_phy->alt_clk);
  515. if (ret) {
  516. clk_disable_unprepare(imx_phy->clk);
  517. return ret;
  518. }
  519. /* Disable rx term override */
  520. value = readl(imx_phy->base + PHY_CTRL6);
  521. value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
  522. writel(value, imx_phy->base + PHY_CTRL6);
  523. return 0;
  524. }
  525. static int imx8mq_phy_power_off(struct phy *phy)
  526. {
  527. struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
  528. u32 value;
  529. /* Override rx term to be 0 */
  530. value = readl(imx_phy->base + PHY_CTRL6);
  531. value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
  532. writel(value, imx_phy->base + PHY_CTRL6);
  533. clk_disable_unprepare(imx_phy->alt_clk);
  534. clk_disable_unprepare(imx_phy->clk);
  535. regulator_disable(imx_phy->vbus);
  536. return 0;
  537. }
  538. static const struct phy_ops imx8mq_usb_phy_ops = {
  539. .init = imx8mq_usb_phy_init,
  540. .power_on = imx8mq_phy_power_on,
  541. .power_off = imx8mq_phy_power_off,
  542. .owner = THIS_MODULE,
  543. };
  544. static const struct phy_ops imx8mp_usb_phy_ops = {
  545. .init = imx8mp_usb_phy_init,
  546. .power_on = imx8mq_phy_power_on,
  547. .power_off = imx8mq_phy_power_off,
  548. .owner = THIS_MODULE,
  549. };
  550. static const struct of_device_id imx8mq_usb_phy_of_match[] = {
  551. {.compatible = "fsl,imx8mq-usb-phy",
  552. .data = &imx8mq_usb_phy_ops,},
  553. {.compatible = "fsl,imx8mp-usb-phy",
  554. .data = &imx8mp_usb_phy_ops,},
  555. {.compatible = "fsl,imx95-usb-phy",
  556. .data = &imx8mp_usb_phy_ops,},
  557. { }
  558. };
  559. MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
  560. static int imx8mq_usb_phy_probe(struct platform_device *pdev)
  561. {
  562. struct phy_provider *phy_provider;
  563. struct device *dev = &pdev->dev;
  564. struct imx8mq_usb_phy *imx_phy;
  565. const struct phy_ops *phy_ops;
  566. imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
  567. if (!imx_phy)
  568. return -ENOMEM;
  569. platform_set_drvdata(pdev, imx_phy);
  570. imx_phy->clk = devm_clk_get(dev, "phy");
  571. if (IS_ERR(imx_phy->clk)) {
  572. dev_err(dev, "failed to get imx8mq usb phy clock\n");
  573. return PTR_ERR(imx_phy->clk);
  574. }
  575. imx_phy->alt_clk = devm_clk_get_optional(dev, "alt");
  576. if (IS_ERR(imx_phy->alt_clk))
  577. return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk),
  578. "Failed to get alt clk\n");
  579. imx_phy->base = devm_platform_ioremap_resource(pdev, 0);
  580. if (IS_ERR(imx_phy->base))
  581. return PTR_ERR(imx_phy->base);
  582. phy_ops = of_device_get_match_data(dev);
  583. if (!phy_ops)
  584. return -EINVAL;
  585. imx_phy->phy = devm_phy_create(dev, NULL, phy_ops);
  586. if (IS_ERR(imx_phy->phy))
  587. return PTR_ERR(imx_phy->phy);
  588. imx_phy->vbus = devm_regulator_get(dev, "vbus");
  589. if (IS_ERR(imx_phy->vbus))
  590. return dev_err_probe(dev, PTR_ERR(imx_phy->vbus), "failed to get vbus\n");
  591. phy_set_drvdata(imx_phy->phy, imx_phy);
  592. imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy);
  593. if (IS_ERR(imx_phy->tca))
  594. return dev_err_probe(dev, PTR_ERR(imx_phy->tca),
  595. "failed to get tca\n");
  596. imx8m_get_phy_tuning_data(imx_phy);
  597. phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
  598. return PTR_ERR_OR_ZERO(phy_provider);
  599. }
  600. static void imx8mq_usb_phy_remove(struct platform_device *pdev)
  601. {
  602. struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
  603. imx95_usb_phy_put_tca(imx_phy);
  604. }
  605. static struct platform_driver imx8mq_usb_phy_driver = {
  606. .probe = imx8mq_usb_phy_probe,
  607. .remove = imx8mq_usb_phy_remove,
  608. .driver = {
  609. .name = "imx8mq-usb-phy",
  610. .of_match_table = imx8mq_usb_phy_of_match,
  611. .suppress_bind_attrs = true,
  612. }
  613. };
  614. module_platform_driver(imx8mq_usb_phy_driver);
  615. MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver");
  616. MODULE_LICENSE("GPL");