diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 27a4afdf3e44..36225c7ab7e0 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -831,6 +831,8 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) extcon_get_state(rphy->edev, EXTCON_USB_VBUS_EN) > 0 ) { dev_dbg(&rport->phy->dev, "usb otg host connect\n"); rport->state = OTG_STATE_A_HOST; + rphy->chg_state = USB_CHG_STATE_UNDEFINED; + rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; mutex_unlock(&rport->mutex); rockchip_usb2phy_power_on(rport->phy); return; @@ -887,13 +889,23 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) } break; case OTG_STATE_B_PERIPHERAL: - if (!rport->vbus_attached) { + sch_work = true; + + if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0 || + extcon_get_state(rphy->edev, + EXTCON_USB_VBUS_EN) > 0) { + dev_dbg(&rport->phy->dev, "usb otg host connect\n"); + rport->state = OTG_STATE_A_HOST; + rphy->chg_state = USB_CHG_STATE_UNDEFINED; + rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; + rport->perip_connected = false; + sch_work = false; + } else if (!rport->vbus_attached) { dev_dbg(&rport->phy->dev, "usb disconnect\n"); rport->state = OTG_STATE_B_IDLE; rport->perip_connected = false; delay = OTG_SCHEDULE_DELAY * 2; } - sch_work = true; break; case OTG_STATE_A_HOST: if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) { @@ -903,6 +915,9 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) rockchip_usb2phy_power_off(rport->phy); mutex_lock(&rport->mutex); sch_work = true; + } else { + mutex_unlock(&rport->mutex); + return; } break; default: @@ -913,6 +928,15 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) if (extcon_get_state(rphy->edev, cable) != rport->vbus_attached) extcon_set_state_sync(rphy->edev, cable, rport->vbus_attached); + else if (rport->state == OTG_STATE_A_HOST && + extcon_get_state(rphy->edev, cable)) + /* + * If plug in OTG host cable when the rport state is + * OTG_STATE_B_PERIPHERAL, the vbus voltage will stay + * in high, so the rport->vbus_attached may not be + * changed. We need to set cable state here. + */ + extcon_set_state_sync(rphy->edev, cable, false); if (rphy->edev_self && (extcon_get_state(rphy->edev, EXTCON_USB) != @@ -1341,7 +1365,6 @@ static int rockchip_otg_event(struct notifier_block *nb, struct rockchip_usb2phy_port *rport = container_of(nb, struct rockchip_usb2phy_port, event_nb); - cancel_delayed_work_sync(&rport->otg_sm_work); schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY); return NOTIFY_DONE;