xref: /OK3568_Linux_fs/kernel/drivers/phy/samsung/phy-exynos5-usbdrd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Samsung Exynos5 SoC series USB DRD PHY driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2014 Samsung Electronics Co., Ltd.
8*4882a593Smuzhiyun  * Author: Vivek Gautam <gautam.vivek@samsung.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/clk.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/of_address.h>
18*4882a593Smuzhiyun #include <linux/of_device.h>
19*4882a593Smuzhiyun #include <linux/iopoll.h>
20*4882a593Smuzhiyun #include <linux/phy/phy.h>
21*4882a593Smuzhiyun #include <linux/platform_device.h>
22*4882a593Smuzhiyun #include <linux/mutex.h>
23*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
24*4882a593Smuzhiyun #include <linux/regmap.h>
25*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
26*4882a593Smuzhiyun #include <linux/soc/samsung/exynos-regs-pmu.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Exynos USB PHY registers */
29*4882a593Smuzhiyun #define EXYNOS5_FSEL_9MHZ6		0x0
30*4882a593Smuzhiyun #define EXYNOS5_FSEL_10MHZ		0x1
31*4882a593Smuzhiyun #define EXYNOS5_FSEL_12MHZ		0x2
32*4882a593Smuzhiyun #define EXYNOS5_FSEL_19MHZ2		0x3
33*4882a593Smuzhiyun #define EXYNOS5_FSEL_20MHZ		0x4
34*4882a593Smuzhiyun #define EXYNOS5_FSEL_24MHZ		0x5
35*4882a593Smuzhiyun #define EXYNOS5_FSEL_50MHZ		0x7
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* Exynos5: USB 3.0 DRD PHY registers */
38*4882a593Smuzhiyun #define EXYNOS5_DRD_LINKSYSTEM			0x04
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define LINKSYSTEM_FLADJ_MASK			(0x3f << 1)
41*4882a593Smuzhiyun #define LINKSYSTEM_FLADJ(_x)			((_x) << 1)
42*4882a593Smuzhiyun #define LINKSYSTEM_XHCI_VERSION_CONTROL		BIT(27)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYUTMI			0x08
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define PHYUTMI_OTGDISABLE			BIT(6)
47*4882a593Smuzhiyun #define PHYUTMI_FORCESUSPEND			BIT(1)
48*4882a593Smuzhiyun #define PHYUTMI_FORCESLEEP			BIT(0)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYPIPE			0x0c
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYCLKRST			0x10
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define PHYCLKRST_EN_UTMISUSPEND		BIT(31)
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define PHYCLKRST_SSC_REFCLKSEL_MASK		(0xff << 23)
57*4882a593Smuzhiyun #define PHYCLKRST_SSC_REFCLKSEL(_x)		((_x) << 23)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define PHYCLKRST_SSC_RANGE_MASK		(0x03 << 21)
60*4882a593Smuzhiyun #define PHYCLKRST_SSC_RANGE(_x)			((_x) << 21)
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define PHYCLKRST_SSC_EN			BIT(20)
63*4882a593Smuzhiyun #define PHYCLKRST_REF_SSP_EN			BIT(19)
64*4882a593Smuzhiyun #define PHYCLKRST_REF_CLKDIV2			BIT(18)
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_MASK		(0x7f << 11)
67*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF	(0x19 << 11)
68*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_50M_REF	(0x32 << 11)
69*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF	(0x68 << 11)
70*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF	(0x7d << 11)
71*4882a593Smuzhiyun #define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF	(0x02 << 11)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define PHYCLKRST_FSEL_UTMI_MASK		(0x7 << 5)
74*4882a593Smuzhiyun #define PHYCLKRST_FSEL_PIPE_MASK		(0x7 << 8)
75*4882a593Smuzhiyun #define PHYCLKRST_FSEL(_x)			((_x) << 5)
76*4882a593Smuzhiyun #define PHYCLKRST_FSEL_PAD_100MHZ		(0x27 << 5)
77*4882a593Smuzhiyun #define PHYCLKRST_FSEL_PAD_24MHZ		(0x2a << 5)
78*4882a593Smuzhiyun #define PHYCLKRST_FSEL_PAD_20MHZ		(0x31 << 5)
79*4882a593Smuzhiyun #define PHYCLKRST_FSEL_PAD_19_2MHZ		(0x38 << 5)
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define PHYCLKRST_RETENABLEN			BIT(4)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define PHYCLKRST_REFCLKSEL_MASK		(0x03 << 2)
84*4882a593Smuzhiyun #define PHYCLKRST_REFCLKSEL_PAD_REFCLK		(0x2 << 2)
85*4882a593Smuzhiyun #define PHYCLKRST_REFCLKSEL_EXT_REFCLK		(0x3 << 2)
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define PHYCLKRST_PORTRESET			BIT(1)
88*4882a593Smuzhiyun #define PHYCLKRST_COMMONONN			BIT(0)
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYREG0			0x14
91*4882a593Smuzhiyun #define PHYREG0_SSC_REF_CLK_SEL			BIT(21)
92*4882a593Smuzhiyun #define PHYREG0_SSC_RANGE			BIT(20)
93*4882a593Smuzhiyun #define PHYREG0_CR_WRITE			BIT(19)
94*4882a593Smuzhiyun #define PHYREG0_CR_READ				BIT(18)
95*4882a593Smuzhiyun #define PHYREG0_CR_DATA_IN(_x)			((_x) << 2)
96*4882a593Smuzhiyun #define PHYREG0_CR_CAP_DATA			BIT(1)
97*4882a593Smuzhiyun #define PHYREG0_CR_CAP_ADDR			BIT(0)
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYREG1			0x18
100*4882a593Smuzhiyun #define PHYREG1_CR_DATA_OUT(_x)			((_x) << 1)
101*4882a593Smuzhiyun #define PHYREG1_CR_ACK				BIT(0)
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYPARAM0			0x1c
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun #define PHYPARAM0_REF_USE_PAD			BIT(31)
106*4882a593Smuzhiyun #define PHYPARAM0_REF_LOSLEVEL_MASK		(0x1f << 26)
107*4882a593Smuzhiyun #define PHYPARAM0_REF_LOSLEVEL			(0x9 << 26)
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYPARAM1			0x20
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun #define PHYPARAM1_PCS_TXDEEMPH_MASK		(0x1f << 0)
112*4882a593Smuzhiyun #define PHYPARAM1_PCS_TXDEEMPH			(0x1c)
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYTERM			0x24
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYTEST			0x28
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #define PHYTEST_POWERDOWN_SSP			BIT(3)
119*4882a593Smuzhiyun #define PHYTEST_POWERDOWN_HSP			BIT(2)
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYADP			0x2c
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYUTMICLKSEL		0x30
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun #define PHYUTMICLKSEL_UTMI_CLKSEL		BIT(2)
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYRESUME			0x34
128*4882a593Smuzhiyun #define EXYNOS5_DRD_LINKPORT			0x44
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun /* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */
131*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN		(0x15)
132*4882a593Smuzhiyun #define LOSLEVEL_OVRD_IN_LOS_BIAS_5420			(0x5 << 13)
133*4882a593Smuzhiyun #define LOSLEVEL_OVRD_IN_LOS_BIAS_DEFAULT		(0x0 << 13)
134*4882a593Smuzhiyun #define LOSLEVEL_OVRD_IN_EN				(0x1 << 10)
135*4882a593Smuzhiyun #define LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT		(0x9 << 0)
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN	(0x12)
138*4882a593Smuzhiyun #define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420		(0x5 << 13)
139*4882a593Smuzhiyun #define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_DEFAULT		(0x4 << 13)
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun #define EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG		(0x1010)
142*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M		(0x4 << 4)
143*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M		(0x8 << 4)
144*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_25M_26M		(0x8 << 4)
145*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M	(0x20 << 4)
146*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_62M5		(0x20 << 4)
147*4882a593Smuzhiyun #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_96M_100M		(0x40 << 4)
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun #define KHZ	1000
150*4882a593Smuzhiyun #define MHZ	(KHZ * KHZ)
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun enum exynos5_usbdrd_phy_id {
153*4882a593Smuzhiyun 	EXYNOS5_DRDPHY_UTMI,
154*4882a593Smuzhiyun 	EXYNOS5_DRDPHY_PIPE3,
155*4882a593Smuzhiyun 	EXYNOS5_DRDPHYS_NUM,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun struct phy_usb_instance;
159*4882a593Smuzhiyun struct exynos5_usbdrd_phy;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun struct exynos5_usbdrd_phy_config {
162*4882a593Smuzhiyun 	u32 id;
163*4882a593Smuzhiyun 	void (*phy_isol)(struct phy_usb_instance *inst, u32 on);
164*4882a593Smuzhiyun 	void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd);
165*4882a593Smuzhiyun 	unsigned int (*set_refclk)(struct phy_usb_instance *inst);
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun struct exynos5_usbdrd_phy_drvdata {
169*4882a593Smuzhiyun 	const struct exynos5_usbdrd_phy_config *phy_cfg;
170*4882a593Smuzhiyun 	u32 pmu_offset_usbdrd0_phy;
171*4882a593Smuzhiyun 	u32 pmu_offset_usbdrd1_phy;
172*4882a593Smuzhiyun 	bool has_common_clk_gate;
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun /**
176*4882a593Smuzhiyun  * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY
177*4882a593Smuzhiyun  * @dev: pointer to device instance of this platform device
178*4882a593Smuzhiyun  * @reg_phy: usb phy controller register memory base
179*4882a593Smuzhiyun  * @clk: phy clock for register access
180*4882a593Smuzhiyun  * @pipeclk: clock for pipe3 phy
181*4882a593Smuzhiyun  * @utmiclk: clock for utmi+ phy
182*4882a593Smuzhiyun  * @itpclk: clock for ITP generation
183*4882a593Smuzhiyun  * @drv_data: pointer to SoC level driver data structure
184*4882a593Smuzhiyun  * @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
185*4882a593Smuzhiyun  *	    instances each with its 'phy' and 'phy_cfg'.
186*4882a593Smuzhiyun  * @extrefclk: frequency select settings when using 'separate
187*4882a593Smuzhiyun  *	       reference clocks' for SS and HS operations
188*4882a593Smuzhiyun  * @ref_clk: reference clock to PHY block from which PHY's
189*4882a593Smuzhiyun  *	     operational clocks are derived
190*4882a593Smuzhiyun  * @vbus: VBUS regulator for phy
191*4882a593Smuzhiyun  * @vbus_boost: Boost regulator for VBUS present on few Exynos boards
192*4882a593Smuzhiyun  */
193*4882a593Smuzhiyun struct exynos5_usbdrd_phy {
194*4882a593Smuzhiyun 	struct device *dev;
195*4882a593Smuzhiyun 	void __iomem *reg_phy;
196*4882a593Smuzhiyun 	struct clk *clk;
197*4882a593Smuzhiyun 	struct clk *pipeclk;
198*4882a593Smuzhiyun 	struct clk *utmiclk;
199*4882a593Smuzhiyun 	struct clk *itpclk;
200*4882a593Smuzhiyun 	const struct exynos5_usbdrd_phy_drvdata *drv_data;
201*4882a593Smuzhiyun 	struct phy_usb_instance {
202*4882a593Smuzhiyun 		struct phy *phy;
203*4882a593Smuzhiyun 		u32 index;
204*4882a593Smuzhiyun 		struct regmap *reg_pmu;
205*4882a593Smuzhiyun 		u32 pmu_offset;
206*4882a593Smuzhiyun 		const struct exynos5_usbdrd_phy_config *phy_cfg;
207*4882a593Smuzhiyun 	} phys[EXYNOS5_DRDPHYS_NUM];
208*4882a593Smuzhiyun 	u32 extrefclk;
209*4882a593Smuzhiyun 	struct clk *ref_clk;
210*4882a593Smuzhiyun 	struct regulator *vbus;
211*4882a593Smuzhiyun 	struct regulator *vbus_boost;
212*4882a593Smuzhiyun };
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun static inline
to_usbdrd_phy(struct phy_usb_instance * inst)215*4882a593Smuzhiyun struct exynos5_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	return container_of((inst), struct exynos5_usbdrd_phy,
218*4882a593Smuzhiyun 			    phys[(inst)->index]);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /*
222*4882a593Smuzhiyun  * exynos5_rate_to_clk() converts the supplied clock rate to the value that
223*4882a593Smuzhiyun  * can be written to the phy register.
224*4882a593Smuzhiyun  */
exynos5_rate_to_clk(unsigned long rate,u32 * reg)225*4882a593Smuzhiyun static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	/* EXYNOS5_FSEL_MASK */
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	switch (rate) {
230*4882a593Smuzhiyun 	case 9600 * KHZ:
231*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_9MHZ6;
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case 10 * MHZ:
234*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_10MHZ;
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 	case 12 * MHZ:
237*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_12MHZ;
238*4882a593Smuzhiyun 		break;
239*4882a593Smuzhiyun 	case 19200 * KHZ:
240*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_19MHZ2;
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	case 20 * MHZ:
243*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_20MHZ;
244*4882a593Smuzhiyun 		break;
245*4882a593Smuzhiyun 	case 24 * MHZ:
246*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_24MHZ;
247*4882a593Smuzhiyun 		break;
248*4882a593Smuzhiyun 	case 50 * MHZ:
249*4882a593Smuzhiyun 		*reg = EXYNOS5_FSEL_50MHZ;
250*4882a593Smuzhiyun 		break;
251*4882a593Smuzhiyun 	default:
252*4882a593Smuzhiyun 		return -EINVAL;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return 0;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
exynos5_usbdrd_phy_isol(struct phy_usb_instance * inst,unsigned int on)258*4882a593Smuzhiyun static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
259*4882a593Smuzhiyun 						unsigned int on)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	unsigned int val;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (!inst->reg_pmu)
264*4882a593Smuzhiyun 		return;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	val = on ? 0 : EXYNOS4_PHY_ENABLE;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
269*4882a593Smuzhiyun 			   EXYNOS4_PHY_ENABLE, val);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /*
273*4882a593Smuzhiyun  * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock
274*4882a593Smuzhiyun  * from clock core. Further sets multiplier values and spread spectrum
275*4882a593Smuzhiyun  * clock settings for SuperSpeed operations.
276*4882a593Smuzhiyun  */
277*4882a593Smuzhiyun static unsigned int
exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance * inst)278*4882a593Smuzhiyun exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	u32 reg;
281*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* restore any previous reference clock settings */
284*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	/* Use EXTREFCLK as ref clock */
287*4882a593Smuzhiyun 	reg &= ~PHYCLKRST_REFCLKSEL_MASK;
288*4882a593Smuzhiyun 	reg |=	PHYCLKRST_REFCLKSEL_EXT_REFCLK;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	/* FSEL settings corresponding to reference clock */
291*4882a593Smuzhiyun 	reg &= ~PHYCLKRST_FSEL_PIPE_MASK |
292*4882a593Smuzhiyun 		PHYCLKRST_MPLL_MULTIPLIER_MASK |
293*4882a593Smuzhiyun 		PHYCLKRST_SSC_REFCLKSEL_MASK;
294*4882a593Smuzhiyun 	switch (phy_drd->extrefclk) {
295*4882a593Smuzhiyun 	case EXYNOS5_FSEL_50MHZ:
296*4882a593Smuzhiyun 		reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
297*4882a593Smuzhiyun 			PHYCLKRST_SSC_REFCLKSEL(0x00));
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	case EXYNOS5_FSEL_24MHZ:
300*4882a593Smuzhiyun 		reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
301*4882a593Smuzhiyun 			PHYCLKRST_SSC_REFCLKSEL(0x88));
302*4882a593Smuzhiyun 		break;
303*4882a593Smuzhiyun 	case EXYNOS5_FSEL_20MHZ:
304*4882a593Smuzhiyun 		reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
305*4882a593Smuzhiyun 			PHYCLKRST_SSC_REFCLKSEL(0x00));
306*4882a593Smuzhiyun 		break;
307*4882a593Smuzhiyun 	case EXYNOS5_FSEL_19MHZ2:
308*4882a593Smuzhiyun 		reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
309*4882a593Smuzhiyun 			PHYCLKRST_SSC_REFCLKSEL(0x88));
310*4882a593Smuzhiyun 		break;
311*4882a593Smuzhiyun 	default:
312*4882a593Smuzhiyun 		dev_dbg(phy_drd->dev, "unsupported ref clk\n");
313*4882a593Smuzhiyun 		break;
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	return reg;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun /*
320*4882a593Smuzhiyun  * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock
321*4882a593Smuzhiyun  * from clock core. Further sets the FSEL values for HighSpeed operations.
322*4882a593Smuzhiyun  */
323*4882a593Smuzhiyun static unsigned int
exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance * inst)324*4882a593Smuzhiyun exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	u32 reg;
327*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/* restore any previous reference clock settings */
330*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	reg &= ~PHYCLKRST_REFCLKSEL_MASK;
333*4882a593Smuzhiyun 	reg |=	PHYCLKRST_REFCLKSEL_EXT_REFCLK;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	reg &= ~PHYCLKRST_FSEL_UTMI_MASK |
336*4882a593Smuzhiyun 		PHYCLKRST_MPLL_MULTIPLIER_MASK |
337*4882a593Smuzhiyun 		PHYCLKRST_SSC_REFCLKSEL_MASK;
338*4882a593Smuzhiyun 	reg |= PHYCLKRST_FSEL(phy_drd->extrefclk);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return reg;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy * phy_drd)343*4882a593Smuzhiyun static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	u32 reg;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
348*4882a593Smuzhiyun 	/* Set Tx De-Emphasis level */
349*4882a593Smuzhiyun 	reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
350*4882a593Smuzhiyun 	reg |=	PHYPARAM1_PCS_TXDEEMPH;
351*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
354*4882a593Smuzhiyun 	reg &= ~PHYTEST_POWERDOWN_SSP;
355*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy * phy_drd)358*4882a593Smuzhiyun static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	u32 reg;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
363*4882a593Smuzhiyun 	/* Set Loss-of-Signal Detector sensitivity */
364*4882a593Smuzhiyun 	reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
365*4882a593Smuzhiyun 	reg |=	PHYPARAM0_REF_LOSLEVEL;
366*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
369*4882a593Smuzhiyun 	/* Set Tx De-Emphasis level */
370*4882a593Smuzhiyun 	reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
371*4882a593Smuzhiyun 	reg |=	PHYPARAM1_PCS_TXDEEMPH;
372*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	/* UTMI Power Control */
375*4882a593Smuzhiyun 	writel(PHYUTMI_OTGDISABLE, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
378*4882a593Smuzhiyun 	reg &= ~PHYTEST_POWERDOWN_HSP;
379*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
exynos5_usbdrd_phy_init(struct phy * phy)382*4882a593Smuzhiyun static int exynos5_usbdrd_phy_init(struct phy *phy)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	int ret;
385*4882a593Smuzhiyun 	u32 reg;
386*4882a593Smuzhiyun 	struct phy_usb_instance *inst = phy_get_drvdata(phy);
387*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	ret = clk_prepare_enable(phy_drd->clk);
390*4882a593Smuzhiyun 	if (ret)
391*4882a593Smuzhiyun 		return ret;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/* Reset USB 3.0 PHY */
394*4882a593Smuzhiyun 	writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
395*4882a593Smuzhiyun 	writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYRESUME);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/*
398*4882a593Smuzhiyun 	 * Setting the Frame length Adj value[6:1] to default 0x20
399*4882a593Smuzhiyun 	 * See xHCI 1.0 spec, 5.2.4
400*4882a593Smuzhiyun 	 */
401*4882a593Smuzhiyun 	reg =	LINKSYSTEM_XHCI_VERSION_CONTROL |
402*4882a593Smuzhiyun 		LINKSYSTEM_FLADJ(0x20);
403*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
406*4882a593Smuzhiyun 	/* Select PHY CLK source */
407*4882a593Smuzhiyun 	reg &= ~PHYPARAM0_REF_USE_PAD;
408*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	/* This bit must be set for both HS and SS operations */
411*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL);
412*4882a593Smuzhiyun 	reg |= PHYUTMICLKSEL_UTMI_CLKSEL;
413*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	/* UTMI or PIPE3 specific init */
416*4882a593Smuzhiyun 	inst->phy_cfg->phy_init(phy_drd);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	/* reference clock settings */
419*4882a593Smuzhiyun 	reg = inst->phy_cfg->set_refclk(inst);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 		/* Digital power supply in normal operating mode */
422*4882a593Smuzhiyun 	reg |=	PHYCLKRST_RETENABLEN |
423*4882a593Smuzhiyun 		/* Enable ref clock for SS function */
424*4882a593Smuzhiyun 		PHYCLKRST_REF_SSP_EN |
425*4882a593Smuzhiyun 		/* Enable spread spectrum */
426*4882a593Smuzhiyun 		PHYCLKRST_SSC_EN |
427*4882a593Smuzhiyun 		/* Power down HS Bias and PLL blocks in suspend mode */
428*4882a593Smuzhiyun 		PHYCLKRST_COMMONONN |
429*4882a593Smuzhiyun 		/* Reset the port */
430*4882a593Smuzhiyun 		PHYCLKRST_PORTRESET;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	udelay(10);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	reg &= ~PHYCLKRST_PORTRESET;
437*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	clk_disable_unprepare(phy_drd->clk);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
exynos5_usbdrd_phy_exit(struct phy * phy)444*4882a593Smuzhiyun static int exynos5_usbdrd_phy_exit(struct phy *phy)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	int ret;
447*4882a593Smuzhiyun 	u32 reg;
448*4882a593Smuzhiyun 	struct phy_usb_instance *inst = phy_get_drvdata(phy);
449*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	ret = clk_prepare_enable(phy_drd->clk);
452*4882a593Smuzhiyun 	if (ret)
453*4882a593Smuzhiyun 		return ret;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	reg =	PHYUTMI_OTGDISABLE |
456*4882a593Smuzhiyun 		PHYUTMI_FORCESUSPEND |
457*4882a593Smuzhiyun 		PHYUTMI_FORCESLEEP;
458*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	/* Resetting the PHYCLKRST enable bits to reduce leakage current */
461*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
462*4882a593Smuzhiyun 	reg &= ~(PHYCLKRST_REF_SSP_EN |
463*4882a593Smuzhiyun 		 PHYCLKRST_SSC_EN |
464*4882a593Smuzhiyun 		 PHYCLKRST_COMMONONN);
465*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	/* Control PHYTEST to remove leakage current */
468*4882a593Smuzhiyun 	reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
469*4882a593Smuzhiyun 	reg |=	PHYTEST_POWERDOWN_SSP |
470*4882a593Smuzhiyun 		PHYTEST_POWERDOWN_HSP;
471*4882a593Smuzhiyun 	writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	clk_disable_unprepare(phy_drd->clk);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	return 0;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
exynos5_usbdrd_phy_power_on(struct phy * phy)478*4882a593Smuzhiyun static int exynos5_usbdrd_phy_power_on(struct phy *phy)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	int ret;
481*4882a593Smuzhiyun 	struct phy_usb_instance *inst = phy_get_drvdata(phy);
482*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	clk_prepare_enable(phy_drd->ref_clk);
487*4882a593Smuzhiyun 	if (!phy_drd->drv_data->has_common_clk_gate) {
488*4882a593Smuzhiyun 		clk_prepare_enable(phy_drd->pipeclk);
489*4882a593Smuzhiyun 		clk_prepare_enable(phy_drd->utmiclk);
490*4882a593Smuzhiyun 		clk_prepare_enable(phy_drd->itpclk);
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	/* Enable VBUS supply */
494*4882a593Smuzhiyun 	if (phy_drd->vbus_boost) {
495*4882a593Smuzhiyun 		ret = regulator_enable(phy_drd->vbus_boost);
496*4882a593Smuzhiyun 		if (ret) {
497*4882a593Smuzhiyun 			dev_err(phy_drd->dev,
498*4882a593Smuzhiyun 				"Failed to enable VBUS boost supply\n");
499*4882a593Smuzhiyun 			goto fail_vbus;
500*4882a593Smuzhiyun 		}
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (phy_drd->vbus) {
504*4882a593Smuzhiyun 		ret = regulator_enable(phy_drd->vbus);
505*4882a593Smuzhiyun 		if (ret) {
506*4882a593Smuzhiyun 			dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
507*4882a593Smuzhiyun 			goto fail_vbus_boost;
508*4882a593Smuzhiyun 		}
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	/* Power-on PHY*/
512*4882a593Smuzhiyun 	inst->phy_cfg->phy_isol(inst, 0);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return 0;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun fail_vbus_boost:
517*4882a593Smuzhiyun 	if (phy_drd->vbus_boost)
518*4882a593Smuzhiyun 		regulator_disable(phy_drd->vbus_boost);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun fail_vbus:
521*4882a593Smuzhiyun 	clk_disable_unprepare(phy_drd->ref_clk);
522*4882a593Smuzhiyun 	if (!phy_drd->drv_data->has_common_clk_gate) {
523*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->itpclk);
524*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->utmiclk);
525*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->pipeclk);
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	return ret;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
exynos5_usbdrd_phy_power_off(struct phy * phy)531*4882a593Smuzhiyun static int exynos5_usbdrd_phy_power_off(struct phy *phy)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	struct phy_usb_instance *inst = phy_get_drvdata(phy);
534*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	/* Power-off the PHY */
539*4882a593Smuzhiyun 	inst->phy_cfg->phy_isol(inst, 1);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	/* Disable VBUS supply */
542*4882a593Smuzhiyun 	if (phy_drd->vbus)
543*4882a593Smuzhiyun 		regulator_disable(phy_drd->vbus);
544*4882a593Smuzhiyun 	if (phy_drd->vbus_boost)
545*4882a593Smuzhiyun 		regulator_disable(phy_drd->vbus_boost);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	clk_disable_unprepare(phy_drd->ref_clk);
548*4882a593Smuzhiyun 	if (!phy_drd->drv_data->has_common_clk_gate) {
549*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->itpclk);
550*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->pipeclk);
551*4882a593Smuzhiyun 		clk_disable_unprepare(phy_drd->utmiclk);
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return 0;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
crport_handshake(struct exynos5_usbdrd_phy * phy_drd,u32 val,u32 cmd)557*4882a593Smuzhiyun static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd,
558*4882a593Smuzhiyun 			    u32 val, u32 cmd)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	unsigned int result;
561*4882a593Smuzhiyun 	int err;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	writel(val | cmd, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	err = readl_poll_timeout(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1,
566*4882a593Smuzhiyun 				 result, (result & PHYREG1_CR_ACK), 1, 100);
567*4882a593Smuzhiyun 	if (err == -ETIMEDOUT) {
568*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "CRPORT handshake timeout1 (0x%08x)\n", val);
569*4882a593Smuzhiyun 		return err;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	err = readl_poll_timeout(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1,
575*4882a593Smuzhiyun 				 result, !(result & PHYREG1_CR_ACK), 1, 100);
576*4882a593Smuzhiyun 	if (err == -ETIMEDOUT) {
577*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "CRPORT handshake timeout2 (0x%08x)\n", val);
578*4882a593Smuzhiyun 		return err;
579*4882a593Smuzhiyun 	}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	return 0;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
crport_ctrl_write(struct exynos5_usbdrd_phy * phy_drd,u32 addr,u32 data)584*4882a593Smuzhiyun static int crport_ctrl_write(struct exynos5_usbdrd_phy *phy_drd,
585*4882a593Smuzhiyun 			     u32 addr, u32 data)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	int ret;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	/* Write Address */
590*4882a593Smuzhiyun 	writel(PHYREG0_CR_DATA_IN(addr),
591*4882a593Smuzhiyun 	       phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
592*4882a593Smuzhiyun 	ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(addr),
593*4882a593Smuzhiyun 			       PHYREG0_CR_CAP_ADDR);
594*4882a593Smuzhiyun 	if (ret)
595*4882a593Smuzhiyun 		return ret;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* Write Data */
598*4882a593Smuzhiyun 	writel(PHYREG0_CR_DATA_IN(data),
599*4882a593Smuzhiyun 	       phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
600*4882a593Smuzhiyun 	ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
601*4882a593Smuzhiyun 			       PHYREG0_CR_CAP_DATA);
602*4882a593Smuzhiyun 	if (ret)
603*4882a593Smuzhiyun 		return ret;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
606*4882a593Smuzhiyun 			       PHYREG0_CR_WRITE);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	return ret;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun /*
612*4882a593Smuzhiyun  * Calibrate few PHY parameters using CR_PORT register to meet
613*4882a593Smuzhiyun  * SuperSpeed requirements on Exynos5420 and Exynos5800 systems,
614*4882a593Smuzhiyun  * which have 28nm USB 3.0 DRD PHY.
615*4882a593Smuzhiyun  */
exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy * phy_drd)616*4882a593Smuzhiyun static int exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy *phy_drd)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun 	unsigned int temp;
619*4882a593Smuzhiyun 	int ret = 0;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	/*
622*4882a593Smuzhiyun 	 * Change los_bias to (0x5) for 28nm PHY from a
623*4882a593Smuzhiyun 	 * default value (0x0); los_level is set as default
624*4882a593Smuzhiyun 	 * (0x9) as also reflected in los_level[30:26] bits
625*4882a593Smuzhiyun 	 * of PHYPARAM0 register.
626*4882a593Smuzhiyun 	 */
627*4882a593Smuzhiyun 	temp = LOSLEVEL_OVRD_IN_LOS_BIAS_5420 |
628*4882a593Smuzhiyun 		LOSLEVEL_OVRD_IN_EN |
629*4882a593Smuzhiyun 		LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT;
630*4882a593Smuzhiyun 	ret = crport_ctrl_write(phy_drd,
631*4882a593Smuzhiyun 				EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN,
632*4882a593Smuzhiyun 				temp);
633*4882a593Smuzhiyun 	if (ret) {
634*4882a593Smuzhiyun 		dev_err(phy_drd->dev,
635*4882a593Smuzhiyun 			"Failed setting Loss-of-Signal level for SuperSpeed\n");
636*4882a593Smuzhiyun 		return ret;
637*4882a593Smuzhiyun 	}
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	/*
640*4882a593Smuzhiyun 	 * Set tx_vboost_lvl to (0x5) for 28nm PHY Tuning,
641*4882a593Smuzhiyun 	 * to raise Tx signal level from its default value of (0x4)
642*4882a593Smuzhiyun 	 */
643*4882a593Smuzhiyun 	temp = TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420;
644*4882a593Smuzhiyun 	ret = crport_ctrl_write(phy_drd,
645*4882a593Smuzhiyun 				EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN,
646*4882a593Smuzhiyun 				temp);
647*4882a593Smuzhiyun 	if (ret) {
648*4882a593Smuzhiyun 		dev_err(phy_drd->dev,
649*4882a593Smuzhiyun 			"Failed setting Tx-Vboost-Level for SuperSpeed\n");
650*4882a593Smuzhiyun 		return ret;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	/*
654*4882a593Smuzhiyun 	 * Set proper time to wait for RxDetect measurement, for
655*4882a593Smuzhiyun 	 * desired reference clock of PHY, by tuning the CR_PORT
656*4882a593Smuzhiyun 	 * register LANE0.TX_DEBUG which is internal to PHY.
657*4882a593Smuzhiyun 	 * This fixes issue with few USB 3.0 devices, which are
658*4882a593Smuzhiyun 	 * not detected (not even generate interrupts on the bus
659*4882a593Smuzhiyun 	 * on insertion) without this change.
660*4882a593Smuzhiyun 	 * e.g. Samsung SUM-TSB16S 3.0 USB drive.
661*4882a593Smuzhiyun 	 */
662*4882a593Smuzhiyun 	switch (phy_drd->extrefclk) {
663*4882a593Smuzhiyun 	case EXYNOS5_FSEL_50MHZ:
664*4882a593Smuzhiyun 		temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M;
665*4882a593Smuzhiyun 		break;
666*4882a593Smuzhiyun 	case EXYNOS5_FSEL_20MHZ:
667*4882a593Smuzhiyun 	case EXYNOS5_FSEL_19MHZ2:
668*4882a593Smuzhiyun 		temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M;
669*4882a593Smuzhiyun 		break;
670*4882a593Smuzhiyun 	case EXYNOS5_FSEL_24MHZ:
671*4882a593Smuzhiyun 	default:
672*4882a593Smuzhiyun 		temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M;
673*4882a593Smuzhiyun 		break;
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	ret = crport_ctrl_write(phy_drd,
677*4882a593Smuzhiyun 				EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG,
678*4882a593Smuzhiyun 				temp);
679*4882a593Smuzhiyun 	if (ret)
680*4882a593Smuzhiyun 		dev_err(phy_drd->dev,
681*4882a593Smuzhiyun 			"Fail to set RxDet measurement time for SuperSpeed\n");
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return ret;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
exynos5_usbdrd_phy_xlate(struct device * dev,struct of_phandle_args * args)686*4882a593Smuzhiyun static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
687*4882a593Smuzhiyun 					struct of_phandle_args *args)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
692*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	return phy_drd->phys[args->args[0]].phy;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
exynos5_usbdrd_phy_calibrate(struct phy * phy)697*4882a593Smuzhiyun static int exynos5_usbdrd_phy_calibrate(struct phy *phy)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	struct phy_usb_instance *inst = phy_get_drvdata(phy);
700*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI)
703*4882a593Smuzhiyun 		return exynos5420_usbdrd_phy_calibrate(phy_drd);
704*4882a593Smuzhiyun 	return 0;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun static const struct phy_ops exynos5_usbdrd_phy_ops = {
708*4882a593Smuzhiyun 	.init		= exynos5_usbdrd_phy_init,
709*4882a593Smuzhiyun 	.exit		= exynos5_usbdrd_phy_exit,
710*4882a593Smuzhiyun 	.power_on	= exynos5_usbdrd_phy_power_on,
711*4882a593Smuzhiyun 	.power_off	= exynos5_usbdrd_phy_power_off,
712*4882a593Smuzhiyun 	.calibrate	= exynos5_usbdrd_phy_calibrate,
713*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
714*4882a593Smuzhiyun };
715*4882a593Smuzhiyun 
exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy * phy_drd)716*4882a593Smuzhiyun static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun 	unsigned long ref_rate;
719*4882a593Smuzhiyun 	int ret;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
722*4882a593Smuzhiyun 	if (IS_ERR(phy_drd->clk)) {
723*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "Failed to get phy clock\n");
724*4882a593Smuzhiyun 		return PTR_ERR(phy_drd->clk);
725*4882a593Smuzhiyun 	}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
728*4882a593Smuzhiyun 	if (IS_ERR(phy_drd->ref_clk)) {
729*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
730*4882a593Smuzhiyun 		return PTR_ERR(phy_drd->ref_clk);
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 	ref_rate = clk_get_rate(phy_drd->ref_clk);
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
735*4882a593Smuzhiyun 	if (ret) {
736*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
737*4882a593Smuzhiyun 			ref_rate);
738*4882a593Smuzhiyun 		return ret;
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (!phy_drd->drv_data->has_common_clk_gate) {
742*4882a593Smuzhiyun 		phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
743*4882a593Smuzhiyun 		if (IS_ERR(phy_drd->pipeclk)) {
744*4882a593Smuzhiyun 			dev_info(phy_drd->dev,
745*4882a593Smuzhiyun 				 "PIPE3 phy operational clock not specified\n");
746*4882a593Smuzhiyun 			phy_drd->pipeclk = NULL;
747*4882a593Smuzhiyun 		}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 		phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
750*4882a593Smuzhiyun 		if (IS_ERR(phy_drd->utmiclk)) {
751*4882a593Smuzhiyun 			dev_info(phy_drd->dev,
752*4882a593Smuzhiyun 				 "UTMI phy operational clock not specified\n");
753*4882a593Smuzhiyun 			phy_drd->utmiclk = NULL;
754*4882a593Smuzhiyun 		}
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 		phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
757*4882a593Smuzhiyun 		if (IS_ERR(phy_drd->itpclk)) {
758*4882a593Smuzhiyun 			dev_info(phy_drd->dev,
759*4882a593Smuzhiyun 				 "ITP clock from main OSC not specified\n");
760*4882a593Smuzhiyun 			phy_drd->itpclk = NULL;
761*4882a593Smuzhiyun 		}
762*4882a593Smuzhiyun 	}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	return 0;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
768*4882a593Smuzhiyun 	{
769*4882a593Smuzhiyun 		.id		= EXYNOS5_DRDPHY_UTMI,
770*4882a593Smuzhiyun 		.phy_isol	= exynos5_usbdrd_phy_isol,
771*4882a593Smuzhiyun 		.phy_init	= exynos5_usbdrd_utmi_init,
772*4882a593Smuzhiyun 		.set_refclk	= exynos5_usbdrd_utmi_set_refclk,
773*4882a593Smuzhiyun 	},
774*4882a593Smuzhiyun 	{
775*4882a593Smuzhiyun 		.id		= EXYNOS5_DRDPHY_PIPE3,
776*4882a593Smuzhiyun 		.phy_isol	= exynos5_usbdrd_phy_isol,
777*4882a593Smuzhiyun 		.phy_init	= exynos5_usbdrd_pipe3_init,
778*4882a593Smuzhiyun 		.set_refclk	= exynos5_usbdrd_pipe3_set_refclk,
779*4882a593Smuzhiyun 	},
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
783*4882a593Smuzhiyun 	.phy_cfg		= phy_cfg_exynos5,
784*4882a593Smuzhiyun 	.pmu_offset_usbdrd0_phy	= EXYNOS5_USBDRD_PHY_CONTROL,
785*4882a593Smuzhiyun 	.pmu_offset_usbdrd1_phy	= EXYNOS5420_USBDRD1_PHY_CONTROL,
786*4882a593Smuzhiyun 	.has_common_clk_gate	= true,
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
790*4882a593Smuzhiyun 	.phy_cfg		= phy_cfg_exynos5,
791*4882a593Smuzhiyun 	.pmu_offset_usbdrd0_phy	= EXYNOS5_USBDRD_PHY_CONTROL,
792*4882a593Smuzhiyun 	.has_common_clk_gate	= true,
793*4882a593Smuzhiyun };
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
796*4882a593Smuzhiyun 	.phy_cfg		= phy_cfg_exynos5,
797*4882a593Smuzhiyun 	.pmu_offset_usbdrd0_phy	= EXYNOS5_USBDRD_PHY_CONTROL,
798*4882a593Smuzhiyun 	.pmu_offset_usbdrd1_phy	= EXYNOS5433_USBHOST30_PHY_CONTROL,
799*4882a593Smuzhiyun 	.has_common_clk_gate	= false,
800*4882a593Smuzhiyun };
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
803*4882a593Smuzhiyun 	.phy_cfg		= phy_cfg_exynos5,
804*4882a593Smuzhiyun 	.pmu_offset_usbdrd0_phy	= EXYNOS5_USBDRD_PHY_CONTROL,
805*4882a593Smuzhiyun 	.has_common_clk_gate	= false,
806*4882a593Smuzhiyun };
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
809*4882a593Smuzhiyun 	{
810*4882a593Smuzhiyun 		.compatible = "samsung,exynos5250-usbdrd-phy",
811*4882a593Smuzhiyun 		.data = &exynos5250_usbdrd_phy
812*4882a593Smuzhiyun 	}, {
813*4882a593Smuzhiyun 		.compatible = "samsung,exynos5420-usbdrd-phy",
814*4882a593Smuzhiyun 		.data = &exynos5420_usbdrd_phy
815*4882a593Smuzhiyun 	}, {
816*4882a593Smuzhiyun 		.compatible = "samsung,exynos5433-usbdrd-phy",
817*4882a593Smuzhiyun 		.data = &exynos5433_usbdrd_phy
818*4882a593Smuzhiyun 	}, {
819*4882a593Smuzhiyun 		.compatible = "samsung,exynos7-usbdrd-phy",
820*4882a593Smuzhiyun 		.data = &exynos7_usbdrd_phy
821*4882a593Smuzhiyun 	},
822*4882a593Smuzhiyun 	{ },
823*4882a593Smuzhiyun };
824*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, exynos5_usbdrd_phy_of_match);
825*4882a593Smuzhiyun 
exynos5_usbdrd_phy_probe(struct platform_device * pdev)826*4882a593Smuzhiyun static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
829*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
830*4882a593Smuzhiyun 	struct exynos5_usbdrd_phy *phy_drd;
831*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
832*4882a593Smuzhiyun 	struct resource *res;
833*4882a593Smuzhiyun 	const struct exynos5_usbdrd_phy_drvdata *drv_data;
834*4882a593Smuzhiyun 	struct regmap *reg_pmu;
835*4882a593Smuzhiyun 	u32 pmu_offset;
836*4882a593Smuzhiyun 	int i, ret;
837*4882a593Smuzhiyun 	int channel;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL);
840*4882a593Smuzhiyun 	if (!phy_drd)
841*4882a593Smuzhiyun 		return -ENOMEM;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	dev_set_drvdata(dev, phy_drd);
844*4882a593Smuzhiyun 	phy_drd->dev = dev;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
847*4882a593Smuzhiyun 	phy_drd->reg_phy = devm_ioremap_resource(dev, res);
848*4882a593Smuzhiyun 	if (IS_ERR(phy_drd->reg_phy))
849*4882a593Smuzhiyun 		return PTR_ERR(phy_drd->reg_phy);
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	drv_data = of_device_get_match_data(dev);
852*4882a593Smuzhiyun 	if (!drv_data)
853*4882a593Smuzhiyun 		return -EINVAL;
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	phy_drd->drv_data = drv_data;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
858*4882a593Smuzhiyun 	if (ret) {
859*4882a593Smuzhiyun 		dev_err(dev, "Failed to initialize clocks\n");
860*4882a593Smuzhiyun 		return ret;
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
864*4882a593Smuzhiyun 						   "samsung,pmu-syscon");
865*4882a593Smuzhiyun 	if (IS_ERR(reg_pmu)) {
866*4882a593Smuzhiyun 		dev_err(dev, "Failed to lookup PMU regmap\n");
867*4882a593Smuzhiyun 		return PTR_ERR(reg_pmu);
868*4882a593Smuzhiyun 	}
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	/*
871*4882a593Smuzhiyun 	 * Exynos5420 SoC has multiple channels for USB 3.0 PHY, with
872*4882a593Smuzhiyun 	 * each having separate power control registers.
873*4882a593Smuzhiyun 	 * 'channel' facilitates to set such registers.
874*4882a593Smuzhiyun 	 */
875*4882a593Smuzhiyun 	channel = of_alias_get_id(node, "usbdrdphy");
876*4882a593Smuzhiyun 	if (channel < 0)
877*4882a593Smuzhiyun 		dev_dbg(dev, "Not a multi-controller usbdrd phy\n");
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	switch (channel) {
880*4882a593Smuzhiyun 	case 1:
881*4882a593Smuzhiyun 		pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy;
882*4882a593Smuzhiyun 		break;
883*4882a593Smuzhiyun 	case 0:
884*4882a593Smuzhiyun 	default:
885*4882a593Smuzhiyun 		pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy;
886*4882a593Smuzhiyun 		break;
887*4882a593Smuzhiyun 	}
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* Get Vbus regulators */
890*4882a593Smuzhiyun 	phy_drd->vbus = devm_regulator_get(dev, "vbus");
891*4882a593Smuzhiyun 	if (IS_ERR(phy_drd->vbus)) {
892*4882a593Smuzhiyun 		ret = PTR_ERR(phy_drd->vbus);
893*4882a593Smuzhiyun 		if (ret == -EPROBE_DEFER)
894*4882a593Smuzhiyun 			return ret;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 		dev_warn(dev, "Failed to get VBUS supply regulator\n");
897*4882a593Smuzhiyun 		phy_drd->vbus = NULL;
898*4882a593Smuzhiyun 	}
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
901*4882a593Smuzhiyun 	if (IS_ERR(phy_drd->vbus_boost)) {
902*4882a593Smuzhiyun 		ret = PTR_ERR(phy_drd->vbus_boost);
903*4882a593Smuzhiyun 		if (ret == -EPROBE_DEFER)
904*4882a593Smuzhiyun 			return ret;
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 		dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
907*4882a593Smuzhiyun 		phy_drd->vbus_boost = NULL;
908*4882a593Smuzhiyun 	}
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	dev_vdbg(dev, "Creating usbdrd_phy phy\n");
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
913*4882a593Smuzhiyun 		struct phy *phy = devm_phy_create(dev, NULL,
914*4882a593Smuzhiyun 						  &exynos5_usbdrd_phy_ops);
915*4882a593Smuzhiyun 		if (IS_ERR(phy)) {
916*4882a593Smuzhiyun 			dev_err(dev, "Failed to create usbdrd_phy phy\n");
917*4882a593Smuzhiyun 			return PTR_ERR(phy);
918*4882a593Smuzhiyun 		}
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 		phy_drd->phys[i].phy = phy;
921*4882a593Smuzhiyun 		phy_drd->phys[i].index = i;
922*4882a593Smuzhiyun 		phy_drd->phys[i].reg_pmu = reg_pmu;
923*4882a593Smuzhiyun 		phy_drd->phys[i].pmu_offset = pmu_offset;
924*4882a593Smuzhiyun 		phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
925*4882a593Smuzhiyun 		phy_set_drvdata(phy, &phy_drd->phys[i]);
926*4882a593Smuzhiyun 	}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(dev,
929*4882a593Smuzhiyun 						     exynos5_usbdrd_phy_xlate);
930*4882a593Smuzhiyun 	if (IS_ERR(phy_provider)) {
931*4882a593Smuzhiyun 		dev_err(phy_drd->dev, "Failed to register phy provider\n");
932*4882a593Smuzhiyun 		return PTR_ERR(phy_provider);
933*4882a593Smuzhiyun 	}
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	return 0;
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun static struct platform_driver exynos5_usb3drd_phy = {
939*4882a593Smuzhiyun 	.probe	= exynos5_usbdrd_phy_probe,
940*4882a593Smuzhiyun 	.driver = {
941*4882a593Smuzhiyun 		.of_match_table	= exynos5_usbdrd_phy_of_match,
942*4882a593Smuzhiyun 		.name		= "exynos5_usb3drd_phy",
943*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
944*4882a593Smuzhiyun 	}
945*4882a593Smuzhiyun };
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun module_platform_driver(exynos5_usb3drd_phy);
948*4882a593Smuzhiyun MODULE_DESCRIPTION("Samsung Exynos5 SoCs USB 3.0 DRD controller PHY driver");
949*4882a593Smuzhiyun MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
950*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
951*4882a593Smuzhiyun MODULE_ALIAS("platform:exynos5_usb3drd_phy");
952