1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/arch/arm/mach-pxa/pxa3xx-ulpi.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * code specific to pxa3xx aka Monahans
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2010 CompuLab Ltd.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * 2010-13-07: Igor Grinberg <grinberg@compulab.co.il>
10*4882a593Smuzhiyun * initial version: pxa310 USB Host mode support
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/device.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/err.h>
19*4882a593Smuzhiyun #include <linux/io.h>
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/clk.h>
22*4882a593Smuzhiyun #include <linux/usb.h>
23*4882a593Smuzhiyun #include <linux/usb/otg.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <mach/hardware.h>
26*4882a593Smuzhiyun #include "regs-u2d.h"
27*4882a593Smuzhiyun #include <linux/platform_data/usb-pxa3xx-ulpi.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct pxa3xx_u2d_ulpi {
30*4882a593Smuzhiyun struct clk *clk;
31*4882a593Smuzhiyun void __iomem *mmio_base;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun struct usb_phy *otg;
34*4882a593Smuzhiyun unsigned int ulpi_mode;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static struct pxa3xx_u2d_ulpi *u2d;
38*4882a593Smuzhiyun
u2d_readl(u32 reg)39*4882a593Smuzhiyun static inline u32 u2d_readl(u32 reg)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun return __raw_readl(u2d->mmio_base + reg);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
u2d_writel(u32 reg,u32 val)44*4882a593Smuzhiyun static inline void u2d_writel(u32 reg, u32 val)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun __raw_writel(val, u2d->mmio_base + reg);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #if defined(CONFIG_PXA310_ULPI)
50*4882a593Smuzhiyun enum u2d_ulpi_phy_mode {
51*4882a593Smuzhiyun SYNCH = 0,
52*4882a593Smuzhiyun CARKIT = (1 << 0),
53*4882a593Smuzhiyun SER_3PIN = (1 << 1),
54*4882a593Smuzhiyun SER_6PIN = (1 << 2),
55*4882a593Smuzhiyun LOWPOWER = (1 << 3),
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
pxa310_ulpi_get_phymode(void)58*4882a593Smuzhiyun static inline enum u2d_ulpi_phy_mode pxa310_ulpi_get_phymode(void)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun return (u2d_readl(U2DOTGUSR) >> 28) & 0xF;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
pxa310_ulpi_poll(void)63*4882a593Smuzhiyun static int pxa310_ulpi_poll(void)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun int timeout = 50000;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun while (timeout--) {
68*4882a593Smuzhiyun if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun cpu_relax();
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun pr_warn("%s: ULPI access timed out!\n", __func__);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return -ETIMEDOUT;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
pxa310_ulpi_read(struct usb_phy * otg,u32 reg)79*4882a593Smuzhiyun static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun int err;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (pxa310_ulpi_get_phymode() != SYNCH) {
84*4882a593Smuzhiyun pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
85*4882a593Smuzhiyun return -EBUSY;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << 16));
89*4882a593Smuzhiyun msleep(5);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun err = pxa310_ulpi_poll();
92*4882a593Smuzhiyun if (err)
93*4882a593Smuzhiyun return err;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
pxa310_ulpi_write(struct usb_phy * otg,u32 val,u32 reg)98*4882a593Smuzhiyun static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun if (pxa310_ulpi_get_phymode() != SYNCH) {
101*4882a593Smuzhiyun pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
102*4882a593Smuzhiyun return -EBUSY;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << 16) | (val << 8));
106*4882a593Smuzhiyun msleep(5);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return pxa310_ulpi_poll();
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun struct usb_phy_io_ops pxa310_ulpi_access_ops = {
112*4882a593Smuzhiyun .read = pxa310_ulpi_read,
113*4882a593Smuzhiyun .write = pxa310_ulpi_write,
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun
pxa310_otg_transceiver_rtsm(void)116*4882a593Smuzhiyun static void pxa310_otg_transceiver_rtsm(void)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun u32 u2dotgcr;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* put PHY to sync mode */
121*4882a593Smuzhiyun u2dotgcr = u2d_readl(U2DOTGCR);
122*4882a593Smuzhiyun u2dotgcr |= U2DOTGCR_RTSM | U2DOTGCR_UTMID;
123*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2dotgcr);
124*4882a593Smuzhiyun msleep(10);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* setup OTG sync mode */
127*4882a593Smuzhiyun u2dotgcr = u2d_readl(U2DOTGCR);
128*4882a593Smuzhiyun u2dotgcr |= U2DOTGCR_ULAF;
129*4882a593Smuzhiyun u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
130*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2dotgcr);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
pxa310_start_otg_host_transcvr(struct usb_bus * host)133*4882a593Smuzhiyun static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun int err;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun pxa310_otg_transceiver_rtsm();
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun err = usb_phy_init(u2d->otg);
140*4882a593Smuzhiyun if (err) {
141*4882a593Smuzhiyun pr_err("OTG transceiver init failed");
142*4882a593Smuzhiyun return err;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun err = otg_set_vbus(u2d->otg->otg, 1);
146*4882a593Smuzhiyun if (err) {
147*4882a593Smuzhiyun pr_err("OTG transceiver VBUS set failed");
148*4882a593Smuzhiyun return err;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun err = otg_set_host(u2d->otg->otg, host);
152*4882a593Smuzhiyun if (err)
153*4882a593Smuzhiyun pr_err("OTG transceiver Host mode set failed");
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return err;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
pxa310_start_otg_hc(struct usb_bus * host)158*4882a593Smuzhiyun static int pxa310_start_otg_hc(struct usb_bus *host)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun u32 u2dotgcr;
161*4882a593Smuzhiyun int err;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* disable USB device controller */
164*4882a593Smuzhiyun u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
165*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
166*4882a593Smuzhiyun u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun err = pxa310_start_otg_host_transcvr(host);
169*4882a593Smuzhiyun if (err)
170*4882a593Smuzhiyun return err;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* set xceiver mode */
173*4882a593Smuzhiyun if (u2d->ulpi_mode & ULPI_IC_6PIN_SERIAL)
174*4882a593Smuzhiyun u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
175*4882a593Smuzhiyun else if (u2d->ulpi_mode & ULPI_IC_3PIN_SERIAL)
176*4882a593Smuzhiyun u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* start OTG host controller */
179*4882a593Smuzhiyun u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
180*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun return 0;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
pxa310_stop_otg_hc(void)185*4882a593Smuzhiyun static void pxa310_stop_otg_hc(void)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun pxa310_otg_transceiver_rtsm();
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun otg_set_host(u2d->otg->otg, NULL);
190*4882a593Smuzhiyun otg_set_vbus(u2d->otg->otg, 0);
191*4882a593Smuzhiyun usb_phy_shutdown(u2d->otg);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
pxa310_u2d_setup_otg_hc(void)194*4882a593Smuzhiyun static void pxa310_u2d_setup_otg_hc(void)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun u32 u2dotgcr;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun u2dotgcr = u2d_readl(U2DOTGCR);
199*4882a593Smuzhiyun u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
200*4882a593Smuzhiyun u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
201*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2dotgcr);
202*4882a593Smuzhiyun msleep(5);
203*4882a593Smuzhiyun u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
204*4882a593Smuzhiyun msleep(5);
205*4882a593Smuzhiyun u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
pxa310_otg_init(struct pxa3xx_u2d_platform_data * pdata)208*4882a593Smuzhiyun static int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun unsigned int ulpi_mode = ULPI_OTG_DRVVBUS;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (pdata) {
213*4882a593Smuzhiyun if (pdata->ulpi_mode & ULPI_SER_6PIN)
214*4882a593Smuzhiyun ulpi_mode |= ULPI_IC_6PIN_SERIAL;
215*4882a593Smuzhiyun else if (pdata->ulpi_mode & ULPI_SER_3PIN)
216*4882a593Smuzhiyun ulpi_mode |= ULPI_IC_3PIN_SERIAL;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun u2d->ulpi_mode = ulpi_mode;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun u2d->otg = otg_ulpi_create(&pxa310_ulpi_access_ops, ulpi_mode);
222*4882a593Smuzhiyun if (!u2d->otg)
223*4882a593Smuzhiyun return -ENOMEM;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun u2d->otg->io_priv = u2d->mmio_base;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
pxa310_otg_exit(void)230*4882a593Smuzhiyun static void pxa310_otg_exit(void)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun kfree(u2d->otg);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun #else
pxa310_u2d_setup_otg_hc(void)235*4882a593Smuzhiyun static inline void pxa310_u2d_setup_otg_hc(void) {}
pxa310_start_otg_hc(struct usb_bus * host)236*4882a593Smuzhiyun static inline int pxa310_start_otg_hc(struct usb_bus *host)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun }
pxa310_stop_otg_hc(void)240*4882a593Smuzhiyun static inline void pxa310_stop_otg_hc(void) {}
pxa310_otg_init(struct pxa3xx_u2d_platform_data * pdata)241*4882a593Smuzhiyun static inline int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun return 0;
244*4882a593Smuzhiyun }
pxa310_otg_exit(void)245*4882a593Smuzhiyun static inline void pxa310_otg_exit(void) {}
246*4882a593Smuzhiyun #endif /* CONFIG_PXA310_ULPI */
247*4882a593Smuzhiyun
pxa3xx_u2d_start_hc(struct usb_bus * host)248*4882a593Smuzhiyun int pxa3xx_u2d_start_hc(struct usb_bus *host)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun int err = 0;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* In case the PXA3xx ULPI isn't used, do nothing. */
253*4882a593Smuzhiyun if (!u2d)
254*4882a593Smuzhiyun return 0;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun clk_prepare_enable(u2d->clk);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (cpu_is_pxa310()) {
259*4882a593Smuzhiyun pxa310_u2d_setup_otg_hc();
260*4882a593Smuzhiyun err = pxa310_start_otg_hc(host);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return err;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pxa3xx_u2d_start_hc);
266*4882a593Smuzhiyun
pxa3xx_u2d_stop_hc(struct usb_bus * host)267*4882a593Smuzhiyun void pxa3xx_u2d_stop_hc(struct usb_bus *host)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun /* In case the PXA3xx ULPI isn't used, do nothing. */
270*4882a593Smuzhiyun if (!u2d)
271*4882a593Smuzhiyun return;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (cpu_is_pxa310())
274*4882a593Smuzhiyun pxa310_stop_otg_hc();
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun clk_disable_unprepare(u2d->clk);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pxa3xx_u2d_stop_hc);
279*4882a593Smuzhiyun
pxa3xx_u2d_probe(struct platform_device * pdev)280*4882a593Smuzhiyun static int pxa3xx_u2d_probe(struct platform_device *pdev)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
283*4882a593Smuzhiyun struct resource *r;
284*4882a593Smuzhiyun int err;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun u2d = kzalloc(sizeof(*u2d), GFP_KERNEL);
287*4882a593Smuzhiyun if (!u2d)
288*4882a593Smuzhiyun return -ENOMEM;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun u2d->clk = clk_get(&pdev->dev, NULL);
291*4882a593Smuzhiyun if (IS_ERR(u2d->clk)) {
292*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to get u2d clock\n");
293*4882a593Smuzhiyun err = PTR_ERR(u2d->clk);
294*4882a593Smuzhiyun goto err_free_mem;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
298*4882a593Smuzhiyun if (!r) {
299*4882a593Smuzhiyun dev_err(&pdev->dev, "no IO memory resource defined\n");
300*4882a593Smuzhiyun err = -ENODEV;
301*4882a593Smuzhiyun goto err_put_clk;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun r = request_mem_region(r->start, resource_size(r), pdev->name);
305*4882a593Smuzhiyun if (!r) {
306*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to request memory resource\n");
307*4882a593Smuzhiyun err = -EBUSY;
308*4882a593Smuzhiyun goto err_put_clk;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun u2d->mmio_base = ioremap(r->start, resource_size(r));
312*4882a593Smuzhiyun if (!u2d->mmio_base) {
313*4882a593Smuzhiyun dev_err(&pdev->dev, "ioremap() failed\n");
314*4882a593Smuzhiyun err = -ENODEV;
315*4882a593Smuzhiyun goto err_free_res;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (pdata->init) {
319*4882a593Smuzhiyun err = pdata->init(&pdev->dev);
320*4882a593Smuzhiyun if (err)
321*4882a593Smuzhiyun goto err_free_io;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* Only PXA310 U2D has OTG functionality */
325*4882a593Smuzhiyun if (cpu_is_pxa310()) {
326*4882a593Smuzhiyun err = pxa310_otg_init(pdata);
327*4882a593Smuzhiyun if (err)
328*4882a593Smuzhiyun goto err_free_plat;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun platform_set_drvdata(pdev, u2d);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun return 0;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun err_free_plat:
336*4882a593Smuzhiyun if (pdata->exit)
337*4882a593Smuzhiyun pdata->exit(&pdev->dev);
338*4882a593Smuzhiyun err_free_io:
339*4882a593Smuzhiyun iounmap(u2d->mmio_base);
340*4882a593Smuzhiyun err_free_res:
341*4882a593Smuzhiyun release_mem_region(r->start, resource_size(r));
342*4882a593Smuzhiyun err_put_clk:
343*4882a593Smuzhiyun clk_put(u2d->clk);
344*4882a593Smuzhiyun err_free_mem:
345*4882a593Smuzhiyun kfree(u2d);
346*4882a593Smuzhiyun return err;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
pxa3xx_u2d_remove(struct platform_device * pdev)349*4882a593Smuzhiyun static int pxa3xx_u2d_remove(struct platform_device *pdev)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
352*4882a593Smuzhiyun struct resource *r;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if (cpu_is_pxa310()) {
355*4882a593Smuzhiyun pxa310_stop_otg_hc();
356*4882a593Smuzhiyun pxa310_otg_exit();
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (pdata->exit)
360*4882a593Smuzhiyun pdata->exit(&pdev->dev);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun platform_set_drvdata(pdev, NULL);
363*4882a593Smuzhiyun iounmap(u2d->mmio_base);
364*4882a593Smuzhiyun r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
365*4882a593Smuzhiyun release_mem_region(r->start, resource_size(r));
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun clk_put(u2d->clk);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun kfree(u2d);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun static struct platform_driver pxa3xx_u2d_ulpi_driver = {
375*4882a593Smuzhiyun .driver = {
376*4882a593Smuzhiyun .name = "pxa3xx-u2d",
377*4882a593Smuzhiyun },
378*4882a593Smuzhiyun .probe = pxa3xx_u2d_probe,
379*4882a593Smuzhiyun .remove = pxa3xx_u2d_remove,
380*4882a593Smuzhiyun };
381*4882a593Smuzhiyun module_platform_driver(pxa3xx_u2d_ulpi_driver);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun MODULE_DESCRIPTION("PXA3xx U2D ULPI driver");
384*4882a593Smuzhiyun MODULE_AUTHOR("Igor Grinberg");
385*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
386