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