Commit 6e0abdbc authored by Juha Yrjola's avatar Juha Yrjola

Merge branch 'master' of /home/git/linux-omap-2.6

parents 40cedbdb 6c4a8512
......@@ -508,7 +508,6 @@ void musb_g_tx(struct musb *pThis, u8 bEnd)
if (!pRequest) {
DBG(4, "%s idle now\n",
pEnd->end_point.name);
musb_platform_try_idle(pThis);
break;
}
}
......@@ -974,8 +973,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
pEnd->dma ? "dma, " : "",
pEnd->wPacketSize);
pThis->status |= MUSB_VBUS_STATUS_CHG;
schedule_work(&pThis->irq_work);
sysfs_notify(&pThis->controller->kobj, NULL, "cable");
fail:
spin_unlock_irqrestore(&pThis->Lock, flags);
......@@ -1018,8 +1016,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
/* abort all pending DMA and requests */
nuke(pEnd, -ESHUTDOWN);
pThis->status |= MUSB_VBUS_STATUS_CHG; /* FIXME not for ep_disable!! */
schedule_work(&pThis->irq_work);
sysfs_notify(&pThis->controller->kobj, NULL, "cable");
spin_unlock_irqrestore(&(pThis->Lock), flags);
......@@ -1664,6 +1661,9 @@ int __devinit musb_gadget_setup(struct musb *pThis)
musb_g_init_endpoints(pThis);
pThis->is_active = 0;
musb_platform_try_idle(pThis);
status = device_register(&pThis->g.dev);
if (status != 0)
the_gadget = NULL;
......@@ -1746,6 +1746,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
*/
pThis->xceiv.gadget = &pThis->g;
pThis->xceiv.state = OTG_STATE_B_IDLE;
pThis->is_active = 1;
/* FIXME this ignores the softconnect flag. Drivers are
* allowed hold the peripheral inactive until for example
......@@ -1857,6 +1858,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
musb->pGadgetDriver = NULL;
musb->g.dev.driver = NULL;
musb->is_active = 0;
musb_platform_try_idle(musb);
} else
retval = -EINVAL;
......@@ -1944,6 +1946,8 @@ void musb_g_disconnect(struct musb *pThis)
case OTG_STATE_B_SRP_INIT:
break;
}
pThis->is_active = 0;
}
void musb_g_reset(struct musb *pThis)
......@@ -1977,6 +1981,7 @@ __acquires(pThis->Lock)
? USB_SPEED_HIGH : USB_SPEED_FULL;
/* start in USB_STATE_DEFAULT */
pThis->is_active = 1;
MUSB_DEV_MODE(pThis);
pThis->bAddress = 0;
pThis->ep0_state = MGC_END0_STAGE_SETUP;
......
......@@ -754,11 +754,11 @@ static int musb_proc_read(char *page, char **start,
}
}
musb_platform_try_idle(pThis);
spin_unlock_irqrestore(&pThis->Lock, flags);
*eof = 1;
musb_platform_try_idle(pThis);
return (buffer - page) - off;
}
......
......@@ -197,9 +197,6 @@ enum musb_g_ep0_state {
MGC_END0_STAGE_ACKWAIT, /* after zlp, before statusin */
} __attribute__ ((packed));
/* driver and cable VBUS status states for musb_irq_work */
#define MUSB_VBUS_STATUS_CHG (1 << 0)
/* failure codes */
#define MUSB_ERR_WAITING 1
#define MUSB_ERR_VBUS -1
......@@ -395,7 +392,6 @@ struct musb {
spinlock_t Lock;
struct clk *clock;
irqreturn_t (*isr)(int, void *, struct pt_regs *);
struct work_struct irq_work;
#ifdef CONFIG_USB_MUSB_HDRC_HCD
......@@ -450,10 +446,11 @@ struct musb {
u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state);
u8 status; /* status change flags for musb_irq_work */
s8 bFailCode; /* one of MUSB_ERR_* failure code */
/* active means connected and not suspended */
unsigned is_active:1;
unsigned bIsMultipoint:1;
unsigned bIsDevice:1;
unsigned bIsHost:1;
......
......@@ -212,6 +212,7 @@ static void otg_timeout(unsigned long ptr)
default:
WARN("timeout in state %d, now what?\n", pMachine->bState);
}
musb_platform_try_idle(musb);
spin_unlock_irqrestore(&musb->Lock, flags);
}
......
......@@ -384,6 +384,7 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
if (bIntrUSB & MGC_M_INTR_RESUME) {
handled = IRQ_HANDLED;
DBG(3, "RESUME\n");
pThis->is_active = 1;
if (devctl & MGC_M_DEVCTL_HM) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
......@@ -458,6 +459,7 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
if (bIntrUSB & MGC_M_INTR_CONNECT) {
handled = IRQ_HANDLED;
pThis->is_active = 1;
pThis->bEnd0Stage = MGC_END0_START;
......@@ -527,6 +529,8 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
otg_input_changed(pThis, devctl, TRUE, FALSE,
(power & MGC_M_POWER_SUSPENDM)
? TRUE : FALSE);
sysfs_notify(&pThis->controller->kobj, NULL, "cable");
}
handled = IRQ_HANDLED;
......@@ -598,6 +602,7 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
DBG(1, "DISCONNECT as %s, devctl %02x\n",
MUSB_MODE(pThis), devctl);
handled = IRQ_HANDLED;
pThis->is_active = 0;
/* need to check it against pThis, because devctl is going
* to report ID low as soon as the device gets disconnected
......@@ -609,6 +614,8 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
/* REVISIT all OTG state machine transitions */
otg_input_changed_X(pThis, FALSE, FALSE);
sysfs_notify(&pThis->controller->kobj, NULL, "cable");
}
if (bIntrUSB & MGC_M_INTR_SUSPEND) {
......@@ -618,9 +625,15 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
/* peripheral suspend, may trigger HNP */
if (!(devctl & MGC_M_DEVCTL_HM)) {
musb_g_suspend(pThis);
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
pThis->is_active = is_otg_enabled(pThis)
&& pThis->xceiv.gadget->b_hnp_enable;
#else
pThis->is_active = 0;
#endif
otg_input_changed(pThis, devctl, FALSE, FALSE, TRUE);
musb_platform_try_idle(pThis);
}
} else
pThis->is_active = 0;
}
return handled;
......@@ -1416,7 +1429,6 @@ musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
v2 = "connected";
else
v2 = "disconnected";
musb_platform_try_idle(musb);
#else
/* NOTE: board-specific issues, like too-big capacitors keeping
* VBUS high for a long time after power has been removed, can
......@@ -1440,6 +1452,7 @@ musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
} else /* VBUS level below A-Valid */
v2 = "disconnected";
#endif
musb_platform_try_idle(musb);
spin_unlock_irqrestore(&musb->Lock, flags);
return sprintf(buf, "%s%s\n", v1, v2);
......@@ -1448,25 +1461,6 @@ static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL);
#endif
static void musb_irq_work(void *data)
{
struct musb *musb = (struct musb *)data;
unsigned long flags;
u8 event = 0;
spin_lock_irqsave(&musb->Lock, flags);
if (musb->status & MUSB_VBUS_STATUS_CHG) {
musb->status &= ~MUSB_VBUS_STATUS_CHG;
event = 1;
}
musb_platform_try_idle(musb);
spin_unlock_irqrestore(&musb->Lock, flags);
#ifdef CONFIG_SYSFS
if (event)
sysfs_notify(&musb->controller->kobj, NULL, "cable");
#endif
}
/* --------------------------------------------------------------------------
* Init support
*/
......@@ -1654,6 +1648,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail2;
}
pThis->nIrq = nIrq;
device_init_wakeup(dev, 1);
pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
musb_driver_name,
......@@ -1668,11 +1663,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
? "DMA" : "PIO",
pThis->nIrq);
// FIXME:
// - convert to the HCD framework
// - if (board_mode == MUSB_OTG) do startup with peripheral
// - ... involves refcounting updates
#ifdef CONFIG_USB_MUSB_HDRC_HCD
/* host side needs more setup, except for no-host modes */
if (pThis->board_mode != MUSB_PERIPHERAL) {
......@@ -1737,11 +1727,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_debug_create("driver/musb_hdrc", pThis);
else {
fail:
device_init_wakeup(dev, 0);
musb_free(pThis);
return status;
}
INIT_WORK(&pThis->irq_work, musb_irq_work, pThis);
#ifdef CONFIG_SYSFS
device_create_file(dev, &dev_attr_mode);
device_create_file(dev, &dev_attr_cable);
......@@ -1796,15 +1786,12 @@ static int __devexit musb_remove(struct platform_device *pdev)
usb_remove_hcd(musb_to_hcd(musb));
#endif
musb_free(musb);
device_init_wakeup(&pdev->dev, 0);
return 0;
}
#ifdef CONFIG_PM
/* REVISIT when power savings matter on DaVinci, look at turning
* off its phy clock during system suspend iff wakeup is disabled
*/
static int musb_suspend(struct platform_device *pdev, pm_message_t message)
{
unsigned long flags;
......@@ -1821,11 +1808,10 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
*/
} else if (is_host_active(musb)) {
/* we know all the children are suspended; sometimes
* they will even be wakeup-enabled
* they will even be wakeup-enabled.
*/
}
musb_platform_try_idle(musb);
clk_disable(musb->clock);
spin_unlock_irqrestore(&musb->Lock, flags);
return 0;
......
......@@ -145,6 +145,10 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
/*
* Enables TUSB6010 to use VBUS as power source in peripheral mode.
* In host mode, a local battery must power the TUSB chip as well as
* (through the charge pump) VBUS. For OTG peripherals, the battery
* must power the chip until it enters a confguration that's allowed
* to draw enough current (call it 100mA).
*/
static inline void tusb_enable_vbus_charge(struct musb *musb)
{
......@@ -159,21 +163,29 @@ static inline void tusb_enable_vbus_charge(struct musb *musb)
}
/*
* Idles TUSB6010 until next wake-up event interrupt. Use all wake-up
* events for now. Note that TUSB will not respond if NOR chip select
* wake-up event is masked. Also note that any access to TUSB will wake
* it up from idle.
* Idle TUSB6010 until next wake-up event; NOR access always wakes.
* Other code ensures that we idle unless we're connected _and_ the
* USB link is not suspended ... and tells us the relevant wakeup
* events.
*/
static inline void tusb_allow_idle(struct musb *musb, int wakeup_mask)
static inline void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
{
void __iomem *base = musb->ctrl_base;
u32 reg;
musb_writel(base, TUSB_PRCM_WAKEUP_MASK, wakeup_mask);
wakeup_enables |= TUSB_PRCM_WNORCS;
musb_writel(base, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
reg = musb_readl(base, TUSB_PRCM_MNGMT);
reg &= ~TUSB_PRCM_MNGMT_CPEN_MASK;
reg |= TUSB_PRCM_MNGMT_SUSPEND_MASK;
reg &= ~( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN
| TUSB_PRCM_MNGMT_15_SW_EN
| TUSB_PRCM_MNGMT_33_SW_EN );
reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN
| TUSB_PRCM_MNGMT_PM_IDLE
| TUSB_PRCM_MNGMT_DEV_IDLE;
musb_writel(base, TUSB_PRCM_MNGMT, reg);
DBG(2, "idle, wake on %02x\n", wakeup_enables);
}
/*
......@@ -206,36 +218,117 @@ int musb_platform_get_vbus_status(struct musb *musb)
return ret;
}
static struct timer_list musb_idle_timer;
static void musb_do_idle(unsigned long _musb)
{
struct musb *musb = (void *)_musb;
unsigned long flags;
spin_lock_irqsave(&musb->Lock, flags);
if (!musb->is_active) {
u32 wakeups;
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
if (is_peripheral_enabled(musb) && !musb->pGadgetDriver)
wakeups = 0;
else {
wakeups = TUSB_PRCM_WHOSTDISCON
| TUSB_PRCM_WBUS
| TUSB_PRCM_WVBUS;
if (is_otg_enabled(musb))
wakeups |= TUSB_PRCM_WLD;
}
#else
wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS;
#endif
tusb_allow_idle(musb, wakeups);
}
spin_unlock_irqrestore(&musb->Lock, flags);
}
/*
* Sets the TUSB6010 idles mode in peripheral mode depending on the
* gadget driver state and cable VBUS status. Needs to be called as
* the last function everywhere where there is register access to
* TUSB6010 because of the NOR flash wake-up capability.
* Caller must take care of locking.
* Maybe put TUSB6010 into idle mode mode depending on USB link status,
* like "disconnected" or "suspended". We'll be woken out of it by
* connect, resume, or disconnect.
*
* Needs to be called as the last function everywhere where there is
* register access to TUSB6010 because of NOR flash wake-up.
* Caller should own controller spinlock.
*
* Delay because peripheral enables D+ pullup 3msec after SE0, and
* we don't want to treat that full speed J as a wakeup event.
* ... peripherals must draw only suspend current after 10 msec.
*/
void musb_platform_try_idle(struct musb *musb)
{
u32 wakeup_mask = 0;
if (musb->is_active)
del_timer(&musb_idle_timer);
else
mod_timer(&musb_idle_timer, jiffies +
(is_host_active(musb) ? msecs_to_jiffies(3) : 0));
}
/* Suspend with only NOR flash wake-up event enabled if no
* gadget driver is active.
*/
if (musb->xceiv.state == OTG_STATE_UNDEFINED) {
wakeup_mask = 0xffff & ~TUSB_PRCM_WNORCS;
tusb_allow_idle(musb, wakeup_mask);
return;
static inline void
tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *base)
{
u32 otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
/* ID pin */
if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
int default_a;
default_a = is_host_enabled(musb)
&& (otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
if (default_a != musb->xceiv.default_a) {
musb->xceiv.default_a = default_a;
if (musb->xceiv.default_a) {
musb->xceiv.state = OTG_STATE_A_IDLE;
/* REVISIT start the session? */
} else
musb->xceiv.state = OTG_STATE_B_IDLE;
DBG(1, "Default-%c\n", musb->xceiv.default_a
? 'A' : 'B');
musb->is_active = 1;
}
}
/* Use VBUS as power source if available, otherwise suspend
* with all wake-up events enabled.
*
* FIXME only B-device state machine ever _consumes_ VBUS.
/* VBUS state change */
if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
/* no vbus ~= disconnect */
if (!is_host_enabled(musb) || !musb->xceiv.default_a) {
/* REVISIT in B-Default state machine, use VBUS power
* for the USB link when (a) non-OTG, since 100 mA is
* always available; or (b) OTG after SET_CONFIGURATION
* enabling 100+ (?) mA draw.
*/
if (musb_platform_get_vbus_status(musb))
tusb_enable_vbus_charge(musb);
else {
wakeup_mask = TUSB_PRCM_WLD;
tusb_allow_idle(musb, wakeup_mask);
/* REVISIT use the b_sess_valid comparator, not
* lowpower one; TUSB_DEV_OTG_STAT_SESS_VALID ?
*/
if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE) {
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 1;
/* REVISIT start the session? */
} else {
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->is_active = 0;
}
DBG(1, "%s\n", musb->is_active
? "b_peripheral" : "b_idle");
sysfs_notify(&musb->controller->kobj, NULL, "cable");
}
}
/* OTG timer expiration */
if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
DBG(3, "tusb: OTG timer expired\n");
musb_writel(base, TUSB_DEV_OTG_TIMER,
musb_readl(base, TUSB_DEV_OTG_TIMER)
| TUSB_DEV_OTG_TIMER_ENABLE);
}
}
......@@ -244,88 +337,43 @@ irqreturn_t tusb_interrupt(int irq, void *__hci, struct pt_regs *r)
struct musb *musb = __hci;
void __iomem *base = musb->ctrl_base;
unsigned long flags;
u32 dma_src, int_src, otg_stat, musb_src = 0;
u32 dma_src = 0, int_src;
spin_lock_irqsave(&musb->Lock, flags);
dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
int_src = musb_readl(base, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS;
otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
if (int_src & TUSB_INT_SRC_TXRX_DMA_DONE)
dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
DBG(3, "TUSB interrupt dma: %08x int: %08x otg: %08x\n",
dma_src, int_src, otg_stat);
DBG(3, "TUSB interrupt dma: %08x int: %08x\n", dma_src, int_src);
musb->int_usb = 0;
musb->int_rx = 0;
musb->int_tx = 0;
musb->int_regs = r;
if (otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS) {
/* ID pin is up. Either A-plug was removed or TUSB6010
* is in peripheral mode */
/* Still in pheripheral mode? */
if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
DBG(3, "tusb: Status change\n");
//goto out;
}
}
/* Peripheral suspend. Cable may be disconnected, try to idle */
if (int_src & TUSB_INT_SRC_USB_IP_SUSPEND) {
musb->status |= MUSB_VBUS_STATUS_CHG;
schedule_work(&musb->irq_work);
}
/* Connect and disconnect for host mode */
if (int_src & TUSB_INT_SRC_USB_IP_CONN) {
DBG(3, "tusb: Connected\n");
}
else if (int_src & TUSB_INT_SRC_USB_IP_DISCON) {
DBG(3, "tusb: Disconnected\n");
}
/* VBUS state change */
if ((int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG)
|| (int_src & TUSB_INT_SRC_USB_IP_VBUS_ERR)) {
musb->status |= MUSB_VBUS_STATUS_CHG;
schedule_work(&musb->irq_work);
/* Acknowledge wake-up source interrupts */
if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
u32 reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
#if 0
DBG(3, "tusb: VBUS changed. VBUS state %d\n",
(otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE) ? 1 : 0);
if (!(otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE)
&& !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
/* VBUS went off and ID pin is down */
DBG(3, "tusb: No VBUS, starting session\n");
/* Start session again, VBUS will be enabled */
musb_writeb(musb_base, MGC_O_HDRC_DEVCTL,
MGC_M_DEVCTL_SESSION);
}
#endif
musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
if (reg & ~TUSB_PRCM_WNORCS) {
musb->is_active = 1;
sysfs_notify(&musb->controller->kobj, NULL, "cable");
}
/* ID pin change */
if (int_src & TUSB_INT_SRC_ID_STATUS_CHNG) {
DBG(3, "tusb: ID pin changed. State is %d\n",
(musb_readl(base, TUSB_DEV_OTG_STAT)
& TUSB_DEV_OTG_STAT_ID_STATUS)
? 1 : 0);
DBG(3, "wake %sactive %02x\n",
musb->is_active ? "" : "in", reg);
}
/* OTG timer expiration */
if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
DBG(3, "tusb: OTG timer expired\n");
musb_writel(base, TUSB_DEV_OTG_TIMER,
musb_readl(base, TUSB_DEV_OTG_TIMER) |
TUSB_DEV_OTG_TIMER_ENABLE);
}
/* OTG state change reports (annoyingly) not issued by Mentor core */
if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
| TUSB_INT_SRC_OTG_TIMEOUT
| TUSB_INT_SRC_ID_STATUS_CHNG))
tusb_otg_ints(musb, int_src, base);
/* TX dma callback must be handled here, RX dma callback is
* handled in tusb_omap_dma_cb.
*/
if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE) && dma_src) {
u32 real_dma_src = musb_readl(base, TUSB_DMA_INT_MASK);
real_dma_src = ~real_dma_src & dma_src;
if (tusb_dma_omap()) {
int tx_source = (real_dma_src & 0xffff);
......@@ -343,27 +391,25 @@ irqreturn_t tusb_interrupt(int irq, void *__hci, struct pt_regs *r)
/* EP interrupts. In OCP mode tusb6010 mirrors the MUSB * interrupts */
if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) {
musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
u32 musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
musb_writel(base, TUSB_USBIP_INT_CLEAR, musb_src);
musb->int_rx = (((musb_src >> 16) & 0xffff) << 1);
musb->int_tx = (musb_src & 0xffff);
}
musb->int_usb = (int_src & 0xff);
if (musb->int_usb || musb->int_rx || musb->int_tx)
musb_interrupt(musb);
} else
musb->int_rx = musb->int_tx = 0;
/* Acknowledge wake-up source interrupts */
if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
u32 reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
schedule_work(&musb->irq_work);
if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff)) {
musb->int_usb = (u8) int_src;
musb_interrupt(musb);
}
/* Acknowledge TUSB interrupts. Clear only non-reserved bits */
if (int_src)
musb_writel(base, TUSB_INT_SRC_CLEAR,
int_src & ~TUSB_INT_MASK_RESERVED_BITS);
musb->int_regs = NULL;
musb_platform_try_idle(musb);
spin_unlock_irqrestore(&musb->Lock, flags);
return IRQ_HANDLED;
......@@ -589,7 +635,7 @@ int __devinit musb_platform_init(struct musb *musb)
}
musb->isr = tusb_interrupt;
musb_platform_try_idle(musb);
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
return ret;
}
......
......@@ -103,9 +103,20 @@
#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
#define TUSB_PRCM_MNGMT_PM_CLEAR_MASK ((0x3 << 3) | (0x3 << 0))
#define TUSB_PRCM_MNGMT_CPEN_MASK ((1 << 9) | (0x3 << 3))
#define TUSB_PRCM_MNGMT_SUSPEND_MASK ((1 << 10) | (0x3 << 0))
#define TUSB_PRCM_MNGMT_PM_CLEAR_MASK \
( TUSB_PRCM_MNGMT_15_SW_EN \
| TUSB_PRCM_MNGMT_33_SW_EN \
| TUSB_PRCM_MNGMT_PM_IDLE \
| TUSB_PRCM_MNGMT_DEV_IDLE )
#define TUSB_PRCM_MNGMT_CPEN_MASK \
( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN \
| TUSB_PRCM_MNGMT_15_SW_EN \
| TUSB_PRCM_MNGMT_33_SW_EN )
#define TUSB_PRCM_MNGMT_SUSPEND_MASK \
( TUSB_PRCM_MNGMT_OTG_SESS_END_EN \
| TUSB_PRCM_MNGMT_PM_IDLE \
| TUSB_PRCM_MNGMT_DEV_IDLE )
/* Wake-up source clear and mask registers */
#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
......
......@@ -145,7 +145,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
struct musb_hw_ep *hw_ep = chdat->hw_ep;
void __iomem *ep_conf = hw_ep->conf;
void __iomem *musb_base = musb->pRegs;
unsigned long transferred, flags;
unsigned long remaining, flags;
int ch;
spin_lock_irqsave(&musb->Lock, flags);
......@@ -158,17 +158,19 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
if (ch_status != OMAP_DMA_BLOCK_IRQ)
printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status);
DBG(3, "ep%i %s dma callback ch: %i status: %x\n",
DBG(2, "ep%i %s dma callback ch: %i status: %x\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
ch, ch_status);
if (chdat->tx)
transferred = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
else
transferred = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
transferred = TUSB_EP_CONFIG_XFR_SIZE(transferred);
channel->dwActualLength = chdat->transfer_len - transferred;
remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
channel->dwActualLength = chdat->transfer_len - remaining;
DBG(2, "remaining %lu/%lu\n", remaining, chdat->transfer_len);
if (!dmareq_works())
tusb_omap_free_shared_dmareq(chdat);
......@@ -192,7 +194,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
u16 csr;
if (chdat->tx) {
DBG(3, "terminating short tx packet\n");
DBG(2, "terminating short tx packet\n");
MGC_SelectEnd(musb_base, chdat->epnum);
csr = musb_readw(hw_ep->regs, MGC_O_HDRC_TXCSR);
csr |= MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY;
......@@ -221,53 +223,27 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
s8 dmareq;
s8 sync_dev;
if (len < 32) {
DBG(3, "dma too short for ep%i %s dma_addr: %08x len: %u\n",
chdat->epnum, chdat->tx ? "tx" : "rx", dma_addr, len);
if (unlikely(dma_addr & 0x1))
return FALSE;
}
#if 0
if ((len % 32 != 0)) {
transfer_len = len / 32;
transfer_len *= 32;
DBG(3, "ep%i short %s dma: %lu/%lu %lu remainder\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
transfer_len, len, len - transfer_len);
} else
transfer_len = len;
#else
if ((len % 32) != 0) {
DBG(3, "bad dma length for ep%i %s dma_addr: %08x len: %u\n",
chdat->epnum, chdat->tx ? "tx" : "rx", dma_addr, len);
if (len < 32)
return FALSE;
} else
transfer_len = len;
#endif
if (dma_addr & 0x1) {
DBG(3, "unaligned dma address for ep%i %s: %08x\n",
chdat->epnum, chdat->tx ? "tx" : "rx", dma_addr);
if ((len % 32 != 0))
return FALSE;
}
else
transfer_len = len;
if (dmareq_works()) {
/* FIXME: Check for allocated dma ch */
ch = chdat->ch;
dmareq = chdat->dmareq;
sync_dev = chdat->sync_dev;
} else {
if (tusb_omap_use_shared_dmareq(chdat) != 0)
if (tusb_omap_use_shared_dmareq(chdat) != 0) {
DBG(3, "could not get dma for ep%i\n", chdat->epnum);
return FALSE;
/* FIXME: Check for allocated dma ch */
}
ch = tusb_dma->ch;
dmareq = tusb_dma->dmareq;
sync_dev = tusb_dma->sync_dev;
omap_set_dma_callback(ch, tusb_omap_dma_cb, channel);
}
......@@ -278,26 +254,32 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
chdat->dma_addr = (void __iomem *)dma_addr;
channel->bStatus = MGC_DMA_STATUS_BUSY;
DBG(3, "ep%i %s dma ch%i dma: %08x len: %u packet_sz: %i rndis: %d\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
ch, dma_addr, transfer_len, packet_sz, rndis_mode);
/* Since we're recycling dma areas, we need to clean or invalidate */
if (chdat->tx)
consistent_sync(phys_to_virt(dma_addr), len,
DMA_TO_DEVICE);
else
consistent_sync(phys_to_virt(dma_addr), len,
DMA_FROM_DEVICE);
if (chdat->tx) {
consistent_sync(phys_to_virt(dma_addr), len, DMA_TO_DEVICE);
} else
consistent_sync(phys_to_virt(dma_addr), len, DMA_FROM_DEVICE);
/* Use 16-bit transfer if dma_addr is not 32-bit aligned */
if ((dma_addr & 0x3) == 0) {
dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
dma_params.elem_count = 8; /* Elements in frame */
} else {
dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
dma_params.elem_count = 16; /* Elements in frame */
fifo = hw_ep->fifo_async;
}
dma_params.frame_count = transfer_len / 32; /* Burst sz frame */
DBG(2, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
ch, dma_addr, transfer_len, len, packet_sz);
/*
* Prepare omap DMA for transfer
*/
if (chdat->tx) {
dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
dma_params.elem_count = 8; /* 8x32-bit burst */
dma_params.frame_count = transfer_len / 32; /* Burst sz */
dma_params.src_amode = OMAP_DMA_AMODE_POST_INC;
dma_params.src_start = (unsigned long)dma_addr;
dma_params.src_ei = 0;
......@@ -312,13 +294,9 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
dma_params.sync_mode = OMAP_DMA_SYNC_FRAME;
dma_params.src_or_dst_synch = 0; /* Dest sync */
src_burst = OMAP_DMA_DATA_BURST_16;
dst_burst = OMAP_DMA_DATA_BURST_8;
src_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 read */
dst_burst = OMAP_DMA_DATA_BURST_8; /* 8x32 write */
} else {
dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
dma_params.elem_count = 8; /* 8x32-bit burst */
dma_params.frame_count = transfer_len / 32; /* Burst sz */
dma_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX;
dma_params.src_start = (unsigned long)fifo;
dma_params.src_ei = 1;
......@@ -337,25 +315,11 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
dst_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 write */
}
/* Use 16x16 transfer if addresses not 32-bit aligned */
if ((dma_params.src_start & 0x2) || (dma_params.dst_start & 0x2)) {
DBG(3, "using 16x16 async dma from 0x%08lx to 0x%08lx\n",
dma_params.src_start, dma_params.dst_start);
dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
dma_params.elem_count = 16; /* 16x16-bit burst */
fifo = hw_ep->fifo_async;
/* REVISIT: Check if 16x16 sync dma might also work */
if (chdat->tx)
dma_params.dst_start = (unsigned long) fifo;
else
dma_params.src_start =(unsigned long) fifo;
} else {
DBG(3, "ep%i %s using 16x32 sync dma from 0x%08lx to 0x%08lx\n",
DBG(2, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n",
chdat->epnum, chdat->tx ? "tx" : "rx",
(dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,
((dma_addr & 0x3) == 0) ? "sync" : "async",
dma_params.src_start, dma_params.dst_start);
}
omap_set_dma_params(ch, &dma_params);
omap_set_dma_src_burst_mode(ch, src_burst);
......
......@@ -58,11 +58,15 @@ static void musb_port_suspend(struct musb *musb, u8 bSuspend)
musb_writeb(pBase, MGC_O_HDRC_POWER,
power | MGC_M_POWER_SUSPENDM);
musb->port1_status |= USB_PORT_STAT_SUSPEND;
musb->is_active = is_otg_enabled(musb)
&& musb->xceiv.host->b_hnp_enable;
musb_platform_try_idle(musb);
} else if (power & MGC_M_POWER_SUSPENDM) {
DBG(3, "Root port resumed\n");
musb_writeb(pBase, MGC_O_HDRC_POWER,
power | MGC_M_POWER_RESUME);
musb->is_active = 1;
musb_writeb(pBase, MGC_O_HDRC_POWER, power);
musb->port1_status &= ~USB_PORT_STAT_SUSPEND;
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
......@@ -134,6 +138,7 @@ void musb_root_disconnect(struct musb *musb)
);
musb->port1_status |= USB_PORT_STAT_C_CONNECTION << 16;
usb_hcd_poll_rh_status(musb_to_hcd(musb));
musb->is_active = 0;
switch (musb->xceiv.state) {
case OTG_STATE_A_HOST:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment