blob: ad3bbf7d7790e8782ca5db84e7ca18c770458136 [file] [log] [blame]
Mayank Rana3cb43a32016-08-02 12:10:20 -07001/*
Hemant Kumar84c6b592018-01-31 14:02:12 -08002 * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Mayank Rana3cb43a32016-08-02 12:10:20 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/slab.h>
19#include <linux/io.h>
20#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/platform_device.h>
23#include <linux/regulator/consumer.h>
24#include <linux/usb/phy.h>
Mayank Rana3cb43a32016-08-02 12:10:20 -070025#include <linux/clk.h>
Amit Nischal4d278212016-06-06 17:54:34 +053026#include <linux/reset.h>
Mayank Rana3cb43a32016-08-02 12:10:20 -070027
28enum core_ldo_levels {
29 CORE_LEVEL_NONE = 0,
30 CORE_LEVEL_MIN,
31 CORE_LEVEL_MAX,
32};
33
34#define INIT_MAX_TIME_USEC 1000
35
36/* default CORE votlage and load values */
37#define USB_SSPHY_1P2_VOL_MIN 1200000 /* uV */
38#define USB_SSPHY_1P2_VOL_MAX 1200000 /* uV */
39#define USB_SSPHY_HPM_LOAD 23000 /* uA */
40
41/* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */
42#define PHYSTATUS BIT(6)
43
44/* PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL bits */
45#define ARCVR_DTCT_EN BIT(0)
46#define ALFPS_DTCT_EN BIT(1)
47#define ARCVR_DTCT_EVENT_SEL BIT(4)
48
Mayank Rana4c40cd92017-03-21 14:40:55 -070049/*
50 * register bits
51 * PCIE_USB3_PHY_PCS_MISC_TYPEC_CTRL - for QMP USB PHY
52 * USB3_DP_COM_PHY_MODE_CTRL - for QMP USB DP Combo PHY
53 */
Mayank Rana3cb43a32016-08-02 12:10:20 -070054
55/* 0 - selects Lane A. 1 - selects Lane B */
56#define SW_PORTSELECT BIT(0)
57/* port select mux: 1 - sw control. 0 - HW control*/
58#define SW_PORTSELECT_MX BIT(1)
59
Mayank Rana4c40cd92017-03-21 14:40:55 -070060/* USB3_DP_PHY_USB3_DP_COM_SWI_CTRL bits */
61
62/* LANE related register read/write with USB3 */
63#define USB3_SWI_ACT_ACCESS_EN BIT(0)
64/* LANE related register read/write with DP */
65#define DP_SWI_ACT_ACCESS_EN BIT(1)
66
67/* USB3_DP_COM_RESET_OVRD_CTRL bits */
68
69/* DP PHY soft reset */
70#define SW_DPPHY_RESET BIT(0)
71/* mux to select DP PHY reset control, 0:HW control, 1: software reset */
72#define SW_DPPHY_RESET_MUX BIT(1)
73/* USB3 PHY soft reset */
74#define SW_USB3PHY_RESET BIT(2)
75/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
76#define SW_USB3PHY_RESET_MUX BIT(3)
77
78/* USB3_DP_COM_PHY_MODE_CTRL bits */
79#define USB3_MODE BIT(0) /* enables USB3 mode */
80#define DP_MODE BIT(1) /* enables DP mode */
81
Mayank Rana3cb43a32016-08-02 12:10:20 -070082enum qmp_phy_rev_reg {
83 USB3_PHY_PCS_STATUS,
84 USB3_PHY_AUTONOMOUS_MODE_CTRL,
85 USB3_PHY_LFPS_RXTERM_IRQ_CLEAR,
86 USB3_PHY_POWER_DOWN_CONTROL,
87 USB3_PHY_SW_RESET,
88 USB3_PHY_START,
Mayank Rana4c40cd92017-03-21 14:40:55 -070089
90 /* USB DP Combo PHY related */
91 USB3_DP_DP_PHY_PD_CTL,
92 USB3_DP_COM_POWER_DOWN_CTRL,
93 USB3_DP_COM_SW_RESET,
94 USB3_DP_COM_RESET_OVRD_CTRL,
95 USB3_DP_COM_PHY_MODE_CTRL,
96 USB3_DP_COM_TYPEC_CTRL,
97 USB3_DP_COM_SWI_CTRL,
98 USB3_PCS_MISC_CLAMP_ENABLE,
99 /* TypeC port select configuration (optional) */
Mayank Rana3cb43a32016-08-02 12:10:20 -0700100 USB3_PHY_PCS_MISC_TYPEC_CTRL,
101 USB3_PHY_REG_MAX,
102};
103
104/* reg values to write */
105struct qmp_reg_val {
106 u32 offset;
107 u32 val;
108 u32 delay;
109};
110
111struct msm_ssphy_qmp {
112 struct usb_phy phy;
113 void __iomem *base;
114 void __iomem *vls_clamp_reg;
Hemant Kumar84c6b592018-01-31 14:02:12 -0800115 void __iomem *pcs_clamp_enable_reg;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700116 void __iomem *tcsr_usb3_dp_phymode;
117
118 struct regulator *vdd;
119 int vdd_levels[3]; /* none, low, high */
120 struct regulator *core_ldo;
121 int core_voltage_levels[3];
122 struct clk *ref_clk_src;
123 struct clk *ref_clk;
124 struct clk *aux_clk;
Mayank Rana561d0442017-03-16 18:19:14 -0700125 struct clk *com_aux_clk;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700126 struct clk *cfg_ahb_clk;
127 struct clk *pipe_clk;
Amit Nischal4d278212016-06-06 17:54:34 +0530128 struct reset_control *phy_reset;
129 struct reset_control *phy_phy_reset;
Mayank Rana807b8962017-04-11 20:50:11 -0700130 struct reset_control *global_phy_reset;
Hemant Kumar16d1a052016-08-30 16:54:19 -0700131 bool power_enabled;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700132 bool clk_enabled;
133 bool cable_connected;
134 bool in_suspend;
135 bool emulation;
136 unsigned int *phy_reg; /* revision based offset */
137 unsigned int *qmp_phy_init_seq;
138 int init_seq_len;
139 unsigned int *qmp_phy_reg_offset;
140 int reg_offset_cnt;
141};
142
143static const struct of_device_id msm_usb_id_table[] = {
144 {
145 .compatible = "qcom,usb-ssphy-qmp",
146 },
147 {
148 .compatible = "qcom,usb-ssphy-qmp-v1",
149 },
150 {
151 .compatible = "qcom,usb-ssphy-qmp-v2",
152 },
Mayank Rana4c40cd92017-03-21 14:40:55 -0700153 {
154 .compatible = "qcom,usb-ssphy-qmp-dp-combo",
155 },
Hemant Kumarbce97a22017-12-07 16:17:38 -0800156 {
157 .compatible = "qcom,usb-ssphy-qmp-usb3-or-dp",
158 },
Mayank Rana3cb43a32016-08-02 12:10:20 -0700159 { },
160};
161MODULE_DEVICE_TABLE(of, msm_usb_id_table);
162
Mayank Rana807b8962017-04-11 20:50:11 -0700163static void usb_qmp_powerup_phy(struct msm_ssphy_qmp *phy);
Mayank Rana561d0442017-03-16 18:19:14 -0700164static void msm_ssphy_qmp_enable_clks(struct msm_ssphy_qmp *phy, bool on);
165
Mayank Rana3cb43a32016-08-02 12:10:20 -0700166static inline char *get_cable_status_str(struct msm_ssphy_qmp *phy)
167{
168 return phy->cable_connected ? "connected" : "disconnected";
169}
170
171static void msm_ssusb_qmp_clr_lfps_rxterm_int(struct msm_ssphy_qmp *phy)
172{
173 writeb_relaxed(1, phy->base +
174 phy->phy_reg[USB3_PHY_LFPS_RXTERM_IRQ_CLEAR]);
175 /* flush the previous write before next write */
176 wmb();
177 writeb_relaxed(0, phy->base +
178 phy->phy_reg[USB3_PHY_LFPS_RXTERM_IRQ_CLEAR]);
179}
180
Mayank Rana4c40cd92017-03-21 14:40:55 -0700181static void msm_ssusb_qmp_clamp_enable(struct msm_ssphy_qmp *phy, bool val)
182{
183 switch (phy->phy.type) {
Hemant Kumarbce97a22017-12-07 16:17:38 -0800184 case USB_PHY_TYPE_USB3_AND_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700185 writel_relaxed(!val, phy->base +
186 phy->phy_reg[USB3_PCS_MISC_CLAMP_ENABLE]);
187 break;
Hemant Kumarbce97a22017-12-07 16:17:38 -0800188 case USB_PHY_TYPE_USB3_OR_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700189 case USB_PHY_TYPE_USB3:
190 writel_relaxed(!!val, phy->vls_clamp_reg);
Hemant Kumar84c6b592018-01-31 14:02:12 -0800191 if (phy->pcs_clamp_enable_reg)
192 writel_relaxed(!val, phy->pcs_clamp_enable_reg);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700193 break;
194 default:
195 break;
196 }
197}
198
Mayank Rana3cb43a32016-08-02 12:10:20 -0700199static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy,
200 int enable)
201{
202 u8 val;
203 unsigned int autonomous_mode_offset =
204 phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL];
205
206 dev_dbg(phy->phy.dev, "enabling QMP autonomous mode with cable %s\n",
207 get_cable_status_str(phy));
208
209 if (enable) {
210 msm_ssusb_qmp_clr_lfps_rxterm_int(phy);
Mayank Rana0d5efd72017-06-08 10:06:00 -0700211 val = readb_relaxed(phy->base + autonomous_mode_offset);
212 val |= ARCVR_DTCT_EN;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700213 if (phy->phy.flags & DEVICE_IN_SS_MODE) {
Mayank Rana3cb43a32016-08-02 12:10:20 -0700214 val |= ALFPS_DTCT_EN;
215 val &= ~ARCVR_DTCT_EVENT_SEL;
Mayank Rana0d5efd72017-06-08 10:06:00 -0700216 } else {
217 val &= ~ALFPS_DTCT_EN;
218 val |= ARCVR_DTCT_EVENT_SEL;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700219 }
Mayank Rana0d5efd72017-06-08 10:06:00 -0700220 writeb_relaxed(val, phy->base + autonomous_mode_offset);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700221 msm_ssusb_qmp_clamp_enable(phy, true);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700222 } else {
Mayank Rana4c40cd92017-03-21 14:40:55 -0700223 msm_ssusb_qmp_clamp_enable(phy, false);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700224 writeb_relaxed(0, phy->base + autonomous_mode_offset);
225 msm_ssusb_qmp_clr_lfps_rxterm_int(phy);
226 }
227}
228
Mayank Rana3cb43a32016-08-02 12:10:20 -0700229static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
230{
Hemant Kumar16d1a052016-08-30 16:54:19 -0700231 int min, rc = 0;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700232
233 dev_dbg(phy->phy.dev, "reg (%s)\n", on ? "HPM" : "LPM");
234
Hemant Kumar16d1a052016-08-30 16:54:19 -0700235 if (phy->power_enabled == on) {
236 dev_dbg(phy->phy.dev, "PHYs' regulators status %d\n",
237 phy->power_enabled);
238 return 0;
239 }
240
241 phy->power_enabled = on;
242
243 min = on ? 1 : 0; /* low or none? */
244
Mayank Rana3cb43a32016-08-02 12:10:20 -0700245 if (!on)
246 goto disable_regulators;
247
Hemant Kumar16d1a052016-08-30 16:54:19 -0700248 rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
249 phy->vdd_levels[2]);
250 if (rc) {
251 dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
252 return rc;
253 }
254
255 dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n",
256 phy->vdd_levels[min], phy->vdd_levels[2]);
257
258 rc = regulator_enable(phy->vdd);
259 if (rc) {
260 dev_err(phy->phy.dev,
261 "regulator_enable(phy->vdd) failed, ret=%d",
262 rc);
263 goto unconfig_vdd;
264 }
Mayank Rana3cb43a32016-08-02 12:10:20 -0700265
266 rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD);
267 if (rc < 0) {
268 dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n");
Hemant Kumar16d1a052016-08-30 16:54:19 -0700269 goto disable_vdd;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700270 }
271
272 rc = regulator_set_voltage(phy->core_ldo,
273 phy->core_voltage_levels[CORE_LEVEL_MIN],
274 phy->core_voltage_levels[CORE_LEVEL_MAX]);
275 if (rc) {
276 dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
277 goto put_core_ldo_lpm;
278 }
279
280 rc = regulator_enable(phy->core_ldo);
281 if (rc) {
282 dev_err(phy->phy.dev, "Unable to enable core_ldo\n");
283 goto unset_core_ldo;
284 }
285
286 return 0;
287
288disable_regulators:
289 rc = regulator_disable(phy->core_ldo);
290 if (rc)
291 dev_err(phy->phy.dev, "Unable to disable core_ldo\n");
292
293unset_core_ldo:
294 rc = regulator_set_voltage(phy->core_ldo,
295 phy->core_voltage_levels[CORE_LEVEL_NONE],
296 phy->core_voltage_levels[CORE_LEVEL_MAX]);
297 if (rc)
298 dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
299
300put_core_ldo_lpm:
301 rc = regulator_set_load(phy->core_ldo, 0);
302 if (rc < 0)
303 dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n");
304
Hemant Kumar16d1a052016-08-30 16:54:19 -0700305disable_vdd:
306 rc = regulator_disable(phy->vdd);
307 if (rc)
308 dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d",
309 rc);
310
311unconfig_vdd:
312 rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
313 phy->vdd_levels[2]);
314 if (rc)
315 dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
316
Mayank Rana3cb43a32016-08-02 12:10:20 -0700317 return rc < 0 ? rc : 0;
318}
319
320static int configure_phy_regs(struct usb_phy *uphy,
321 const struct qmp_reg_val *reg)
322{
323 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
324 phy);
325
326 if (!reg) {
327 dev_err(uphy->dev, "NULL PHY configuration\n");
328 return -EINVAL;
329 }
330
331 while (reg->offset != -1) {
332 writel_relaxed(reg->val, phy->base + reg->offset);
333 if (reg->delay)
334 usleep_range(reg->delay, reg->delay + 10);
335 reg++;
336 }
337 return 0;
338}
339
Mayank Rana4c40cd92017-03-21 14:40:55 -0700340static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
341{
342 int val;
343
344 /* perform lane selection */
345 val = -EINVAL;
Mayank Rana807b8962017-04-11 20:50:11 -0700346 if (phy->phy.flags & PHY_LANE_A)
Mayank Rana4c40cd92017-03-21 14:40:55 -0700347 val = SW_PORTSELECT_MX;
Mayank Rana807b8962017-04-11 20:50:11 -0700348 else if (phy->phy.flags & PHY_LANE_B)
Mayank Rana4c40cd92017-03-21 14:40:55 -0700349 val = SW_PORTSELECT | SW_PORTSELECT_MX;
Mayank Rana807b8962017-04-11 20:50:11 -0700350
351 /* PHY must be powered up before updating portselect and phymode. */
352 usb_qmp_powerup_phy(phy);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700353
354 switch (phy->phy.type) {
Hemant Kumarbce97a22017-12-07 16:17:38 -0800355 case USB_PHY_TYPE_USB3_AND_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700356 /* override hardware control for reset of qmp phy */
357 writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
358 SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET,
359 phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
360
361 /* update port select */
362 if (val > 0) {
363 dev_err(phy->phy.dev,
364 "USB DP QMP PHY: Update TYPEC CTRL(%d)\n", val);
365 writel_relaxed(val, phy->base +
366 phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]);
367 }
368
369 writel_relaxed(USB3_MODE | DP_MODE,
370 phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]);
371
Mayank Rana4c40cd92017-03-21 14:40:55 -0700372 /* bring both QMP USB and QMP DP PHYs PCS block out of reset */
373 writel_relaxed(0x00,
374 phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
375 break;
Hemant Kumarbce97a22017-12-07 16:17:38 -0800376 case USB_PHY_TYPE_USB3_OR_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700377 if (val > 0) {
378 dev_err(phy->phy.dev,
379 "USB QMP PHY: Update TYPEC CTRL(%d)\n", val);
380 writel_relaxed(val, phy->base +
381 phy->phy_reg[USB3_PHY_PCS_MISC_TYPEC_CTRL]);
382 }
383 break;
384 default:
Hemant Kumarbce97a22017-12-07 16:17:38 -0800385 dev_dbg(phy->phy.dev, "no portselect for phy type %d\n",
386 phy->phy.type);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700387 break;
388 }
389
390 /* Make sure above selection and reset sequence is gone through */
391 mb();
392}
393
394static void usb_qmp_powerup_phy(struct msm_ssphy_qmp *phy)
395{
396 switch (phy->phy.type) {
Hemant Kumarbce97a22017-12-07 16:17:38 -0800397 case USB_PHY_TYPE_USB3_AND_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700398 /* power up USB3 and DP common logic block */
399 writel_relaxed(0x01,
400 phy->base + phy->phy_reg[USB3_DP_COM_POWER_DOWN_CTRL]);
401
402 /*
Mayank Rana807b8962017-04-11 20:50:11 -0700403 * Don't write 0x0 to DP_COM_SW_RESET here as portselect and
404 * phymode operation needs DP_COM_SW_RESET as 0x1.
405 * msm_ssphy_qmp_init() writes 0x0 to DP_COM_SW_RESET before
406 * initializing PHY.
Mayank Rana4c40cd92017-03-21 14:40:55 -0700407 */
408
409 /* intentional fall-through */
Hemant Kumarbce97a22017-12-07 16:17:38 -0800410 case USB_PHY_TYPE_USB3_OR_DP:
Mayank Rana4c40cd92017-03-21 14:40:55 -0700411 case USB_PHY_TYPE_USB3:
412 /* power up USB3 PHY */
413 writel_relaxed(0x01,
414 phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
415 break;
416 default:
417 dev_err(phy->phy.dev, "phy_powerup: Unknown USB QMP PHY type\n");
418 break;
419 }
420
421 /* Make sure that above write completed to power up PHY */
422 mb();
423}
424
Mayank Rana3cb43a32016-08-02 12:10:20 -0700425/* SSPHY Initialization */
426static int msm_ssphy_qmp_init(struct usb_phy *uphy)
427{
428 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
429 phy);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700430 int ret;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700431 unsigned int init_timeout_usec = INIT_MAX_TIME_USEC;
432 const struct qmp_reg_val *reg = NULL;
433
434 dev_dbg(uphy->dev, "Initializing QMP phy\n");
435
436 if (phy->emulation)
437 return 0;
438
Hemant Kumar16d1a052016-08-30 16:54:19 -0700439 ret = msm_ssusb_qmp_ldo_enable(phy, 1);
440 if (ret) {
441 dev_err(phy->phy.dev,
442 "msm_ssusb_qmp_ldo_enable(1) failed, ret=%d\n",
443 ret);
444 return ret;
445 }
446
Mayank Rana561d0442017-03-16 18:19:14 -0700447 msm_ssphy_qmp_enable_clks(phy, true);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700448
Mayank Rana4c40cd92017-03-21 14:40:55 -0700449 /* select appropriate port select and PHY mode if applicable */
450 usb_qmp_update_portselect_phymode(phy);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700451
Mayank Rana807b8962017-04-11 20:50:11 -0700452 /* power up PHY */
453 usb_qmp_powerup_phy(phy);
454
Mayank Rana3cb43a32016-08-02 12:10:20 -0700455 reg = (struct qmp_reg_val *)phy->qmp_phy_init_seq;
456
457 /* Main configuration */
458 ret = configure_phy_regs(uphy, reg);
459 if (ret) {
460 dev_err(uphy->dev, "Failed the main PHY configuration\n");
461 return ret;
462 }
463
Mayank Rana4c40cd92017-03-21 14:40:55 -0700464 /* perform software reset of PHY common logic */
Hemant Kumarbce97a22017-12-07 16:17:38 -0800465 if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP)
Mayank Rana4c40cd92017-03-21 14:40:55 -0700466 writel_relaxed(0x00,
467 phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700468
Mayank Rana4c40cd92017-03-21 14:40:55 -0700469 /* perform software reset of PCS/Serdes */
Mayank Rana3cb43a32016-08-02 12:10:20 -0700470 writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_PHY_SW_RESET]);
Mayank Rana4c40cd92017-03-21 14:40:55 -0700471 /* start PCS/Serdes to operation mode */
472 writel_relaxed(0x03, phy->base + phy->phy_reg[USB3_PHY_START]);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700473
474 /* Make sure above write completed to bring PHY out of reset */
475 mb();
476
477 /* Wait for PHY initialization to be done */
478 do {
479 if (readl_relaxed(phy->base +
480 phy->phy_reg[USB3_PHY_PCS_STATUS]) & PHYSTATUS)
481 usleep_range(1, 2);
482 else
483 break;
484 } while (--init_timeout_usec);
485
486 if (!init_timeout_usec) {
487 dev_err(uphy->dev, "QMP PHY initialization timeout\n");
488 dev_err(uphy->dev, "USB3_PHY_PCS_STATUS:%x\n",
489 readl_relaxed(phy->base +
490 phy->phy_reg[USB3_PHY_PCS_STATUS]));
491 return -EBUSY;
492 };
493
494 return 0;
495}
496
Mayank Rana4c40cd92017-03-21 14:40:55 -0700497static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy)
498{
499 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
500 phy);
501 int ret = 0;
502
Mayank Rana4c40cd92017-03-21 14:40:55 -0700503 dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n");
Mayank Rana807b8962017-04-11 20:50:11 -0700504 /* Assert global PHY reset */
505 ret = reset_control_assert(phy->global_phy_reset);
506 if (ret) {
507 dev_err(uphy->dev, "global_phy_reset assert failed\n");
508 goto exit;
509 }
510
511 /* Assert QMP USB PHY reset */
Mayank Rana4c40cd92017-03-21 14:40:55 -0700512 ret = reset_control_assert(phy->phy_reset);
513 if (ret) {
514 dev_err(uphy->dev, "phy_reset assert failed\n");
515 goto exit;
516 }
517
Mayank Rana807b8962017-04-11 20:50:11 -0700518 /* De-Assert QMP USB PHY reset */
Mayank Rana4c40cd92017-03-21 14:40:55 -0700519 ret = reset_control_deassert(phy->phy_reset);
520 if (ret)
521 dev_err(uphy->dev, "phy_reset deassert failed\n");
522
Mayank Rana807b8962017-04-11 20:50:11 -0700523 /* De-Assert global PHY reset */
524 ret = reset_control_deassert(phy->global_phy_reset);
525 if (ret)
526 dev_err(uphy->dev, "global_phy_reset deassert failed\n");
527
Mayank Rana4c40cd92017-03-21 14:40:55 -0700528exit:
529 return ret;
530}
531
Mayank Rana3cb43a32016-08-02 12:10:20 -0700532static int msm_ssphy_qmp_reset(struct usb_phy *uphy)
533{
534 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
535 phy);
536 int ret;
537
538 dev_dbg(uphy->dev, "Resetting QMP phy\n");
539
540 /* Assert USB3 PHY reset */
Amit Nischal4d278212016-06-06 17:54:34 +0530541 ret = reset_control_assert(phy->phy_phy_reset);
542 if (ret) {
543 dev_err(uphy->dev, "phy_phy_reset assert failed\n");
544 goto exit;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700545 }
546
547 /* Assert USB3 PHY CSR reset */
Amit Nischal4d278212016-06-06 17:54:34 +0530548 ret = reset_control_assert(phy->phy_reset);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700549 if (ret) {
Amit Nischal4d278212016-06-06 17:54:34 +0530550 dev_err(uphy->dev, "phy_reset assert failed\n");
Mayank Rana3cb43a32016-08-02 12:10:20 -0700551 goto deassert_phy_phy_reset;
552 }
553
Jack Phamffe2ec42017-03-22 12:03:53 -0700554 /* select usb3 phy mode */
555 if (phy->tcsr_usb3_dp_phymode)
556 writel_relaxed(0x0, phy->tcsr_usb3_dp_phymode);
557
Mayank Rana3cb43a32016-08-02 12:10:20 -0700558 /* Deassert USB3 PHY CSR reset */
Amit Nischal4d278212016-06-06 17:54:34 +0530559 ret = reset_control_deassert(phy->phy_reset);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700560 if (ret) {
Amit Nischal4d278212016-06-06 17:54:34 +0530561 dev_err(uphy->dev, "phy_reset deassert failed\n");
Mayank Rana3cb43a32016-08-02 12:10:20 -0700562 goto deassert_phy_phy_reset;
563 }
564
565 /* Deassert USB3 PHY reset */
Amit Nischal4d278212016-06-06 17:54:34 +0530566 ret = reset_control_deassert(phy->phy_phy_reset);
567 if (ret) {
568 dev_err(uphy->dev, "phy_phy_reset deassert failed\n");
569 goto exit;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700570 }
571
572 return 0;
573
574deassert_phy_phy_reset:
Amit Nischal4d278212016-06-06 17:54:34 +0530575 ret = reset_control_deassert(phy->phy_phy_reset);
576 if (ret)
577 dev_err(uphy->dev, "phy_phy_reset deassert failed\n");
Mayank Rana3cb43a32016-08-02 12:10:20 -0700578exit:
579 phy->in_suspend = false;
580
581 return ret;
582}
583
584static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on)
585{
586 bool host = phy->phy.flags & PHY_HOST_MODE;
587 int ret = 0;
588
589 /*
590 * Turn off the phy's LDOs when cable is disconnected for device mode
591 * with external vbus_id indication.
592 */
593 if (!host && !phy->cable_connected) {
594 if (on) {
Mayank Rana3cb43a32016-08-02 12:10:20 -0700595 ret = msm_ssusb_qmp_ldo_enable(phy, 1);
596 if (ret)
597 dev_err(phy->phy.dev,
598 "msm_ssusb_qmp_ldo_enable(1) failed, ret=%d\n",
599 ret);
600 } else {
601 ret = msm_ssusb_qmp_ldo_enable(phy, 0);
602 if (ret)
603 dev_err(phy->phy.dev,
604 "msm_ssusb_qmp_ldo_enable(0) failed, ret=%d\n",
605 ret);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700606 }
607 }
608
609 return ret;
610}
611
612/**
613 * Performs QMP PHY suspend/resume functionality.
614 *
615 * @uphy - usb phy pointer.
616 * @suspend - to enable suspend or not. 1 - suspend, 0 - resume
617 *
618 */
619static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend)
620{
621 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
622 phy);
623
624 dev_dbg(uphy->dev, "QMP PHY set_suspend for %s called with cable %s\n",
625 (suspend ? "suspend" : "resume"),
626 get_cable_status_str(phy));
627
628 if (phy->in_suspend == suspend) {
629 dev_dbg(uphy->dev, "%s: USB PHY is already %s.\n",
630 __func__, (suspend ? "suspended" : "resumed"));
631 return 0;
632 }
633
634 if (suspend) {
Hemant Kumar3e7dcb52017-09-25 18:01:23 -0700635 if (phy->cable_connected)
Mayank Rana3cb43a32016-08-02 12:10:20 -0700636 msm_ssusb_qmp_enable_autonomous(phy, 1);
637
Mayank Rana813952b2016-02-04 11:11:42 -0800638 /* Make sure above write completed with PHY */
639 wmb();
640
Mayank Rana561d0442017-03-16 18:19:14 -0700641 msm_ssphy_qmp_enable_clks(phy, false);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700642 phy->in_suspend = true;
643 msm_ssphy_power_enable(phy, 0);
644 dev_dbg(uphy->dev, "QMP PHY is suspend\n");
645 } else {
646 msm_ssphy_power_enable(phy, 1);
Mayank Rana561d0442017-03-16 18:19:14 -0700647 msm_ssphy_qmp_enable_clks(phy, true);
Mayank Rana3cb43a32016-08-02 12:10:20 -0700648 if (!phy->cable_connected) {
649 writel_relaxed(0x01,
650 phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
651 } else {
652 msm_ssusb_qmp_enable_autonomous(phy, 0);
653 }
Mayank Rana813952b2016-02-04 11:11:42 -0800654
655 /* Make sure that above write completed with PHY */
656 wmb();
657
Mayank Rana3cb43a32016-08-02 12:10:20 -0700658 phy->in_suspend = false;
659 dev_dbg(uphy->dev, "QMP PHY is resumed\n");
660 }
661
662 return 0;
663}
664
665static int msm_ssphy_qmp_notify_connect(struct usb_phy *uphy,
666 enum usb_device_speed speed)
667{
668 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
669 phy);
670
671 dev_dbg(uphy->dev, "QMP phy connect notification\n");
672 phy->cable_connected = true;
673 dev_dbg(uphy->dev, "cable_connected=%d\n", phy->cable_connected);
674 return 0;
675}
676
677static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy,
678 enum usb_device_speed speed)
679{
680 struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
681 phy);
682
Hemant Kumar3e7dcb52017-09-25 18:01:23 -0700683 writel_relaxed(0x00,
684 phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
685 readl_relaxed(phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
686
Mayank Rana3cb43a32016-08-02 12:10:20 -0700687 dev_dbg(uphy->dev, "QMP phy disconnect notification\n");
688 dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected);
689 phy->cable_connected = false;
690 return 0;
691}
692
Mayank Rana561d0442017-03-16 18:19:14 -0700693static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev)
Mayank Rana3cb43a32016-08-02 12:10:20 -0700694{
Mayank Rana561d0442017-03-16 18:19:14 -0700695 int ret = 0;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700696
697 phy->aux_clk = devm_clk_get(dev, "aux_clk");
698 if (IS_ERR(phy->aux_clk)) {
699 ret = PTR_ERR(phy->aux_clk);
700 phy->aux_clk = NULL;
701 if (ret != -EPROBE_DEFER)
702 dev_err(dev, "failed to get aux_clk\n");
703 goto err;
704 }
Mayank Rana3cb43a32016-08-02 12:10:20 -0700705 clk_set_rate(phy->aux_clk, clk_round_rate(phy->aux_clk, ULONG_MAX));
706
Mayank Rana561d0442017-03-16 18:19:14 -0700707 if (of_property_match_string(dev->of_node,
708 "clock-names", "cfg_ahb_clk") >= 0) {
Mayank Rana3cb43a32016-08-02 12:10:20 -0700709 phy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk");
710 if (IS_ERR(phy->cfg_ahb_clk)) {
711 ret = PTR_ERR(phy->cfg_ahb_clk);
712 if (ret != -EPROBE_DEFER)
713 dev_err(dev,
714 "failed to get cfg_ahb_clk ret %d\n", ret);
715 goto err;
716 }
717 }
718
719 phy->pipe_clk = devm_clk_get(dev, "pipe_clk");
720 if (IS_ERR(phy->pipe_clk)) {
721 ret = PTR_ERR(phy->pipe_clk);
722 phy->pipe_clk = NULL;
723 if (ret != -EPROBE_DEFER)
724 dev_err(dev, "failed to get pipe_clk\n");
725 goto err;
726 }
727
Mayank Rana561d0442017-03-16 18:19:14 -0700728 phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
729 if (IS_ERR(phy->ref_clk_src))
730 phy->ref_clk_src = NULL;
731
732 phy->ref_clk = devm_clk_get(dev, "ref_clk");
733 if (IS_ERR(phy->ref_clk))
734 phy->ref_clk = NULL;
735
736 if (of_property_match_string(dev->of_node,
737 "clock-names", "com_aux_clk") >= 0) {
738 phy->com_aux_clk = devm_clk_get(dev, "com_aux_clk");
739 if (IS_ERR(phy->com_aux_clk)) {
740 ret = PTR_ERR(phy->com_aux_clk);
741 if (ret != -EPROBE_DEFER)
742 dev_err(dev,
743 "failed to get com_aux_clk ret %d\n", ret);
744 goto err;
745 }
746 }
747
748err:
749 return ret;
750}
751
752static void msm_ssphy_qmp_enable_clks(struct msm_ssphy_qmp *phy, bool on)
753{
754 dev_dbg(phy->phy.dev, "%s(): clk_enabled:%d on:%d\n", __func__,
755 phy->clk_enabled, on);
756
757 if (!phy->clk_enabled && on) {
758 if (phy->ref_clk_src)
759 clk_prepare_enable(phy->ref_clk_src);
760
761 if (phy->ref_clk)
762 clk_prepare_enable(phy->ref_clk);
763
764 if (phy->com_aux_clk)
765 clk_prepare_enable(phy->com_aux_clk);
766
767 clk_prepare_enable(phy->aux_clk);
768 if (phy->cfg_ahb_clk)
769 clk_prepare_enable(phy->cfg_ahb_clk);
770
771 clk_prepare_enable(phy->pipe_clk);
772 phy->clk_enabled = true;
773 }
774
775 if (phy->clk_enabled && !on) {
776 clk_disable_unprepare(phy->pipe_clk);
777
778 if (phy->cfg_ahb_clk)
779 clk_disable_unprepare(phy->cfg_ahb_clk);
780
781 clk_disable_unprepare(phy->aux_clk);
782 if (phy->com_aux_clk)
783 clk_disable_unprepare(phy->com_aux_clk);
784
785 if (phy->ref_clk)
786 clk_disable_unprepare(phy->ref_clk);
787
788 if (phy->ref_clk_src)
789 clk_disable_unprepare(phy->ref_clk_src);
790
791 phy->clk_enabled = false;
792 }
793}
794
795static int msm_ssphy_qmp_probe(struct platform_device *pdev)
796{
797 struct msm_ssphy_qmp *phy;
798 struct device *dev = &pdev->dev;
799 struct resource *res;
800 int ret = 0, size = 0, len;
801
802 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
803 if (!phy)
804 return -ENOMEM;
805
Mayank Rana4c40cd92017-03-21 14:40:55 -0700806 phy->phy.type = USB_PHY_TYPE_USB3;
807 if (of_device_is_compatible(dev->of_node,
808 "qcom,usb-ssphy-qmp-dp-combo"))
Hemant Kumarbce97a22017-12-07 16:17:38 -0800809 phy->phy.type = USB_PHY_TYPE_USB3_AND_DP;
810
811 if (of_device_is_compatible(dev->of_node,
812 "qcom,usb-ssphy-qmp-usb-or-dp"))
813 phy->phy.type = USB_PHY_TYPE_USB3_OR_DP;
Mayank Rana4c40cd92017-03-21 14:40:55 -0700814
Mayank Rana561d0442017-03-16 18:19:14 -0700815 ret = msm_ssphy_qmp_get_clks(phy, dev);
816 if (ret)
817 goto err;
818
Amit Nischal4d278212016-06-06 17:54:34 +0530819 phy->phy_reset = devm_reset_control_get(dev, "phy_reset");
820 if (IS_ERR(phy->phy_reset)) {
821 ret = PTR_ERR(phy->phy_reset);
822 dev_dbg(dev, "failed to get phy_reset\n");
823 goto err;
Mayank Rana3cb43a32016-08-02 12:10:20 -0700824 }
825
Hemant Kumarbce97a22017-12-07 16:17:38 -0800826 if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) {
Mayank Rana807b8962017-04-11 20:50:11 -0700827 phy->global_phy_reset = devm_reset_control_get(dev,
828 "global_phy_reset");
829 if (IS_ERR(phy->global_phy_reset)) {
830 ret = PTR_ERR(phy->global_phy_reset);
831 dev_dbg(dev, "failed to get global_phy_reset\n");
832 goto err;
833 }
834 } else {
Mayank Rana4c40cd92017-03-21 14:40:55 -0700835 phy->phy_phy_reset = devm_reset_control_get(dev,
836 "phy_phy_reset");
837 if (IS_ERR(phy->phy_phy_reset)) {
838 ret = PTR_ERR(phy->phy_phy_reset);
839 dev_dbg(dev, "failed to get phy_phy_reset\n");
840 goto err;
841 }
Mayank Rana3cb43a32016-08-02 12:10:20 -0700842 }
843
844 of_get_property(dev->of_node, "qcom,qmp-phy-reg-offset", &size);
845 if (size) {
846 phy->qmp_phy_reg_offset = devm_kzalloc(dev,
847 size, GFP_KERNEL);
848 if (phy->qmp_phy_reg_offset) {
849 phy->reg_offset_cnt =
850 (size / sizeof(*phy->qmp_phy_reg_offset));
851 if (phy->reg_offset_cnt > USB3_PHY_REG_MAX) {
852 dev_err(dev, "invalid reg offset count\n");
853 return -EINVAL;
854 }
855
856 of_property_read_u32_array(dev->of_node,
857 "qcom,qmp-phy-reg-offset",
858 phy->qmp_phy_reg_offset,
859 phy->reg_offset_cnt);
860 } else {
861 dev_err(dev, "err mem alloc for qmp_phy_reg_offset\n");
862 return -ENOMEM;
863 }
864 phy->phy_reg = phy->qmp_phy_reg_offset;
865 } else {
866 dev_err(dev, "err provide qcom,qmp-phy-reg-offset\n");
867 return -EINVAL;
868 }
869
870 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
871 "qmp_phy_base");
872 if (!res) {
873 dev_err(dev, "failed getting qmp_phy_base\n");
874 return -ENODEV;
875 }
Mayank Rana4c40cd92017-03-21 14:40:55 -0700876
877 /*
878 * For USB QMP DP combo PHY, common set of registers shall be accessed
879 * by DP driver as well.
880 */
881 phy->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
882 if (IS_ERR_OR_NULL(phy->base)) {
Mayank Rana3cb43a32016-08-02 12:10:20 -0700883 ret = PTR_ERR(phy->base);
884 goto err;
885 }
886
Hemant Kumarbce97a22017-12-07 16:17:38 -0800887 if (phy->phy.type != USB_PHY_TYPE_USB3_AND_DP) {
Mayank Rana4c40cd92017-03-21 14:40:55 -0700888 res = platform_get_resource_byname(pdev,
889 IORESOURCE_MEM, "vls_clamp_reg");
890 phy->vls_clamp_reg = devm_ioremap_resource(dev, res);
891 if (IS_ERR(phy->vls_clamp_reg)) {
892 dev_err(dev, "couldn't find vls_clamp_reg address.\n");
893 return PTR_ERR(phy->vls_clamp_reg);
894 }
Mayank Rana3cb43a32016-08-02 12:10:20 -0700895 }
896
897 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
Hemant Kumar84c6b592018-01-31 14:02:12 -0800898 "pcs_clamp_enable_reg");
899 if (res) {
900 phy->pcs_clamp_enable_reg = devm_ioremap_resource(dev, res);
901 if (IS_ERR(phy->pcs_clamp_enable_reg)) {
902 dev_err(dev, "err getting pcs_clamp_enable_reg address.\n");
903 return PTR_ERR(phy->pcs_clamp_enable_reg);
904 }
905 }
906
907 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
Mayank Rana3cb43a32016-08-02 12:10:20 -0700908 "tcsr_usb3_dp_phymode");
909 if (res) {
910 phy->tcsr_usb3_dp_phymode = devm_ioremap_resource(dev, res);
911 if (IS_ERR(phy->tcsr_usb3_dp_phymode)) {
912 dev_err(dev, "err getting tcsr_usb3_dp_phymode addr\n");
913 return PTR_ERR(phy->tcsr_usb3_dp_phymode);
914 }
915 }
916
917 phy->emulation = of_property_read_bool(dev->of_node,
918 "qcom,emulation");
919 if (!phy->emulation) {
920 of_get_property(dev->of_node, "qcom,qmp-phy-init-seq", &size);
921 if (size) {
922 if (size % sizeof(*phy->qmp_phy_init_seq)) {
923 dev_err(dev, "invalid init_seq_len\n");
924 return -EINVAL;
925 }
926 phy->qmp_phy_init_seq = devm_kzalloc(dev,
927 size, GFP_KERNEL);
928 if (phy->qmp_phy_init_seq) {
929 phy->init_seq_len =
930 (size / sizeof(*phy->qmp_phy_init_seq));
931
932 of_property_read_u32_array(dev->of_node,
933 "qcom,qmp-phy-init-seq",
934 phy->qmp_phy_init_seq,
935 phy->init_seq_len);
936 } else {
937 dev_err(dev, "error allocating memory for phy_init_seq\n");
938 return -EINVAL;
939 }
940 } else {
941 dev_err(dev, "error need qmp-phy-init-seq\n");
942 return -EINVAL;
943 }
944 }
945
946 /* Set default core voltage values */
947 phy->core_voltage_levels[CORE_LEVEL_NONE] = 0;
948 phy->core_voltage_levels[CORE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
949 phy->core_voltage_levels[CORE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
950
951 if (of_get_property(dev->of_node, "qcom,core-voltage-level", &len) &&
952 len == sizeof(phy->core_voltage_levels)) {
953 ret = of_property_read_u32_array(dev->of_node,
954 "qcom,core-voltage-level",
955 (u32 *)phy->core_voltage_levels,
956 len / sizeof(u32));
957 if (ret) {
958 dev_err(dev, "err qcom,core-voltage-level property\n");
959 goto err;
960 }
961 }
962
963 if (of_get_property(dev->of_node, "qcom,vdd-voltage-level", &len) &&
964 len == sizeof(phy->vdd_levels)) {
965 ret = of_property_read_u32_array(dev->of_node,
966 "qcom,vdd-voltage-level",
967 (u32 *) phy->vdd_levels,
968 len / sizeof(u32));
969 if (ret) {
970 dev_err(dev, "err qcom,vdd-voltage-level property\n");
971 goto err;
972 }
973 } else {
974 ret = -EINVAL;
975 dev_err(dev, "error invalid inputs for vdd-voltage-level\n");
976 goto err;
977 }
978
979 phy->vdd = devm_regulator_get(dev, "vdd");
980 if (IS_ERR(phy->vdd)) {
981 dev_err(dev, "unable to get vdd supply\n");
982 ret = PTR_ERR(phy->vdd);
983 goto err;
984 }
985
986 phy->core_ldo = devm_regulator_get(dev, "core");
987 if (IS_ERR(phy->core_ldo)) {
988 dev_err(dev, "unable to get core ldo supply\n");
989 ret = PTR_ERR(phy->core_ldo);
990 goto err;
991 }
992
Mayank Rana3cb43a32016-08-02 12:10:20 -0700993 platform_set_drvdata(pdev, phy);
994
995 if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
996 phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE;
997
998 phy->phy.dev = dev;
999 phy->phy.init = msm_ssphy_qmp_init;
1000 phy->phy.set_suspend = msm_ssphy_qmp_set_suspend;
1001 phy->phy.notify_connect = msm_ssphy_qmp_notify_connect;
1002 phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect;
Mayank Rana4c40cd92017-03-21 14:40:55 -07001003
Hemant Kumarbce97a22017-12-07 16:17:38 -08001004 if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP)
Mayank Rana4c40cd92017-03-21 14:40:55 -07001005 phy->phy.reset = msm_ssphy_qmp_dp_combo_reset;
1006 else
1007 phy->phy.reset = msm_ssphy_qmp_reset;
Mayank Rana3cb43a32016-08-02 12:10:20 -07001008
1009 ret = usb_add_phy_dev(&phy->phy);
Mayank Rana3cb43a32016-08-02 12:10:20 -07001010
Mayank Rana3cb43a32016-08-02 12:10:20 -07001011err:
1012 return ret;
1013}
1014
1015static int msm_ssphy_qmp_remove(struct platform_device *pdev)
1016{
1017 struct msm_ssphy_qmp *phy = platform_get_drvdata(pdev);
1018
1019 if (!phy)
1020 return 0;
1021
1022 usb_remove_phy(&phy->phy);
Mayank Rana561d0442017-03-16 18:19:14 -07001023 msm_ssphy_qmp_enable_clks(phy, false);
Mayank Rana3cb43a32016-08-02 12:10:20 -07001024 msm_ssusb_qmp_ldo_enable(phy, 0);
Mayank Rana3cb43a32016-08-02 12:10:20 -07001025 kfree(phy);
1026 return 0;
1027}
1028
1029static struct platform_driver msm_ssphy_qmp_driver = {
1030 .probe = msm_ssphy_qmp_probe,
1031 .remove = msm_ssphy_qmp_remove,
1032 .driver = {
1033 .name = "msm-usb-ssphy-qmp",
1034 .of_match_table = of_match_ptr(msm_usb_id_table),
1035 },
1036};
1037
1038module_platform_driver(msm_ssphy_qmp_driver);
1039
1040MODULE_DESCRIPTION("MSM USB SS QMP PHY driver");
1041MODULE_LICENSE("GPL v2");