Lines Matching +full:ocv +full:- +full:capacity

1 // SPDX-License-Identifier: GPL-2.0-only
3 * axp288_fuel_gauge.c - Xpower AXP288 PMIC Fuel Gauge Driver
5 * Copyright (C) 2020-2021 Andrejus Basovas <xxx@yyy.tld>
6 * Copyright (C) 2016-2021 Hans de Goede <hdegoede@redhat.com>
136 int ocv; member
162 ret = regmap_read(info->regmap, reg, &val); in fuel_gauge_reg_readb()
164 dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); in fuel_gauge_reg_readb()
175 ret = regmap_write(info->regmap, reg, (unsigned int)val); in fuel_gauge_reg_writeb()
178 dev_err(info->dev, "Error writing reg 0x%02x err: %d\n", reg, ret); in fuel_gauge_reg_writeb()
188 ret = regmap_bulk_read(info->regmap, reg, buf, 2); in fuel_gauge_read_15bit_word()
190 dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); in fuel_gauge_read_15bit_word()
196 dev_err(info->dev, "Error reg 0x%02x contents not valid\n", reg); in fuel_gauge_read_15bit_word()
197 return -ENXIO; in fuel_gauge_read_15bit_word()
208 ret = regmap_bulk_read(info->regmap, reg, buf, 2); in fuel_gauge_read_12bit_word()
210 dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); in fuel_gauge_read_12bit_word()
214 /* 12-bit data values have upper 8 bits in buf[0], lower 4 in buf[1] */ in fuel_gauge_read_12bit_word()
222 if (info->valid && time_before(jiffies, info->last_updated + AXP288_REG_UPDATE_INTERVAL)) in fuel_gauge_update_registers()
225 dev_dbg(info->dev, "Fuel Gauge updating register values...\n"); in fuel_gauge_update_registers()
234 info->pwr_stat = ret; in fuel_gauge_update_registers()
242 info->fg_res = ret; in fuel_gauge_update_registers()
244 ret = iio_read_channel_raw(info->iio_channel[BAT_VOLT], &info->bat_volt); in fuel_gauge_update_registers()
251 info->ocv = ret; in fuel_gauge_update_registers()
256 if (info->pwr_stat & PS_STAT_BAT_CHRG_DIR) { in fuel_gauge_update_registers()
257 info->d_curr = 0; in fuel_gauge_update_registers()
258 ret = iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], &info->c_curr); in fuel_gauge_update_registers()
262 info->c_curr = 0; in fuel_gauge_update_registers()
263 ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &info->d_curr); in fuel_gauge_update_registers()
271 info->fg_cc_mtr1 = ret; in fuel_gauge_update_registers()
276 info->fg_des_cap1 = ret; in fuel_gauge_update_registers()
279 info->last_updated = jiffies; in fuel_gauge_update_registers()
280 info->valid = 1; in fuel_gauge_update_registers()
289 int pwr_stat = info->pwr_stat; in fuel_gauge_get_status()
290 int fg_res = info->fg_res; in fuel_gauge_get_status()
291 int curr = info->d_curr; in fuel_gauge_get_status()
293 /* Report full if Vbus is valid and the reported capacity is 100% */ in fuel_gauge_get_status()
302 info->status = POWER_SUPPLY_STATUS_FULL; in fuel_gauge_get_status()
307 * Sometimes the charger turns itself off before fg-res reaches 100%. in fuel_gauge_get_status()
308 * When this happens the AXP288 reports a not-charging status and in fuel_gauge_get_status()
315 info->status = POWER_SUPPLY_STATUS_FULL; in fuel_gauge_get_status()
321 info->status = POWER_SUPPLY_STATUS_CHARGING; in fuel_gauge_get_status()
323 info->status = POWER_SUPPLY_STATUS_DISCHARGING; in fuel_gauge_get_status()
328 int vocv = VOLTAGE_FROM_ADC(info->ocv); in fuel_gauge_battery_health()
331 if (vocv > info->max_volt) in fuel_gauge_battery_health()
346 mutex_lock(&info->lock); in fuel_gauge_get_property()
355 val->intval = info->status; in fuel_gauge_get_property()
358 val->intval = fuel_gauge_battery_health(info); in fuel_gauge_get_property()
361 value = VOLTAGE_FROM_ADC(info->bat_volt); in fuel_gauge_get_property()
362 val->intval = PROP_VOLT(value); in fuel_gauge_get_property()
365 value = VOLTAGE_FROM_ADC(info->ocv); in fuel_gauge_get_property()
366 val->intval = PROP_VOLT(value); in fuel_gauge_get_property()
369 if (info->d_curr > 0) in fuel_gauge_get_property()
370 value = -1 * info->d_curr; in fuel_gauge_get_property()
372 value = info->c_curr; in fuel_gauge_get_property()
374 val->intval = PROP_CURR(value); in fuel_gauge_get_property()
377 if (info->pwr_op & CHRG_STAT_BAT_PRESENT) in fuel_gauge_get_property()
378 val->intval = 1; in fuel_gauge_get_property()
380 val->intval = 0; in fuel_gauge_get_property()
383 if (!(info->fg_res & FG_REP_CAP_VALID)) in fuel_gauge_get_property()
384 dev_err(info->dev, "capacity measurement not valid\n"); in fuel_gauge_get_property()
385 val->intval = (info->fg_res & FG_REP_CAP_VAL_MASK); in fuel_gauge_get_property()
388 val->intval = (info->low_cap & 0x0f); in fuel_gauge_get_property()
391 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; in fuel_gauge_get_property()
394 val->intval = info->fg_cc_mtr1 * FG_DES_CAP_RES_LSB; in fuel_gauge_get_property()
397 val->intval = info->fg_des_cap1 * FG_DES_CAP_RES_LSB; in fuel_gauge_get_property()
400 val->intval = PROP_VOLT(info->max_volt); in fuel_gauge_get_property()
403 ret = -EINVAL; in fuel_gauge_get_property()
407 mutex_unlock(&info->lock); in fuel_gauge_get_property()
418 mutex_lock(&info->lock); in fuel_gauge_set_property()
421 if ((val->intval < 0) || (val->intval > 15)) { in fuel_gauge_set_property()
422 ret = -EINVAL; in fuel_gauge_set_property()
425 new_low_cap = info->low_cap; in fuel_gauge_set_property()
427 new_low_cap |= (val->intval & 0xf); in fuel_gauge_set_property()
430 info->low_cap = new_low_cap; in fuel_gauge_set_property()
433 ret = -EINVAL; in fuel_gauge_set_property()
437 mutex_unlock(&info->lock); in fuel_gauge_set_property()
463 if (info->irq[i] == irq) in fuel_gauge_thread_handler()
468 dev_warn(info->dev, "spurious interrupt!!\n"); in fuel_gauge_thread_handler()
474 dev_info(info->dev, "Quit Battery under temperature in work mode IRQ (QWBTU)\n"); in fuel_gauge_thread_handler()
477 dev_info(info->dev, "Battery under temperature in work mode IRQ (WBTU)\n"); in fuel_gauge_thread_handler()
480 dev_info(info->dev, "Quit Battery over temperature in work mode IRQ (QWBTO)\n"); in fuel_gauge_thread_handler()
483 dev_info(info->dev, "Battery over temperature in work mode IRQ (WBTO)\n"); in fuel_gauge_thread_handler()
486 dev_info(info->dev, "Low Batt Warning(2) INTR\n"); in fuel_gauge_thread_handler()
489 dev_info(info->dev, "Low Batt Warning(1) INTR\n"); in fuel_gauge_thread_handler()
492 dev_warn(info->dev, "Spurious Interrupt!!!\n"); in fuel_gauge_thread_handler()
495 mutex_lock(&info->lock); in fuel_gauge_thread_handler()
496 info->valid = 0; /* Force updating of the cached registers */ in fuel_gauge_thread_handler()
497 mutex_unlock(&info->lock); in fuel_gauge_thread_handler()
499 power_supply_changed(info->bat); in fuel_gauge_thread_handler()
507 mutex_lock(&info->lock); in fuel_gauge_external_power_changed()
508 info->valid = 0; /* Force updating of the cached registers */ in fuel_gauge_external_power_changed()
509 mutex_unlock(&info->lock); in fuel_gauge_external_power_changed()
536 /* also match on somewhat unique bios-version */
547 /* also match on somewhat unique bios-version */
585 /* Minix Neo Z83-4 mini PC */
588 DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
614 * Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks
637 ret = regmap_read(info->regmap, AXP20X_CC_CTRL, &val); in axp288_fuel_gauge_read_initial_regs()
641 return -ENODEV; in axp288_fuel_gauge_read_initial_regs()
648 dev_err(info->dev, "axp288 not configured by firmware\n"); in axp288_fuel_gauge_read_initial_regs()
649 return -ENODEV; in axp288_fuel_gauge_read_initial_regs()
657 info->max_volt = 4100; in axp288_fuel_gauge_read_initial_regs()
660 info->max_volt = 4150; in axp288_fuel_gauge_read_initial_regs()
663 info->max_volt = 4200; in axp288_fuel_gauge_read_initial_regs()
666 info->max_volt = 4350; in axp288_fuel_gauge_read_initial_regs()
673 info->pwr_op = ret; in axp288_fuel_gauge_read_initial_regs()
678 info->low_cap = ret; in axp288_fuel_gauge_read_initial_regs()
689 if (!IS_ERR_OR_NULL(info->iio_channel[i])) in axp288_fuel_gauge_release_iio_chans()
690 iio_channel_release(info->iio_channel[i]); in axp288_fuel_gauge_release_iio_chans()
696 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp288_fuel_gauge_probe()
699 [BAT_CHRG_CURR] = "axp288-chrg-curr", in axp288_fuel_gauge_probe()
700 [BAT_D_CURR] = "axp288-chrg-d-curr", in axp288_fuel_gauge_probe()
701 [BAT_VOLT] = "axp288-batt-volt", in axp288_fuel_gauge_probe()
704 struct device *dev = &pdev->dev; in axp288_fuel_gauge_probe()
713 return -ENODEV; in axp288_fuel_gauge_probe()
717 quirks = (unsigned long)dmi_id->driver_data; in axp288_fuel_gauge_probe()
720 return -ENODEV; in axp288_fuel_gauge_probe()
724 return -ENOMEM; in axp288_fuel_gauge_probe()
726 info->dev = dev; in axp288_fuel_gauge_probe()
727 info->regmap = axp20x->regmap; in axp288_fuel_gauge_probe()
728 info->status = POWER_SUPPLY_STATUS_UNKNOWN; in axp288_fuel_gauge_probe()
729 info->valid = 0; in axp288_fuel_gauge_probe()
733 mutex_init(&info->lock); in axp288_fuel_gauge_probe()
739 ret = regmap_irq_get_virq(axp20x->regmap_irqc, pirq); in axp288_fuel_gauge_probe()
743 info->irq[i] = ret; in axp288_fuel_gauge_probe()
749 * lack the device<->channel maps which iio_channel_get will in axp288_fuel_gauge_probe()
752 info->iio_channel[i] = in axp288_fuel_gauge_probe()
754 if (IS_ERR(info->iio_channel[i])) { in axp288_fuel_gauge_probe()
755 ret = PTR_ERR(info->iio_channel[i]); in axp288_fuel_gauge_probe()
758 if (ret == -ENODEV) in axp288_fuel_gauge_probe()
759 ret = -EPROBE_DEFER; in axp288_fuel_gauge_probe()
781 fuel_gauge_desc.num_properties = ARRAY_SIZE(fuel_gauge_props) - 3; in axp288_fuel_gauge_probe()
782 info->bat = devm_power_supply_register(dev, &fuel_gauge_desc, &psy_cfg); in axp288_fuel_gauge_probe()
783 if (IS_ERR(info->bat)) { in axp288_fuel_gauge_probe()
784 ret = PTR_ERR(info->bat); in axp288_fuel_gauge_probe()
790 ret = devm_request_threaded_irq(dev, info->irq[i], NULL, in axp288_fuel_gauge_probe()
794 return dev_err_probe(dev, ret, "requesting IRQ %d\n", info->irq[i]); in axp288_fuel_gauge_probe()