100-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. --- a/drivers/phy/Kconfig
  2. +++ b/drivers/phy/Kconfig
  3. @@ -390,4 +390,15 @@ config PHY_CYGNUS_PCIE
  4. Enable this to support the Broadcom Cygnus PCIe PHY.
  5. If unsure, say N.
  6. +config PHY_QCOM_DWC3
  7. + tristate "QCOM DWC3 USB PHY support"
  8. + depends on ARCH_QCOM
  9. + depends on HAS_IOMEM
  10. + depends on OF
  11. + select GENERIC_PHY
  12. + help
  13. + This option enables support for the Synopsis PHYs present inside the
  14. + Qualcomm USB3.0 DWC3 controller. This driver supports both HS and SS
  15. + PHY controllers.
  16. +
  17. endmenu
  18. --- a/drivers/phy/Makefile
  19. +++ b/drivers/phy/Makefile
  20. @@ -48,3 +48,4 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1
  21. obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
  22. obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
  23. obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
  24. +obj-$(CONFIG_PHY_QCOM_DWC3) += phy-qcom-dwc3.o
  25. --- /dev/null
  26. +++ b/drivers/phy/phy-qcom-dwc3.c
  27. @@ -0,0 +1,482 @@
  28. +/* Copyright (c) 2013-2014, Code Aurora Forum. All rights reserved.
  29. + *
  30. + * This program is free software; you can redistribute it and/or modify
  31. + * it under the terms of the GNU General Public License version 2 and
  32. + * only version 2 as published by the Free Software Foundation.
  33. + *
  34. + * This program is distributed in the hope that it will be useful,
  35. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  36. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  37. + * GNU General Public License for more details.
  38. + */
  39. +
  40. +#include <linux/clk.h>
  41. +#include <linux/err.h>
  42. +#include <linux/io.h>
  43. +#include <linux/module.h>
  44. +#include <linux/of.h>
  45. +#include <linux/phy/phy.h>
  46. +#include <linux/platform_device.h>
  47. +#include <linux/delay.h>
  48. +
  49. +/**
  50. + * USB QSCRATCH Hardware registers
  51. + */
  52. +#define QSCRATCH_GENERAL_CFG (0x08)
  53. +#define HSUSB_PHY_CTRL_REG (0x10)
  54. +
  55. +/* PHY_CTRL_REG */
  56. +#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24)
  57. +#define HSUSB_CTRL_USB2_SUSPEND BIT(23)
  58. +#define HSUSB_CTRL_UTMI_CLK_EN BIT(21)
  59. +#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20)
  60. +#define HSUSB_CTRL_USE_CLKCORE BIT(18)
  61. +#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17)
  62. +#define HSUSB_CTRL_COMMONONN BIT(11)
  63. +#define HSUSB_CTRL_ID_HV_CLAMP BIT(9)
  64. +#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8)
  65. +#define HSUSB_CTRL_CLAMP_EN BIT(7)
  66. +#define HSUSB_CTRL_RETENABLEN BIT(1)
  67. +#define HSUSB_CTRL_POR BIT(0)
  68. +
  69. +/* QSCRATCH_GENERAL_CFG */
  70. +#define HSUSB_GCFG_XHCI_REV BIT(2)
  71. +
  72. +/**
  73. + * USB QSCRATCH Hardware registers
  74. + */
  75. +#define SSUSB_PHY_CTRL_REG (0x00)
  76. +#define SSUSB_PHY_PARAM_CTRL_1 (0x04)
  77. +#define SSUSB_PHY_PARAM_CTRL_2 (0x08)
  78. +#define CR_PROTOCOL_DATA_IN_REG (0x0c)
  79. +#define CR_PROTOCOL_DATA_OUT_REG (0x10)
  80. +#define CR_PROTOCOL_CAP_ADDR_REG (0x14)
  81. +#define CR_PROTOCOL_CAP_DATA_REG (0x18)
  82. +#define CR_PROTOCOL_READ_REG (0x1c)
  83. +#define CR_PROTOCOL_WRITE_REG (0x20)
  84. +
  85. +/* PHY_CTRL_REG */
  86. +#define SSUSB_CTRL_REF_USE_PAD BIT(28)
  87. +#define SSUSB_CTRL_TEST_POWERDOWN BIT(27)
  88. +#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24)
  89. +#define SSUSB_CTRL_SS_PHY_EN BIT(8)
  90. +#define SSUSB_CTRL_SS_PHY_RESET BIT(7)
  91. +
  92. +/* SSPHY control registers */
  93. +#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * lane)
  94. +#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * lane)
  95. +
  96. +/* RX OVRD IN HI bits */
  97. +#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13)
  98. +#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12)
  99. +#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11)
  100. +#define RX_OVRD_IN_HI_RX_EQ_MASK 0x0700
  101. +#define RX_OVRD_IN_HI_RX_EQ_SHIFT 8
  102. +#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7)
  103. +#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6)
  104. +#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5)
  105. +#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK 0x0018
  106. +#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2)
  107. +#define RX_OVRD_IN_HI_RX_RATE_MASK 0x0003
  108. +
  109. +/* TX OVRD DRV LO register bits */
  110. +#define TX_OVRD_DRV_LO_AMPLITUDE_MASK 0x007F
  111. +#define TX_OVRD_DRV_LO_PREEMPH_MASK 0x3F80
  112. +#define TX_OVRD_DRV_LO_PREEMPH_SHIFT 7
  113. +#define TX_OVRD_DRV_LO_EN BIT(14)
  114. +
  115. +struct qcom_dwc3_usb_phy {
  116. + void __iomem *base;
  117. + struct device *dev;
  118. + struct phy *phy;
  119. +
  120. + int (*phy_init)(struct qcom_dwc3_usb_phy *phy_dwc3);
  121. + int (*phy_exit)(struct qcom_dwc3_usb_phy *phy_dwc3);
  122. +
  123. + struct clk *xo_clk;
  124. + struct clk *ref_clk;
  125. +};
  126. +
  127. +/**
  128. + * Write register and read back masked value to confirm it is written
  129. + *
  130. + * @base - QCOM DWC3 PHY base virtual address.
  131. + * @offset - register offset.
  132. + * @mask - register bitmask specifying what should be updated
  133. + * @val - value to write.
  134. + */
  135. +static inline void qcom_dwc3_phy_write_readback(
  136. + struct qcom_dwc3_usb_phy *phy_dwc3, u32 offset,
  137. + const u32 mask, u32 val)
  138. +{
  139. + u32 write_val, tmp = readl(phy_dwc3->base + offset);
  140. +
  141. + tmp &= ~mask; /* retain other bits */
  142. + write_val = tmp | val;
  143. +
  144. + writel(write_val, phy_dwc3->base + offset);
  145. +
  146. + /* Read back to see if val was written */
  147. + tmp = readl(phy_dwc3->base + offset);
  148. + tmp &= mask; /* clear other bits */
  149. +
  150. + if (tmp != val)
  151. + dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n",
  152. + val, offset);
  153. +}
  154. +
  155. +static int wait_for_latch(void __iomem *addr)
  156. +{
  157. + u32 retry = 10;
  158. +
  159. + while (true) {
  160. + if (!readl(addr))
  161. + break;
  162. +
  163. + if (--retry == 0)
  164. + return -ETIMEDOUT;
  165. +
  166. + usleep_range(10, 20);
  167. + }
  168. +
  169. + return 0;
  170. +}
  171. +
  172. +/**
  173. + * Write SSPHY register
  174. + *
  175. + * @base - QCOM DWC3 PHY base virtual address.
  176. + * @addr - SSPHY address to write.
  177. + * @val - value to write.
  178. + */
  179. +static int qcom_dwc3_ss_write_phycreg(void __iomem *base, u32 addr, u32 val)
  180. +{
  181. + int ret;
  182. +
  183. + writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
  184. + writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG);
  185. +
  186. + ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG);
  187. + if (ret)
  188. + goto err_wait;
  189. +
  190. + writel(val, base + CR_PROTOCOL_DATA_IN_REG);
  191. + writel(0x1, base + CR_PROTOCOL_CAP_DATA_REG);
  192. +
  193. + ret = wait_for_latch(base + CR_PROTOCOL_CAP_DATA_REG);
  194. + if (ret)
  195. + goto err_wait;
  196. +
  197. + writel(0x1, base + CR_PROTOCOL_WRITE_REG);
  198. +
  199. + ret = wait_for_latch(base + CR_PROTOCOL_WRITE_REG);
  200. +
  201. +err_wait:
  202. + return ret;
  203. +}
  204. +
  205. +/**
  206. + * Read SSPHY register.
  207. + *
  208. + * @base - QCOM DWC3 PHY base virtual address.
  209. + * @addr - SSPHY address to read.
  210. + */
  211. +static int qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr, u32 *val)
  212. +{
  213. + int ret;
  214. + bool first_read = true;
  215. +
  216. + writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
  217. + writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG);
  218. +
  219. + ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG);
  220. + if (ret)
  221. + goto err_wait;
  222. +
  223. + /*
  224. + * Due to hardware bug, first read of SSPHY register might be
  225. + * incorrect. Hence as workaround, SW should perform SSPHY register
  226. + * read twice, but use only second read and ignore first read.
  227. + */
  228. +retry:
  229. + writel(0x1, base + CR_PROTOCOL_READ_REG);
  230. +
  231. + ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
  232. + if (ret)
  233. + goto err_wait;
  234. +
  235. + if (first_read) {
  236. + readl(base + CR_PROTOCOL_DATA_OUT_REG);
  237. + first_read = false;
  238. + goto retry;
  239. + }
  240. +
  241. + *val = readl(base + CR_PROTOCOL_DATA_OUT_REG);
  242. +
  243. +err_wait:
  244. + return ret;
  245. +}
  246. +
  247. +static int qcom_dwc3_phy_power_on(struct phy *phy)
  248. +{
  249. + int ret;
  250. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  251. +
  252. + ret = clk_prepare_enable(phy_dwc3->xo_clk);
  253. + if (ret)
  254. + return ret;
  255. +
  256. + ret = clk_prepare_enable(phy_dwc3->ref_clk);
  257. + if (ret)
  258. + clk_disable_unprepare(phy_dwc3->xo_clk);
  259. +
  260. + return ret;
  261. +}
  262. +
  263. +static int qcom_dwc3_phy_power_off(struct phy *phy)
  264. +{
  265. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  266. +
  267. + clk_disable_unprepare(phy_dwc3->ref_clk);
  268. + clk_disable_unprepare(phy_dwc3->xo_clk);
  269. +
  270. + return 0;
  271. +}
  272. +
  273. +static int qcom_dwc3_hs_phy_init(struct qcom_dwc3_usb_phy *phy_dwc3)
  274. +{
  275. + u32 val;
  276. +
  277. + /*
  278. + * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
  279. + * enable clamping, and disable RETENTION (power-on default is ENABLED)
  280. + */
  281. + val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
  282. + HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN |
  283. + HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
  284. + HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID |
  285. + HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70;
  286. +
  287. + /* use core clock if external reference is not present */
  288. + if (!phy_dwc3->xo_clk)
  289. + val |= HSUSB_CTRL_USE_CLKCORE;
  290. +
  291. + writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
  292. + usleep_range(2000, 2200);
  293. +
  294. + /* Disable (bypass) VBUS and ID filters */
  295. + writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
  296. +
  297. + return 0;
  298. +}
  299. +
  300. +static int qcom_dwc3_ss_phy_init(struct qcom_dwc3_usb_phy *phy_dwc3)
  301. +{
  302. + int ret;
  303. + u32 data = 0;
  304. +
  305. + /* reset phy */
  306. + data = readl_relaxed(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  307. + writel_relaxed(data | SSUSB_CTRL_SS_PHY_RESET,
  308. + phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  309. + usleep_range(2000, 2200);
  310. + writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  311. +
  312. + /* clear REF_PAD if we don't have XO clk */
  313. + if (!phy_dwc3->xo_clk)
  314. + data &= ~SSUSB_CTRL_REF_USE_PAD;
  315. + else
  316. + data |= SSUSB_CTRL_REF_USE_PAD;
  317. +
  318. + writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  319. + msleep(30);
  320. +
  321. + data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
  322. + writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  323. +
  324. + /*
  325. + * Fix RX Equalization setting as follows
  326. + * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
  327. + * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
  328. + * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
  329. + * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
  330. + */
  331. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  332. + SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
  333. + if (ret)
  334. + goto err_phy_trans;
  335. +
  336. + data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
  337. + data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
  338. + data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
  339. + data |= 0x3 << RX_OVRD_IN_HI_RX_EQ_SHIFT;
  340. + data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
  341. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3->base,
  342. + SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
  343. + if (ret)
  344. + goto err_phy_trans;
  345. +
  346. + /*
  347. + * Set EQ and TX launch amplitudes as follows
  348. + * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
  349. + * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
  350. + * LANE0.TX_OVRD_DRV_LO.EN set to 1.
  351. + */
  352. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  353. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
  354. + if (ret)
  355. + goto err_phy_trans;
  356. +
  357. + data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
  358. + data |= 0x16 << TX_OVRD_DRV_LO_PREEMPH_SHIFT;
  359. + data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
  360. + data |= 0x7f;
  361. + data |= TX_OVRD_DRV_LO_EN;
  362. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3->base,
  363. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
  364. + if (ret)
  365. + goto err_phy_trans;
  366. +
  367. + /*
  368. + * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
  369. + * TX_FULL_SWING [26:20] amplitude to 127
  370. + * TX_DEEMPH_3_5DB [13:8] to 22
  371. + * LOS_BIAS [2:0] to 0x5
  372. + */
  373. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
  374. + 0x07f03f07, 0x07f01605);
  375. +
  376. +err_phy_trans:
  377. + return ret;
  378. +}
  379. +
  380. +static int qcom_dwc3_ss_phy_exit(struct qcom_dwc3_usb_phy *phy_dwc3)
  381. +{
  382. + /* Sequence to put SSPHY in low power state:
  383. + * 1. Clear REF_PHY_EN in PHY_CTRL_REG
  384. + * 2. Clear REF_USE_PAD in PHY_CTRL_REG
  385. + * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
  386. + * 4. Disable SSPHY ref clk
  387. + */
  388. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  389. + SSUSB_CTRL_SS_PHY_EN, 0x0);
  390. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  391. + SSUSB_CTRL_REF_USE_PAD, 0x0);
  392. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  393. + 0x0, SSUSB_CTRL_TEST_POWERDOWN);
  394. +
  395. + return 0;
  396. +}
  397. +
  398. +static int qcom_dwc3_phy_init(struct phy *phy)
  399. +{
  400. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  401. +
  402. + if (phy_dwc3->phy_init)
  403. + return phy_dwc3->phy_init(phy_dwc3);
  404. +
  405. + return 0;
  406. +}
  407. +
  408. +static int qcom_dwc3_phy_exit(struct phy *phy)
  409. +{
  410. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  411. +
  412. + if (phy_dwc3->phy_exit)
  413. + return qcom_dwc3_ss_phy_exit(phy_dwc3);
  414. +
  415. + return 0;
  416. +}
  417. +
  418. +static struct phy_ops qcom_dwc3_phy_ops = {
  419. + .init = qcom_dwc3_phy_init,
  420. + .exit = qcom_dwc3_phy_exit,
  421. + .power_on = qcom_dwc3_phy_power_on,
  422. + .power_off = qcom_dwc3_phy_power_off,
  423. + .owner = THIS_MODULE,
  424. +};
  425. +
  426. +static const struct of_device_id qcom_dwc3_phy_table[] = {
  427. + { .compatible = "qcom,dwc3-hs-usb-phy", },
  428. + { .compatible = "qcom,dwc3-ss-usb-phy", },
  429. + { /* Sentinel */ }
  430. +};
  431. +MODULE_DEVICE_TABLE(of, qcom_dwc3_phy_table);
  432. +
  433. +static int qcom_dwc3_phy_probe(struct platform_device *pdev)
  434. +{
  435. + struct qcom_dwc3_usb_phy *phy_dwc3;
  436. + struct phy_provider *phy_provider;
  437. + struct resource *res;
  438. +
  439. + phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
  440. + if (!phy_dwc3)
  441. + return -ENOMEM;
  442. +
  443. + platform_set_drvdata(pdev, phy_dwc3);
  444. +
  445. + phy_dwc3->dev = &pdev->dev;
  446. +
  447. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  448. + phy_dwc3->base = devm_ioremap_resource(phy_dwc3->dev, res);
  449. + if (IS_ERR(phy_dwc3->base))
  450. + return PTR_ERR(phy_dwc3->base);
  451. +
  452. + phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
  453. + if (IS_ERR(phy_dwc3->ref_clk)) {
  454. + dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
  455. + return PTR_ERR(phy_dwc3->ref_clk);
  456. + }
  457. +
  458. + if (of_device_is_compatible(pdev->dev.of_node,
  459. + "qcom,dwc3-hs-usb-phy")) {
  460. + clk_set_rate(phy_dwc3->ref_clk, 60000000);
  461. + phy_dwc3->phy_init = qcom_dwc3_hs_phy_init;
  462. + } else if (of_device_is_compatible(pdev->dev.of_node,
  463. + "qcom,dwc3-ss-usb-phy")) {
  464. + phy_dwc3->phy_init = qcom_dwc3_ss_phy_init;
  465. + phy_dwc3->phy_exit = qcom_dwc3_ss_phy_exit;
  466. + clk_set_rate(phy_dwc3->ref_clk, 125000000);
  467. + } else {
  468. + dev_err(phy_dwc3->dev, "Unknown phy\n");
  469. + return -EINVAL;
  470. + }
  471. +
  472. + phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo");
  473. + if (IS_ERR(phy_dwc3->xo_clk)) {
  474. + dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n");
  475. + phy_dwc3->xo_clk = NULL;
  476. + }
  477. +
  478. + phy_dwc3->phy = devm_phy_create(phy_dwc3->dev, NULL, &qcom_dwc3_phy_ops);
  479. +
  480. + if (IS_ERR(phy_dwc3->phy))
  481. + return PTR_ERR(phy_dwc3->phy);
  482. +
  483. + phy_set_drvdata(phy_dwc3->phy, phy_dwc3);
  484. +
  485. + phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
  486. + of_phy_simple_xlate);
  487. +
  488. + if (IS_ERR(phy_provider))
  489. + return PTR_ERR(phy_provider);
  490. +
  491. + return 0;
  492. +}
  493. +
  494. +static struct platform_driver qcom_dwc3_phy_driver = {
  495. + .probe = qcom_dwc3_phy_probe,
  496. + .driver = {
  497. + .name = "qcom-dwc3-usb-phy",
  498. + .owner = THIS_MODULE,
  499. + .of_match_table = qcom_dwc3_phy_table,
  500. + },
  501. +};
  502. +
  503. +module_platform_driver(qcom_dwc3_phy_driver);
  504. +
  505. +MODULE_ALIAS("platform:phy-qcom-dwc3");
  506. +MODULE_LICENSE("GPL v2");
  507. +MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
  508. +MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
  509. +MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");