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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. --- a/drivers/phy/Kconfig
  2. +++ b/drivers/phy/Kconfig
  3. @@ -391,4 +391,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,484 @@
  28. +/* Copyright (c) 2014-2015, 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. +/* SS CAP register bits */
  116. +#define SS_CR_CAP_ADDR_REG BIT(0)
  117. +#define SS_CR_CAP_DATA_REG BIT(0)
  118. +#define SS_CR_READ_REG BIT(0)
  119. +#define SS_CR_WRITE_REG BIT(0)
  120. +
  121. +struct qcom_dwc3_usb_phy {
  122. + void __iomem *base;
  123. + struct device *dev;
  124. + struct clk *xo_clk;
  125. + struct clk *ref_clk;
  126. +};
  127. +
  128. +struct qcom_dwc3_phy_drvdata {
  129. + struct phy_ops ops;
  130. + u32 clk_rate;
  131. +};
  132. +
  133. +/**
  134. + * Write register and read back masked value to confirm it is written
  135. + *
  136. + * @base - QCOM DWC3 PHY base virtual address.
  137. + * @offset - register offset.
  138. + * @mask - register bitmask specifying what should be updated
  139. + * @val - value to write.
  140. + */
  141. +static inline void qcom_dwc3_phy_write_readback(
  142. + struct qcom_dwc3_usb_phy *phy_dwc3, u32 offset,
  143. + const u32 mask, u32 val)
  144. +{
  145. + u32 write_val, tmp = readl(phy_dwc3->base + offset);
  146. +
  147. + tmp &= ~mask; /* retain other bits */
  148. + write_val = tmp | val;
  149. +
  150. + writel(write_val, phy_dwc3->base + offset);
  151. +
  152. + /* Read back to see if val was written */
  153. + tmp = readl(phy_dwc3->base + offset);
  154. + tmp &= mask; /* clear other bits */
  155. +
  156. + if (tmp != val)
  157. + dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n",
  158. + val, offset);
  159. +}
  160. +
  161. +static int wait_for_latch(void __iomem *addr)
  162. +{
  163. + u32 retry = 10;
  164. +
  165. + while (true) {
  166. + if (!readl(addr))
  167. + break;
  168. +
  169. + if (--retry == 0)
  170. + return -ETIMEDOUT;
  171. +
  172. + usleep_range(10, 20);
  173. + }
  174. +
  175. + return 0;
  176. +}
  177. +
  178. +/**
  179. + * Write SSPHY register
  180. + *
  181. + * @base - QCOM DWC3 PHY base virtual address.
  182. + * @addr - SSPHY address to write.
  183. + * @val - value to write.
  184. + */
  185. +static int qcom_dwc3_ss_write_phycreg(struct qcom_dwc3_usb_phy *phy_dwc3,
  186. + u32 addr, u32 val)
  187. +{
  188. + int ret;
  189. +
  190. + writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
  191. + writel(SS_CR_CAP_ADDR_REG, phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
  192. +
  193. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
  194. + if (ret)
  195. + goto err_wait;
  196. +
  197. + writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
  198. + writel(SS_CR_CAP_DATA_REG, phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
  199. +
  200. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
  201. + if (ret)
  202. + goto err_wait;
  203. +
  204. + writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
  205. +
  206. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
  207. +
  208. +err_wait:
  209. + if (ret)
  210. + dev_err(phy_dwc3->dev, "timeout waiting for latch\n");
  211. + return ret;
  212. +}
  213. +
  214. +/**
  215. + * Read SSPHY register.
  216. + *
  217. + * @base - QCOM DWC3 PHY base virtual address.
  218. + * @addr - SSPHY address to read.
  219. + */
  220. +static int qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr, u32 *val)
  221. +{
  222. + int ret;
  223. +
  224. + writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
  225. + writel(SS_CR_CAP_ADDR_REG, base + CR_PROTOCOL_CAP_ADDR_REG);
  226. +
  227. + ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG);
  228. + if (ret)
  229. + goto err_wait;
  230. +
  231. + /*
  232. + * Due to hardware bug, first read of SSPHY register might be
  233. + * incorrect. Hence as workaround, SW should perform SSPHY register
  234. + * read twice, but use only second read and ignore first read.
  235. + */
  236. + writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
  237. +
  238. + ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
  239. + if (ret)
  240. + goto err_wait;
  241. +
  242. + /* throwaway read */
  243. + readl(base + CR_PROTOCOL_DATA_OUT_REG);
  244. +
  245. + writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
  246. +
  247. + ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
  248. + if (ret)
  249. + goto err_wait;
  250. +
  251. + *val = readl(base + CR_PROTOCOL_DATA_OUT_REG);
  252. +
  253. +err_wait:
  254. + return ret;
  255. +}
  256. +
  257. +static int qcom_dwc3_phy_power_on(struct phy *phy)
  258. +{
  259. + int ret;
  260. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  261. +
  262. + ret = clk_prepare_enable(phy_dwc3->xo_clk);
  263. + if (ret)
  264. + return ret;
  265. +
  266. + ret = clk_prepare_enable(phy_dwc3->ref_clk);
  267. + if (ret)
  268. + clk_disable_unprepare(phy_dwc3->xo_clk);
  269. +
  270. + return ret;
  271. +}
  272. +
  273. +static int qcom_dwc3_phy_power_off(struct phy *phy)
  274. +{
  275. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  276. +
  277. + clk_disable_unprepare(phy_dwc3->ref_clk);
  278. + clk_disable_unprepare(phy_dwc3->xo_clk);
  279. +
  280. + return 0;
  281. +}
  282. +
  283. +static int qcom_dwc3_hs_phy_init(struct phy *phy)
  284. +{
  285. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  286. + u32 val;
  287. +
  288. + /*
  289. + * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
  290. + * enable clamping, and disable RETENTION (power-on default is ENABLED)
  291. + */
  292. + val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
  293. + HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN |
  294. + HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
  295. + HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID |
  296. + HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70;
  297. +
  298. + /* use core clock if external reference is not present */
  299. + if (!phy_dwc3->xo_clk)
  300. + val |= HSUSB_CTRL_USE_CLKCORE;
  301. +
  302. + writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
  303. + usleep_range(2000, 2200);
  304. +
  305. + /* Disable (bypass) VBUS and ID filters */
  306. + writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
  307. +
  308. + return 0;
  309. +}
  310. +
  311. +static int qcom_dwc3_ss_phy_init(struct phy *phy)
  312. +{
  313. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  314. + int ret;
  315. + u32 data = 0;
  316. +
  317. + /* reset phy */
  318. + data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  319. + writel(data | SSUSB_CTRL_SS_PHY_RESET,
  320. + phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  321. + usleep_range(2000, 2200);
  322. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  323. +
  324. + /* clear REF_PAD if we don't have XO clk */
  325. + if (!phy_dwc3->xo_clk)
  326. + data &= ~SSUSB_CTRL_REF_USE_PAD;
  327. + else
  328. + data |= SSUSB_CTRL_REF_USE_PAD;
  329. +
  330. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  331. +
  332. + /* wait for ref clk to become stable, this can take up to 30ms */
  333. + msleep(30);
  334. +
  335. + data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
  336. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  337. +
  338. + /*
  339. + * Fix RX Equalization setting as follows
  340. + * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
  341. + * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
  342. + * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
  343. + * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
  344. + */
  345. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  346. + SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
  347. + if (ret)
  348. + goto err_phy_trans;
  349. +
  350. + data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
  351. + data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
  352. + data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
  353. + data |= 0x3 << RX_OVRD_IN_HI_RX_EQ_SHIFT;
  354. + data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
  355. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
  356. + SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
  357. + if (ret)
  358. + goto err_phy_trans;
  359. +
  360. + /*
  361. + * Set EQ and TX launch amplitudes as follows
  362. + * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
  363. + * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
  364. + * LANE0.TX_OVRD_DRV_LO.EN set to 1.
  365. + */
  366. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  367. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
  368. + if (ret)
  369. + goto err_phy_trans;
  370. +
  371. + data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
  372. + data |= 0x16 << TX_OVRD_DRV_LO_PREEMPH_SHIFT;
  373. + data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
  374. + data |= 0x7f;
  375. + data |= TX_OVRD_DRV_LO_EN;
  376. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
  377. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
  378. + if (ret)
  379. + goto err_phy_trans;
  380. +
  381. + /*
  382. + * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
  383. + * TX_FULL_SWING [26:20] amplitude to 127
  384. + * TX_DEEMPH_3_5DB [13:8] to 22
  385. + * LOS_BIAS [2:0] to 0x5
  386. + */
  387. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
  388. + 0x07f03f07, 0x07f01605);
  389. +
  390. +err_phy_trans:
  391. + return ret;
  392. +}
  393. +
  394. +static int qcom_dwc3_ss_phy_exit(struct phy *phy)
  395. +{
  396. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  397. +
  398. + /* Sequence to put SSPHY in low power state:
  399. + * 1. Clear REF_PHY_EN in PHY_CTRL_REG
  400. + * 2. Clear REF_USE_PAD in PHY_CTRL_REG
  401. + * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
  402. + */
  403. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  404. + SSUSB_CTRL_SS_PHY_EN, 0x0);
  405. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  406. + SSUSB_CTRL_REF_USE_PAD, 0x0);
  407. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  408. + 0x0, SSUSB_CTRL_TEST_POWERDOWN);
  409. +
  410. + return 0;
  411. +}
  412. +
  413. +static const struct qcom_dwc3_phy_drvdata qcom_dwc3_hs_drvdata = {
  414. + .ops = {
  415. + .init = qcom_dwc3_hs_phy_init,
  416. + .power_on = qcom_dwc3_phy_power_on,
  417. + .power_off = qcom_dwc3_phy_power_off,
  418. + .owner = THIS_MODULE,
  419. + },
  420. + .clk_rate = 60000000,
  421. +};
  422. +
  423. +static const struct qcom_dwc3_phy_drvdata qcom_dwc3_ss_drvdata = {
  424. + .ops = {
  425. + .init = qcom_dwc3_ss_phy_init,
  426. + .exit = qcom_dwc3_ss_phy_exit,
  427. + .power_on = qcom_dwc3_phy_power_on,
  428. + .power_off = qcom_dwc3_phy_power_off,
  429. + .owner = THIS_MODULE,
  430. + },
  431. + .clk_rate = 125000000,
  432. +};
  433. +
  434. +static const struct of_device_id qcom_dwc3_phy_table[] = {
  435. + { .compatible = "qcom,dwc3-hs-usb-phy", .data = &qcom_dwc3_hs_drvdata },
  436. + { .compatible = "qcom,dwc3-ss-usb-phy", .data = &qcom_dwc3_ss_drvdata },
  437. + { /* Sentinel */ }
  438. +};
  439. +MODULE_DEVICE_TABLE(of, qcom_dwc3_phy_table);
  440. +
  441. +static int qcom_dwc3_phy_probe(struct platform_device *pdev)
  442. +{
  443. + struct qcom_dwc3_usb_phy *phy_dwc3;
  444. + struct phy_provider *phy_provider;
  445. + struct phy *generic_phy;
  446. + struct resource *res;
  447. + const struct of_device_id *match;
  448. + const struct qcom_dwc3_phy_drvdata *data;
  449. +
  450. + phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
  451. + if (!phy_dwc3)
  452. + return -ENOMEM;
  453. +
  454. + match = of_match_node(qcom_dwc3_phy_table, pdev->dev.of_node);
  455. + data = match->data;
  456. +
  457. + phy_dwc3->dev = &pdev->dev;
  458. +
  459. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  460. + phy_dwc3->base = devm_ioremap_resource(phy_dwc3->dev, res);
  461. + if (IS_ERR(phy_dwc3->base))
  462. + return PTR_ERR(phy_dwc3->base);
  463. +
  464. + phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
  465. + if (IS_ERR(phy_dwc3->ref_clk)) {
  466. + dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
  467. + return PTR_ERR(phy_dwc3->ref_clk);
  468. + }
  469. +
  470. + clk_set_rate(phy_dwc3->ref_clk, data->clk_rate);
  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. + generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node,
  479. + &data->ops);
  480. +
  481. + if (IS_ERR(generic_phy))
  482. + return PTR_ERR(generic_phy);
  483. +
  484. + phy_set_drvdata(generic_phy, phy_dwc3);
  485. + platform_set_drvdata(pdev, phy_dwc3);
  486. +
  487. + phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
  488. + of_phy_simple_xlate);
  489. +
  490. + if (IS_ERR(phy_provider))
  491. + return PTR_ERR(phy_provider);
  492. +
  493. + return 0;
  494. +}
  495. +
  496. +static struct platform_driver qcom_dwc3_phy_driver = {
  497. + .probe = qcom_dwc3_phy_probe,
  498. + .driver = {
  499. + .name = "qcom-dwc3-usb-phy",
  500. + .owner = THIS_MODULE,
  501. + .of_match_table = qcom_dwc3_phy_table,
  502. + },
  503. +};
  504. +
  505. +module_platform_driver(qcom_dwc3_phy_driver);
  506. +
  507. +MODULE_ALIAS("platform:phy-qcom-dwc3");
  508. +MODULE_LICENSE("GPL v2");
  509. +MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
  510. +MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
  511. +MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");