if (cdns->roles[role]->state == CDNS_ROLE_STATE_ACTIVE) return0;
mutex_lock(&cdns->mutex);
ret = cdns->roles[role]->start(cdns); if (!ret)
cdns->roles[role]->state = CDNS_ROLE_STATE_ACTIVE;
mutex_unlock(&cdns->mutex);
return ret;
}
staticvoid cdns_role_stop(struct cdns *cdns)
{ enum usb_role role = cdns->role;
if (WARN_ON(role > USB_ROLE_DEVICE)) return;
if (cdns->roles[role]->state == CDNS_ROLE_STATE_INACTIVE) return;
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { if ((cdns->version == CDNSP_CONTROLLER_V2 &&
IS_ENABLED(CONFIG_USB_CDNSP_HOST)) ||
(cdns->version < CDNSP_CONTROLLER_V2 &&
IS_ENABLED(CONFIG_USB_CDNS3_HOST)))
ret = cdns_host_init(cdns); else
ret = -ENXIO;
if (ret) {
dev_err(dev, "Host initialization failed with %d\n",
ret); goto err;
}
}
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { if (cdns->gadget_init)
ret = cdns->gadget_init(cdns); else
ret = -ENXIO;
if (ret) {
dev_err(dev, "Device initialization failed with %d\n",
ret); goto err;
}
}
cdns->dr_mode = dr_mode;
ret = cdns_drd_update_mode(cdns); if (ret) goto err;
/* Initialize idle role to start with */
ret = cdns_role_start(cdns, USB_ROLE_NONE); if (ret) goto err;
switch (cdns->dr_mode) { case USB_DR_MODE_OTG:
ret = cdns_hw_role_switch(cdns); if (ret) goto err; break; case USB_DR_MODE_PERIPHERAL:
ret = cdns_role_start(cdns, USB_ROLE_DEVICE); if (ret) goto err; break; case USB_DR_MODE_HOST:
ret = cdns_role_start(cdns, USB_ROLE_HOST); if (ret) goto err; break; default:
ret = -EINVAL; goto err;
}
/** *cdns_hw_role_state_machine-roleswitchstatemachinebasedonhwevents. *@cdns:Pointertocontrollerstructure. * *Returnsnextroletobeenteredbasedonhwevents.
*/ staticenum usb_role cdns_hw_role_state_machine(struct cdns *cdns)
{ enum usb_role role = USB_ROLE_NONE; int id, vbus;
if (cdns->dr_mode != USB_DR_MODE_OTG) { if (cdns_is_host(cdns))
role = USB_ROLE_HOST; if (cdns_is_device(cdns))
role = USB_ROLE_DEVICE;
return role;
}
id = cdns_get_id(cdns);
vbus = cdns_get_vbus(cdns);
/* *Rolechangestatemachine *Inputs:ID,VBUS *Previousstate:cdns->role *Nextstate:role
*/
role = cdns->role;
switch (role) { case USB_ROLE_NONE: /* *DrivertreatsUSB_ROLE_NONEsynonymoustoIDLEstatefrom *controllerspecification.
*/ if (!id)
role = USB_ROLE_HOST; elseif (vbus)
role = USB_ROLE_DEVICE; break; case USB_ROLE_HOST: /* from HOST, we can only change to NONE */ if (id)
role = USB_ROLE_NONE; break; case USB_ROLE_DEVICE: /* from GADGET, we can only change to NONE*/ if (!vbus)
role = USB_ROLE_NONE; break;
}
/* Do nothing if nothing changed */ if (current_role == real_role) gotoexit;
cdns_role_stop(cdns);
dev_dbg(cdns->dev, "Switching role %d -> %d", current_role, real_role);
ret = cdns_role_start(cdns, real_role); if (ret) { /* Back to current role */
dev_err(cdns->dev, "set %d has failed, back to %d\n",
real_role, current_role);
ret = cdns_role_start(cdns, current_role); if (ret)
dev_err(cdns->dev, "back to %d failed too\n",
current_role);
} exit:
pm_runtime_put_sync(cdns->dev); return ret;
}
if (pm_runtime_status_suspended(dev))
pm_runtime_resume(dev);
if (cdns->roles[cdns->role]->suspend) {
spin_lock_irqsave(&cdns->lock, flags);
cdns->roles[cdns->role]->suspend(cdns, false);
spin_unlock_irqrestore(&cdns->lock, flags);
}
return0;
}
EXPORT_SYMBOL_GPL(cdns_suspend);
int cdns_resume(struct cdns *cdns)
{ bool power_lost = cdns_power_is_lost(cdns); enum usb_role real_role; bool role_changed = false; int ret = 0;
if (power_lost) { if (!cdns->role_sw) {
real_role = cdns_hw_role_state_machine(cdns); if (real_role != cdns->role) {
ret = cdns_hw_role_switch(cdns); if (ret) return ret;
role_changed = true;
}
}
if (!role_changed) { if (cdns->role == USB_ROLE_HOST)
ret = cdns_drd_host_on(cdns); elseif (cdns->role == USB_ROLE_DEVICE)
ret = cdns_drd_gadget_on(cdns);
if (ret) return ret;
}
}
if (cdns->roles[cdns->role]->resume)
cdns->roles[cdns->role]->resume(cdns, power_lost);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.