ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val); if (ret) goto out;
val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED); if (val != power->old_status)
power_supply_changed(power->supply);
if (power->usb_bc_en_bit && (val & AXP20X_PWR_STATUS_VBUS_PRESENT) !=
(power->old_status & AXP20X_PWR_STATUS_VBUS_PRESENT)) {
dev_dbg(power->dev, "Cable status changed, re-enabling USB BC");
ret = regmap_field_write(power->usb_bc_en_bit, 1); if (ret)
dev_err(power->dev, "failed to enable USB BC: errno %d",
ret);
}
power->old_status = val;
power->online = val & AXP20X_PWR_STATUS_VBUS_USED;
out: if (axp20x_usb_vbus_needs_polling(power))
mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
}
staticint axp717_usb_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct axp20x_usb_power *power = power_supply_get_drvdata(psy); unsignedint v; int ret;
switch (psp) { case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); if (ret) return ret;
if (!(v & AXP717_PWR_STATUS_VBUS_GOOD))
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
ret = regmap_read(power->regmap, AXP717_PMU_FAULT_VBUS, &v); if (ret) return ret;
v &= (AXP717_PMU_FAULT_VBUS | AXP717_PMU_FAULT_VSYS); if (v) {
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
regmap_write(power->regmap, AXP717_PMU_FAULT_VBUS, v);
}
break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(power->regmap, AXP717_INPUT_CUR_LIMIT_CTRL, &v); if (ret) return ret;
/* 50ma step size with 100ma offset. */
v &= AXP717_INPUT_CUR_LIMIT_MASK;
val->intval = (v * 50000) + 100000; break; case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_PRESENT:
ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); if (ret) return ret;
val->intval = !!(v & AXP717_PWR_STATUS_VBUS_GOOD); break; case POWER_SUPPLY_PROP_USB_TYPE: return axp20x_get_usb_type(power, val); case POWER_SUPPLY_PROP_VOLTAGE_MIN:
ret = regmap_read(power->regmap, AXP717_INPUT_VOL_LIMIT_CTRL, &v); if (ret) return ret;
/* 80mv step size with 3.88v offset. */
v &= AXP717_INPUT_VOL_LIMIT_MASK;
val->intval = (v * 80000) + 3880000; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { /* *IIOframeworkgivesmVbutPowerSupplyframework *givesuV.
*/
ret = iio_read_channel_processed_scale(power->vbus_v,
&val->intval, 1000); if (ret) return ret;
return0;
}
ret = axp20x_read_variable_width(power->regmap,
AXP717_VBUS_V_H, 16); if (ret < 0) return ret;
staticint axp717_usb_power_set_voltage_min(struct axp20x_usb_power *power, int intval)
{ int val;
/* Minimum value of 3.88v and maximum of 5.08v. */ if (intval < 3880000 || intval > 5080000) return -EINVAL;
/* step size of 80ma with 3.88v offset. */
val = (intval - 3880000) / 80000; return regmap_update_bits(power->regmap,
AXP717_INPUT_VOL_LIMIT_CTRL,
AXP717_INPUT_VOL_LIMIT_MASK, val);
}
staticint axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *power, int intval)
{ int ret; unsignedint reg; constunsignedint max = power->axp_data->curr_lim_table_size;
if (intval == -1) return -EINVAL;
if (power->max_input_cur && (intval > power->max_input_cur)) {
dev_warn(power->dev, "requested current %d clamped to max current %d\n",
intval, power->max_input_cur);
intval = power->max_input_cur;
}
/* *BC1.2detectioncancausearaceconditionifwetrytosetacurrent *limitwhileit'sinprogress.Whenitfinishesitwilloverwritethe *currentlimitwejustset.
*/ if (power->usb_bc_en_bit) {
dev_dbg(power->dev, "disabling BC1.2 detection because current limit was set");
ret = regmap_field_write(power->usb_bc_en_bit, 0); if (ret) return ret;
}
for (reg = max - 1; reg > 0; reg--) if (power->axp_data->curr_lim_table[reg] <= intval) break;
dev_dbg(power->dev, "setting input current limit reg to %d (%d uA), requested %d uA",
reg, power->axp_data->curr_lim_table[reg], intval);
staticint axp717_usb_power_set_input_current_limit(struct axp20x_usb_power *power, int intval)
{ int tmp;
/* Minimum value of 100mA and maximum value of 3.25A*/ if (intval < 100000 || intval > 3250000) return -EINVAL;
if (power->max_input_cur && (intval > power->max_input_cur)) {
dev_warn(power->dev, "requested current %d clamped to max current %d\n",
intval, power->max_input_cur);
intval = power->max_input_cur;
}
/* Minimum value of 100mA with step size of 50mA. */
tmp = (intval - 100000) / 50000; return regmap_update_bits(power->regmap,
AXP717_INPUT_CUR_LIMIT_CTRL,
AXP717_INPUT_CUR_LIMIT_MASK, tmp);
}
#ifdef CONFIG_PM_SLEEP staticint axp20x_usb_power_suspend(struct device *dev)
{ struct axp20x_usb_power *power = dev_get_drvdata(dev); int i = 0;
/* *AllowwakeviaVBUS_PLUGINonly. * *AsnestedthreadedIRQsarenotautomaticallydisabledduring *suspend,wemustexplicitlydisabletheremainderoftheIRQs.
*/ if (device_may_wakeup(&power->supply->dev))
enable_irq_wake(power->irqs[i++]); while (i < power->num_irqs)
disable_irq(power->irqs[i++]);
return0;
}
staticint axp20x_usb_power_resume(struct device *dev)
{ struct axp20x_usb_power *power = dev_get_drvdata(dev); int i = 0;
if (device_may_wakeup(&power->supply->dev))
disable_irq_wake(power->irqs[i++]); while (i < power->num_irqs)
enable_irq(power->irqs[i++]);
field = devm_regmap_field_alloc(dev, regmap, fdesc); if (IS_ERR(field)) return PTR_ERR(field);
*fieldp = field; return0;
}
/* Optionally allow users to specify a maximum charging current. */ staticvoid axp20x_usb_power_parse_dt(struct device *dev, struct axp20x_usb_power *power)
{ int ret;
ret = device_property_read_u32(dev, "input-current-limit-microamp",
&power->max_input_cur); if (ret)
dev_dbg(dev, "%s() no input-current-limit specified\n", __func__);
}
power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap,
axp_data->curr_lim_fld); if (IS_ERR(power->curr_lim_fld)) return PTR_ERR(power->curr_lim_fld);
axp20x_usb_power_parse_dt(&pdev->dev, power);
ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,
axp_data->vbus_valid_bit,
&power->vbus_valid_bit); if (ret) return ret;
ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,
axp_data->vbus_mon_bit,
&power->vbus_mon_bit); if (ret) return ret;
ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,
axp_data->usb_bc_en_bit,
&power->usb_bc_en_bit); if (ret) return ret;
ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,
axp_data->usb_bc_det_fld,
&power->usb_bc_det_fld); if (ret) return ret;
ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,
axp_data->vbus_disable_bit,
&power->vbus_disable_bit); if (ret) return ret;
ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect,
axp_data->axp20x_read_vbus); if (ret) return ret;
if (power->vbus_mon_bit) { /* Enable vbus valid checking */
ret = regmap_field_write(power->vbus_mon_bit, 1); if (ret) return ret;
if (IS_ENABLED(CONFIG_AXP20X_ADC))
ret = axp_data->axp20x_cfg_iio_chan(pdev, power); else
ret = axp_data->axp20x_cfg_adc_reg(power);
if (ret) return ret;
}
if (power->usb_bc_en_bit) { /* Enable USB Battery Charging specification detection */
ret = regmap_field_write(power->usb_bc_en_bit, 1); if (ret) return ret;
}
power->supply = devm_power_supply_register(&pdev->dev,
axp_data->power_desc,
&psy_cfg); if (IS_ERR(power->supply)) return PTR_ERR(power->supply);
/* Request irqs after registering, as irqs may trigger immediately */ for (i = 0; i < axp_data->num_irq_names; i++) {
irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]); if (irq < 0) return irq;
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.