/* Change USB protocol when there is a protocol change */ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) { int ret = 0; if (fsm->protocol != protocol) { VDBG("Changing role fsm->protocol= %d; new protocol= %d\n", fsm->protocol, protocol); /* stop old protocol */ if (fsm->protocol == PROTO_HOST) ret = otg_start_host(fsm, 0); else if (fsm->protocol == PROTO_GADGET) ret = otg_start_gadget(fsm, 0); if (ret) return ret; /* start new protocol */ if (protocol == PROTO_HOST) ret = otg_start_host(fsm, 1); else if (protocol == PROTO_GADGET) ret = otg_start_gadget(fsm, 1); if (ret) return ret; fsm->protocol = protocol; return 0; } return 0; }
static int dwc3_otg_statemachine(struct otg_fsm *fsm) { struct usb_phy *phy = fsm->otg->phy; enum usb_otg_state prev_state = phy->state; int ret = 0; if (fsm->reset) { if (phy->state == OTG_STATE_A_HOST) { otg_drv_vbus(fsm, 0); otg_start_host(fsm, 0); } else if (phy->state == OTG_STATE_B_PERIPHERAL) { otg_start_gadget(fsm, 0); } phy->state = OTG_STATE_UNDEFINED; goto exit; } switch (phy->state) { case OTG_STATE_UNDEFINED: if (fsm->id) phy->state = OTG_STATE_B_IDLE; else phy->state = OTG_STATE_A_IDLE; break; case OTG_STATE_B_IDLE: if (!fsm->id) { phy->state = OTG_STATE_A_IDLE; } else if (fsm->b_sess_vld) { ret = otg_start_gadget(fsm, 1); if (!ret) phy->state = OTG_STATE_B_PERIPHERAL; else pr_err("OTG SM: cannot start gadget\n"); } break; case OTG_STATE_B_PERIPHERAL: if (!fsm->id || !fsm->b_sess_vld) { ret = otg_start_gadget(fsm, 0); if (!ret) phy->state = OTG_STATE_B_IDLE; else pr_err("OTG SM: cannot stop gadget\n"); } break; case OTG_STATE_A_IDLE: if (fsm->id) { phy->state = OTG_STATE_B_IDLE; } else { ret = otg_start_host(fsm, 1); if (!ret) { otg_drv_vbus(fsm, 1); phy->state = OTG_STATE_A_HOST; } else { pr_err("OTG SM: cannot start host\n"); } } break; case OTG_STATE_A_HOST: if (fsm->id) { otg_drv_vbus(fsm, 0); ret = otg_start_host(fsm, 0); if (!ret) phy->state = OTG_STATE_A_IDLE; else pr_err("OTG SM: cannot stop host\n"); } break; default: pr_err("OTG SM: invalid state\n"); } exit: if (!ret) ret = (phy->state != prev_state); pr_debug("OTG SM: %s => %s\n", usb_otg_state_string(prev_state), (ret > 0) ? usb_otg_state_string(phy->state) : "(no change)"); return ret; }