xref: /rk3399_rockchip-uboot/drivers/usb/musb-new/da8xx.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
1*3e620e50SAdam Ford // SPDX-License-Identifier: GPL-2.0
2*3e620e50SAdam Ford /*
3*3e620e50SAdam Ford  * Texas Instruments da8xx "glue layer"
4*3e620e50SAdam Ford  *
5*3e620e50SAdam Ford  * Copyright (c) 2019, by Texas Instruments
6*3e620e50SAdam Ford  *
7*3e620e50SAdam Ford  * Based on the DA8xx "glue layer" code.
8*3e620e50SAdam Ford  * Copyright (c) 2008-2019, MontaVista Software, Inc. <source@mvista.com>
9*3e620e50SAdam Ford  *
10*3e620e50SAdam Ford  * DT support
11*3e620e50SAdam Ford  * Copyright (c) 2016 Petr Kulhavy <petr@barix.com>
12*3e620e50SAdam Ford  * This file is part of the Inventra Controller Driver for Linux.
13*3e620e50SAdam Ford  *
14*3e620e50SAdam Ford  */
15*3e620e50SAdam Ford 
16*3e620e50SAdam Ford #include <common.h>
17*3e620e50SAdam Ford #include <dm.h>
18*3e620e50SAdam Ford #include <dm/device-internal.h>
19*3e620e50SAdam Ford #include <dm/lists.h>
20*3e620e50SAdam Ford #include <asm/arch/hardware.h>
21*3e620e50SAdam Ford #include <asm/arch/da8xx-usb.h>
22*3e620e50SAdam Ford #include <linux/usb/otg.h>
23*3e620e50SAdam Ford #include <asm/omap_musb.h>
24*3e620e50SAdam Ford #include <generic-phy.h>
25*3e620e50SAdam Ford #include "linux-compat.h"
26*3e620e50SAdam Ford #include "musb_core.h"
27*3e620e50SAdam Ford #include "musb_uboot.h"
28*3e620e50SAdam Ford 
29*3e620e50SAdam Ford /* USB 2.0 OTG module registers */
30*3e620e50SAdam Ford #define DA8XX_USB_REVISION_REG	0x00
31*3e620e50SAdam Ford #define DA8XX_USB_CTRL_REG	0x04
32*3e620e50SAdam Ford #define DA8XX_USB_STAT_REG	0x08
33*3e620e50SAdam Ford #define DA8XX_USB_EMULATION_REG 0x0c
34*3e620e50SAdam Ford #define DA8XX_USB_SRP_FIX_TIME_REG 0x18
35*3e620e50SAdam Ford #define DA8XX_USB_INTR_SRC_REG	0x20
36*3e620e50SAdam Ford #define DA8XX_USB_INTR_SRC_SET_REG 0x24
37*3e620e50SAdam Ford #define DA8XX_USB_INTR_SRC_CLEAR_REG 0x28
38*3e620e50SAdam Ford #define DA8XX_USB_INTR_MASK_REG 0x2c
39*3e620e50SAdam Ford #define DA8XX_USB_INTR_MASK_SET_REG 0x30
40*3e620e50SAdam Ford #define DA8XX_USB_INTR_MASK_CLEAR_REG 0x34
41*3e620e50SAdam Ford #define DA8XX_USB_INTR_SRC_MASKED_REG 0x38
42*3e620e50SAdam Ford #define DA8XX_USB_END_OF_INTR_REG 0x3c
43*3e620e50SAdam Ford #define DA8XX_USB_GENERIC_RNDIS_EP_SIZE_REG(n) (0x50 + (((n) - 1) << 2))
44*3e620e50SAdam Ford 
45*3e620e50SAdam Ford /* Control register bits */
46*3e620e50SAdam Ford #define DA8XX_SOFT_RESET_MASK	1
47*3e620e50SAdam Ford 
48*3e620e50SAdam Ford #define DA8XX_USB_TX_EP_MASK	0x1f		/* EP0 + 4 Tx EPs */
49*3e620e50SAdam Ford #define DA8XX_USB_RX_EP_MASK	0x1e		/* 4 Rx EPs */
50*3e620e50SAdam Ford 
51*3e620e50SAdam Ford /* USB interrupt register bits */
52*3e620e50SAdam Ford #define DA8XX_INTR_USB_SHIFT	16
53*3e620e50SAdam Ford #define DA8XX_INTR_USB_MASK	(0x1ff << DA8XX_INTR_USB_SHIFT) /* 8 Mentor */
54*3e620e50SAdam Ford 					/* interrupts and DRVVBUS interrupt */
55*3e620e50SAdam Ford #define DA8XX_INTR_DRVVBUS	0x100
56*3e620e50SAdam Ford #define DA8XX_INTR_RX_SHIFT	8
57*3e620e50SAdam Ford #define DA8XX_INTR_RX_MASK	(DA8XX_USB_RX_EP_MASK << DA8XX_INTR_RX_SHIFT)
58*3e620e50SAdam Ford #define DA8XX_INTR_TX_SHIFT	0
59*3e620e50SAdam Ford #define DA8XX_INTR_TX_MASK	(DA8XX_USB_TX_EP_MASK << DA8XX_INTR_TX_SHIFT)
60*3e620e50SAdam Ford 
61*3e620e50SAdam Ford #define DA8XX_MENTOR_CORE_OFFSET 0x400
62*3e620e50SAdam Ford 
da8xx_musb_interrupt(int irq,void * hci)63*3e620e50SAdam Ford static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
64*3e620e50SAdam Ford {
65*3e620e50SAdam Ford 	struct musb		*musb = hci;
66*3e620e50SAdam Ford 	void __iomem		*reg_base = musb->ctrl_base;
67*3e620e50SAdam Ford 	unsigned long		flags;
68*3e620e50SAdam Ford 	irqreturn_t		ret = IRQ_NONE;
69*3e620e50SAdam Ford 	u32			status;
70*3e620e50SAdam Ford 
71*3e620e50SAdam Ford 	spin_lock_irqsave(&musb->lock, flags);
72*3e620e50SAdam Ford 
73*3e620e50SAdam Ford 	/*
74*3e620e50SAdam Ford 	 * NOTE: DA8XX shadows the Mentor IRQs.  Don't manage them through
75*3e620e50SAdam Ford 	 * the Mentor registers (except for setup), use the TI ones and EOI.
76*3e620e50SAdam Ford 	 */
77*3e620e50SAdam Ford 
78*3e620e50SAdam Ford 	/* Acknowledge and handle non-CPPI interrupts */
79*3e620e50SAdam Ford 	status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG);
80*3e620e50SAdam Ford 	if (!status)
81*3e620e50SAdam Ford 		goto eoi;
82*3e620e50SAdam Ford 
83*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status);
84*3e620e50SAdam Ford 	dev_dbg(musb->controller, "USB IRQ %08x\n", status);
85*3e620e50SAdam Ford 
86*3e620e50SAdam Ford 	musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;
87*3e620e50SAdam Ford 	musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT;
88*3e620e50SAdam Ford 	musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT;
89*3e620e50SAdam Ford 
90*3e620e50SAdam Ford 	/*
91*3e620e50SAdam Ford 	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
92*3e620e50SAdam Ford 	 * DA8xx's missing ID change IRQ.  We need an ID change IRQ to
93*3e620e50SAdam Ford 	 * switch appropriately between halves of the OTG state machine.
94*3e620e50SAdam Ford 	 * Managing DEVCTL.Session per Mentor docs requires that we know its
95*3e620e50SAdam Ford 	 * value but DEVCTL.BDevice is invalid without DEVCTL.Session set.
96*3e620e50SAdam Ford 	 * Also, DRVVBUS pulses for SRP (but not at 5 V)...
97*3e620e50SAdam Ford 	 */
98*3e620e50SAdam Ford 	if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) {
99*3e620e50SAdam Ford 		int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG);
100*3e620e50SAdam Ford 		void __iomem *mregs = musb->mregs;
101*3e620e50SAdam Ford 		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
102*3e620e50SAdam Ford 		int err;
103*3e620e50SAdam Ford 
104*3e620e50SAdam Ford 		err = musb->int_usb & MUSB_INTR_VBUSERROR;
105*3e620e50SAdam Ford 		if (err) {
106*3e620e50SAdam Ford 			/*
107*3e620e50SAdam Ford 			 * The Mentor core doesn't debounce VBUS as needed
108*3e620e50SAdam Ford 			 * to cope with device connect current spikes. This
109*3e620e50SAdam Ford 			 * means it's not uncommon for bus-powered devices
110*3e620e50SAdam Ford 			 * to get VBUS errors during enumeration.
111*3e620e50SAdam Ford 			 *
112*3e620e50SAdam Ford 			 * This is a workaround, but newer RTL from Mentor
113*3e620e50SAdam Ford 			 * seems to allow a better one: "re"-starting sessions
114*3e620e50SAdam Ford 			 * without waiting for VBUS to stop registering in
115*3e620e50SAdam Ford 			 * devctl.
116*3e620e50SAdam Ford 			 */
117*3e620e50SAdam Ford 			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
118*3e620e50SAdam Ford 			WARNING("VBUS error workaround (delay coming)\n");
119*3e620e50SAdam Ford 		} else if (drvvbus) {
120*3e620e50SAdam Ford 			MUSB_HST_MODE(musb);
121*3e620e50SAdam Ford 			musb->port1_status |= USB_PORT_STAT_POWER;
122*3e620e50SAdam Ford 		} else if (!(musb->int_usb & MUSB_INTR_BABBLE)) {
123*3e620e50SAdam Ford 			/*
124*3e620e50SAdam Ford 			 * When babble condition happens, drvvbus interrupt
125*3e620e50SAdam Ford 			 * is also generated. Ignore this drvvbus interrupt
126*3e620e50SAdam Ford 			 * and let babble interrupt handler recovers the
127*3e620e50SAdam Ford 			 * controller; otherwise, the host-mode flag is lost
128*3e620e50SAdam Ford 			 * due to the MUSB_DEV_MODE() call below and babble
129*3e620e50SAdam Ford 			 * recovery logic will not be called.
130*3e620e50SAdam Ford 			 */
131*3e620e50SAdam Ford 			musb->is_active = 0;
132*3e620e50SAdam Ford 			MUSB_DEV_MODE(musb);
133*3e620e50SAdam Ford 			musb->port1_status &= ~USB_PORT_STAT_POWER;
134*3e620e50SAdam Ford 		}
135*3e620e50SAdam Ford 		ret = IRQ_HANDLED;
136*3e620e50SAdam Ford 	}
137*3e620e50SAdam Ford 
138*3e620e50SAdam Ford 	if (musb->int_tx || musb->int_rx || musb->int_usb)
139*3e620e50SAdam Ford 		ret |= musb_interrupt(musb);
140*3e620e50SAdam Ford eoi:
141*3e620e50SAdam Ford 	/* EOI needs to be written for the IRQ to be re-asserted. */
142*3e620e50SAdam Ford 	if (ret == IRQ_HANDLED || status)
143*3e620e50SAdam Ford 		musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
144*3e620e50SAdam Ford 
145*3e620e50SAdam Ford 	spin_unlock_irqrestore(&musb->lock, flags);
146*3e620e50SAdam Ford 
147*3e620e50SAdam Ford 	return ret;
148*3e620e50SAdam Ford }
149*3e620e50SAdam Ford 
da8xx_musb_init(struct musb * musb)150*3e620e50SAdam Ford static int da8xx_musb_init(struct musb *musb)
151*3e620e50SAdam Ford {
152*3e620e50SAdam Ford 	u32  revision;
153*3e620e50SAdam Ford 	void __iomem *reg_base = musb->ctrl_base;
154*3e620e50SAdam Ford 
155*3e620e50SAdam Ford 	int ret;
156*3e620e50SAdam Ford 
157*3e620e50SAdam Ford 	/* reset the controller */
158*3e620e50SAdam Ford 	writel(0x1, &da8xx_usb_regs->control);
159*3e620e50SAdam Ford 	udelay(50);
160*3e620e50SAdam Ford 
161*3e620e50SAdam Ford 	/* Returns zero if e.g. not clocked */
162*3e620e50SAdam Ford 	revision = readl(&da8xx_usb_regs->revision);
163*3e620e50SAdam Ford 	if (revision == 0)
164*3e620e50SAdam Ford 		return -ENODEV;
165*3e620e50SAdam Ford 
166*3e620e50SAdam Ford 	/* Disable all interrupts */
167*3e620e50SAdam Ford 	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
168*3e620e50SAdam Ford 		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set);
169*3e620e50SAdam Ford 
170*3e620e50SAdam Ford 	musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
171*3e620e50SAdam Ford 
172*3e620e50SAdam Ford 	/* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */
173*3e620e50SAdam Ford 	debug("DA8xx OTG revision %08x, control %02x\n", revision,
174*3e620e50SAdam Ford 	      musb_readb(reg_base, DA8XX_USB_CTRL_REG));
175*3e620e50SAdam Ford 
176*3e620e50SAdam Ford 	musb->isr = da8xx_musb_interrupt;
177*3e620e50SAdam Ford 	return 0;
178*3e620e50SAdam Ford }
179*3e620e50SAdam Ford 
da8xx_musb_exit(struct musb * musb)180*3e620e50SAdam Ford static int da8xx_musb_exit(struct musb *musb)
181*3e620e50SAdam Ford {
182*3e620e50SAdam Ford 	/* flush any interrupts */
183*3e620e50SAdam Ford 	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
184*3e620e50SAdam Ford 		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
185*3e620e50SAdam Ford 	writel(0, &da8xx_usb_regs->eoi);
186*3e620e50SAdam Ford 
187*3e620e50SAdam Ford 	return 0;
188*3e620e50SAdam Ford }
189*3e620e50SAdam Ford 
190*3e620e50SAdam Ford /**
191*3e620e50SAdam Ford  * da8xx_musb_enable - enable interrupts
192*3e620e50SAdam Ford  */
da8xx_musb_enable(struct musb * musb)193*3e620e50SAdam Ford static int da8xx_musb_enable(struct musb *musb)
194*3e620e50SAdam Ford {
195*3e620e50SAdam Ford 	void __iomem *reg_base = musb->ctrl_base;
196*3e620e50SAdam Ford 	u32 mask;
197*3e620e50SAdam Ford 
198*3e620e50SAdam Ford 	/* Workaround: setup IRQs through both register sets. */
199*3e620e50SAdam Ford 	mask = ((musb->epmask & DA8XX_USB_TX_EP_MASK) << DA8XX_INTR_TX_SHIFT) |
200*3e620e50SAdam Ford 	       ((musb->epmask & DA8XX_USB_RX_EP_MASK) << DA8XX_INTR_RX_SHIFT) |
201*3e620e50SAdam Ford 	       DA8XX_INTR_USB_MASK;
202*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
203*3e620e50SAdam Ford 
204*3e620e50SAdam Ford 	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
205*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
206*3e620e50SAdam Ford 		    DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
207*3e620e50SAdam Ford 
208*3e620e50SAdam Ford 	return 0;
209*3e620e50SAdam Ford }
210*3e620e50SAdam Ford 
211*3e620e50SAdam Ford /**
212*3e620e50SAdam Ford  * da8xx_musb_disable - disable HDRC and flush interrupts
213*3e620e50SAdam Ford  */
da8xx_musb_disable(struct musb * musb)214*3e620e50SAdam Ford static void da8xx_musb_disable(struct musb *musb)
215*3e620e50SAdam Ford {
216*3e620e50SAdam Ford 	void __iomem *reg_base = musb->ctrl_base;
217*3e620e50SAdam Ford 
218*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG,
219*3e620e50SAdam Ford 		    DA8XX_INTR_USB_MASK |
220*3e620e50SAdam Ford 		    DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK);
221*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
222*3e620e50SAdam Ford }
223*3e620e50SAdam Ford 
da8xx_musb_reset(struct udevice * dev)224*3e620e50SAdam Ford void da8xx_musb_reset(struct udevice *dev)
225*3e620e50SAdam Ford {
226*3e620e50SAdam Ford 	void *reg_base = dev_read_addr_ptr(dev);
227*3e620e50SAdam Ford 
228*3e620e50SAdam Ford 	/* Reset the controller */
229*3e620e50SAdam Ford 	musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
230*3e620e50SAdam Ford }
231*3e620e50SAdam Ford 
da8xx_musb_clear_irq(struct udevice * dev)232*3e620e50SAdam Ford void da8xx_musb_clear_irq(struct udevice *dev)
233*3e620e50SAdam Ford {
234*3e620e50SAdam Ford 	/* flush any interrupts */
235*3e620e50SAdam Ford 	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
236*3e620e50SAdam Ford 		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
237*3e620e50SAdam Ford 	writel(0, &da8xx_usb_regs->eoi);
238*3e620e50SAdam Ford }
239*3e620e50SAdam Ford 
240*3e620e50SAdam Ford const struct musb_platform_ops da8xx_ops = {
241*3e620e50SAdam Ford 	.init		= da8xx_musb_init,
242*3e620e50SAdam Ford 	.exit		= da8xx_musb_exit,
243*3e620e50SAdam Ford 	.enable		= da8xx_musb_enable,
244*3e620e50SAdam Ford 	.disable	= da8xx_musb_disable,
245*3e620e50SAdam Ford };
246*3e620e50SAdam Ford 
247*3e620e50SAdam Ford struct da8xx_musb_platdata {
248*3e620e50SAdam Ford 	void *base;
249*3e620e50SAdam Ford 	void *ctrl_mod_base;
250*3e620e50SAdam Ford 	struct musb_hdrc_platform_data plat;
251*3e620e50SAdam Ford 	struct musb_hdrc_config musb_config;
252*3e620e50SAdam Ford 	struct omap_musb_board_data otg_board_data;
253*3e620e50SAdam Ford 	struct phy phy;
254*3e620e50SAdam Ford };
255*3e620e50SAdam Ford 
da8xx_musb_ofdata_to_platdata(struct udevice * dev)256*3e620e50SAdam Ford static int da8xx_musb_ofdata_to_platdata(struct udevice *dev)
257*3e620e50SAdam Ford {
258*3e620e50SAdam Ford 	struct da8xx_musb_platdata *platdata = dev_get_platdata(dev);
259*3e620e50SAdam Ford 	const void *fdt = gd->fdt_blob;
260*3e620e50SAdam Ford 	int node = dev_of_offset(dev);
261*3e620e50SAdam Ford 
262*3e620e50SAdam Ford 	platdata->base = (void *)dev_read_addr_ptr(dev);
263*3e620e50SAdam Ford 	platdata->musb_config.multipoint = 1;
264*3e620e50SAdam Ford 	platdata->musb_config.dyn_fifo = 1;
265*3e620e50SAdam Ford 	platdata->musb_config.num_eps = 5;
266*3e620e50SAdam Ford 	platdata->musb_config.ram_bits = 10;
267*3e620e50SAdam Ford 	platdata->plat.power = fdtdec_get_int(fdt, node, "power", 50);
268*3e620e50SAdam Ford 	platdata->otg_board_data.interface_type = MUSB_INTERFACE_UTMI;
269*3e620e50SAdam Ford 	platdata->plat.mode = MUSB_HOST;
270*3e620e50SAdam Ford 	platdata->otg_board_data.dev = dev;
271*3e620e50SAdam Ford 	platdata->plat.config = &platdata->musb_config;
272*3e620e50SAdam Ford 	platdata->plat.platform_ops = &da8xx_ops;
273*3e620e50SAdam Ford 	platdata->plat.board_data = &platdata->otg_board_data;
274*3e620e50SAdam Ford 	platdata->otg_board_data.clear_irq = da8xx_musb_clear_irq;
275*3e620e50SAdam Ford 	platdata->otg_board_data.reset = da8xx_musb_reset;
276*3e620e50SAdam Ford 	return 0;
277*3e620e50SAdam Ford }
278*3e620e50SAdam Ford 
da8xx_musb_probe(struct udevice * dev)279*3e620e50SAdam Ford static int da8xx_musb_probe(struct udevice *dev)
280*3e620e50SAdam Ford {
281*3e620e50SAdam Ford 	struct musb_host_data *host = dev_get_priv(dev);
282*3e620e50SAdam Ford 	struct da8xx_musb_platdata *platdata = dev_get_platdata(dev);
283*3e620e50SAdam Ford 	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
284*3e620e50SAdam Ford 	struct omap_musb_board_data *otg_board_data;
285*3e620e50SAdam Ford 	int ret;
286*3e620e50SAdam Ford 	void *base = dev_read_addr_ptr(dev);
287*3e620e50SAdam Ford 
288*3e620e50SAdam Ford 	/* Get the phy info from the device tree */
289*3e620e50SAdam Ford 	ret = generic_phy_get_by_name(dev, "usb-phy", &platdata->phy);
290*3e620e50SAdam Ford 	if (ret)
291*3e620e50SAdam Ford 		return ret;
292*3e620e50SAdam Ford 
293*3e620e50SAdam Ford 	/* Initialize the phy */
294*3e620e50SAdam Ford 	ret = generic_phy_init(&platdata->phy);
295*3e620e50SAdam Ford 	if (ret)
296*3e620e50SAdam Ford 		return ret;
297*3e620e50SAdam Ford 
298*3e620e50SAdam Ford 	/* enable psc for usb2.0 */
299*3e620e50SAdam Ford 	lpsc_on(33);
300*3e620e50SAdam Ford 
301*3e620e50SAdam Ford 	/* Enable phy */
302*3e620e50SAdam Ford 	generic_phy_power_on(&platdata->phy);
303*3e620e50SAdam Ford 
304*3e620e50SAdam Ford 	priv->desc_before_addr = true;
305*3e620e50SAdam Ford 	otg_board_data = &platdata->otg_board_data;
306*3e620e50SAdam Ford 
307*3e620e50SAdam Ford 	host->host = musb_init_controller(&platdata->plat,
308*3e620e50SAdam Ford 					  (struct device *)otg_board_data,
309*3e620e50SAdam Ford 					  platdata->base);
310*3e620e50SAdam Ford 	if (!host->host) {
311*3e620e50SAdam Ford 		ret = -ENODEV;
312*3e620e50SAdam Ford 		goto shutdown; /* Shutdown what we started */
313*3e620e50SAdam Ford 	}
314*3e620e50SAdam Ford 
315*3e620e50SAdam Ford 	ret = musb_lowlevel_init(host);
316*3e620e50SAdam Ford 
317*3e620e50SAdam Ford 	if (ret == 0)
318*3e620e50SAdam Ford 		return 0;
319*3e620e50SAdam Ford shutdown:
320*3e620e50SAdam Ford 	/* Turn off the phy if we fail */
321*3e620e50SAdam Ford 	generic_phy_power_off(&platdata->phy);
322*3e620e50SAdam Ford 	lpsc_disable(33);
323*3e620e50SAdam Ford 	return ret;
324*3e620e50SAdam Ford }
325*3e620e50SAdam Ford 
da8xx_musb_remove(struct udevice * dev)326*3e620e50SAdam Ford static int da8xx_musb_remove(struct udevice *dev)
327*3e620e50SAdam Ford {
328*3e620e50SAdam Ford 	struct musb_host_data *host = dev_get_priv(dev);
329*3e620e50SAdam Ford 
330*3e620e50SAdam Ford 	musb_stop(host->host);
331*3e620e50SAdam Ford 
332*3e620e50SAdam Ford 	return 0;
333*3e620e50SAdam Ford }
334*3e620e50SAdam Ford 
335*3e620e50SAdam Ford static const struct udevice_id da8xx_musb_ids[] = {
336*3e620e50SAdam Ford 	{ .compatible = "ti,da830-musb" },
337*3e620e50SAdam Ford 	{ }
338*3e620e50SAdam Ford };
339*3e620e50SAdam Ford 
340*3e620e50SAdam Ford U_BOOT_DRIVER(da8xx_musb) = {
341*3e620e50SAdam Ford 	.name	= "da8xx-musb",
342*3e620e50SAdam Ford 	.id		= UCLASS_USB,
343*3e620e50SAdam Ford 	.of_match = da8xx_musb_ids,
344*3e620e50SAdam Ford 	.ofdata_to_platdata = da8xx_musb_ofdata_to_platdata,
345*3e620e50SAdam Ford 	.probe = da8xx_musb_probe,
346*3e620e50SAdam Ford 	.remove = da8xx_musb_remove,
347*3e620e50SAdam Ford 	.ops = &musb_usb_ops,
348*3e620e50SAdam Ford 	.platdata_auto_alloc_size = sizeof(struct da8xx_musb_platdata),
349*3e620e50SAdam Ford 	.priv_auto_alloc_size = sizeof(struct musb_host_data),
350*3e620e50SAdam Ford };
351