staticvoid tusb1210_chg_det_set_state(struct tusb1210 *tusb, enum tusb1210_chg_det_state new_state, int delay_ms)
{ if (delay_ms)
dev_dbg(tusb->dev, "chg_det new state %s in %d ms\n",
tusb1210_chg_det_states[new_state], delay_ms);
/* * Boards using a TUSB121x for charger-detection have 3 power_supply class devs: * * tusb1211-charger-detect(1) -> charger -> fuel-gauge * * To determine if an USB charger is connected to the board, the online prop of * the charger psy needs to be read. Since the tusb1211-charger-detect psy is * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied() * cannot be used here. * * Instead, below is a list of the power_supply names of known chargers for * these boards and the charger psy is looked up by name from this list. * * (1) modelling the external USB charger
*/ staticconstchar * const tusb1210_chargers[] = { "bq24190-charger",
};
staticbool tusb1210_get_online(struct tusb1210 *tusb)
{ struct power_supply *charger = NULL; union power_supply_propval val; bool online = false; int i, ret;
for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !charger; i++)
charger = power_supply_get_by_name(tusb1210_chargers[i]);
if (!charger) returnfalse;
ret = power_supply_get_property(charger, POWER_SUPPLY_PROP_ONLINE, &val); if (ret == 0)
online = val.intval;
dev_dbg(tusb->dev, "chg_det state %s vbus_present %d\n",
tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
switch (tusb->chg_det_state) { case TUSB1210_CHG_DET_CONNECTING:
tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
tusb->chg_det_retries = 0; /* Power on USB controller for ulpi_read()/_write() */
ret = pm_runtime_resume_and_get(tusb->dev->parent); if (ret < 0) {
dev_err(tusb->dev, "error %d runtime-resuming\n", ret); /* Should never happen, skip charger detection */
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); return;
}
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0); break; case TUSB1210_CHG_DET_START_DET: /* * Use the builtin charger detection FSM to keep things simple. * This only detects DCP / SDP. This is good enough for the few * boards which actually rely on the phy for charger detection.
*/
mutex_lock(&tusb->phy->mutex);
ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
mutex_unlock(&tusb->phy->mutex); if (ret) {
tusb1210_chg_det_handle_ulpi_error(tusb); break;
}
/* Wait 400 ms for the charger detection FSM to finish */
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400); break; case TUSB1210_CHG_DET_READ_DET:
mutex_lock(&tusb->phy->mutex);
ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
mutex_unlock(&tusb->phy->mutex); if (ret) {
tusb1210_chg_det_handle_ulpi_error(tusb); break;
}
if (val & TUSB1211_POWER_CONTROL_DET_COMP)
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP); else
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0); break; case TUSB1210_CHG_DET_FINISH_DET:
mutex_lock(&tusb->phy->mutex);
/* Set SW_CONTROL to stop the charger-det FSM */
ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
TUSB1211_POWER_CONTROL_SW_CONTROL);
/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
TUSB1211_POWER_CONTROL_DP_VSRC_EN);
/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
/* If any of the above fails reset the phy */ if (ret) {
tusb1210_reset(tusb);
msleep(TUSB1210_RESET_TIME_MS);
}
pm_runtime_put(tusb->dev->parent);
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); break; case TUSB1210_CHG_DET_CONNECTED: if (!vbus_present)
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0); break; case TUSB1210_CHG_DET_DISCONNECTING: /* * The phy seems to take approx. 600ms longer then the charger * chip (which is used to get vbus_present) to determine Vbus * session end. Wait 800ms to ensure the phy has detected and * signalled Vbus session end.
*/
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800); break; case TUSB1210_CHG_DET_DISCONNECTING_DONE: /* * The phy often stops reacting to ulpi_read()/_write requests * after a Vbus-session end. Reset it to work around this.
*/
tusb1210_reset(tusb);
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0); break; case TUSB1210_CHG_DET_DISCONNECTED: if (vbus_present)
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0); break;
}
}
/* Setup charger detection if requested, on errors continue without chg-det */ staticvoid tusb1210_probe_charger_detect(struct tusb1210 *tusb)
{ struct power_supply_config psy_cfg = { .drv_data = tusb }; struct device *dev = tusb->dev; struct ulpi *ulpi = to_ulpi_dev(dev); int ret;
if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect")) return;
if (ulpi->id.product != TI_DEVICE_TUSB1211) {
dev_err(dev, "error charger detection is only supported on the TUSB1211\n"); return;
}
ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl); if (ret) return;
tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg); if (IS_ERR(tusb->psy)) return;
/* * Delay initial run by 2 seconds to allow the charger driver, * which is used to determine vbus_present, to load.
*/
tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
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.