power = musb_readb(musb->mregs, MUSB_POWER);
power &= ~MUSB_POWER_RESUME;
musb_dbg(musb, "root port resume stopped, power %02x", power);
musb_writeb(musb->mregs, MUSB_POWER, power);
/* * ISSUE: DaVinci (RTL 1.300) disconnects after * resume of high speed peripherals (but not full * speed ones).
*/
musb->is_active = 1;
musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME);
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb->hcd); /* NOTE: it might really be A_WAIT_BCON ... */
musb_set_state(musb, OTG_STATE_A_HOST);
/* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect * SE0 changing to connect (J) or wakeup (K) states.
*/
power = musb_readb(mbase, MUSB_POWER); if (do_suspend) { int retries = 10000;
if (power & MUSB_POWER_RESUME) return -EBUSY;
if (!(power & MUSB_POWER_SUSPENDM)) {
power |= MUSB_POWER_SUSPENDM;
musb_writeb(mbase, MUSB_POWER, power);
/* Needed for OPT A tests */
power = musb_readb(mbase, MUSB_POWER); while (power & MUSB_POWER_SUSPENDM) {
power = musb_readb(mbase, MUSB_POWER); if (retries-- < 1) break;
}
}
musb_dbg(musb, "Root port suspended, power %02x", power);
if (musb_get_state(musb) == OTG_STATE_B_IDLE) {
musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle");
musb->port1_status &= ~USB_PORT_STAT_RESET; return;
}
if (!is_host_active(musb)) return;
/* NOTE: caller guarantees it will turn off the reset when * the appropriate amount of time has passed
*/
power = musb_readb(mbase, MUSB_POWER); if (do_reset) { /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start * generating SOFs. If we don't do this, OPT HS A 6.8 tests * fail with "Error! Did not receive an SOF before suspend * detected".
*/ if (power & MUSB_POWER_RESUME) { long remain = (unsignedlong) musb->rh_timer - jiffies;
if (musb->rh_timer > 0 && remain > 0) { /* take into account the minimum delay after resume */
schedule_delayed_work(
&musb->deassert_reset_work, remain); return;
}
musb_writeb(mbase, MUSB_POWER,
power & ~MUSB_POWER_RESUME);
/* Give the core 1 ms to clear MUSB_POWER_RESUME */
schedule_delayed_work(&musb->deassert_reset_work,
msecs_to_jiffies(1)); return;
}
power &= 0xf0;
musb_writeb(mbase, MUSB_POWER,
power | MUSB_POWER_RESET);
/* Caller may or may not hold musb->lock */ int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
{ struct musb *musb = hcd_to_musb(hcd); int retval = 0;
/* called in_irq() via usb_hcd_poll_rh_status() */ if (musb->port1_status & 0xffff0000) {
*buf = 0x02;
retval = 1;
} return retval;
}
staticint musb_has_gadget(struct musb *musb)
{ /* * In host-only mode we start a connection right away. In OTG mode * we have to wait until we loaded a gadget. We don't really need a * gadget if we operate as a host but we should not start a session * as a device without a gadget or else we explode.
*/ #ifdef CONFIG_USB_MUSB_HOST return 1; #else return musb->port_mode == MUSB_HOST; #endif
}
if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
spin_unlock_irqrestore(&musb->lock, flags); return -ESHUTDOWN;
}
/* hub features: always zero, setting is a NOP * port features: reported, sometimes updated when host is active * no indicators
*/ switch (typeReq) { case ClearHubFeature: case SetHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: break; default: goto error;
} break; case ClearPortFeature: if ((wIndex & 0xff) != 1) goto error;
switch (wValue) { case USB_PORT_FEAT_ENABLE: break; case USB_PORT_FEAT_SUSPEND:
musb_port_suspend(musb, false); break; case USB_PORT_FEAT_POWER: if (!hcd->self.is_b_host)
musb_platform_set_vbus(musb, 0); break; case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_SUSPEND: break; default: goto error;
}
musb_dbg(musb, "clear feature %d", wValue);
musb->port1_status &= ~(1 << wValue); break; case GetHubDescriptor:
{ struct usb_hub_descriptor *desc = (void *)buf;
/* port change status is more interesting */
musb_dbg(musb, "port status %08x", musb->port1_status); break; case SetPortFeature: if ((wIndex & 0xff) != 1) goto error;
switch (wValue) { case USB_PORT_FEAT_POWER: /* NOTE: this controller has a strange state machine * that involves "requesting sessions" according to * magic side effects from incompletely-described * rules about startup... * * This call is what really starts the host mode; be * very careful about side effects if you reorder any * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up.
*/ if (!hcd->self.is_b_host && musb_has_gadget(musb))
start_musb = true; break; case USB_PORT_FEAT_RESET:
musb_port_reset(musb, true); break; case USB_PORT_FEAT_SUSPEND:
musb_port_suspend(musb, true); break; case USB_PORT_FEAT_TEST: if (unlikely(is_host_active(musb))) goto error;
wIndex >>= 8; switch (wIndex) { case USB_TEST_J:
pr_debug("USB_TEST_J\n");
temp = MUSB_TEST_J; break; case USB_TEST_K:
pr_debug("USB_TEST_K\n");
temp = MUSB_TEST_K; break; case USB_TEST_SE0_NAK:
pr_debug("USB_TEST_SE0_NAK\n");
temp = MUSB_TEST_SE0_NAK; break; case USB_TEST_PACKET:
pr_debug("USB_TEST_PACKET\n");
temp = MUSB_TEST_PACKET;
musb_load_testpacket(musb); break; case USB_TEST_FORCE_ENABLE:
pr_debug("USB_TEST_FORCE_ENABLE\n");
temp = MUSB_TEST_FORCE_HOST
| MUSB_TEST_FORCE_HS;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.