xref: /OK3568_Linux_fs/kernel/drivers/phy/samsung/phy-exynos4210-usb2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
6*4882a593Smuzhiyun  * Author: Kamil Debski <k.debski@samsung.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/phy/phy.h>
12*4882a593Smuzhiyun #include <linux/regmap.h>
13*4882a593Smuzhiyun #include "phy-samsung-usb2.h"
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* Exynos USB PHY registers */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* PHY power control */
18*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR			0x0
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	BIT(0)
21*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY0_PWR		BIT(3)
22*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	BIT(4)
23*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		BIT(5)
24*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY0	( \
25*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
26*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
27*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
28*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	BIT(6)
31*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY1_PWR		BIT(7)
32*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		BIT(8)
33*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_PHY1 ( \
34*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
35*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
36*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND	BIT(9)
39*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP		BIT(10)
40*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC0 ( \
41*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
42*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND	BIT(11)
45*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP		BIT(12)
46*4882a593Smuzhiyun #define EXYNOS_4210_UPHYPWR_HSIC1 ( \
47*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
48*4882a593Smuzhiyun 	EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* PHY clock control */
51*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK			0x4
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
54*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET	0
55*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
56*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
57*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	BIT(2)
60*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	BIT(4)
61*4882a593Smuzhiyun #define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	BIT(7)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /* PHY reset control */
64*4882a593Smuzhiyun #define EXYNOS_4210_UPHYRST			0x8
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_PHY0		BIT(0)
67*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_OTG_HLINK		BIT(1)
68*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_OTG_PHYLINK		BIT(2)
69*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_PHY1_ALL		BIT(3)
70*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_PHY1_P0		BIT(4)
71*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_PHY1_P1P2		BIT(5)
72*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_HOST_LINK_ALL	BIT(6)
73*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_HOST_LINK_P0	BIT(7)
74*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_HOST_LINK_P1	BIT(8)
75*4882a593Smuzhiyun #define EXYNOS_4210_URSTCON_HOST_LINK_P2	BIT(9)
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* Isolation, configured in the power management unit */
78*4882a593Smuzhiyun #define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
79*4882a593Smuzhiyun #define EXYNOS_4210_USB_ISOL_DEVICE		BIT(0)
80*4882a593Smuzhiyun #define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
81*4882a593Smuzhiyun #define EXYNOS_4210_USB_ISOL_HOST		BIT(0)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /* USBYPHY1 Floating prevention */
84*4882a593Smuzhiyun #define EXYNOS_4210_UPHY1CON			0x34
85*4882a593Smuzhiyun #define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /* Mode switching SUB Device <-> Host */
88*4882a593Smuzhiyun #define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
89*4882a593Smuzhiyun #define EXYNOS_4210_MODE_SWITCH_MASK		1
90*4882a593Smuzhiyun #define EXYNOS_4210_MODE_SWITCH_DEVICE		0
91*4882a593Smuzhiyun #define EXYNOS_4210_MODE_SWITCH_HOST		1
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun enum exynos4210_phy_id {
94*4882a593Smuzhiyun 	EXYNOS4210_DEVICE,
95*4882a593Smuzhiyun 	EXYNOS4210_HOST,
96*4882a593Smuzhiyun 	EXYNOS4210_HSIC0,
97*4882a593Smuzhiyun 	EXYNOS4210_HSIC1,
98*4882a593Smuzhiyun 	EXYNOS4210_NUM_PHYS,
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun  * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
103*4882a593Smuzhiyun  * can be written to the phy register.
104*4882a593Smuzhiyun  */
exynos4210_rate_to_clk(unsigned long rate,u32 * reg)105*4882a593Smuzhiyun static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	switch (rate) {
108*4882a593Smuzhiyun 	case 12 * MHZ:
109*4882a593Smuzhiyun 		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
110*4882a593Smuzhiyun 		break;
111*4882a593Smuzhiyun 	case 24 * MHZ:
112*4882a593Smuzhiyun 		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
113*4882a593Smuzhiyun 		break;
114*4882a593Smuzhiyun 	case 48 * MHZ:
115*4882a593Smuzhiyun 		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
116*4882a593Smuzhiyun 		break;
117*4882a593Smuzhiyun 	default:
118*4882a593Smuzhiyun 		return -EINVAL;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
exynos4210_isol(struct samsung_usb2_phy_instance * inst,bool on)124*4882a593Smuzhiyun static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct samsung_usb2_phy_driver *drv = inst->drv;
127*4882a593Smuzhiyun 	u32 offset;
128*4882a593Smuzhiyun 	u32 mask;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	switch (inst->cfg->id) {
131*4882a593Smuzhiyun 	case EXYNOS4210_DEVICE:
132*4882a593Smuzhiyun 		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
133*4882a593Smuzhiyun 		mask = EXYNOS_4210_USB_ISOL_DEVICE;
134*4882a593Smuzhiyun 		break;
135*4882a593Smuzhiyun 	case EXYNOS4210_HOST:
136*4882a593Smuzhiyun 		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
137*4882a593Smuzhiyun 		mask = EXYNOS_4210_USB_ISOL_HOST;
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 	default:
140*4882a593Smuzhiyun 		return;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
exynos4210_phy_pwr(struct samsung_usb2_phy_instance * inst,bool on)146*4882a593Smuzhiyun static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct samsung_usb2_phy_driver *drv = inst->drv;
149*4882a593Smuzhiyun 	u32 rstbits = 0;
150*4882a593Smuzhiyun 	u32 phypwr = 0;
151*4882a593Smuzhiyun 	u32 rst;
152*4882a593Smuzhiyun 	u32 pwr;
153*4882a593Smuzhiyun 	u32 clk;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	switch (inst->cfg->id) {
156*4882a593Smuzhiyun 	case EXYNOS4210_DEVICE:
157*4882a593Smuzhiyun 		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
158*4882a593Smuzhiyun 		rstbits =	EXYNOS_4210_URSTCON_PHY0;
159*4882a593Smuzhiyun 		break;
160*4882a593Smuzhiyun 	case EXYNOS4210_HOST:
161*4882a593Smuzhiyun 		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
162*4882a593Smuzhiyun 		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
163*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_PHY1_P0 |
164*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_PHY1_P1P2 |
165*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
166*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_HOST_LINK_P0;
167*4882a593Smuzhiyun 		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
168*4882a593Smuzhiyun 		break;
169*4882a593Smuzhiyun 	case EXYNOS4210_HSIC0:
170*4882a593Smuzhiyun 		phypwr =	EXYNOS_4210_UPHYPWR_HSIC0;
171*4882a593Smuzhiyun 		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
172*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_HOST_LINK_P1;
173*4882a593Smuzhiyun 		break;
174*4882a593Smuzhiyun 	case EXYNOS4210_HSIC1:
175*4882a593Smuzhiyun 		phypwr =	EXYNOS_4210_UPHYPWR_HSIC1;
176*4882a593Smuzhiyun 		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
177*4882a593Smuzhiyun 				EXYNOS_4210_URSTCON_HOST_LINK_P2;
178*4882a593Smuzhiyun 		break;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (on) {
182*4882a593Smuzhiyun 		clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
183*4882a593Smuzhiyun 		clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
184*4882a593Smuzhiyun 		clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
185*4882a593Smuzhiyun 		writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
188*4882a593Smuzhiyun 		pwr &= ~phypwr;
189*4882a593Smuzhiyun 		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
192*4882a593Smuzhiyun 		rst |= rstbits;
193*4882a593Smuzhiyun 		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
194*4882a593Smuzhiyun 		udelay(10);
195*4882a593Smuzhiyun 		rst &= ~rstbits;
196*4882a593Smuzhiyun 		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
197*4882a593Smuzhiyun 		/* The following delay is necessary for the reset sequence to be
198*4882a593Smuzhiyun 		 * completed */
199*4882a593Smuzhiyun 		udelay(80);
200*4882a593Smuzhiyun 	} else {
201*4882a593Smuzhiyun 		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
202*4882a593Smuzhiyun 		pwr |= phypwr;
203*4882a593Smuzhiyun 		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
exynos4210_power_on(struct samsung_usb2_phy_instance * inst)207*4882a593Smuzhiyun static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	/* Order of initialisation is important - first power then isolation */
210*4882a593Smuzhiyun 	exynos4210_phy_pwr(inst, 1);
211*4882a593Smuzhiyun 	exynos4210_isol(inst, 0);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
exynos4210_power_off(struct samsung_usb2_phy_instance * inst)216*4882a593Smuzhiyun static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	exynos4210_isol(inst, 1);
219*4882a593Smuzhiyun 	exynos4210_phy_pwr(inst, 0);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun static const struct samsung_usb2_common_phy exynos4210_phys[] = {
226*4882a593Smuzhiyun 	{
227*4882a593Smuzhiyun 		.label		= "device",
228*4882a593Smuzhiyun 		.id		= EXYNOS4210_DEVICE,
229*4882a593Smuzhiyun 		.power_on	= exynos4210_power_on,
230*4882a593Smuzhiyun 		.power_off	= exynos4210_power_off,
231*4882a593Smuzhiyun 	},
232*4882a593Smuzhiyun 	{
233*4882a593Smuzhiyun 		.label		= "host",
234*4882a593Smuzhiyun 		.id		= EXYNOS4210_HOST,
235*4882a593Smuzhiyun 		.power_on	= exynos4210_power_on,
236*4882a593Smuzhiyun 		.power_off	= exynos4210_power_off,
237*4882a593Smuzhiyun 	},
238*4882a593Smuzhiyun 	{
239*4882a593Smuzhiyun 		.label		= "hsic0",
240*4882a593Smuzhiyun 		.id		= EXYNOS4210_HSIC0,
241*4882a593Smuzhiyun 		.power_on	= exynos4210_power_on,
242*4882a593Smuzhiyun 		.power_off	= exynos4210_power_off,
243*4882a593Smuzhiyun 	},
244*4882a593Smuzhiyun 	{
245*4882a593Smuzhiyun 		.label		= "hsic1",
246*4882a593Smuzhiyun 		.id		= EXYNOS4210_HSIC1,
247*4882a593Smuzhiyun 		.power_on	= exynos4210_power_on,
248*4882a593Smuzhiyun 		.power_off	= exynos4210_power_off,
249*4882a593Smuzhiyun 	},
250*4882a593Smuzhiyun };
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
253*4882a593Smuzhiyun 	.has_mode_switch	= 0,
254*4882a593Smuzhiyun 	.num_phys		= EXYNOS4210_NUM_PHYS,
255*4882a593Smuzhiyun 	.phys			= exynos4210_phys,
256*4882a593Smuzhiyun 	.rate_to_clk		= exynos4210_rate_to_clk,
257*4882a593Smuzhiyun };
258