xref: /OK3568_Linux_fs/kernel/drivers/usb/dwc3/dwc3-rockchip-inno.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun  * dwc3-rockchip-inno.c - Rockchip DWC3 Specific Glue layer with INNO PHY
3*4882a593Smuzhiyun  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors: William Wu <william.wu@rock-chips.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This program is free software: you can redistribute it and/or modify
8*4882a593Smuzhiyun  * it under the terms of the GNU General Public License version 2 of
9*4882a593Smuzhiyun  * the License as published by the Free Software Foundation.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*4882a593Smuzhiyun  * GNU General Public License for more details.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/platform_device.h>
21*4882a593Smuzhiyun #include <linux/dma-mapping.h>
22*4882a593Smuzhiyun #include <linux/clk.h>
23*4882a593Smuzhiyun #include <linux/clk-provider.h>
24*4882a593Smuzhiyun #include <linux/debugfs.h>
25*4882a593Smuzhiyun #include <linux/of.h>
26*4882a593Smuzhiyun #include <linux/of_platform.h>
27*4882a593Smuzhiyun #include <linux/pm_runtime.h>
28*4882a593Smuzhiyun #include <linux/usb.h>
29*4882a593Smuzhiyun #include <linux/usb/hcd.h>
30*4882a593Smuzhiyun #include <linux/notifier.h>
31*4882a593Smuzhiyun #include <linux/uaccess.h>
32*4882a593Smuzhiyun #include <linux/usb/phy.h>
33*4882a593Smuzhiyun #include <linux/usb/ch9.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include "core.h"
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define XHCI_TSTCTRL_MASK		(0xf << 28)
38*4882a593Smuzhiyun struct dwc3_rockchip {
39*4882a593Smuzhiyun 	struct device		*dev;
40*4882a593Smuzhiyun 	struct clk		**clks;
41*4882a593Smuzhiyun 	int			num_clocks;
42*4882a593Smuzhiyun 	struct dwc3		*dwc;
43*4882a593Smuzhiyun 	struct usb_phy		*phy;
44*4882a593Smuzhiyun 	struct notifier_block	u3phy_nb;
45*4882a593Smuzhiyun 	struct work_struct      u3_work;
46*4882a593Smuzhiyun 	struct mutex		lock;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
u3phy_disconnect_det_notifier(struct notifier_block * nb,unsigned long event,void * p)49*4882a593Smuzhiyun static int u3phy_disconnect_det_notifier(struct notifier_block *nb,
50*4882a593Smuzhiyun 					 unsigned long event, void *p)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	struct dwc3_rockchip *rockchip =
53*4882a593Smuzhiyun 		container_of(nb, struct dwc3_rockchip, u3phy_nb);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	schedule_work(&rockchip->u3_work);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	return NOTIFY_DONE;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
u3phy_disconnect_det_work(struct work_struct * work)60*4882a593Smuzhiyun static void u3phy_disconnect_det_work(struct work_struct *work)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct dwc3_rockchip *rockchip =
63*4882a593Smuzhiyun 		container_of(work, struct dwc3_rockchip, u3_work);
64*4882a593Smuzhiyun 	struct usb_hcd	*hcd = dev_get_drvdata(&rockchip->dwc->xhci->dev);
65*4882a593Smuzhiyun 	u32		count = 0;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	mutex_lock(&rockchip->lock);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (hcd->state != HC_STATE_HALT)
70*4882a593Smuzhiyun 		dwc3_host_exit(rockchip->dwc);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	if (rockchip->phy)
73*4882a593Smuzhiyun 		usb_phy_shutdown(rockchip->phy);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	while (hcd->state != HC_STATE_HALT) {
76*4882a593Smuzhiyun 		if (++count > 1000) {
77*4882a593Smuzhiyun 			dev_err(rockchip->dev,
78*4882a593Smuzhiyun 				"wait for HCD remove 1s timeout!\n");
79*4882a593Smuzhiyun 			break;
80*4882a593Smuzhiyun 		}
81*4882a593Smuzhiyun 		usleep_range(1000, 1100);
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (hcd->state == HC_STATE_HALT)
85*4882a593Smuzhiyun 		dwc3_host_init(rockchip->dwc);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (rockchip->phy)
88*4882a593Smuzhiyun 		usb_phy_init(rockchip->phy);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	mutex_unlock(&rockchip->lock);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
dwc3_rockchip_probe(struct platform_device * pdev)93*4882a593Smuzhiyun static int dwc3_rockchip_probe(struct platform_device *pdev)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	struct dwc3_rockchip	*rockchip;
96*4882a593Smuzhiyun 	struct device		*dev = &pdev->dev;
97*4882a593Smuzhiyun 	struct device_node	*np = dev->of_node, *child;
98*4882a593Smuzhiyun 	struct platform_device	*child_pdev;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	unsigned int		count;
101*4882a593Smuzhiyun 	int			ret;
102*4882a593Smuzhiyun 	int			i;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
105*4882a593Smuzhiyun 	if (!rockchip)
106*4882a593Smuzhiyun 		return -ENOMEM;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	child = of_get_child_by_name(np, "dwc3");
109*4882a593Smuzhiyun 	if (!child) {
110*4882a593Smuzhiyun 		dev_err(dev, "failed to find dwc3 core node\n");
111*4882a593Smuzhiyun 		return -ENODEV;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	count = of_clk_get_parent_count(np);
115*4882a593Smuzhiyun 	if (!count)
116*4882a593Smuzhiyun 		return -ENOENT;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	rockchip->num_clocks = count;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	rockchip->clks = devm_kcalloc(dev, rockchip->num_clocks,
121*4882a593Smuzhiyun 			sizeof(struct clk *), GFP_KERNEL);
122*4882a593Smuzhiyun 	if (!rockchip->clks)
123*4882a593Smuzhiyun 		return -ENOMEM;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	platform_set_drvdata(pdev, rockchip);
126*4882a593Smuzhiyun 	rockchip->dev = dev;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	for (i = 0; i < rockchip->num_clocks; i++) {
129*4882a593Smuzhiyun 		struct clk	*clk;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 		clk = of_clk_get(np, i);
132*4882a593Smuzhiyun 		if (IS_ERR(clk)) {
133*4882a593Smuzhiyun 			ret = PTR_ERR(clk);
134*4882a593Smuzhiyun 			goto err0;
135*4882a593Smuzhiyun 		}
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 		ret = clk_prepare_enable(clk);
138*4882a593Smuzhiyun 		if (ret < 0) {
139*4882a593Smuzhiyun 			clk_put(clk);
140*4882a593Smuzhiyun 			goto err0;
141*4882a593Smuzhiyun 		}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 		rockchip->clks[i] = clk;
144*4882a593Smuzhiyun 	}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	pm_runtime_set_active(dev);
147*4882a593Smuzhiyun 	pm_runtime_enable(dev);
148*4882a593Smuzhiyun 	ret = pm_runtime_get_sync(dev);
149*4882a593Smuzhiyun 	if (ret < 0) {
150*4882a593Smuzhiyun 		dev_err(dev, "get_sync failed with err %d\n", ret);
151*4882a593Smuzhiyun 		goto err1;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	ret = of_platform_populate(np, NULL, NULL, dev);
155*4882a593Smuzhiyun 	if (ret)
156*4882a593Smuzhiyun 		goto err1;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	child_pdev = of_find_device_by_node(child);
159*4882a593Smuzhiyun 	if (!child_pdev) {
160*4882a593Smuzhiyun 		dev_err(dev, "failed to find dwc3 core device\n");
161*4882a593Smuzhiyun 		ret = -ENODEV;
162*4882a593Smuzhiyun 		goto err2;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	rockchip->dwc = platform_get_drvdata(child_pdev);
166*4882a593Smuzhiyun 	if (!rockchip->dwc || !rockchip->dwc->xhci) {
167*4882a593Smuzhiyun 		dev_dbg(dev, "failed to get drvdata dwc3\n");
168*4882a593Smuzhiyun 		ret = -EPROBE_DEFER;
169*4882a593Smuzhiyun 		goto err2;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	mutex_init(&rockchip->lock);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	rockchip->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
175*4882a593Smuzhiyun 	if (rockchip->phy) {
176*4882a593Smuzhiyun 		INIT_WORK(&rockchip->u3_work, u3phy_disconnect_det_work);
177*4882a593Smuzhiyun 		rockchip->u3phy_nb.notifier_call =
178*4882a593Smuzhiyun 			u3phy_disconnect_det_notifier;
179*4882a593Smuzhiyun 		usb_register_notifier(rockchip->phy, &rockchip->u3phy_nb);
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return 0;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun err2:
185*4882a593Smuzhiyun 	of_platform_depopulate(dev);
186*4882a593Smuzhiyun err1:
187*4882a593Smuzhiyun 	pm_runtime_put_sync(dev);
188*4882a593Smuzhiyun 	pm_runtime_disable(dev);
189*4882a593Smuzhiyun err0:
190*4882a593Smuzhiyun 	for (i = 0; i < rockchip->num_clocks && rockchip->clks[i]; i++) {
191*4882a593Smuzhiyun 		if (!pm_runtime_status_suspended(dev))
192*4882a593Smuzhiyun 			clk_disable(rockchip->clks[i]);
193*4882a593Smuzhiyun 		clk_unprepare(rockchip->clks[i]);
194*4882a593Smuzhiyun 		clk_put(rockchip->clks[i]);
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return ret;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
dwc3_rockchip_remove(struct platform_device * pdev)200*4882a593Smuzhiyun static int dwc3_rockchip_remove(struct platform_device *pdev)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	struct dwc3_rockchip	*rockchip = platform_get_drvdata(pdev);
203*4882a593Smuzhiyun 	struct device		*dev = &pdev->dev;
204*4882a593Smuzhiyun 	int			i;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	of_platform_depopulate(dev);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	pm_runtime_put_sync(dev);
209*4882a593Smuzhiyun 	pm_runtime_disable(dev);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	for (i = 0; i < rockchip->num_clocks; i++) {
212*4882a593Smuzhiyun 		if (!pm_runtime_status_suspended(dev))
213*4882a593Smuzhiyun 			clk_disable(rockchip->clks[i]);
214*4882a593Smuzhiyun 		clk_unprepare(rockchip->clks[i]);
215*4882a593Smuzhiyun 		clk_put(rockchip->clks[i]);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun #ifdef CONFIG_PM
dwc3_rockchip_runtime_suspend(struct device * dev)222*4882a593Smuzhiyun static int dwc3_rockchip_runtime_suspend(struct device *dev)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct dwc3_rockchip	*rockchip = dev_get_drvdata(dev);
225*4882a593Smuzhiyun 	int			i;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	for (i = 0; i < rockchip->num_clocks; i++)
228*4882a593Smuzhiyun 		clk_disable(rockchip->clks[i]);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	return 0;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
dwc3_rockchip_runtime_resume(struct device * dev)233*4882a593Smuzhiyun static int dwc3_rockchip_runtime_resume(struct device *dev)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	struct dwc3_rockchip	*rockchip = dev_get_drvdata(dev);
236*4882a593Smuzhiyun 	int			ret;
237*4882a593Smuzhiyun 	int			i;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	for (i = 0; i < rockchip->num_clocks; i++) {
240*4882a593Smuzhiyun 		ret = clk_enable(rockchip->clks[i]);
241*4882a593Smuzhiyun 		if (ret < 0) {
242*4882a593Smuzhiyun 			while (--i >= 0)
243*4882a593Smuzhiyun 				clk_disable(rockchip->clks[i]);
244*4882a593Smuzhiyun 			return ret;
245*4882a593Smuzhiyun 		}
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return 0;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun static const struct dev_pm_ops dwc3_rockchip_dev_pm_ops = {
252*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(dwc3_rockchip_runtime_suspend,
253*4882a593Smuzhiyun 			   dwc3_rockchip_runtime_resume, NULL)
254*4882a593Smuzhiyun };
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun #define DEV_PM_OPS	(&dwc3_rockchip_dev_pm_ops)
257*4882a593Smuzhiyun #else
258*4882a593Smuzhiyun #define DEV_PM_OPS	NULL
259*4882a593Smuzhiyun #endif /* CONFIG_PM */
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static const struct of_device_id rockchip_dwc3_match[] = {
262*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3328-dwc3" },
263*4882a593Smuzhiyun 	{ /* Sentinel */ }
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rockchip_dwc3_match);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun static struct platform_driver dwc3_rockchip_driver = {
268*4882a593Smuzhiyun 	.probe		= dwc3_rockchip_probe,
269*4882a593Smuzhiyun 	.remove		= dwc3_rockchip_remove,
270*4882a593Smuzhiyun 	.driver		= {
271*4882a593Smuzhiyun 		.name	= "rockchip-inno-dwc3",
272*4882a593Smuzhiyun 		.pm	= DEV_PM_OPS,
273*4882a593Smuzhiyun 		.of_match_table = rockchip_dwc3_match,
274*4882a593Smuzhiyun 	},
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun module_platform_driver(dwc3_rockchip_driver);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun MODULE_ALIAS("platform:rockchip-inno-dwc3");
280*4882a593Smuzhiyun MODULE_AUTHOR("William Wu <william.wu@rock-chips.com>");
281*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
282*4882a593Smuzhiyun MODULE_DESCRIPTION("DesignWare USB3 rockchip-inno Glue Layer");
283