/* Maximum supported battery voltage (via regs.battery.type) */ int vbat_max; /* Scaling constants for regs.boost.undervolt_limit */ struct { int setpoint; int microvolts_per_bit;
} boost_undervolt; /* Scaling constants for regs.charger.const_curr_sel */ struct { int setpoint;
} const_curr; /* Whether regs.charger.chg_end is inverted */
u8 chg_end_inverted;
};
int vbat_max; int boost_undervolt_setpoint; int boost_undervolt_uv_per_bit; int const_curr_setpoint;
u8 chg_end_inverted;
};
/* * The IP5xxx charger only responds on I2C when it is "awake". The charger is * generally only awake when VIN is powered or when its boost converter is * enabled. Going into shutdown resets all register values. To handle this: * 1) When any bus error occurs, assume the charger has gone into shutdown. * 2) Attempt the initialization sequence on each subsequent register access * until it succeeds.
*/ staticint ip5xxx_read(struct ip5xxx *ip5xxx, struct regmap_field *field, unsignedint *val)
{ int ret;
if (!field) return -EOPNOTSUPP;
ret = regmap_field_read(field, val); if (ret)
ip5xxx->initialized = false;
/* * Disable shutdown under light load. * Enable power on when under load.
*/ if (ip5xxx->regs.boost.light_load_shutdown.enable) {
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.light_load_shutdown.enable, 0); if (ret) return ret;
}
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.load_powerup_en, 1); if (ret) return ret;
/* * Enable shutdown after a long button press (as configured below).
*/
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_enable, 1); if (ret) return ret;
/* * Power on automatically when VIN is removed.
*/
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.vin_pullout_en, 1); if (ret) return ret;
/* * Enable the NTC. * Configure the button for two presses => LED, long press => shutdown.
*/ if (ip5xxx->regs.battery.ntc_dis) {
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.ntc_dis, 0); if (ret) return ret;
}
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.wled_mode, 1); if (ret) return ret;
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_mode, 1); if (ret) return ret;
ip5xxx->initialized = true;
dev_dbg(psy->dev.parent, "Initialized after power on\n");
staticint ip5xxx_battery_get_status(struct ip5xxx *ip5xxx, int *val)
{ unsignedint rval; int ret;
if (!ip5xxx->regs.charger.status) { // Fall-back to Charging Ended bit
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.chg_end, &rval); if (ret) return ret;
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval); if (ret) return ret;
switch (rval) { case IP5XXX_CHG_STAT_IDLE:
*val = POWER_SUPPLY_STATUS_DISCHARGING; break; case IP5XXX_CHG_STAT_TRICKLE: case IP5XXX_CHG_STAT_CONST_CUR: case IP5XXX_CHG_STAT_CONST_VOLT:
*val = POWER_SUPPLY_STATUS_CHARGING; break; case IP5XXX_CHG_STAT_CONST_VOLT_STOP: case IP5XXX_CHG_STAT_FULL:
*val = POWER_SUPPLY_STATUS_FULL; break; case IP5XXX_CHG_STAT_TIMEOUT:
*val = POWER_SUPPLY_STATUS_NOT_CHARGING; break; default: return -EINVAL;
}
return 0;
}
staticint ip5xxx_battery_get_charge_type(struct ip5xxx *ip5xxx, int *val)
{ unsignedint rval; int ret;
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval); if (ret) return ret;
switch (rval) { case IP5XXX_CHG_STAT_IDLE: case IP5XXX_CHG_STAT_CONST_VOLT_STOP: case IP5XXX_CHG_STAT_FULL: case IP5XXX_CHG_STAT_TIMEOUT:
*val = POWER_SUPPLY_CHARGE_TYPE_NONE; break; case IP5XXX_CHG_STAT_TRICKLE:
*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; break; case IP5XXX_CHG_STAT_CONST_CUR: case IP5XXX_CHG_STAT_CONST_VOLT:
*val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; break; default: return -EINVAL;
}
return 0;
}
staticint ip5xxx_battery_get_health(struct ip5xxx *ip5xxx, int *val)
{ unsignedint rval; int ret;
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.timeout, &rval); if (ret) return ret;
if (rval)
*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; else
*val = POWER_SUPPLY_HEALTH_GOOD;
return 0;
}
staticint ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
{ unsignedint rval; int ret;
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.battery.type, &rval); if (ret) return ret;
/* * It is not clear what this will return if * IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN is not set...
*/ switch (rval) { case IP5XXX_BAT_TYPE_4_2V:
*val = 4200000; break; case IP5XXX_BAT_TYPE_4_3V:
*val = 4300000; break; case IP5XXX_BAT_TYPE_4_35V:
*val = 4350000; break; case IP5XXX_BAT_TYPE_4_4V:
*val = 4400000; break; default: return -EINVAL;
}
return 0;
}
staticint ip5xxx_battery_read_adc(struct ip5xxx *ip5xxx, struct ip5xxx_battery_adc_regs *regs, int *val)
{ unsignedint hi, lo; int ret;
ret = ip5xxx_read(ip5xxx, regs->low, &lo); if (ret) return ret;
ret = ip5xxx_read(ip5xxx, regs->high, &hi); if (ret) return ret;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = 100000 * 0x1f; return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax); if (ret) return ret;
ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.const_volt_sel, &rval); if (ret) return ret;
val->intval = vmax + 14000 * rval; return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax); if (ret) return ret;
val->intval = vmax + 14000 * 3; return 0;
default: return -EINVAL;
}
}
staticint ip5xxx_battery_set_voltage_max(struct ip5xxx *ip5xxx, int val)
{ unsignedint rval; int ret;
if (val > ip5xxx->vbat_max) return -EINVAL;
switch (val) { case 4200000:
rval = IP5XXX_BAT_TYPE_4_2V; break; case 4300000:
rval = IP5XXX_BAT_TYPE_4_3V; break; case 4350000:
rval = IP5XXX_BAT_TYPE_4_35V; break; case 4400000:
rval = IP5XXX_BAT_TYPE_4_4V; break; default: return -EINVAL;
}
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.type, rval); if (ret) return ret;
/* Don't try to auto-detect battery type, even if the IC could */ if (ip5xxx->regs.battery.vset_en) {
ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.vset_en, 1); if (ret) return ret;
}
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.