diff options
Diffstat (limited to 'drivers/usb/musb/musb_core.c')
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 1262 |
1 files changed, 556 insertions, 706 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e6669fc3b80..eff3c5cf84f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -83,7 +83,7 @@ * This gets many kinds of configuration information: * - Kconfig for everything user-configurable * - platform_device for addressing, irq, and platform_data - * - platform_data is mostly for board-specific informarion + * - platform_data is mostly for board-specific information * (plus recentrly, SOC or family details) * * Most of the conditional compilation will (someday) vanish. @@ -93,32 +93,18 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/kobject.h> +#include <linux/prefetch.h> #include <linux/platform_device.h> #include <linux/io.h> - -#ifdef CONFIG_ARM -#include <mach/hardware.h> -#include <mach/memory.h> -#include <asm/mach-types.h> -#endif +#include <linux/dma-mapping.h> #include "musb_core.h" - -#ifdef CONFIG_ARCH_DAVINCI -#include "davinci.h" -#endif - #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) -unsigned musb_debug; -module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); - #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" #define DRIVER_DESC "Inventra Dual-Role USB Controller Driver" @@ -126,7 +112,7 @@ MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); #define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION -#define MUSB_DRIVER_NAME "musb_hdrc" +#define MUSB_DRIVER_NAME "musb-hdrc" const char musb_driver_name[] = MUSB_DRIVER_NAME; MODULE_DESCRIPTION(DRIVER_INFO); @@ -139,23 +125,21 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); static inline struct musb *dev_to_musb(struct device *dev) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* usbcore insists dev->driver_data is a "struct hcd *" */ - return hcd_to_musb(dev_get_drvdata(dev)); -#else return dev_get_drvdata(dev); -#endif } /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) +static int musb_ulpi_read(struct usb_phy *phy, u32 offset) { - void __iomem *addr = otg->io_priv; + void __iomem *addr = phy->io_priv; int i = 0; u8 r; u8 power; + int ret; + + pm_runtime_get_sync(phy->io_dev); /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); @@ -174,8 +158,8 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) & MUSB_ULPI_REG_CMPLT)) { i++; if (i == 10000) { - DBG(3, "ULPI read timed out\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } } @@ -183,16 +167,23 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) r &= ~MUSB_ULPI_REG_CMPLT; musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - return musb_readb(addr, MUSB_ULPI_REG_DATA); + ret = musb_readb(addr, MUSB_ULPI_REG_DATA); + +out: + pm_runtime_put(phy->io_dev); + + return ret; } -static int musb_ulpi_write(struct otg_transceiver *otg, - u32 offset, u32 data) +static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) { - void __iomem *addr = otg->io_priv; + void __iomem *addr = phy->io_priv; int i = 0; u8 r = 0; u8 power; + int ret = 0; + + pm_runtime_get_sync(phy->io_dev); /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); @@ -207,8 +198,8 @@ static int musb_ulpi_write(struct otg_transceiver *otg, & MUSB_ULPI_REG_CMPLT)) { i++; if (i == 10000) { - DBG(3, "ULPI write timed out\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } } @@ -216,32 +207,39 @@ static int musb_ulpi_write(struct otg_transceiver *otg, r &= ~MUSB_ULPI_REG_CMPLT; musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - return 0; +out: + pm_runtime_put(phy->io_dev); + + return ret; } #else #define musb_ulpi_read NULL #define musb_ulpi_write NULL #endif -static struct otg_io_access_ops musb_ulpi_access = { +static struct usb_phy_io_ops musb_ulpi_access = { .read = musb_ulpi_read, .write = musb_ulpi_write, }; /*-------------------------------------------------------------------------*/ -#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) +#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN) /* * Load an endpoint's FIFO */ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) { + struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; + if (unlikely(len == 0)) + return; + prefetch((u8 *)src); - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", 'T', hw_ep->epnum, fifo, len, src); /* we can't assume unaligned reads work */ @@ -251,7 +249,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) /* best case is 32bit-aligned source address */ if ((0x02 & (unsigned long) src) == 0) { if (len >= 4) { - writesl(fifo, src + index, len >> 2); + iowrite32_rep(fifo, src + index, len >> 2); index += len & ~0x03; } if (len & 0x02) { @@ -260,7 +258,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) } } else { if (len >= 2) { - writesw(fifo, src + index, len >> 1); + iowrite16_rep(fifo, src + index, len >> 1); index += len & ~0x01; } } @@ -268,7 +266,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) musb_writeb(fifo, 0, src[index]); } else { /* byte aligned */ - writesb(fifo, src, len); + iowrite8_rep(fifo, src, len); } } @@ -278,9 +276,13 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) */ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) { + struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + if (unlikely(len == 0)) + return; + + dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", 'R', hw_ep->epnum, fifo, len, dst); /* we can't assume unaligned writes work */ @@ -290,7 +292,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) /* best case is 32bit-aligned destination address */ if ((0x02 & (unsigned long) dst) == 0) { if (len >= 4) { - readsl(fifo, dst, len >> 2); + ioread32_rep(fifo, dst, len >> 2); index = len & ~0x03; } if (len & 0x02) { @@ -299,7 +301,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } } else { if (len >= 2) { - readsw(fifo, dst, len >> 1); + ioread16_rep(fifo, dst, len >> 1); index = len & ~0x01; } } @@ -307,7 +309,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) dst[index] = musb_readb(fifo, 0); } else { /* byte aligned */ - readsb(fifo, dst, len); + ioread8_rep(fifo, dst, len); } } #endif @@ -349,32 +351,10 @@ void musb_load_testpacket(struct musb *musb) /*-------------------------------------------------------------------------*/ -const char *otg_state_string(struct musb *musb) -{ - switch (musb->xceiv->state) { - case OTG_STATE_A_IDLE: return "a_idle"; - case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; - case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; - case OTG_STATE_A_HOST: return "a_host"; - case OTG_STATE_A_SUSPEND: return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; - case OTG_STATE_B_IDLE: return "b_idle"; - case OTG_STATE_B_SRP_INIT: return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; - case OTG_STATE_B_HOST: return "b_host"; - default: return "UNDEFINED"; - } -} - -#ifdef CONFIG_USB_MUSB_OTG - /* * Handles OTG hnp timeouts, such as b_ase0_brst */ -void musb_otg_timer_func(unsigned long data) +static void musb_otg_timer_func(unsigned long data) { struct musb *musb = (struct musb *)data; unsigned long flags; @@ -382,21 +362,22 @@ void musb_otg_timer_func(unsigned long data) spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_B_WAIT_ACON: - DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n"); + dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n"); musb_g_disconnect(musb); musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 0; break; case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: - DBG(1, "HNP: %s timeout\n", otg_state_string(musb)); - musb_set_vbus(musb, 0); + dev_dbg(musb->controller, "HNP: %s timeout\n", + usb_otg_state_string(musb->xceiv->state)); + musb_platform_set_vbus(musb, 0); musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; break; default: - DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb)); + dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", + usb_otg_state_string(musb->xceiv->state)); } - musb->ignore_disconnect = 0; spin_unlock_irqrestore(&musb->lock, flags); } @@ -405,20 +386,23 @@ void musb_otg_timer_func(unsigned long data) */ void musb_hnp_stop(struct musb *musb) { - struct usb_hcd *hcd = musb_to_hcd(musb); + struct usb_hcd *hcd = musb->hcd; void __iomem *mbase = musb->mregs; u8 reg; - DBG(1, "HNP: stop from %s\n", otg_state_string(musb)); + dev_dbg(musb->controller, "HNP: stop from %s\n", + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { case OTG_STATE_A_PERIPHERAL: musb_g_disconnect(musb); - DBG(1, "HNP: back to %s\n", otg_state_string(musb)); + dev_dbg(musb->controller, "HNP: back to %s\n", + usb_otg_state_string(musb->xceiv->state)); break; case OTG_STATE_B_HOST: - DBG(1, "HNP: Disabling HR\n"); - hcd->self.is_b_host = 0; + dev_dbg(musb->controller, "HNP: Disabling HR\n"); + if (hcd) + hcd->self.is_b_host = 0; musb->xceiv->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); reg = musb_readb(mbase, MUSB_POWER); @@ -427,8 +411,8 @@ void musb_hnp_stop(struct musb *musb) /* REVISIT: Start SESSION_REQUEST here? */ break; default: - DBG(1, "HNP: Stopping in unknown state %s\n", - otg_state_string(musb)); + dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", + usb_otg_state_string(musb->xceiv->state)); } /* @@ -439,8 +423,6 @@ void musb_hnp_stop(struct musb *musb) musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); } -#endif - /* * Interrupt Service Routine to record USB "global" interrupts. * Since these do not happen often and signify things of @@ -454,11 +436,11 @@ void musb_hnp_stop(struct musb *musb) */ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, - u8 devctl, u8 power) + u8 devctl) { irqreturn_t handled = IRQ_NONE; - DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, + dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, int_usb); /* in host mode, the peripheral may issue remote wakeup. @@ -467,11 +449,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ if (int_usb & MUSB_INTR_RESUME) { handled = IRQ_HANDLED; - DBG(3, "RESUME (%s)\n", otg_state_string(musb)); + dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state)); if (devctl & MUSB_DEVCTL_HM) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD void __iomem *mbase = musb->mregs; + u8 power; switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: @@ -479,10 +461,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * will stop RESUME signaling */ + power = musb_readb(musb->mregs, MUSB_POWER); if (power & MUSB_POWER_SUSPENDM) { /* spurious */ musb->int_usb &= ~MUSB_INTR_SUSPEND; - DBG(2, "Spurious SUSPENDM\n"); + dev_dbg(musb->controller, "Spurious SUSPENDM\n"); break; } @@ -494,11 +477,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies - + msecs_to_jiffies(20); + + msecs_to_jiffies(20); + schedule_delayed_work( + &musb->finish_resume_work, + msecs_to_jiffies(20)); musb->xceiv->state = OTG_STATE_A_HOST; musb->is_active = 1; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: musb->xceiv->state = OTG_STATE_B_PERIPHERAL; @@ -508,19 +494,15 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "host", - otg_state_string(musb)); + usb_otg_state_string(musb->xceiv->state)); } -#endif } else { switch (musb->xceiv->state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_SUSPEND: /* possibly DISCONNECT is upcoming */ musb->xceiv->state = OTG_STATE_A_HOST; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); break; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_PERIPHERAL: /* disconnect while suspended? we may @@ -538,27 +520,26 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, case OTG_STATE_B_IDLE: musb->int_usb &= ~MUSB_INTR_SUSPEND; break; -#endif default: WARNING("bogus %s RESUME (%s)\n", "peripheral", - otg_state_string(musb)); + usb_otg_state_string(musb->xceiv->state)); } } } -#ifdef CONFIG_USB_MUSB_HDRC_HCD /* see manual for the order of the tests */ if (int_usb & MUSB_INTR_SESSREQ) { void __iomem *mbase = musb->mregs; if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS && (devctl & MUSB_DEVCTL_BDEVICE)) { - DBG(3, "SessReq while on B state\n"); + dev_dbg(musb->controller, "SessReq while on B state\n"); return IRQ_HANDLED; } - DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); + dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", + usb_otg_state_string(musb->xceiv->state)); /* IRQ arrives from ID pin sense or (later, if VBUS power * is removed) SRP. responses are time critical: @@ -571,7 +552,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->ep0_stage = MUSB_EP0_START; musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); - musb_set_vbus(musb, 1); + musb_platform_set_vbus(musb, 1); handled = IRQ_HANDLED; } @@ -622,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; } - DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - otg_state_string(musb), + dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, + "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", + usb_otg_state_string(musb->xceiv->state), devctl, ({ char *s; switch (devctl & MUSB_DEVCTL_VBUS) { @@ -636,24 +618,22 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */ default: s = "VALID"; break; - }; s; }), + } s; }), VBUSERR_RETRY_COUNT - musb->vbuserr_retry, musb->port1_status); /* go through A_WAIT_VFALL then start a new session */ if (!ignore) - musb_set_vbus(musb, 0); + musb_platform_set_vbus(musb, 0); handled = IRQ_HANDLED; } -#endif if (int_usb & MUSB_INTR_SUSPEND) { - DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", - otg_state_string(musb), devctl, power); + dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", + usb_otg_state_string(musb->xceiv->state), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { -#ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_A_PERIPHERAL: /* We also come here if the cable is removed, since * this silicon doesn't report ID-no-longer-grounded. @@ -663,29 +643,25 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * undesired detour through A_WAIT_BCON. */ musb_hnp_stop(musb); - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); musb_root_disconnect(musb); musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(musb->a_wait_bcon ? : OTG_TIME_A_WAIT_BCON)); break; -#endif case OTG_STATE_B_IDLE: if (!musb->is_active) break; case OTG_STATE_B_PERIPHERAL: musb_g_suspend(musb); - musb->is_active = is_otg_enabled(musb) - && musb->xceiv->gadget->b_hnp_enable; + musb->is_active = musb->g.b_hnp_enable; if (musb->is_active) { -#ifdef CONFIG_USB_MUSB_OTG musb->xceiv->state = OTG_STATE_B_WAIT_ACON; - DBG(1, "HNP: Setting timer for b_ase0_brst\n"); + dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( OTG_TIME_B_ASE0_BRST)); -#endif } break; case OTG_STATE_A_WAIT_BCON: @@ -695,12 +671,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && musb->xceiv->host->b_hnp_enable; + musb->is_active = musb->hcd->self.b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ - DBG(1, "REVISIT: SUSPEND as B_HOST\n"); + dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n"); break; default: /* "should not happen" */ @@ -709,25 +684,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } } -#ifdef CONFIG_USB_MUSB_HDRC_HCD if (int_usb & MUSB_INTR_CONNECT) { - struct usb_hcd *hcd = musb_to_hcd(musb); + struct usb_hcd *hcd = musb->hcd; handled = IRQ_HANDLED; musb->is_active = 1; - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); musb->ep0_stage = MUSB_EP0_START; -#ifdef CONFIG_USB_MUSB_OTG /* flush endpoints when transitioning from Device Mode */ if (is_peripheral_active(musb)) { /* REVISIT HNP; just force disconnect */ } - musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); - musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); -#endif musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED |USB_PORT_STAT_HIGH_SPEED |USB_PORT_STAT_ENABLE @@ -743,59 +716,51 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, switch (musb->xceiv->state) { case OTG_STATE_B_PERIPHERAL: if (int_usb & MUSB_INTR_SUSPEND) { - DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n"); + dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); int_usb &= ~MUSB_INTR_SUSPEND; goto b_host; } else - DBG(1, "CONNECT as b_peripheral???\n"); + dev_dbg(musb->controller, "CONNECT as b_peripheral???\n"); break; case OTG_STATE_B_WAIT_ACON: - DBG(1, "HNP: CONNECT, now b_host\n"); + dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n"); b_host: musb->xceiv->state = OTG_STATE_B_HOST; - hcd->self.is_b_host = 1; - musb->ignore_disconnect = 0; + if (musb->hcd) + musb->hcd->self.is_b_host = 1; del_timer(&musb->otg_timer); break; default: if ((devctl & MUSB_DEVCTL_VBUS) == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { musb->xceiv->state = OTG_STATE_A_HOST; - hcd->self.is_b_host = 0; + if (hcd) + hcd->self.is_b_host = 0; } break; } - /* poke the root hub */ - MUSB_HST_MODE(musb); - if (hcd->status_urb) - usb_hcd_poll_rh_status(hcd); - else - usb_hcd_resume_root_hub(hcd); + musb_host_poke_root_hub(musb); - DBG(1, "CONNECT (%s) devctl %02x\n", - otg_state_string(musb), devctl); + dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", + usb_otg_state_string(musb->xceiv->state), devctl); } -#endif /* CONFIG_USB_MUSB_HDRC_HCD */ - if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { - DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n", - otg_state_string(musb), + if (int_usb & MUSB_INTR_DISCONNECT) { + dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", + usb_otg_state_string(musb->xceiv->state), MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_HOST: case OTG_STATE_A_SUSPEND: - usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_host_resume_root_hub(musb); musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) + if (musb->a_wait_bcon != 0) musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(musb->a_wait_bcon)); break; -#endif /* HOST */ -#ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_B_HOST: /* REVISIT this behaves for "real disconnect" * cases; make sure the other transitions from @@ -803,7 +768,8 @@ b_host: * in hnp_stop() is currently not used... */ musb_root_disconnect(musb); - musb_to_hcd(musb)->self.is_b_host = 0; + if (musb->hcd) + musb->hcd->self.is_b_host = 0; musb->xceiv->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); musb_g_disconnect(musb); @@ -814,16 +780,13 @@ b_host: /* FALLTHROUGH */ case OTG_STATE_B_WAIT_ACON: /* FALLTHROUGH */ -#endif /* OTG */ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: musb_g_disconnect(musb); break; -#endif /* GADGET */ default: WARNING("unhandled DISCONNECT transition (%s)\n", - otg_state_string(musb)); + usb_otg_state_string(musb->xceiv->state)); break; } } @@ -833,7 +796,7 @@ b_host: */ if (int_usb & MUSB_INTR_RESET) { handled = IRQ_HANDLED; - if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) { + if ((devctl & MUSB_DEVCTL_HM) != 0) { /* * Looks like non-HS BABBLE can be ignored, but * HS BABBLE is an error condition. For HS the solution @@ -842,43 +805,36 @@ b_host: * stop the session. */ if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) - DBG(1, "BABBLE devctl: %02x\n", devctl); + dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl); else { ERR("Stopping host session -- babble\n"); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } - } else if (is_peripheral_capable()) { - DBG(1, "BUS RESET as %s\n", otg_state_string(musb)); + } else { + dev_dbg(musb->controller, "BUS RESET as %s\n", + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { -#ifdef CONFIG_USB_OTG case OTG_STATE_A_SUSPEND: - /* We need to ignore disconnect on suspend - * otherwise tusb 2.0 won't reconnect after a - * power cycle, which breaks otg compliance. - */ - musb->ignore_disconnect = 1; musb_g_reset(musb); /* FALLTHROUGH */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ /* never use invalid T(a_wait_bcon) */ - DBG(1, "HNP: in %s, %d msec timeout\n", - otg_state_string(musb), - TA_WAIT_BCON(musb)); + dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", + usb_otg_state_string(musb->xceiv->state), + TA_WAIT_BCON(musb)); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(TA_WAIT_BCON(musb))); break; case OTG_STATE_A_PERIPHERAL: - musb->ignore_disconnect = 0; del_timer(&musb->otg_timer); musb_g_reset(musb); break; case OTG_STATE_B_WAIT_ACON: - DBG(1, "HNP: RESET (%s), to b_peripheral\n", - otg_state_string(musb)); + dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", + usb_otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); break; -#endif case OTG_STATE_B_IDLE: musb->xceiv->state = OTG_STATE_B_PERIPHERAL; /* FALLTHROUGH */ @@ -886,12 +842,16 @@ b_host: musb_g_reset(musb); break; default: - DBG(1, "Unhandled BUS RESET as %s\n", - otg_state_string(musb)); + dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", + usb_otg_state_string(musb->xceiv->state)); } } } + /* handle babble condition */ + if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) + schedule_work(&musb->recover_work); + #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -910,7 +870,7 @@ b_host: u8 epnum; u16 frame; - DBG(6, "START_OF_FRAME\n"); + dev_dbg(musb->controller, "START_OF_FRAME\n"); handled = IRQ_HANDLED; /* start any periodic Tx transfers waiting for current frame */ @@ -944,79 +904,74 @@ b_host: /*-------------------------------------------------------------------------*/ +static void musb_generic_disable(struct musb *musb) +{ + void __iomem *mbase = musb->mregs; + u16 temp; + + /* disable interrupts */ + musb_writeb(mbase, MUSB_INTRUSBE, 0); + musb->intrtxe = 0; + musb_writew(mbase, MUSB_INTRTXE, 0); + musb->intrrxe = 0; + musb_writew(mbase, MUSB_INTRRXE, 0); + + /* off */ + musb_writeb(mbase, MUSB_DEVCTL, 0); + + /* flush pending interrupts */ + temp = musb_readb(mbase, MUSB_INTRUSB); + temp = musb_readw(mbase, MUSB_INTRTX); + temp = musb_readw(mbase, MUSB_INTRRX); + +} + /* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ + * Program the HDRC to start (enable interrupts, dma, etc.). + */ void musb_start(struct musb *musb) { - void __iomem *regs = musb->mregs; - u8 devctl = musb_readb(regs, MUSB_DEVCTL); + void __iomem *regs = musb->mregs; + u8 devctl = musb_readb(regs, MUSB_DEVCTL); - DBG(2, "<== devctl %02x\n", devctl); + dev_dbg(musb->controller, "<== devctl %02x\n", devctl); /* Set INT enable registers, enable interrupts */ - musb_writew(regs, MUSB_INTRTXE, musb->epmask); - musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(regs, MUSB_INTRUSBE, 0xf7); musb_writeb(regs, MUSB_TESTMODE, 0); /* put into basic highspeed mode and start session */ musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE - | MUSB_POWER_SOFTCONN - | MUSB_POWER_HSENAB - /* ENSUSPEND wedges tusb */ - /* | MUSB_POWER_ENSUSPEND */ - ); + | MUSB_POWER_HSENAB + /* ENSUSPEND wedges tusb */ + /* | MUSB_POWER_ENSUSPEND */ + ); musb->is_active = 0; devctl = musb_readb(regs, MUSB_DEVCTL); devctl &= ~MUSB_DEVCTL_SESSION; - if (is_otg_enabled(musb)) { - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; - - } else if (is_host_enabled(musb)) { - /* assume ID pin is hard-wired to ground */ + /* session started after: + * (a) ID-grounded irq, host mode; + * (b) vbus present/connect IRQ, peripheral mode; + * (c) peripheral initiates, using SRP + */ + if (musb->port_mode != MUSB_PORT_MODE_HOST && + (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { + musb->is_active = 1; + } else { devctl |= MUSB_DEVCTL_SESSION; - - } else /* peripheral is enabled */ { - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; } + musb_platform_enable(musb); musb_writeb(regs, MUSB_DEVCTL, devctl); } - -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u16 temp; - - /* disable interrupts */ - musb_writeb(mbase, MUSB_INTRUSBE, 0); - musb_writew(mbase, MUSB_INTRTXE, 0); - musb_writew(mbase, MUSB_INTRRXE, 0); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); - - /* flush pending interrupts */ - temp = musb_readb(mbase, MUSB_INTRUSB); - temp = musb_readw(mbase, MUSB_INTRTX); - temp = musb_readw(mbase, MUSB_INTRRX); - -} - /* * Make the HDRC stop (disable interrupts, etc.); * reversible by musb_start @@ -1029,7 +984,7 @@ void musb_stop(struct musb *musb) /* stop IRQs, timers, ... */ musb_platform_disable(musb); musb_generic_disable(musb); - DBG(3, "HDRC disabled\n"); + dev_dbg(musb->controller, "HDRC disabled\n"); /* FIXME * - mark host and/or peripheral drivers unusable/inactive @@ -1046,18 +1001,20 @@ static void musb_shutdown(struct platform_device *pdev) struct musb *musb = dev_to_musb(&pdev->dev); unsigned long flags; + pm_runtime_get_sync(musb->controller); + + musb_host_cleanup(musb); + musb_gadget_cleanup(musb); + spin_lock_irqsave(&musb->lock, flags); musb_platform_disable(musb); musb_generic_disable(musb); - if (musb->clock) - 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); + pm_runtime_put(musb->controller); /* FIXME power down */ } @@ -1074,12 +1031,20 @@ static void musb_shutdown(struct platform_device *pdev) * We don't currently use dynamic fifo setup capability to do anything * more than selecting one of a bunch of predefined configurations. */ -#if defined(CONFIG_USB_TUSB6010) || \ - defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ - || defined(CONFIG_ARCH_OMAP4) -static ushort __initdata fifo_mode = 4; +#if defined(CONFIG_USB_MUSB_TUSB6010) \ + || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) \ + || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ + || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \ + || defined(CONFIG_USB_MUSB_AM35X) \ + || defined(CONFIG_USB_MUSB_AM35X_MODULE) \ + || defined(CONFIG_USB_MUSB_DSPS) \ + || defined(CONFIG_USB_MUSB_DSPS_MODULE) +static ushort fifo_mode = 4; +#elif defined(CONFIG_USB_MUSB_UX500) \ + || defined(CONFIG_USB_MUSB_UX500_MODULE) +static ushort fifo_mode = 5; #else -static ushort __initdata fifo_mode = 2; +static ushort fifo_mode = 2; #endif /* "modprobe ... fifo_mode=1" etc */ @@ -1092,7 +1057,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); */ /* mode 0 - fits in 2KB */ -static struct musb_fifo_cfg __initdata mode_0_cfg[] = { +static struct musb_fifo_cfg mode_0_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, @@ -1101,7 +1066,7 @@ static struct musb_fifo_cfg __initdata mode_0_cfg[] = { }; /* mode 1 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_1_cfg[] = { +static struct musb_fifo_cfg mode_1_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, @@ -1110,7 +1075,7 @@ static struct musb_fifo_cfg __initdata mode_1_cfg[] = { }; /* mode 2 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_2_cfg[] = { +static struct musb_fifo_cfg mode_2_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1120,7 +1085,7 @@ static struct musb_fifo_cfg __initdata mode_2_cfg[] = { }; /* mode 3 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_3_cfg[] = { +static struct musb_fifo_cfg mode_3_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1130,7 +1095,7 @@ static struct musb_fifo_cfg __initdata mode_3_cfg[] = { }; /* mode 4 - fits in 16KB */ -static struct musb_fifo_cfg __initdata mode_4_cfg[] = { +static struct musb_fifo_cfg mode_4_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1161,7 +1126,7 @@ static struct musb_fifo_cfg __initdata mode_4_cfg[] = { }; /* mode 5 - fits in 8KB */ -static struct musb_fifo_cfg __initdata mode_5_cfg[] = { +static struct musb_fifo_cfg mode_5_cfg[] = { { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, @@ -1197,7 +1162,7 @@ static struct musb_fifo_cfg __initdata mode_5_cfg[] = { * * returns negative errno or offset for next fifo. */ -static int __init +static int fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, const struct musb_fifo_cfg *cfg, u16 offset) { @@ -1226,14 +1191,12 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, /* configure the FIFO */ musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); -#ifdef CONFIG_USB_MUSB_HDRC_HCD /* EP0 reserved endpoint for control, bidirectional; - * EP1 reserved for bulk, two unidirection halves. + * EP1 reserved for bulk, two unidirectional halves. */ if (hw_ep->epnum == 1) musb->bulk_ep = hw_ep; /* REVISIT error check: be sure ep0 can both rx and tx ... */ -#endif switch (cfg->style) { case FIFO_TX: musb_write_txfifosz(mbase, c_size); @@ -1270,11 +1233,11 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); } -static struct musb_fifo_cfg __initdata ep0_cfg = { +static struct musb_fifo_cfg ep0_cfg = { .style = FIFO_RXTX, .maxpacket = 64, }; -static int __init ep_config_from_table(struct musb *musb) +static int ep_config_from_table(struct musb *musb) { const struct musb_fifo_cfg *cfg; unsigned i, n; @@ -1341,7 +1304,7 @@ done: if (offset < 0) { pr_debug("%s: mem overrun, ep %d\n", musb_driver_name, epn); - return -EINVAL; + return offset; } epn++; musb->nr_endpoints = max(epn, musb->nr_endpoints); @@ -1352,12 +1315,10 @@ done: n + 1, musb->config->num_eps * 2 - 1, offset, (1 << (musb->config->ram_bits + 2))); -#ifdef CONFIG_USB_MUSB_HDRC_HCD if (!musb->bulk_ep) { pr_debug("%s: missing bulk\n", musb_driver_name); return -EINVAL; } -#endif return 0; } @@ -1367,14 +1328,14 @@ done: * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false * @param musb the controller */ -static int __init ep_config_from_hw(struct musb *musb) +static int ep_config_from_hw(struct musb *musb) { u8 epnum = 0; struct musb_hw_ep *hw_ep; - void *mbase = musb->mregs; + void __iomem *mbase = musb->mregs; int ret = 0; - DBG(2, "<== static silicon ep config\n"); + dev_dbg(musb->controller, "<== static silicon ep config\n"); /* FIXME pick up ep0 maxpacket size */ @@ -1388,7 +1349,6 @@ static int __init ep_config_from_hw(struct musb *musb) /* FIXME set up hw_ep->{rx,tx}_double_buffered */ -#ifdef CONFIG_USB_MUSB_HDRC_HCD /* pick an RX/TX endpoint for bulk */ if (hw_ep->max_packet_sz_tx < 512 || hw_ep->max_packet_sz_rx < 512) @@ -1400,15 +1360,12 @@ static int __init ep_config_from_hw(struct musb *musb) if (musb->bulk_ep) continue; musb->bulk_ep = hw_ep; -#endif } -#ifdef CONFIG_USB_MUSB_HDRC_HCD if (!musb->bulk_ep) { pr_debug("%s: missing bulk\n", musb_driver_name); return -EINVAL; } -#endif return 0; } @@ -1418,7 +1375,7 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, }; /* Initialize MUSB (M)HDRC part of the USB hardware subsystem; * configure endpoints, or take their config from silicon */ -static int __init musb_core_init(u16 musb_type, struct musb *musb) +static int musb_core_init(u16 musb_type, struct musb *musb) { u8 reg; char *type; @@ -1464,13 +1421,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) } else { musb->is_multipoint = 0; type = ""; -#ifdef CONFIG_USB_MUSB_HDRC_HCD #ifndef CONFIG_USB_OTG_BLACKLIST_HUB printk(KERN_ERR "%s: kernel must blacklist external hubs\n", musb_driver_name); #endif -#endif } /* log release info */ @@ -1501,7 +1456,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) struct musb_hw_ep *hw_ep = musb->endpoints + i; hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i); hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i); hw_ep->fifo_sync_va = @@ -1514,14 +1469,12 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) #endif hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; -#ifdef CONFIG_USB_MUSB_HDRC_HCD hw_ep->target_regs = musb_read_target_reg_base(i, mbase); hw_ep->rx_reinit = 1; hw_ep->tx_reinit = 1; -#endif if (hw_ep->max_packet_sz_tx) { - DBG(1, + dev_dbg(musb->controller, "%s: hw_ep %d%s, %smax %d\n", musb_driver_name, i, hw_ep->is_shared_fifo ? "shared" : "tx", @@ -1530,7 +1483,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) hw_ep->max_packet_sz_tx); } if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { - DBG(1, + dev_dbg(musb->controller, "%s: hw_ep %d%s, %smax %d\n", musb_driver_name, i, "rx", @@ -1539,7 +1492,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) hw_ep->max_packet_sz_rx); } if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) - DBG(1, "hw_ep %d not configured\n", i); + dev_dbg(musb->controller, "hw_ep %d not configured\n", i); } return 0; @@ -1547,33 +1500,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -#else -#define generic_interrupt NULL -#endif - /* * handle all the irqs defined by the HDRC core. for now we expect: other * irq sources (phy, dma, etc) will be handled first, musb->int_* values @@ -1584,31 +1510,22 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) irqreturn_t musb_interrupt(struct musb *musb) { irqreturn_t retval = IRQ_NONE; - u8 devctl, power; + u8 devctl; int ep_num; u32 reg; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - power = musb_readb(musb->mregs, MUSB_POWER); - DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", + dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) - if (!musb->gadget_driver) { - DBG(5, "No gadget driver loaded\n"); - return IRQ_HANDLED; - } -#endif - /* the core can interrupt us for multiple reasons; docs have * a generic interrupt flowchart to follow */ if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, - devctl, power); + devctl); /* "stage 1" is handling endpoint irqs */ @@ -1628,13 +1545,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, ep_num); + else + musb_g_rx(musb, ep_num); } reg >>= 1; @@ -1649,13 +1563,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, ep_num); + else + musb_g_tx(musb, ep_num); } reg >>= 1; ep_num++; @@ -1663,10 +1574,10 @@ irqreturn_t musb_interrupt(struct musb *musb) return retval; } - +EXPORT_SYMBOL_GPL(musb_interrupt); #ifndef CONFIG_MUSB_PIO_ONLY -static int __initdata use_dma = 1; +static bool use_dma = 1; /* "modprobe ... use_dma=0" etc */ module_param(use_dma, bool, 0); @@ -1691,25 +1602,20 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) } else { /* endpoints 1..15 */ if (transmit) { - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, epnum); + else + musb_g_tx(musb, epnum); } else { /* receive */ - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, epnum); + else + musb_g_rx(musb, epnum); } } } +EXPORT_SYMBOL_GPL(musb_dma_completion); #else #define use_dma 0 @@ -1717,8 +1623,6 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_SYSFS - static ssize_t musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1727,7 +1631,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) int ret = -EINVAL; spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", otg_state_string(musb)); + ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state)); spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -1801,8 +1705,6 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - /* Gadget drivers can't know that a host is connected so they might want * to start SRP, but users can. This allows userspace to trigger SRP. */ @@ -1826,14 +1728,10 @@ musb_srp_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); -#endif /* CONFIG_USB_GADGET_MUSB_HDRC */ - static struct attribute *musb_attributes[] = { &dev_attr_mode.attr, &dev_attr_vbus.attr, -#ifdef CONFIG_USB_GADGET_MUSB_HDRC &dev_attr_srp.attr, -#endif NULL }; @@ -1841,56 +1739,67 @@ static const struct attribute_group musb_attr_group = { .attrs = musb_attributes, }; -#endif /* sysfs */ - /* Only used to provide driver mode change events */ static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work); - static int old_state; - if (musb->xceiv->state != old_state) { - old_state = musb->xceiv->state; + if (musb->xceiv->state != musb->xceiv_old_state) { + musb->xceiv_old_state = musb->xceiv->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, recover_work); + int status; + + musb_platform_reset(musb); + + usb_phy_vbus_off(musb->xceiv); + udelay(100); + + usb_phy_vbus_on(musb->xceiv); + udelay(100); + + /* + * When a babble condition occurs, the musb controller removes the + * session bit and the endpoint config is lost. + */ + if (musb->dyn_fifo) + status = ep_config_from_table(musb); + else + status = ep_config_from_hw(musb); + + /* start the session again */ + if (status == 0) + musb_start(musb); +} + /* -------------------------------------------------------------------------- * Init support */ -static struct musb *__init -allocate_instance(struct device *dev, +static struct musb *allocate_instance(struct device *dev, struct musb_hdrc_config *config, void __iomem *mbase) { struct musb *musb; struct musb_hw_ep *ep; int epnum; -#ifdef CONFIG_USB_MUSB_HDRC_HCD - struct usb_hcd *hcd; + int ret; - hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); - if (!hcd) + musb = devm_kzalloc(dev, sizeof(*musb), GFP_KERNEL); + if (!musb) return NULL; - /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ - musb = hcd_to_musb(hcd); INIT_LIST_HEAD(&musb->control); INIT_LIST_HEAD(&musb->in_bulk); INIT_LIST_HEAD(&musb->out_bulk); - hcd->uses_new_polling = 1; - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; -#else - musb = kzalloc(sizeof *musb, GFP_KERNEL); - if (!musb) - return NULL; - dev_set_drvdata(dev, musb); - -#endif - musb->mregs = mbase; musb->ctrl_base = mbase; musb->nIrq = -ENODEV; @@ -1904,7 +1813,17 @@ allocate_instance(struct device *dev, } musb->controller = dev; + + ret = musb_host_alloc(musb); + if (ret < 0) + goto err_free; + + dev_set_drvdata(dev, musb); + return musb; + +err_free: + return NULL; } static void musb_free(struct musb *musb) @@ -1918,43 +1837,44 @@ static void musb_free(struct musb *musb) sysfs_remove_group(&musb->controller->kobj, &musb_attr_group); #endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - musb_gadget_cleanup(musb); -#endif - if (musb->nIrq >= 0) { if (musb->irq_wake) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - (void) c->stop(c); - dma_controller_destroy(c); - } + musb_host_free(musb); +} -#ifdef CONFIG_USB_MUSB_HDRC_HCD - usb_put_hcd(musb_to_hcd(musb)); -#else - kfree(musb); -#endif +static void musb_deassert_reset(struct work_struct *work) +{ + struct musb *musb; + unsigned long flags; + + musb = container_of(work, struct musb, deassert_reset_work.work); + + spin_lock_irqsave(&musb->lock, flags); + + if (musb->port1_status & USB_PORT_STAT_RESET) + musb_port_reset(musb, false); + + spin_unlock_irqrestore(&musb->lock, flags); } /* * Perform generic per-controller initialization. * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, + * @dev: the controller (already clocked, etc) + * @nIrq: IRQ number + * @ctrl: virtual address of controller registers, * not yet corrected for platform-specific offsets */ -static int __init +static int musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) { int status; struct musb *musb; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. @@ -1965,31 +1885,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail0; } - switch (plat->mode) { - case MUSB_HOST: -#ifdef CONFIG_USB_MUSB_HDRC_HCD - break; -#else - goto bad_config; -#endif - case MUSB_PERIPHERAL: -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - break; -#else - goto bad_config; -#endif - case MUSB_OTG: -#ifdef CONFIG_USB_MUSB_OTG - break; -#else -bad_config: -#endif - default: - dev_err(dev, "incompatible Kconfig role setting\n"); - status = -EINVAL; - goto fail0; - } - /* allocate */ musb = allocate_instance(dev, plat->config, ctrl); if (!musb) { @@ -1997,72 +1892,63 @@ bad_config: goto fail0; } + pm_runtime_use_autosuspend(musb->controller); + pm_runtime_set_autosuspend_delay(musb->controller, 200); + pm_runtime_enable(musb->controller); + spin_lock_init(&musb->lock); - musb->board_mode = plat->mode; musb->board_set_power = plat->set_power; - musb->set_clock = plat->set_clock; musb->min_power = plat->min_power; - - /* Clock usage is chip-specific ... functional clock (DaVinci, - * OMAP2430), or PHY ref (some TUSB6010 boards). All this core - * code does is make sure a clock handle is available; platform - * code manages it during start/stop and suspend/resume. - */ - if (plat->clock) { - musb->clock = clk_get(dev, plat->clock); - if (IS_ERR(musb->clock)) { - status = PTR_ERR(musb->clock); - musb->clock = NULL; - goto fail1; - } - } + musb->ops = plat->platform_ops; + musb->port_mode = plat->mode; /* The musb_platform_init() call: - * - adjusts musb->mregs and musb->isr if needed, - * - may initialize an integrated tranceiver - * - initializes musb->xceiv, usually by otg_get_transceiver() - * - activates clocks. + * - adjusts musb->mregs + * - sets the musb->isr + * - may initialize an integrated transceiver + * - initializes musb->xceiv, usually by otg_get_phy() * - stops powering VBUS - * - assigns musb->board_set_vbus if host mode is enabled * - * There are various transciever configurations. Blackfin, + * There are various transceiver configurations. Blackfin, * DaVinci, TUSB60x0, and others integrate them. OMAP3 uses * external/discrete ones in various flavors (twl4030 family, * isp1504, non-OTG, etc) mostly hooking up through ULPI. */ - musb->isr = generic_interrupt; - status = musb_platform_init(musb, plat->board_data); + status = musb_platform_init(musb); if (status < 0) - goto fail2; + goto fail1; if (!musb->isr) { status = -ENODEV; - goto fail3; + goto fail2; } if (!musb->xceiv->io_ops) { + musb->xceiv->io_dev = musb->controller; musb->xceiv->io_priv = musb->mregs; musb->xceiv->io_ops = &musb_ulpi_access; } -#ifndef CONFIG_MUSB_PIO_ONLY - if (use_dma && dev->dma_mask) { - struct dma_controller *c; + pm_runtime_get_sync(musb->controller); - c = dma_controller_create(musb, musb->mregs); - musb->dma_controller = c; - if (c) - (void) c->start(c); + if (use_dma && dev->dma_mask) { + musb->dma_controller = dma_controller_create(musb, musb->mregs); + if (IS_ERR(musb->dma_controller)) { + status = PTR_ERR(musb->dma_controller); + goto fail2_5; + } } -#endif - /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) - dev->dma_mask = NULL; /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); musb_generic_disable(musb); + /* Init IRQ workqueue before request_irq */ + INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_WORK(&musb->recover_work, musb_recover_work); + INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); + INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); + /* setup musb parts of the core (especially endpoints) */ status = musb_core_init(plat->config->multipoint ? MUSB_CONTROLLER_MHDRC @@ -2070,12 +1956,7 @@ bad_config: if (status < 0) goto fail3; -#ifdef CONFIG_USB_MUSB_OTG setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); -#endif - - /* Init IRQ workqueue before request_irq */ - INIT_WORK(&musb->irq_work, musb_irq_work); /* attach to the IRQ */ if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { @@ -2084,7 +1965,7 @@ bad_config: goto fail3; } musb->nIrq = nIrq; -/* FIXME this handles wakeup irqs wrong */ + /* FIXME this handles wakeup irqs wrong */ if (enable_irq_wake(nIrq) == 0) { musb->irq_wake = 1; device_init_wakeup(dev, 1); @@ -2092,56 +1973,50 @@ bad_config: musb->irq_wake = 0; } - /* host side needs more setup */ - if (is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - otg_set_host(musb->xceiv, &hcd->self); - - if (is_otg_enabled(musb)) - hcd->self.otg_port = 1; - musb->xceiv->host = &hcd->self; - hcd->power_budget = 2 * (plat->power ? : 250); - - /* program PHY to use external vBus if required */ - if (plat->extvbus) { - u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); - busctl |= MUSB_ULPI_USE_EXTVBUS; - musb_write_ulpi_buscontrol(musb->mregs, busctl); - } + /* program PHY to use external vBus if required */ + if (plat->extvbus) { + u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); + busctl |= MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); } - /* For the host-only role, we can activate right away. - * (We expect the ID pin to be forcibly grounded!!) - * Otherwise, wait till the gadget driver hooks up. - */ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { + if (musb->xceiv->otg->default_a) { MUSB_HST_MODE(musb); - musb->xceiv->default_a = 1; musb->xceiv->state = OTG_STATE_A_IDLE; - - status = usb_add_hcd(musb_to_hcd(musb), -1, 0); - - DBG(1, "%s mode, status %d, devctl %02x %c\n", - "HOST", status, - musb_readb(musb->mregs, MUSB_DEVCTL), - (musb_readb(musb->mregs, MUSB_DEVCTL) - & MUSB_DEVCTL_BDEVICE - ? 'B' : 'A')); - - } else /* peripheral is enabled */ { + } else { MUSB_DEV_MODE(musb); - musb->xceiv->default_a = 0; musb->xceiv->state = OTG_STATE_B_IDLE; + } + switch (musb->port_mode) { + case MUSB_PORT_MODE_HOST: + status = musb_host_setup(musb, plat->power); + if (status < 0) + goto fail3; + status = musb_platform_set_mode(musb, MUSB_HOST); + break; + case MUSB_PORT_MODE_GADGET: status = musb_gadget_setup(musb); - - DBG(1, "%s mode, status %d, dev%02x\n", - is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", - status, - musb_readb(musb->mregs, MUSB_DEVCTL)); - + if (status < 0) + goto fail3; + status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); + break; + case MUSB_PORT_MODE_DUAL_ROLE: + status = musb_host_setup(musb, plat->power); + if (status < 0) + goto fail3; + status = musb_gadget_setup(musb); + if (status) { + musb_host_cleanup(musb); + goto fail3; + } + status = musb_platform_set_mode(musb, MUSB_OTG); + break; + default: + dev_err(dev, "unsupported port mode %d\n", musb->port_mode); + break; } + if (status < 0) goto fail3; @@ -2149,23 +2024,11 @@ bad_config: if (status < 0) goto fail4; -#ifdef CONFIG_SYSFS status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group); if (status) goto fail5; -#endif - dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", - ({char *s; - switch (musb->board_mode) { - case MUSB_HOST: s = "Host"; break; - case MUSB_PERIPHERAL: s = "Peripheral"; break; - default: s = "OTG"; break; - }; s; }), - ctrl, - (is_dma_capable() && musb->dma_controller) - ? "DMA" : "PIO", - musb->nIrq); + pm_runtime_put(musb->controller); return 0; @@ -2173,21 +2036,26 @@ fail5: musb_exit_debugfs(musb); fail4: - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); - else - musb_gadget_cleanup(musb); + musb_gadget_cleanup(musb); + musb_host_cleanup(musb); fail3: + cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->finish_resume_work); + cancel_delayed_work_sync(&musb->deassert_reset_work); + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); +fail2_5: + pm_runtime_put_sync(musb->controller); + +fail2: if (musb->irq_wake) device_init_wakeup(dev, 0); musb_platform_exit(musb); -fail2: - if (musb->clock) - clk_put(musb->clock); - fail1: + pm_runtime_disable(musb->controller); dev_err(musb->controller, "musb_init_controller failed with status %d\n", status); @@ -2204,44 +2072,28 @@ fail0: /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just * bridge to a platform device; this driver then suffices. */ - -#ifndef CONFIG_MUSB_PIO_ONLY -static u64 *orig_dma_mask; -#endif - -static int __init musb_probe(struct platform_device *pdev) +static int musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - int irq = platform_get_irq(pdev, 0); - int status; + int irq = platform_get_irq_byname(pdev, "mc"); struct resource *iomem; void __iomem *base; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq == 0) + if (!iomem || irq <= 0) return -ENODEV; - base = ioremap(iomem->start, resource_size(iomem)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, iomem); + if (IS_ERR(base)) + return PTR_ERR(base); -#ifndef CONFIG_MUSB_PIO_ONLY - /* clobbered by use_dma=n */ - orig_dma_mask = dev->dma_mask; -#endif - status = musb_init_controller(dev, irq, base); - if (status < 0) - iounmap(base); - - return status; + return musb_init_controller(dev, irq, base); } -static int __exit musb_remove(struct platform_device *pdev) +static int musb_remove(struct platform_device *pdev) { - struct musb *musb = dev_to_musb(&pdev->dev); - void __iomem *ctrl_base = musb->ctrl_base; + struct device *dev = &pdev->dev; + struct musb *musb = dev_to_musb(dev); /* this gets called on rmmod. * - Host mode: host may still be active @@ -2251,164 +2103,180 @@ static int __exit musb_remove(struct platform_device *pdev) musb_exit_debugfs(musb); musb_shutdown(pdev); + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); + + cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->finish_resume_work); + cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); - iounmap(ctrl_base); - device_init_wakeup(&pdev->dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY - pdev->dev.dma_mask = orig_dma_mask; -#endif + device_init_wakeup(dev, 0); return 0; } #ifdef CONFIG_PM -static struct musb_context_registers musb_context; - -void musb_save_context(struct musb *musb) +static void musb_save_context(struct musb *musb) { int i; void __iomem *musb_base = musb->mregs; void __iomem *epio; - if (is_host_enabled(musb)) { - musb_context.frame = musb_readw(musb_base, MUSB_FRAME); - musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE); - musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs); - } - musb_context.power = musb_readb(musb_base, MUSB_POWER); - musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); - musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); - musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); - musb_context.index = musb_readb(musb_base, MUSB_INDEX); - musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL); + musb->context.frame = musb_readw(musb_base, MUSB_FRAME); + musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); + musb->context.power = musb_readb(musb_base, MUSB_POWER); + musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); + musb->context.index = musb_readb(musb_base, MUSB_INDEX); + musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); for (i = 0; i < musb->config->num_eps; ++i) { - epio = musb->endpoints[i].regs; - musb_context.index_regs[i].txmaxp = + struct musb_hw_ep *hw_ep; + + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + + musb_writeb(musb_base, MUSB_INDEX, i); + musb->context.index_regs[i].txmaxp = musb_readw(epio, MUSB_TXMAXP); - musb_context.index_regs[i].txcsr = + musb->context.index_regs[i].txcsr = musb_readw(epio, MUSB_TXCSR); - musb_context.index_regs[i].rxmaxp = + musb->context.index_regs[i].rxmaxp = musb_readw(epio, MUSB_RXMAXP); - musb_context.index_regs[i].rxcsr = + musb->context.index_regs[i].rxcsr = musb_readw(epio, MUSB_RXCSR); if (musb->dyn_fifo) { - musb_context.index_regs[i].txfifoadd = + musb->context.index_regs[i].txfifoadd = musb_read_txfifoadd(musb_base); - musb_context.index_regs[i].rxfifoadd = + musb->context.index_regs[i].rxfifoadd = musb_read_rxfifoadd(musb_base); - musb_context.index_regs[i].txfifosz = + musb->context.index_regs[i].txfifosz = musb_read_txfifosz(musb_base); - musb_context.index_regs[i].rxfifosz = + musb->context.index_regs[i].rxfifosz = musb_read_rxfifosz(musb_base); } - if (is_host_enabled(musb)) { - musb_context.index_regs[i].txtype = - musb_readb(epio, MUSB_TXTYPE); - musb_context.index_regs[i].txinterval = - musb_readb(epio, MUSB_TXINTERVAL); - musb_context.index_regs[i].rxtype = - musb_readb(epio, MUSB_RXTYPE); - musb_context.index_regs[i].rxinterval = - musb_readb(epio, MUSB_RXINTERVAL); - - musb_context.index_regs[i].txfunaddr = - musb_read_txfunaddr(musb_base, i); - musb_context.index_regs[i].txhubaddr = - musb_read_txhubaddr(musb_base, i); - musb_context.index_regs[i].txhubport = - musb_read_txhubport(musb_base, i); - - musb_context.index_regs[i].rxfunaddr = - musb_read_rxfunaddr(musb_base, i); - musb_context.index_regs[i].rxhubaddr = - musb_read_rxhubaddr(musb_base, i); - musb_context.index_regs[i].rxhubport = - musb_read_rxhubport(musb_base, i); - } - } - musb_platform_save_context(musb, &musb_context); + musb->context.index_regs[i].txtype = + musb_readb(epio, MUSB_TXTYPE); + musb->context.index_regs[i].txinterval = + musb_readb(epio, MUSB_TXINTERVAL); + musb->context.index_regs[i].rxtype = + musb_readb(epio, MUSB_RXTYPE); + musb->context.index_regs[i].rxinterval = + musb_readb(epio, MUSB_RXINTERVAL); + + musb->context.index_regs[i].txfunaddr = + musb_read_txfunaddr(musb_base, i); + musb->context.index_regs[i].txhubaddr = + musb_read_txhubaddr(musb_base, i); + musb->context.index_regs[i].txhubport = + musb_read_txhubport(musb_base, i); + + musb->context.index_regs[i].rxfunaddr = + musb_read_rxfunaddr(musb_base, i); + musb->context.index_regs[i].rxhubaddr = + musb_read_rxhubaddr(musb_base, i); + musb->context.index_regs[i].rxhubport = + musb_read_rxhubport(musb_base, i); + } } -void musb_restore_context(struct musb *musb) +static void musb_restore_context(struct musb *musb) { int i; void __iomem *musb_base = musb->mregs; void __iomem *ep_target_regs; void __iomem *epio; + u8 power; - musb_platform_restore_context(musb, &musb_context); + musb_writew(musb_base, MUSB_FRAME, musb->context.frame); + musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); + musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - if (is_host_enabled(musb)) { - musb_writew(musb_base, MUSB_FRAME, musb_context.frame); - musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode); - musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl); - } - musb_writeb(musb_base, MUSB_POWER, musb_context.power); - musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe); - musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe); - musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe); - musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl); + /* Don't affect SUSPENDM/RESUME bits in POWER reg */ + power = musb_readb(musb_base, MUSB_POWER); + power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; + musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); + power |= musb->context.power; + musb_writeb(musb_base, MUSB_POWER, power); + + musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); + musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); + musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { - epio = musb->endpoints[i].regs; + struct musb_hw_ep *hw_ep; + + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + + musb_writeb(musb_base, MUSB_INDEX, i); musb_writew(epio, MUSB_TXMAXP, - musb_context.index_regs[i].txmaxp); + musb->context.index_regs[i].txmaxp); musb_writew(epio, MUSB_TXCSR, - musb_context.index_regs[i].txcsr); + musb->context.index_regs[i].txcsr); musb_writew(epio, MUSB_RXMAXP, - musb_context.index_regs[i].rxmaxp); + musb->context.index_regs[i].rxmaxp); musb_writew(epio, MUSB_RXCSR, - musb_context.index_regs[i].rxcsr); + musb->context.index_regs[i].rxcsr); if (musb->dyn_fifo) { musb_write_txfifosz(musb_base, - musb_context.index_regs[i].txfifosz); + musb->context.index_regs[i].txfifosz); musb_write_rxfifosz(musb_base, - musb_context.index_regs[i].rxfifosz); + musb->context.index_regs[i].rxfifosz); musb_write_txfifoadd(musb_base, - musb_context.index_regs[i].txfifoadd); + musb->context.index_regs[i].txfifoadd); musb_write_rxfifoadd(musb_base, - musb_context.index_regs[i].rxfifoadd); + musb->context.index_regs[i].rxfifoadd); } - if (is_host_enabled(musb)) { - musb_writeb(epio, MUSB_TXTYPE, - musb_context.index_regs[i].txtype); - musb_writeb(epio, MUSB_TXINTERVAL, - musb_context.index_regs[i].txinterval); - musb_writeb(epio, MUSB_RXTYPE, - musb_context.index_regs[i].rxtype); - musb_writeb(epio, MUSB_RXINTERVAL, - - musb_context.index_regs[i].rxinterval); - musb_write_txfunaddr(musb_base, i, - musb_context.index_regs[i].txfunaddr); - musb_write_txhubaddr(musb_base, i, - musb_context.index_regs[i].txhubaddr); - musb_write_txhubport(musb_base, i, - musb_context.index_regs[i].txhubport); - - ep_target_regs = - musb_read_target_reg_base(i, musb_base); - - musb_write_rxfunaddr(ep_target_regs, - musb_context.index_regs[i].rxfunaddr); - musb_write_rxhubaddr(ep_target_regs, - musb_context.index_regs[i].rxhubaddr); - musb_write_rxhubport(ep_target_regs, - musb_context.index_regs[i].rxhubport); - } + musb_writeb(epio, MUSB_TXTYPE, + musb->context.index_regs[i].txtype); + musb_writeb(epio, MUSB_TXINTERVAL, + musb->context.index_regs[i].txinterval); + musb_writeb(epio, MUSB_RXTYPE, + musb->context.index_regs[i].rxtype); + musb_writeb(epio, MUSB_RXINTERVAL, + + musb->context.index_regs[i].rxinterval); + musb_write_txfunaddr(musb_base, i, + musb->context.index_regs[i].txfunaddr); + musb_write_txhubaddr(musb_base, i, + musb->context.index_regs[i].txhubaddr); + musb_write_txhubport(musb_base, i, + musb->context.index_regs[i].txhubport); + + ep_target_regs = + musb_read_target_reg_base(i, musb_base); + + musb_write_rxfunaddr(ep_target_regs, + musb->context.index_regs[i].rxfunaddr); + musb_write_rxhubaddr(ep_target_regs, + musb->context.index_regs[i].rxhubaddr); + musb_write_rxhubport(ep_target_regs, + musb->context.index_regs[i].rxhubport); } + musb_writeb(musb_base, MUSB_INDEX, musb->context.index); } static int musb_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); + struct musb *musb = dev_to_musb(dev); unsigned long flags; - struct musb *musb = dev_to_musb(&pdev->dev); spin_lock_irqsave(&musb->lock, flags); @@ -2424,40 +2292,64 @@ static int musb_suspend(struct device *dev) musb_save_context(musb); - 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; } static int musb_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct musb *musb = dev_to_musb(&pdev->dev); + struct musb *musb = dev_to_musb(dev); - if (musb->clock) { - if (musb->set_clock) - musb->set_clock(musb->clock, 1); - else - clk_enable(musb->clock); - } + /* + * For static cmos like DaVinci, register values were preserved + * unless for some reason the whole soc powered down or the USB + * module got reset through the PSC (vs just being disabled). + * + * For the DSPS glue layer though, a full register restore has to + * be done. As it shouldn't harm other platforms, we do it + * unconditionally. + */ musb_restore_context(musb); - /* for static cmos like DaVinci, register values were preserved - * unless for some reason the whole soc powered down or the USB - * module got reset through the PSC (vs just being disabled). + return 0; +} + +static int musb_runtime_suspend(struct device *dev) +{ + struct musb *musb = dev_to_musb(dev); + + musb_save_context(musb); + + return 0; +} + +static int musb_runtime_resume(struct device *dev) +{ + struct musb *musb = dev_to_musb(dev); + static int first = 1; + + /* + * When pm_runtime_get_sync called for the first time in driver + * init, some of the structure is still not initialized which is + * used in restore function. But clock needs to be + * enabled before any register access, so + * pm_runtime_get_sync has to be called. + * Also context restore without save does not make + * any sense */ + if (!first) + musb_restore_context(musb); + first = 0; + return 0; } static const struct dev_pm_ops musb_dev_pm_ops = { .suspend = musb_suspend, .resume_noirq = musb_resume_noirq, + .runtime_suspend = musb_runtime_suspend, + .runtime_resume = musb_runtime_resume, }; #define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) @@ -2472,51 +2364,9 @@ static struct platform_driver musb_driver = { .owner = THIS_MODULE, .pm = MUSB_DEV_PM_OPS, }, - .remove = __exit_p(musb_remove), + .probe = musb_probe, + .remove = musb_remove, .shutdown = musb_shutdown, }; -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (usb_disabled()) - return 0; -#endif - - pr_info("%s: version " MUSB_VERSION ", " -#ifdef CONFIG_MUSB_PIO_ONLY - "pio" -#elif defined(CONFIG_USB_TI_CPPI_DMA) - "cppi-dma" -#elif defined(CONFIG_USB_INVENTRA_DMA) - "musb-dma" -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - "tusb-omap-dma" -#else - "?dma?" -#endif - ", " -#ifdef CONFIG_USB_MUSB_OTG - "otg (peripheral+host)" -#elif defined(CONFIG_USB_GADGET_MUSB_HDRC) - "peripheral" -#elif defined(CONFIG_USB_MUSB_HDRC_HCD) - "host" -#endif - ", debug=%d\n", - musb_driver_name, musb_debug); - return platform_driver_probe(&musb_driver, musb_probe); -} - -/* make us init after usbcore and i2c (transceivers, regulators, etc) - * and before usb gadget and host-side drivers start to register - */ -fs_initcall(musb_init); - -static void __exit musb_cleanup(void) -{ - platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); +module_platform_driver(musb_driver); |
