xref: /OK3568_Linux_fs/kernel/drivers/usb/host/xhci-mtk.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * MediaTek xHCI Host Controller Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2015 MediaTek Inc.
6*4882a593Smuzhiyun  * Author:
7*4882a593Smuzhiyun  *  Chunfeng Yun <chunfeng.yun@mediatek.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/dma-mapping.h>
12*4882a593Smuzhiyun #include <linux/iopoll.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/pm_runtime.h>
19*4882a593Smuzhiyun #include <linux/regmap.h>
20*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "xhci.h"
23*4882a593Smuzhiyun #include "xhci-mtk.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* ip_pw_ctrl0 register */
26*4882a593Smuzhiyun #define CTRL0_IP_SW_RST	BIT(0)
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* ip_pw_ctrl1 register */
29*4882a593Smuzhiyun #define CTRL1_IP_HOST_PDN	BIT(0)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* ip_pw_ctrl2 register */
32*4882a593Smuzhiyun #define CTRL2_IP_DEV_PDN	BIT(0)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* ip_pw_sts1 register */
35*4882a593Smuzhiyun #define STS1_IP_SLEEP_STS	BIT(30)
36*4882a593Smuzhiyun #define STS1_U3_MAC_RST	BIT(16)
37*4882a593Smuzhiyun #define STS1_XHCI_RST		BIT(11)
38*4882a593Smuzhiyun #define STS1_SYS125_RST	BIT(10)
39*4882a593Smuzhiyun #define STS1_REF_RST		BIT(8)
40*4882a593Smuzhiyun #define STS1_SYSPLL_STABLE	BIT(0)
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /* ip_xhci_cap register */
43*4882a593Smuzhiyun #define CAP_U3_PORT_NUM(p)	((p) & 0xff)
44*4882a593Smuzhiyun #define CAP_U2_PORT_NUM(p)	(((p) >> 8) & 0xff)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* u3_ctrl_p register */
47*4882a593Smuzhiyun #define CTRL_U3_PORT_HOST_SEL	BIT(2)
48*4882a593Smuzhiyun #define CTRL_U3_PORT_PDN	BIT(1)
49*4882a593Smuzhiyun #define CTRL_U3_PORT_DIS	BIT(0)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* u2_ctrl_p register */
52*4882a593Smuzhiyun #define CTRL_U2_PORT_HOST_SEL	BIT(2)
53*4882a593Smuzhiyun #define CTRL_U2_PORT_PDN	BIT(1)
54*4882a593Smuzhiyun #define CTRL_U2_PORT_DIS	BIT(0)
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /* u2_phy_pll register */
57*4882a593Smuzhiyun #define CTRL_U2_FORCE_PLL_STB	BIT(28)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* usb remote wakeup registers in syscon */
60*4882a593Smuzhiyun /* mt8173 etc */
61*4882a593Smuzhiyun #define PERI_WK_CTRL1	0x4
62*4882a593Smuzhiyun #define WC1_IS_C(x)	(((x) & 0xf) << 26)  /* cycle debounce */
63*4882a593Smuzhiyun #define WC1_IS_EN	BIT(25)
64*4882a593Smuzhiyun #define WC1_IS_P	BIT(6)  /* polarity for ip sleep */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* mt2712 etc */
67*4882a593Smuzhiyun #define PERI_SSUSB_SPM_CTRL	0x0
68*4882a593Smuzhiyun #define SSC_IP_SLEEP_EN	BIT(4)
69*4882a593Smuzhiyun #define SSC_SPM_INT_EN		BIT(1)
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun enum ssusb_uwk_vers {
72*4882a593Smuzhiyun 	SSUSB_UWK_V1 = 1,
73*4882a593Smuzhiyun 	SSUSB_UWK_V2,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun 
xhci_mtk_host_enable(struct xhci_hcd_mtk * mtk)76*4882a593Smuzhiyun static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
79*4882a593Smuzhiyun 	u32 value, check_val;
80*4882a593Smuzhiyun 	int u3_ports_disabled = 0;
81*4882a593Smuzhiyun 	int ret;
82*4882a593Smuzhiyun 	int i;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (!mtk->has_ippc)
85*4882a593Smuzhiyun 		return 0;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* power on host ip */
88*4882a593Smuzhiyun 	value = readl(&ippc->ip_pw_ctr1);
89*4882a593Smuzhiyun 	value &= ~CTRL1_IP_HOST_PDN;
90*4882a593Smuzhiyun 	writel(value, &ippc->ip_pw_ctr1);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* power on and enable u3 ports except skipped ones */
93*4882a593Smuzhiyun 	for (i = 0; i < mtk->num_u3_ports; i++) {
94*4882a593Smuzhiyun 		if ((0x1 << i) & mtk->u3p_dis_msk) {
95*4882a593Smuzhiyun 			u3_ports_disabled++;
96*4882a593Smuzhiyun 			continue;
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		value = readl(&ippc->u3_ctrl_p[i]);
100*4882a593Smuzhiyun 		value &= ~(CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS);
101*4882a593Smuzhiyun 		value |= CTRL_U3_PORT_HOST_SEL;
102*4882a593Smuzhiyun 		writel(value, &ippc->u3_ctrl_p[i]);
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* power on and enable all u2 ports */
106*4882a593Smuzhiyun 	for (i = 0; i < mtk->num_u2_ports; i++) {
107*4882a593Smuzhiyun 		value = readl(&ippc->u2_ctrl_p[i]);
108*4882a593Smuzhiyun 		value &= ~(CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS);
109*4882a593Smuzhiyun 		value |= CTRL_U2_PORT_HOST_SEL;
110*4882a593Smuzhiyun 		writel(value, &ippc->u2_ctrl_p[i]);
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/*
114*4882a593Smuzhiyun 	 * wait for clocks to be stable, and clock domains reset to
115*4882a593Smuzhiyun 	 * be inactive after power on and enable ports
116*4882a593Smuzhiyun 	 */
117*4882a593Smuzhiyun 	check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
118*4882a593Smuzhiyun 			STS1_SYS125_RST | STS1_XHCI_RST;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (mtk->num_u3_ports > u3_ports_disabled)
121*4882a593Smuzhiyun 		check_val |= STS1_U3_MAC_RST;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
124*4882a593Smuzhiyun 			  (check_val == (value & check_val)), 100, 20000);
125*4882a593Smuzhiyun 	if (ret) {
126*4882a593Smuzhiyun 		dev_err(mtk->dev, "clocks are not stable (0x%x)\n", value);
127*4882a593Smuzhiyun 		return ret;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
xhci_mtk_host_disable(struct xhci_hcd_mtk * mtk)133*4882a593Smuzhiyun static int xhci_mtk_host_disable(struct xhci_hcd_mtk *mtk)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
136*4882a593Smuzhiyun 	u32 value;
137*4882a593Smuzhiyun 	int ret;
138*4882a593Smuzhiyun 	int i;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (!mtk->has_ippc)
141*4882a593Smuzhiyun 		return 0;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* power down u3 ports except skipped ones */
144*4882a593Smuzhiyun 	for (i = 0; i < mtk->num_u3_ports; i++) {
145*4882a593Smuzhiyun 		if ((0x1 << i) & mtk->u3p_dis_msk)
146*4882a593Smuzhiyun 			continue;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 		value = readl(&ippc->u3_ctrl_p[i]);
149*4882a593Smuzhiyun 		value |= CTRL_U3_PORT_PDN;
150*4882a593Smuzhiyun 		writel(value, &ippc->u3_ctrl_p[i]);
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* power down all u2 ports */
154*4882a593Smuzhiyun 	for (i = 0; i < mtk->num_u2_ports; i++) {
155*4882a593Smuzhiyun 		value = readl(&ippc->u2_ctrl_p[i]);
156*4882a593Smuzhiyun 		value |= CTRL_U2_PORT_PDN;
157*4882a593Smuzhiyun 		writel(value, &ippc->u2_ctrl_p[i]);
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* power down host ip */
161*4882a593Smuzhiyun 	value = readl(&ippc->ip_pw_ctr1);
162*4882a593Smuzhiyun 	value |= CTRL1_IP_HOST_PDN;
163*4882a593Smuzhiyun 	writel(value, &ippc->ip_pw_ctr1);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* wait for host ip to sleep */
166*4882a593Smuzhiyun 	ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
167*4882a593Smuzhiyun 			  (value & STS1_IP_SLEEP_STS), 100, 100000);
168*4882a593Smuzhiyun 	if (ret) {
169*4882a593Smuzhiyun 		dev_err(mtk->dev, "ip sleep failed!!!\n");
170*4882a593Smuzhiyun 		return ret;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
xhci_mtk_ssusb_config(struct xhci_hcd_mtk * mtk)175*4882a593Smuzhiyun static int xhci_mtk_ssusb_config(struct xhci_hcd_mtk *mtk)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
178*4882a593Smuzhiyun 	u32 value;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (!mtk->has_ippc)
181*4882a593Smuzhiyun 		return 0;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* reset whole ip */
184*4882a593Smuzhiyun 	value = readl(&ippc->ip_pw_ctr0);
185*4882a593Smuzhiyun 	value |= CTRL0_IP_SW_RST;
186*4882a593Smuzhiyun 	writel(value, &ippc->ip_pw_ctr0);
187*4882a593Smuzhiyun 	udelay(1);
188*4882a593Smuzhiyun 	value = readl(&ippc->ip_pw_ctr0);
189*4882a593Smuzhiyun 	value &= ~CTRL0_IP_SW_RST;
190*4882a593Smuzhiyun 	writel(value, &ippc->ip_pw_ctr0);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	/*
193*4882a593Smuzhiyun 	 * device ip is default power-on in fact
194*4882a593Smuzhiyun 	 * power down device ip, otherwise ip-sleep will fail
195*4882a593Smuzhiyun 	 */
196*4882a593Smuzhiyun 	value = readl(&ippc->ip_pw_ctr2);
197*4882a593Smuzhiyun 	value |= CTRL2_IP_DEV_PDN;
198*4882a593Smuzhiyun 	writel(value, &ippc->ip_pw_ctr2);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	value = readl(&ippc->ip_xhci_cap);
201*4882a593Smuzhiyun 	mtk->num_u3_ports = CAP_U3_PORT_NUM(value);
202*4882a593Smuzhiyun 	mtk->num_u2_ports = CAP_U2_PORT_NUM(value);
203*4882a593Smuzhiyun 	dev_dbg(mtk->dev, "%s u2p:%d, u3p:%d\n", __func__,
204*4882a593Smuzhiyun 			mtk->num_u2_ports, mtk->num_u3_ports);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return xhci_mtk_host_enable(mtk);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
xhci_mtk_clks_get(struct xhci_hcd_mtk * mtk)209*4882a593Smuzhiyun static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct device *dev = mtk->dev;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	mtk->sys_clk = devm_clk_get(dev, "sys_ck");
214*4882a593Smuzhiyun 	if (IS_ERR(mtk->sys_clk)) {
215*4882a593Smuzhiyun 		dev_err(dev, "fail to get sys_ck\n");
216*4882a593Smuzhiyun 		return PTR_ERR(mtk->sys_clk);
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	mtk->xhci_clk = devm_clk_get_optional(dev, "xhci_ck");
220*4882a593Smuzhiyun 	if (IS_ERR(mtk->xhci_clk))
221*4882a593Smuzhiyun 		return PTR_ERR(mtk->xhci_clk);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	mtk->ref_clk = devm_clk_get_optional(dev, "ref_ck");
224*4882a593Smuzhiyun 	if (IS_ERR(mtk->ref_clk))
225*4882a593Smuzhiyun 		return PTR_ERR(mtk->ref_clk);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	mtk->mcu_clk = devm_clk_get_optional(dev, "mcu_ck");
228*4882a593Smuzhiyun 	if (IS_ERR(mtk->mcu_clk))
229*4882a593Smuzhiyun 		return PTR_ERR(mtk->mcu_clk);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	mtk->dma_clk = devm_clk_get_optional(dev, "dma_ck");
232*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(mtk->dma_clk);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
xhci_mtk_clks_enable(struct xhci_hcd_mtk * mtk)235*4882a593Smuzhiyun static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	int ret;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	ret = clk_prepare_enable(mtk->ref_clk);
240*4882a593Smuzhiyun 	if (ret) {
241*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable ref_clk\n");
242*4882a593Smuzhiyun 		goto ref_clk_err;
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	ret = clk_prepare_enable(mtk->sys_clk);
246*4882a593Smuzhiyun 	if (ret) {
247*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable sys_clk\n");
248*4882a593Smuzhiyun 		goto sys_clk_err;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	ret = clk_prepare_enable(mtk->xhci_clk);
252*4882a593Smuzhiyun 	if (ret) {
253*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable xhci_clk\n");
254*4882a593Smuzhiyun 		goto xhci_clk_err;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	ret = clk_prepare_enable(mtk->mcu_clk);
258*4882a593Smuzhiyun 	if (ret) {
259*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable mcu_clk\n");
260*4882a593Smuzhiyun 		goto mcu_clk_err;
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	ret = clk_prepare_enable(mtk->dma_clk);
264*4882a593Smuzhiyun 	if (ret) {
265*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable dma_clk\n");
266*4882a593Smuzhiyun 		goto dma_clk_err;
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	return 0;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun dma_clk_err:
272*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->mcu_clk);
273*4882a593Smuzhiyun mcu_clk_err:
274*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->xhci_clk);
275*4882a593Smuzhiyun xhci_clk_err:
276*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->sys_clk);
277*4882a593Smuzhiyun sys_clk_err:
278*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->ref_clk);
279*4882a593Smuzhiyun ref_clk_err:
280*4882a593Smuzhiyun 	return ret;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
xhci_mtk_clks_disable(struct xhci_hcd_mtk * mtk)283*4882a593Smuzhiyun static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->dma_clk);
286*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->mcu_clk);
287*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->xhci_clk);
288*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->sys_clk);
289*4882a593Smuzhiyun 	clk_disable_unprepare(mtk->ref_clk);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun /* only clocks can be turn off for ip-sleep wakeup mode */
usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk * mtk,bool enable)293*4882a593Smuzhiyun static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	u32 reg, msk, val;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	switch (mtk->uwk_vers) {
298*4882a593Smuzhiyun 	case SSUSB_UWK_V1:
299*4882a593Smuzhiyun 		reg = mtk->uwk_reg_base + PERI_WK_CTRL1;
300*4882a593Smuzhiyun 		msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P;
301*4882a593Smuzhiyun 		val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0;
302*4882a593Smuzhiyun 		break;
303*4882a593Smuzhiyun 	case SSUSB_UWK_V2:
304*4882a593Smuzhiyun 		reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
305*4882a593Smuzhiyun 		msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
306*4882a593Smuzhiyun 		val = enable ? msk : 0;
307*4882a593Smuzhiyun 		break;
308*4882a593Smuzhiyun 	default:
309*4882a593Smuzhiyun 		return;
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 	regmap_update_bits(mtk->uwk, reg, msk, val);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
usb_wakeup_of_property_parse(struct xhci_hcd_mtk * mtk,struct device_node * dn)314*4882a593Smuzhiyun static int usb_wakeup_of_property_parse(struct xhci_hcd_mtk *mtk,
315*4882a593Smuzhiyun 				struct device_node *dn)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	struct of_phandle_args args;
318*4882a593Smuzhiyun 	int ret;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	/* Wakeup function is optional */
321*4882a593Smuzhiyun 	mtk->uwk_en = of_property_read_bool(dn, "wakeup-source");
322*4882a593Smuzhiyun 	if (!mtk->uwk_en)
323*4882a593Smuzhiyun 		return 0;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	ret = of_parse_phandle_with_fixed_args(dn,
326*4882a593Smuzhiyun 				"mediatek,syscon-wakeup", 2, 0, &args);
327*4882a593Smuzhiyun 	if (ret)
328*4882a593Smuzhiyun 		return ret;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	mtk->uwk_reg_base = args.args[0];
331*4882a593Smuzhiyun 	mtk->uwk_vers = args.args[1];
332*4882a593Smuzhiyun 	mtk->uwk = syscon_node_to_regmap(args.np);
333*4882a593Smuzhiyun 	of_node_put(args.np);
334*4882a593Smuzhiyun 	dev_info(mtk->dev, "uwk - reg:0x%x, version:%d\n",
335*4882a593Smuzhiyun 			mtk->uwk_reg_base, mtk->uwk_vers);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(mtk->uwk);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
usb_wakeup_set(struct xhci_hcd_mtk * mtk,bool enable)341*4882a593Smuzhiyun static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	if (mtk->uwk_en)
344*4882a593Smuzhiyun 		usb_wakeup_ip_sleep_set(mtk, enable);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
xhci_mtk_ldos_enable(struct xhci_hcd_mtk * mtk)347*4882a593Smuzhiyun static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	int ret;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ret = regulator_enable(mtk->vbus);
352*4882a593Smuzhiyun 	if (ret) {
353*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable vbus\n");
354*4882a593Smuzhiyun 		return ret;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	ret = regulator_enable(mtk->vusb33);
358*4882a593Smuzhiyun 	if (ret) {
359*4882a593Smuzhiyun 		dev_err(mtk->dev, "failed to enable vusb33\n");
360*4882a593Smuzhiyun 		regulator_disable(mtk->vbus);
361*4882a593Smuzhiyun 		return ret;
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun 	return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
xhci_mtk_ldos_disable(struct xhci_hcd_mtk * mtk)366*4882a593Smuzhiyun static void xhci_mtk_ldos_disable(struct xhci_hcd_mtk *mtk)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	regulator_disable(mtk->vbus);
369*4882a593Smuzhiyun 	regulator_disable(mtk->vusb33);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
xhci_mtk_quirks(struct device * dev,struct xhci_hcd * xhci)372*4882a593Smuzhiyun static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	struct usb_hcd *hcd = xhci_to_hcd(xhci);
375*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/*
378*4882a593Smuzhiyun 	 * As of now platform drivers don't provide MSI support so we ensure
379*4882a593Smuzhiyun 	 * here that the generic code does not try to make a pci_dev from our
380*4882a593Smuzhiyun 	 * dev struct in order to setup MSI
381*4882a593Smuzhiyun 	 */
382*4882a593Smuzhiyun 	xhci->quirks |= XHCI_PLAT;
383*4882a593Smuzhiyun 	xhci->quirks |= XHCI_MTK_HOST;
384*4882a593Smuzhiyun 	/*
385*4882a593Smuzhiyun 	 * MTK host controller gives a spurious successful event after a
386*4882a593Smuzhiyun 	 * short transfer. Ignore it.
387*4882a593Smuzhiyun 	 */
388*4882a593Smuzhiyun 	xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
389*4882a593Smuzhiyun 	if (mtk->lpm_support)
390*4882a593Smuzhiyun 		xhci->quirks |= XHCI_LPM_SUPPORT;
391*4882a593Smuzhiyun 	if (mtk->u2_lpm_disable)
392*4882a593Smuzhiyun 		xhci->quirks |= XHCI_HW_LPM_DISABLE;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/*
395*4882a593Smuzhiyun 	 * MTK xHCI 0.96: PSA is 1 by default even if doesn't support stream,
396*4882a593Smuzhiyun 	 * and it's 3 when support it.
397*4882a593Smuzhiyun 	 */
398*4882a593Smuzhiyun 	if (xhci->hci_version < 0x100 && HCC_MAX_PSA(xhci->hcc_params) == 4)
399*4882a593Smuzhiyun 		xhci->quirks |= XHCI_BROKEN_STREAMS;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun /* called during probe() after chip reset completes */
xhci_mtk_setup(struct usb_hcd * hcd)403*4882a593Smuzhiyun static int xhci_mtk_setup(struct usb_hcd *hcd)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
406*4882a593Smuzhiyun 	int ret;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (usb_hcd_is_primary_hcd(hcd)) {
409*4882a593Smuzhiyun 		ret = xhci_mtk_ssusb_config(mtk);
410*4882a593Smuzhiyun 		if (ret)
411*4882a593Smuzhiyun 			return ret;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
415*4882a593Smuzhiyun 	if (ret)
416*4882a593Smuzhiyun 		return ret;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (usb_hcd_is_primary_hcd(hcd)) {
419*4882a593Smuzhiyun 		ret = xhci_mtk_sch_init(mtk);
420*4882a593Smuzhiyun 		if (ret)
421*4882a593Smuzhiyun 			return ret;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	return ret;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
428*4882a593Smuzhiyun 	.reset = xhci_mtk_setup,
429*4882a593Smuzhiyun 	.add_endpoint = xhci_mtk_add_ep,
430*4882a593Smuzhiyun 	.drop_endpoint = xhci_mtk_drop_ep,
431*4882a593Smuzhiyun 	.check_bandwidth = xhci_mtk_check_bandwidth,
432*4882a593Smuzhiyun 	.reset_bandwidth = xhci_mtk_reset_bandwidth,
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun static struct hc_driver __read_mostly xhci_mtk_hc_driver;
436*4882a593Smuzhiyun 
xhci_mtk_probe(struct platform_device * pdev)437*4882a593Smuzhiyun static int xhci_mtk_probe(struct platform_device *pdev)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
440*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
441*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk;
442*4882a593Smuzhiyun 	const struct hc_driver *driver;
443*4882a593Smuzhiyun 	struct xhci_hcd *xhci;
444*4882a593Smuzhiyun 	struct resource *res;
445*4882a593Smuzhiyun 	struct usb_hcd *hcd;
446*4882a593Smuzhiyun 	int ret = -ENODEV;
447*4882a593Smuzhiyun 	int irq;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if (usb_disabled())
450*4882a593Smuzhiyun 		return -ENODEV;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	driver = &xhci_mtk_hc_driver;
453*4882a593Smuzhiyun 	mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL);
454*4882a593Smuzhiyun 	if (!mtk)
455*4882a593Smuzhiyun 		return -ENOMEM;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	mtk->dev = dev;
458*4882a593Smuzhiyun 	mtk->vbus = devm_regulator_get(dev, "vbus");
459*4882a593Smuzhiyun 	if (IS_ERR(mtk->vbus)) {
460*4882a593Smuzhiyun 		dev_err(dev, "fail to get vbus\n");
461*4882a593Smuzhiyun 		return PTR_ERR(mtk->vbus);
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	mtk->vusb33 = devm_regulator_get(dev, "vusb33");
465*4882a593Smuzhiyun 	if (IS_ERR(mtk->vusb33)) {
466*4882a593Smuzhiyun 		dev_err(dev, "fail to get vusb33\n");
467*4882a593Smuzhiyun 		return PTR_ERR(mtk->vusb33);
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	ret = xhci_mtk_clks_get(mtk);
471*4882a593Smuzhiyun 	if (ret)
472*4882a593Smuzhiyun 		return ret;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable");
475*4882a593Smuzhiyun 	mtk->u2_lpm_disable = of_property_read_bool(node, "usb2-lpm-disable");
476*4882a593Smuzhiyun 	/* optional property, ignore the error if it does not exist */
477*4882a593Smuzhiyun 	of_property_read_u32(node, "mediatek,u3p-dis-msk",
478*4882a593Smuzhiyun 			     &mtk->u3p_dis_msk);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	ret = usb_wakeup_of_property_parse(mtk, node);
481*4882a593Smuzhiyun 	if (ret) {
482*4882a593Smuzhiyun 		dev_err(dev, "failed to parse uwk property\n");
483*4882a593Smuzhiyun 		return ret;
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	pm_runtime_enable(dev);
487*4882a593Smuzhiyun 	pm_runtime_get_sync(dev);
488*4882a593Smuzhiyun 	device_enable_async_suspend(dev);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	ret = xhci_mtk_ldos_enable(mtk);
491*4882a593Smuzhiyun 	if (ret)
492*4882a593Smuzhiyun 		goto disable_pm;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	ret = xhci_mtk_clks_enable(mtk);
495*4882a593Smuzhiyun 	if (ret)
496*4882a593Smuzhiyun 		goto disable_ldos;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
499*4882a593Smuzhiyun 	if (irq < 0) {
500*4882a593Smuzhiyun 		ret = irq;
501*4882a593Smuzhiyun 		goto disable_clk;
502*4882a593Smuzhiyun 	}
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	hcd = usb_create_hcd(driver, dev, dev_name(dev));
505*4882a593Smuzhiyun 	if (!hcd) {
506*4882a593Smuzhiyun 		ret = -ENOMEM;
507*4882a593Smuzhiyun 		goto disable_clk;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	/*
511*4882a593Smuzhiyun 	 * USB 2.0 roothub is stored in the platform_device.
512*4882a593Smuzhiyun 	 * Swap it with mtk HCD.
513*4882a593Smuzhiyun 	 */
514*4882a593Smuzhiyun 	mtk->hcd = platform_get_drvdata(pdev);
515*4882a593Smuzhiyun 	platform_set_drvdata(pdev, mtk);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac");
518*4882a593Smuzhiyun 	hcd->regs = devm_ioremap_resource(dev, res);
519*4882a593Smuzhiyun 	if (IS_ERR(hcd->regs)) {
520*4882a593Smuzhiyun 		ret = PTR_ERR(hcd->regs);
521*4882a593Smuzhiyun 		goto put_usb2_hcd;
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 	hcd->rsrc_start = res->start;
524*4882a593Smuzhiyun 	hcd->rsrc_len = resource_size(res);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ippc");
527*4882a593Smuzhiyun 	if (res) {	/* ippc register is optional */
528*4882a593Smuzhiyun 		mtk->ippc_regs = devm_ioremap_resource(dev, res);
529*4882a593Smuzhiyun 		if (IS_ERR(mtk->ippc_regs)) {
530*4882a593Smuzhiyun 			ret = PTR_ERR(mtk->ippc_regs);
531*4882a593Smuzhiyun 			goto put_usb2_hcd;
532*4882a593Smuzhiyun 		}
533*4882a593Smuzhiyun 		mtk->has_ippc = true;
534*4882a593Smuzhiyun 	} else {
535*4882a593Smuzhiyun 		mtk->has_ippc = false;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	device_init_wakeup(dev, true);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	xhci = hcd_to_xhci(hcd);
541*4882a593Smuzhiyun 	xhci->main_hcd = hcd;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/*
544*4882a593Smuzhiyun 	 * imod_interval is the interrupt moderation value in nanoseconds.
545*4882a593Smuzhiyun 	 * The increment interval is 8 times as much as that defined in
546*4882a593Smuzhiyun 	 * the xHCI spec on MTK's controller.
547*4882a593Smuzhiyun 	 */
548*4882a593Smuzhiyun 	xhci->imod_interval = 5000;
549*4882a593Smuzhiyun 	device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
552*4882a593Smuzhiyun 			dev_name(dev), hcd);
553*4882a593Smuzhiyun 	if (!xhci->shared_hcd) {
554*4882a593Smuzhiyun 		ret = -ENOMEM;
555*4882a593Smuzhiyun 		goto disable_device_wakeup;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
559*4882a593Smuzhiyun 	if (ret)
560*4882a593Smuzhiyun 		goto put_usb3_hcd;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
563*4882a593Smuzhiyun 	    !(xhci->quirks & XHCI_BROKEN_STREAMS))
564*4882a593Smuzhiyun 		xhci->shared_hcd->can_do_streams = 1;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
567*4882a593Smuzhiyun 	if (ret)
568*4882a593Smuzhiyun 		goto dealloc_usb2_hcd;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	return 0;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun dealloc_usb2_hcd:
573*4882a593Smuzhiyun 	usb_remove_hcd(hcd);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun put_usb3_hcd:
576*4882a593Smuzhiyun 	xhci_mtk_sch_exit(mtk);
577*4882a593Smuzhiyun 	usb_put_hcd(xhci->shared_hcd);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun disable_device_wakeup:
580*4882a593Smuzhiyun 	device_init_wakeup(dev, false);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun put_usb2_hcd:
583*4882a593Smuzhiyun 	usb_put_hcd(hcd);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun disable_clk:
586*4882a593Smuzhiyun 	xhci_mtk_clks_disable(mtk);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun disable_ldos:
589*4882a593Smuzhiyun 	xhci_mtk_ldos_disable(mtk);
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun disable_pm:
592*4882a593Smuzhiyun 	pm_runtime_put_sync(dev);
593*4882a593Smuzhiyun 	pm_runtime_disable(dev);
594*4882a593Smuzhiyun 	return ret;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
xhci_mtk_remove(struct platform_device * dev)597*4882a593Smuzhiyun static int xhci_mtk_remove(struct platform_device *dev)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
600*4882a593Smuzhiyun 	struct usb_hcd	*hcd = mtk->hcd;
601*4882a593Smuzhiyun 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
602*4882a593Smuzhiyun 	struct usb_hcd  *shared_hcd = xhci->shared_hcd;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	pm_runtime_put_noidle(&dev->dev);
605*4882a593Smuzhiyun 	pm_runtime_disable(&dev->dev);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	usb_remove_hcd(shared_hcd);
608*4882a593Smuzhiyun 	xhci->shared_hcd = NULL;
609*4882a593Smuzhiyun 	device_init_wakeup(&dev->dev, false);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	usb_remove_hcd(hcd);
612*4882a593Smuzhiyun 	usb_put_hcd(shared_hcd);
613*4882a593Smuzhiyun 	usb_put_hcd(hcd);
614*4882a593Smuzhiyun 	xhci_mtk_sch_exit(mtk);
615*4882a593Smuzhiyun 	xhci_mtk_clks_disable(mtk);
616*4882a593Smuzhiyun 	xhci_mtk_ldos_disable(mtk);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun /*
622*4882a593Smuzhiyun  * if ip sleep fails, and all clocks are disabled, access register will hang
623*4882a593Smuzhiyun  * AHB bus, so stop polling roothubs to avoid regs access on bus suspend.
624*4882a593Smuzhiyun  * and no need to check whether ip sleep failed or not; this will cause SPM
625*4882a593Smuzhiyun  * to wake up system immediately after system suspend complete if ip sleep
626*4882a593Smuzhiyun  * fails, it is what we wanted.
627*4882a593Smuzhiyun  */
xhci_mtk_suspend(struct device * dev)628*4882a593Smuzhiyun static int __maybe_unused xhci_mtk_suspend(struct device *dev)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
631*4882a593Smuzhiyun 	struct usb_hcd *hcd = mtk->hcd;
632*4882a593Smuzhiyun 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	xhci_dbg(xhci, "%s: stop port polling\n", __func__);
635*4882a593Smuzhiyun 	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
636*4882a593Smuzhiyun 	del_timer_sync(&hcd->rh_timer);
637*4882a593Smuzhiyun 	clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
638*4882a593Smuzhiyun 	del_timer_sync(&xhci->shared_hcd->rh_timer);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	xhci_mtk_host_disable(mtk);
641*4882a593Smuzhiyun 	xhci_mtk_clks_disable(mtk);
642*4882a593Smuzhiyun 	usb_wakeup_set(mtk, true);
643*4882a593Smuzhiyun 	return 0;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun 
xhci_mtk_resume(struct device * dev)646*4882a593Smuzhiyun static int __maybe_unused xhci_mtk_resume(struct device *dev)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun 	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
649*4882a593Smuzhiyun 	struct usb_hcd *hcd = mtk->hcd;
650*4882a593Smuzhiyun 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	usb_wakeup_set(mtk, false);
653*4882a593Smuzhiyun 	xhci_mtk_clks_enable(mtk);
654*4882a593Smuzhiyun 	xhci_mtk_host_enable(mtk);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	xhci_dbg(xhci, "%s: restart port polling\n", __func__);
657*4882a593Smuzhiyun 	set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
658*4882a593Smuzhiyun 	usb_hcd_poll_rh_status(xhci->shared_hcd);
659*4882a593Smuzhiyun 	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
660*4882a593Smuzhiyun 	usb_hcd_poll_rh_status(hcd);
661*4882a593Smuzhiyun 	return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun static const struct dev_pm_ops xhci_mtk_pm_ops = {
665*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume)
666*4882a593Smuzhiyun };
667*4882a593Smuzhiyun #define DEV_PM_OPS IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun #ifdef CONFIG_OF
670*4882a593Smuzhiyun static const struct of_device_id mtk_xhci_of_match[] = {
671*4882a593Smuzhiyun 	{ .compatible = "mediatek,mt8173-xhci"},
672*4882a593Smuzhiyun 	{ .compatible = "mediatek,mtk-xhci"},
673*4882a593Smuzhiyun 	{ },
674*4882a593Smuzhiyun };
675*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mtk_xhci_of_match);
676*4882a593Smuzhiyun #endif
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun static struct platform_driver mtk_xhci_driver = {
679*4882a593Smuzhiyun 	.probe	= xhci_mtk_probe,
680*4882a593Smuzhiyun 	.remove	= xhci_mtk_remove,
681*4882a593Smuzhiyun 	.driver	= {
682*4882a593Smuzhiyun 		.name = "xhci-mtk",
683*4882a593Smuzhiyun 		.pm = DEV_PM_OPS,
684*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(mtk_xhci_of_match),
685*4882a593Smuzhiyun 	},
686*4882a593Smuzhiyun };
687*4882a593Smuzhiyun MODULE_ALIAS("platform:xhci-mtk");
688*4882a593Smuzhiyun 
xhci_mtk_init(void)689*4882a593Smuzhiyun static int __init xhci_mtk_init(void)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun 	xhci_init_driver(&xhci_mtk_hc_driver, &xhci_mtk_overrides);
692*4882a593Smuzhiyun 	return platform_driver_register(&mtk_xhci_driver);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun module_init(xhci_mtk_init);
695*4882a593Smuzhiyun 
xhci_mtk_exit(void)696*4882a593Smuzhiyun static void __exit xhci_mtk_exit(void)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun 	platform_driver_unregister(&mtk_xhci_driver);
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun module_exit(xhci_mtk_exit);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
703*4882a593Smuzhiyun MODULE_DESCRIPTION("MediaTek xHCI Host Controller Driver");
704*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
705