kernel: update 3.14 to 3.14.18
[openwrt.git] / target / linux / ipq806x / patches / 0157-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch
1 From d968f8c82db73141c6bc145148642391cb698442 Mon Sep 17 00:00:00 2001
2 From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
3 Date: Mon, 7 Oct 2013 10:44:56 +0300
4 Subject: [PATCH 157/182] usb: phy: Add Qualcomm DWC3 HS/SS PHY drivers
5
6 These drivers handles control and configuration of the HS
7 and SS USB PHY transceivers. They are part of the driver
8 which manage Synopsys DesignWare USB3 controller stack
9 inside Qualcomm SoC's.
10
11 Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
12 ---
13  drivers/usb/phy/Kconfig          |   13 +-
14  drivers/usb/phy/Makefile         |    2 +
15  drivers/usb/phy/phy-qcom-hsusb.c |  340 ++++++++++++++++++++++++++++
16  drivers/usb/phy/phy-qcom-ssusb.c |  455 ++++++++++++++++++++++++++++++++++++++
17  4 files changed, 809 insertions(+), 1 deletion(-)
18  create mode 100644 drivers/usb/phy/phy-qcom-hsusb.c
19  create mode 100644 drivers/usb/phy/phy-qcom-ssusb.c
20
21 --- a/drivers/usb/phy/Kconfig
22 +++ b/drivers/usb/phy/Kconfig
23 @@ -193,7 +193,7 @@ config USB_ISP1301
24  
25  config USB_MSM_OTG
26         tristate "OTG support for Qualcomm on-chip USB controller"
27 -       depends on (USB || USB_GADGET) && ARCH_MSM
28 +       depends on (USB || USB_GADGET) && ARCH_QCOM
29         select USB_PHY
30         help
31           Enable this to support the USB OTG transceiver on MSM chips. It
32 @@ -251,6 +251,17 @@ config USB_RCAR_GEN2_PHY
33           To compile this driver as a module, choose M here: the
34           module will be called phy-rcar-gen2-usb.
35  
36 +config USB_QCOM_DWC3_PHY
37 +       tristate "Qualcomm USB controller DWC3 PHY wrappers support"
38 +       depends on (USB || USB_GADGET) && ARCH_QCOM
39 +       select USB_PHY
40 +       help
41 +         Enable this to support the DWC3 USB PHY transceivers on QCOM chips
42 +         with DWC3 USB core. It handles PHY initialization, clock
43 +         management required after resetting the hardware and power
44 +         management. This driver is required even for peripheral only or
45 +         host only mode configurations.
46 +
47  config USB_ULPI
48         bool "Generic ULPI Transceiver Driver"
49         depends on ARM
50 --- a/drivers/usb/phy/Makefile
51 +++ b/drivers/usb/phy/Makefile
52 @@ -26,6 +26,8 @@ obj-$(CONFIG_USB_EHCI_TEGRA)          += phy-teg
53  obj-$(CONFIG_USB_GPIO_VBUS)            += phy-gpio-vbus-usb.o
54  obj-$(CONFIG_USB_ISP1301)              += phy-isp1301.o
55  obj-$(CONFIG_USB_MSM_OTG)              += phy-msm-usb.o
56 +obj-$(CONFIG_USB_QCOM_DWC3_PHY)                += phy-qcom-hsusb.o
57 +obj-$(CONFIG_USB_QCOM_DWC3_PHY)                += phy-qcom-ssusb.o
58  obj-$(CONFIG_USB_MV_OTG)               += phy-mv-usb.o
59  obj-$(CONFIG_USB_MXS_PHY)              += phy-mxs-usb.o
60  obj-$(CONFIG_USB_RCAR_PHY)             += phy-rcar-usb.o
61 --- /dev/null
62 +++ b/drivers/usb/phy/phy-qcom-hsusb.c
63 @@ -0,0 +1,340 @@
64 +/* Copyright (c) 2013-2014, Code Aurora Forum. All rights reserved.
65 + *
66 + * This program is free software; you can redistribute it and/or modify
67 + * it under the terms of the GNU General Public License version 2 and
68 + * only version 2 as published by the Free Software Foundation.
69 + *
70 + * This program is distributed in the hope that it will be useful,
71 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
72 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
73 + * GNU General Public License for more details.
74 + */
75 +
76 +#include <linux/clk.h>
77 +#include <linux/err.h>
78 +#include <linux/io.h>
79 +#include <linux/module.h>
80 +#include <linux/of.h>
81 +#include <linux/platform_device.h>
82 +#include <linux/regulator/consumer.h>
83 +#include <linux/usb/phy.h>
84 +
85 +/**
86 + *  USB QSCRATCH Hardware registers
87 + */
88 +#define QSCRATCH_CTRL_REG              (0x04)
89 +#define QSCRATCH_GENERAL_CFG           (0x08)
90 +#define PHY_CTRL_REG                   (0x10)
91 +#define PARAMETER_OVERRIDE_X_REG       (0x14)
92 +#define CHARGING_DET_CTRL_REG          (0x18)
93 +#define CHARGING_DET_OUTPUT_REG                (0x1c)
94 +#define ALT_INTERRUPT_EN_REG           (0x20)
95 +#define PHY_IRQ_STAT_REG               (0x24)
96 +#define CGCTL_REG                      (0x28)
97 +
98 +#define PHY_3P3_VOL_MIN                        3050000 /* uV */
99 +#define PHY_3P3_VOL_MAX                        3300000 /* uV */
100 +#define PHY_3P3_HPM_LOAD               16000   /* uA */
101 +
102 +#define PHY_1P8_VOL_MIN                        1800000 /* uV */
103 +#define PHY_1P8_VOL_MAX                        1800000 /* uV */
104 +#define PHY_1P8_HPM_LOAD               19000   /* uA */
105 +
106 +/* TODO: these are suspicious */
107 +#define USB_VDDCX_NO                   1       /* index */
108 +#define USB_VDDCX_MIN                  5       /* index */
109 +#define USB_VDDCX_MAX                  7       /* index */
110 +
111 +struct qcom_dwc3_hs_phy {
112 +       struct usb_phy          phy;
113 +       void __iomem            *base;
114 +       struct device           *dev;
115 +
116 +       struct clk              *xo_clk;
117 +       struct clk              *utmi_clk;
118 +
119 +       struct regulator        *v3p3;
120 +       struct regulator        *v1p8;
121 +       struct regulator        *vddcx;
122 +       struct regulator        *vbus;
123 +};
124 +
125 +#define        phy_to_dw_phy(x)        container_of((x), struct qcom_dwc3_hs_phy, phy)
126 +
127 +
128 +/**
129 + * Write register.
130 + *
131 + * @base - QCOM DWC3 PHY base virtual address.
132 + * @offset - register offset.
133 + * @val - value to write.
134 + */
135 +static inline void qcom_dwc3_hs_write(void __iomem *base, u32 offset, u32 val)
136 +{
137 +       writel(val, base + offset);
138 +}
139 +
140 +/**
141 + * Write register and read back masked value to confirm it is written
142 + *
143 + * @base - QCOM DWC3 PHY base virtual address.
144 + * @offset - register offset.
145 + * @mask - register bitmask specifying what should be updated
146 + * @val - value to write.
147 + */
148 +static inline void qcom_dwc3_hs_write_readback(void __iomem *base, u32 offset,
149 +                                           const u32 mask, u32 val)
150 +{
151 +       u32 write_val, tmp = readl(base + offset);
152 +
153 +       tmp &= ~mask;           /* retain other bits */
154 +       write_val = tmp | val;
155 +
156 +       writel(write_val, base + offset);
157 +
158 +       /* Read back to see if val was written */
159 +       tmp = readl(base + offset);
160 +       tmp &= mask;            /* clear other bits */
161 +
162 +       if (tmp != val)
163 +               pr_err("write: %x to QSCRATCH: %x FAILED\n", val, offset);
164 +}
165 +
166 +static int qcom_dwc3_hs_notify_connect(struct usb_phy *x,
167 +       enum usb_device_speed speed)
168 +{
169 +       struct qcom_dwc3_hs_phy *phy = phy_to_dw_phy(x);
170 +
171 +       dev_err(phy->dev, "notify connect\n");
172 +       return 0;
173 +}
174 +
175 +static int qcom_dwc3_hs_notify_disconnect(struct usb_phy *x,
176 +       enum usb_device_speed speed)
177 +{
178 +       struct qcom_dwc3_hs_phy *phy = phy_to_dw_phy(x);
179 +
180 +       dev_err(phy->dev, "notify disconnect\n");
181 +       return 0;
182 +}
183 +
184 +
185 +static void qcom_dwc3_hs_phy_shutdown(struct usb_phy *x)
186 +{
187 +       struct qcom_dwc3_hs_phy *phy = phy_to_dw_phy(x);
188 +       int ret;
189 +
190 +       ret = regulator_set_voltage(phy->v3p3, 0, PHY_3P3_VOL_MAX);
191 +       if (ret)
192 +               dev_err(phy->dev, "cannot set voltage for v3p3\n");
193 +
194 +       ret = regulator_set_voltage(phy->v1p8, 0, PHY_1P8_VOL_MAX);
195 +       if (ret)
196 +               dev_err(phy->dev, "cannot set voltage for v1p8\n");
197 +
198 +       ret = regulator_disable(phy->v1p8);
199 +       if (ret)
200 +               dev_err(phy->dev, "cannot disable v1p8\n");
201 +
202 +       ret = regulator_disable(phy->v3p3);
203 +       if (ret)
204 +               dev_err(phy->dev, "cannot disable v3p3\n");
205 +
206 +       ret = regulator_set_voltage(phy->vddcx, USB_VDDCX_NO, USB_VDDCX_MAX);
207 +       if (ret)
208 +               dev_err(phy->dev, "cannot set voltage for vddcx\n");
209 +
210 +       ret = regulator_disable(phy->vddcx);
211 +       if (ret)
212 +               dev_err(phy->dev, "cannot enable vddcx\n");
213 +
214 +       clk_disable_unprepare(phy->utmi_clk);
215 +}
216 +
217 +static int qcom_dwc3_hs_phy_init(struct usb_phy *x)
218 +{
219 +       struct qcom_dwc3_hs_phy *phy = phy_to_dw_phy(x);
220 +       int ret;
221 +       u32 val;
222 +
223 +       clk_prepare_enable(phy->utmi_clk);
224 +
225 +       ret = regulator_set_voltage(phy->vddcx, USB_VDDCX_MIN, USB_VDDCX_MAX);
226 +       if (ret)
227 +               dev_err(phy->dev, "cannot set voltage for vddcx\n");
228 +
229 +       ret = regulator_enable(phy->vddcx);
230 +       if (ret)
231 +               dev_err(phy->dev, "cannot enable vddcx\n");
232 +
233 +       ret = regulator_set_voltage(phy->v3p3, PHY_3P3_VOL_MIN,
234 +                                   PHY_3P3_VOL_MAX);
235 +       if (ret)
236 +               dev_err(phy->dev, "cannot set voltage for v3p3\n");
237 +
238 +       ret = regulator_set_voltage(phy->v1p8, PHY_1P8_VOL_MIN,
239 +                                   PHY_1P8_VOL_MAX);
240 +       if (ret)
241 +               dev_err(phy->dev, "cannot set voltage for v1p8\n");
242 +
243 +       ret = regulator_set_optimum_mode(phy->v1p8, PHY_1P8_HPM_LOAD);
244 +       if (ret < 0)
245 +               dev_err(phy->dev, "cannot set HPM of regulator v1p8\n");
246 +
247 +       ret = regulator_enable(phy->v1p8);
248 +       if (ret)
249 +               dev_err(phy->dev, "cannot enable v1p8\n");
250 +
251 +       ret = regulator_set_optimum_mode(phy->v3p3, PHY_3P3_HPM_LOAD);
252 +       if (ret < 0)
253 +               dev_err(phy->dev, "cannot set HPM of regulator v3p3\n");
254 +
255 +       ret = regulator_enable(phy->v3p3);
256 +       if (ret)
257 +               dev_err(phy->dev, "cannot enable v3p3\n");
258 +
259 +       /*
260 +        * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
261 +        * and disable RETENTION (power-on default is ENABLED)
262 +        */
263 +       val = readl(phy->base + PHY_CTRL_REG);
264 +       val |= BIT(18) | BIT(20) | BIT(11) | 0x70;
265 +       qcom_dwc3_hs_write(phy->base, PHY_CTRL_REG, val);
266 +       usleep_range(2000, 2200);
267 +
268 +       /*
269 +        * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
270 +        * VBUS valid threshold, disconnect valid threshold, DC voltage level,
271 +        * preempasis and rise/fall time.
272 +        */
273 +       qcom_dwc3_hs_write_readback(phy->base, PARAMETER_OVERRIDE_X_REG,
274 +                               0x03ffffff, 0x00d191a4);
275 +
276 +       /* Disable (bypass) VBUS and ID filters */
277 +       qcom_dwc3_hs_write(phy->base, QSCRATCH_GENERAL_CFG, BIT(2));
278 +
279 +       return 0;
280 +}
281 +
282 +static int qcom_dwc3_hs_phy_set_vbus(struct usb_phy *x, int on)
283 +{
284 +       struct qcom_dwc3_hs_phy *phy = phy_to_dw_phy(x);
285 +       int ret = 0;
286 +
287 +       if (IS_ERR(phy->vbus))
288 +               return on ? PTR_ERR(phy->vbus) : 0;
289 +
290 +       if (on)
291 +               ret = regulator_enable(phy->vbus);
292 +       else
293 +               ret = regulator_disable(phy->vbus);
294 +
295 +       if (ret)
296 +               dev_err(x->dev, "Cannot %s Vbus\n", on ? "set" : "off");
297 +       return ret;
298 +}
299 +
300 +static int qcom_dwc3_hs_probe(struct platform_device *pdev)
301 +{
302 +       struct qcom_dwc3_hs_phy *phy;
303 +       struct resource         *res;
304 +       void __iomem            *base;
305 +
306 +       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
307 +       if (!phy)
308 +               return -ENOMEM;
309 +
310 +       platform_set_drvdata(pdev, phy);
311 +
312 +       phy->dev = &pdev->dev;
313 +
314 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
315 +       base = devm_ioremap_resource(phy->dev, res);
316 +       if (IS_ERR(base))
317 +               return PTR_ERR(base);
318 +
319 +       phy->vddcx = devm_regulator_get(phy->dev, "vddcx");
320 +       if (IS_ERR(phy->vddcx)) {
321 +               dev_dbg(phy->dev, "cannot get vddcx\n");
322 +               return  PTR_ERR(phy->vddcx);
323 +       }
324 +
325 +       phy->v3p3 = devm_regulator_get(phy->dev, "v3p3");
326 +       if (IS_ERR(phy->v3p3)) {
327 +               dev_dbg(phy->dev, "cannot get v3p3\n");
328 +               return PTR_ERR(phy->v3p3);
329 +       }
330 +
331 +       phy->v1p8 = devm_regulator_get(phy->dev, "v1p8");
332 +       if (IS_ERR(phy->v1p8)) {
333 +               dev_dbg(phy->dev, "cannot get v1p8\n");
334 +               return PTR_ERR(phy->v1p8);
335 +       }
336 +
337 +       phy->vbus = devm_regulator_get(phy->dev, "vbus");
338 +       if (IS_ERR(phy->vbus))
339 +               dev_dbg(phy->dev, "Failed to get vbus\n");
340 +
341 +       phy->utmi_clk = devm_clk_get(phy->dev, "utmi");
342 +       if (IS_ERR(phy->utmi_clk)) {
343 +               dev_dbg(phy->dev, "cannot get UTMI handle\n");
344 +               return PTR_ERR(phy->utmi_clk);
345 +       }
346 +
347 +       phy->xo_clk = devm_clk_get(phy->dev, "xo");
348 +       if (IS_ERR(phy->xo_clk)) {
349 +               dev_dbg(phy->dev, "cannot get TCXO buffer handle\n");
350 +               phy->xo_clk = NULL;
351 +       }
352 +
353 +       clk_set_rate(phy->utmi_clk, 60000000);
354 +
355 +       if (phy->xo_clk)
356 +               clk_prepare_enable(phy->xo_clk);
357 +
358 +       phy->base               = base;
359 +       phy->phy.dev            = phy->dev;
360 +       phy->phy.label          = "qcom-dwc3-hsphy";
361 +       phy->phy.init           = qcom_dwc3_hs_phy_init;
362 +       phy->phy.notify_connect = qcom_dwc3_hs_notify_connect;
363 +       phy->phy.notify_disconnect = qcom_dwc3_hs_notify_disconnect;
364 +       phy->phy.shutdown       = qcom_dwc3_hs_phy_shutdown;
365 +       phy->phy.set_vbus       = qcom_dwc3_hs_phy_set_vbus;
366 +       phy->phy.type           = USB_PHY_TYPE_USB2;
367 +       phy->phy.state          = OTG_STATE_UNDEFINED;
368 +
369 +       usb_add_phy_dev(&phy->phy);
370 +       return 0;
371 +}
372 +
373 +static int qcom_dwc3_hs_remove(struct platform_device *pdev)
374 +{
375 +       struct qcom_dwc3_hs_phy *phy = platform_get_drvdata(pdev);
376 +
377 +       if (phy->xo_clk)
378 +               clk_disable_unprepare(phy->xo_clk);
379 +       usb_remove_phy(&phy->phy);
380 +       return 0;
381 +}
382 +
383 +static const struct of_device_id qcom_dwc3_hs_id_table[] = {
384 +       { .compatible = "qcom,dwc3-hsphy" },
385 +       { /* Sentinel */ }
386 +};
387 +MODULE_DEVICE_TABLE(of, qcom_dwc3_hs_id_table);
388 +
389 +static struct platform_driver qcom_dwc3_hs_driver = {
390 +       .probe          = qcom_dwc3_hs_probe,
391 +       .remove         = qcom_dwc3_hs_remove,
392 +       .driver         = {
393 +               .name   = "qcom-dwc3-hsphy",
394 +               .owner  = THIS_MODULE,
395 +               .of_match_table = qcom_dwc3_hs_id_table,
396 +       },
397 +};
398 +
399 +module_platform_driver(qcom_dwc3_hs_driver);
400 +
401 +MODULE_ALIAS("platform:qcom-dwc3-hsphy");
402 +MODULE_LICENSE("GPL v2");
403 +MODULE_DESCRIPTION("DesignWare USB3 QCOM HSPHY driver");
404 --- /dev/null
405 +++ b/drivers/usb/phy/phy-qcom-ssusb.c
406 @@ -0,0 +1,455 @@
407 +/* Copyright (c) 2013-2014, Code Aurora Forum. All rights reserved.
408 + *
409 + * This program is free software; you can redistribute it and/or modify
410 + * it under the terms of the GNU General Public License version 2 and
411 + * only version 2 as published by the Free Software Foundation.
412 + *
413 + * This program is distributed in the hope that it will be useful,
414 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
415 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
416 + * GNU General Public License for more details.
417 + */
418 +
419 +#include <linux/clk.h>
420 +#include <linux/err.h>
421 +#include <linux/io.h>
422 +#include <linux/module.h>
423 +#include <linux/of.h>
424 +#include <linux/platform_device.h>
425 +#include <linux/regulator/consumer.h>
426 +#include <linux/usb/phy.h>
427 +
428 +/**
429 + *  USB QSCRATCH Hardware registers
430 + */
431 +#define PHY_CTRL_REG                   (0x00)
432 +#define PHY_PARAM_CTRL_1               (0x04)
433 +#define PHY_PARAM_CTRL_2               (0x08)
434 +#define CR_PROTOCOL_DATA_IN_REG                (0x0c)
435 +#define CR_PROTOCOL_DATA_OUT_REG       (0x10)
436 +#define CR_PROTOCOL_CAP_ADDR_REG       (0x14)
437 +#define CR_PROTOCOL_CAP_DATA_REG       (0x18)
438 +#define CR_PROTOCOL_READ_REG           (0x1c)
439 +#define CR_PROTOCOL_WRITE_REG          (0x20)
440 +
441 +#define PHY_1P8_VOL_MIN                        1800000 /* uV */
442 +#define PHY_1P8_VOL_MAX                        1800000 /* uV */
443 +#define PHY_1P8_HPM_LOAD               23000   /* uA */
444 +
445 +/* TODO: these are suspicious */
446 +#define USB_VDDCX_NO                   1       /* index */
447 +#define USB_VDDCX_MIN                  5       /* index */
448 +#define USB_VDDCX_MAX                  7       /* index */
449 +
450 +struct qcom_dwc3_ss_phy {
451 +       struct usb_phy          phy;
452 +       void __iomem            *base;
453 +       struct device           *dev;
454 +
455 +       struct regulator        *v1p8;
456 +       struct regulator        *vddcx;
457 +
458 +       struct clk              *xo_clk;
459 +       struct clk              *ref_clk;
460 +};
461 +
462 +#define        phy_to_dw_phy(x)        container_of((x), struct qcom_dwc3_ss_phy, phy)
463 +
464 +
465 +/**
466 + * Write register
467 + *
468 + * @base - QCOM DWC3 PHY base virtual address.
469 + * @offset - register offset.
470 + * @val - value to write.
471 + */
472 +static inline void qcom_dwc3_ss_write(void __iomem *base, u32 offset, u32 val)
473 +{
474 +       writel(val, base + offset);
475 +}
476 +
477 +/**
478 + * Write register and read back masked value to confirm it is written
479 + *
480 + * @base - QCOM DWC3 PHY base virtual address.
481 + * @offset - register offset.
482 + * @mask - register bitmask specifying what should be updated
483 + * @val - value to write.
484 + */
485 +static inline void qcom_dwc3_ss_write_readback(void __iomem *base, u32 offset,
486 +                                           const u32 mask, u32 val)
487 +{
488 +       u32 write_val, tmp = readl(base + offset);
489 +
490 +       tmp &= ~mask;           /* retain other bits */
491 +       write_val = tmp | val;
492 +
493 +       writel(write_val, base + offset);
494 +
495 +       /* Read back to see if val was written */
496 +       tmp = readl(base + offset);
497 +       tmp &= mask;            /* clear other bits */
498 +
499 +       if (tmp != val)
500 +               pr_err("write: %x to QSCRATCH: %x FAILED\n", val, offset);
501 +}
502 +
503 +/**
504 + * Write SSPHY register
505 + *
506 + * @base - QCOM DWC3 PHY base virtual address.
507 + * @addr - SSPHY address to write.
508 + * @val - value to write.
509 + */
510 +static void qcom_dwc3_ss_write_phycreg(void __iomem *base, u32 addr, u32 val)
511 +{
512 +       writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
513 +       writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG);
514 +       while (readl(base + CR_PROTOCOL_CAP_ADDR_REG))
515 +               cpu_relax();
516 +
517 +       writel(val, base + CR_PROTOCOL_DATA_IN_REG);
518 +       writel(0x1, base + CR_PROTOCOL_CAP_DATA_REG);
519 +       while (readl(base + CR_PROTOCOL_CAP_DATA_REG))
520 +               cpu_relax();
521 +
522 +       writel(0x1, base + CR_PROTOCOL_WRITE_REG);
523 +       while (readl(base + CR_PROTOCOL_WRITE_REG))
524 +               cpu_relax();
525 +}
526 +
527 +/**
528 + * Read SSPHY register.
529 + *
530 + * @base - QCOM DWC3 PHY base virtual address.
531 + * @addr - SSPHY address to read.
532 + */
533 +static u32 qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr)
534 +{
535 +       bool first_read = true;
536 +
537 +       writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
538 +       writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG);
539 +       while (readl(base + CR_PROTOCOL_CAP_ADDR_REG))
540 +               cpu_relax();
541 +
542 +       /*
543 +        * Due to hardware bug, first read of SSPHY register might be
544 +        * incorrect. Hence as workaround, SW should perform SSPHY register
545 +        * read twice, but use only second read and ignore first read.
546 +        */
547 +retry:
548 +       writel(0x1, base + CR_PROTOCOL_READ_REG);
549 +       while (readl(base + CR_PROTOCOL_READ_REG))
550 +               cpu_relax();
551 +
552 +       if (first_read) {
553 +               readl(base + CR_PROTOCOL_DATA_OUT_REG);
554 +               first_read = false;
555 +               goto retry;
556 +       }
557 +
558 +       return readl(base + CR_PROTOCOL_DATA_OUT_REG);
559 +}
560 +
561 +static void qcom_dwc3_ss_phy_shutdown(struct usb_phy *x)
562 +{
563 +       struct qcom_dwc3_ss_phy *phy = phy_to_dw_phy(x);
564 +       int ret;
565 +
566 +       /* Sequence to put SSPHY in low power state:
567 +        * 1. Clear REF_PHY_EN in PHY_CTRL_REG
568 +        * 2. Clear REF_USE_PAD in PHY_CTRL_REG
569 +        * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
570 +        * 4. Disable SSPHY ref clk
571 +        */
572 +       qcom_dwc3_ss_write_readback(phy->base, PHY_CTRL_REG, (1 << 8), 0x0);
573 +       qcom_dwc3_ss_write_readback(phy->base, PHY_CTRL_REG, (1 << 28), 0x0);
574 +       qcom_dwc3_ss_write_readback(phy->base, PHY_CTRL_REG,
575 +                                   (1 << 26), (1 << 26));
576 +
577 +       usleep_range(1000, 1200);
578 +       clk_disable_unprepare(phy->ref_clk);
579 +
580 +       ret = regulator_set_voltage(phy->vddcx, USB_VDDCX_NO, USB_VDDCX_MAX);
581 +       if (ret)
582 +               dev_err(phy->dev, "cannot set voltage for vddcx\n");
583 +
584 +       regulator_disable(phy->vddcx);
585 +
586 +       ret = regulator_set_voltage(phy->v1p8, 0, PHY_1P8_VOL_MAX);
587 +       if (ret)
588 +               dev_err(phy->dev, "cannot set v1p8\n");
589 +
590 +       regulator_disable(phy->v1p8);
591 +}
592 +
593 +static int qcom_dwc3_ss_phy_init(struct usb_phy *x)
594 +{
595 +       struct qcom_dwc3_ss_phy *phy = phy_to_dw_phy(x);
596 +       u32 data = 0;
597 +       int ret;
598 +
599 +       ret = regulator_set_voltage(phy->vddcx, USB_VDDCX_MIN, USB_VDDCX_MAX);
600 +       if (ret) {
601 +               dev_err(phy->dev, "cannot set voltage for vddcx\n");
602 +               return ret;
603 +       }
604 +
605 +       ret = regulator_enable(phy->vddcx);
606 +       if (ret) {
607 +               dev_err(phy->dev, "cannot enable vddcx\n");
608 +               return ret;
609 +       }
610 +
611 +       ret = regulator_set_voltage(phy->v1p8, PHY_1P8_VOL_MIN,
612 +                                   PHY_1P8_VOL_MAX);
613 +       if (ret) {
614 +               regulator_disable(phy->vddcx);
615 +               dev_err(phy->dev, "cannot set v1p8\n");
616 +               return ret;
617 +       }
618 +
619 +       ret = regulator_enable(phy->v1p8);
620 +       if (ret) {
621 +               regulator_disable(phy->vddcx);
622 +               dev_err(phy->dev, "cannot enable v1p8\n");
623 +               return ret;
624 +       }
625 +
626 +       clk_prepare_enable(phy->ref_clk);
627 +       usleep_range(1000, 1200);
628 +
629 +       /* reset phy */
630 +       data = readl_relaxed(phy->base + PHY_CTRL_REG);
631 +       writel_relaxed(data | BIT(7), phy->base + PHY_CTRL_REG);
632 +       usleep_range(2000, 2200);
633 +       writel_relaxed(data, phy->base + PHY_CTRL_REG);
634 +
635 +       /* clear REF_PAD, we don't have XO clk */
636 +       data &= ~BIT(28);
637 +       writel_relaxed(data, phy->base + PHY_CTRL_REG);
638 +       msleep(30);
639 +
640 +       data |= BIT(8) | BIT(24);
641 +       writel_relaxed(data, phy->base + PHY_CTRL_REG);
642 +
643 +       /*
644 +        * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
645 +        * in HS mode instead of SS mode. Workaround it by asserting
646 +        * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
647 +        */
648 +       data = qcom_dwc3_ss_read_phycreg(phy->base, 0x102d);
649 +       data |= (1 << 7);
650 +       qcom_dwc3_ss_write_phycreg(phy->base, 0x102D, data);
651 +
652 +       data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1010);
653 +       data &= ~0xff0;
654 +       data |= 0x20;
655 +       qcom_dwc3_ss_write_phycreg(phy->base, 0x1010, data);
656 +
657 +       /*
658 +        * Fix RX Equalization setting as follows
659 +        * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
660 +        * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
661 +        * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
662 +        * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
663 +        */
664 +       data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1006);
665 +       data &= ~(1 << 6);
666 +       data |= (1 << 7);
667 +       data &= ~(0x7 << 8);
668 +       data |= (0x3 << 8);
669 +       data |= (0x1 << 11);
670 +       qcom_dwc3_ss_write_phycreg(phy->base, 0x1006, data);
671 +
672 +       /*
673 +        * Set EQ and TX launch amplitudes as follows
674 +        * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
675 +        * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
676 +        * LANE0.TX_OVRD_DRV_LO.EN set to 1.
677 +        */
678 +       data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1002);
679 +       data &= ~0x3f80;
680 +       data |= (0x16 << 7);
681 +       data &= ~0x7f;
682 +       data |= (0x7f | (1 << 14));
683 +       qcom_dwc3_ss_write_phycreg(phy->base, 0x1002, data);
684 +
685 +       /*
686 +        * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
687 +        * TX_FULL_SWING [26:20] amplitude to 127
688 +        * TX_DEEMPH_3_5DB [13:8] to 22
689 +        * LOS_BIAS [2:0] to 0x5
690 +        */
691 +       qcom_dwc3_ss_write_readback(phy->base, PHY_PARAM_CTRL_1,
692 +                                  0x07f03f07, 0x07f01605);
693 +       return 0;
694 +}
695 +
696 +static int qcom_dwc3_ss_set_suspend(struct usb_phy *x, int suspend)
697 +{
698 +       struct qcom_dwc3_ss_phy *phy = phy_to_dw_phy(x);
699 +       u32 data;
700 +
701 +       if (!suspend) {
702 +               /* reset phy */
703 +               data = readl_relaxed(phy->base + PHY_CTRL_REG);
704 +               writel_relaxed(data | BIT(7), phy->base + PHY_CTRL_REG);
705 +               usleep_range(2000, 2200);
706 +               writel_relaxed(data, phy->base + PHY_CTRL_REG);
707 +
708 +               /* clear REF_PAD, we don't have XO clk */
709 +               data &= ~BIT(28);
710 +               writel_relaxed(data, phy->base + PHY_CTRL_REG);
711 +               msleep(30);
712 +
713 +               data |= BIT(8) | BIT(24);
714 +               writel_relaxed(data, phy->base + PHY_CTRL_REG);
715 +
716 +               /*
717 +                * WORKAROUND: There is SSPHY suspend bug due to which USB
718 +                * enumerates in HS mode instead of SS mode. Workaround it by
719 +                * asserting LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use
720 +                * alt bus mode
721 +                */
722 +               data = qcom_dwc3_ss_read_phycreg(phy->base, 0x102d);
723 +               data |= (1 << 7);
724 +               qcom_dwc3_ss_write_phycreg(phy->base, 0x102D, data);
725 +
726 +               data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1010);
727 +               data &= ~0xff0;
728 +               data |= 0x20;
729 +               qcom_dwc3_ss_write_phycreg(phy->base, 0x1010, data);
730 +
731 +               /*
732 +                * Fix RX Equalization setting as follows
733 +                * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
734 +                * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
735 +                * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
736 +                * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
737 +                */
738 +               data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1006);
739 +               data &= ~(1 << 6);
740 +               data |= (1 << 7);
741 +               data &= ~(0x7 << 8);
742 +               data |= (0x3 << 8);
743 +               data |= (0x1 << 11);
744 +               qcom_dwc3_ss_write_phycreg(phy->base, 0x1006, data);
745 +
746 +               /*
747 +                * Set EQ and TX launch amplitudes as follows
748 +                * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
749 +                * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
750 +                * LANE0.TX_OVRD_DRV_LO.EN set to 1.
751 +                */
752 +               data = qcom_dwc3_ss_read_phycreg(phy->base, 0x1002);
753 +               data &= ~0x3f80;
754 +               data |= (0x16 << 7);
755 +               data &= ~0x7f;
756 +               data |= (0x7f | (1 << 14));
757 +               qcom_dwc3_ss_write_phycreg(phy->base, 0x1002, data);
758 +
759 +               /*
760 +                * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
761 +                * TX_FULL_SWING [26:20] amplitude to 127
762 +                * TX_DEEMPH_3_5DB [13:8] to 22
763 +                * LOS_BIAS [2:0] to 0x5
764 +                */
765 +               qcom_dwc3_ss_write_readback(phy->base, PHY_PARAM_CTRL_1,
766 +                                          0x07f03f07, 0x07f01605);
767 +       }
768 +       return 0;
769 +}
770 +
771 +static int qcom_dwc3_ss_probe(struct platform_device *pdev)
772 +{
773 +       struct qcom_dwc3_ss_phy *phy;
774 +       struct resource         *res;
775 +       void __iomem            *base;
776 +       int ret;
777 +
778 +       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
779 +       if (!phy)
780 +               return -ENOMEM;
781 +
782 +       platform_set_drvdata(pdev, phy);
783 +
784 +       phy->dev = &pdev->dev;
785 +
786 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
787 +       base = devm_ioremap_resource(phy->dev, res);
788 +       if (IS_ERR(base))
789 +               return PTR_ERR(base);
790 +
791 +       phy->vddcx = devm_regulator_get(phy->dev, "vddcx");
792 +       if (IS_ERR(phy->vddcx)) {
793 +               dev_dbg(phy->dev, "cannot get vddcx\n");
794 +               return  PTR_ERR(phy->vddcx);
795 +       }
796 +
797 +       phy->v1p8 = devm_regulator_get(phy->dev, "v1p8");
798 +       if (IS_ERR(phy->v1p8)) {
799 +               dev_dbg(phy->dev, "cannot get v1p8\n");
800 +               return  PTR_ERR(phy->v1p8);
801 +       }
802 +
803 +       phy->xo_clk = devm_clk_get(phy->dev, "xo");
804 +       if (IS_ERR(phy->xo_clk)) {
805 +               dev_dbg(phy->dev, "cannot get XO clk, assuming not present\n");
806 +               phy->xo_clk = NULL;
807 +       }
808 +
809 +       phy->ref_clk = devm_clk_get(phy->dev, "ref");
810 +       if (IS_ERR(phy->ref_clk)) {
811 +               dev_dbg(phy->dev, "cannot get ref clock handle\n");
812 +               return PTR_ERR(phy->ref_clk);
813 +       }
814 +
815 +       clk_set_rate(phy->ref_clk, 125000000);
816 +       if (phy->xo_clk)
817 +               clk_prepare_enable(phy->xo_clk);
818 +
819 +       phy->base               = base;
820 +       phy->phy.dev            = phy->dev;
821 +       phy->phy.label          = "qcom-dwc3-ssphy";
822 +       phy->phy.init           = qcom_dwc3_ss_phy_init;
823 +       phy->phy.shutdown       = qcom_dwc3_ss_phy_shutdown;
824 +       phy->phy.set_suspend    = qcom_dwc3_ss_set_suspend;
825 +       phy->phy.type           = USB_PHY_TYPE_USB3;
826 +
827 +       ret = usb_add_phy_dev(&phy->phy);
828 +       return ret;
829 +}
830 +
831 +static int qcom_dwc3_ss_remove(struct platform_device *pdev)
832 +{
833 +       struct qcom_dwc3_ss_phy *phy = platform_get_drvdata(pdev);
834 +
835 +       if (phy->xo_clk)
836 +               clk_disable_unprepare(phy->xo_clk);
837 +       usb_remove_phy(&phy->phy);
838 +       return 0;
839 +}
840 +
841 +static const struct of_device_id qcom_dwc3_ss_id_table[] = {
842 +       { .compatible = "qcom,dwc3-ssphy" },
843 +       { /* Sentinel */ }
844 +};
845 +MODULE_DEVICE_TABLE(of, qcom_dwc3_ss_id_table);
846 +
847 +static struct platform_driver qcom_dwc3_ss_driver = {
848 +       .probe          = qcom_dwc3_ss_probe,
849 +       .remove         = qcom_dwc3_ss_remove,
850 +       .driver         = {
851 +               .name   = "qcom-dwc3-ssphy",
852 +               .owner  = THIS_MODULE,
853 +               .of_match_table = qcom_dwc3_ss_id_table,
854 +       },
855 +};
856 +
857 +module_platform_driver(qcom_dwc3_ss_driver);
858 +
859 +MODULE_ALIAS("platform:qcom-dwc3-ssphy");
860 +MODULE_LICENSE("GPL v2");
861 +MODULE_DESCRIPTION("DesignWare USB3 QCOM SSPHY driver");