0032-phy-add-qcom-dwc3-phy.patch 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. From b9004f4fd23e4c614d71c972f3a9311665480e29 Mon Sep 17 00:00:00 2001
  2. From: Andy Gross <[email protected]>
  3. Date: Thu, 9 Mar 2017 08:19:18 +0100
  4. Subject: [PATCH 32/69] phy: add qcom dwc3 phy
  5. Signed-off-by: Andy Gross <[email protected]>
  6. ---
  7. drivers/phy/Kconfig | 12 +
  8. drivers/phy/Makefile | 1 +
  9. drivers/phy/phy-qcom-dwc3.c | 575 ++++++++++++++++++++++++++++++++++++++++++++
  10. 3 files changed, 588 insertions(+)
  11. create mode 100644 drivers/phy/phy-qcom-dwc3.c
  12. --- a/drivers/phy/Kconfig
  13. +++ b/drivers/phy/Kconfig
  14. @@ -490,4 +490,16 @@ config PHY_NS2_PCIE
  15. help
  16. Enable this to support the Broadcom Northstar2 PCIe PHY.
  17. If unsure, say N.
  18. +
  19. +config PHY_QCOM_DWC3
  20. + tristate "QCOM DWC3 USB PHY support"
  21. + depends on ARCH_QCOM
  22. + depends on HAS_IOMEM
  23. + depends on OF
  24. + select GENERIC_PHY
  25. + help
  26. + This option enables support for the Synopsis PHYs present inside the
  27. + Qualcomm USB3.0 DWC3 controller. This driver supports both HS and SS
  28. + PHY controllers.
  29. +
  30. endmenu
  31. --- a/drivers/phy/Makefile
  32. +++ b/drivers/phy/Makefile
  33. @@ -60,3 +60,4 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-
  34. obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
  35. obj-$(CONFIG_ARCH_TEGRA) += tegra/
  36. obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
  37. +obj-$(CONFIG_PHY_QCOM_DWC3) += phy-qcom-dwc3.o
  38. --- /dev/null
  39. +++ b/drivers/phy/phy-qcom-dwc3.c
  40. @@ -0,0 +1,575 @@
  41. +/* Copyright (c) 2014-2015, Code Aurora Forum. All rights reserved.
  42. + *
  43. + * This program is free software; you can redistribute it and/or modify
  44. + * it under the terms of the GNU General Public License version 2 and
  45. + * only version 2 as published by the Free Software Foundation.
  46. + *
  47. +* This program is distributed in the hope that it will be useful,
  48. +* but WITHOUT ANY WARRANTY; without even the implied warranty of
  49. +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  50. +* GNU General Public License for more details.
  51. +*/
  52. +
  53. +#include <linux/clk.h>
  54. +#include <linux/err.h>
  55. +#include <linux/io.h>
  56. +#include <linux/module.h>
  57. +#include <linux/of.h>
  58. +#include <linux/phy/phy.h>
  59. +#include <linux/platform_device.h>
  60. +#include <linux/delay.h>
  61. +
  62. +/**
  63. + * USB QSCRATCH Hardware registers
  64. + */
  65. +#define QSCRATCH_GENERAL_CFG (0x08)
  66. +#define HSUSB_PHY_CTRL_REG (0x10)
  67. +
  68. +/* PHY_CTRL_REG */
  69. +#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24)
  70. +#define HSUSB_CTRL_USB2_SUSPEND BIT(23)
  71. +#define HSUSB_CTRL_UTMI_CLK_EN BIT(21)
  72. +#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20)
  73. +#define HSUSB_CTRL_USE_CLKCORE BIT(18)
  74. +#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17)
  75. +#define HSUSB_CTRL_COMMONONN BIT(11)
  76. +#define HSUSB_CTRL_ID_HV_CLAMP BIT(9)
  77. +#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8)
  78. +#define HSUSB_CTRL_CLAMP_EN BIT(7)
  79. +#define HSUSB_CTRL_RETENABLEN BIT(1)
  80. +#define HSUSB_CTRL_POR BIT(0)
  81. +
  82. +/* QSCRATCH_GENERAL_CFG */
  83. +#define HSUSB_GCFG_XHCI_REV BIT(2)
  84. +
  85. +/**
  86. + * USB QSCRATCH Hardware registers
  87. + */
  88. +#define SSUSB_PHY_CTRL_REG (0x00)
  89. +#define SSUSB_PHY_PARAM_CTRL_1 (0x04)
  90. +#define SSUSB_PHY_PARAM_CTRL_2 (0x08)
  91. +#define CR_PROTOCOL_DATA_IN_REG (0x0c)
  92. +#define CR_PROTOCOL_DATA_OUT_REG (0x10)
  93. +#define CR_PROTOCOL_CAP_ADDR_REG (0x14)
  94. +#define CR_PROTOCOL_CAP_DATA_REG (0x18)
  95. +#define CR_PROTOCOL_READ_REG (0x1c)
  96. +#define CR_PROTOCOL_WRITE_REG (0x20)
  97. +
  98. +/* PHY_CTRL_REG */
  99. +#define SSUSB_CTRL_REF_USE_PAD BIT(28)
  100. +#define SSUSB_CTRL_TEST_POWERDOWN BIT(27)
  101. +#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24)
  102. +#define SSUSB_CTRL_SS_PHY_EN BIT(8)
  103. +#define SSUSB_CTRL_SS_PHY_RESET BIT(7)
  104. +
  105. +/* SSPHY control registers */
  106. +#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * lane)
  107. +#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * lane)
  108. +
  109. +/* SSPHY SoC version specific values */
  110. +#define SSPHY_RX_EQ_VALUE 4 /* Override value for rx_eq */
  111. +#define SSPHY_TX_DEEMPH_3_5DB 23 /* Override value for transmit
  112. + preemphasis */
  113. +#define SSPHY_MPLL_VALUE 0 /* Override value for mpll */
  114. +
  115. +/* QSCRATCH PHY_PARAM_CTRL1 fields */
  116. +#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK 0x07f00000u
  117. +#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK 0x000fc000u
  118. +#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK 0x00003f00u
  119. +#define PHY_PARAM_CTRL1_LOS_BIAS_MASK 0x000000f8u
  120. +
  121. +#define PHY_PARAM_CTRL1_MASK \
  122. + (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK | \
  123. + PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK | \
  124. + PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \
  125. + PHY_PARAM_CTRL1_LOS_BIAS_MASK)
  126. +
  127. +#define PHY_PARAM_CTRL1_TX_FULL_SWING(x) \
  128. + (((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK)
  129. +#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x) \
  130. + (((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK)
  131. +#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x) \
  132. + (((x) << 8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK)
  133. +#define PHY_PARAM_CTRL1_LOS_BIAS(x) \
  134. + (((x) << 3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK)
  135. +
  136. +/* RX OVRD IN HI bits */
  137. +#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13)
  138. +#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12)
  139. +#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11)
  140. +#define RX_OVRD_IN_HI_RX_EQ_MASK 0x0700
  141. +#define RX_OVRD_IN_HI_RX_EQ_SHIFT 8
  142. +#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7)
  143. +#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6)
  144. +#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5)
  145. +#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK 0x0018
  146. +#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2)
  147. +#define RX_OVRD_IN_HI_RX_RATE_MASK 0x0003
  148. +
  149. +/* TX OVRD DRV LO register bits */
  150. +#define TX_OVRD_DRV_LO_AMPLITUDE_MASK 0x007F
  151. +#define TX_OVRD_DRV_LO_PREEMPH_MASK 0x3F80
  152. +#define TX_OVRD_DRV_LO_PREEMPH_SHIFT 7
  153. +#define TX_OVRD_DRV_LO_EN BIT(14)
  154. +
  155. +/* SS CAP register bits */
  156. +#define SS_CR_CAP_ADDR_REG BIT(0)
  157. +#define SS_CR_CAP_DATA_REG BIT(0)
  158. +#define SS_CR_READ_REG BIT(0)
  159. +#define SS_CR_WRITE_REG BIT(0)
  160. +
  161. +struct qcom_dwc3_usb_phy {
  162. + void __iomem *base;
  163. + struct device *dev;
  164. + struct clk *xo_clk;
  165. + struct clk *ref_clk;
  166. + u32 rx_eq;
  167. + u32 tx_deamp_3_5db;
  168. + u32 mpll;
  169. +};
  170. +
  171. +struct qcom_dwc3_phy_drvdata {
  172. + struct phy_ops ops;
  173. + u32 clk_rate;
  174. +};
  175. +
  176. +/**
  177. + * Write register and read back masked value to confirm it is written
  178. + *
  179. + * @base - QCOM DWC3 PHY base virtual address.
  180. + * @offset - register offset.
  181. + * @mask - register bitmask specifying what should be updated
  182. + * @val - value to write.
  183. + */
  184. +static inline void qcom_dwc3_phy_write_readback(
  185. + struct qcom_dwc3_usb_phy *phy_dwc3, u32 offset,
  186. + const u32 mask, u32 val)
  187. +{
  188. + u32 write_val, tmp = readl(phy_dwc3->base + offset);
  189. +
  190. + tmp &= ~mask; /* retain other bits */
  191. + write_val = tmp | val;
  192. +
  193. + writel(write_val, phy_dwc3->base + offset);
  194. +
  195. + /* Read back to see if val was written */
  196. + tmp = readl(phy_dwc3->base + offset);
  197. + tmp &= mask; /* clear other bits */
  198. +
  199. + if (tmp != val)
  200. + dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n",
  201. + val, offset);
  202. +}
  203. +
  204. +static int wait_for_latch(void __iomem *addr)
  205. +{
  206. + u32 retry = 10;
  207. +
  208. + while (true) {
  209. + if (!readl(addr))
  210. + break;
  211. +
  212. + if (--retry == 0)
  213. + return -ETIMEDOUT;
  214. +
  215. + usleep_range(10, 20);
  216. + }
  217. +
  218. + return 0;
  219. +}
  220. +
  221. +/**
  222. + * Write SSPHY register
  223. + *
  224. + * @base - QCOM DWC3 PHY base virtual address.
  225. + * @addr - SSPHY address to write.
  226. + * @val - value to write.
  227. + */
  228. +static int qcom_dwc3_ss_write_phycreg(struct qcom_dwc3_usb_phy *phy_dwc3,
  229. + u32 addr, u32 val)
  230. +{
  231. + int ret;
  232. +
  233. + writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
  234. + writel(SS_CR_CAP_ADDR_REG, phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
  235. +
  236. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
  237. + if (ret)
  238. + goto err_wait;
  239. +
  240. + writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
  241. + writel(SS_CR_CAP_DATA_REG, phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
  242. +
  243. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
  244. + if (ret)
  245. + goto err_wait;
  246. +
  247. + writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
  248. +
  249. + ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
  250. +
  251. +err_wait:
  252. + if (ret)
  253. + dev_err(phy_dwc3->dev, "timeout waiting for latch\n");
  254. + return ret;
  255. +}
  256. +
  257. +/**
  258. + * Read SSPHY register.
  259. + *
  260. + * @base - QCOM DWC3 PHY base virtual address.
  261. + * @addr - SSPHY address to read.
  262. + */
  263. +static int qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr, u32 *val)
  264. +{
  265. + int ret;
  266. +
  267. + writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
  268. + writel(SS_CR_CAP_ADDR_REG, base + CR_PROTOCOL_CAP_ADDR_REG);
  269. +
  270. + ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG);
  271. + if (ret)
  272. + goto err_wait;
  273. +
  274. + /*
  275. + * Due to hardware bug, first read of SSPHY register might be
  276. + * incorrect. Hence as workaround, SW should perform SSPHY register
  277. + * read twice, but use only second read and ignore first read.
  278. + */
  279. + writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
  280. +
  281. + ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
  282. + if (ret)
  283. + goto err_wait;
  284. +
  285. + /* throwaway read */
  286. + readl(base + CR_PROTOCOL_DATA_OUT_REG);
  287. +
  288. + writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
  289. +
  290. + ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
  291. + if (ret)
  292. + goto err_wait;
  293. +
  294. + *val = readl(base + CR_PROTOCOL_DATA_OUT_REG);
  295. +
  296. +err_wait:
  297. + return ret;
  298. +}
  299. +
  300. +static int qcom_dwc3_hs_phy_init(struct phy *phy)
  301. +{
  302. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  303. + int ret;
  304. + u32 val;
  305. +
  306. + ret = clk_prepare_enable(phy_dwc3->xo_clk);
  307. + if (ret)
  308. + return ret;
  309. +
  310. + ret = clk_prepare_enable(phy_dwc3->ref_clk);
  311. + if (ret) {
  312. + clk_disable_unprepare(phy_dwc3->xo_clk);
  313. + return ret;
  314. + }
  315. +
  316. + /*
  317. + * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
  318. + * enable clamping, and disable RETENTION (power-on default is ENABLED)
  319. + */
  320. + val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
  321. + HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN |
  322. + HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
  323. + HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID |
  324. + HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70;
  325. +
  326. + /* use core clock if external reference is not present */
  327. + if (!phy_dwc3->xo_clk)
  328. + val |= HSUSB_CTRL_USE_CLKCORE;
  329. +
  330. + writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
  331. + usleep_range(2000, 2200);
  332. +
  333. + /* Disable (bypass) VBUS and ID filters */
  334. + writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
  335. +
  336. + return 0;
  337. +}
  338. +
  339. +static int qcom_dwc3_hs_phy_exit(struct phy *phy)
  340. +{
  341. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  342. +
  343. + clk_disable_unprepare(phy_dwc3->ref_clk);
  344. + clk_disable_unprepare(phy_dwc3->xo_clk);
  345. +
  346. + return 0;
  347. +}
  348. +
  349. +static int qcom_dwc3_ss_phy_init(struct phy *phy)
  350. +{
  351. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  352. + int ret;
  353. + u32 data = 0;
  354. +
  355. + ret = clk_prepare_enable(phy_dwc3->xo_clk);
  356. + if (ret)
  357. + return ret;
  358. +
  359. + ret = clk_prepare_enable(phy_dwc3->ref_clk);
  360. + if (ret) {
  361. + clk_disable_unprepare(phy_dwc3->xo_clk);
  362. + return ret;
  363. + }
  364. +
  365. + /* reset phy */
  366. + data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  367. + writel(data | SSUSB_CTRL_SS_PHY_RESET,
  368. + phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  369. + usleep_range(2000, 2200);
  370. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  371. +
  372. + /* clear REF_PAD if we don't have XO clk */
  373. + if (!phy_dwc3->xo_clk)
  374. + data &= ~SSUSB_CTRL_REF_USE_PAD;
  375. + else
  376. + data |= SSUSB_CTRL_REF_USE_PAD;
  377. +
  378. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  379. +
  380. + /* wait for ref clk to become stable, this can take up to 30ms */
  381. + msleep(30);
  382. +
  383. + data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
  384. + writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
  385. +
  386. + /*
  387. + * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
  388. + * in HS mode instead of SS mode. Workaround it by asserting
  389. + * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
  390. + */
  391. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x102D, &data);
  392. + if (ret)
  393. + goto err_phy_trans;
  394. +
  395. + data |= (1 << 7);
  396. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x102D, data);
  397. + if (ret)
  398. + goto err_phy_trans;
  399. +
  400. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x1010, &data);
  401. + if (ret)
  402. + goto err_phy_trans;
  403. +
  404. + data &= ~0xff0;
  405. + data |= 0x20;
  406. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x1010, data);
  407. + if (ret)
  408. + goto err_phy_trans;
  409. +
  410. + /*
  411. + * Fix RX Equalization setting as follows
  412. + * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
  413. + * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
  414. + * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version
  415. + * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
  416. + */
  417. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  418. + SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
  419. + if (ret)
  420. + goto err_phy_trans;
  421. +
  422. + data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
  423. + data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
  424. + data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
  425. + data |= phy_dwc3->rx_eq << RX_OVRD_IN_HI_RX_EQ_SHIFT;
  426. + data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
  427. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
  428. + SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
  429. + if (ret)
  430. + goto err_phy_trans;
  431. +
  432. + /*
  433. + * Set EQ and TX launch amplitudes as follows
  434. + * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version
  435. + * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110
  436. + * LANE0.TX_OVRD_DRV_LO.EN set to 1.
  437. + */
  438. + ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
  439. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
  440. + if (ret)
  441. + goto err_phy_trans;
  442. +
  443. + data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
  444. + data |= phy_dwc3->tx_deamp_3_5db << TX_OVRD_DRV_LO_PREEMPH_SHIFT;
  445. + data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
  446. + data |= 0x6E;
  447. + data |= TX_OVRD_DRV_LO_EN;
  448. + ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
  449. + SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
  450. + if (ret)
  451. + goto err_phy_trans;
  452. +
  453. + qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x30, phy_dwc3->mpll);
  454. +
  455. + /*
  456. + * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
  457. + * TX_FULL_SWING [26:20] amplitude to 110
  458. + * TX_DEEMPH_6DB [19:14] to 32
  459. + * TX_DEEMPH_3_5DB [13:8] set based on SoC version
  460. + * LOS_BIAS [7:3] to 9
  461. + */
  462. + data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1);
  463. +
  464. + data &= ~PHY_PARAM_CTRL1_MASK;
  465. +
  466. + data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) |
  467. + PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) |
  468. + PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) |
  469. + PHY_PARAM_CTRL1_LOS_BIAS(0x9);
  470. +
  471. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
  472. + PHY_PARAM_CTRL1_MASK, data);
  473. +
  474. +err_phy_trans:
  475. + return ret;
  476. +}
  477. +
  478. +static int qcom_dwc3_ss_phy_exit(struct phy *phy)
  479. +{
  480. + struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
  481. +
  482. + /* Sequence to put SSPHY in low power state:
  483. + * 1. Clear REF_PHY_EN in PHY_CTRL_REG
  484. + * 2. Clear REF_USE_PAD in PHY_CTRL_REG
  485. + * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
  486. + */
  487. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  488. + SSUSB_CTRL_SS_PHY_EN, 0x0);
  489. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  490. + SSUSB_CTRL_REF_USE_PAD, 0x0);
  491. + qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
  492. + SSUSB_CTRL_TEST_POWERDOWN, 0x0);
  493. +
  494. + clk_disable_unprepare(phy_dwc3->ref_clk);
  495. + clk_disable_unprepare(phy_dwc3->xo_clk);
  496. +
  497. + return 0;
  498. +}
  499. +
  500. +static const struct qcom_dwc3_phy_drvdata qcom_dwc3_hs_drvdata = {
  501. + .ops = {
  502. + .init = qcom_dwc3_hs_phy_init,
  503. + .exit = qcom_dwc3_hs_phy_exit,
  504. + .owner = THIS_MODULE,
  505. + },
  506. + .clk_rate = 60000000,
  507. +};
  508. +
  509. +static const struct qcom_dwc3_phy_drvdata qcom_dwc3_ss_drvdata = {
  510. + .ops = {
  511. + .init = qcom_dwc3_ss_phy_init,
  512. + .exit = qcom_dwc3_ss_phy_exit,
  513. + .owner = THIS_MODULE,
  514. + },
  515. + .clk_rate = 125000000,
  516. +};
  517. +
  518. +static const struct of_device_id qcom_dwc3_phy_table[] = {
  519. + { .compatible = "qcom,dwc3-hs-usb-phy", .data = &qcom_dwc3_hs_drvdata },
  520. + { .compatible = "qcom,dwc3-ss-usb-phy", .data = &qcom_dwc3_ss_drvdata },
  521. + { /* Sentinel */ }
  522. +};
  523. +MODULE_DEVICE_TABLE(of, qcom_dwc3_phy_table);
  524. +
  525. +static int qcom_dwc3_phy_probe(struct platform_device *pdev)
  526. +{
  527. + struct qcom_dwc3_usb_phy *phy_dwc3;
  528. + struct phy_provider *phy_provider;
  529. + struct phy *generic_phy;
  530. + struct resource *res;
  531. + const struct of_device_id *match;
  532. + const struct qcom_dwc3_phy_drvdata *data;
  533. + struct device_node *np;
  534. +
  535. + phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
  536. + if (!phy_dwc3)
  537. + return -ENOMEM;
  538. +
  539. + match = of_match_node(qcom_dwc3_phy_table, pdev->dev.of_node);
  540. + data = match->data;
  541. +
  542. + phy_dwc3->dev = &pdev->dev;
  543. +
  544. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  545. + phy_dwc3->base = devm_ioremap_resource(phy_dwc3->dev, res);
  546. + if (IS_ERR(phy_dwc3->base))
  547. + return PTR_ERR(phy_dwc3->base);
  548. +
  549. + phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
  550. + if (IS_ERR(phy_dwc3->ref_clk)) {
  551. + dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
  552. + return PTR_ERR(phy_dwc3->ref_clk);
  553. + }
  554. +
  555. + clk_set_rate(phy_dwc3->ref_clk, data->clk_rate);
  556. +
  557. + phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo");
  558. + if (IS_ERR(phy_dwc3->xo_clk)) {
  559. + dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n");
  560. + phy_dwc3->xo_clk = NULL;
  561. + }
  562. +
  563. + /* Parse device node to probe HSIO settings */
  564. + np = of_node_get(pdev->dev.of_node);
  565. + if (!of_compat_cmp(match->compatible, "qcom,dwc3-ss-usb-phy",
  566. + strlen(match->compatible))) {
  567. +
  568. + if (of_property_read_u32(np, "rx_eq", &phy_dwc3->rx_eq) ||
  569. + of_property_read_u32(np, "tx_deamp_3_5db",
  570. + &phy_dwc3->tx_deamp_3_5db) ||
  571. + of_property_read_u32(np, "mpll", &phy_dwc3->mpll)) {
  572. +
  573. + dev_err(phy_dwc3->dev, "cannot get HSIO settings from device node, using default values\n");
  574. +
  575. + /* Default HSIO settings */
  576. + phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE;
  577. + phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB;
  578. + phy_dwc3->mpll = SSPHY_MPLL_VALUE;
  579. + }
  580. + }
  581. +
  582. + generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node,
  583. + &data->ops);
  584. +
  585. + if (IS_ERR(generic_phy))
  586. + return PTR_ERR(generic_phy);
  587. +
  588. + phy_set_drvdata(generic_phy, phy_dwc3);
  589. + platform_set_drvdata(pdev, phy_dwc3);
  590. +
  591. + phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
  592. + of_phy_simple_xlate);
  593. +
  594. + if (IS_ERR(phy_provider))
  595. + return PTR_ERR(phy_provider);
  596. +
  597. + return 0;
  598. +}
  599. +
  600. +static struct platform_driver qcom_dwc3_phy_driver = {
  601. + .probe = qcom_dwc3_phy_probe,
  602. + .driver = {
  603. + .name = "qcom-dwc3-usb-phy",
  604. + .owner = THIS_MODULE,
  605. + .of_match_table = qcom_dwc3_phy_table,
  606. + },
  607. +};
  608. +
  609. +module_platform_driver(qcom_dwc3_phy_driver);
  610. +
  611. +MODULE_ALIAS("platform:phy-qcom-dwc3");
  612. +MODULE_LICENSE("GPL v2");
  613. +MODULE_AUTHOR("Andy Gross <[email protected]>");
  614. +MODULE_AUTHOR("Ivan T. Ivanov <[email protected]>");
  615. +MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");