/* * The tables below provide a 2-way mapping for the value that goes in * the register field and the real-world value that it represents. * The index of the array is the value that goes in the register; the * number at that index in the array is the real-world value that it * represents.
*/
/* * The FAULT register is latched by the bq24190 (except for NTC_FAULT) * so the first read after a fault returns the latched value and subsequent * reads return the current value. In order to return the fault status * to the user, have the interrupt handler save the reg's value and retrieve * it in the appropriate health/status routine.
*/ struct bq24190_dev_info { struct i2c_client *client; struct device *dev; struct extcon_dev *edev; struct power_supply *charger; struct power_supply *battery; struct delayed_work input_current_limit_work; char model_name[I2C_NAME_SIZE]; bool initialized; bool irq_event; bool otg_vbus_enabled; int charge_type;
u16 sys_min;
u16 iprechg;
u16 iterm;
u32 ichg;
u32 ichg_max;
u32 vreg;
u32 vreg_max; struct mutex f_reg_lock;
u8 f_reg;
u8 ss_reg;
u8 watchdog; conststruct bq24190_chip_info *info;
};
struct bq24190_chip_info { int ichg_array_size; #ifdef CONFIG_REGULATOR conststruct regulator_desc *vbus_desc; #endif int (*check_chip)(struct bq24190_dev_info *bdi); int (*set_chg_config)(struct bq24190_dev_info *bdi, const u8 chg_config); int (*set_otg_vbus)(struct bq24190_dev_info *bdi, bool enable);
u8 ntc_fault_mask; int (*get_ntc_status)(const u8 value);
};
/* * Return the index in 'tbl' of greatest value that is less than or equal to * 'val'. The index range returned is 0 to 'tbl_size' - 1. Assumes that * the values in 'tbl' are sorted from smallest to largest and 'tbl_size' * is less than 2^8.
*/ static u8 bq24190_find_idx(constint tbl[], int tbl_size, int v)
{ int i;
for (i = 1; i < tbl_size; i++) if (v < tbl[i]) break;
#ifdef CONFIG_SYSFS /* * There are a numerous options that are configurable on the bq24190 * that go well beyond what the power_supply properties provide access to. * Provide sysfs access to them so they can be examined and possibly modified * on the fly. They will be provided for the charger power_supply object only * and will be prefixed by 'f_' to make them easier to recognize.
*/
/* * According to the "Host Mode and default Mode" section of the * manual, a write to any register causes the bq24190 to switch * from default mode to host mode. It will switch back to default * mode after a WDT timeout unless the WDT is turned off as well. * So, by simply turning off the WDT, we accomplish both with the * same write.
*/
v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
ret = bq24190_write(bdi, BQ24190_REG_CTTC, v); if (ret < 0) return ret;
if (bdi->sys_min) {
v = bdi->sys_min / 100 - 30; // manual section 9.5.1.2, table 9
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_SYS_MIN_MASK,
BQ24190_REG_POC_SYS_MIN_SHIFT,
v); if (ret < 0) return ret;
}
if (bdi->iprechg) {
v = bdi->iprechg / 128 - 1; // manual section 9.5.1.4, table 11
ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC,
BQ24190_REG_PCTCC_IPRECHG_MASK,
BQ24190_REG_PCTCC_IPRECHG_SHIFT,
v); if (ret < 0) return ret;
}
if (bdi->iterm) {
v = bdi->iterm / 128 - 1; // manual section 9.5.1.4, table 11
ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC,
BQ24190_REG_PCTCC_ITERM_MASK,
BQ24190_REG_PCTCC_ITERM_SHIFT,
v); if (ret < 0) return ret;
}
if (bdi->ichg) {
ret = bq24190_set_field_val(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_ICHG_MASK,
BQ24190_REG_CCC_ICHG_SHIFT,
bq24190_ccc_ichg_values,
bdi->info->ichg_array_size,
bdi->ichg); if (ret < 0) return ret;
}
if (bdi->vreg) {
ret = bq24190_set_field_val(bdi, BQ24190_REG_CVC,
BQ24190_REG_CVC_VREG_MASK,
BQ24190_REG_CVC_VREG_SHIFT,
bq24190_cvc_vreg_values,
ARRAY_SIZE(bq24190_cvc_vreg_values),
bdi->vreg); if (ret < 0) return ret;
}
/* * This prop. can be passed on device instantiation from platform code: * struct property_entry pe[] = * { PROPERTY_ENTRY_BOOL("disable-reset"), ... }; * struct i2c_board_info bi = * { .type = "bq24190", .addr = 0x6b, .properties = pe, .irq = irq }; * struct i2c_adapter ad = { ... }; * i2c_add_adapter(&ad); * i2c_new_client_device(&ad, &bi);
*/ if (device_property_read_bool(bdi->dev, "disable-reset")) return 0;
/* Reset the registers */
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_RESET_MASK,
BQ24190_REG_POC_RESET_SHIFT,
0x1); if (ret < 0) return ret;
/* Reset bit will be cleared by hardware so poll until it is */ do {
ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_RESET_MASK,
BQ24190_REG_POC_RESET_SHIFT,
&v); if (ret < 0) return ret;
if (v == 0) return 0;
usleep_range(100, 200);
} while (--limit);
return -EIO;
}
/* Charger power supply property routines */
staticint bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi, union power_supply_propval *val)
{
u8 v; int type, ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_CHG_CONFIG_MASK,
BQ24190_REG_POC_CHG_CONFIG_SHIFT,
&v); if (ret < 0) return ret;
/* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */ if (!v) {
type = POWER_SUPPLY_CHARGE_TYPE_NONE;
} else {
ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_FORCE_20PCT_MASK,
BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
&v); if (ret < 0) return ret;
type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
POWER_SUPPLY_CHARGE_TYPE_FAST;
}
/* * According to the "Termination when REG02[0] = 1" section of * the bq24190 manual, the trickle charge could be less than the * termination current so it recommends turning off the termination * function. * * Note: AFAICT from the datasheet, the user will have to manually * turn off the charging when in 20% mode. If its not turned off, * there could be battery damage. So, use this mode at your own risk.
*/ switch (val->intval) { case POWER_SUPPLY_CHARGE_TYPE_NONE:
chg_config = 0x0; break; case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
chg_config = 0x1;
force_20pct = 0x1;
en_term = 0x0; break; case POWER_SUPPLY_CHARGE_TYPE_FAST:
chg_config = 0x1;
force_20pct = 0x0;
en_term = 0x1; break; default: return -EINVAL;
}
bdi->charge_type = val->intval; /* * If the 5V Vbus boost regulator is enabled delay setting * the charge-type until its gets disabled.
*/ if (bdi->otg_vbus_enabled) return 0;
if (chg_config) { /* Enabling the charger */
ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_FORCE_20PCT_MASK,
BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
force_20pct); if (ret < 0) return ret;
ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
BQ24190_REG_CTTC_EN_TERM_MASK,
BQ24190_REG_CTTC_EN_TERM_SHIFT,
en_term); if (ret < 0) return ret;
}
staticint bq24190_charger_get_ntc_status(u8 value)
{ int health;
switch (value >> BQ24190_REG_F_NTC_FAULT_SHIFT & 0x7) { case 0x1: /* TS1 Cold */ case 0x3: /* TS2 Cold */ case 0x5: /* Both Cold */
health = POWER_SUPPLY_HEALTH_COLD; break; case 0x2: /* TS1 Hot */ case 0x4: /* TS2 Hot */ case 0x6: /* Both Hot */
health = POWER_SUPPLY_HEALTH_OVERHEAT; break; default:
health = POWER_SUPPLY_HEALTH_UNKNOWN;
}
return health;
}
staticint bq24296_charger_get_ntc_status(u8 value)
{ int health;
switch (value >> BQ24296_REG_F_NTC_FAULT_SHIFT & 0x3) { case 0x0: /* Normal */
health = POWER_SUPPLY_HEALTH_GOOD; break; case 0x1: /* Hot */
health = POWER_SUPPLY_HEALTH_OVERHEAT; break; case 0x2: /* Cold */
health = POWER_SUPPLY_HEALTH_COLD; break; default:
health = POWER_SUPPLY_HEALTH_UNKNOWN;
}
return health;
}
staticint bq24190_charger_get_health(struct bq24190_dev_info *bdi, union power_supply_propval *val)
{
u8 v; int health;
mutex_lock(&bdi->f_reg_lock);
v = bdi->f_reg;
mutex_unlock(&bdi->f_reg_lock);
if (v & bdi->info->ntc_fault_mask) {
health = bdi->info->get_ntc_status(v);
} elseif (v & BQ24190_REG_F_BAT_FAULT_MASK) {
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} elseif (v & BQ24190_REG_F_CHRG_FAULT_MASK) { switch (v >> BQ24190_REG_F_CHRG_FAULT_SHIFT & 0x3) { case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */ /* * This could be over-voltage or under-voltage * and there's no way to tell which. Instead * of looking foolish and returning 'OVERVOLTAGE' * when its really under-voltage, just return * 'UNSPEC_FAILURE'.
*/
health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; break; case 0x2: /* Thermal Shutdown */
health = POWER_SUPPLY_HEALTH_OVERHEAT; break; case 0x3: /* Charge Safety Timer Expiration */
health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; break; default: /* prevent compiler warning */
health = -1;
}
} elseif (v & BQ24190_REG_F_BOOST_FAULT_MASK) { /* * This could be over-current or over-voltage but there's * no way to tell which. Return 'OVERVOLTAGE' since there * isn't an 'OVERCURRENT' value defined that we can return * even if it was over-current.
*/
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else {
health = POWER_SUPPLY_HEALTH_GOOD;
}
val->intval = health;
return 0;
}
staticint bq24190_charger_get_online(struct bq24190_dev_info *bdi, union power_supply_propval *val)
{
u8 pg_stat, batfet_disable; int ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
BQ24190_REG_SS_PG_STAT_MASK,
BQ24190_REG_SS_PG_STAT_SHIFT, &pg_stat); if (ret < 0) return ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
BQ24190_REG_MOC_BATFET_DISABLE_MASK,
BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable); if (ret < 0) return ret;
staticint bq24190_charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); int ret;
dev_dbg(bdi->dev, "prop: %d\n", psp);
ret = pm_runtime_resume_and_get(bdi->dev); if (ret < 0) return ret;
switch (psp) { case POWER_SUPPLY_PROP_CHARGE_TYPE: case POWER_SUPPLY_PROP_CHARGE_TYPES:
ret = bq24190_charger_get_charge_type(bdi, val); break; case POWER_SUPPLY_PROP_HEALTH:
ret = bq24190_charger_get_health(bdi, val); break; case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_charger_get_online(bdi, val); break; case POWER_SUPPLY_PROP_STATUS:
ret = bq24190_charger_get_status(bdi, val); break; case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_charger_get_temp_alert_max(bdi, val); break; case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
ret = bq24190_charger_get_precharge(bdi, val); break; case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
ret = bq24190_charger_get_charge_term(bdi, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = bq24190_charger_get_current(bdi, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = bdi->ichg_max;
ret = 0; break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = bq24190_charger_get_voltage(bdi, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
val->intval = bdi->vreg_max;
ret = 0; break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = bq24190_charger_get_iinlimit(bdi, val); break; case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
ret = 0; break; case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = bdi->model_name;
ret = 0; break; case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = BQ24190_MANUFACTURER;
ret = 0; break; default:
ret = -ENODATA;
}
ret = pm_runtime_resume_and_get(bdi->dev); if (ret < 0) return ret;
switch (psp) { case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_charger_set_online(bdi, val); break; case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_charger_set_temp_alert_max(bdi, val); break; case POWER_SUPPLY_PROP_CHARGE_TYPE: case POWER_SUPPLY_PROP_CHARGE_TYPES:
ret = bq24190_charger_set_charge_type(bdi, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = bq24190_charger_set_current(bdi, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = bq24190_charger_set_voltage(bdi, val); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = bq24190_charger_set_iinlimit(bdi, val); break; default:
ret = -EINVAL;
}
pm_runtime_put_autosuspend(bdi->dev);
return ret;
}
staticint bq24190_charger_property_is_writeable(struct power_supply *psy, enum power_supply_property psp)
{ switch (psp) { case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: case POWER_SUPPLY_PROP_CHARGE_TYPE: case POWER_SUPPLY_PROP_CHARGE_TYPES: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: return 1; default: return 0;
}
}
staticvoid bq24190_input_current_limit_work(struct work_struct *work)
{ struct bq24190_dev_info *bdi =
container_of(work, struct bq24190_dev_info,
input_current_limit_work.work); union power_supply_propval val; int ret;
ret = power_supply_get_property_from_supplier(bdi->charger,
POWER_SUPPLY_PROP_CURRENT_MAX,
&val); if (ret) return;
/* Sync the input-current-limit with our parent supply (if we have one) */ staticvoid bq24190_charger_external_power_changed(struct power_supply *psy)
{ struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
/* * The Power-Good detection may take up to 220ms, sometimes * the external charger detection is quicker, and the bq24190 will * reset to iinlim based on its own charger detection (which is not * hooked up when using external charger detection) resulting in a * too low default 500mA iinlim. Delay setting the input-current-limit * for 300ms to avoid this.
*/
queue_delayed_work(system_wq, &bdi->input_current_limit_work,
msecs_to_jiffies(300));
}
ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg); if (ret < 0) return ret;
/* * The battery must be discharging when any of these are true: * - there is no good power source; * - there is a charge fault. * Could also be discharging when in "supplement mode" but * there is no way to tell when its in that mode.
*/ if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
status = POWER_SUPPLY_STATUS_DISCHARGING;
} else {
ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
switch (ss_reg) { case 0x0: /* Not Charging */
status = POWER_SUPPLY_STATUS_NOT_CHARGING; break; case 0x1: /* Pre-charge */ case 0x2: /* Fast Charging */
status = POWER_SUPPLY_STATUS_CHARGING; break; case 0x3: /* Charge Termination Done */
status = POWER_SUPPLY_STATUS_FULL; break; default:
ret = -EIO;
}
}
if (!ret)
val->intval = status;
return ret;
}
staticint bq24190_battery_get_health(struct bq24190_dev_info *bdi, union power_supply_propval *val)
{
u8 v; int health;
mutex_lock(&bdi->f_reg_lock);
v = bdi->f_reg;
mutex_unlock(&bdi->f_reg_lock);
if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else {
v &= bdi->info->ntc_fault_mask;
health = v ? bdi->info->get_ntc_status(v) : POWER_SUPPLY_HEALTH_GOOD;
}
val->intval = health; return 0;
}
staticint bq24190_battery_get_online(struct bq24190_dev_info *bdi, union power_supply_propval *val)
{
u8 batfet_disable; int ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
BQ24190_REG_MOC_BATFET_DISABLE_MASK,
BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable); if (ret < 0) return ret;
staticint bq24190_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); int ret;
dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
dev_dbg(bdi->dev, "prop: %d\n", psp);
ret = pm_runtime_resume_and_get(bdi->dev); if (ret < 0) return ret;
switch (psp) { case POWER_SUPPLY_PROP_STATUS:
ret = bq24190_battery_get_status(bdi, val); break; case POWER_SUPPLY_PROP_HEALTH:
ret = bq24190_battery_get_health(bdi, val); break; case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_battery_get_online(bdi, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: /* Could be Li-on or Li-polymer but no way to tell which */
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
ret = 0; break; case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_battery_get_temp_alert_max(bdi, val); break; case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
ret = 0; break; default:
ret = -ENODATA;
}
dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
dev_dbg(bdi->dev, "prop: %d\n", psp);
ret = pm_runtime_resume_and_get(bdi->dev); if (ret < 0) return ret;
switch (psp) { case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_battery_set_online(bdi, val); break; case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_battery_set_temp_alert_max(bdi, val); break; default:
ret = -EINVAL;
}
pm_runtime_put_autosuspend(bdi->dev);
return ret;
}
staticint bq24190_battery_property_is_writeable(struct power_supply *psy, enum power_supply_property psp)
{ int ret;
switch (psp) { case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = 1; break; default:
ret = 0;
}
otg_enabled = !!(ss_reg & BQ24190_REG_SS_VBUS_STAT_MASK);
ret = extcon_set_state_sync(bdi->edev, EXTCON_USB, otg_enabled); if (ret < 0)
dev_err(bdi->dev, "Can't set extcon state to %d: %d\n",
otg_enabled, ret);
if (ss_reg != bdi->ss_reg) { /* * The device is in host mode so when PG_STAT goes from 1->0 * (i.e., power removed) HIZ needs to be disabled.
*/ if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
BQ24190_REG_ISC_EN_HIZ_MASK,
BQ24190_REG_ISC_EN_HIZ_SHIFT,
0); if (ret < 0)
dev_err(bdi->dev, "Can't access ISC reg: %d\n",
ret);
}
if (device_property_read_u32(bdi->dev, s, &v) == 0) {
v /= 1000; if (v >= BQ24190_REG_POC_SYS_MIN_MIN
&& v <= BQ24190_REG_POC_SYS_MIN_MAX)
bdi->sys_min = v; else
dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v);
}
if (!power_supply_get_battery_info(bdi->charger, &info)) {
v = info->precharge_current_ua / 1000; if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN
&& v <= BQ24190_REG_PCTCC_IPRECHG_MAX)
bdi->iprechg = v; else
dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n",
v);
v = info->charge_term_current_ua / 1000; if (v >= BQ24190_REG_PCTCC_ITERM_MIN
&& v <= BQ24190_REG_PCTCC_ITERM_MAX)
bdi->iterm = v; else
dev_warn(bdi->dev, "invalid value for battery:charge-term-current-microamp: %d\n",
v);
/* These are optional, so no warning when not set */
v = info->constant_charge_current_max_ua; if (v >= bq24190_ccc_ichg_values[0] && v <= bdi->ichg_max)
bdi->ichg = bdi->ichg_max = v;
v = info->constant_charge_voltage_max_uv; if (v >= bq24190_cvc_vreg_values[0] && v <= bdi->vreg_max)
bdi->vreg = bdi->vreg_max = v;
/* the battery class is deprecated and will be removed. */ /* in the interim, this property hides it. */ if (!device_property_read_bool(dev, "omit-battery-class")) {
battery_cfg.drv_data = bdi;
bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
&battery_cfg); if (IS_ERR(bdi->battery)) {
dev_err(dev, "Can't register battery\n");
ret = PTR_ERR(bdi->battery); goto out_charger;
}
}
ret = bq24190_get_config(bdi); if (ret < 0) {
dev_err(dev, "Can't get devicetree config\n"); goto out_charger;
}
ret = bq24190_hw_init(bdi); if (ret < 0) {
dev_err(dev, "Hardware init failed\n"); goto out_charger;
}
ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg); if (ret < 0) goto out_charger;
bdi->initialized = true;
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq24190_irq_handler_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "bq24190-charger", bdi); if (ret < 0) {
dev_err(dev, "Can't set up irq handler\n"); goto out_charger;
}
ret = bq24190_register_vbus_regulator(bdi); if (ret < 0) goto out_charger;
enable_irq_wake(client->irq);
pm_runtime_put_autosuspend(dev);
return 0;
out_charger: if (!IS_ERR_OR_NULL(bdi->battery))
power_supply_unregister(bdi->battery);
power_supply_unregister(bdi->charger);
if (error >= 0) {
pm_runtime_put_autosuspend(bdi->dev);
}
/* Things may have changed while suspended so alert upper layer */
power_supply_changed(bdi->charger); if (bdi->battery)
power_supply_changed(bdi->battery);
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.