usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT; switch (usbsrc) { default:
dev_warn(ext->dev, "Unhandled charger type %d, defaulting to SDP\n",
ret);
ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; return EXTCON_CHG_USB_SDP; case CHT_WC_USBSRC_TYPE_SDP: case CHT_WC_USBSRC_TYPE_FLOATING: case CHT_WC_USBSRC_TYPE_OTHER:
ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; return EXTCON_CHG_USB_SDP; case CHT_WC_USBSRC_TYPE_CDP:
ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP; return EXTCON_CHG_USB_CDP; case CHT_WC_USBSRC_TYPE_DCP: case CHT_WC_USBSRC_TYPE_DCP_EXTPHY: case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
ext->usb_type = POWER_SUPPLY_USB_TYPE_DCP; return EXTCON_CHG_USB_DCP; case CHT_WC_USBSRC_TYPE_ACA:
ext->usb_type = POWER_SUPPLY_USB_TYPE_ACA; return EXTCON_CHG_USB_ACA;
}
}
staticvoid cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
{ int ret;
ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state); if (ret)
dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
}
staticvoid cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, bool enable)
{ int ret, val;
/* *The5VboostconverterisenabledthroughagpioonthePMIC,since *therecurrentlyisnogpiodriverweaccessthegpioregdirectly.
*/
val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT; if (enable)
val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT;
ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); if (ret)
dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret);
}
staticvoid cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext, bool enable)
{ unsignedint val = enable ? CHT_WC_CHGRCTRL1_OTGMODE : 0; int ret;
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL1,
CHT_WC_CHGRCTRL1_OTGMODE, val); if (ret)
dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret);
if (ext->vbus_boost && ext->vbus_boost_enabled != enable) { if (enable)
ret = regulator_enable(ext->vbus_boost); else
ret = regulator_disable(ext->vbus_boost);
staticvoid cht_wc_extcon_enable_charging(struct cht_wc_extcon_data *ext, bool enable)
{ unsignedint val = enable ? 0 : CHT_WC_CHGDISCTRL_OUT; int ret;
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL,
CHT_WC_CHGDISCTRL_OUT, val); if (ret)
dev_err(ext->dev, "Error updating CHGDISCTRL reg: %d\n", ret);
}
/* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */ staticvoid cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext, unsignedint cable, bool state)
{
extcon_set_state_sync(ext->edev, cable, state); if (cable == EXTCON_CHG_USB_SDP)
extcon_set_state_sync(ext->edev, EXTCON_USB, state);
}
staticvoid cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext)
{ int ret, pwrsrc_sts, id; unsignedint cable = EXTCON_NONE; /* Ignore errors in host mode, as the 5v boost converter is on then */ bool ignore_get_charger_errors = ext->usb_host; enum usb_role role;
ext->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); if (ret) {
dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); return;
}
id = cht_wc_extcon_get_id(ext, pwrsrc_sts); if (id == INTEL_USB_ID_GND) {
cht_wc_extcon_enable_charging(ext, false);
cht_wc_extcon_set_otgmode(ext, true);
/* The 5v boost causes a false VBUS / SDP detect, skip */ goto charger_det_done;
}
/* Plugged into a host/charger or not connected? */ if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) { /* Route D+ and D- to PMIC for future charger detection */
cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); goto set_state;
}
ret = cht_wc_extcon_get_charger(ext, ignore_get_charger_errors); if (ret >= 0)
cable = ret;
charger_det_done: /* Route D+ and D- to SoC for the host or gadget controller */
cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
if (ext->usb_host)
role = USB_ROLE_HOST; elseif (pwrsrc_sts & CHT_WC_PWRSRC_VBUS)
role = USB_ROLE_DEVICE; else
role = USB_ROLE_NONE;
/* Note: this is a no-op when ext->role_sw is NULL */
ret = usb_role_switch_set_role(ext->role_sw, role); if (ret)
dev_err(ext->dev, "Error setting USB-role: %d\n", ret);
val = enable ? 0 : CHT_WC_CHGDISCTRL_FN;
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL,
CHT_WC_CHGDISCTRL_FN, val); if (ret)
dev_err(ext->dev, "Error setting sw control for CHGDIS pin: %d\n",
ret);
mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF;
val = enable ? mask : 0;
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); if (ret)
dev_err(ext->dev, "Error setting sw control: %d\n", ret);
/* Some boards require controlling the role-sw and Vbus based on the id-pin */ staticint cht_wc_extcon_get_role_sw_and_regulator(struct cht_wc_extcon_data *ext)
{ int ret;
ret = cht_wc_extcon_find_role_sw(ext); if (ret) return ret;
ret = devm_add_action_or_reset(ext->dev, cht_wc_extcon_put_role_sw, ext); if (ret) return ret;
/* *Onx86/ACPIplatformstheregulator<->consumerlinkisprovided *byplatform_datapassedtotheregulatordriver.Thismeansthat *thisinfoisnotavailablebeforetheregulatordriverhasbound. *Usedevm_regulator_get_optional()toavoidgettingadummy *regulatorandwaitfortheregulatortoshowupifnecessary.
*/
ext->vbus_boost = devm_regulator_get_optional(ext->dev, "vbus"); if (IS_ERR(ext->vbus_boost)) {
ret = PTR_ERR(ext->vbus_boost); if (ret == -ENODEV)
ret = -EPROBE_DEFER;
switch (pmic->cht_wc_model) { case INTEL_CHT_WC_GPD_WIN_POCKET: /* *Whenahost-cableisdetectedtheBIOSenablesanexternal5vboost *convertertopowerconnecteddevicesthereare2problemswiththis: *1)ThisgetsseenbytheexternalbatterychargerasavalidVbus *supplyanditthentriestofeedVsysfromthiscreatinga *feedbackloopwhichcausesaprox.300mAextrabatterydrain *(andunlesswedrivetheexternal-charger-disablepinhighit *alsotriestochargethebatterycausingevenmorefeedback). *2)ThisgetsseenbythepwrsrcblockasaSDPUSBVbussupply *Sincetheexternalbatterychargerhasitsown5vboostconverter *whichdoesnothavetheseissues,wesimplyturntheseparate *external5vboostconverteroffandleaveitoffentirely.
*/
cht_wc_extcon_set_5v_boost(ext, false); break; case INTEL_CHT_WC_LENOVO_YOGABOOK1: case INTEL_CHT_WC_LENOVO_YT3_X90: /* Do this first, as it may very well return -EPROBE_DEFER. */
ret = cht_wc_extcon_get_role_sw_and_regulator(ext); if (ret) return ret; /* *Thebq25890usedherereliesonthisdriver'sBC-1.2charger *detection,andthebq25890driverexpectthisinfotobe *availablethroughaparentpower_supplyclassdevicewhich *modelsthedetectedcharger(idemtohowtheType-CTCPMcode *registersapower_supplyclassdevfortheconnectedcharger).
*/
ret = cht_wc_extcon_register_psy(ext); if (ret) return ret; break; case INTEL_CHT_WC_XIAOMI_MIPAD2:
ret = cht_wc_extcon_get_role_sw_and_regulator(ext); if (ret) return ret; break; default: break;
}
/* Enable sw control */
ret = cht_wc_extcon_sw_control(ext, true); if (ret) goto disable_sw_control;
/* Disable charging by external battery charger */
cht_wc_extcon_enable_charging(ext, false);
ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); if (ret) {
dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); goto disable_sw_control;
}
/* *IfnoUSBhostordeviceconnected,routeD+andD-toPMICfor *initialchargerdetection
*/
id = cht_wc_extcon_get_id(ext, pwrsrc_sts); if (id != INTEL_USB_ID_GND)
cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
/* Get initial state */
cht_wc_extcon_pwrsrc_event(ext);
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.