static void rockchip_usb2phy_otg_sm_work()

in rockchip/phy-rockchip-inno-usb2.c [520:632]


static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
{
	struct rockchip_usb2phy_port *rport =
		container_of(work, struct rockchip_usb2phy_port,
			     otg_sm_work.work);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
	static unsigned int cable;
	unsigned long delay;
	bool vbus_attach, sch_work, notify_charger;

	vbus_attach = property_enabled(rphy->grf,
				       &rport->port_cfg->utmi_bvalid);

	sch_work = false;
	notify_charger = false;
	delay = OTG_SCHEDULE_DELAY;
	dev_dbg(&rport->phy->dev, "%s otg sm work\n",
		usb_otg_state_string(rport->state));

	switch (rport->state) {
	case OTG_STATE_UNDEFINED:
		rport->state = OTG_STATE_B_IDLE;
		if (!vbus_attach)
			rockchip_usb2phy_power_off(rport->phy);
		fallthrough;
	case OTG_STATE_B_IDLE:
		if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
			dev_dbg(&rport->phy->dev, "usb otg host connect\n");
			rport->state = OTG_STATE_A_HOST;
			rockchip_usb2phy_power_on(rport->phy);
			return;
		} else if (vbus_attach) {
			dev_dbg(&rport->phy->dev, "vbus_attach\n");
			switch (rphy->chg_state) {
			case USB_CHG_STATE_UNDEFINED:
				schedule_delayed_work(&rport->chg_work, 0);
				return;
			case USB_CHG_STATE_DETECTED:
				switch (rphy->chg_type) {
				case POWER_SUPPLY_TYPE_USB:
					dev_dbg(&rport->phy->dev, "sdp cable is connected\n");
					rockchip_usb2phy_power_on(rport->phy);
					rport->state = OTG_STATE_B_PERIPHERAL;
					notify_charger = true;
					sch_work = true;
					cable = EXTCON_CHG_USB_SDP;
					break;
				case POWER_SUPPLY_TYPE_USB_DCP:
					dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
					rockchip_usb2phy_power_off(rport->phy);
					notify_charger = true;
					sch_work = true;
					cable = EXTCON_CHG_USB_DCP;
					break;
				case POWER_SUPPLY_TYPE_USB_CDP:
					dev_dbg(&rport->phy->dev, "cdp cable is connected\n");
					rockchip_usb2phy_power_on(rport->phy);
					rport->state = OTG_STATE_B_PERIPHERAL;
					notify_charger = true;
					sch_work = true;
					cable = EXTCON_CHG_USB_CDP;
					break;
				default:
					break;
				}
				break;
			default:
				break;
			}
		} else {
			notify_charger = true;
			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
		}

		if (rport->vbus_attached != vbus_attach) {
			rport->vbus_attached = vbus_attach;

			if (notify_charger && rphy->edev) {
				extcon_set_state_sync(rphy->edev,
							cable, vbus_attach);
				if (cable == EXTCON_CHG_USB_SDP)
					extcon_set_state_sync(rphy->edev,
							      EXTCON_USB,
							      vbus_attach);
			}
		}
		break;
	case OTG_STATE_B_PERIPHERAL:
		if (!vbus_attach) {
			dev_dbg(&rport->phy->dev, "usb disconnect\n");
			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
			rport->state = OTG_STATE_B_IDLE;
			delay = 0;
			rockchip_usb2phy_power_off(rport->phy);
		}
		sch_work = true;
		break;
	case OTG_STATE_A_HOST:
		if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) {
			dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
			rport->state = OTG_STATE_B_IDLE;
			rockchip_usb2phy_power_off(rport->phy);
		}
		break;
	default:
		break;
	}

	if (sch_work)
		schedule_delayed_work(&rport->otg_sm_work, delay);
}