diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 611a9d274363..fcb5206a65bd 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -171,8 +171,9 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci) } /* Start sampling ID pin, when plug is removed from MUSB */ - if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE - || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE + || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) || + (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) { mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); musb->a_wait_bcon = TIMER_DELAY; } @@ -323,30 +324,8 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) return -EIO; } -int __init musb_platform_init(struct musb *musb, void *board_data) +static void musb_platform_reg_init(struct musb *musb) { - - /* - * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE - * and OTG HOST modes, while rev 1.1 and greater require PE7 to - * be low for DEVICE mode and high for HOST mode. We set it high - * here because we are in host mode - */ - - if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { - printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n", - musb->config->gpio_vrsel); - return -ENODEV; - } - gpio_direction_output(musb->config->gpio_vrsel, 0); - - usb_nop_xceiv_register(); - musb->xceiv = otg_get_transceiver(); - if (!musb->xceiv) { - gpio_free(musb->config->gpio_vrsel); - return -ENODEV; - } - if (ANOMALY_05000346) { bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); SSYNC(); @@ -358,7 +337,8 @@ int __init musb_platform_init(struct musb *musb, void *board_data) } /* Configure PLL oscillator register */ - bfin_write_USB_PLLOSC_CTRL(0x30a8); + bfin_write_USB_PLLOSC_CTRL(0x3080 | + ((480/musb->config->clkin) << 1)); SSYNC(); bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1); @@ -380,6 +360,33 @@ int __init musb_platform_init(struct musb *musb, void *board_data) EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); SSYNC(); +} + +int __init musb_platform_init(struct musb *musb, void *board_data) +{ + + /* + * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE + * and OTG HOST modes, while rev 1.1 and greater require PE7 to + * be low for DEVICE mode and high for HOST mode. We set it high + * here because we are in host mode + */ + + if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { + printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n", + musb->config->gpio_vrsel); + return -ENODEV; + } + gpio_direction_output(musb->config->gpio_vrsel, 0); + + usb_nop_xceiv_register(); + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) { + gpio_free(musb->config->gpio_vrsel); + return -ENODEV; + } + + musb_platform_reg_init(musb); if (is_host_enabled(musb)) { musb->board_set_vbus = bfin_set_vbus; @@ -394,6 +401,27 @@ int __init musb_platform_init(struct musb *musb, void *board_data) return 0; } +#ifdef CONFIG_PM +void musb_platform_save_context(struct musb *musb, + struct musb_context_registers *musb_context) +{ + if (is_host_active(musb)) + /* + * During hibernate gpio_vrsel will change from high to low + * low which will generate wakeup event resume the system + * immediately. Set it to 0 before hibernate to avoid this + * wakeup event. + */ + gpio_set_value(musb->config->gpio_vrsel, 0); +} + +void musb_platform_restore_context(struct musb *musb, + struct musb_context_registers *musb_context) +{ + musb_platform_reg_init(musb); +} +#endif + int musb_platform_exit(struct musb *musb) { gpio_free(musb->config->gpio_vrsel); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c9f9024c5515..e6669fc3b804 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -552,7 +552,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (int_usb & MUSB_INTR_SESSREQ) { void __iomem *mbase = musb->mregs; - if (devctl & MUSB_DEVCTL_BDEVICE) { + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS + && (devctl & MUSB_DEVCTL_BDEVICE)) { DBG(3, "SessReq while on B state\n"); return IRQ_HANDLED; } @@ -1052,6 +1053,11 @@ static void musb_shutdown(struct platform_device *pdev) clk_put(musb->clock); spin_unlock_irqrestore(&musb->lock, flags); + if (!is_otg_enabled(musb) && is_host_enabled(musb)) + usb_remove_hcd(musb_to_hcd(musb)); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_platform_exit(musb); + /* FIXME power down */ } @@ -2244,13 +2250,6 @@ static int __exit musb_remove(struct platform_device *pdev) */ musb_exit_debugfs(musb); musb_shutdown(pdev); -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (musb->board_mode == MUSB_HOST) - usb_remove_hcd(musb_to_hcd(musb)); -#endif - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_platform_exit(musb); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_free(musb); iounmap(ctrl_base); @@ -2411,9 +2410,6 @@ static int musb_suspend(struct device *dev) unsigned long flags; struct musb *musb = dev_to_musb(&pdev->dev); - if (!musb->clock) - return 0; - spin_lock_irqsave(&musb->lock, flags); if (is_peripheral_active(musb)) { @@ -2428,10 +2424,12 @@ static int musb_suspend(struct device *dev) musb_save_context(musb); - if (musb->set_clock) - musb->set_clock(musb->clock, 0); - else - clk_disable(musb->clock); + if (musb->clock) { + if (musb->set_clock) + musb->set_clock(musb->clock, 0); + else + clk_disable(musb->clock); + } spin_unlock_irqrestore(&musb->lock, flags); return 0; } @@ -2441,13 +2439,12 @@ static int musb_resume_noirq(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct musb *musb = dev_to_musb(&pdev->dev); - if (!musb->clock) - return 0; - - if (musb->set_clock) - musb->set_clock(musb->clock, 1); - else - clk_enable(musb->clock); + if (musb->clock) { + if (musb->set_clock) + musb->set_clock(musb->clock, 1); + else + clk_enable(musb->clock); + } musb_restore_context(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 69797e5b46a7..febaabcc2b35 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -487,7 +487,7 @@ struct musb_context_registers { }; #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) + defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_BLACKFIN) extern void musb_platform_save_context(struct musb *musb, struct musb_context_registers *musb_context); extern void musb_platform_restore_context(struct musb *musb, diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5d815049cbaa..36cfd060dbe5 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -644,10 +644,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) */ csr |= MUSB_RXCSR_DMAENAB; - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) - csr |= MUSB_RXCSR_AUTOCLEAR; #ifdef USE_MODE1 + csr |= MUSB_RXCSR_AUTOCLEAR; /* csr |= MUSB_RXCSR_DMAMODE; */ /* this special sequence (enabling and then @@ -656,6 +654,10 @@ static void rxstate(struct musb *musb, struct musb_request *req) */ musb_writew(epio, MUSB_RXCSR, csr | MUSB_RXCSR_DMAMODE); +#else + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; #endif musb_writew(epio, MUSB_RXCSR, csr); @@ -807,7 +809,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) /* Autoclear doesn't clear RxPktRdy for short packets */ - if ((dma->desired_mode == 0) + if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered) || (dma->actual_len & (musb_ep->packet_sz - 1))) { /* ack the read! */ @@ -818,8 +820,16 @@ void musb_g_rx(struct musb *musb, u8 epnum) /* incomplete, and not short? wait for next IN packet */ if ((request->actual < request->length) && (musb_ep->dma->actual_len - == musb_ep->packet_sz)) + == musb_ep->packet_sz)) { + /* In double buffer case, continue to unload fifo if + * there is Rx packet in FIFO. + **/ + csr = musb_readw(epio, MUSB_RXCSR); + if ((csr & MUSB_RXCSR_RXPKTRDY) && + hw_ep->rx_double_buffered) + goto exit; return; + } #endif musb_g_giveback(musb_ep, request, 0); @@ -827,7 +837,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) if (!request) return; } - +exit: /* Analyze request */ rxstate(musb, to_musb_request(request)); } @@ -916,13 +926,9 @@ static int musb_gadget_enable(struct usb_ep *ep, * likewise high bandwidth periodic tx */ /* Set TXMAXP with the FIFO size of the endpoint - * to disable double buffering mode. Currently, It seems that double - * buffering has problem if musb RTL revision number < 2.0. + * to disable double buffering mode. */ - if (musb->hwvers < MUSB_HWVERS_2000) - musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); - else - musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); + musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; if (musb_readw(regs, MUSB_TXCSR) @@ -958,10 +964,7 @@ static int musb_gadget_enable(struct usb_ep *ep, /* Set RXMAXP with the FIFO size of the endpoint * to disable double buffering mode. */ - if (musb->hwvers < MUSB_HWVERS_2000) - musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx); - else - musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); + musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); /* force shared fifo to OUT-only mode */ if (hw_ep->is_shared_fifo) { @@ -1166,8 +1169,6 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, : DMA_FROM_DEVICE); request->mapped = 0; } - } else if (!req->buf) { - return -ENODATA; } else request->mapped = 0; @@ -1695,8 +1696,10 @@ int __init musb_gadget_setup(struct musb *musb) musb_platform_try_idle(musb, 0); status = device_register(&musb->g.dev); - if (status != 0) + if (status != 0) { + put_device(&musb->g.dev); the_gadget = NULL; + } return status; } diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 244267527a60..5a727c5b8676 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -633,8 +633,9 @@ static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) return 0; } -static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum) +static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) { + return 0; } #endif /* CONFIG_BLACKFIN */ diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 6f771af5cbdb..563114d613d6 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -158,6 +158,8 @@ static int dma_channel_program(struct dma_channel *channel, dma_addr_t dma_addr, u32 len) { struct musb_dma_channel *musb_channel = channel->private_data; + struct musb_dma_controller *controller = musb_channel->controller; + struct musb *musb = controller->private_data; DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", musb_channel->epnum, @@ -167,6 +169,18 @@ static int dma_channel_program(struct dma_channel *channel, BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); + /* + * The DMA engine in RTL1.8 and above cannot handle + * DMA addresses that are not aligned to a 4 byte boundary. + * It ends up masking the last two bits of the address + * programmed in DMA_ADDR. + * + * Fail such DMA transfers, so that the backup PIO mode + * can carry out the transfer + */ + if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4)) + return false; + channel->actual_len = 0; musb_channel->start_addr = dma_addr; musb_channel->len = len; diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h index ee2dd1d506ed..2387f9fc8138 100644 --- a/include/linux/usb/musb.h +++ b/include/linux/usb/musb.h @@ -89,6 +89,8 @@ struct musb_hdrc_config { /* A GPIO controlling VRSEL in Blackfin */ unsigned int gpio_vrsel; unsigned int gpio_vrsel_active; + /* musb CLKIN in Blackfin in MHZ */ + unsigned char clkin; #endif };