xref: /OK3568_Linux_fs/kernel/drivers/usb/musb/sunxi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Allwinner sun4i MUSB Glue Layer
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on code from
8*4882a593Smuzhiyun  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/clk.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/extcon.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/of.h>
18*4882a593Smuzhiyun #include <linux/phy/phy-sun4i-usb.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/reset.h>
21*4882a593Smuzhiyun #include <linux/soc/sunxi/sunxi_sram.h>
22*4882a593Smuzhiyun #include <linux/usb/musb.h>
23*4882a593Smuzhiyun #include <linux/usb/of.h>
24*4882a593Smuzhiyun #include <linux/usb/usb_phy_generic.h>
25*4882a593Smuzhiyun #include <linux/workqueue.h>
26*4882a593Smuzhiyun #include "musb_core.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * Register offsets, note sunxi musb has a different layout then most
30*4882a593Smuzhiyun  * musb implementations, we translate the layout in musb_readb & friends.
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun #define SUNXI_MUSB_POWER			0x0040
33*4882a593Smuzhiyun #define SUNXI_MUSB_DEVCTL			0x0041
34*4882a593Smuzhiyun #define SUNXI_MUSB_INDEX			0x0042
35*4882a593Smuzhiyun #define SUNXI_MUSB_VEND0			0x0043
36*4882a593Smuzhiyun #define SUNXI_MUSB_INTRTX			0x0044
37*4882a593Smuzhiyun #define SUNXI_MUSB_INTRRX			0x0046
38*4882a593Smuzhiyun #define SUNXI_MUSB_INTRTXE			0x0048
39*4882a593Smuzhiyun #define SUNXI_MUSB_INTRRXE			0x004a
40*4882a593Smuzhiyun #define SUNXI_MUSB_INTRUSB			0x004c
41*4882a593Smuzhiyun #define SUNXI_MUSB_INTRUSBE			0x0050
42*4882a593Smuzhiyun #define SUNXI_MUSB_FRAME			0x0054
43*4882a593Smuzhiyun #define SUNXI_MUSB_TXFIFOSZ			0x0090
44*4882a593Smuzhiyun #define SUNXI_MUSB_TXFIFOADD			0x0092
45*4882a593Smuzhiyun #define SUNXI_MUSB_RXFIFOSZ			0x0094
46*4882a593Smuzhiyun #define SUNXI_MUSB_RXFIFOADD			0x0096
47*4882a593Smuzhiyun #define SUNXI_MUSB_FADDR			0x0098
48*4882a593Smuzhiyun #define SUNXI_MUSB_TXFUNCADDR			0x0098
49*4882a593Smuzhiyun #define SUNXI_MUSB_TXHUBADDR			0x009a
50*4882a593Smuzhiyun #define SUNXI_MUSB_TXHUBPORT			0x009b
51*4882a593Smuzhiyun #define SUNXI_MUSB_RXFUNCADDR			0x009c
52*4882a593Smuzhiyun #define SUNXI_MUSB_RXHUBADDR			0x009e
53*4882a593Smuzhiyun #define SUNXI_MUSB_RXHUBPORT			0x009f
54*4882a593Smuzhiyun #define SUNXI_MUSB_CONFIGDATA			0x00c0
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /* VEND0 bits */
57*4882a593Smuzhiyun #define SUNXI_MUSB_VEND0_PIO_MODE		0
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* flags */
60*4882a593Smuzhiyun #define SUNXI_MUSB_FL_ENABLED			0
61*4882a593Smuzhiyun #define SUNXI_MUSB_FL_HOSTMODE			1
62*4882a593Smuzhiyun #define SUNXI_MUSB_FL_HOSTMODE_PEND		2
63*4882a593Smuzhiyun #define SUNXI_MUSB_FL_VBUS_ON			3
64*4882a593Smuzhiyun #define SUNXI_MUSB_FL_PHY_ON			4
65*4882a593Smuzhiyun #define SUNXI_MUSB_FL_HAS_SRAM			5
66*4882a593Smuzhiyun #define SUNXI_MUSB_FL_HAS_RESET			6
67*4882a593Smuzhiyun #define SUNXI_MUSB_FL_NO_CONFIGDATA		7
68*4882a593Smuzhiyun #define SUNXI_MUSB_FL_PHY_MODE_PEND		8
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* Our read/write methods need access and do not get passed in a musb ref :| */
71*4882a593Smuzhiyun static struct musb *sunxi_musb;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun struct sunxi_glue {
74*4882a593Smuzhiyun 	struct device		*dev;
75*4882a593Smuzhiyun 	struct musb		*musb;
76*4882a593Smuzhiyun 	struct platform_device	*musb_pdev;
77*4882a593Smuzhiyun 	struct clk		*clk;
78*4882a593Smuzhiyun 	struct reset_control	*rst;
79*4882a593Smuzhiyun 	struct phy		*phy;
80*4882a593Smuzhiyun 	struct platform_device	*usb_phy;
81*4882a593Smuzhiyun 	struct usb_phy		*xceiv;
82*4882a593Smuzhiyun 	enum phy_mode		phy_mode;
83*4882a593Smuzhiyun 	unsigned long		flags;
84*4882a593Smuzhiyun 	struct work_struct	work;
85*4882a593Smuzhiyun 	struct extcon_dev	*extcon;
86*4882a593Smuzhiyun 	struct notifier_block	host_nb;
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /* phy_power_on / off may sleep, so we use a workqueue  */
sunxi_musb_work(struct work_struct * work)90*4882a593Smuzhiyun static void sunxi_musb_work(struct work_struct *work)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work);
93*4882a593Smuzhiyun 	bool vbus_on, phy_on;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
96*4882a593Smuzhiyun 		return;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) {
99*4882a593Smuzhiyun 		struct musb *musb = glue->musb;
100*4882a593Smuzhiyun 		unsigned long flags;
101*4882a593Smuzhiyun 		u8 devctl;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		spin_lock_irqsave(&musb->lock, flags);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 		devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL);
106*4882a593Smuzhiyun 		if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
107*4882a593Smuzhiyun 			set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
108*4882a593Smuzhiyun 			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
109*4882a593Smuzhiyun 			MUSB_HST_MODE(musb);
110*4882a593Smuzhiyun 			devctl |= MUSB_DEVCTL_SESSION;
111*4882a593Smuzhiyun 		} else {
112*4882a593Smuzhiyun 			clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
113*4882a593Smuzhiyun 			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
114*4882a593Smuzhiyun 			MUSB_DEV_MODE(musb);
115*4882a593Smuzhiyun 			devctl &= ~MUSB_DEVCTL_SESSION;
116*4882a593Smuzhiyun 		}
117*4882a593Smuzhiyun 		writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 		spin_unlock_irqrestore(&musb->lock, flags);
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
123*4882a593Smuzhiyun 	phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (phy_on != vbus_on) {
126*4882a593Smuzhiyun 		if (vbus_on) {
127*4882a593Smuzhiyun 			phy_power_on(glue->phy);
128*4882a593Smuzhiyun 			set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
129*4882a593Smuzhiyun 		} else {
130*4882a593Smuzhiyun 			phy_power_off(glue->phy);
131*4882a593Smuzhiyun 			clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
132*4882a593Smuzhiyun 		}
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (test_and_clear_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags))
136*4882a593Smuzhiyun 		phy_set_mode(glue->phy, glue->phy_mode);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
sunxi_musb_set_vbus(struct musb * musb,int is_on)139*4882a593Smuzhiyun static void sunxi_musb_set_vbus(struct musb *musb, int is_on)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (is_on) {
144*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
145*4882a593Smuzhiyun 		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
146*4882a593Smuzhiyun 	} else {
147*4882a593Smuzhiyun 		clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	schedule_work(&glue->work);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
sunxi_musb_pre_root_reset_end(struct musb * musb)153*4882a593Smuzhiyun static void sunxi_musb_pre_root_reset_end(struct musb *musb)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	sun4i_usb_phy_set_squelch_detect(glue->phy, false);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
sunxi_musb_post_root_reset_end(struct musb * musb)160*4882a593Smuzhiyun static void sunxi_musb_post_root_reset_end(struct musb *musb)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	sun4i_usb_phy_set_squelch_detect(glue->phy, true);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
sunxi_musb_interrupt(int irq,void * __hci)167*4882a593Smuzhiyun static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct musb *musb = __hci;
170*4882a593Smuzhiyun 	unsigned long flags;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	spin_lock_irqsave(&musb->lock, flags);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB);
175*4882a593Smuzhiyun 	if (musb->int_usb)
176*4882a593Smuzhiyun 		writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) {
179*4882a593Smuzhiyun 		/* ep0 FADDR must be 0 when (re)entering peripheral mode */
180*4882a593Smuzhiyun 		musb_ep_select(musb->mregs, 0);
181*4882a593Smuzhiyun 		musb_writeb(musb->mregs, MUSB_FADDR, 0);
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX);
185*4882a593Smuzhiyun 	if (musb->int_tx)
186*4882a593Smuzhiyun 		writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX);
189*4882a593Smuzhiyun 	if (musb->int_rx)
190*4882a593Smuzhiyun 		writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	musb_interrupt(musb);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	spin_unlock_irqrestore(&musb->lock, flags);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return IRQ_HANDLED;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
sunxi_musb_host_notifier(struct notifier_block * nb,unsigned long event,void * ptr)199*4882a593Smuzhiyun static int sunxi_musb_host_notifier(struct notifier_block *nb,
200*4882a593Smuzhiyun 				    unsigned long event, void *ptr)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (event)
205*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
206*4882a593Smuzhiyun 	else
207*4882a593Smuzhiyun 		clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags);
210*4882a593Smuzhiyun 	schedule_work(&glue->work);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	return NOTIFY_DONE;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
sunxi_musb_init(struct musb * musb)215*4882a593Smuzhiyun static int sunxi_musb_init(struct musb *musb)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
218*4882a593Smuzhiyun 	int ret;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	sunxi_musb = musb;
221*4882a593Smuzhiyun 	musb->phy = glue->phy;
222*4882a593Smuzhiyun 	musb->xceiv = glue->xceiv;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) {
225*4882a593Smuzhiyun 		ret = sunxi_sram_claim(musb->controller->parent);
226*4882a593Smuzhiyun 		if (ret)
227*4882a593Smuzhiyun 			return ret;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ret = clk_prepare_enable(glue->clk);
231*4882a593Smuzhiyun 	if (ret)
232*4882a593Smuzhiyun 		goto error_sram_release;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
235*4882a593Smuzhiyun 		ret = reset_control_deassert(glue->rst);
236*4882a593Smuzhiyun 		if (ret)
237*4882a593Smuzhiyun 			goto error_clk_disable;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	/* Register notifier before calling phy_init() */
243*4882a593Smuzhiyun 	ret = devm_extcon_register_notifier(glue->dev, glue->extcon,
244*4882a593Smuzhiyun 					EXTCON_USB_HOST, &glue->host_nb);
245*4882a593Smuzhiyun 	if (ret)
246*4882a593Smuzhiyun 		goto error_reset_assert;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	ret = phy_init(glue->phy);
249*4882a593Smuzhiyun 	if (ret)
250*4882a593Smuzhiyun 		goto error_reset_assert;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	musb->isr = sunxi_musb_interrupt;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Stop the musb-core from doing runtime pm (not supported on sunxi) */
255*4882a593Smuzhiyun 	pm_runtime_get(musb->controller);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return 0;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun error_reset_assert:
260*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
261*4882a593Smuzhiyun 		reset_control_assert(glue->rst);
262*4882a593Smuzhiyun error_clk_disable:
263*4882a593Smuzhiyun 	clk_disable_unprepare(glue->clk);
264*4882a593Smuzhiyun error_sram_release:
265*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
266*4882a593Smuzhiyun 		sunxi_sram_release(musb->controller->parent);
267*4882a593Smuzhiyun 	return ret;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
sunxi_musb_exit(struct musb * musb)270*4882a593Smuzhiyun static int sunxi_musb_exit(struct musb *musb)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	pm_runtime_put(musb->controller);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	cancel_work_sync(&glue->work);
277*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags))
278*4882a593Smuzhiyun 		phy_power_off(glue->phy);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	phy_exit(glue->phy);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
283*4882a593Smuzhiyun 		reset_control_assert(glue->rst);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	clk_disable_unprepare(glue->clk);
286*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
287*4882a593Smuzhiyun 		sunxi_sram_release(musb->controller->parent);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	devm_usb_put_phy(glue->dev, glue->xceiv);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return 0;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
sunxi_musb_enable(struct musb * musb)294*4882a593Smuzhiyun static void sunxi_musb_enable(struct musb *musb)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	glue->musb = musb;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	/* musb_core does not call us in a balanced manner */
301*4882a593Smuzhiyun 	if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
302*4882a593Smuzhiyun 		return;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	schedule_work(&glue->work);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
sunxi_musb_disable(struct musb * musb)307*4882a593Smuzhiyun static void sunxi_musb_disable(struct musb *musb)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun static struct dma_controller *
sunxi_musb_dma_controller_create(struct musb * musb,void __iomem * base)315*4882a593Smuzhiyun sunxi_musb_dma_controller_create(struct musb *musb, void __iomem *base)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	return NULL;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
sunxi_musb_dma_controller_destroy(struct dma_controller * c)320*4882a593Smuzhiyun static void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
sunxi_musb_set_mode(struct musb * musb,u8 mode)324*4882a593Smuzhiyun static int sunxi_musb_set_mode(struct musb *musb, u8 mode)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
327*4882a593Smuzhiyun 	enum phy_mode new_mode;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	switch (mode) {
330*4882a593Smuzhiyun 	case MUSB_HOST:
331*4882a593Smuzhiyun 		new_mode = PHY_MODE_USB_HOST;
332*4882a593Smuzhiyun 		break;
333*4882a593Smuzhiyun 	case MUSB_PERIPHERAL:
334*4882a593Smuzhiyun 		new_mode = PHY_MODE_USB_DEVICE;
335*4882a593Smuzhiyun 		break;
336*4882a593Smuzhiyun 	case MUSB_OTG:
337*4882a593Smuzhiyun 		new_mode = PHY_MODE_USB_OTG;
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 	default:
340*4882a593Smuzhiyun 		dev_err(musb->controller->parent,
341*4882a593Smuzhiyun 			"Error requested mode not supported by this kernel\n");
342*4882a593Smuzhiyun 		return -EINVAL;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (glue->phy_mode == new_mode)
346*4882a593Smuzhiyun 		return 0;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (musb->port_mode != MUSB_OTG) {
349*4882a593Smuzhiyun 		dev_err(musb->controller->parent,
350*4882a593Smuzhiyun 			"Error changing modes is only supported in dual role mode\n");
351*4882a593Smuzhiyun 		return -EINVAL;
352*4882a593Smuzhiyun 	}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (musb->port1_status & USB_PORT_STAT_ENABLE)
355*4882a593Smuzhiyun 		musb_root_disconnect(musb);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	/*
358*4882a593Smuzhiyun 	 * phy_set_mode may sleep, and we're called with a spinlock held,
359*4882a593Smuzhiyun 	 * so let sunxi_musb_work deal with it.
360*4882a593Smuzhiyun 	 */
361*4882a593Smuzhiyun 	glue->phy_mode = new_mode;
362*4882a593Smuzhiyun 	set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags);
363*4882a593Smuzhiyun 	schedule_work(&glue->work);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
sunxi_musb_recover(struct musb * musb)368*4882a593Smuzhiyun static int sunxi_musb_recover(struct musb *musb)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	/*
373*4882a593Smuzhiyun 	 * Schedule a phy_set_mode with the current glue->phy_mode value,
374*4882a593Smuzhiyun 	 * this will force end the current session.
375*4882a593Smuzhiyun 	 */
376*4882a593Smuzhiyun 	set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags);
377*4882a593Smuzhiyun 	schedule_work(&glue->work);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun  * sunxi musb register layout
384*4882a593Smuzhiyun  * 0x00 - 0x17	fifo regs, 1 long per fifo
385*4882a593Smuzhiyun  * 0x40 - 0x57	generic control regs (power - frame)
386*4882a593Smuzhiyun  * 0x80 - 0x8f	ep control regs (addressed through hw_ep->regs, indexed)
387*4882a593Smuzhiyun  * 0x90 - 0x97	fifo control regs (indexed)
388*4882a593Smuzhiyun  * 0x98 - 0x9f	multipoint / busctl regs (indexed)
389*4882a593Smuzhiyun  * 0xc0		configdata reg
390*4882a593Smuzhiyun  */
391*4882a593Smuzhiyun 
sunxi_musb_fifo_offset(u8 epnum)392*4882a593Smuzhiyun static u32 sunxi_musb_fifo_offset(u8 epnum)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	return (epnum * 4);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
sunxi_musb_ep_offset(u8 epnum,u16 offset)397*4882a593Smuzhiyun static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	WARN_ONCE(offset != 0,
400*4882a593Smuzhiyun 		  "sunxi_musb_ep_offset called with non 0 offset\n");
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	return 0x80; /* indexed, so ignore epnum */
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
sunxi_musb_busctl_offset(u8 epnum,u16 offset)405*4882a593Smuzhiyun static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	return SUNXI_MUSB_TXFUNCADDR + offset;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
sunxi_musb_readb(void __iomem * addr,u32 offset)410*4882a593Smuzhiyun static u8 sunxi_musb_readb(void __iomem *addr, u32 offset)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	struct sunxi_glue *glue;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	if (addr == sunxi_musb->mregs) {
415*4882a593Smuzhiyun 		/* generic control or fifo control reg access */
416*4882a593Smuzhiyun 		switch (offset) {
417*4882a593Smuzhiyun 		case MUSB_FADDR:
418*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_FADDR);
419*4882a593Smuzhiyun 		case MUSB_POWER:
420*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_POWER);
421*4882a593Smuzhiyun 		case MUSB_INTRUSB:
422*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_INTRUSB);
423*4882a593Smuzhiyun 		case MUSB_INTRUSBE:
424*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_INTRUSBE);
425*4882a593Smuzhiyun 		case MUSB_INDEX:
426*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_INDEX);
427*4882a593Smuzhiyun 		case MUSB_TESTMODE:
428*4882a593Smuzhiyun 			return 0; /* No testmode on sunxi */
429*4882a593Smuzhiyun 		case MUSB_DEVCTL:
430*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_DEVCTL);
431*4882a593Smuzhiyun 		case MUSB_TXFIFOSZ:
432*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_TXFIFOSZ);
433*4882a593Smuzhiyun 		case MUSB_RXFIFOSZ:
434*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_RXFIFOSZ);
435*4882a593Smuzhiyun 		case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */
436*4882a593Smuzhiyun 			glue = dev_get_drvdata(sunxi_musb->controller->parent);
437*4882a593Smuzhiyun 			/* A33 saves a reg, and we get to hardcode this */
438*4882a593Smuzhiyun 			if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA,
439*4882a593Smuzhiyun 				     &glue->flags))
440*4882a593Smuzhiyun 				return 0xde;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 			return readb(addr + SUNXI_MUSB_CONFIGDATA);
443*4882a593Smuzhiyun 		/* Offset for these is fixed by sunxi_musb_busctl_offset() */
444*4882a593Smuzhiyun 		case SUNXI_MUSB_TXFUNCADDR:
445*4882a593Smuzhiyun 		case SUNXI_MUSB_TXHUBADDR:
446*4882a593Smuzhiyun 		case SUNXI_MUSB_TXHUBPORT:
447*4882a593Smuzhiyun 		case SUNXI_MUSB_RXFUNCADDR:
448*4882a593Smuzhiyun 		case SUNXI_MUSB_RXHUBADDR:
449*4882a593Smuzhiyun 		case SUNXI_MUSB_RXHUBPORT:
450*4882a593Smuzhiyun 			/* multipoint / busctl reg access */
451*4882a593Smuzhiyun 			return readb(addr + offset);
452*4882a593Smuzhiyun 		default:
453*4882a593Smuzhiyun 			dev_err(sunxi_musb->controller->parent,
454*4882a593Smuzhiyun 				"Error unknown readb offset %u\n", offset);
455*4882a593Smuzhiyun 			return 0;
456*4882a593Smuzhiyun 		}
457*4882a593Smuzhiyun 	} else if (addr == (sunxi_musb->mregs + 0x80)) {
458*4882a593Smuzhiyun 		/* ep control reg access */
459*4882a593Smuzhiyun 		/* sunxi has a 2 byte hole before the txtype register */
460*4882a593Smuzhiyun 		if (offset >= MUSB_TXTYPE)
461*4882a593Smuzhiyun 			offset += 2;
462*4882a593Smuzhiyun 		return readb(addr + offset);
463*4882a593Smuzhiyun 	}
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	dev_err(sunxi_musb->controller->parent,
466*4882a593Smuzhiyun 		"Error unknown readb at 0x%x bytes offset\n",
467*4882a593Smuzhiyun 		(int)(addr - sunxi_musb->mregs));
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
sunxi_musb_writeb(void __iomem * addr,unsigned offset,u8 data)471*4882a593Smuzhiyun static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	if (addr == sunxi_musb->mregs) {
474*4882a593Smuzhiyun 		/* generic control or fifo control reg access */
475*4882a593Smuzhiyun 		switch (offset) {
476*4882a593Smuzhiyun 		case MUSB_FADDR:
477*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_FADDR);
478*4882a593Smuzhiyun 		case MUSB_POWER:
479*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_POWER);
480*4882a593Smuzhiyun 		case MUSB_INTRUSB:
481*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_INTRUSB);
482*4882a593Smuzhiyun 		case MUSB_INTRUSBE:
483*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_INTRUSBE);
484*4882a593Smuzhiyun 		case MUSB_INDEX:
485*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_INDEX);
486*4882a593Smuzhiyun 		case MUSB_TESTMODE:
487*4882a593Smuzhiyun 			if (data)
488*4882a593Smuzhiyun 				dev_warn(sunxi_musb->controller->parent,
489*4882a593Smuzhiyun 					"sunxi-musb does not have testmode\n");
490*4882a593Smuzhiyun 			return;
491*4882a593Smuzhiyun 		case MUSB_DEVCTL:
492*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_DEVCTL);
493*4882a593Smuzhiyun 		case MUSB_TXFIFOSZ:
494*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ);
495*4882a593Smuzhiyun 		case MUSB_RXFIFOSZ:
496*4882a593Smuzhiyun 			return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ);
497*4882a593Smuzhiyun 		/* Offset for these is fixed by sunxi_musb_busctl_offset() */
498*4882a593Smuzhiyun 		case SUNXI_MUSB_TXFUNCADDR:
499*4882a593Smuzhiyun 		case SUNXI_MUSB_TXHUBADDR:
500*4882a593Smuzhiyun 		case SUNXI_MUSB_TXHUBPORT:
501*4882a593Smuzhiyun 		case SUNXI_MUSB_RXFUNCADDR:
502*4882a593Smuzhiyun 		case SUNXI_MUSB_RXHUBADDR:
503*4882a593Smuzhiyun 		case SUNXI_MUSB_RXHUBPORT:
504*4882a593Smuzhiyun 			/* multipoint / busctl reg access */
505*4882a593Smuzhiyun 			return writeb(data, addr + offset);
506*4882a593Smuzhiyun 		default:
507*4882a593Smuzhiyun 			dev_err(sunxi_musb->controller->parent,
508*4882a593Smuzhiyun 				"Error unknown writeb offset %u\n", offset);
509*4882a593Smuzhiyun 			return;
510*4882a593Smuzhiyun 		}
511*4882a593Smuzhiyun 	} else if (addr == (sunxi_musb->mregs + 0x80)) {
512*4882a593Smuzhiyun 		/* ep control reg access */
513*4882a593Smuzhiyun 		if (offset >= MUSB_TXTYPE)
514*4882a593Smuzhiyun 			offset += 2;
515*4882a593Smuzhiyun 		return writeb(data, addr + offset);
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	dev_err(sunxi_musb->controller->parent,
519*4882a593Smuzhiyun 		"Error unknown writeb at 0x%x bytes offset\n",
520*4882a593Smuzhiyun 		(int)(addr - sunxi_musb->mregs));
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
sunxi_musb_readw(void __iomem * addr,u32 offset)523*4882a593Smuzhiyun static u16 sunxi_musb_readw(void __iomem *addr, u32 offset)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	if (addr == sunxi_musb->mregs) {
526*4882a593Smuzhiyun 		/* generic control or fifo control reg access */
527*4882a593Smuzhiyun 		switch (offset) {
528*4882a593Smuzhiyun 		case MUSB_INTRTX:
529*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_INTRTX);
530*4882a593Smuzhiyun 		case MUSB_INTRRX:
531*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_INTRRX);
532*4882a593Smuzhiyun 		case MUSB_INTRTXE:
533*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_INTRTXE);
534*4882a593Smuzhiyun 		case MUSB_INTRRXE:
535*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_INTRRXE);
536*4882a593Smuzhiyun 		case MUSB_FRAME:
537*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_FRAME);
538*4882a593Smuzhiyun 		case MUSB_TXFIFOADD:
539*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_TXFIFOADD);
540*4882a593Smuzhiyun 		case MUSB_RXFIFOADD:
541*4882a593Smuzhiyun 			return readw(addr + SUNXI_MUSB_RXFIFOADD);
542*4882a593Smuzhiyun 		case MUSB_HWVERS:
543*4882a593Smuzhiyun 			return 0; /* sunxi musb version is not known */
544*4882a593Smuzhiyun 		default:
545*4882a593Smuzhiyun 			dev_err(sunxi_musb->controller->parent,
546*4882a593Smuzhiyun 				"Error unknown readw offset %u\n", offset);
547*4882a593Smuzhiyun 			return 0;
548*4882a593Smuzhiyun 		}
549*4882a593Smuzhiyun 	} else if (addr == (sunxi_musb->mregs + 0x80)) {
550*4882a593Smuzhiyun 		/* ep control reg access */
551*4882a593Smuzhiyun 		return readw(addr + offset);
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	dev_err(sunxi_musb->controller->parent,
555*4882a593Smuzhiyun 		"Error unknown readw at 0x%x bytes offset\n",
556*4882a593Smuzhiyun 		(int)(addr - sunxi_musb->mregs));
557*4882a593Smuzhiyun 	return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
sunxi_musb_writew(void __iomem * addr,unsigned offset,u16 data)560*4882a593Smuzhiyun static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	if (addr == sunxi_musb->mregs) {
563*4882a593Smuzhiyun 		/* generic control or fifo control reg access */
564*4882a593Smuzhiyun 		switch (offset) {
565*4882a593Smuzhiyun 		case MUSB_INTRTX:
566*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_INTRTX);
567*4882a593Smuzhiyun 		case MUSB_INTRRX:
568*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_INTRRX);
569*4882a593Smuzhiyun 		case MUSB_INTRTXE:
570*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_INTRTXE);
571*4882a593Smuzhiyun 		case MUSB_INTRRXE:
572*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_INTRRXE);
573*4882a593Smuzhiyun 		case MUSB_FRAME:
574*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_FRAME);
575*4882a593Smuzhiyun 		case MUSB_TXFIFOADD:
576*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_TXFIFOADD);
577*4882a593Smuzhiyun 		case MUSB_RXFIFOADD:
578*4882a593Smuzhiyun 			return writew(data, addr + SUNXI_MUSB_RXFIFOADD);
579*4882a593Smuzhiyun 		default:
580*4882a593Smuzhiyun 			dev_err(sunxi_musb->controller->parent,
581*4882a593Smuzhiyun 				"Error unknown writew offset %u\n", offset);
582*4882a593Smuzhiyun 			return;
583*4882a593Smuzhiyun 		}
584*4882a593Smuzhiyun 	} else if (addr == (sunxi_musb->mregs + 0x80)) {
585*4882a593Smuzhiyun 		/* ep control reg access */
586*4882a593Smuzhiyun 		return writew(data, addr + offset);
587*4882a593Smuzhiyun 	}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	dev_err(sunxi_musb->controller->parent,
590*4882a593Smuzhiyun 		"Error unknown writew at 0x%x bytes offset\n",
591*4882a593Smuzhiyun 		(int)(addr - sunxi_musb->mregs));
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun static const struct musb_platform_ops sunxi_musb_ops = {
595*4882a593Smuzhiyun 	.quirks		= MUSB_INDEXED_EP,
596*4882a593Smuzhiyun 	.init		= sunxi_musb_init,
597*4882a593Smuzhiyun 	.exit		= sunxi_musb_exit,
598*4882a593Smuzhiyun 	.enable		= sunxi_musb_enable,
599*4882a593Smuzhiyun 	.disable	= sunxi_musb_disable,
600*4882a593Smuzhiyun 	.fifo_offset	= sunxi_musb_fifo_offset,
601*4882a593Smuzhiyun 	.ep_offset	= sunxi_musb_ep_offset,
602*4882a593Smuzhiyun 	.busctl_offset	= sunxi_musb_busctl_offset,
603*4882a593Smuzhiyun 	.readb		= sunxi_musb_readb,
604*4882a593Smuzhiyun 	.writeb		= sunxi_musb_writeb,
605*4882a593Smuzhiyun 	.readw		= sunxi_musb_readw,
606*4882a593Smuzhiyun 	.writew		= sunxi_musb_writew,
607*4882a593Smuzhiyun 	.dma_init	= sunxi_musb_dma_controller_create,
608*4882a593Smuzhiyun 	.dma_exit	= sunxi_musb_dma_controller_destroy,
609*4882a593Smuzhiyun 	.set_mode	= sunxi_musb_set_mode,
610*4882a593Smuzhiyun 	.recover	= sunxi_musb_recover,
611*4882a593Smuzhiyun 	.set_vbus	= sunxi_musb_set_vbus,
612*4882a593Smuzhiyun 	.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
613*4882a593Smuzhiyun 	.post_root_reset_end = sunxi_musb_post_root_reset_end,
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun /* Allwinner OTG supports up to 5 endpoints */
617*4882a593Smuzhiyun #define SUNXI_MUSB_MAX_EP_NUM	6
618*4882a593Smuzhiyun #define SUNXI_MUSB_RAM_BITS	11
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
621*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
622*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
623*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
624*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
625*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
626*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
627*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
628*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
629*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
630*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
631*4882a593Smuzhiyun };
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun /* H3/V3s OTG supports only 4 endpoints */
634*4882a593Smuzhiyun #define SUNXI_MUSB_MAX_EP_NUM_H3	5
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
637*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
638*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
639*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
640*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
641*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
642*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
643*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
644*4882a593Smuzhiyun 	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
645*4882a593Smuzhiyun };
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun static const struct musb_hdrc_config sunxi_musb_hdrc_config = {
648*4882a593Smuzhiyun 	.fifo_cfg       = sunxi_musb_mode_cfg,
649*4882a593Smuzhiyun 	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg),
650*4882a593Smuzhiyun 	.multipoint	= true,
651*4882a593Smuzhiyun 	.dyn_fifo	= true,
652*4882a593Smuzhiyun 	.num_eps	= SUNXI_MUSB_MAX_EP_NUM,
653*4882a593Smuzhiyun 	.ram_bits	= SUNXI_MUSB_RAM_BITS,
654*4882a593Smuzhiyun };
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun static struct musb_hdrc_config sunxi_musb_hdrc_config_h3 = {
657*4882a593Smuzhiyun 	.fifo_cfg       = sunxi_musb_mode_cfg_h3,
658*4882a593Smuzhiyun 	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg_h3),
659*4882a593Smuzhiyun 	.multipoint	= true,
660*4882a593Smuzhiyun 	.dyn_fifo	= true,
661*4882a593Smuzhiyun 	.num_eps	= SUNXI_MUSB_MAX_EP_NUM_H3,
662*4882a593Smuzhiyun 	.ram_bits	= SUNXI_MUSB_RAM_BITS,
663*4882a593Smuzhiyun };
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 
sunxi_musb_probe(struct platform_device * pdev)666*4882a593Smuzhiyun static int sunxi_musb_probe(struct platform_device *pdev)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun 	struct musb_hdrc_platform_data	pdata;
669*4882a593Smuzhiyun 	struct platform_device_info	pinfo;
670*4882a593Smuzhiyun 	struct sunxi_glue		*glue;
671*4882a593Smuzhiyun 	struct device_node		*np = pdev->dev.of_node;
672*4882a593Smuzhiyun 	int ret;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (!np) {
675*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error no device tree node found\n");
676*4882a593Smuzhiyun 		return -EINVAL;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
680*4882a593Smuzhiyun 	if (!glue)
681*4882a593Smuzhiyun 		return -ENOMEM;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	memset(&pdata, 0, sizeof(pdata));
684*4882a593Smuzhiyun 	switch (usb_get_dr_mode(&pdev->dev)) {
685*4882a593Smuzhiyun #if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
686*4882a593Smuzhiyun 	case USB_DR_MODE_HOST:
687*4882a593Smuzhiyun 		pdata.mode = MUSB_HOST;
688*4882a593Smuzhiyun 		glue->phy_mode = PHY_MODE_USB_HOST;
689*4882a593Smuzhiyun 		break;
690*4882a593Smuzhiyun #endif
691*4882a593Smuzhiyun #if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET
692*4882a593Smuzhiyun 	case USB_DR_MODE_PERIPHERAL:
693*4882a593Smuzhiyun 		pdata.mode = MUSB_PERIPHERAL;
694*4882a593Smuzhiyun 		glue->phy_mode = PHY_MODE_USB_DEVICE;
695*4882a593Smuzhiyun 		break;
696*4882a593Smuzhiyun #endif
697*4882a593Smuzhiyun #ifdef CONFIG_USB_MUSB_DUAL_ROLE
698*4882a593Smuzhiyun 	case USB_DR_MODE_OTG:
699*4882a593Smuzhiyun 		pdata.mode = MUSB_OTG;
700*4882a593Smuzhiyun 		glue->phy_mode = PHY_MODE_USB_OTG;
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun #endif
703*4882a593Smuzhiyun 	default:
704*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
705*4882a593Smuzhiyun 		return -EINVAL;
706*4882a593Smuzhiyun 	}
707*4882a593Smuzhiyun 	pdata.platform_ops	= &sunxi_musb_ops;
708*4882a593Smuzhiyun 	if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb"))
709*4882a593Smuzhiyun 		pdata.config = &sunxi_musb_hdrc_config;
710*4882a593Smuzhiyun 	else
711*4882a593Smuzhiyun 		pdata.config = &sunxi_musb_hdrc_config_h3;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	glue->dev = &pdev->dev;
714*4882a593Smuzhiyun 	INIT_WORK(&glue->work, sunxi_musb_work);
715*4882a593Smuzhiyun 	glue->host_nb.notifier_call = sunxi_musb_host_notifier;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
718*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
721*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") ||
724*4882a593Smuzhiyun 	    of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) {
725*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
726*4882a593Smuzhiyun 		set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags);
727*4882a593Smuzhiyun 	}
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	glue->clk = devm_clk_get(&pdev->dev, NULL);
730*4882a593Smuzhiyun 	if (IS_ERR(glue->clk)) {
731*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error getting clock: %ld\n",
732*4882a593Smuzhiyun 			PTR_ERR(glue->clk));
733*4882a593Smuzhiyun 		return PTR_ERR(glue->clk);
734*4882a593Smuzhiyun 	}
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
737*4882a593Smuzhiyun 		glue->rst = devm_reset_control_get(&pdev->dev, NULL);
738*4882a593Smuzhiyun 		if (IS_ERR(glue->rst)) {
739*4882a593Smuzhiyun 			if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
740*4882a593Smuzhiyun 				return -EPROBE_DEFER;
741*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Error getting reset %ld\n",
742*4882a593Smuzhiyun 				PTR_ERR(glue->rst));
743*4882a593Smuzhiyun 			return PTR_ERR(glue->rst);
744*4882a593Smuzhiyun 		}
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
748*4882a593Smuzhiyun 	if (IS_ERR(glue->extcon)) {
749*4882a593Smuzhiyun 		if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
750*4882a593Smuzhiyun 			return -EPROBE_DEFER;
751*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Invalid or missing extcon\n");
752*4882a593Smuzhiyun 		return PTR_ERR(glue->extcon);
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	glue->phy = devm_phy_get(&pdev->dev, "usb");
756*4882a593Smuzhiyun 	if (IS_ERR(glue->phy)) {
757*4882a593Smuzhiyun 		if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
758*4882a593Smuzhiyun 			return -EPROBE_DEFER;
759*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error getting phy %ld\n",
760*4882a593Smuzhiyun 			PTR_ERR(glue->phy));
761*4882a593Smuzhiyun 		return PTR_ERR(glue->phy);
762*4882a593Smuzhiyun 	}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	glue->usb_phy = usb_phy_generic_register();
765*4882a593Smuzhiyun 	if (IS_ERR(glue->usb_phy)) {
766*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error registering usb-phy %ld\n",
767*4882a593Smuzhiyun 			PTR_ERR(glue->usb_phy));
768*4882a593Smuzhiyun 		return PTR_ERR(glue->usb_phy);
769*4882a593Smuzhiyun 	}
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
772*4882a593Smuzhiyun 	if (IS_ERR(glue->xceiv)) {
773*4882a593Smuzhiyun 		ret = PTR_ERR(glue->xceiv);
774*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret);
775*4882a593Smuzhiyun 		goto err_unregister_usb_phy;
776*4882a593Smuzhiyun 	}
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	platform_set_drvdata(pdev, glue);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	memset(&pinfo, 0, sizeof(pinfo));
781*4882a593Smuzhiyun 	pinfo.name	 = "musb-hdrc";
782*4882a593Smuzhiyun 	pinfo.id	= PLATFORM_DEVID_AUTO;
783*4882a593Smuzhiyun 	pinfo.parent	= &pdev->dev;
784*4882a593Smuzhiyun 	pinfo.fwnode	= of_fwnode_handle(pdev->dev.of_node);
785*4882a593Smuzhiyun 	pinfo.of_node_reused = true;
786*4882a593Smuzhiyun 	pinfo.res	= pdev->resource;
787*4882a593Smuzhiyun 	pinfo.num_res	= pdev->num_resources;
788*4882a593Smuzhiyun 	pinfo.data	= &pdata;
789*4882a593Smuzhiyun 	pinfo.size_data = sizeof(pdata);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	glue->musb_pdev = platform_device_register_full(&pinfo);
792*4882a593Smuzhiyun 	if (IS_ERR(glue->musb_pdev)) {
793*4882a593Smuzhiyun 		ret = PTR_ERR(glue->musb_pdev);
794*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
795*4882a593Smuzhiyun 		goto err_unregister_usb_phy;
796*4882a593Smuzhiyun 	}
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	return 0;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun err_unregister_usb_phy:
801*4882a593Smuzhiyun 	usb_phy_generic_unregister(glue->usb_phy);
802*4882a593Smuzhiyun 	return ret;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
sunxi_musb_remove(struct platform_device * pdev)805*4882a593Smuzhiyun static int sunxi_musb_remove(struct platform_device *pdev)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun 	struct sunxi_glue *glue = platform_get_drvdata(pdev);
808*4882a593Smuzhiyun 	struct platform_device *usb_phy = glue->usb_phy;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	platform_device_unregister(glue->musb_pdev);
811*4882a593Smuzhiyun 	usb_phy_generic_unregister(usb_phy);
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	return 0;
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun static const struct of_device_id sunxi_musb_match[] = {
817*4882a593Smuzhiyun 	{ .compatible = "allwinner,sun4i-a10-musb", },
818*4882a593Smuzhiyun 	{ .compatible = "allwinner,sun6i-a31-musb", },
819*4882a593Smuzhiyun 	{ .compatible = "allwinner,sun8i-a33-musb", },
820*4882a593Smuzhiyun 	{ .compatible = "allwinner,sun8i-h3-musb", },
821*4882a593Smuzhiyun 	{}
822*4882a593Smuzhiyun };
823*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sunxi_musb_match);
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun static struct platform_driver sunxi_musb_driver = {
826*4882a593Smuzhiyun 	.probe = sunxi_musb_probe,
827*4882a593Smuzhiyun 	.remove = sunxi_musb_remove,
828*4882a593Smuzhiyun 	.driver = {
829*4882a593Smuzhiyun 		.name = "musb-sunxi",
830*4882a593Smuzhiyun 		.of_match_table = sunxi_musb_match,
831*4882a593Smuzhiyun 	},
832*4882a593Smuzhiyun };
833*4882a593Smuzhiyun module_platform_driver(sunxi_musb_driver);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer");
836*4882a593Smuzhiyun MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
837*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
838