blob: df0e906b1850c7a84007eb808303d9b89a68cc79 [file] [log] [blame]
Bryan Wu0c6a8812008-12-02 21:33:44 +02001/*
2 * MUSB OTG controller driver for Blackfin Processors
3 *
4 * Copyright 2006-2008 Analog Devices Inc.
5 *
6 * Enter bugs at http://blackfin.uclinux.org/
7 *
8 * Licensed under the GPL-2 or later.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
Bryan Wu0c6a8812008-12-02 21:33:44 +020014#include <linux/init.h>
15#include <linux/list.h>
Bryan Wu0c6a8812008-12-02 21:33:44 +020016#include <linux/gpio.h>
17#include <linux/io.h>
Felipe Balbi9cb03082010-12-02 09:21:05 +020018#include <linux/platform_device.h>
19#include <linux/dma-mapping.h>
Bryan Wu0c6a8812008-12-02 21:33:44 +020020
21#include <asm/cacheflush.h>
22
23#include "musb_core.h"
24#include "blackfin.h"
25
Felipe Balbia023c632010-12-02 09:42:50 +020026struct bfin_glue {
27 struct device *dev;
28 struct platform_device *musb;
29};
Felipe Balbifcd22e32010-12-02 13:13:09 +020030#define glue_to_musb(g) platform_get_drvdata(g->musb)
Felipe Balbia023c632010-12-02 09:42:50 +020031
Bryan Wu0c6a8812008-12-02 21:33:44 +020032/*
33 * Load an endpoint's FIFO
34 */
35void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
36{
37 void __iomem *fifo = hw_ep->fifo;
38 void __iomem *epio = hw_ep->regs;
Bryan Wu1c4bdc02009-12-21 09:49:52 -050039 u8 epnum = hw_ep->epnum;
Bryan Wu0c6a8812008-12-02 21:33:44 +020040
41 prefetch((u8 *)src);
42
43 musb_writew(epio, MUSB_TXCOUNT, len);
44
45 DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n",
46 hw_ep->epnum, fifo, len, src, epio);
47
48 dump_fifo_data(src, len);
49
Bryan Wu1c4bdc02009-12-21 09:49:52 -050050 if (!ANOMALY_05000380 && epnum != 0) {
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020051 u16 dma_reg;
52
53 flush_dcache_range((unsigned long)src,
54 (unsigned long)(src + len));
Bryan Wu0c6a8812008-12-02 21:33:44 +020055
Bryan Wu1c4bdc02009-12-21 09:49:52 -050056 /* Setup DMA address register */
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020057 dma_reg = (u32)src;
Bryan Wu1c4bdc02009-12-21 09:49:52 -050058 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
59 SSYNC();
60
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020061 dma_reg = (u32)src >> 16;
Bryan Wu1c4bdc02009-12-21 09:49:52 -050062 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
63 SSYNC();
64
65 /* Setup DMA count register */
66 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
67 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
68 SSYNC();
69
70 /* Enable the DMA */
71 dma_reg = (epnum << 4) | DMA_ENA | INT_ENA | DIRECTION;
72 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
73 SSYNC();
74
75 /* Wait for compelete */
76 while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
77 cpu_relax();
78
79 /* acknowledge dma interrupt */
80 bfin_write_USB_DMA_INTERRUPT(1 << epnum);
81 SSYNC();
82
83 /* Reset DMA */
84 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
85 SSYNC();
86 } else {
87 SSYNC();
88
89 if (unlikely((unsigned long)src & 0x01))
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020090 outsw_8((unsigned long)fifo, src, (len + 1) >> 1);
Bryan Wu1c4bdc02009-12-21 09:49:52 -050091 else
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020092 outsw((unsigned long)fifo, src, (len + 1) >> 1);
Bryan Wu1c4bdc02009-12-21 09:49:52 -050093 }
94}
Bryan Wu0c6a8812008-12-02 21:33:44 +020095/*
96 * Unload an endpoint's FIFO
97 */
98void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
99{
100 void __iomem *fifo = hw_ep->fifo;
101 u8 epnum = hw_ep->epnum;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200102
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500103 if (ANOMALY_05000467 && epnum != 0) {
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200104 u16 dma_reg;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200105
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200106 invalidate_dcache_range((unsigned long)dst,
107 (unsigned long)(dst + len));
Bryan Wu0c6a8812008-12-02 21:33:44 +0200108
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500109 /* Setup DMA address register */
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200110 dma_reg = (u32)dst;
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500111 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
112 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200113
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200114 dma_reg = (u32)dst >> 16;
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500115 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
116 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200117
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500118 /* Setup DMA count register */
119 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
120 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
121 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200122
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500123 /* Enable the DMA */
124 dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
125 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
126 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200127
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500128 /* Wait for compelete */
129 while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
130 cpu_relax();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200131
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500132 /* acknowledge dma interrupt */
133 bfin_write_USB_DMA_INTERRUPT(1 << epnum);
134 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200135
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500136 /* Reset DMA */
137 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
138 SSYNC();
139 } else {
140 SSYNC();
141 /* Read the last byte of packet with odd size from address fifo + 4
142 * to trigger 1 byte access to EP0 FIFO.
143 */
144 if (len == 1)
145 *dst = (u8)inw((unsigned long)fifo + 4);
146 else {
147 if (unlikely((unsigned long)dst & 0x01))
148 insw_8((unsigned long)fifo, dst, len >> 1);
149 else
150 insw((unsigned long)fifo, dst, len >> 1);
151
152 if (len & 0x01)
153 *(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);
154 }
155 }
Mike Frysinger04f40862009-11-16 16:19:19 +0530156 DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
157 'R', hw_ep->epnum, fifo, len, dst);
158
Bryan Wu0c6a8812008-12-02 21:33:44 +0200159 dump_fifo_data(dst, len);
160}
161
162static irqreturn_t blackfin_interrupt(int irq, void *__hci)
163{
164 unsigned long flags;
165 irqreturn_t retval = IRQ_NONE;
166 struct musb *musb = __hci;
167
168 spin_lock_irqsave(&musb->lock, flags);
169
170 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
171 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
172 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
173
174 if (musb->int_usb || musb->int_tx || musb->int_rx) {
175 musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
176 musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
177 musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
178 retval = musb_interrupt(musb);
179 }
180
Cliff Caiff927ad2010-03-25 13:25:19 +0200181 /* Start sampling ID pin, when plug is removed from MUSB */
182 if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
183 || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
184 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
185 musb->a_wait_bcon = TIMER_DELAY;
186 }
187
Bryan Wu0c6a8812008-12-02 21:33:44 +0200188 spin_unlock_irqrestore(&musb->lock, flags);
189
Sergei Shtylyov2f831752010-03-25 13:14:25 +0200190 return retval;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200191}
192
193static void musb_conn_timer_handler(unsigned long _musb)
194{
195 struct musb *musb = (void *)_musb;
196 unsigned long flags;
197 u16 val;
Cliff Caiff927ad2010-03-25 13:25:19 +0200198 static u8 toggle;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200199
200 spin_lock_irqsave(&musb->lock, flags);
David Brownell84e250f2009-03-31 12:30:04 -0700201 switch (musb->xceiv->state) {
Bryan Wu0c6a8812008-12-02 21:33:44 +0200202 case OTG_STATE_A_IDLE:
203 case OTG_STATE_A_WAIT_BCON:
204 /* Start a new session */
205 val = musb_readw(musb->mregs, MUSB_DEVCTL);
Cliff Caiff927ad2010-03-25 13:25:19 +0200206 val &= ~MUSB_DEVCTL_SESSION;
207 musb_writew(musb->mregs, MUSB_DEVCTL, val);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200208 val |= MUSB_DEVCTL_SESSION;
209 musb_writew(musb->mregs, MUSB_DEVCTL, val);
Cliff Caiff927ad2010-03-25 13:25:19 +0200210 /* Check if musb is host or peripheral. */
Bryan Wu0c6a8812008-12-02 21:33:44 +0200211 val = musb_readw(musb->mregs, MUSB_DEVCTL);
Cliff Caiff927ad2010-03-25 13:25:19 +0200212
213 if (!(val & MUSB_DEVCTL_BDEVICE)) {
214 gpio_set_value(musb->config->gpio_vrsel, 1);
215 musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
216 } else {
217 gpio_set_value(musb->config->gpio_vrsel, 0);
218 /* Ignore VBUSERROR and SUSPEND IRQ */
219 val = musb_readb(musb->mregs, MUSB_INTRUSBE);
220 val &= ~MUSB_INTR_VBUSERROR;
221 musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
222
223 val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
224 musb_writeb(musb->mregs, MUSB_INTRUSB, val);
225 if (is_otg_enabled(musb))
226 musb->xceiv->state = OTG_STATE_B_IDLE;
227 else
228 musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
229 }
230 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
231 break;
232 case OTG_STATE_B_IDLE:
233
234 if (!is_peripheral_enabled(musb))
235 break;
236 /* Start a new session. It seems that MUSB needs taking
237 * some time to recognize the type of the plug inserted?
238 */
239 val = musb_readw(musb->mregs, MUSB_DEVCTL);
240 val |= MUSB_DEVCTL_SESSION;
241 musb_writew(musb->mregs, MUSB_DEVCTL, val);
242 val = musb_readw(musb->mregs, MUSB_DEVCTL);
243
Bryan Wu0c6a8812008-12-02 21:33:44 +0200244 if (!(val & MUSB_DEVCTL_BDEVICE)) {
245 gpio_set_value(musb->config->gpio_vrsel, 1);
David Brownell84e250f2009-03-31 12:30:04 -0700246 musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200247 } else {
248 gpio_set_value(musb->config->gpio_vrsel, 0);
249
250 /* Ignore VBUSERROR and SUSPEND IRQ */
251 val = musb_readb(musb->mregs, MUSB_INTRUSBE);
252 val &= ~MUSB_INTR_VBUSERROR;
253 musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
254
255 val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
256 musb_writeb(musb->mregs, MUSB_INTRUSB, val);
257
Cliff Caiff927ad2010-03-25 13:25:19 +0200258 /* Toggle the Soft Conn bit, so that we can response to
259 * the inserting of either A-plug or B-plug.
260 */
261 if (toggle) {
262 val = musb_readb(musb->mregs, MUSB_POWER);
263 val &= ~MUSB_POWER_SOFTCONN;
264 musb_writeb(musb->mregs, MUSB_POWER, val);
265 toggle = 0;
266 } else {
267 val = musb_readb(musb->mregs, MUSB_POWER);
268 val |= MUSB_POWER_SOFTCONN;
269 musb_writeb(musb->mregs, MUSB_POWER, val);
270 toggle = 1;
271 }
272 /* The delay time is set to 1/4 second by default,
273 * shortening it, if accelerating A-plug detection
274 * is needed in OTG mode.
275 */
276 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200277 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200278 break;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200279 default:
280 DBG(1, "%s state not handled\n", otg_state_string(musb));
281 break;
282 }
283 spin_unlock_irqrestore(&musb->lock, flags);
284
285 DBG(4, "state is %s\n", otg_state_string(musb));
286}
287
Felipe Balbi743411b2010-12-01 13:22:05 +0200288static void bfin_musb_enable(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200289{
Cliff Caiff927ad2010-03-25 13:25:19 +0200290 if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
Bryan Wu0c6a8812008-12-02 21:33:44 +0200291 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
292 musb->a_wait_bcon = TIMER_DELAY;
293 }
294}
295
Felipe Balbi743411b2010-12-01 13:22:05 +0200296static void bfin_musb_disable(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200297{
298}
299
Felipe Balbi743411b2010-12-01 13:22:05 +0200300static void bfin_musb_set_vbus(struct musb *musb, int is_on)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200301{
Cliff Cai6ddc6da2010-03-12 10:29:10 +0200302 int value = musb->config->gpio_vrsel_active;
303 if (!is_on)
304 value = !value;
305 gpio_set_value(musb->config->gpio_vrsel, value);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200306
307 DBG(1, "VBUS %s, devctl %02x "
308 /* otg %3x conf %08x prcm %08x */ "\n",
309 otg_state_string(musb),
310 musb_readb(musb->mregs, MUSB_DEVCTL));
311}
312
Felipe Balbi743411b2010-12-01 13:22:05 +0200313static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200314{
315 return 0;
316}
317
Felipe Balbi743411b2010-12-01 13:22:05 +0200318static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200319{
Cliff Caiff927ad2010-03-25 13:25:19 +0200320 if (!is_otg_enabled(musb) && is_host_enabled(musb))
Bryan Wu0c6a8812008-12-02 21:33:44 +0200321 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
322}
323
Felipe Balbi743411b2010-12-01 13:22:05 +0200324static int bfin_musb_get_vbus_status(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200325{
326 return 0;
327}
328
Felipe Balbi743411b2010-12-01 13:22:05 +0200329static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200330{
Bryan Wu2002e762009-11-16 16:19:25 +0530331 return -EIO;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200332}
333
Felipe Balbi743411b2010-12-01 13:22:05 +0200334static void bfin_musb_reg_init(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200335{
Robin Getzd426e602008-12-02 21:33:45 +0200336 if (ANOMALY_05000346) {
337 bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
338 SSYNC();
339 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200340
Robin Getzd426e602008-12-02 21:33:45 +0200341 if (ANOMALY_05000347) {
342 bfin_write_USB_APHY_CNTRL(0x0);
343 SSYNC();
344 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200345
Bryan Wu0c6a8812008-12-02 21:33:44 +0200346 /* Configure PLL oscillator register */
347 bfin_write_USB_PLLOSC_CTRL(0x30a8);
348 SSYNC();
349
350 bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
351 SSYNC();
352
353 bfin_write_USB_EP_NI0_RXMAXP(64);
354 SSYNC();
355
356 bfin_write_USB_EP_NI0_TXMAXP(64);
357 SSYNC();
358
359 /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
360 bfin_write_USB_GLOBINTR(0x7);
361 SSYNC();
362
363 bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
364 EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
365 EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
366 EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
367 EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
368 SSYNC();
Felipe Balbi743411b2010-12-01 13:22:05 +0200369}
370
371static int bfin_musb_init(struct musb *musb)
372{
373
374 /*
375 * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
376 * and OTG HOST modes, while rev 1.1 and greater require PE7 to
377 * be low for DEVICE mode and high for HOST mode. We set it high
378 * here because we are in host mode
379 */
380
381 if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
382 printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
383 musb->config->gpio_vrsel);
384 return -ENODEV;
385 }
386 gpio_direction_output(musb->config->gpio_vrsel, 0);
387
388 usb_nop_xceiv_register();
389 musb->xceiv = otg_get_transceiver();
390 if (!musb->xceiv) {
391 gpio_free(musb->config->gpio_vrsel);
392 return -ENODEV;
393 }
394
395 bfin_musb_reg_init(musb);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200396
397 if (is_host_enabled(musb)) {
Felipe Balbi743411b2010-12-01 13:22:05 +0200398 musb->board_set_vbus = bfin_musb_set_vbus;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200399 setup_timer(&musb_conn_timer,
400 musb_conn_timer_handler, (unsigned long) musb);
401 }
402 if (is_peripheral_enabled(musb))
Felipe Balbi743411b2010-12-01 13:22:05 +0200403 musb->xceiv->set_power = bfin_musb_set_power;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200404
405 musb->isr = blackfin_interrupt;
406
407 return 0;
408}
409
Felipe Balbi743411b2010-12-01 13:22:05 +0200410static int bfin_musb_exit(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200411{
Bryan Wu0c6a8812008-12-02 21:33:44 +0200412 gpio_free(musb->config->gpio_vrsel);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200413
Sergei Shtylyovf4053872010-09-29 09:54:29 +0300414 otg_put_transceiver(musb->xceiv);
Sergei Shtylyov3daad242010-09-29 09:54:30 +0300415 usb_nop_xceiv_unregister();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200416 return 0;
417}
Felipe Balbi743411b2010-12-01 13:22:05 +0200418
Felipe Balbif7ec9432010-12-02 09:48:58 +0200419static const struct musb_platform_ops bfin_ops = {
Felipe Balbi743411b2010-12-01 13:22:05 +0200420 .init = bfin_musb_init,
421 .exit = bfin_musb_exit,
422
423 .enable = bfin_musb_enable,
424 .disable = bfin_musb_disable,
425
426 .set_mode = bfin_musb_set_mode,
427 .try_idle = bfin_musb_try_idle,
428
429 .vbus_status = bfin_musb_vbus_status,
430 .set_vbus = bfin_musb_set_vbus,
431};
Felipe Balbi9cb03082010-12-02 09:21:05 +0200432
433static u64 bfin_dmamask = DMA_BIT_MASK(32);
434
435static int __init bfin_probe(struct platform_device *pdev)
436{
437 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
438 struct platform_device *musb;
Felipe Balbia023c632010-12-02 09:42:50 +0200439 struct bfin_glue *glue;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200440
441 int ret = -ENOMEM;
442
Felipe Balbia023c632010-12-02 09:42:50 +0200443 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
444 if (!glue) {
445 dev_err(&pdev->dev, "failed to allocate glue context\n");
446 goto err0;
447 }
448
Felipe Balbi9cb03082010-12-02 09:21:05 +0200449 musb = platform_device_alloc("musb-hdrc", -1);
450 if (!musb) {
451 dev_err(&pdev->dev, "failed to allocate musb device\n");
Felipe Balbia023c632010-12-02 09:42:50 +0200452 goto err1;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200453 }
454
455 musb->dev.parent = &pdev->dev;
456 musb->dev.dma_mask = &bfin_dmamask;
457 musb->dev.coherent_dma_mask = bfin_dmamask;
458
Felipe Balbia023c632010-12-02 09:42:50 +0200459 glue->dev = &pdev->dev;
460 glue->musb = musb;
461
Felipe Balbif7ec9432010-12-02 09:48:58 +0200462 pdata->platform_ops = &bfin_ops;
463
Felipe Balbia023c632010-12-02 09:42:50 +0200464 platform_set_drvdata(pdev, glue);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200465
466 ret = platform_device_add_resources(musb, pdev->resource,
467 pdev->num_resources);
468 if (ret) {
469 dev_err(&pdev->dev, "failed to add resources\n");
Felipe Balbia023c632010-12-02 09:42:50 +0200470 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200471 }
472
473 ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
474 if (ret) {
475 dev_err(&pdev->dev, "failed to add platform_data\n");
Felipe Balbia023c632010-12-02 09:42:50 +0200476 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200477 }
478
479 ret = platform_device_add(musb);
480 if (ret) {
481 dev_err(&pdev->dev, "failed to register musb device\n");
Felipe Balbia023c632010-12-02 09:42:50 +0200482 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200483 }
484
485 return 0;
486
Felipe Balbia023c632010-12-02 09:42:50 +0200487err2:
Felipe Balbi9cb03082010-12-02 09:21:05 +0200488 platform_device_put(musb);
489
Felipe Balbia023c632010-12-02 09:42:50 +0200490err1:
491 kfree(glue);
492
Felipe Balbi9cb03082010-12-02 09:21:05 +0200493err0:
494 return ret;
495}
496
497static int __exit bfin_remove(struct platform_device *pdev)
498{
Felipe Balbia023c632010-12-02 09:42:50 +0200499 struct bfin_glue *glue = platform_get_drvdata(pdev);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200500
Felipe Balbia023c632010-12-02 09:42:50 +0200501 platform_device_del(glue->musb);
502 platform_device_put(glue->musb);
503 kfree(glue);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200504
505 return 0;
506}
507
Felipe Balbifcd22e32010-12-02 13:13:09 +0200508#ifdef CONFIG_PM
509static int bfin_suspend(struct device *dev)
510{
511 struct bfin_glue *glue = dev_get_drvdata(dev);
512 struct musb *musb = glue_to_musb(glue);
513
514 if (is_host_active(musb))
515 /*
516 * During hibernate gpio_vrsel will change from high to low
517 * low which will generate wakeup event resume the system
518 * immediately. Set it to 0 before hibernate to avoid this
519 * wakeup event.
520 */
521 gpio_set_value(musb->config->gpio_vrsel, 0);
522
523 return 0;
524}
525
526static int bfin_resume(struct device *dev)
527{
528 struct bfin_glue *glue = dev_get_drvdata(dev);
529 struct musb *musb = glue_to_musb(glue);
530
531 bfin_musb_reg_init(musb);
532
533 return 0;
534}
535
536static struct dev_pm_ops bfin_pm_ops = {
537 .suspend = bfin_suspend,
538 .resume = bfin_resume,
539};
540
541#define DEV_PM_OPS &bfin_pm_op,
542#else
543#define DEV_PM_OPS NULL
544#endif
545
Felipe Balbi9cb03082010-12-02 09:21:05 +0200546static struct platform_driver bfin_driver = {
547 .remove = __exit_p(bfin_remove),
548 .driver = {
549 .name = "musb-bfin",
Felipe Balbifcd22e32010-12-02 13:13:09 +0200550 .pm = DEV_PM_OPS,
Felipe Balbi9cb03082010-12-02 09:21:05 +0200551 },
552};
553
554MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
555MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
556MODULE_LICENSE("GPL v2");
557
558static int __init bfin_init(void)
559{
560 return platform_driver_probe(&bfin_driver, bfin_probe);
561}
562subsys_initcall(bfin_init);
563
564static void __exit bfin_exit(void)
565{
566 platform_driver_unregister(&bfin_driver);
567}
568module_exit(bfin_exit);