> > >
> > > +int ci_otg_fsm_work(struct ci_hdrc *ci) {
> > > + /*
> > > + * Don't do fsm transition for B device
> > > + * when there is no gadget class driver
> > > + */
> > > + if (ci->fsm.id && !(ci->driver) &&
> > > + ci->transceiver->state < OTG_STATE_A_IDLE)
> > > + return 0;
> > > +
> > > + if (otg_statemachine(&ci->fsm)) {
> > > + if (ci->transceiver->state == OTG_STATE_A_IDLE) {
> > > + /*
> > > + * Further state change for cases:
> > > + * A idle to B idle, or
> > > + * A idle to A wait vrise due to ID change, or
> >
> > At OTG A-device with HNP State Diagram, I haven't seen ID change is
> > one of the reason for A idle to A wait vrise. Why you do this here?
> >
> > Peter
>
> Yes, this is out of OTG spec, but it's necessary for the case user insert
> a ID cable(ID is 0) and the A-device can transit to a_wait_bcon/a_host
> automatically, then enumeration can be started if the other end has a B-
> device, otherwise app need do a_bus_req additionally, I think this is
> making sense.
>
Get it, add comment for that please.
No more comments, you just need to fix the two tiny comments for your v10
patchset.
Peter
> Li Jun
> > > + * A idle to A wait vrise when power up
> > > + */
> > > + if ((ci->fsm.id) || (ci->id_event) ||
> > > + (ci->fsm.power_up)) {
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + if (ci->id_event)
> > > + ci->id_event = false;
> > > + }
> > > + }
> > > + return 0;
> > > +}
> > > +
> > > +/*
> > > + * Update fsm variables in each state if catching expected
> > > +interrupts,
> > > + * called by otg fsm isr.
> > > + */
> > > +static void ci_otg_fsm_event(struct ci_hdrc *ci) {
> > > + u32 intr_sts, otg_bsess_vld, port_conn;
> > > + struct otg_fsm *fsm = &ci->fsm;
> > > +
> > > + intr_sts = hw_read_intr_status(ci);
> > > + otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV);
> > > + port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS);
> > > +
> > > + switch (ci->transceiver->state) {
> > > + case OTG_STATE_A_WAIT_BCON:
> > > + if (port_conn) {
> > > + fsm->b_conn = 1;
> > > + fsm->a_bus_req = 1;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + break;
> > > + case OTG_STATE_B_IDLE:
> > > + if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) {
> > > + fsm->b_sess_vld = 1;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + if (fsm->b_sess_vld)
> > > + fsm->power_up = 0;
> > > + break;
> > > + case OTG_STATE_B_PERIPHERAL:
> > > + if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) {
> > > + fsm->a_bus_suspend = 1;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + } else if (intr_sts & USBi_PCI) {
> > > + if (fsm->a_bus_suspend == 1)
> > > + fsm->a_bus_suspend = 0;
> > > + }
> > > + break;
> > > + case OTG_STATE_B_HOST:
> > > + if ((intr_sts & USBi_PCI) && !port_conn) {
> > > + fsm->a_conn = 0;
> > > + fsm->b_bus_req = 0;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + ci_otg_add_timer(ci, B_SESS_VLD);
> > > + }
> > > + break;
> > > + case OTG_STATE_A_PERIPHERAL:
> > > + if (intr_sts & USBi_SLI) {
> > > + fsm->b_bus_suspend = 1;
> > > + /*
> > > + * Init a timer to know how long this suspend
> > > + * will contine, if time out, indicates B no longer
> > > + * wants to be host role
> > > + */
> > > + ci_otg_add_timer(ci, A_BIDL_ADIS);
> > > + }
> > > +
> > > + if (intr_sts & USBi_URI)
> > > + ci_otg_del_timer(ci, A_BIDL_ADIS);
> > > +
> > > + if (intr_sts & USBi_PCI) {
> > > + if (fsm->b_bus_suspend == 1) {
> > > + ci_otg_del_timer(ci, A_BIDL_ADIS);
> > > + fsm->b_bus_suspend = 0;
> > > + }
> > > + }
> > > + break;
> > > + case OTG_STATE_A_SUSPEND:
> > > + if ((intr_sts & USBi_PCI) && !port_conn) {
> > > + fsm->b_conn = 0;
> > > +
> > > + /* if gadget driver is binded */
> > > + if (ci->driver) {
> > > + /* A device to be peripheral mode */
> > > + ci->gadget.is_a_peripheral = 1;
> > > + }
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + break;
> > > + case OTG_STATE_A_HOST:
> > > + if ((intr_sts & USBi_PCI) && !port_conn) {
> > > + fsm->b_conn = 0;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + break;
> > > + case OTG_STATE_B_WAIT_ACON:
> > > + if ((intr_sts & USBi_PCI) && port_conn) {
> > > + fsm->a_conn = 1;
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + }
> > > + break;
> > > + default:
> > > + break;
> > > + }
> > > +}
> > > +
> > > +/*
> > > + * ci_otg_irq - otg fsm related irq handling
> > > + * and also update otg fsm variable by monitoring usb host and udc
> > > + * state change interrupts.
> > > + * @ci: ci_hdrc
> > > + */
> > > +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) {
> > > + irqreturn_t retval = IRQ_NONE;
> > > + u32 otgsc, otg_int_src = 0;
> > > + struct otg_fsm *fsm = &ci->fsm;
> > > +
> > > + otgsc = hw_read_otgsc(ci, ~0);
> > > + otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8);
> > > + fsm->id = (otgsc & OTGSC_ID) ? 1 : 0;
> > > +
> > > + if (otg_int_src) {
> > > + if (otg_int_src & OTGSC_1MSIS) {
> > > + hw_write_otgsc(ci, OTGSC_1MSIS, OTGSC_1MSIS);
> > > + retval = ci_otg_tick_timer(ci);
> > > + return IRQ_HANDLED;
> > > + } else if (otg_int_src & OTGSC_DPIS) {
> > > + hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
> > > + fsm->a_srp_det = 1;
> > > + fsm->a_bus_drop = 0;
> > > + } else if (otg_int_src & OTGSC_IDIS) {
> > > + hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
> > > + if (fsm->id == 0) {
> > > + fsm->a_bus_drop = 0;
> > > + fsm->a_bus_req = 1;
> > > + ci->id_event = true;
> > > + }
> > > + } else if (otg_int_src & OTGSC_BSVIS) {
> > > + hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
> > > + if (otgsc & OTGSC_BSV) {
> > > + fsm->b_sess_vld = 1;
> > > + ci_otg_del_timer(ci, B_SSEND_SRP);
> > > + ci_otg_del_timer(ci, B_SRP_FAIL);
> > > + fsm->b_ssend_srp = 0;
> > > + } else {
> > > + fsm->b_sess_vld = 0;
> > > + if (fsm->id)
> > > + ci_otg_add_timer(ci, B_SSEND_SRP);
> > > + }
> > > + } else if (otg_int_src & OTGSC_AVVIS) {
> > > + hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS);
> > > + if (otgsc & OTGSC_AVV) {
> > > + fsm->a_vbus_vld = 1;
> > > + } else {
> > > + fsm->a_vbus_vld = 0;
> > > + fsm->b_conn = 0;
> > > + }
> > > + }
> > > + disable_irq_nosync(ci->irq);
> > > + queue_work(ci->wq, &ci->work);
> > > + return IRQ_HANDLED;
> > > + }
> > > +
> > > + ci_otg_fsm_event(ci);
> > > +
> > > + return retval;
> > > +}
> > > +
> > > +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) {
> > > + ci_otg_fsm_work(ci);
> > > +}
> > > +
> > > int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) {
> > > int retval = 0;
> > > diff --git a/drivers/usb/chipidea/otg_fsm.h
> > > b/drivers/usb/chipidea/otg_fsm.h index 420f081..6ec8247 100644
> > > --- a/drivers/usb/chipidea/otg_fsm.h
> > > +++ b/drivers/usb/chipidea/otg_fsm.h
> > > @@ -92,6 +92,9 @@ struct ci_otg_fsm_timer_list { #ifdef
> > > CONFIG_USB_OTG_FSM
> > >
> > > int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
> > > +int ci_otg_fsm_work(struct ci_hdrc *ci); irqreturn_t
> > > +ci_otg_fsm_irq(struct ci_hdrc *ci); void
> > > +ci_hdrc_otg_fsm_start(struct ci_hdrc *ci);
> > >
> > > #else
> > >
> > > @@ -100,6 +103,21 @@ static inline int ci_hdrc_otg_fsm_init(struct
> ci_hdrc *ci)
> > > return 0;
> > > }
> > >
> > > +static inline int ci_otg_fsm_work(struct ci_hdrc *ci) {
> > > + return -ENXIO;
> > > +}
> > > +
> > > +static inline irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) {
> > > + return IRQ_NONE;
> > > +}
> > > +
> > > +static inline void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) {
> > > +
> > > +}
> > > +
> > > #endif
> > >
> > > #endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */ diff --git
> > > a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index
> > > cba7fd6..362d8f1 100644
> > > --- a/drivers/usb/chipidea/udc.c
> > > +++ b/drivers/usb/chipidea/udc.c
> > > @@ -28,6 +28,7 @@
> > > #include "bits.h"
> > > #include "debug.h"
> > > #include "otg.h"
> > > +#include "otg_fsm.h"
> > >
> > > /* control endpoint description */
> > > static const struct usb_endpoint_descriptor @@ -1644,7 +1645,15 @@
> > > static int ci_udc_start(struct usb_gadget *gadget,
> > > return retval;
> > >
> > > ci->driver = driver;
> > > +
> > > + /* Start otg fsm for B-device */
> > > + if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) {
> > > + ci_hdrc_otg_fsm_start(ci);
> > > + return retval;
> > > + }
> > > +
> > > pm_runtime_get_sync(&ci->gadget.dev);
> > > +
> > > if (ci->vbus_active) {
> > > spin_lock_irqsave(&ci->lock, flags);
> > > hw_device_reset(ci, USBMODE_CM_DC);
> > > --
> > > 1.7.9.5
> > >
> > >
> >
> > --
> >
> > Best Regards,
> > Peter Chen
> >
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html