On 17/07/15 11:14, Li Jun wrote: > Hi, > > On Wed, Jul 08, 2015 at 01:19:36PM +0300, Roger Quadros wrote: >> DRD mode is a reduced functionality OTG mode. In this mode >> we don't support SRP, HNP and dynamic role-swap. >> >> In DRD operation, the controller mode (Host or Peripheral) >> is decided based on the ID pin status. Once a cable plug (Type-A >> or Type-B) is attached the controller selects the state >> and doesn't change till the cable in unplugged and a different >> cable type is inserted. >> >> As we don't need most of the complex OTG states and OTG timers >> we implement a lean DRD state machine in usb-otg.c. >> The DRD state machine is only interested in 2 hardware inputs >> 'id' and 'vbus; that are still passed via the origintal struct otg_fsm. >> >> Most of the usb-otg.c functionality remains the same except >> adding a new parameter to usb_otg_register() to indicate that >> the OTG controller needs to operate in DRD mode. >> >> Signed-off-by: Roger Quadros <rogerq@xxxxxx> >> --- >> drivers/usb/common/usb-otg.c | 179 ++++++++++++++++++++++++++++++++++++++++--- >> include/linux/usb/otg-fsm.h | 8 +- >> include/linux/usb/otg.h | 5 +- >> 3 files changed, 180 insertions(+), 12 deletions(-) >> >> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c >> index 1f19001..9b89f4b 100644 >> --- a/drivers/usb/common/usb-otg.c >> +++ b/drivers/usb/common/usb-otg.c >> @@ -44,6 +44,7 @@ struct otg_hcd { >> struct otg_data { >> struct device *dev; /* HCD & GCD's parent device */ >> >> + bool drd_only; /* Dual-role only, no OTG features */ > > After we introduce otg caps, we can use hnp_support to judge it it's > drd or OTG. Yes. I will rebase this series on top of your otg_caps patches and incorporate it. > >> struct otg_fsm fsm; >> /* HCD, GCD and usb_otg_state are present in otg_fsm->otg >> * HCD is bus_to_hcd(fsm->otg->host) >> @@ -272,20 +273,172 @@ static int usb_otg_start_gadget(struct otg_fsm *fsm, int on) >> return 0; >> } >> >> +/* Change USB protocol when there is a protocol change */ >> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol) >> +{ >> + struct otg_data *otgd = container_of(fsm, struct otg_data, fsm); >> + int ret = 0; >> + >> + if (fsm->protocol != protocol) { >> + dev_dbg(otgd->dev, "otg: 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; >> +} >> + >> +/* Called when entering a DRD state */ >> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) >> +{ >> + struct otg_data *otgd = container_of(fsm, struct otg_data, fsm); >> + >> + if (fsm->otg->state == new_state) >> + return; >> + >> + fsm->state_changed = 1; >> + dev_dbg(otgd->dev, "otg: set state: %s\n", >> + usb_otg_state_string(new_state)); >> + switch (new_state) { >> + case OTG_STATE_B_IDLE: > > otg_drv_vbus(fsm, 0); > >> + drd_set_protocol(fsm, PROTO_UNDEF); >> + break; >> + case OTG_STATE_B_PERIPHERAL: > > otg_drv_vbus(fsm, 0); > >> + drd_set_protocol(fsm, PROTO_GADGET); >> + break; >> + case OTG_STATE_A_HOST: > > otg_drv_vbus(fsm, 1); OK. > >> + drd_set_protocol(fsm, PROTO_HOST); >> + break; >> + case OTG_STATE_UNDEFINED: >> + case OTG_STATE_B_SRP_INIT: >> + case OTG_STATE_B_WAIT_ACON: >> + case OTG_STATE_B_HOST: >> + case OTG_STATE_A_IDLE: >> + case OTG_STATE_A_WAIT_VRISE: >> + case OTG_STATE_A_WAIT_BCON: >> + case OTG_STATE_A_SUSPEND: >> + case OTG_STATE_A_PERIPHERAL: >> + case OTG_STATE_A_WAIT_VFALL: >> + case OTG_STATE_A_VBUS_ERR: >> + default: >> + dev_warn(otgd->dev, "%s: otg: invalid state: %s\n", >> + __func__, usb_otg_state_string(new_state)); >> + break; >> + } >> + >> + fsm->otg->state = new_state; >> +} >> + cheers, -roger -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html