/* * If using extcon framework for VBUS and/or ID signal * detection overwrite OTGSC register value
*/
cable = &ci->platdata->vbus_extcon; if (!IS_ERR(cable->edev) || ci->role_switch) { if (cable->changed)
val |= OTGSC_BSVIS; else
val &= ~OTGSC_BSVIS;
if (cable->connected)
val |= OTGSC_BSV; else
val &= ~OTGSC_BSV;
if (cable->enabled)
val |= OTGSC_BSVIE; else
val &= ~OTGSC_BSVIE;
}
cable = &ci->platdata->id_extcon; if (!IS_ERR(cable->edev) || ci->role_switch) { if (cable->changed)
val |= OTGSC_IDIS; else
val &= ~OTGSC_IDIS;
if (cable->connected)
val &= ~OTGSC_ID; /* host */ else
val |= OTGSC_ID; /* device */
if (cable->enabled)
val |= OTGSC_IDIE; else
val &= ~OTGSC_IDIE;
}
return val & mask;
}
/** * hw_write_otgsc - updates target bits of OTGSC register. * @ci: the controller * @mask: bitfield mask * @data: to be written
*/ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
{ struct ci_hdrc_cable *cable;
cable = &ci->platdata->vbus_extcon; if (!IS_ERR(cable->edev) || ci->role_switch) { if (data & mask & OTGSC_BSVIS)
cable->changed = false;
/* Don't enable vbus interrupt if using external notifier */ if (data & mask & OTGSC_BSVIE) {
cable->enabled = true;
data &= ~OTGSC_BSVIE;
} elseif (mask & OTGSC_BSVIE) {
cable->enabled = false;
}
}
cable = &ci->platdata->id_extcon; if (!IS_ERR(cable->edev) || ci->role_switch) { if (data & mask & OTGSC_IDIS)
cable->changed = false;
/* Don't enable id interrupt if using external notifier */ if (data & mask & OTGSC_IDIE) {
cable->enabled = true;
data &= ~OTGSC_IDIE;
} elseif (mask & OTGSC_IDIE) {
cable->enabled = false;
}
}
/** * ci_otg_role - pick role based on ID pin state * @ci: the controller
*/ enum ci_role ci_otg_role(struct ci_hdrc *ci)
{ enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
? CI_ROLE_GADGET
: CI_ROLE_HOST;
return role;
}
void ci_handle_vbus_change(struct ci_hdrc *ci)
{ if (!ci->is_otg) { if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS)
usb_gadget_vbus_connect(&ci->gadget); return;
}
/** * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value * should be lower than OTGSC_BSV before connecting * to host. * * @ci: the controller * * This function returns an error code if timeout
*/ staticint hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
{ unsignedlong elapse = jiffies + msecs_to_jiffies(5000);
u32 mask = OTGSC_BSV;
while (hw_read_otgsc(ci, mask)) { if (time_after(jiffies, elapse)) {
dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n",
mask); return -ETIMEDOUT;
}
msleep(20);
}
mutex_lock(&ci->mutex);
role = ci_otg_role(ci); if (role != ci->role) {
dev_dbg(ci->dev, "switching from %s to %s\n",
ci_role(ci)->name, ci->roles[role]->name);
if (ci->vbus_active && ci->role == CI_ROLE_GADGET) /* * vbus disconnect event is lost due to role * switch occurs during system suspend.
*/
usb_gadget_vbus_disconnect(&ci->gadget);
ci_role_stop(ci);
if (role == CI_ROLE_GADGET &&
IS_ERR(ci->platdata->vbus_extcon.edev)) /* * Wait vbus lower than OTGSC_BSV before connecting * to host. If connecting status is from an external * connector instead of register, we don't need to * care vbus on the board, since it will not affect * external connector status.
*/
hw_wait_vbus_lower_bsv(ci);
if (ci_otg_is_fsm_mode(ci)) return ci_hdrc_otg_fsm_init(ci);
return 0;
}
/** * ci_hdrc_otg_destroy - destroy otg struct * @ci: the controller
*/ void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
{ if (ci->wq)
destroy_workqueue(ci->wq);
/* Disable all OTG irq and clear status */
hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
OTGSC_INT_STATUS_BITS); if (ci_otg_is_fsm_mode(ci))
ci_hdrc_otg_fsm_remove(ci);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet)
¤
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.