Commit 0c6a8818447d38f7bb0b0013448659113d37a3e1

Authored by Bryan Wu
Committed by Greg Kroah-Hartman
1 parent 2ffcdb3bda

USB: musb: add Blackfin driver to MUSB framework (v2)

- replace MUSB_FIFOSIZE register to MUSB_TXCOUNT, cause no MUSB_FIFOSIZE
   register on Blackfin
- use #ifdef to replace #if defined()

Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 2 changed files with 368 additions and 0 deletions Side-by-side Diff

drivers/usb/musb/blackfin.c
  1 +/*
  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>
  14 +#include <linux/slab.h>
  15 +#include <linux/init.h>
  16 +#include <linux/list.h>
  17 +#include <linux/clk.h>
  18 +#include <linux/gpio.h>
  19 +#include <linux/io.h>
  20 +
  21 +#include <asm/cacheflush.h>
  22 +
  23 +#include "musb_core.h"
  24 +#include "blackfin.h"
  25 +
  26 +/*
  27 + * Load an endpoint's FIFO
  28 + */
  29 +void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
  30 +{
  31 + void __iomem *fifo = hw_ep->fifo;
  32 + void __iomem *epio = hw_ep->regs;
  33 +
  34 + prefetch((u8 *)src);
  35 +
  36 + musb_writew(epio, MUSB_TXCOUNT, len);
  37 +
  38 + DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n",
  39 + hw_ep->epnum, fifo, len, src, epio);
  40 +
  41 + dump_fifo_data(src, len);
  42 +
  43 + if (unlikely((unsigned long)src & 0x01))
  44 + outsw_8(fifo, src, len & 0x01 ? (len >> 1) + 1 : len >> 1);
  45 + else
  46 + outsw(fifo, src, len & 0x01 ? (len >> 1) + 1 : len >> 1);
  47 +}
  48 +
  49 +/*
  50 + * Unload an endpoint's FIFO
  51 + */
  52 +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
  53 +{
  54 + void __iomem *fifo = hw_ep->fifo;
  55 + u8 epnum = hw_ep->epnum;
  56 + u16 dma_reg = 0;
  57 + int i;
  58 + u16 *data;
  59 +
  60 + DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
  61 + 'R', hw_ep->epnum, fifo, len, dst);
  62 +
  63 +#ifdef CONFIG_BF52x
  64 + invalidate_dcache_range((unsigned int)dst,
  65 + (unsigned int)(dst + len));
  66 +
  67 + /* Setup DMA address register */
  68 + dma_reg = (u16) ((u32) dst & 0xFFFF);
  69 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
  70 + SSYNC();
  71 +
  72 + dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
  73 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
  74 + SSYNC();
  75 +
  76 + /* Setup DMA count register */
  77 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
  78 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
  79 + SSYNC();
  80 +
  81 + /* Enable the DMA */
  82 + dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
  83 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
  84 + SSYNC();
  85 +
  86 + /* Wait for compelete */
  87 + while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
  88 + cpu_relax();
  89 +
  90 + /* acknowledge dma interrupt */
  91 + bfin_write_USB_DMA_INTERRUPT(1 << epnum);
  92 + SSYNC();
  93 +
  94 + /* Reset DMA */
  95 + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
  96 + SSYNC();
  97 +#else
  98 + if (unlikely((unsigned long)dst & 0x01))
  99 + insw_8(fifo, dst, len & 0x01 ? (len >> 1) + 1 : len >> 1);
  100 + else
  101 + insw(fifo, dst, len & 0x01 ? (len >> 1) + 1 : len >> 1);
  102 +#endif
  103 +
  104 + dump_fifo_data(dst, len);
  105 +}
  106 +
  107 +static irqreturn_t blackfin_interrupt(int irq, void *__hci)
  108 +{
  109 + unsigned long flags;
  110 + irqreturn_t retval = IRQ_NONE;
  111 + struct musb *musb = __hci;
  112 +
  113 + spin_lock_irqsave(&musb->lock, flags);
  114 +
  115 + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
  116 + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
  117 + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
  118 +
  119 + if (musb->int_usb || musb->int_tx || musb->int_rx) {
  120 + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
  121 + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
  122 + musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
  123 + retval = musb_interrupt(musb);
  124 + }
  125 +
  126 + spin_unlock_irqrestore(&musb->lock, flags);
  127 +
  128 + /* REVISIT we sometimes get spurious IRQs on g_ep0
  129 + * not clear why... fall in BF54x too.
  130 + */
  131 + if (retval != IRQ_HANDLED)
  132 + DBG(5, "spurious?\n");
  133 +
  134 + return IRQ_HANDLED;
  135 +}
  136 +
  137 +static void musb_conn_timer_handler(unsigned long _musb)
  138 +{
  139 + struct musb *musb = (void *)_musb;
  140 + unsigned long flags;
  141 + u16 val;
  142 +
  143 + spin_lock_irqsave(&musb->lock, flags);
  144 + switch (musb->xceiv.state) {
  145 + case OTG_STATE_A_IDLE:
  146 + case OTG_STATE_A_WAIT_BCON:
  147 + /* Start a new session */
  148 + val = musb_readw(musb->mregs, MUSB_DEVCTL);
  149 + val |= MUSB_DEVCTL_SESSION;
  150 + musb_writew(musb->mregs, MUSB_DEVCTL, val);
  151 +
  152 + val = musb_readw(musb->mregs, MUSB_DEVCTL);
  153 + if (!(val & MUSB_DEVCTL_BDEVICE)) {
  154 + gpio_set_value(musb->config->gpio_vrsel, 1);
  155 + musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
  156 + } else {
  157 + gpio_set_value(musb->config->gpio_vrsel, 0);
  158 +
  159 + /* Ignore VBUSERROR and SUSPEND IRQ */
  160 + val = musb_readb(musb->mregs, MUSB_INTRUSBE);
  161 + val &= ~MUSB_INTR_VBUSERROR;
  162 + musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
  163 +
  164 + val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
  165 + musb_writeb(musb->mregs, MUSB_INTRUSB, val);
  166 +
  167 + val = MUSB_POWER_HSENAB;
  168 + musb_writeb(musb->mregs, MUSB_POWER, val);
  169 + }
  170 + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
  171 + break;
  172 +
  173 + default:
  174 + DBG(1, "%s state not handled\n", otg_state_string(musb));
  175 + break;
  176 + }
  177 + spin_unlock_irqrestore(&musb->lock, flags);
  178 +
  179 + DBG(4, "state is %s\n", otg_state_string(musb));
  180 +}
  181 +
  182 +void musb_platform_enable(struct musb *musb)
  183 +{
  184 + if (is_host_enabled(musb)) {
  185 + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
  186 + musb->a_wait_bcon = TIMER_DELAY;
  187 + }
  188 +}
  189 +
  190 +void musb_platform_disable(struct musb *musb)
  191 +{
  192 +}
  193 +
  194 +static void bfin_vbus_power(struct musb *musb, int is_on, int sleeping)
  195 +{
  196 +}
  197 +
  198 +static void bfin_set_vbus(struct musb *musb, int is_on)
  199 +{
  200 + if (is_on)
  201 + gpio_set_value(musb->config->gpio_vrsel, 1);
  202 + else
  203 + gpio_set_value(musb->config->gpio_vrsel, 0);
  204 +
  205 + DBG(1, "VBUS %s, devctl %02x "
  206 + /* otg %3x conf %08x prcm %08x */ "\n",
  207 + otg_state_string(musb),
  208 + musb_readb(musb->mregs, MUSB_DEVCTL));
  209 +}
  210 +
  211 +static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
  212 +{
  213 + return 0;
  214 +}
  215 +
  216 +void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
  217 +{
  218 + if (is_host_enabled(musb))
  219 + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
  220 +}
  221 +
  222 +int musb_platform_get_vbus_status(struct musb *musb)
  223 +{
  224 + return 0;
  225 +}
  226 +
  227 +void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
  228 +{
  229 +}
  230 +
  231 +int __init musb_platform_init(struct musb *musb)
  232 +{
  233 +
  234 + /*
  235 + * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
  236 + * and OTG HOST modes, while rev 1.1 and greater require PE7 to
  237 + * be low for DEVICE mode and high for HOST mode. We set it high
  238 + * here because we are in host mode
  239 + */
  240 +
  241 + if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
  242 + printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
  243 + musb->config->gpio_vrsel);
  244 + return -ENODEV;
  245 + }
  246 + gpio_direction_output(musb->config->gpio_vrsel, 0);
  247 +
  248 + /* Anomaly #05000346 */
  249 + bfin_write_USB_APHY_CALIB(0x5411);
  250 + SSYNC();
  251 +
  252 + /* Anomaly #05000347 */
  253 + bfin_write_USB_APHY_CNTRL(0x0);
  254 + SSYNC();
  255 +
  256 + /* TODO
  257 + * Set SIC-IVG register
  258 + */
  259 +
  260 + /* Configure PLL oscillator register */
  261 + bfin_write_USB_PLLOSC_CTRL(0x30a8);
  262 + SSYNC();
  263 +
  264 + bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
  265 + SSYNC();
  266 +
  267 + bfin_write_USB_EP_NI0_RXMAXP(64);
  268 + SSYNC();
  269 +
  270 + bfin_write_USB_EP_NI0_TXMAXP(64);
  271 + SSYNC();
  272 +
  273 + /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
  274 + bfin_write_USB_GLOBINTR(0x7);
  275 + SSYNC();
  276 +
  277 + bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
  278 + EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
  279 + EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
  280 + EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
  281 + EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
  282 + SSYNC();
  283 +
  284 + if (is_host_enabled(musb)) {
  285 + musb->board_set_vbus = bfin_set_vbus;
  286 + setup_timer(&musb_conn_timer,
  287 + musb_conn_timer_handler, (unsigned long) musb);
  288 + }
  289 + if (is_peripheral_enabled(musb))
  290 + musb->xceiv.set_power = bfin_set_power;
  291 +
  292 + musb->isr = blackfin_interrupt;
  293 +
  294 + return 0;
  295 +}
  296 +
  297 +int musb_platform_suspend(struct musb *musb)
  298 +{
  299 + return 0;
  300 +}
  301 +
  302 +int musb_platform_resume(struct musb *musb)
  303 +{
  304 + return 0;
  305 +}
  306 +
  307 +
  308 +int musb_platform_exit(struct musb *musb)
  309 +{
  310 +
  311 + bfin_vbus_power(musb, 0 /*off*/, 1);
  312 + gpio_free(musb->config->gpio_vrsel);
  313 + musb_platform_suspend(musb);
  314 +
  315 + return 0;
  316 +}
drivers/usb/musb/blackfin.h
  1 +/*
  2 + * Copyright (C) 2007 by Analog Devices, Inc.
  3 + *
  4 + * The Inventra Controller Driver for Linux is free software; you
  5 + * can redistribute it and/or modify it under the terms of the GNU
  6 + * General Public License version 2 as published by the Free Software
  7 + * Foundation.
  8 + */
  9 +
  10 +#ifndef __MUSB_BLACKFIN_H__
  11 +#define __MUSB_BLACKFIN_H__
  12 +
  13 +/*
  14 + * Blackfin specific definitions
  15 + */
  16 +
  17 +#undef DUMP_FIFO_DATA
  18 +#ifdef DUMP_FIFO_DATA
  19 +static void dump_fifo_data(u8 *buf, u16 len)
  20 +{
  21 + u8 *tmp = buf;
  22 + int i;
  23 +
  24 + for (i = 0; i < len; i++) {
  25 + if (!(i % 16) && i)
  26 + pr_debug("\n");
  27 + pr_debug("%02x ", *tmp++);
  28 + }
  29 + pr_debug("\n");
  30 +}
  31 +#else
  32 +#define dump_fifo_data(buf, len) do {} while (0)
  33 +#endif
  34 +
  35 +#ifdef CONFIG_BF52x
  36 +
  37 +#define USB_DMA_BASE USB_DMA_INTERRUPT
  38 +#define USB_DMAx_CTRL 0x04
  39 +#define USB_DMAx_ADDR_LOW 0x08
  40 +#define USB_DMAx_ADDR_HIGH 0x0C
  41 +#define USB_DMAx_COUNT_LOW 0x10
  42 +#define USB_DMAx_COUNT_HIGH 0x14
  43 +
  44 +#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg)
  45 +#endif
  46 +
  47 +/* Almost 1 second */
  48 +#define TIMER_DELAY (1 * HZ)
  49 +
  50 +static struct timer_list musb_conn_timer;
  51 +
  52 +#endif /* __MUSB_BLACKFIN_H__ */