blob: 310238c6b5cd699bcd89ef101b926feba5d60a8c [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/list.h>
Bryan Wu0c6a8812008-12-02 21:33:44 +020015#include <linux/gpio.h>
16#include <linux/io.h>
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +053017#include <linux/err.h>
Felipe Balbi9cb03082010-12-02 09:21:05 +020018#include <linux/platform_device.h>
19#include <linux/dma-mapping.h>
Bob Liuad50c1b2011-08-05 17:33:05 +080020#include <linux/prefetch.h>
Felipe Balbid7078df2014-04-16 15:28:32 -050021#include <linux/usb/usb_phy_generic.h>
Bryan Wu0c6a8812008-12-02 21:33:44 +020022
23#include <asm/cacheflush.h>
24
25#include "musb_core.h"
Mike Frysinger13254302011-03-30 22:48:54 -040026#include "musbhsdma.h"
Bryan Wu0c6a8812008-12-02 21:33:44 +020027#include "blackfin.h"
28
Felipe Balbia023c632010-12-02 09:42:50 +020029struct bfin_glue {
30 struct device *dev;
31 struct platform_device *musb;
Felipe Balbi2f36ff62014-04-16 16:16:33 -050032 struct platform_device *phy;
Felipe Balbia023c632010-12-02 09:42:50 +020033};
Felipe Balbifcd22e32010-12-02 13:13:09 +020034#define glue_to_musb(g) platform_get_drvdata(g->musb)
Felipe Balbia023c632010-12-02 09:42:50 +020035
Tony Lindgrencc92f682014-11-24 11:05:01 -080036static u32 bfin_fifo_offset(u8 epnum)
37{
38 return USB_OFFSET(USB_EP0_FIFO) + (epnum * 8);
39}
40
41static u8 bfin_readb(const void __iomem *addr, unsigned offset)
42{
43 return (u8)(bfin_read16(addr + offset));
44}
45
46static u16 bfin_readw(const void __iomem *addr, unsigned offset)
47{
48 return bfin_read16(addr + offset);
49}
50
51static u32 bfin_readl(const void __iomem *addr, unsigned offset)
52{
53 return (u32)(bfin_read16(addr + offset));
54}
55
56static void bfin_writeb(void __iomem *addr, unsigned offset, u8 data)
57{
58 bfin_write16(addr + offset, (u16)data);
59}
60
61static void bfin_writew(void __iomem *addr, unsigned offset, u16 data)
62{
63 bfin_write16(addr + offset, data);
64}
65
Felipe Balbib1d34782014-11-26 08:01:37 -060066static void bfin_writel(void __iomem *addr, unsigned offset, u32 data)
Tony Lindgrencc92f682014-11-24 11:05:01 -080067{
68 bfin_write16(addr + offset, (u16)data);
69}
70
Bryan Wu0c6a8812008-12-02 21:33:44 +020071/*
72 * Load an endpoint's FIFO
73 */
Tony Lindgren1b40fc52014-11-24 11:05:02 -080074static void bfin_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
Bryan Wu0c6a8812008-12-02 21:33:44 +020075{
Felipe Balbi28e49702011-05-18 00:25:03 +030076 struct musb *musb = hw_ep->musb;
Bryan Wu0c6a8812008-12-02 21:33:44 +020077 void __iomem *fifo = hw_ep->fifo;
78 void __iomem *epio = hw_ep->regs;
Bryan Wu1c4bdc02009-12-21 09:49:52 -050079 u8 epnum = hw_ep->epnum;
Bryan Wu0c6a8812008-12-02 21:33:44 +020080
81 prefetch((u8 *)src);
82
83 musb_writew(epio, MUSB_TXCOUNT, len);
84
Felipe Balbi5c8a86e2011-05-11 12:44:08 +030085 dev_dbg(musb->controller, "TX ep%d fifo %p count %d buf %p, epio %p\n",
Bryan Wu0c6a8812008-12-02 21:33:44 +020086 hw_ep->epnum, fifo, len, src, epio);
87
88 dump_fifo_data(src, len);
89
Bryan Wu1c4bdc02009-12-21 09:49:52 -050090 if (!ANOMALY_05000380 && epnum != 0) {
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020091 u16 dma_reg;
92
93 flush_dcache_range((unsigned long)src,
94 (unsigned long)(src + len));
Bryan Wu0c6a8812008-12-02 21:33:44 +020095
Bryan Wu1c4bdc02009-12-21 09:49:52 -050096 /* Setup DMA address register */
Bryan Wu1ca9e9c2009-12-28 13:40:39 +020097 dma_reg = (u32)src;
Bryan Wu1c4bdc02009-12-21 09:49:52 -050098 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
99 SSYNC();
100
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200101 dma_reg = (u32)src >> 16;
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500102 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
103 SSYNC();
104
105 /* Setup DMA count register */
106 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
107 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
108 SSYNC();
109
110 /* Enable the DMA */
111 dma_reg = (epnum << 4) | DMA_ENA | INT_ENA | DIRECTION;
112 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
113 SSYNC();
114
Rahul Bedarkar5ae477b2014-01-02 19:27:47 +0530115 /* Wait for complete */
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500116 while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
117 cpu_relax();
118
119 /* acknowledge dma interrupt */
120 bfin_write_USB_DMA_INTERRUPT(1 << epnum);
121 SSYNC();
122
123 /* Reset DMA */
124 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
125 SSYNC();
126 } else {
127 SSYNC();
128
129 if (unlikely((unsigned long)src & 0x01))
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200130 outsw_8((unsigned long)fifo, src, (len + 1) >> 1);
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500131 else
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200132 outsw((unsigned long)fifo, src, (len + 1) >> 1);
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500133 }
134}
Bryan Wu0c6a8812008-12-02 21:33:44 +0200135/*
136 * Unload an endpoint's FIFO
137 */
Tony Lindgren1b40fc52014-11-24 11:05:02 -0800138static void bfin_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200139{
Felipe Balbi28e49702011-05-18 00:25:03 +0300140 struct musb *musb = hw_ep->musb;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200141 void __iomem *fifo = hw_ep->fifo;
142 u8 epnum = hw_ep->epnum;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200143
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500144 if (ANOMALY_05000467 && epnum != 0) {
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200145 u16 dma_reg;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200146
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200147 invalidate_dcache_range((unsigned long)dst,
148 (unsigned long)(dst + len));
Bryan Wu0c6a8812008-12-02 21:33:44 +0200149
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500150 /* Setup DMA address register */
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200151 dma_reg = (u32)dst;
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500152 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
153 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200154
Bryan Wu1ca9e9c2009-12-28 13:40:39 +0200155 dma_reg = (u32)dst >> 16;
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500156 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
157 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200158
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500159 /* Setup DMA count register */
160 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
161 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
162 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200163
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500164 /* Enable the DMA */
165 dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
166 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
167 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200168
Rahul Bedarkar5ae477b2014-01-02 19:27:47 +0530169 /* Wait for complete */
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500170 while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
171 cpu_relax();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200172
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500173 /* acknowledge dma interrupt */
174 bfin_write_USB_DMA_INTERRUPT(1 << epnum);
175 SSYNC();
Bryan Wu0c6a8812008-12-02 21:33:44 +0200176
Bryan Wu1c4bdc02009-12-21 09:49:52 -0500177 /* Reset DMA */
178 bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
179 SSYNC();
180 } else {
181 SSYNC();
182 /* Read the last byte of packet with odd size from address fifo + 4
183 * to trigger 1 byte access to EP0 FIFO.
184 */
185 if (len == 1)
186 *dst = (u8)inw((unsigned long)fifo + 4);
187 else {
188 if (unlikely((unsigned long)dst & 0x01))
189 insw_8((unsigned long)fifo, dst, len >> 1);
190 else
191 insw((unsigned long)fifo, dst, len >> 1);
192
193 if (len & 0x01)
194 *(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);
195 }
196 }
Felipe Balbi5c8a86e2011-05-11 12:44:08 +0300197 dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
Mike Frysinger04f40862009-11-16 16:19:19 +0530198 'R', hw_ep->epnum, fifo, len, dst);
199
Bryan Wu0c6a8812008-12-02 21:33:44 +0200200 dump_fifo_data(dst, len);
201}
202
203static irqreturn_t blackfin_interrupt(int irq, void *__hci)
204{
205 unsigned long flags;
206 irqreturn_t retval = IRQ_NONE;
207 struct musb *musb = __hci;
208
209 spin_lock_irqsave(&musb->lock, flags);
210
211 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
212 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
213 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
214
215 if (musb->int_usb || musb->int_tx || musb->int_rx) {
216 musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
217 musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
218 musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
219 retval = musb_interrupt(musb);
220 }
221
Cliff Caiff927ad2010-03-25 13:25:19 +0200222 /* Start sampling ID pin, when plug is removed from MUSB */
Antoine Tenarte47d9252014-10-30 18:41:13 +0100223 if ((musb->xceiv->otg->state == OTG_STATE_B_IDLE
224 || musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON) ||
Bob Liu68f64712010-10-23 05:12:00 -0500225 (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
Cliff Caiff927ad2010-03-25 13:25:19 +0200226 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
227 musb->a_wait_bcon = TIMER_DELAY;
228 }
229
Bryan Wu0c6a8812008-12-02 21:33:44 +0200230 spin_unlock_irqrestore(&musb->lock, flags);
231
Sergei Shtylyov2f831752010-03-25 13:14:25 +0200232 return retval;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200233}
234
235static void musb_conn_timer_handler(unsigned long _musb)
236{
237 struct musb *musb = (void *)_musb;
238 unsigned long flags;
239 u16 val;
Cliff Caiff927ad2010-03-25 13:25:19 +0200240 static u8 toggle;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200241
242 spin_lock_irqsave(&musb->lock, flags);
Antoine Tenarte47d9252014-10-30 18:41:13 +0100243 switch (musb->xceiv->otg->state) {
Bryan Wu0c6a8812008-12-02 21:33:44 +0200244 case OTG_STATE_A_IDLE:
245 case OTG_STATE_A_WAIT_BCON:
246 /* Start a new session */
247 val = musb_readw(musb->mregs, MUSB_DEVCTL);
Cliff Caiff927ad2010-03-25 13:25:19 +0200248 val &= ~MUSB_DEVCTL_SESSION;
249 musb_writew(musb->mregs, MUSB_DEVCTL, val);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200250 val |= MUSB_DEVCTL_SESSION;
251 musb_writew(musb->mregs, MUSB_DEVCTL, val);
Cliff Caiff927ad2010-03-25 13:25:19 +0200252 /* Check if musb is host or peripheral. */
Bryan Wu0c6a8812008-12-02 21:33:44 +0200253 val = musb_readw(musb->mregs, MUSB_DEVCTL);
Cliff Caiff927ad2010-03-25 13:25:19 +0200254
255 if (!(val & MUSB_DEVCTL_BDEVICE)) {
256 gpio_set_value(musb->config->gpio_vrsel, 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +0100257 musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
Cliff Caiff927ad2010-03-25 13:25:19 +0200258 } else {
259 gpio_set_value(musb->config->gpio_vrsel, 0);
260 /* Ignore VBUSERROR and SUSPEND IRQ */
261 val = musb_readb(musb->mregs, MUSB_INTRUSBE);
262 val &= ~MUSB_INTR_VBUSERROR;
263 musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
264
265 val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
266 musb_writeb(musb->mregs, MUSB_INTRUSB, val);
Antoine Tenarte47d9252014-10-30 18:41:13 +0100267 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
Cliff Caiff927ad2010-03-25 13:25:19 +0200268 }
269 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
270 break;
271 case OTG_STATE_B_IDLE:
Felipe Balbi032ec492011-11-24 15:46:26 +0200272 /*
273 * Start a new session. It seems that MUSB needs taking
Cliff Caiff927ad2010-03-25 13:25:19 +0200274 * some time to recognize the type of the plug inserted?
275 */
276 val = musb_readw(musb->mregs, MUSB_DEVCTL);
277 val |= MUSB_DEVCTL_SESSION;
278 musb_writew(musb->mregs, MUSB_DEVCTL, val);
279 val = musb_readw(musb->mregs, MUSB_DEVCTL);
280
Bryan Wu0c6a8812008-12-02 21:33:44 +0200281 if (!(val & MUSB_DEVCTL_BDEVICE)) {
282 gpio_set_value(musb->config->gpio_vrsel, 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +0100283 musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200284 } else {
285 gpio_set_value(musb->config->gpio_vrsel, 0);
286
287 /* Ignore VBUSERROR and SUSPEND IRQ */
288 val = musb_readb(musb->mregs, MUSB_INTRUSBE);
289 val &= ~MUSB_INTR_VBUSERROR;
290 musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
291
292 val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
293 musb_writeb(musb->mregs, MUSB_INTRUSB, val);
294
Cliff Caiff927ad2010-03-25 13:25:19 +0200295 /* Toggle the Soft Conn bit, so that we can response to
296 * the inserting of either A-plug or B-plug.
297 */
298 if (toggle) {
299 val = musb_readb(musb->mregs, MUSB_POWER);
300 val &= ~MUSB_POWER_SOFTCONN;
301 musb_writeb(musb->mregs, MUSB_POWER, val);
302 toggle = 0;
303 } else {
304 val = musb_readb(musb->mregs, MUSB_POWER);
305 val |= MUSB_POWER_SOFTCONN;
306 musb_writeb(musb->mregs, MUSB_POWER, val);
307 toggle = 1;
308 }
309 /* The delay time is set to 1/4 second by default,
310 * shortening it, if accelerating A-plug detection
311 * is needed in OTG mode.
312 */
313 mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200314 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200315 break;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200316 default:
Felipe Balbi5c8a86e2011-05-11 12:44:08 +0300317 dev_dbg(musb->controller, "%s state not handled\n",
Antoine Tenarte47d9252014-10-30 18:41:13 +0100318 usb_otg_state_string(musb->xceiv->otg->state));
Bryan Wu0c6a8812008-12-02 21:33:44 +0200319 break;
320 }
321 spin_unlock_irqrestore(&musb->lock, flags);
322
Felipe Balbi5c8a86e2011-05-11 12:44:08 +0300323 dev_dbg(musb->controller, "state is %s\n",
Antoine Tenarte47d9252014-10-30 18:41:13 +0100324 usb_otg_state_string(musb->xceiv->otg->state));
Bryan Wu0c6a8812008-12-02 21:33:44 +0200325}
326
Felipe Balbi743411b2010-12-01 13:22:05 +0200327static void bfin_musb_enable(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200328{
Felipe Balbi032ec492011-11-24 15:46:26 +0200329 /* REVISIT is this really correct ? */
Bryan Wu0c6a8812008-12-02 21:33:44 +0200330}
331
Felipe Balbi743411b2010-12-01 13:22:05 +0200332static void bfin_musb_disable(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200333{
334}
335
Felipe Balbi743411b2010-12-01 13:22:05 +0200336static void bfin_musb_set_vbus(struct musb *musb, int is_on)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200337{
Cliff Cai6ddc6da2010-03-12 10:29:10 +0200338 int value = musb->config->gpio_vrsel_active;
339 if (!is_on)
340 value = !value;
341 gpio_set_value(musb->config->gpio_vrsel, value);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200342
Felipe Balbi5c8a86e2011-05-11 12:44:08 +0300343 dev_dbg(musb->controller, "VBUS %s, devctl %02x "
Bryan Wu0c6a8812008-12-02 21:33:44 +0200344 /* otg %3x conf %08x prcm %08x */ "\n",
Antoine Tenarte47d9252014-10-30 18:41:13 +0100345 usb_otg_state_string(musb->xceiv->otg->state),
Bryan Wu0c6a8812008-12-02 21:33:44 +0200346 musb_readb(musb->mregs, MUSB_DEVCTL));
347}
348
Heikki Krogerus86753812012-02-13 13:24:02 +0200349static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200350{
351 return 0;
352}
353
Mike Frysinger45567c22011-03-21 14:06:32 -0400354static int bfin_musb_vbus_status(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200355{
356 return 0;
357}
358
Felipe Balbi743411b2010-12-01 13:22:05 +0200359static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200360{
Bryan Wu2002e762009-11-16 16:19:25 +0530361 return -EIO;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200362}
363
Mike Frysinger13254302011-03-30 22:48:54 -0400364static int bfin_musb_adjust_channel_params(struct dma_channel *channel,
365 u16 packet_sz, u8 *mode,
366 dma_addr_t *dma_addr, u32 *len)
367{
368 struct musb_dma_channel *musb_channel = channel->private_data;
369
370 /*
371 * Anomaly 05000450 might cause data corruption when using DMA
372 * MODE 1 transmits with short packet. So to work around this,
373 * we truncate all MODE 1 transfers down to a multiple of the
374 * max packet size, and then do the last short packet transfer
375 * (if there is any) using MODE 0.
376 */
377 if (ANOMALY_05000450) {
378 if (musb_channel->transmit && *mode == 1)
379 *len = *len - (*len % packet_sz);
380 }
381
382 return 0;
383}
384
Felipe Balbi743411b2010-12-01 13:22:05 +0200385static void bfin_musb_reg_init(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200386{
Robin Getzd426e602008-12-02 21:33:45 +0200387 if (ANOMALY_05000346) {
388 bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
389 SSYNC();
390 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200391
Robin Getzd426e602008-12-02 21:33:45 +0200392 if (ANOMALY_05000347) {
393 bfin_write_USB_APHY_CNTRL(0x0);
394 SSYNC();
395 }
Bryan Wu0c6a8812008-12-02 21:33:44 +0200396
Bryan Wu0c6a8812008-12-02 21:33:44 +0200397 /* Configure PLL oscillator register */
Bob Liu9c756462010-10-23 05:12:01 -0500398 bfin_write_USB_PLLOSC_CTRL(0x3080 |
399 ((480/musb->config->clkin) << 1));
Bryan Wu0c6a8812008-12-02 21:33:44 +0200400 SSYNC();
401
402 bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
403 SSYNC();
404
405 bfin_write_USB_EP_NI0_RXMAXP(64);
406 SSYNC();
407
408 bfin_write_USB_EP_NI0_TXMAXP(64);
409 SSYNC();
410
411 /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
412 bfin_write_USB_GLOBINTR(0x7);
413 SSYNC();
414
415 bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
416 EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
417 EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
418 EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
419 EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
420 SSYNC();
Felipe Balbi743411b2010-12-01 13:22:05 +0200421}
422
423static int bfin_musb_init(struct musb *musb)
424{
425
426 /*
427 * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
428 * and OTG HOST modes, while rev 1.1 and greater require PE7 to
429 * be low for DEVICE mode and high for HOST mode. We set it high
430 * here because we are in host mode
431 */
432
433 if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
434 printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
435 musb->config->gpio_vrsel);
436 return -ENODEV;
437 }
438 gpio_direction_output(musb->config->gpio_vrsel, 0);
439
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530440 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +0530441 if (IS_ERR_OR_NULL(musb->xceiv)) {
Felipe Balbi743411b2010-12-01 13:22:05 +0200442 gpio_free(musb->config->gpio_vrsel);
Ming Lei25736e02013-01-04 23:13:58 +0800443 return -EPROBE_DEFER;
Felipe Balbi743411b2010-12-01 13:22:05 +0200444 }
445
446 bfin_musb_reg_init(musb);
Bryan Wu0c6a8812008-12-02 21:33:44 +0200447
Felipe Balbi032ec492011-11-24 15:46:26 +0200448 setup_timer(&musb_conn_timer, musb_conn_timer_handler,
449 (unsigned long) musb);
450
451 musb->xceiv->set_power = bfin_musb_set_power;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200452
453 musb->isr = blackfin_interrupt;
Felipe Balbi06624812011-01-21 13:39:20 +0800454 musb->double_buffer_not_ok = true;
Bryan Wu0c6a8812008-12-02 21:33:44 +0200455
456 return 0;
457}
458
Felipe Balbi743411b2010-12-01 13:22:05 +0200459static int bfin_musb_exit(struct musb *musb)
Bryan Wu0c6a8812008-12-02 21:33:44 +0200460{
Bryan Wu0c6a8812008-12-02 21:33:44 +0200461 gpio_free(musb->config->gpio_vrsel);
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530462 usb_put_phy(musb->xceiv);
Felipe Balbie741e632014-04-16 16:05:17 -0500463
Bryan Wu0c6a8812008-12-02 21:33:44 +0200464 return 0;
465}
Felipe Balbi743411b2010-12-01 13:22:05 +0200466
Felipe Balbif7ec9432010-12-02 09:48:58 +0200467static const struct musb_platform_ops bfin_ops = {
Tony Lindgrenf8e9f34f2015-05-01 12:29:27 -0700468 .quirks = MUSB_DMA_INVENTRA,
Felipe Balbi743411b2010-12-01 13:22:05 +0200469 .init = bfin_musb_init,
470 .exit = bfin_musb_exit,
471
Tony Lindgrencc92f682014-11-24 11:05:01 -0800472 .readb = bfin_readb,
473 .writeb = bfin_writeb,
474 .readw = bfin_readw,
475 .writew = bfin_writew,
476 .readl = bfin_readl,
477 .writel = bfin_writel,
Tony Lindgren8a77f052014-11-24 11:05:04 -0800478 .fifo_mode = 2,
Tony Lindgren1b40fc52014-11-24 11:05:02 -0800479 .read_fifo = bfin_read_fifo,
480 .write_fifo = bfin_write_fifo,
Tony Lindgren7f6283e2015-05-01 12:29:28 -0700481#ifdef CONFIG_USB_INVENTRA_DMA
482 .dma_init = musbhs_dma_controller_create,
483 .dma_exit = musbhs_dma_controller_destroy,
484#endif
Felipe Balbi743411b2010-12-01 13:22:05 +0200485 .enable = bfin_musb_enable,
486 .disable = bfin_musb_disable,
487
488 .set_mode = bfin_musb_set_mode,
Felipe Balbi743411b2010-12-01 13:22:05 +0200489
490 .vbus_status = bfin_musb_vbus_status,
491 .set_vbus = bfin_musb_set_vbus,
Mike Frysinger13254302011-03-30 22:48:54 -0400492
493 .adjust_channel_params = bfin_musb_adjust_channel_params,
Felipe Balbi743411b2010-12-01 13:22:05 +0200494};
Felipe Balbi9cb03082010-12-02 09:21:05 +0200495
496static u64 bfin_dmamask = DMA_BIT_MASK(32);
497
Bill Pemberton41ac7b32012-11-19 13:21:48 -0500498static int bfin_probe(struct platform_device *pdev)
Felipe Balbi9cb03082010-12-02 09:21:05 +0200499{
Felipe Balbi09fc7d22013-04-24 17:21:42 +0300500 struct resource musb_resources[2];
Jingoo Hanc1a7d672013-07-30 17:03:12 +0900501 struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200502 struct platform_device *musb;
Felipe Balbia023c632010-12-02 09:42:50 +0200503 struct bfin_glue *glue;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200504
505 int ret = -ENOMEM;
506
Himangi Saraogif875bf32014-06-02 02:13:21 +0530507 glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
Peter Chen65469792014-10-14 15:56:09 +0800508 if (!glue)
Felipe Balbia023c632010-12-02 09:42:50 +0200509 goto err0;
Felipe Balbia023c632010-12-02 09:42:50 +0200510
Sebastian Andrzej Siewior2f771162012-10-31 16:12:43 +0100511 musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
Peter Chen65469792014-10-14 15:56:09 +0800512 if (!musb)
Himangi Saraogif875bf32014-06-02 02:13:21 +0530513 goto err0;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200514
515 musb->dev.parent = &pdev->dev;
516 musb->dev.dma_mask = &bfin_dmamask;
517 musb->dev.coherent_dma_mask = bfin_dmamask;
518
Felipe Balbia023c632010-12-02 09:42:50 +0200519 glue->dev = &pdev->dev;
520 glue->musb = musb;
521
Felipe Balbif7ec9432010-12-02 09:48:58 +0200522 pdata->platform_ops = &bfin_ops;
523
Felipe Balbi2f36ff62014-04-16 16:16:33 -0500524 glue->phy = usb_phy_generic_register();
525 if (IS_ERR(glue->phy))
Himangi Saraogif875bf32014-06-02 02:13:21 +0530526 goto err1;
Felipe Balbia023c632010-12-02 09:42:50 +0200527 platform_set_drvdata(pdev, glue);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200528
Felipe Balbi09fc7d22013-04-24 17:21:42 +0300529 memset(musb_resources, 0x00, sizeof(*musb_resources) *
530 ARRAY_SIZE(musb_resources));
531
532 musb_resources[0].name = pdev->resource[0].name;
533 musb_resources[0].start = pdev->resource[0].start;
534 musb_resources[0].end = pdev->resource[0].end;
535 musb_resources[0].flags = pdev->resource[0].flags;
536
537 musb_resources[1].name = pdev->resource[1].name;
538 musb_resources[1].start = pdev->resource[1].start;
539 musb_resources[1].end = pdev->resource[1].end;
540 musb_resources[1].flags = pdev->resource[1].flags;
541
542 ret = platform_device_add_resources(musb, musb_resources,
543 ARRAY_SIZE(musb_resources));
Felipe Balbi9cb03082010-12-02 09:21:05 +0200544 if (ret) {
545 dev_err(&pdev->dev, "failed to add resources\n");
Himangi Saraogif875bf32014-06-02 02:13:21 +0530546 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200547 }
548
549 ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
550 if (ret) {
551 dev_err(&pdev->dev, "failed to add platform_data\n");
Himangi Saraogif875bf32014-06-02 02:13:21 +0530552 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200553 }
554
555 ret = platform_device_add(musb);
556 if (ret) {
557 dev_err(&pdev->dev, "failed to register musb device\n");
Himangi Saraogif875bf32014-06-02 02:13:21 +0530558 goto err2;
Felipe Balbi9cb03082010-12-02 09:21:05 +0200559 }
560
561 return 0;
562
Himangi Saraogif875bf32014-06-02 02:13:21 +0530563err2:
Felipe Balbi2f36ff62014-04-16 16:16:33 -0500564 usb_phy_generic_unregister(glue->phy);
565
Felipe Balbia023c632010-12-02 09:42:50 +0200566err1:
Himangi Saraogif875bf32014-06-02 02:13:21 +0530567 platform_device_put(musb);
Felipe Balbia023c632010-12-02 09:42:50 +0200568
Felipe Balbi9cb03082010-12-02 09:21:05 +0200569err0:
570 return ret;
571}
572
Bill Pembertonfb4e98a2012-11-19 13:26:20 -0500573static int bfin_remove(struct platform_device *pdev)
Felipe Balbi9cb03082010-12-02 09:21:05 +0200574{
Felipe Balbia023c632010-12-02 09:42:50 +0200575 struct bfin_glue *glue = platform_get_drvdata(pdev);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200576
Wei Yongjun01e40da2012-10-23 13:26:00 +0800577 platform_device_unregister(glue->musb);
Felipe Balbi2f36ff62014-04-16 16:16:33 -0500578 usb_phy_generic_unregister(glue->phy);
Felipe Balbi9cb03082010-12-02 09:21:05 +0200579
580 return 0;
581}
582
Felipe Balbifcd22e32010-12-02 13:13:09 +0200583#ifdef CONFIG_PM
584static int bfin_suspend(struct device *dev)
585{
586 struct bfin_glue *glue = dev_get_drvdata(dev);
587 struct musb *musb = glue_to_musb(glue);
588
589 if (is_host_active(musb))
590 /*
591 * During hibernate gpio_vrsel will change from high to low
592 * low which will generate wakeup event resume the system
593 * immediately. Set it to 0 before hibernate to avoid this
594 * wakeup event.
595 */
596 gpio_set_value(musb->config->gpio_vrsel, 0);
597
598 return 0;
599}
600
601static int bfin_resume(struct device *dev)
602{
603 struct bfin_glue *glue = dev_get_drvdata(dev);
604 struct musb *musb = glue_to_musb(glue);
605
606 bfin_musb_reg_init(musb);
607
608 return 0;
609}
Felipe Balbifcd22e32010-12-02 13:13:09 +0200610#endif
611
Daniel Mack09673132013-09-30 21:02:08 +0200612static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume);
613
Felipe Balbi9cb03082010-12-02 09:21:05 +0200614static struct platform_driver bfin_driver = {
Felipe Balbie9e8c852012-01-26 12:40:23 +0200615 .probe = bfin_probe,
Dmitry Torokhovd9b2b192015-01-31 21:13:59 -0800616 .remove = bfin_remove,
Felipe Balbi9cb03082010-12-02 09:21:05 +0200617 .driver = {
Mike Frysinger417ddf82011-03-22 14:43:37 -0400618 .name = "musb-blackfin",
Daniel Mack09673132013-09-30 21:02:08 +0200619 .pm = &bfin_pm_ops,
Felipe Balbi9cb03082010-12-02 09:21:05 +0200620 },
621};
622
623MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
624MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
625MODULE_LICENSE("GPL v2");
Srinivas Kandagatla692373e2012-10-10 19:36:52 +0100626module_platform_driver(bfin_driver);