13d0407baSopenharmony_ci/* 23d0407baSopenharmony_ci * rk817 battery driver 33d0407baSopenharmony_ci * 43d0407baSopenharmony_ci * Copyright (C) 2018 Rockchip Corporation 53d0407baSopenharmony_ci * 63d0407baSopenharmony_ci * This program is free software; you can redistribute it and/or modify 73d0407baSopenharmony_ci * it under the terms of the GNU General Public License as published by 83d0407baSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 93d0407baSopenharmony_ci * (at your option) any later version. 103d0407baSopenharmony_ci * 113d0407baSopenharmony_ci * This program is distributed in the hope that it will be useful, 123d0407baSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 133d0407baSopenharmony_ci * MERCHANTABILITY or FITNESS FR A PARTICULAR PURPOSE. See the 143d0407baSopenharmony_ci * GNU General Public License for more details. 153d0407baSopenharmony_ci * 163d0407baSopenharmony_ci */ 173d0407baSopenharmony_ci 183d0407baSopenharmony_ci#define pr_fmt(fmt) "rk817-bat: " fmt 193d0407baSopenharmony_ci 203d0407baSopenharmony_ci#include <linux/delay.h> 213d0407baSopenharmony_ci#include <linux/extcon.h> 223d0407baSopenharmony_ci#include <linux/fb.h> 233d0407baSopenharmony_ci#include <linux/gpio.h> 243d0407baSopenharmony_ci#include <linux/iio/consumer.h> 253d0407baSopenharmony_ci#include <linux/iio/iio.h> 263d0407baSopenharmony_ci#include <linux/irq.h> 273d0407baSopenharmony_ci#include <linux/jiffies.h> 283d0407baSopenharmony_ci#include <linux/mfd/rk808.h> 293d0407baSopenharmony_ci#include <linux/module.h> 303d0407baSopenharmony_ci#include <linux/of_device.h> 313d0407baSopenharmony_ci#include <linux/of_gpio.h> 323d0407baSopenharmony_ci#include <linux/platform_device.h> 333d0407baSopenharmony_ci#include <linux/power_supply.h> 343d0407baSopenharmony_ci#include <linux/power/rk_usbbc.h> 353d0407baSopenharmony_ci#include <linux/regmap.h> 363d0407baSopenharmony_ci#include <linux/rk_keys.h> 373d0407baSopenharmony_ci#include <linux/rtc.h> 383d0407baSopenharmony_ci#include <linux/timer.h> 393d0407baSopenharmony_ci#include <linux/wakelock.h> 403d0407baSopenharmony_ci#include <linux/workqueue.h> 413d0407baSopenharmony_ci 423d0407baSopenharmony_cistatic int dbg_enable; 433d0407baSopenharmony_ci 443d0407baSopenharmony_cimodule_param_named(dbg_level, dbg_enable, int, 0644); 453d0407baSopenharmony_ci 463d0407baSopenharmony_ci#define DBG(args...) \ 473d0407baSopenharmony_ci do { \ 483d0407baSopenharmony_ci if (dbg_enable) { \ 493d0407baSopenharmony_ci pr_info(args); \ 503d0407baSopenharmony_ci } \ 513d0407baSopenharmony_ci } while (0) 523d0407baSopenharmony_ci 533d0407baSopenharmony_ci#define BAT_INFO(fmt, args...) pr_info(fmt, ##args) 543d0407baSopenharmony_ci 553d0407baSopenharmony_ci#define DRIVER_VERSION "1.00" 563d0407baSopenharmony_ci#define SFT_SET_KB 1 573d0407baSopenharmony_ci 583d0407baSopenharmony_ci#define DIV(x) ((x) ? (x) : 1) 593d0407baSopenharmony_ci#define ENABLE 0x01 603d0407baSopenharmony_ci#define DISABLE 0x00 613d0407baSopenharmony_ci#define MAX_INTERPOLATE 1000 623d0407baSopenharmony_ci#define MAX_PERCENTAGE 100 633d0407baSopenharmony_ci#define MAX_INT 0x7FFF 643d0407baSopenharmony_ci 653d0407baSopenharmony_ci/* RK818_GGCON */ 663d0407baSopenharmony_ci#define OCV_SAMP_MIN_MSK 0x0c 673d0407baSopenharmony_ci#define OCV_SAMP_8MIN (0x00 << 2) 683d0407baSopenharmony_ci 693d0407baSopenharmony_ci#define ADC_CAL_8MIN 0x00 703d0407baSopenharmony_ci#define RELAX_VOL12_UPD_MSK (RELAX_VOL1_UPD | RELAX_VOL2_UPD) 713d0407baSopenharmony_ci#define MINUTE(x) \ 723d0407baSopenharmony_ci ((x) * 60) 733d0407baSopenharmony_ci 743d0407baSopenharmony_ci#define ADC_TO_CURRENT(adc_value, samp_res) \ 753d0407baSopenharmony_ci (adc_value * 172 / 1000 / samp_res) 763d0407baSopenharmony_ci#define CURRENT_TO_ADC(current, samp_res) \ 773d0407baSopenharmony_ci (current * 1000 * samp_res / 172) 783d0407baSopenharmony_ci 793d0407baSopenharmony_ci#define ADC_TO_CAPACITY(adc_value, samp_res) \ 803d0407baSopenharmony_ci (adc_value / 1000 * 172 / 3600 / samp_res) 813d0407baSopenharmony_ci#define CAPACITY_TO_ADC(capacity, samp_res) \ 823d0407baSopenharmony_ci (capacity * samp_res * 3600 / 172 * 1000) 833d0407baSopenharmony_ci 843d0407baSopenharmony_ci#define ADC_TO_CAPACITY_UAH(adc_value, samp_res) \ 853d0407baSopenharmony_ci (adc_value / 3600 * 172 / samp_res) 863d0407baSopenharmony_ci#define ADC_TO_CAPACITY_MAH(adc_value, samp_res) \ 873d0407baSopenharmony_ci (adc_value / 1000 * 172 / 3600 / samp_res) 883d0407baSopenharmony_ci 893d0407baSopenharmony_ci/* THREAML_REG */ 903d0407baSopenharmony_ci#define TEMP_85C (0x00 << 2) 913d0407baSopenharmony_ci#define TEMP_95C (0x01 << 2) 923d0407baSopenharmony_ci#define TEMP_105C (0x02 << 2) 933d0407baSopenharmony_ci#define TEMP_115C (0x03 << 2) 943d0407baSopenharmony_ci 953d0407baSopenharmony_ci#define ZERO_LOAD_LVL1 1400 963d0407baSopenharmony_ci#define ZERO_LOAD_LVL2 600 973d0407baSopenharmony_ci 983d0407baSopenharmony_ci/* zero algorithm */ 993d0407baSopenharmony_ci#define PWROFF_THRESD 3400 1003d0407baSopenharmony_ci#define MIN_ZERO_DSOC_ACCURACY 10 /*0.01%*/ 1013d0407baSopenharmony_ci#define MIN_ZERO_OVERCNT 100 1023d0407baSopenharmony_ci#define MIN_ACCURACY 1 1033d0407baSopenharmony_ci#define DEF_PWRPATH_RES 50 1043d0407baSopenharmony_ci#define WAIT_DSOC_DROP_SEC 15 1053d0407baSopenharmony_ci#define WAIT_SHTD_DROP_SEC 30 1063d0407baSopenharmony_ci#define MIN_ZERO_GAP_XSOC1 10 1073d0407baSopenharmony_ci#define MIN_ZERO_GAP_XSOC2 5 1083d0407baSopenharmony_ci#define MIN_ZERO_GAP_XSOC3 3 1093d0407baSopenharmony_ci#define MIN_ZERO_GAP_CALIB 5 1103d0407baSopenharmony_ci 1113d0407baSopenharmony_ci#define ADC_CALIB_THRESHOLD 4 1123d0407baSopenharmony_ci#define ADC_CALIB_LMT_MIN 3 1133d0407baSopenharmony_ci#define ADC_CALIB_CNT 5 1143d0407baSopenharmony_ci 1153d0407baSopenharmony_ci/* default param */ 1163d0407baSopenharmony_ci#define DEFAULT_BAT_RES 135 1173d0407baSopenharmony_ci#define DEFAULT_SLP_ENTER_CUR 300 1183d0407baSopenharmony_ci#define DEFAULT_SLP_EXIT_CUR 300 1193d0407baSopenharmony_ci#define DEFAULT_SLP_FILTER_CUR 100 1203d0407baSopenharmony_ci#define DEFAULT_PWROFF_VOL_THRESD 3400 1213d0407baSopenharmony_ci#define DEFAULT_MONITOR_SEC 5 1223d0407baSopenharmony_ci#define DEFAULT_ALGR_VOL_THRESD1 3850 1233d0407baSopenharmony_ci#define DEFAULT_ALGR_VOL_THRESD2 3950 1243d0407baSopenharmony_ci#define DEFAULT_CHRG_VOL_SEL CHRG_VOL4200MV 1253d0407baSopenharmony_ci#define DEFAULT_CHRG_CUR_SEL CHRG_CUR1400MA 1263d0407baSopenharmony_ci#define DEFAULT_CHRG_CUR_INPUT INPUT_CUR2000MA 1273d0407baSopenharmony_ci#define DEFAULT_POFFSET 42 1283d0407baSopenharmony_ci#define DEFAULT_MAX_SOC_OFFSET 60 1293d0407baSopenharmony_ci#define DEFAULT_FB_TEMP TEMP_115C 1303d0407baSopenharmony_ci#define DEFAULT_ENERGY_MODE 0 1313d0407baSopenharmony_ci#define DEFAULT_ZERO_RESERVE_DSOC 10 1323d0407baSopenharmony_ci#define DEFAULT_SAMPLE_RES 20 1333d0407baSopenharmony_ci 1343d0407baSopenharmony_ci/* sample resistor and division */ 1353d0407baSopenharmony_ci#define SAMPLE_RES_10MR 10 1363d0407baSopenharmony_ci#define SAMPLE_RES_20MR 20 1373d0407baSopenharmony_ci#define SAMPLE_RES_DIV1 1 1383d0407baSopenharmony_ci#define SAMPLE_RES_DIV2 2 1393d0407baSopenharmony_ci 1403d0407baSopenharmony_ci/* sleep */ 1413d0407baSopenharmony_ci#define SLP_CURR_MAX 40 1423d0407baSopenharmony_ci#define SLP_CURR_MIN 6 1433d0407baSopenharmony_ci#define LOW_PWR_SLP_CURR_MAX 20 1443d0407baSopenharmony_ci#define LOW_PWR_SLP_CURR_MIN 1 1453d0407baSopenharmony_ci#define DISCHRG_TIME_STEP1 MINUTE(10) 1463d0407baSopenharmony_ci#define DISCHRG_TIME_STEP2 MINUTE(60) 1473d0407baSopenharmony_ci#define SLP_DSOC_VOL_THRESD 3600 1483d0407baSopenharmony_ci#define REBOOT_PERIOD_SEC 180 1493d0407baSopenharmony_ci#define REBOOT_MAX_CNT 80 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ci#define TIMER_MS_COUNTS 1000 1523d0407baSopenharmony_ci/* fcc */ 1533d0407baSopenharmony_ci#define MIN_FCC 500 1543d0407baSopenharmony_ci#define CAP_INVALID 0x80 1553d0407baSopenharmony_ci 1563d0407baSopenharmony_ci/* virtual params */ 1573d0407baSopenharmony_ci#define VIRTUAL_CURRENT 1000 1583d0407baSopenharmony_ci#define VIRTUAL_VOLTAGE 3888 1593d0407baSopenharmony_ci#define VIRTUAL_SOC 66 1603d0407baSopenharmony_ci#define VIRTUAL_PRESET 1 1613d0407baSopenharmony_ci#define VIRTUAL_TEMPERATURE 188 1623d0407baSopenharmony_ci#define VIRTUAL_STATUS POWER_SUPPLY_STATUS_CHARGING 1633d0407baSopenharmony_ci 1643d0407baSopenharmony_ci#define FINISH_CHRG_CUR1 1000 1653d0407baSopenharmony_ci#define FINISH_CHRG_CUR2 1500 1663d0407baSopenharmony_ci#define FINISH_MAX_SOC_DELAY 20 1673d0407baSopenharmony_ci#define TERM_CHRG_DSOC 88 1683d0407baSopenharmony_ci#define TERM_CHRG_CURR 600 1693d0407baSopenharmony_ci#define TERM_CHRG_K 650 1703d0407baSopenharmony_ci#define SIMULATE_CHRG_INTV 8 1713d0407baSopenharmony_ci#define SIMULATE_CHRG_CURR 400 1723d0407baSopenharmony_ci#define SIMULATE_CHRG_K 1500 1733d0407baSopenharmony_ci#define FULL_CHRG_K 400 1743d0407baSopenharmony_ci 1753d0407baSopenharmony_cienum work_mode { 1763d0407baSopenharmony_ci MODE_ZERO = 0, 1773d0407baSopenharmony_ci MODE_FINISH, 1783d0407baSopenharmony_ci MODE_SMOOTH_CHRG, 1793d0407baSopenharmony_ci MODE_SMOOTH_DISCHRG, 1803d0407baSopenharmony_ci MODE_SMOOTH, 1813d0407baSopenharmony_ci}; 1823d0407baSopenharmony_ci 1833d0407baSopenharmony_cienum charge_status { 1843d0407baSopenharmony_ci CHRG_OFF, 1853d0407baSopenharmony_ci DEAD_CHRG, 1863d0407baSopenharmony_ci TRICKLE_CHRG, 1873d0407baSopenharmony_ci CC_OR_CV_CHRG, 1883d0407baSopenharmony_ci CHARGE_FINISH, 1893d0407baSopenharmony_ci USB_OVER_VOL, 1903d0407baSopenharmony_ci BAT_TMP_ERR, 1913d0407baSopenharmony_ci BAT_TIM_ERR, 1923d0407baSopenharmony_ci}; 1933d0407baSopenharmony_ci 1943d0407baSopenharmony_cienum bat_mode { 1953d0407baSopenharmony_ci MODE_BATTARY = 0, 1963d0407baSopenharmony_ci MODE_VIRTUAL, 1973d0407baSopenharmony_ci}; 1983d0407baSopenharmony_ci 1993d0407baSopenharmony_cienum rk817_sample_time { 2003d0407baSopenharmony_ci S_8_MIN, 2013d0407baSopenharmony_ci S_16_MIN, 2023d0407baSopenharmony_ci S_32_MIN, 2033d0407baSopenharmony_ci S_48_MIN, 2043d0407baSopenharmony_ci}; 2053d0407baSopenharmony_ci 2063d0407baSopenharmony_cienum rk817_output_mode { 2073d0407baSopenharmony_ci AVERAGE_MODE, 2083d0407baSopenharmony_ci INSTANT_MODE, 2093d0407baSopenharmony_ci}; 2103d0407baSopenharmony_ci 2113d0407baSopenharmony_cienum rk817_battery_fields { 2123d0407baSopenharmony_ci ADC_SLP_RATE, BAT_CUR_ADC_EN, BAT_VOL_ADC_EN, 2133d0407baSopenharmony_ci USB_VOL_ADC_EN, TS_ADC_EN, SYS_VOL_ADC_EN, GG_EN, /*ADC_CONFIG0*/ 2143d0407baSopenharmony_ci CUR_ADC_DITH_SEL, CUR_ADC_DIH_EN, CUR_ADC_CHOP_EN, 2153d0407baSopenharmony_ci CUR_ADC_CHOP_SEL, CUR_ADC_CHOP_VREF_EN, /*CUR_ADC_CFG0*/ 2163d0407baSopenharmony_ci CUR_ADC_VCOM_SEL, CUR_ADC_VCOM_BUF_INC, CUR_ADC_VREF_BUF_INC, 2173d0407baSopenharmony_ci CUR_ADC_BIAS_DEC, CUR_ADC_IBIAS_SEL,/*CUR_ADC_CFG1*/ 2183d0407baSopenharmony_ci VOL_ADC_EXT_VREF_EN, VOL_ADC_DITH_SEL, VOL_ADC_DITH_EN, 2193d0407baSopenharmony_ci VOL_ADC_CHOP_EN, VOL_ADC_CHOP_SEL, VOL_ADC_CHOP_VREF_EN, 2203d0407baSopenharmony_ci VOL_ADC_VCOM_SEL, VOL_ADC_VCOM_BUF_INC, VOL_ADC_VREF_BUF_INC, 2213d0407baSopenharmony_ci VOL_ADC_IBIAS_SEL, /*VOL_ADC_CFG1*/ 2223d0407baSopenharmony_ci RLX_CUR_FILTER, TS_FUN, VOL_ADC_TSCUR_SEL, 2233d0407baSopenharmony_ci VOL_CALIB_UPD, CUR_CALIB_UPD, /*ADC_CONFIG1*/ 2243d0407baSopenharmony_ci CUR_OUT_MOD, VOL_OUT_MOD, FRAME_SMP_INTERV, 2253d0407baSopenharmony_ci ADC_OFF_CAL_INTERV, RLX_SPT, /*GG_CON*/ 2263d0407baSopenharmony_ci OCV_UPD, RELAX_STS, RELAX_VOL2_UPD, RELAX_VOL1_UPD, BAT_CON, 2273d0407baSopenharmony_ci QMAX_UPD_SOFT, TERM_UPD, OCV_STS, /*GG_STS*/ 2283d0407baSopenharmony_ci RELAX_THRE_H, RELAX_THRE_L, /*RELAX_THRE*/ 2293d0407baSopenharmony_ci RELAX_VOL1_H, RELAX_VOL1_L, 2303d0407baSopenharmony_ci RELAX_VOL2_H, RELAX_VOL2_L, 2313d0407baSopenharmony_ci RELAX_CUR1_H, RELAX_CUR1_L, 2323d0407baSopenharmony_ci RELAX_CUR2_H, RELAX_CUR2_L, 2333d0407baSopenharmony_ci OCV_THRE_VOL, 2343d0407baSopenharmony_ci OCV_VOL_H, OCV_VOL_L, 2353d0407baSopenharmony_ci OCV_VOL0_H, OCV_VOL0_L, 2363d0407baSopenharmony_ci OCV_CUR_H, OCV_CUR_L, 2373d0407baSopenharmony_ci OCV_CUR0_H, OCV_CUR0_L, 2383d0407baSopenharmony_ci PWRON_VOL_H, PWRON_VOL_L, 2393d0407baSopenharmony_ci PWRON_CUR_H, PWRON_CUR_L, 2403d0407baSopenharmony_ci OFF_CNT, 2413d0407baSopenharmony_ci Q_INIT_H3, Q_INIT_H2, Q_INIT_L1, Q_INIT_L0, 2423d0407baSopenharmony_ci Q_PRESS_H3, Q_PRESS_H2, Q_PRESS_L1, Q_PRESS_L0, 2433d0407baSopenharmony_ci BAT_VOL_H, BAT_VOL_L, 2443d0407baSopenharmony_ci BAT_CUR_H, BAT_CUR_L, 2453d0407baSopenharmony_ci BAT_TS_H, BAT_TS_L, 2463d0407baSopenharmony_ci USB_VOL_H, USB_VOL_L, 2473d0407baSopenharmony_ci SYS_VOL_H, SYS_VOL_L, 2483d0407baSopenharmony_ci Q_MAX_H3, Q_MAX_H2, Q_MAX_L1, Q_MAX_L0, 2493d0407baSopenharmony_ci Q_TERM_H3, Q_TERM_H2, Q_TERM_L1, Q_TERM_L0, 2503d0407baSopenharmony_ci Q_OCV_H3, Q_OCV_H2, Q_OCV_L1, Q_OCV_L0, 2513d0407baSopenharmony_ci OCV_CNT, 2523d0407baSopenharmony_ci SLEEP_CON_SAMP_CUR_H, SLEEP_CON_SAMP_CUR_L, 2533d0407baSopenharmony_ci CAL_OFFSET_H, CAL_OFFSET_L, 2543d0407baSopenharmony_ci VCALIB0_H, VCALIB0_L, 2553d0407baSopenharmony_ci VCALIB1_H, VCALIB1_L, 2563d0407baSopenharmony_ci IOFFSET_H, IOFFSET_L, 2573d0407baSopenharmony_ci BAT_R0, SOC_REG0, SOC_REG1, SOC_REG2, 2583d0407baSopenharmony_ci REMAIN_CAP_REG2, REMAIN_CAP_REG1, REMAIN_CAP_REG0, 2593d0407baSopenharmony_ci NEW_FCC_REG2, NEW_FCC_REG1, NEW_FCC_REG0, 2603d0407baSopenharmony_ci RESET_MODE, 2613d0407baSopenharmony_ci FG_INIT, HALT_CNT_REG, CALC_REST_REGL, CALC_REST_REGH, 2623d0407baSopenharmony_ci VOL_ADC_B3, VOL_ADC_B2, VOL_ADC_B1, VOL_ADC_B0, 2633d0407baSopenharmony_ci VOL_ADC_K3, VOL_ADC_K2, VOL_ADC_K1, VOL_ADC_K0, 2643d0407baSopenharmony_ci BAT_EXS, CHG_STS, BAT_OVP_STS, CHRG_IN_CLAMP, 2653d0407baSopenharmony_ci CHIP_NAME_H, CHIP_NAME_L, 2663d0407baSopenharmony_ci PLUG_IN_STS, 2673d0407baSopenharmony_ci F_MAX_FIELDS 2683d0407baSopenharmony_ci}; 2693d0407baSopenharmony_ci 2703d0407baSopenharmony_cistatic const struct reg_field rk817_battery_reg_fields[] = { 2713d0407baSopenharmony_ci [ADC_SLP_RATE] = REG_FIELD(0x50, 0, 0), 2723d0407baSopenharmony_ci [BAT_CUR_ADC_EN] = REG_FIELD(0x50, 2, 2), 2733d0407baSopenharmony_ci [BAT_VOL_ADC_EN] = REG_FIELD(0x50, 3, 3), 2743d0407baSopenharmony_ci [USB_VOL_ADC_EN] = REG_FIELD(0x50, 4, 4), 2753d0407baSopenharmony_ci [TS_ADC_EN] = REG_FIELD(0x50, 5, 5), 2763d0407baSopenharmony_ci [SYS_VOL_ADC_EN] = REG_FIELD(0x50, 6, 6), 2773d0407baSopenharmony_ci [GG_EN] = REG_FIELD(0x50, 7, 7),/*ADC_CONFIG0*/ 2783d0407baSopenharmony_ci 2793d0407baSopenharmony_ci [CUR_ADC_DITH_SEL] = REG_FIELD(0x51, 1, 3), 2803d0407baSopenharmony_ci [CUR_ADC_DIH_EN] = REG_FIELD(0x51, 4, 4), 2813d0407baSopenharmony_ci [CUR_ADC_CHOP_EN] = REG_FIELD(0x51, 5, 5), 2823d0407baSopenharmony_ci [CUR_ADC_CHOP_SEL] = REG_FIELD(0x51, 6, 6), 2833d0407baSopenharmony_ci [CUR_ADC_CHOP_VREF_EN] = REG_FIELD(0x51, 7, 7), /*CUR_ADC_COFG0*/ 2843d0407baSopenharmony_ci 2853d0407baSopenharmony_ci [CUR_ADC_VCOM_SEL] = REG_FIELD(0x52, 0, 1), 2863d0407baSopenharmony_ci [CUR_ADC_VCOM_BUF_INC] = REG_FIELD(0x52, 2, 2), 2873d0407baSopenharmony_ci [CUR_ADC_VREF_BUF_INC] = REG_FIELD(0x52, 3, 3), 2883d0407baSopenharmony_ci [CUR_ADC_BIAS_DEC] = REG_FIELD(0x52, 4, 4), 2893d0407baSopenharmony_ci [CUR_ADC_IBIAS_SEL] = REG_FIELD(0x52, 5, 6), /*CUR_ADC_COFG1*/ 2903d0407baSopenharmony_ci 2913d0407baSopenharmony_ci [VOL_ADC_EXT_VREF_EN] = REG_FIELD(0x53, 0, 0), 2923d0407baSopenharmony_ci [VOL_ADC_DITH_SEL] = REG_FIELD(0x53, 1, 3), 2933d0407baSopenharmony_ci [VOL_ADC_DITH_EN] = REG_FIELD(0x53, 4, 4), 2943d0407baSopenharmony_ci [VOL_ADC_CHOP_EN] = REG_FIELD(0x53, 5, 5), 2953d0407baSopenharmony_ci [VOL_ADC_CHOP_SEL] = REG_FIELD(0x53, 6, 6), 2963d0407baSopenharmony_ci [VOL_ADC_CHOP_VREF_EN] = REG_FIELD(0x53, 7, 7),/*VOL_ADC_COFG0*/ 2973d0407baSopenharmony_ci 2983d0407baSopenharmony_ci [VOL_ADC_VCOM_SEL] = REG_FIELD(0x54, 0, 1), 2993d0407baSopenharmony_ci [VOL_ADC_VCOM_BUF_INC] = REG_FIELD(0x54, 2, 2), 3003d0407baSopenharmony_ci [VOL_ADC_VREF_BUF_INC] = REG_FIELD(0x54, 3, 3), 3013d0407baSopenharmony_ci [VOL_ADC_IBIAS_SEL] = REG_FIELD(0x54, 5, 6), /*VOL_ADC_COFG1*/ 3023d0407baSopenharmony_ci 3033d0407baSopenharmony_ci [RLX_CUR_FILTER] = REG_FIELD(0x55, 0, 1), 3043d0407baSopenharmony_ci [TS_FUN] = REG_FIELD(0x55, 3, 3), 3053d0407baSopenharmony_ci [VOL_ADC_TSCUR_SEL] = REG_FIELD(0x55, 4, 5), 3063d0407baSopenharmony_ci [VOL_CALIB_UPD] = REG_FIELD(0x55, 6, 6), 3073d0407baSopenharmony_ci [CUR_CALIB_UPD] = REG_FIELD(0x55, 7, 7), /*ADC_CONFIG1*/ 3083d0407baSopenharmony_ci 3093d0407baSopenharmony_ci [CUR_OUT_MOD] = REG_FIELD(0x56, 0, 0), 3103d0407baSopenharmony_ci [VOL_OUT_MOD] = REG_FIELD(0x56, 1, 1), 3113d0407baSopenharmony_ci [FRAME_SMP_INTERV] = REG_FIELD(0x56, 2, 3), 3123d0407baSopenharmony_ci [ADC_OFF_CAL_INTERV] = REG_FIELD(0x56, 4, 5), 3133d0407baSopenharmony_ci [RLX_SPT] = REG_FIELD(0x56, 6, 7), /*GG_CON*/ 3143d0407baSopenharmony_ci 3153d0407baSopenharmony_ci [OCV_UPD] = REG_FIELD(0x57, 0, 0), 3163d0407baSopenharmony_ci [RELAX_STS] = REG_FIELD(0x57, 1, 1), 3173d0407baSopenharmony_ci [RELAX_VOL2_UPD] = REG_FIELD(0x57, 2, 2), 3183d0407baSopenharmony_ci [RELAX_VOL1_UPD] = REG_FIELD(0x57, 3, 3), 3193d0407baSopenharmony_ci [BAT_CON] = REG_FIELD(0x57, 4, 4), 3203d0407baSopenharmony_ci [QMAX_UPD_SOFT] = REG_FIELD(0x57, 5, 5), 3213d0407baSopenharmony_ci [TERM_UPD] = REG_FIELD(0x57, 6, 6), 3223d0407baSopenharmony_ci [OCV_STS] = REG_FIELD(0x57, 7, 7), /*GG_STS*/ 3233d0407baSopenharmony_ci 3243d0407baSopenharmony_ci [RELAX_THRE_H] = REG_FIELD(0x58, 0, 7), 3253d0407baSopenharmony_ci [RELAX_THRE_L] = REG_FIELD(0x59, 0, 7), 3263d0407baSopenharmony_ci 3273d0407baSopenharmony_ci [RELAX_VOL1_H] = REG_FIELD(0x5A, 0, 7), 3283d0407baSopenharmony_ci [RELAX_VOL1_L] = REG_FIELD(0x5B, 0, 7), 3293d0407baSopenharmony_ci [RELAX_VOL2_H] = REG_FIELD(0x5C, 0, 7), 3303d0407baSopenharmony_ci [RELAX_VOL2_L] = REG_FIELD(0x5D, 0, 7), 3313d0407baSopenharmony_ci 3323d0407baSopenharmony_ci [RELAX_CUR1_H] = REG_FIELD(0x5E, 0, 7), 3333d0407baSopenharmony_ci [RELAX_CUR1_L] = REG_FIELD(0x5F, 0, 7), 3343d0407baSopenharmony_ci [RELAX_CUR2_H] = REG_FIELD(0x60, 0, 7), 3353d0407baSopenharmony_ci [RELAX_CUR2_L] = REG_FIELD(0x61, 0, 7), 3363d0407baSopenharmony_ci 3373d0407baSopenharmony_ci [OCV_THRE_VOL] = REG_FIELD(0x62, 0, 7), 3383d0407baSopenharmony_ci 3393d0407baSopenharmony_ci [OCV_VOL_H] = REG_FIELD(0x63, 0, 7), 3403d0407baSopenharmony_ci [OCV_VOL_L] = REG_FIELD(0x64, 0, 7), 3413d0407baSopenharmony_ci [OCV_VOL0_H] = REG_FIELD(0x65, 0, 7), 3423d0407baSopenharmony_ci [OCV_VOL0_L] = REG_FIELD(0x66, 0, 7), 3433d0407baSopenharmony_ci [OCV_CUR_H] = REG_FIELD(0x67, 0, 7), 3443d0407baSopenharmony_ci [OCV_CUR_L] = REG_FIELD(0x68, 0, 7), 3453d0407baSopenharmony_ci [OCV_CUR0_H] = REG_FIELD(0x69, 0, 7), 3463d0407baSopenharmony_ci [OCV_CUR0_L] = REG_FIELD(0x6A, 0, 7), 3473d0407baSopenharmony_ci [PWRON_VOL_H] = REG_FIELD(0x6B, 0, 7), 3483d0407baSopenharmony_ci [PWRON_VOL_L] = REG_FIELD(0x6C, 0, 7), 3493d0407baSopenharmony_ci [PWRON_CUR_H] = REG_FIELD(0x6D, 0, 7), 3503d0407baSopenharmony_ci [PWRON_CUR_L] = REG_FIELD(0x6E, 0, 7), 3513d0407baSopenharmony_ci [OFF_CNT] = REG_FIELD(0x6F, 0, 7), 3523d0407baSopenharmony_ci [Q_INIT_H3] = REG_FIELD(0x70, 0, 7), 3533d0407baSopenharmony_ci [Q_INIT_H2] = REG_FIELD(0x71, 0, 7), 3543d0407baSopenharmony_ci [Q_INIT_L1] = REG_FIELD(0x72, 0, 7), 3553d0407baSopenharmony_ci [Q_INIT_L0] = REG_FIELD(0x73, 0, 7), 3563d0407baSopenharmony_ci 3573d0407baSopenharmony_ci [Q_PRESS_H3] = REG_FIELD(0x74, 0, 7), 3583d0407baSopenharmony_ci [Q_PRESS_H2] = REG_FIELD(0x75, 0, 7), 3593d0407baSopenharmony_ci [Q_PRESS_L1] = REG_FIELD(0x76, 0, 7), 3603d0407baSopenharmony_ci [Q_PRESS_L0] = REG_FIELD(0x77, 0, 7), 3613d0407baSopenharmony_ci 3623d0407baSopenharmony_ci [BAT_VOL_H] = REG_FIELD(0x78, 0, 7), 3633d0407baSopenharmony_ci [BAT_VOL_L] = REG_FIELD(0x79, 0, 7), 3643d0407baSopenharmony_ci 3653d0407baSopenharmony_ci [BAT_CUR_H] = REG_FIELD(0x7A, 0, 7), 3663d0407baSopenharmony_ci [BAT_CUR_L] = REG_FIELD(0x7B, 0, 7), 3673d0407baSopenharmony_ci 3683d0407baSopenharmony_ci [BAT_TS_H] = REG_FIELD(0x7C, 0, 7), 3693d0407baSopenharmony_ci [BAT_TS_L] = REG_FIELD(0x7D, 0, 7), 3703d0407baSopenharmony_ci [USB_VOL_H] = REG_FIELD(0x7E, 0, 7), 3713d0407baSopenharmony_ci [USB_VOL_L] = REG_FIELD(0x7F, 0, 7), 3723d0407baSopenharmony_ci 3733d0407baSopenharmony_ci [SYS_VOL_H] = REG_FIELD(0x80, 0, 7), 3743d0407baSopenharmony_ci [SYS_VOL_L] = REG_FIELD(0x81, 0, 7), 3753d0407baSopenharmony_ci [Q_MAX_H3] = REG_FIELD(0x82, 0, 7), 3763d0407baSopenharmony_ci [Q_MAX_H2] = REG_FIELD(0x83, 0, 7), 3773d0407baSopenharmony_ci [Q_MAX_L1] = REG_FIELD(0x84, 0, 7), 3783d0407baSopenharmony_ci [Q_MAX_L0] = REG_FIELD(0x85, 0, 7), 3793d0407baSopenharmony_ci 3803d0407baSopenharmony_ci [Q_TERM_H3] = REG_FIELD(0x86, 0, 7), 3813d0407baSopenharmony_ci [Q_TERM_H2] = REG_FIELD(0x87, 0, 7), 3823d0407baSopenharmony_ci [Q_TERM_L1] = REG_FIELD(0x88, 0, 7), 3833d0407baSopenharmony_ci [Q_TERM_L0] = REG_FIELD(0x89, 0, 7), 3843d0407baSopenharmony_ci [Q_OCV_H3] = REG_FIELD(0x8A, 0, 7), 3853d0407baSopenharmony_ci [Q_OCV_H2] = REG_FIELD(0x8B, 0, 7), 3863d0407baSopenharmony_ci 3873d0407baSopenharmony_ci [Q_OCV_L1] = REG_FIELD(0x8C, 0, 7), 3883d0407baSopenharmony_ci [Q_OCV_L0] = REG_FIELD(0x8D, 0, 7), 3893d0407baSopenharmony_ci [OCV_CNT] = REG_FIELD(0x8E, 0, 7), 3903d0407baSopenharmony_ci [SLEEP_CON_SAMP_CUR_H] = REG_FIELD(0x8F, 0, 7), 3913d0407baSopenharmony_ci [SLEEP_CON_SAMP_CUR_L] = REG_FIELD(0x90, 0, 7), 3923d0407baSopenharmony_ci [CAL_OFFSET_H] = REG_FIELD(0x91, 0, 7), 3933d0407baSopenharmony_ci [CAL_OFFSET_L] = REG_FIELD(0x92, 0, 7), 3943d0407baSopenharmony_ci [VCALIB0_H] = REG_FIELD(0x93, 0, 7), 3953d0407baSopenharmony_ci [VCALIB0_L] = REG_FIELD(0x94, 0, 7), 3963d0407baSopenharmony_ci [VCALIB1_H] = REG_FIELD(0x95, 0, 7), 3973d0407baSopenharmony_ci [VCALIB1_L] = REG_FIELD(0x96, 0, 7), 3983d0407baSopenharmony_ci [IOFFSET_H] = REG_FIELD(0x97, 0, 7), 3993d0407baSopenharmony_ci [IOFFSET_L] = REG_FIELD(0x98, 0, 7), 4003d0407baSopenharmony_ci 4013d0407baSopenharmony_ci [BAT_R0] = REG_FIELD(0x99, 0, 7), 4023d0407baSopenharmony_ci [SOC_REG0] = REG_FIELD(0x9A, 0, 7), 4033d0407baSopenharmony_ci [SOC_REG1] = REG_FIELD(0x9B, 0, 7), 4043d0407baSopenharmony_ci [SOC_REG2] = REG_FIELD(0x9C, 0, 7), 4053d0407baSopenharmony_ci 4063d0407baSopenharmony_ci [REMAIN_CAP_REG0] = REG_FIELD(0x9D, 0, 7), 4073d0407baSopenharmony_ci [REMAIN_CAP_REG1] = REG_FIELD(0x9E, 0, 7), 4083d0407baSopenharmony_ci [REMAIN_CAP_REG2] = REG_FIELD(0x9F, 0, 7), 4093d0407baSopenharmony_ci [NEW_FCC_REG0] = REG_FIELD(0xA0, 0, 7), 4103d0407baSopenharmony_ci [NEW_FCC_REG1] = REG_FIELD(0xA1, 0, 7), 4113d0407baSopenharmony_ci [NEW_FCC_REG2] = REG_FIELD(0xA2, 0, 7), 4123d0407baSopenharmony_ci [RESET_MODE] = REG_FIELD(0xA3, 0, 3), 4133d0407baSopenharmony_ci [FG_INIT] = REG_FIELD(0xA5, 7, 7), 4143d0407baSopenharmony_ci 4153d0407baSopenharmony_ci [HALT_CNT_REG] = REG_FIELD(0xA6, 0, 7), 4163d0407baSopenharmony_ci [CALC_REST_REGL] = REG_FIELD(0xA7, 0, 7), 4173d0407baSopenharmony_ci [CALC_REST_REGH] = REG_FIELD(0xA8, 0, 7), 4183d0407baSopenharmony_ci 4193d0407baSopenharmony_ci [VOL_ADC_B3] = REG_FIELD(0xA9, 0, 7), 4203d0407baSopenharmony_ci [VOL_ADC_B2] = REG_FIELD(0xAA, 0, 7), 4213d0407baSopenharmony_ci [VOL_ADC_B1] = REG_FIELD(0xAB, 0, 7), 4223d0407baSopenharmony_ci [VOL_ADC_B0] = REG_FIELD(0xAC, 0, 7), 4233d0407baSopenharmony_ci 4243d0407baSopenharmony_ci [VOL_ADC_K3] = REG_FIELD(0xAD, 0, 7), 4253d0407baSopenharmony_ci [VOL_ADC_K2] = REG_FIELD(0xAE, 0, 7), 4263d0407baSopenharmony_ci [VOL_ADC_K1] = REG_FIELD(0xAF, 0, 7), 4273d0407baSopenharmony_ci [VOL_ADC_K0] = REG_FIELD(0xB0, 0, 7), 4283d0407baSopenharmony_ci [BAT_EXS] = REG_FIELD(0xEB, 7, 7), 4293d0407baSopenharmony_ci [CHG_STS] = REG_FIELD(0xEB, 4, 6), 4303d0407baSopenharmony_ci [BAT_OVP_STS] = REG_FIELD(0xEB, 3, 3), 4313d0407baSopenharmony_ci [CHRG_IN_CLAMP] = REG_FIELD(0xEB, 2, 2), 4323d0407baSopenharmony_ci [CHIP_NAME_H] = REG_FIELD(0xED, 0, 7), 4333d0407baSopenharmony_ci [CHIP_NAME_L] = REG_FIELD(0xEE, 0, 7), 4343d0407baSopenharmony_ci [PLUG_IN_STS] = REG_FIELD(0xF0, 6, 6), 4353d0407baSopenharmony_ci}; 4363d0407baSopenharmony_ci 4373d0407baSopenharmony_cistruct battery_platform_data { 4383d0407baSopenharmony_ci u32 *ocv_table; 4393d0407baSopenharmony_ci u32 *zero_table; 4403d0407baSopenharmony_ci 4413d0407baSopenharmony_ci u32 table_t[4][21]; 4423d0407baSopenharmony_ci int temp_t[4]; 4433d0407baSopenharmony_ci u32 temp_t_num; 4443d0407baSopenharmony_ci 4453d0407baSopenharmony_ci u32 *ntc_table; 4463d0407baSopenharmony_ci u32 ocv_size; 4473d0407baSopenharmony_ci u32 ntc_size; 4483d0407baSopenharmony_ci int ntc_degree_from; 4493d0407baSopenharmony_ci u32 ntc_factor; 4503d0407baSopenharmony_ci u32 max_input_current; 4513d0407baSopenharmony_ci u32 max_chrg_current; 4523d0407baSopenharmony_ci u32 max_chrg_voltage; 4533d0407baSopenharmony_ci u32 lp_input_current; 4543d0407baSopenharmony_ci u32 lp_soc_min; 4553d0407baSopenharmony_ci u32 lp_soc_max; 4563d0407baSopenharmony_ci u32 pwroff_vol; 4573d0407baSopenharmony_ci u32 monitor_sec; 4583d0407baSopenharmony_ci u32 zero_algorithm_vol; 4593d0407baSopenharmony_ci u32 zero_reserve_dsoc; 4603d0407baSopenharmony_ci u32 bat_res; 4613d0407baSopenharmony_ci u32 design_capacity; 4623d0407baSopenharmony_ci u32 design_qmax; 4633d0407baSopenharmony_ci u32 sleep_enter_current; 4643d0407baSopenharmony_ci u32 sleep_exit_current; 4653d0407baSopenharmony_ci u32 sleep_filter_current; 4663d0407baSopenharmony_ci 4673d0407baSopenharmony_ci u32 power_dc2otg; 4683d0407baSopenharmony_ci u32 max_soc_offset; 4693d0407baSopenharmony_ci u32 bat_mode; 4703d0407baSopenharmony_ci u32 fb_temp; 4713d0407baSopenharmony_ci u32 energy_mode; 4723d0407baSopenharmony_ci u32 cccv_hour; 4733d0407baSopenharmony_ci u32 dc_det_adc; 4743d0407baSopenharmony_ci int dc_det_pin; 4753d0407baSopenharmony_ci u8 dc_det_level; 4763d0407baSopenharmony_ci u32 sample_res; 4773d0407baSopenharmony_ci u32 bat_res_up; 4783d0407baSopenharmony_ci u32 bat_res_down; 4793d0407baSopenharmony_ci u32 design_max_voltage; 4803d0407baSopenharmony_ci bool extcon; 4813d0407baSopenharmony_ci u32 low_pwr_sleep; 4823d0407baSopenharmony_ci}; 4833d0407baSopenharmony_ci 4843d0407baSopenharmony_cistruct rk817_battery_device { 4853d0407baSopenharmony_ci struct platform_device *pdev; 4863d0407baSopenharmony_ci struct device *dev; 4873d0407baSopenharmony_ci struct i2c_client *client; 4883d0407baSopenharmony_ci struct rk808 *rk817; 4893d0407baSopenharmony_ci struct power_supply *bat; 4903d0407baSopenharmony_ci struct power_supply *chg_psy; 4913d0407baSopenharmony_ci struct power_supply *usb_psy; 4923d0407baSopenharmony_ci struct power_supply *ac_psy; 4933d0407baSopenharmony_ci struct regmap *regmap; 4943d0407baSopenharmony_ci struct regmap_field *rmap_fields[F_MAX_FIELDS]; 4953d0407baSopenharmony_ci struct battery_platform_data *pdata; 4963d0407baSopenharmony_ci struct workqueue_struct *bat_monitor_wq; 4973d0407baSopenharmony_ci struct delayed_work bat_delay_work; 4983d0407baSopenharmony_ci struct delayed_work calib_delay_work; 4993d0407baSopenharmony_ci struct work_struct resume_work; 5003d0407baSopenharmony_ci struct wake_lock wake_lock; 5013d0407baSopenharmony_ci struct timer_list caltimer; 5023d0407baSopenharmony_ci 5033d0407baSopenharmony_ci int res_div; 5043d0407baSopenharmony_ci int bat_res; 5053d0407baSopenharmony_ci bool is_first_power_on; 5063d0407baSopenharmony_ci int chrg_status; 5073d0407baSopenharmony_ci int res_fac; 5083d0407baSopenharmony_ci int over_20mR; 5093d0407baSopenharmony_ci bool is_initialized; 5103d0407baSopenharmony_ci bool bat_first_power_on; 5113d0407baSopenharmony_ci u8 ac_in; 5123d0407baSopenharmony_ci u8 usb_in; 5133d0407baSopenharmony_ci u8 otg_in; 5143d0407baSopenharmony_ci u8 dc_in; 5153d0407baSopenharmony_ci u8 prop_status; 5163d0407baSopenharmony_ci int cvtlmt_irq; 5173d0407baSopenharmony_ci int current_avg; 5183d0407baSopenharmony_ci int current_relax; 5193d0407baSopenharmony_ci int voltage_usb; 5203d0407baSopenharmony_ci int voltage_sys; 5213d0407baSopenharmony_ci int voltage_avg; 5223d0407baSopenharmony_ci int voltage_ocv; 5233d0407baSopenharmony_ci int voltage_relax; 5243d0407baSopenharmony_ci int voltage_k;/* VCALIB0 VCALIB1 */ 5253d0407baSopenharmony_ci int voltage_b; 5263d0407baSopenharmony_ci u32 remain_cap; 5273d0407baSopenharmony_ci int design_cap; 5283d0407baSopenharmony_ci int nac; 5293d0407baSopenharmony_ci int fcc; 5303d0407baSopenharmony_ci int lock_fcc; 5313d0407baSopenharmony_ci int qmax; 5323d0407baSopenharmony_ci int dsoc; 5333d0407baSopenharmony_ci int rsoc; 5343d0407baSopenharmony_ci int poffset; 5353d0407baSopenharmony_ci int fake_offline; 5363d0407baSopenharmony_ci int age_ocv_soc; 5373d0407baSopenharmony_ci bool age_allow_update; 5383d0407baSopenharmony_ci int age_level; 5393d0407baSopenharmony_ci int age_ocv_cap; 5403d0407baSopenharmony_ci int pwron_voltage; 5413d0407baSopenharmony_ci int age_voltage; 5423d0407baSopenharmony_ci int age_adjust_cap; 5433d0407baSopenharmony_ci unsigned long age_keep_sec; 5443d0407baSopenharmony_ci int zero_timeout_cnt; 5453d0407baSopenharmony_ci int zero_remain_cap; 5463d0407baSopenharmony_ci int zero_dsoc; 5473d0407baSopenharmony_ci int zero_linek; 5483d0407baSopenharmony_ci u64 zero_drop_sec; 5493d0407baSopenharmony_ci u64 shtd_drop_sec; 5503d0407baSopenharmony_ci 5513d0407baSopenharmony_ci int powerpatch_res; 5523d0407baSopenharmony_ci int zero_voltage_avg; 5533d0407baSopenharmony_ci int zero_current_avg; 5543d0407baSopenharmony_ci int zero_vsys; 5553d0407baSopenharmony_ci int zero_dead_voltage; 5563d0407baSopenharmony_ci int zero_dead_soc; 5573d0407baSopenharmony_ci int zero_dead_cap; 5583d0407baSopenharmony_ci int zero_batvol_to_ocv; 5593d0407baSopenharmony_ci int zero_batocv_to_soc; 5603d0407baSopenharmony_ci int zero_batocv_to_cap; 5613d0407baSopenharmony_ci int zero_xsoc; 5623d0407baSopenharmony_ci unsigned long finish_base; 5633d0407baSopenharmony_ci time64_t rtc_base; 5643d0407baSopenharmony_ci int sm_remain_cap; 5653d0407baSopenharmony_ci int sm_linek; 5663d0407baSopenharmony_ci int sm_chrg_dsoc; 5673d0407baSopenharmony_ci int sm_dischrg_dsoc; 5683d0407baSopenharmony_ci int smooth_soc; 5693d0407baSopenharmony_ci int algo_rest_val; 5703d0407baSopenharmony_ci int algo_rest_mode; 5713d0407baSopenharmony_ci int sleep_sum_cap; 5723d0407baSopenharmony_ci int sleep_remain_cap; 5733d0407baSopenharmony_ci unsigned long sleep_dischrg_sec; 5743d0407baSopenharmony_ci unsigned long sleep_sum_sec; 5753d0407baSopenharmony_ci bool sleep_chrg_online; 5763d0407baSopenharmony_ci u8 sleep_chrg_status; 5773d0407baSopenharmony_ci bool adc_allow_update; 5783d0407baSopenharmony_ci int fb_blank; 5793d0407baSopenharmony_ci bool s2r; /*suspend to resume*/ 5803d0407baSopenharmony_ci u32 work_mode; 5813d0407baSopenharmony_ci int temperature; 5823d0407baSopenharmony_ci int chrg_cur_lp_input; 5833d0407baSopenharmony_ci int chrg_vol_sel; 5843d0407baSopenharmony_ci int chrg_cur_input; 5853d0407baSopenharmony_ci int chrg_cur_sel; 5863d0407baSopenharmony_ci u32 monitor_ms; 5873d0407baSopenharmony_ci u32 pwroff_min; 5883d0407baSopenharmony_ci u32 adc_calib_cnt; 5893d0407baSopenharmony_ci unsigned long chrg_finish_base; 5903d0407baSopenharmony_ci unsigned long boot_base; 5913d0407baSopenharmony_ci unsigned long flat_match_sec; 5923d0407baSopenharmony_ci unsigned long plug_in_base; 5933d0407baSopenharmony_ci unsigned long plug_out_base; 5943d0407baSopenharmony_ci u8 halt_cnt; 5953d0407baSopenharmony_ci bool is_halt; 5963d0407baSopenharmony_ci bool is_max_soc_offset; 5973d0407baSopenharmony_ci bool is_sw_reset; 5983d0407baSopenharmony_ci bool is_ocv_calib; 5993d0407baSopenharmony_ci bool is_first_on; 6003d0407baSopenharmony_ci bool is_force_calib; 6013d0407baSopenharmony_ci int last_dsoc; 6023d0407baSopenharmony_ci u8 cvtlmt_int_event; 6033d0407baSopenharmony_ci u8 slp_dcdc_en_reg; 6043d0407baSopenharmony_ci int ocv_pre_dsoc; 6053d0407baSopenharmony_ci int ocv_new_dsoc; 6063d0407baSopenharmony_ci int max_pre_dsoc; 6073d0407baSopenharmony_ci int max_new_dsoc; 6083d0407baSopenharmony_ci int force_pre_dsoc; 6093d0407baSopenharmony_ci int force_new_dsoc; 6103d0407baSopenharmony_ci 6113d0407baSopenharmony_ci int dbg_cap_low0; 6123d0407baSopenharmony_ci int dbg_pwr_dsoc; 6133d0407baSopenharmony_ci int dbg_pwr_rsoc; 6143d0407baSopenharmony_ci int dbg_pwr_vol; 6153d0407baSopenharmony_ci int dbg_chrg_min[10]; 6163d0407baSopenharmony_ci int dbg_meet_soc; 6173d0407baSopenharmony_ci int dbg_calc_dsoc; 6183d0407baSopenharmony_ci int dbg_calc_rsoc; 6193d0407baSopenharmony_ci int is_charging; 6203d0407baSopenharmony_ci unsigned long charge_count; 6213d0407baSopenharmony_ci u8 plugin_trigger; 6223d0407baSopenharmony_ci u8 plugout_trigger; 6233d0407baSopenharmony_ci int plugin_irq; 6243d0407baSopenharmony_ci int plugout_irq; 6253d0407baSopenharmony_ci int chip_id; 6263d0407baSopenharmony_ci int is_register_chg_psy; 6273d0407baSopenharmony_ci bool change; /* Battery status change, report information */ 6283d0407baSopenharmony_ci}; 6293d0407baSopenharmony_ci 6303d0407baSopenharmony_cistatic void rk817_bat_resume_work(struct work_struct *work); 6313d0407baSopenharmony_ci 6323d0407baSopenharmony_cistatic u64 get_boot_sec(void) 6333d0407baSopenharmony_ci{ 6343d0407baSopenharmony_ci struct timespec64 ts; 6353d0407baSopenharmony_ci 6363d0407baSopenharmony_ci ktime_get_boottime_ts64(&ts); 6373d0407baSopenharmony_ci 6383d0407baSopenharmony_ci return ts.tv_sec; 6393d0407baSopenharmony_ci} 6403d0407baSopenharmony_ci 6413d0407baSopenharmony_cistatic unsigned long base2sec(unsigned long x) 6423d0407baSopenharmony_ci{ 6433d0407baSopenharmony_ci if (x) 6443d0407baSopenharmony_ci return (get_boot_sec() > x) ? (get_boot_sec() - x) : 0; 6453d0407baSopenharmony_ci else 6463d0407baSopenharmony_ci return 0; 6473d0407baSopenharmony_ci} 6483d0407baSopenharmony_ci 6493d0407baSopenharmony_cistatic u32 interpolate(int value, u32 *table, int size) 6503d0407baSopenharmony_ci{ 6513d0407baSopenharmony_ci u8 i; 6523d0407baSopenharmony_ci u16 d; 6533d0407baSopenharmony_ci 6543d0407baSopenharmony_ci for (i = 0; i < size; i++) { 6553d0407baSopenharmony_ci if (value < table[i]) 6563d0407baSopenharmony_ci break; 6573d0407baSopenharmony_ci } 6583d0407baSopenharmony_ci 6593d0407baSopenharmony_ci if ((i > 0) && (i < size)) { 6603d0407baSopenharmony_ci d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1)); 6613d0407baSopenharmony_ci d /= table[i] - table[i - 1]; 6623d0407baSopenharmony_ci d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1)); 6633d0407baSopenharmony_ci } else { 6643d0407baSopenharmony_ci d = i * ((MAX_INTERPOLATE + size / 2) / size); 6653d0407baSopenharmony_ci } 6663d0407baSopenharmony_ci 6673d0407baSopenharmony_ci if (d > 1000) 6683d0407baSopenharmony_ci d = 1000; 6693d0407baSopenharmony_ci 6703d0407baSopenharmony_ci return d; 6713d0407baSopenharmony_ci} 6723d0407baSopenharmony_ci 6733d0407baSopenharmony_ci/* (a * b) / c */ 6743d0407baSopenharmony_cistatic int32_t ab_div_c(u32 a, u32 b, u32 c) 6753d0407baSopenharmony_ci{ 6763d0407baSopenharmony_ci bool sign; 6773d0407baSopenharmony_ci u32 ans = MAX_INT; 6783d0407baSopenharmony_ci int tmp; 6793d0407baSopenharmony_ci 6803d0407baSopenharmony_ci sign = ((((a ^ b) ^ c) & 0x80000000) != 0); 6813d0407baSopenharmony_ci if (c != 0) { 6823d0407baSopenharmony_ci if (sign) 6833d0407baSopenharmony_ci c = -c; 6843d0407baSopenharmony_ci tmp = (a * b + (c >> 1)) / c; 6853d0407baSopenharmony_ci if (tmp < MAX_INT) 6863d0407baSopenharmony_ci ans = tmp; 6873d0407baSopenharmony_ci } 6883d0407baSopenharmony_ci 6893d0407baSopenharmony_ci if (sign) 6903d0407baSopenharmony_ci ans = -ans; 6913d0407baSopenharmony_ci 6923d0407baSopenharmony_ci return ans; 6933d0407baSopenharmony_ci} 6943d0407baSopenharmony_ci 6953d0407baSopenharmony_cistatic int rk817_bat_field_read(struct rk817_battery_device *battery, 6963d0407baSopenharmony_ci enum rk817_battery_fields field_id) 6973d0407baSopenharmony_ci{ 6983d0407baSopenharmony_ci int val; 6993d0407baSopenharmony_ci int ret; 7003d0407baSopenharmony_ci 7013d0407baSopenharmony_ci ret = regmap_field_read(battery->rmap_fields[field_id], &val); 7023d0407baSopenharmony_ci if (ret < 0) 7033d0407baSopenharmony_ci return ret; 7043d0407baSopenharmony_ci 7053d0407baSopenharmony_ci return val; 7063d0407baSopenharmony_ci} 7073d0407baSopenharmony_ci 7083d0407baSopenharmony_cistatic int rk817_bat_field_write(struct rk817_battery_device *battery, 7093d0407baSopenharmony_ci enum rk817_battery_fields field_id, 7103d0407baSopenharmony_ci unsigned int val) 7113d0407baSopenharmony_ci{ 7123d0407baSopenharmony_ci return regmap_field_write(battery->rmap_fields[field_id], val); 7133d0407baSopenharmony_ci} 7143d0407baSopenharmony_ci 7153d0407baSopenharmony_ci/*cal_offset: current offset value*/ 7163d0407baSopenharmony_cistatic int rk817_bat_get_coffset(struct rk817_battery_device *battery) 7173d0407baSopenharmony_ci{ 7183d0407baSopenharmony_ci int coffset_value = 0; 7193d0407baSopenharmony_ci 7203d0407baSopenharmony_ci coffset_value |= rk817_bat_field_read(battery, CAL_OFFSET_H) << 8; 7213d0407baSopenharmony_ci coffset_value |= rk817_bat_field_read(battery, CAL_OFFSET_L); 7223d0407baSopenharmony_ci 7233d0407baSopenharmony_ci return coffset_value; 7243d0407baSopenharmony_ci} 7253d0407baSopenharmony_ci 7263d0407baSopenharmony_cistatic void rk817_bat_set_coffset(struct rk817_battery_device *battery, int val) 7273d0407baSopenharmony_ci{ 7283d0407baSopenharmony_ci u8 buf = 0; 7293d0407baSopenharmony_ci 7303d0407baSopenharmony_ci buf = (val >> 8) & 0xff; 7313d0407baSopenharmony_ci rk817_bat_field_write(battery, CAL_OFFSET_H, buf); 7323d0407baSopenharmony_ci buf = (val >> 0) & 0xff; 7333d0407baSopenharmony_ci rk817_bat_field_write(battery, CAL_OFFSET_L, buf); 7343d0407baSopenharmony_ci} 7353d0407baSopenharmony_ci 7363d0407baSopenharmony_ci/* current offset value calculated */ 7373d0407baSopenharmony_cistatic int rk817_bat_get_ioffset(struct rk817_battery_device *battery) 7383d0407baSopenharmony_ci{ 7393d0407baSopenharmony_ci int ioffset_value = 0; 7403d0407baSopenharmony_ci 7413d0407baSopenharmony_ci ioffset_value |= rk817_bat_field_read(battery, IOFFSET_H) << 8; 7423d0407baSopenharmony_ci ioffset_value |= rk817_bat_field_read(battery, IOFFSET_L); 7433d0407baSopenharmony_ci 7443d0407baSopenharmony_ci return ioffset_value; 7453d0407baSopenharmony_ci} 7463d0407baSopenharmony_ci 7473d0407baSopenharmony_cistatic void rk817_bat_current_calibration(struct rk817_battery_device *battery) 7483d0407baSopenharmony_ci{ 7493d0407baSopenharmony_ci int pwron_value, ioffset, cal_offset; 7503d0407baSopenharmony_ci 7513d0407baSopenharmony_ci pwron_value = rk817_bat_field_read(battery, PWRON_CUR_H) << 8; 7523d0407baSopenharmony_ci pwron_value |= rk817_bat_field_read(battery, PWRON_CUR_L); 7533d0407baSopenharmony_ci 7543d0407baSopenharmony_ci ioffset = rk817_bat_get_ioffset(battery); 7553d0407baSopenharmony_ci 7563d0407baSopenharmony_ci DBG("Caloffset: 0x%x\n", rk817_bat_get_coffset(battery)); 7573d0407baSopenharmony_ci DBG("IOFFSET: 0x%x\n", ioffset); 7583d0407baSopenharmony_ci if (0) 7593d0407baSopenharmony_ci cal_offset = pwron_value + ioffset; 7603d0407baSopenharmony_ci else 7613d0407baSopenharmony_ci cal_offset = ioffset; 7623d0407baSopenharmony_ci 7633d0407baSopenharmony_ci rk817_bat_set_coffset(battery, cal_offset); 7643d0407baSopenharmony_ci DBG("Caloffset: 0x%x\n", rk817_bat_get_coffset(battery)); 7653d0407baSopenharmony_ci 7663d0407baSopenharmony_ci} 7673d0407baSopenharmony_ci 7683d0407baSopenharmony_cistatic int rk817_bat_get_vaclib0(struct rk817_battery_device *battery) 7693d0407baSopenharmony_ci{ 7703d0407baSopenharmony_ci int vcalib_value = 0; 7713d0407baSopenharmony_ci 7723d0407baSopenharmony_ci vcalib_value |= rk817_bat_field_read(battery, VCALIB0_H) << 8; 7733d0407baSopenharmony_ci vcalib_value |= rk817_bat_field_read(battery, VCALIB0_L); 7743d0407baSopenharmony_ci 7753d0407baSopenharmony_ci return vcalib_value; 7763d0407baSopenharmony_ci} 7773d0407baSopenharmony_ci 7783d0407baSopenharmony_cistatic int rk817_bat_get_vaclib1(struct rk817_battery_device *battery) 7793d0407baSopenharmony_ci{ 7803d0407baSopenharmony_ci int vcalib_value = 0; 7813d0407baSopenharmony_ci 7823d0407baSopenharmony_ci vcalib_value |= rk817_bat_field_read(battery, VCALIB1_H) << 8; 7833d0407baSopenharmony_ci vcalib_value |= rk817_bat_field_read(battery, VCALIB1_L); 7843d0407baSopenharmony_ci 7853d0407baSopenharmony_ci return vcalib_value; 7863d0407baSopenharmony_ci} 7873d0407baSopenharmony_ci 7883d0407baSopenharmony_cistatic void rk817_bat_init_voltage_kb(struct rk817_battery_device *battery) 7893d0407baSopenharmony_ci{ 7903d0407baSopenharmony_ci int vcalib0, vcalib1; 7913d0407baSopenharmony_ci 7923d0407baSopenharmony_ci vcalib0 = rk817_bat_get_vaclib0(battery); 7933d0407baSopenharmony_ci vcalib1 = rk817_bat_get_vaclib1(battery); 7943d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 7953d0407baSopenharmony_ci battery->voltage_k = (1050 - 600) * 1000 / DIV(vcalib1 - vcalib0); 7963d0407baSopenharmony_ci battery->voltage_b = 1050 - (battery->voltage_k * vcalib1) / 1000; 7973d0407baSopenharmony_ci } else { 7983d0407baSopenharmony_ci battery->voltage_k = (4025 - 2300) * 1000 / DIV(vcalib1 - vcalib0); 7993d0407baSopenharmony_ci battery->voltage_b = 4025 - (battery->voltage_k * vcalib1) / 1000; 8003d0407baSopenharmony_ci } 8013d0407baSopenharmony_ci} 8023d0407baSopenharmony_ci 8033d0407baSopenharmony_cistatic void rk817_bat_restart_relax(struct rk817_battery_device *battery) 8043d0407baSopenharmony_ci{ 8053d0407baSopenharmony_ci rk817_bat_field_write(battery, RELAX_VOL1_UPD, 0x00); 8063d0407baSopenharmony_ci rk817_bat_field_write(battery, RELAX_VOL2_UPD, 0x00); 8073d0407baSopenharmony_ci} 8083d0407baSopenharmony_ci 8093d0407baSopenharmony_cistatic bool is_rk817_bat_relax_mode(struct rk817_battery_device *battery) 8103d0407baSopenharmony_ci{ 8113d0407baSopenharmony_ci u8 relax_sts, relax_vol1_upd, relax_vol2_upd; 8123d0407baSopenharmony_ci 8133d0407baSopenharmony_ci relax_sts = rk817_bat_field_read(battery, RELAX_STS); 8143d0407baSopenharmony_ci relax_vol1_upd = rk817_bat_field_read(battery, RELAX_VOL1_UPD); 8153d0407baSopenharmony_ci relax_vol2_upd = rk817_bat_field_read(battery, RELAX_VOL2_UPD); 8163d0407baSopenharmony_ci 8173d0407baSopenharmony_ci DBG("RELAX_STS: %d\n", relax_sts); 8183d0407baSopenharmony_ci DBG("RELAX_VOL1_UPD: %d\n", relax_vol1_upd); 8193d0407baSopenharmony_ci DBG("RELAX_VOL2_UPD: %d\n", relax_vol2_upd); 8203d0407baSopenharmony_ci if (relax_sts && relax_vol1_upd && relax_vol2_upd) 8213d0407baSopenharmony_ci return true; 8223d0407baSopenharmony_ci else 8233d0407baSopenharmony_ci return false; 8243d0407baSopenharmony_ci} 8253d0407baSopenharmony_ci 8263d0407baSopenharmony_cistatic u16 rk817_bat_get_relax_vol1(struct rk817_battery_device *battery) 8273d0407baSopenharmony_ci{ 8283d0407baSopenharmony_ci u16 vol, val = 0; 8293d0407baSopenharmony_ci 8303d0407baSopenharmony_ci val = rk817_bat_field_read(battery, RELAX_VOL1_H) << 8; 8313d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, RELAX_VOL1_L); 8323d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 8333d0407baSopenharmony_ci 8343d0407baSopenharmony_ci return vol; 8353d0407baSopenharmony_ci} 8363d0407baSopenharmony_ci 8373d0407baSopenharmony_cistatic u16 rk817_bat_get_relax_vol2(struct rk817_battery_device *battery) 8383d0407baSopenharmony_ci{ 8393d0407baSopenharmony_ci u16 vol, val = 0; 8403d0407baSopenharmony_ci 8413d0407baSopenharmony_ci val = rk817_bat_field_read(battery, RELAX_VOL2_H) << 8; 8423d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, RELAX_VOL2_L); 8433d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 8443d0407baSopenharmony_ci 8453d0407baSopenharmony_ci return vol; 8463d0407baSopenharmony_ci} 8473d0407baSopenharmony_ci 8483d0407baSopenharmony_cistatic u16 rk817_bat_get_relax_voltage(struct rk817_battery_device *battery) 8493d0407baSopenharmony_ci{ 8503d0407baSopenharmony_ci u16 relax_vol1, relax_vol2; 8513d0407baSopenharmony_ci 8523d0407baSopenharmony_ci if (!is_rk817_bat_relax_mode(battery)) 8533d0407baSopenharmony_ci return 0; 8543d0407baSopenharmony_ci 8553d0407baSopenharmony_ci relax_vol1 = rk817_bat_get_relax_vol1(battery); 8563d0407baSopenharmony_ci relax_vol2 = rk817_bat_get_relax_vol2(battery); 8573d0407baSopenharmony_ci 8583d0407baSopenharmony_ci return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2; 8593d0407baSopenharmony_ci} 8603d0407baSopenharmony_ci 8613d0407baSopenharmony_cistatic void rk817_bat_set_relax_sample(struct rk817_battery_device *battery) 8623d0407baSopenharmony_ci{ 8633d0407baSopenharmony_ci u8 buf; 8643d0407baSopenharmony_ci int enter_thres, filter_thres; 8653d0407baSopenharmony_ci struct battery_platform_data *pdata = battery->pdata; 8663d0407baSopenharmony_ci 8673d0407baSopenharmony_ci filter_thres = pdata->sleep_filter_current * 1000 / 1506; 8683d0407baSopenharmony_ci 8693d0407baSopenharmony_ci enter_thres = CURRENT_TO_ADC(pdata->sleep_enter_current, 8703d0407baSopenharmony_ci battery->res_div); 8713d0407baSopenharmony_ci filter_thres = CURRENT_TO_ADC(pdata->sleep_filter_current, 8723d0407baSopenharmony_ci battery->res_div); 8733d0407baSopenharmony_ci 8743d0407baSopenharmony_ci /* set relax enter and exit threshold */ 8753d0407baSopenharmony_ci buf = (enter_thres >> 8) & 0xff; 8763d0407baSopenharmony_ci rk817_bat_field_write(battery, RELAX_THRE_H, buf); 8773d0407baSopenharmony_ci buf = enter_thres & 0xff; 8783d0407baSopenharmony_ci rk817_bat_field_write(battery, RELAX_THRE_L, buf); 8793d0407baSopenharmony_ci /* set sample current threshold */ 8803d0407baSopenharmony_ci buf = (filter_thres >> 8) & 0xff; 8813d0407baSopenharmony_ci rk817_bat_field_write(battery, SLEEP_CON_SAMP_CUR_H, buf); 8823d0407baSopenharmony_ci buf = filter_thres & 0xff; 8833d0407baSopenharmony_ci rk817_bat_field_write(battery, SLEEP_CON_SAMP_CUR_L, buf); 8843d0407baSopenharmony_ci 8853d0407baSopenharmony_ci /* reset relax update state */ 8863d0407baSopenharmony_ci rk817_bat_restart_relax(battery); 8873d0407baSopenharmony_ci DBG("<%s>. sleep_enter_current = %d, sleep_exit_current = %d\n", 8883d0407baSopenharmony_ci __func__, pdata->sleep_enter_current, pdata->sleep_exit_current); 8893d0407baSopenharmony_ci} 8903d0407baSopenharmony_ci 8913d0407baSopenharmony_ci/* runtime OCV voltage, |RLX_VOL2 - RLX_VOL1| < OCV_THRE, 8923d0407baSopenharmony_ci * the OCV reg update every 120s 8933d0407baSopenharmony_ci */ 8943d0407baSopenharmony_cistatic void rk817_bat_ocv_thre(struct rk817_battery_device *battery, int value) 8953d0407baSopenharmony_ci{ 8963d0407baSopenharmony_ci rk817_bat_field_write(battery, OCV_THRE_VOL, value); 8973d0407baSopenharmony_ci} 8983d0407baSopenharmony_ci 8993d0407baSopenharmony_cistatic int rk817_bat_get_ocv_voltage(struct rk817_battery_device *battery) 9003d0407baSopenharmony_ci{ 9013d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9023d0407baSopenharmony_ci 9033d0407baSopenharmony_ci val = rk817_bat_field_read(battery, OCV_VOL_H) << 8; 9043d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, OCV_VOL_L); 9053d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 9063d0407baSopenharmony_ci 9073d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 9083d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 9093d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 9103d0407baSopenharmony_ci vol = vol_temp; 9113d0407baSopenharmony_ci } 9123d0407baSopenharmony_ci 9133d0407baSopenharmony_ci return vol; 9143d0407baSopenharmony_ci} 9153d0407baSopenharmony_ci 9163d0407baSopenharmony_cistatic int rk817_bat_get_ocv0_voltage0(struct rk817_battery_device *battery) 9173d0407baSopenharmony_ci{ 9183d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9193d0407baSopenharmony_ci 9203d0407baSopenharmony_ci val = rk817_bat_field_read(battery, OCV_VOL0_H) << 8; 9213d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, OCV_VOL0_L); 9223d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 9233d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 9243d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 9253d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 9263d0407baSopenharmony_ci vol = vol_temp; 9273d0407baSopenharmony_ci } 9283d0407baSopenharmony_ci 9293d0407baSopenharmony_ci return vol; 9303d0407baSopenharmony_ci} 9313d0407baSopenharmony_ci 9323d0407baSopenharmony_ci/* power on battery voltage */ 9333d0407baSopenharmony_cistatic int rk817_bat_get_pwron_voltage(struct rk817_battery_device *battery) 9343d0407baSopenharmony_ci{ 9353d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9363d0407baSopenharmony_ci 9373d0407baSopenharmony_ci val = rk817_bat_field_read(battery, PWRON_VOL_H) << 8; 9383d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, PWRON_VOL_L); 9393d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 9403d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 9413d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 9423d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 9433d0407baSopenharmony_ci vol = vol_temp; 9443d0407baSopenharmony_ci } 9453d0407baSopenharmony_ci 9463d0407baSopenharmony_ci return vol; 9473d0407baSopenharmony_ci} 9483d0407baSopenharmony_ci 9493d0407baSopenharmony_cistatic int rk817_bat_get_battery_voltage(struct rk817_battery_device *battery) 9503d0407baSopenharmony_ci{ 9513d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9523d0407baSopenharmony_ci int vcalib0, vcalib1; 9533d0407baSopenharmony_ci 9543d0407baSopenharmony_ci vcalib0 = rk817_bat_get_vaclib0(battery); 9553d0407baSopenharmony_ci vcalib1 = rk817_bat_get_vaclib1(battery); 9563d0407baSopenharmony_ci 9573d0407baSopenharmony_ci 9583d0407baSopenharmony_ci val = rk817_bat_field_read(battery, BAT_VOL_H) << 8; 9593d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, BAT_VOL_L) << 0; 9603d0407baSopenharmony_ci 9613d0407baSopenharmony_ci vol = battery->voltage_k * val / 1000 + battery->voltage_b; 9623d0407baSopenharmony_ci 9633d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 9643d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 9653d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 9663d0407baSopenharmony_ci vol = vol_temp; 9673d0407baSopenharmony_ci } 9683d0407baSopenharmony_ci 9693d0407baSopenharmony_ci return vol; 9703d0407baSopenharmony_ci} 9713d0407baSopenharmony_ci 9723d0407baSopenharmony_cistatic int rk817_bat_get_USB_voltage(struct rk817_battery_device *battery) 9733d0407baSopenharmony_ci{ 9743d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9753d0407baSopenharmony_ci 9763d0407baSopenharmony_ci rk817_bat_field_write(battery, USB_VOL_ADC_EN, 0x01); 9773d0407baSopenharmony_ci 9783d0407baSopenharmony_ci val = rk817_bat_field_read(battery, USB_VOL_H) << 8; 9793d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, USB_VOL_L) << 0; 9803d0407baSopenharmony_ci 9813d0407baSopenharmony_ci vol = (battery->voltage_k * val / 1000 + battery->voltage_b) * 60 / 46; 9823d0407baSopenharmony_ci 9833d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 9843d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 9853d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 9863d0407baSopenharmony_ci vol = vol_temp; 9873d0407baSopenharmony_ci } 9883d0407baSopenharmony_ci 9893d0407baSopenharmony_ci return vol; 9903d0407baSopenharmony_ci} 9913d0407baSopenharmony_ci 9923d0407baSopenharmony_cistatic int rk817_bat_get_sys_voltage(struct rk817_battery_device *battery) 9933d0407baSopenharmony_ci{ 9943d0407baSopenharmony_ci int vol, val = 0, vol_temp; 9953d0407baSopenharmony_ci 9963d0407baSopenharmony_ci val = rk817_bat_field_read(battery, SYS_VOL_H) << 8; 9973d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, SYS_VOL_L) << 0; 9983d0407baSopenharmony_ci 9993d0407baSopenharmony_ci vol = (battery->voltage_k * val / 1000 + battery->voltage_b) * 60 / 46; 10003d0407baSopenharmony_ci 10013d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 10023d0407baSopenharmony_ci vol_temp = vol * battery->pdata->bat_res_up / 10033d0407baSopenharmony_ci battery->pdata->bat_res_down + vol; 10043d0407baSopenharmony_ci vol = vol_temp; 10053d0407baSopenharmony_ci } 10063d0407baSopenharmony_ci 10073d0407baSopenharmony_ci return vol; 10083d0407baSopenharmony_ci} 10093d0407baSopenharmony_ci 10103d0407baSopenharmony_cistatic int rk817_bat_get_avg_current(struct rk817_battery_device *battery) 10113d0407baSopenharmony_ci{ 10123d0407baSopenharmony_ci int cur, val = 0; 10133d0407baSopenharmony_ci 10143d0407baSopenharmony_ci val = rk817_bat_field_read(battery, BAT_CUR_H) << 8; 10153d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, BAT_CUR_L); 10163d0407baSopenharmony_ci 10173d0407baSopenharmony_ci if (val & 0x8000) 10183d0407baSopenharmony_ci val -= 0x10000; 10193d0407baSopenharmony_ci 10203d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 10213d0407baSopenharmony_ci 10223d0407baSopenharmony_ci return cur; 10233d0407baSopenharmony_ci} 10243d0407baSopenharmony_ci 10253d0407baSopenharmony_cistatic int rk817_bat_get_relax_cur1(struct rk817_battery_device *battery) 10263d0407baSopenharmony_ci{ 10273d0407baSopenharmony_ci int cur, val = 0; 10283d0407baSopenharmony_ci 10293d0407baSopenharmony_ci val = rk817_bat_field_read(battery, RELAX_CUR1_H) << 8; 10303d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, RELAX_CUR1_L); 10313d0407baSopenharmony_ci 10323d0407baSopenharmony_ci if (val & 0x8000) 10333d0407baSopenharmony_ci val -= 0x10000; 10343d0407baSopenharmony_ci 10353d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 10363d0407baSopenharmony_ci 10373d0407baSopenharmony_ci return cur; 10383d0407baSopenharmony_ci} 10393d0407baSopenharmony_ci 10403d0407baSopenharmony_cistatic int rk817_bat_get_relax_cur2(struct rk817_battery_device *battery) 10413d0407baSopenharmony_ci{ 10423d0407baSopenharmony_ci int cur, val = 0; 10433d0407baSopenharmony_ci 10443d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, RELAX_CUR2_H) << 8; 10453d0407baSopenharmony_ci val = rk817_bat_field_read(battery, RELAX_CUR2_L); 10463d0407baSopenharmony_ci 10473d0407baSopenharmony_ci if (val & 0x8000) 10483d0407baSopenharmony_ci val -= 0x10000; 10493d0407baSopenharmony_ci 10503d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 10513d0407baSopenharmony_ci 10523d0407baSopenharmony_ci return cur; 10533d0407baSopenharmony_ci} 10543d0407baSopenharmony_ci 10553d0407baSopenharmony_cistatic int rk817_bat_get_relax_current(struct rk817_battery_device *battery) 10563d0407baSopenharmony_ci{ 10573d0407baSopenharmony_ci int relax_cur1, relax_cur2; 10583d0407baSopenharmony_ci 10593d0407baSopenharmony_ci if (!is_rk817_bat_relax_mode(battery)) 10603d0407baSopenharmony_ci return 0; 10613d0407baSopenharmony_ci 10623d0407baSopenharmony_ci relax_cur1 = rk817_bat_get_relax_cur1(battery); 10633d0407baSopenharmony_ci relax_cur2 = rk817_bat_get_relax_cur2(battery); 10643d0407baSopenharmony_ci 10653d0407baSopenharmony_ci return (relax_cur1 < relax_cur2) ? relax_cur1 : relax_cur2; 10663d0407baSopenharmony_ci} 10673d0407baSopenharmony_ci 10683d0407baSopenharmony_cistatic int rk817_bat_get_ocv_current(struct rk817_battery_device *battery) 10693d0407baSopenharmony_ci{ 10703d0407baSopenharmony_ci int cur, val = 0; 10713d0407baSopenharmony_ci 10723d0407baSopenharmony_ci val = rk817_bat_field_read(battery, OCV_CUR_H) << 8; 10733d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, OCV_CUR_L); 10743d0407baSopenharmony_ci 10753d0407baSopenharmony_ci if (val & 0x8000) 10763d0407baSopenharmony_ci val -= 0x10000; 10773d0407baSopenharmony_ci 10783d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 10793d0407baSopenharmony_ci 10803d0407baSopenharmony_ci return cur; 10813d0407baSopenharmony_ci} 10823d0407baSopenharmony_ci 10833d0407baSopenharmony_cistatic int rk817_bat_get_ocv_current0(struct rk817_battery_device *battery) 10843d0407baSopenharmony_ci{ 10853d0407baSopenharmony_ci int cur, val = 0; 10863d0407baSopenharmony_ci 10873d0407baSopenharmony_ci val = rk817_bat_field_read(battery, OCV_CUR0_H) << 8; 10883d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, OCV_CUR0_L); 10893d0407baSopenharmony_ci 10903d0407baSopenharmony_ci if (val & 0x8000) 10913d0407baSopenharmony_ci val -= 0x10000; 10923d0407baSopenharmony_ci 10933d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 10943d0407baSopenharmony_ci 10953d0407baSopenharmony_ci return cur; 10963d0407baSopenharmony_ci} 10973d0407baSopenharmony_ci 10983d0407baSopenharmony_cistatic int rk817_bat_get_pwron_current(struct rk817_battery_device *battery) 10993d0407baSopenharmony_ci{ 11003d0407baSopenharmony_ci int cur, val = 0; 11013d0407baSopenharmony_ci 11023d0407baSopenharmony_ci val = rk817_bat_field_read(battery, PWRON_CUR_H) << 8; 11033d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, PWRON_CUR_L); 11043d0407baSopenharmony_ci 11053d0407baSopenharmony_ci if (val & 0x8000) 11063d0407baSopenharmony_ci val -= 0x10000; 11073d0407baSopenharmony_ci cur = ADC_TO_CURRENT(val, battery->res_div); 11083d0407baSopenharmony_ci 11093d0407baSopenharmony_ci return cur; 11103d0407baSopenharmony_ci} 11113d0407baSopenharmony_ci 11123d0407baSopenharmony_cistatic bool rk817_bat_remain_cap_is_valid(struct rk817_battery_device *battery) 11133d0407baSopenharmony_ci{ 11143d0407baSopenharmony_ci return !(rk817_bat_field_read(battery, Q_PRESS_H3) & CAP_INVALID); 11153d0407baSopenharmony_ci} 11163d0407baSopenharmony_ci 11173d0407baSopenharmony_cistatic u32 rk817_bat_get_capacity_uah(struct rk817_battery_device *battery) 11183d0407baSopenharmony_ci{ 11193d0407baSopenharmony_ci u32 val = 0, capacity = 0; 11203d0407baSopenharmony_ci 11213d0407baSopenharmony_ci if (rk817_bat_remain_cap_is_valid(battery)) { 11223d0407baSopenharmony_ci val = rk817_bat_field_read(battery, Q_PRESS_H3) << 24; 11233d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_H2) << 16; 11243d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_L1) << 8; 11253d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_L0) << 0; 11263d0407baSopenharmony_ci 11273d0407baSopenharmony_ci capacity = ADC_TO_CAPACITY_UAH(val, battery->res_div); 11283d0407baSopenharmony_ci } 11293d0407baSopenharmony_ci 11303d0407baSopenharmony_ci DBG("xxxxxxxxxxxxx capacity = %d\n", capacity); 11313d0407baSopenharmony_ci return capacity; 11323d0407baSopenharmony_ci} 11333d0407baSopenharmony_ci 11343d0407baSopenharmony_cistatic u32 rk817_bat_get_capacity_mah(struct rk817_battery_device *battery) 11353d0407baSopenharmony_ci{ 11363d0407baSopenharmony_ci u32 val, capacity = 0; 11373d0407baSopenharmony_ci 11383d0407baSopenharmony_ci if (rk817_bat_remain_cap_is_valid(battery)) { 11393d0407baSopenharmony_ci val = rk817_bat_field_read(battery, Q_PRESS_H3) << 24; 11403d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_H2) << 16; 11413d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_L1) << 8; 11423d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_PRESS_L0) << 0; 11433d0407baSopenharmony_ci 11443d0407baSopenharmony_ci capacity = ADC_TO_CAPACITY(val, battery->res_div); 11453d0407baSopenharmony_ci } 11463d0407baSopenharmony_ci DBG("Q_PRESS_H3 = 0x%x\n", rk817_bat_field_read(battery, Q_PRESS_H3)); 11473d0407baSopenharmony_ci DBG("Q_PRESS_H2 = 0x%x\n", rk817_bat_field_read(battery, Q_PRESS_H2)); 11483d0407baSopenharmony_ci DBG("Q_PRESS_H1 = 0x%x\n", rk817_bat_field_read(battery, Q_PRESS_L1)); 11493d0407baSopenharmony_ci DBG("Q_PRESS_H0 = 0x%x\n", rk817_bat_field_read(battery, Q_PRESS_L0)); 11503d0407baSopenharmony_ci 11513d0407baSopenharmony_ci DBG("xxxxxxxxxxxxx capacity = %d\n", capacity); 11523d0407baSopenharmony_ci return capacity; 11533d0407baSopenharmony_ci} 11543d0407baSopenharmony_ci 11553d0407baSopenharmony_cistatic void fuel_gauge_q_init_info(struct rk817_battery_device *battery) 11563d0407baSopenharmony_ci{ 11573d0407baSopenharmony_ci DBG("Q_INIT_H3 = 0x%x\n", rk817_bat_field_read(battery, Q_INIT_H3)); 11583d0407baSopenharmony_ci DBG("Q_INIT_H2 = 0x%x\n", rk817_bat_field_read(battery, Q_INIT_H2)); 11593d0407baSopenharmony_ci DBG("Q_INIT_L1 = 0x%x\n", rk817_bat_field_read(battery, Q_INIT_L1)); 11603d0407baSopenharmony_ci DBG("Q_INIT_L0 = 0x%x\n", rk817_bat_field_read(battery, Q_INIT_L0)); 11613d0407baSopenharmony_ci} 11623d0407baSopenharmony_ci 11633d0407baSopenharmony_cistatic void rk817_bat_init_coulomb_cap(struct rk817_battery_device *battery, 11643d0407baSopenharmony_ci u32 capacity) 11653d0407baSopenharmony_ci{ 11663d0407baSopenharmony_ci u8 buf; 11673d0407baSopenharmony_ci u32 cap; 11683d0407baSopenharmony_ci 11693d0407baSopenharmony_ci fuel_gauge_q_init_info(battery); 11703d0407baSopenharmony_ci cap = CAPACITY_TO_ADC(capacity, battery->res_div); 11713d0407baSopenharmony_ci DBG("new cap: 0x%x\n", cap); 11723d0407baSopenharmony_ci buf = (cap >> 24) & 0xff; 11733d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_INIT_H3, buf); 11743d0407baSopenharmony_ci buf = (cap >> 16) & 0xff; 11753d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_INIT_H2, buf); 11763d0407baSopenharmony_ci buf = (cap >> 8) & 0xff; 11773d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_INIT_L1, buf); 11783d0407baSopenharmony_ci buf = (cap >> 0) & 0xff; 11793d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_INIT_L0, buf); 11803d0407baSopenharmony_ci 11813d0407baSopenharmony_ci battery->rsoc = capacity * 1000 * 100 / battery->fcc; 11823d0407baSopenharmony_ci battery->remain_cap = capacity * 1000; 11833d0407baSopenharmony_ci DBG("new remaincap: %d\n", battery->remain_cap); 11843d0407baSopenharmony_ci fuel_gauge_q_init_info(battery); 11853d0407baSopenharmony_ci} 11863d0407baSopenharmony_ci 11873d0407baSopenharmony_cistatic void rk817_bat_save_cap(struct rk817_battery_device *battery, 11883d0407baSopenharmony_ci int capacity) 11893d0407baSopenharmony_ci{ 11903d0407baSopenharmony_ci u8 buf; 11913d0407baSopenharmony_ci static u32 old_cap; 11923d0407baSopenharmony_ci 11933d0407baSopenharmony_ci if (capacity >= battery->qmax) 11943d0407baSopenharmony_ci capacity = battery->qmax; 11953d0407baSopenharmony_ci if (capacity <= 0) 11963d0407baSopenharmony_ci capacity = 0; 11973d0407baSopenharmony_ci if (old_cap == capacity) 11983d0407baSopenharmony_ci return; 11993d0407baSopenharmony_ci 12003d0407baSopenharmony_ci old_cap = capacity; 12013d0407baSopenharmony_ci buf = (capacity >> 16) & 0xff; 12023d0407baSopenharmony_ci rk817_bat_field_write(battery, REMAIN_CAP_REG2, buf); 12033d0407baSopenharmony_ci buf = (capacity >> 8) & 0xff; 12043d0407baSopenharmony_ci rk817_bat_field_write(battery, REMAIN_CAP_REG1, buf); 12053d0407baSopenharmony_ci buf = (capacity >> 0) & 0xff; 12063d0407baSopenharmony_ci rk817_bat_field_write(battery, REMAIN_CAP_REG0, buf); 12073d0407baSopenharmony_ci} 12083d0407baSopenharmony_ci 12093d0407baSopenharmony_cistatic void rk817_bat_update_qmax(struct rk817_battery_device *battery, 12103d0407baSopenharmony_ci u32 capacity) 12113d0407baSopenharmony_ci{ 12123d0407baSopenharmony_ci u8 buf; 12133d0407baSopenharmony_ci u32 cap_adc; 12143d0407baSopenharmony_ci 12153d0407baSopenharmony_ci cap_adc = CAPACITY_TO_ADC(capacity, battery->res_div); 12163d0407baSopenharmony_ci buf = (cap_adc >> 24) & 0xff; 12173d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_MAX_H3, buf); 12183d0407baSopenharmony_ci buf = (cap_adc >> 16) & 0xff; 12193d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_MAX_H2, buf); 12203d0407baSopenharmony_ci buf = (cap_adc >> 8) & 0xff; 12213d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_MAX_L1, buf); 12223d0407baSopenharmony_ci buf = (cap_adc >> 0) & 0xff; 12233d0407baSopenharmony_ci rk817_bat_field_write(battery, Q_MAX_L0, buf); 12243d0407baSopenharmony_ci battery->qmax = capacity; 12253d0407baSopenharmony_ci} 12263d0407baSopenharmony_ci 12273d0407baSopenharmony_cistatic int rk817_bat_get_qmax(struct rk817_battery_device *battery) 12283d0407baSopenharmony_ci{ 12293d0407baSopenharmony_ci u32 capacity; 12303d0407baSopenharmony_ci int val = 0; 12313d0407baSopenharmony_ci 12323d0407baSopenharmony_ci val = rk817_bat_field_read(battery, Q_MAX_H3) << 24; 12333d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_MAX_H2) << 16; 12343d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_MAX_L1) << 8; 12353d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, Q_MAX_L0) << 0; 12363d0407baSopenharmony_ci capacity = ADC_TO_CAPACITY(val, battery->res_div); 12373d0407baSopenharmony_ci battery->qmax = capacity; 12383d0407baSopenharmony_ci return capacity; 12393d0407baSopenharmony_ci} 12403d0407baSopenharmony_ci 12413d0407baSopenharmony_cistatic void rk817_bat_save_fcc(struct rk817_battery_device *battery, int fcc) 12423d0407baSopenharmony_ci{ 12433d0407baSopenharmony_ci u8 buf; 12443d0407baSopenharmony_ci 12453d0407baSopenharmony_ci buf = (fcc >> 16) & 0xff; 12463d0407baSopenharmony_ci rk817_bat_field_write(battery, NEW_FCC_REG2, buf); 12473d0407baSopenharmony_ci buf = (fcc >> 8) & 0xff; 12483d0407baSopenharmony_ci rk817_bat_field_write(battery, NEW_FCC_REG1, buf); 12493d0407baSopenharmony_ci buf = (fcc >> 0) & 0xff; 12503d0407baSopenharmony_ci rk817_bat_field_write(battery, NEW_FCC_REG0, buf); 12513d0407baSopenharmony_ci} 12523d0407baSopenharmony_ci 12533d0407baSopenharmony_cistatic int rk817_bat_get_fcc(struct rk817_battery_device *battery) 12543d0407baSopenharmony_ci{ 12553d0407baSopenharmony_ci u32 fcc = 0; 12563d0407baSopenharmony_ci 12573d0407baSopenharmony_ci fcc |= rk817_bat_field_read(battery, NEW_FCC_REG2) << 16; 12583d0407baSopenharmony_ci fcc |= rk817_bat_field_read(battery, NEW_FCC_REG1) << 8; 12593d0407baSopenharmony_ci fcc |= rk817_bat_field_read(battery, NEW_FCC_REG0) << 0; 12603d0407baSopenharmony_ci 12613d0407baSopenharmony_ci if (fcc < MIN_FCC) { 12623d0407baSopenharmony_ci DBG("invalid fcc(%d), use design cap", fcc); 12633d0407baSopenharmony_ci fcc = battery->pdata->design_capacity; 12643d0407baSopenharmony_ci rk817_bat_save_fcc(battery, fcc); 12653d0407baSopenharmony_ci } else if (fcc > battery->pdata->design_qmax) { 12663d0407baSopenharmony_ci DBG("invalid fcc(%d), use qmax", fcc); 12673d0407baSopenharmony_ci fcc = battery->pdata->design_qmax; 12683d0407baSopenharmony_ci rk817_bat_save_fcc(battery, fcc); 12693d0407baSopenharmony_ci } 12703d0407baSopenharmony_ci 12713d0407baSopenharmony_ci return fcc; 12723d0407baSopenharmony_ci} 12733d0407baSopenharmony_ci 12743d0407baSopenharmony_cistatic int rk817_bat_get_rsoc(struct rk817_battery_device *battery) 12753d0407baSopenharmony_ci{ 12763d0407baSopenharmony_ci int remain_cap; 12773d0407baSopenharmony_ci 12783d0407baSopenharmony_ci remain_cap = rk817_bat_get_capacity_uah(battery); 12793d0407baSopenharmony_ci 12803d0407baSopenharmony_ci return remain_cap * 100 / DIV(battery->fcc); 12813d0407baSopenharmony_ci} 12823d0407baSopenharmony_ci 12833d0407baSopenharmony_cistatic int rk817_bat_get_off_count(struct rk817_battery_device *battery) 12843d0407baSopenharmony_ci{ 12853d0407baSopenharmony_ci return rk817_bat_field_read(battery, OFF_CNT); 12863d0407baSopenharmony_ci} 12873d0407baSopenharmony_ci 12883d0407baSopenharmony_cistatic int rk817_bat_get_ocv_count(struct rk817_battery_device *battery) 12893d0407baSopenharmony_ci{ 12903d0407baSopenharmony_ci return rk817_bat_field_read(battery, OCV_CNT); 12913d0407baSopenharmony_ci} 12923d0407baSopenharmony_ci 12933d0407baSopenharmony_cistatic int rk817_bat_vol_to_soc(struct rk817_battery_device *battery, 12943d0407baSopenharmony_ci int voltage) 12953d0407baSopenharmony_ci{ 12963d0407baSopenharmony_ci u32 *ocv_table, temp; 12973d0407baSopenharmony_ci int ocv_size, ocv_soc; 12983d0407baSopenharmony_ci 12993d0407baSopenharmony_ci ocv_table = battery->pdata->ocv_table; 13003d0407baSopenharmony_ci ocv_size = battery->pdata->ocv_size; 13013d0407baSopenharmony_ci temp = interpolate(voltage, ocv_table, ocv_size); 13023d0407baSopenharmony_ci ocv_soc = ab_div_c(temp, MAX_PERCENTAGE, MAX_INTERPOLATE); 13033d0407baSopenharmony_ci 13043d0407baSopenharmony_ci return ocv_soc; 13053d0407baSopenharmony_ci} 13063d0407baSopenharmony_ci 13073d0407baSopenharmony_cistatic int rk817_bat_vol_to_cap(struct rk817_battery_device *battery, 13083d0407baSopenharmony_ci int voltage) 13093d0407baSopenharmony_ci{ 13103d0407baSopenharmony_ci u32 *ocv_table, temp; 13113d0407baSopenharmony_ci int ocv_size, capacity; 13123d0407baSopenharmony_ci 13133d0407baSopenharmony_ci ocv_table = battery->pdata->ocv_table; 13143d0407baSopenharmony_ci ocv_size = battery->pdata->ocv_size; 13153d0407baSopenharmony_ci temp = interpolate(voltage, ocv_table, ocv_size); 13163d0407baSopenharmony_ci capacity = ab_div_c(temp, battery->fcc, MAX_INTERPOLATE); 13173d0407baSopenharmony_ci 13183d0407baSopenharmony_ci return capacity; 13193d0407baSopenharmony_ci} 13203d0407baSopenharmony_ci 13213d0407baSopenharmony_cistatic void rk817_bat_save_dsoc(struct rk817_battery_device *battery, 13223d0407baSopenharmony_ci int save_soc) 13233d0407baSopenharmony_ci{ 13243d0407baSopenharmony_ci static int last_soc = -1; 13253d0407baSopenharmony_ci 13263d0407baSopenharmony_ci if (last_soc != save_soc) { 13273d0407baSopenharmony_ci rk817_bat_field_write(battery, SOC_REG0, 13283d0407baSopenharmony_ci save_soc & 0xff); 13293d0407baSopenharmony_ci rk817_bat_field_write(battery, SOC_REG1, 13303d0407baSopenharmony_ci (save_soc >> 8) & 0xff); 13313d0407baSopenharmony_ci rk817_bat_field_write(battery, SOC_REG2, 13323d0407baSopenharmony_ci (save_soc >> 16) & 0xff); 13333d0407baSopenharmony_ci 13343d0407baSopenharmony_ci last_soc = save_soc; 13353d0407baSopenharmony_ci } 13363d0407baSopenharmony_ci} 13373d0407baSopenharmony_ci 13383d0407baSopenharmony_cistatic int rk817_bat_get_prev_dsoc(struct rk817_battery_device *battery) 13393d0407baSopenharmony_ci{ 13403d0407baSopenharmony_ci int soc_save; 13413d0407baSopenharmony_ci 13423d0407baSopenharmony_ci soc_save = rk817_bat_field_read(battery, SOC_REG0); 13433d0407baSopenharmony_ci soc_save |= (rk817_bat_field_read(battery, SOC_REG1) << 8); 13443d0407baSopenharmony_ci soc_save |= (rk817_bat_field_read(battery, SOC_REG2) << 16); 13453d0407baSopenharmony_ci 13463d0407baSopenharmony_ci return soc_save; 13473d0407baSopenharmony_ci} 13483d0407baSopenharmony_ci 13493d0407baSopenharmony_cistatic bool is_rk817_bat_first_pwron(struct rk817_battery_device *battery) 13503d0407baSopenharmony_ci{ 13513d0407baSopenharmony_ci if (rk817_bat_field_read(battery, BAT_CON)) { 13523d0407baSopenharmony_ci rk817_bat_field_write(battery, BAT_CON, 0x00); 13533d0407baSopenharmony_ci return true; 13543d0407baSopenharmony_ci } 13553d0407baSopenharmony_ci 13563d0407baSopenharmony_ci return false; 13573d0407baSopenharmony_ci} 13583d0407baSopenharmony_ci 13593d0407baSopenharmony_cistatic int rk817_bat_get_charge_status(struct rk817_battery_device *battery) 13603d0407baSopenharmony_ci{ 13613d0407baSopenharmony_ci int status; 13623d0407baSopenharmony_ci 13633d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 13643d0407baSopenharmony_ci if ((battery->voltage_avg > battery->pdata->design_max_voltage) && 13653d0407baSopenharmony_ci (battery->current_avg > 0) && 13663d0407baSopenharmony_ci ((battery->current_avg < 500) || 13673d0407baSopenharmony_ci (battery->rsoc / 1000 == 100))) 13683d0407baSopenharmony_ci return CHARGE_FINISH; 13693d0407baSopenharmony_ci 13703d0407baSopenharmony_ci if (battery->plugin_trigger) 13713d0407baSopenharmony_ci return CC_OR_CV_CHRG; 13723d0407baSopenharmony_ci else 13733d0407baSopenharmony_ci return CHRG_OFF; 13743d0407baSopenharmony_ci } 13753d0407baSopenharmony_ci status = rk817_bat_field_read(battery, CHG_STS); 13763d0407baSopenharmony_ci 13773d0407baSopenharmony_ci if (status == CC_OR_CV_CHRG) { 13783d0407baSopenharmony_ci if (battery->rsoc == 100 * 1000) { 13793d0407baSopenharmony_ci DBG("charge to finish\n"); 13803d0407baSopenharmony_ci status = CHARGE_FINISH; 13813d0407baSopenharmony_ci } 13823d0407baSopenharmony_ci } 13833d0407baSopenharmony_ci 13843d0407baSopenharmony_ci switch (status) { 13853d0407baSopenharmony_ci case CHRG_OFF: 13863d0407baSopenharmony_ci DBG("charge off...\n"); 13873d0407baSopenharmony_ci break; 13883d0407baSopenharmony_ci case DEAD_CHRG: 13893d0407baSopenharmony_ci DBG("dead charge...\n"); 13903d0407baSopenharmony_ci break; 13913d0407baSopenharmony_ci case TRICKLE_CHRG: 13923d0407baSopenharmony_ci DBG("trickle charge...\n"); 13933d0407baSopenharmony_ci break; 13943d0407baSopenharmony_ci case CC_OR_CV_CHRG: 13953d0407baSopenharmony_ci DBG("CC or CV charge...\n"); 13963d0407baSopenharmony_ci break; 13973d0407baSopenharmony_ci case CHARGE_FINISH: 13983d0407baSopenharmony_ci DBG("charge finish...\n"); 13993d0407baSopenharmony_ci break; 14003d0407baSopenharmony_ci case USB_OVER_VOL: 14013d0407baSopenharmony_ci DBG("USB over voltage...\n"); 14023d0407baSopenharmony_ci break; 14033d0407baSopenharmony_ci case BAT_TMP_ERR: 14043d0407baSopenharmony_ci DBG("battery temperature error...\n"); 14053d0407baSopenharmony_ci break; 14063d0407baSopenharmony_ci case BAT_TIM_ERR: 14073d0407baSopenharmony_ci DBG("battery timer error..\n"); 14083d0407baSopenharmony_ci break; 14093d0407baSopenharmony_ci default: 14103d0407baSopenharmony_ci break; 14113d0407baSopenharmony_ci } 14123d0407baSopenharmony_ci 14133d0407baSopenharmony_ci return status; 14143d0407baSopenharmony_ci} 14153d0407baSopenharmony_ci 14163d0407baSopenharmony_ci/* 14173d0407baSopenharmony_ci * cccv and finish switch all the time will cause dsoc freeze, 14183d0407baSopenharmony_ci * if so, do finish chrg, 100ma is less than min finish_ma. 14193d0407baSopenharmony_ci */ 14203d0407baSopenharmony_cistatic bool rk817_bat_fake_finish_mode(struct rk817_battery_device *battery) 14213d0407baSopenharmony_ci{ 14223d0407baSopenharmony_ci if ((battery->rsoc == 100) && 14233d0407baSopenharmony_ci (rk817_bat_get_charge_status(battery) == CC_OR_CV_CHRG) && 14243d0407baSopenharmony_ci (abs(battery->current_avg) <= 100)) 14253d0407baSopenharmony_ci return true; 14263d0407baSopenharmony_ci else 14273d0407baSopenharmony_ci return false; 14283d0407baSopenharmony_ci} 14293d0407baSopenharmony_ci 14303d0407baSopenharmony_cistatic int get_charge_status(struct rk817_battery_device *battery) 14313d0407baSopenharmony_ci{ 14323d0407baSopenharmony_ci return rk817_bat_get_charge_status(battery); 14333d0407baSopenharmony_ci} 14343d0407baSopenharmony_ci 14353d0407baSopenharmony_cistatic bool is_rk817_bat_ocv_valid(struct rk817_battery_device *battery) 14363d0407baSopenharmony_ci{ 14373d0407baSopenharmony_ci return (!battery->is_initialized && battery->pwroff_min >= 30); 14383d0407baSopenharmony_ci} 14393d0407baSopenharmony_ci 14403d0407baSopenharmony_cistatic void rk817_bat_gas_gaugle_enable(struct rk817_battery_device *battery) 14413d0407baSopenharmony_ci{ 14423d0407baSopenharmony_ci rk817_bat_field_write(battery, GG_EN, ENABLE); 14433d0407baSopenharmony_ci} 14443d0407baSopenharmony_ci 14453d0407baSopenharmony_cistatic void rk817_bat_gg_con_init(struct rk817_battery_device *battery) 14463d0407baSopenharmony_ci{ 14473d0407baSopenharmony_ci rk817_bat_field_write(battery, RLX_SPT, S_8_MIN); 14483d0407baSopenharmony_ci rk817_bat_field_write(battery, ADC_OFF_CAL_INTERV, S_8_MIN); 14493d0407baSopenharmony_ci rk817_bat_field_write(battery, VOL_OUT_MOD, AVERAGE_MODE); 14503d0407baSopenharmony_ci rk817_bat_field_write(battery, CUR_OUT_MOD, AVERAGE_MODE); 14513d0407baSopenharmony_ci} 14523d0407baSopenharmony_ci 14533d0407baSopenharmony_cistatic void rk817_bat_adc_init(struct rk817_battery_device *battery) 14543d0407baSopenharmony_ci{ 14553d0407baSopenharmony_ci rk817_bat_field_write(battery, SYS_VOL_ADC_EN, ENABLE); 14563d0407baSopenharmony_ci rk817_bat_field_write(battery, TS_ADC_EN, ENABLE); 14573d0407baSopenharmony_ci rk817_bat_field_write(battery, USB_VOL_ADC_EN, ENABLE); 14583d0407baSopenharmony_ci rk817_bat_field_write(battery, BAT_VOL_ADC_EN, ENABLE); 14593d0407baSopenharmony_ci rk817_bat_field_write(battery, BAT_CUR_ADC_EN, ENABLE); 14603d0407baSopenharmony_ci} 14613d0407baSopenharmony_ci 14623d0407baSopenharmony_cistatic void rk817_bat_init_info(struct rk817_battery_device *battery) 14633d0407baSopenharmony_ci{ 14643d0407baSopenharmony_ci battery->design_cap = battery->pdata->design_capacity; 14653d0407baSopenharmony_ci battery->qmax = battery->pdata->design_qmax; 14663d0407baSopenharmony_ci battery->bat_res = battery->pdata->bat_res; 14673d0407baSopenharmony_ci battery->monitor_ms = battery->pdata->monitor_sec * TIMER_MS_COUNTS; 14683d0407baSopenharmony_ci battery->res_div = (battery->pdata->sample_res == SAMPLE_RES_20MR) ? 14693d0407baSopenharmony_ci SAMPLE_RES_DIV2 : SAMPLE_RES_DIV1; 14703d0407baSopenharmony_ci DBG("battery->qmax :%d\n", battery->qmax); 14713d0407baSopenharmony_ci} 14723d0407baSopenharmony_ci 14733d0407baSopenharmony_cistatic int rk817_bat_get_prev_cap(struct rk817_battery_device *battery) 14743d0407baSopenharmony_ci{ 14753d0407baSopenharmony_ci int val = 0; 14763d0407baSopenharmony_ci 14773d0407baSopenharmony_ci val = rk817_bat_field_read(battery, REMAIN_CAP_REG2) << 16; 14783d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, REMAIN_CAP_REG1) << 8; 14793d0407baSopenharmony_ci val |= rk817_bat_field_read(battery, REMAIN_CAP_REG0) << 0; 14803d0407baSopenharmony_ci 14813d0407baSopenharmony_ci return val; 14823d0407baSopenharmony_ci} 14833d0407baSopenharmony_ci 14843d0407baSopenharmony_cistatic u8 rk817_bat_get_halt_cnt(struct rk817_battery_device *battery) 14853d0407baSopenharmony_ci{ 14863d0407baSopenharmony_ci return rk817_bat_field_read(battery, HALT_CNT_REG); 14873d0407baSopenharmony_ci} 14883d0407baSopenharmony_ci 14893d0407baSopenharmony_cistatic void rk817_bat_inc_halt_cnt(struct rk817_battery_device *battery) 14903d0407baSopenharmony_ci{ 14913d0407baSopenharmony_ci u8 cnt; 14923d0407baSopenharmony_ci 14933d0407baSopenharmony_ci cnt = rk817_bat_field_read(battery, HALT_CNT_REG); 14943d0407baSopenharmony_ci rk817_bat_field_write(battery, HALT_CNT_REG, ++cnt); 14953d0407baSopenharmony_ci} 14963d0407baSopenharmony_ci 14973d0407baSopenharmony_cistatic bool is_rk817_bat_last_halt(struct rk817_battery_device *battery) 14983d0407baSopenharmony_ci{ 14993d0407baSopenharmony_ci int pre_cap = rk817_bat_get_prev_cap(battery); 15003d0407baSopenharmony_ci int now_cap = rk817_bat_get_capacity_mah(battery); 15013d0407baSopenharmony_ci 15023d0407baSopenharmony_ci /* over 10%: system halt last time */ 15033d0407baSopenharmony_ci if (abs(now_cap - pre_cap) > (battery->fcc / 10)) { 15043d0407baSopenharmony_ci rk817_bat_inc_halt_cnt(battery); 15053d0407baSopenharmony_ci return true; 15063d0407baSopenharmony_ci } else { 15073d0407baSopenharmony_ci return false; 15083d0407baSopenharmony_ci } 15093d0407baSopenharmony_ci} 15103d0407baSopenharmony_ci 15113d0407baSopenharmony_cistatic u8 is_rk817_bat_initialized(struct rk817_battery_device *battery) 15123d0407baSopenharmony_ci{ 15133d0407baSopenharmony_ci u8 val = rk817_bat_field_read(battery, FG_INIT); 15143d0407baSopenharmony_ci 15153d0407baSopenharmony_ci if (val) { 15163d0407baSopenharmony_ci rk817_bat_field_write(battery, FG_INIT, 0x00); 15173d0407baSopenharmony_ci return true; 15183d0407baSopenharmony_ci } else { 15193d0407baSopenharmony_ci return false; 15203d0407baSopenharmony_ci } 15213d0407baSopenharmony_ci} 15223d0407baSopenharmony_ci 15233d0407baSopenharmony_cistatic void rk817_bat_calc_sm_linek(struct rk817_battery_device *battery) 15243d0407baSopenharmony_ci{ 15253d0407baSopenharmony_ci int linek; 15263d0407baSopenharmony_ci int diff, delta; 15273d0407baSopenharmony_ci int current_avg = rk817_bat_get_avg_current(battery); 15283d0407baSopenharmony_ci 15293d0407baSopenharmony_ci delta = abs(battery->dsoc - battery->rsoc); 15303d0407baSopenharmony_ci diff = delta * 3;/* speed:3/4 */ 15313d0407baSopenharmony_ci 15323d0407baSopenharmony_ci if (current_avg > 0) { 15333d0407baSopenharmony_ci if (battery->dsoc < battery->rsoc) 15343d0407baSopenharmony_ci linek = 1000 * (delta + diff) / DIV(diff); 15353d0407baSopenharmony_ci else if (battery->dsoc > battery->rsoc) 15363d0407baSopenharmony_ci linek = 1000 * diff / DIV(delta + diff); 15373d0407baSopenharmony_ci else 15383d0407baSopenharmony_ci linek = 1000; 15393d0407baSopenharmony_ci } else { 15403d0407baSopenharmony_ci if (battery->dsoc < battery->rsoc) 15413d0407baSopenharmony_ci linek = -1000 * diff / DIV(delta + diff); 15423d0407baSopenharmony_ci else if (battery->dsoc > battery->rsoc) 15433d0407baSopenharmony_ci linek = -1000 * (delta + diff) / DIV(diff); 15443d0407baSopenharmony_ci else 15453d0407baSopenharmony_ci linek = -1000; 15463d0407baSopenharmony_ci } 15473d0407baSopenharmony_ci 15483d0407baSopenharmony_ci battery->dbg_meet_soc = (battery->dsoc >= battery->rsoc) ? 15493d0407baSopenharmony_ci (battery->dsoc - diff) : (battery->rsoc - diff); 15503d0407baSopenharmony_ci 15513d0407baSopenharmony_ci battery->sm_linek = linek; 15523d0407baSopenharmony_ci battery->sm_remain_cap = battery->remain_cap; 15533d0407baSopenharmony_ci battery->dbg_calc_dsoc = battery->dsoc; 15543d0407baSopenharmony_ci battery->dbg_calc_rsoc = battery->rsoc; 15553d0407baSopenharmony_ci} 15563d0407baSopenharmony_ci 15573d0407baSopenharmony_cistatic void rk817_bat_smooth_algo_prepare(struct rk817_battery_device *battery) 15583d0407baSopenharmony_ci{ 15593d0407baSopenharmony_ci battery->smooth_soc = battery->dsoc; 15603d0407baSopenharmony_ci 15613d0407baSopenharmony_ci DBG("<%s>. dsoc=%d, dsoc:smooth_soc=%d\n", 15623d0407baSopenharmony_ci __func__, battery->dsoc, battery->smooth_soc); 15633d0407baSopenharmony_ci rk817_bat_calc_sm_linek(battery); 15643d0407baSopenharmony_ci} 15653d0407baSopenharmony_ci 15663d0407baSopenharmony_cistatic void rk817_bat_finish_algo_prepare(struct rk817_battery_device *battery) 15673d0407baSopenharmony_ci{ 15683d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 15693d0407baSopenharmony_ci 15703d0407baSopenharmony_ci if (!battery->finish_base) 15713d0407baSopenharmony_ci battery->finish_base = 1; 15723d0407baSopenharmony_ci} 15733d0407baSopenharmony_ci 15743d0407baSopenharmony_cistatic void rk817_bat_init_dsoc_algorithm(struct rk817_battery_device *battery) 15753d0407baSopenharmony_ci{ 15763d0407baSopenharmony_ci if (battery->dsoc >= 100 * 1000) 15773d0407baSopenharmony_ci battery->dsoc = 100 * 1000; 15783d0407baSopenharmony_ci else if (battery->dsoc <= 0) 15793d0407baSopenharmony_ci battery->dsoc = 0; 15803d0407baSopenharmony_ci /* init current mode */ 15813d0407baSopenharmony_ci battery->voltage_avg = rk817_bat_get_battery_voltage(battery); 15823d0407baSopenharmony_ci battery->current_avg = rk817_bat_get_avg_current(battery); 15833d0407baSopenharmony_ci 15843d0407baSopenharmony_ci if (get_charge_status(battery) == CHARGE_FINISH) { 15853d0407baSopenharmony_ci rk817_bat_finish_algo_prepare(battery); 15863d0407baSopenharmony_ci battery->work_mode = MODE_FINISH; 15873d0407baSopenharmony_ci } else { 15883d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 15893d0407baSopenharmony_ci battery->work_mode = MODE_SMOOTH; 15903d0407baSopenharmony_ci } 15913d0407baSopenharmony_ci DBG("%s, sm_remain_cap = %d, smooth_soc = %d\n", 15923d0407baSopenharmony_ci __func__, battery->sm_remain_cap, battery->smooth_soc); 15933d0407baSopenharmony_ci} 15943d0407baSopenharmony_ci 15953d0407baSopenharmony_cistatic void rk817_bat_first_pwron(struct rk817_battery_device *battery) 15963d0407baSopenharmony_ci{ 15973d0407baSopenharmony_ci battery->rsoc = 15983d0407baSopenharmony_ci rk817_bat_vol_to_soc(battery, 15993d0407baSopenharmony_ci battery->pwron_voltage) * 1000;/* uAH */ 16003d0407baSopenharmony_ci battery->dsoc = battery->rsoc; 16013d0407baSopenharmony_ci battery->fcc = battery->pdata->design_capacity; 16023d0407baSopenharmony_ci battery->nac = rk817_bat_vol_to_cap(battery, battery->pwron_voltage); 16033d0407baSopenharmony_ci 16043d0407baSopenharmony_ci rk817_bat_update_qmax(battery, battery->qmax); 16053d0407baSopenharmony_ci rk817_bat_save_fcc(battery, battery->fcc); 16063d0407baSopenharmony_ci DBG("%s, rsoc = %d, dsoc = %d, fcc = %d, nac = %d\n", 16073d0407baSopenharmony_ci __func__, battery->rsoc, battery->dsoc, battery->fcc, battery->nac); 16083d0407baSopenharmony_ci} 16093d0407baSopenharmony_ci 16103d0407baSopenharmony_cistatic void rk817_bat_not_first_pwron(struct rk817_battery_device *battery) 16113d0407baSopenharmony_ci{ 16123d0407baSopenharmony_ci int now_cap, pre_soc, pre_cap, ocv_cap, ocv_soc, ocv_vol; 16133d0407baSopenharmony_ci 16143d0407baSopenharmony_ci battery->fcc = rk817_bat_get_fcc(battery); 16153d0407baSopenharmony_ci pre_soc = rk817_bat_get_prev_dsoc(battery); 16163d0407baSopenharmony_ci pre_cap = rk817_bat_get_prev_cap(battery); 16173d0407baSopenharmony_ci now_cap = rk817_bat_get_capacity_mah(battery); 16183d0407baSopenharmony_ci battery->remain_cap = pre_cap * 1000; 16193d0407baSopenharmony_ci battery->is_halt = is_rk817_bat_last_halt(battery); 16203d0407baSopenharmony_ci battery->halt_cnt = rk817_bat_get_halt_cnt(battery); 16213d0407baSopenharmony_ci battery->is_initialized = is_rk817_bat_initialized(battery); 16223d0407baSopenharmony_ci battery->is_ocv_calib = is_rk817_bat_ocv_valid(battery); 16233d0407baSopenharmony_ci 16243d0407baSopenharmony_ci if (battery->is_halt) { 16253d0407baSopenharmony_ci BAT_INFO("system halt last time... cap: pre=%d, now=%d\n", 16263d0407baSopenharmony_ci pre_cap, now_cap); 16273d0407baSopenharmony_ci if (now_cap < 0) 16283d0407baSopenharmony_ci now_cap = 0; 16293d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, now_cap); 16303d0407baSopenharmony_ci pre_cap = now_cap; 16313d0407baSopenharmony_ci pre_soc = battery->rsoc; 16323d0407baSopenharmony_ci goto finish; 16333d0407baSopenharmony_ci } else if (battery->is_initialized) { 16343d0407baSopenharmony_ci /* uboot initialized */ 16353d0407baSopenharmony_ci BAT_INFO("initialized yet..\n"); 16363d0407baSopenharmony_ci goto finish; 16373d0407baSopenharmony_ci } else if (battery->is_ocv_calib) { 16383d0407baSopenharmony_ci /* not initialized and poweroff_cnt above 30 min */ 16393d0407baSopenharmony_ci ocv_vol = rk817_bat_get_ocv_voltage(battery); 16403d0407baSopenharmony_ci ocv_soc = rk817_bat_vol_to_soc(battery, ocv_vol); 16413d0407baSopenharmony_ci ocv_cap = rk817_bat_vol_to_cap(battery, ocv_vol); 16423d0407baSopenharmony_ci pre_cap = ocv_cap; 16433d0407baSopenharmony_ci battery->ocv_pre_dsoc = pre_soc; 16443d0407baSopenharmony_ci battery->ocv_new_dsoc = ocv_soc; 16453d0407baSopenharmony_ci if (abs(ocv_soc - pre_soc) >= battery->pdata->max_soc_offset) { 16463d0407baSopenharmony_ci battery->ocv_pre_dsoc = pre_soc; 16473d0407baSopenharmony_ci battery->ocv_new_dsoc = ocv_soc; 16483d0407baSopenharmony_ci battery->is_max_soc_offset = true; 16493d0407baSopenharmony_ci BAT_INFO("trigger max soc offset, dsoc: %d -> %d\n", 16503d0407baSopenharmony_ci pre_soc, ocv_soc); 16513d0407baSopenharmony_ci pre_soc = ocv_soc; 16523d0407baSopenharmony_ci } 16533d0407baSopenharmony_ci BAT_INFO("OCV calib: cap=%d, rsoc=%d\n", ocv_cap, ocv_soc); 16543d0407baSopenharmony_ci } else if (battery->pwroff_min > 0) { 16553d0407baSopenharmony_ci ocv_vol = rk817_bat_get_ocv_voltage(battery); 16563d0407baSopenharmony_ci ocv_soc = rk817_bat_vol_to_soc(battery, ocv_vol); 16573d0407baSopenharmony_ci ocv_cap = rk817_bat_vol_to_cap(battery, ocv_vol); 16583d0407baSopenharmony_ci battery->force_pre_dsoc = pre_soc; 16593d0407baSopenharmony_ci battery->force_new_dsoc = ocv_soc; 16603d0407baSopenharmony_ci if (abs(ocv_soc - pre_soc) >= 80) { 16613d0407baSopenharmony_ci battery->is_force_calib = true; 16623d0407baSopenharmony_ci BAT_INFO("dsoc force calib: %d -> %d\n", 16633d0407baSopenharmony_ci pre_soc, ocv_soc); 16643d0407baSopenharmony_ci pre_soc = ocv_soc; 16653d0407baSopenharmony_ci pre_cap = ocv_cap; 16663d0407baSopenharmony_ci } 16673d0407baSopenharmony_ci } 16683d0407baSopenharmony_cifinish: 16693d0407baSopenharmony_ci battery->dsoc = pre_soc; 16703d0407baSopenharmony_ci battery->nac = pre_cap; 16713d0407baSopenharmony_ci if (battery->nac < 0) 16723d0407baSopenharmony_ci battery->nac = 0; 16733d0407baSopenharmony_ci 16743d0407baSopenharmony_ci DBG("dsoc=%d cap=%d v=%d ov=%d rv=%d min=%d psoc=%d pcap=%d\n", 16753d0407baSopenharmony_ci battery->dsoc, battery->nac, rk817_bat_get_battery_voltage(battery), 16763d0407baSopenharmony_ci rk817_bat_get_ocv_voltage(battery), 16773d0407baSopenharmony_ci rk817_bat_get_relax_voltage(battery), 16783d0407baSopenharmony_ci battery->pwroff_min, rk817_bat_get_prev_dsoc(battery), 16793d0407baSopenharmony_ci rk817_bat_get_prev_cap(battery)); 16803d0407baSopenharmony_ci} 16813d0407baSopenharmony_ci 16823d0407baSopenharmony_cistatic void rk817_bat_rsoc_init(struct rk817_battery_device *battery) 16833d0407baSopenharmony_ci{ 16843d0407baSopenharmony_ci battery->is_first_power_on = is_rk817_bat_first_pwron(battery); 16853d0407baSopenharmony_ci battery->pwroff_min = rk817_bat_get_off_count(battery); 16863d0407baSopenharmony_ci battery->pwron_voltage = rk817_bat_get_pwron_voltage(battery); 16873d0407baSopenharmony_ci 16883d0407baSopenharmony_ci DBG("%s, is_first_power_on = %d, pwroff_min = %d, pwron_voltage = %d\n", 16893d0407baSopenharmony_ci __func__, battery->is_first_power_on, 16903d0407baSopenharmony_ci battery->pwroff_min, battery->pwron_voltage); 16913d0407baSopenharmony_ci 16923d0407baSopenharmony_ci if (battery->is_first_power_on) 16933d0407baSopenharmony_ci rk817_bat_first_pwron(battery); 16943d0407baSopenharmony_ci else 16953d0407baSopenharmony_ci rk817_bat_not_first_pwron(battery); 16963d0407baSopenharmony_ci 16973d0407baSopenharmony_ci rk817_bat_save_dsoc(battery, battery->dsoc); 16983d0407baSopenharmony_ci} 16993d0407baSopenharmony_ci 17003d0407baSopenharmony_cistatic void rk817_bat_caltimer_isr(struct timer_list *t) 17013d0407baSopenharmony_ci{ 17023d0407baSopenharmony_ci struct rk817_battery_device *battery = 17033d0407baSopenharmony_ci from_timer(battery, t, caltimer); 17043d0407baSopenharmony_ci 17053d0407baSopenharmony_ci mod_timer(&battery->caltimer, jiffies + MINUTE(8) * HZ); 17063d0407baSopenharmony_ci queue_delayed_work(battery->bat_monitor_wq, 17073d0407baSopenharmony_ci &battery->calib_delay_work, 17083d0407baSopenharmony_ci msecs_to_jiffies(10)); 17093d0407baSopenharmony_ci} 17103d0407baSopenharmony_ci 17113d0407baSopenharmony_cistatic void rk817_bat_internal_calib(struct work_struct *work) 17123d0407baSopenharmony_ci{ 17133d0407baSopenharmony_ci struct rk817_battery_device *battery = container_of(work, 17143d0407baSopenharmony_ci struct rk817_battery_device, calib_delay_work.work); 17153d0407baSopenharmony_ci 17163d0407baSopenharmony_ci return; 17173d0407baSopenharmony_ci 17183d0407baSopenharmony_ci rk817_bat_current_calibration(battery); 17193d0407baSopenharmony_ci /* calib voltage kb */ 17203d0407baSopenharmony_ci rk817_bat_init_voltage_kb(battery); 17213d0407baSopenharmony_ci 17223d0407baSopenharmony_ci DBG("caltimer:coffset=0x%x\n", rk817_bat_get_coffset(battery)); 17233d0407baSopenharmony_ci} 17243d0407baSopenharmony_ci 17253d0407baSopenharmony_cistatic void rk817_bat_init_caltimer(struct rk817_battery_device *battery) 17263d0407baSopenharmony_ci{ 17273d0407baSopenharmony_ci timer_setup(&battery->caltimer, 17283d0407baSopenharmony_ci rk817_bat_caltimer_isr, 17293d0407baSopenharmony_ci 0); 17303d0407baSopenharmony_ci battery->caltimer.expires = jiffies + MINUTE(8) * HZ; 17313d0407baSopenharmony_ci add_timer(&battery->caltimer); 17323d0407baSopenharmony_ci INIT_DELAYED_WORK(&battery->calib_delay_work, rk817_bat_internal_calib); 17333d0407baSopenharmony_ci} 17343d0407baSopenharmony_ci 17353d0407baSopenharmony_cistatic void rk817_bat_init_fg(struct rk817_battery_device *battery) 17363d0407baSopenharmony_ci{ 17373d0407baSopenharmony_ci rk817_bat_adc_init(battery); 17383d0407baSopenharmony_ci rk817_bat_gas_gaugle_enable(battery); 17393d0407baSopenharmony_ci rk817_bat_gg_con_init(battery); 17403d0407baSopenharmony_ci rk817_bat_init_voltage_kb(battery); 17413d0407baSopenharmony_ci rk817_bat_set_relax_sample(battery); 17423d0407baSopenharmony_ci rk817_bat_ocv_thre(battery, 0xff); 17433d0407baSopenharmony_ci rk817_bat_init_caltimer(battery); 17443d0407baSopenharmony_ci rk817_bat_rsoc_init(battery); 17453d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, battery->nac); 17463d0407baSopenharmony_ci DBG("rsoc%d, fcc = %d\n", battery->rsoc, battery->fcc); 17473d0407baSopenharmony_ci rk817_bat_init_dsoc_algorithm(battery); 17483d0407baSopenharmony_ci battery->qmax = rk817_bat_get_qmax(battery); 17493d0407baSopenharmony_ci battery->voltage_avg = rk817_bat_get_battery_voltage(battery); 17503d0407baSopenharmony_ci battery->voltage_sys = rk817_bat_get_sys_voltage(battery); 17513d0407baSopenharmony_ci 17523d0407baSopenharmony_ci battery->voltage_ocv = rk817_bat_get_ocv_voltage(battery); 17533d0407baSopenharmony_ci battery->voltage_relax = rk817_bat_get_relax_voltage(battery); 17543d0407baSopenharmony_ci battery->current_avg = rk817_bat_get_avg_current(battery); 17553d0407baSopenharmony_ci battery->dbg_pwr_dsoc = battery->dsoc; 17563d0407baSopenharmony_ci battery->dbg_pwr_rsoc = battery->rsoc; 17573d0407baSopenharmony_ci battery->dbg_pwr_vol = battery->voltage_avg; 17583d0407baSopenharmony_ci battery->temperature = VIRTUAL_TEMPERATURE; 17593d0407baSopenharmony_ci 17603d0407baSopenharmony_ci DBG("probe init: battery->dsoc = %d, rsoc = %d\n" 17613d0407baSopenharmony_ci "remain_cap = %d\n, battery_vol = %d\n, system_vol = %d, qmax = %d\n", 17623d0407baSopenharmony_ci battery->dsoc, battery->rsoc, battery->remain_cap, 17633d0407baSopenharmony_ci battery->voltage_avg, battery->voltage_sys, battery->qmax); 17643d0407baSopenharmony_ci DBG("OCV_THRE_VOL: 0x%x", rk817_bat_field_read(battery, OCV_THRE_VOL)); 17653d0407baSopenharmony_ci} 17663d0407baSopenharmony_ci 17673d0407baSopenharmony_cistatic int rk817_bat_parse_dt(struct rk817_battery_device *battery) 17683d0407baSopenharmony_ci{ 17693d0407baSopenharmony_ci u32 out_value; 17703d0407baSopenharmony_ci int length, ret; 17713d0407baSopenharmony_ci size_t size; 17723d0407baSopenharmony_ci struct battery_platform_data *pdata; 17733d0407baSopenharmony_ci struct device *dev = battery->dev; 17743d0407baSopenharmony_ci struct device_node *np = battery->dev->of_node; 17753d0407baSopenharmony_ci 17763d0407baSopenharmony_ci pdata = devm_kzalloc(battery->dev, sizeof(*pdata), GFP_KERNEL); 17773d0407baSopenharmony_ci if (!pdata) 17783d0407baSopenharmony_ci return -ENOMEM; 17793d0407baSopenharmony_ci 17803d0407baSopenharmony_ci battery->pdata = pdata; 17813d0407baSopenharmony_ci /* init default param */ 17823d0407baSopenharmony_ci pdata->bat_res = DEFAULT_BAT_RES; 17833d0407baSopenharmony_ci pdata->monitor_sec = DEFAULT_MONITOR_SEC; 17843d0407baSopenharmony_ci pdata->pwroff_vol = DEFAULT_PWROFF_VOL_THRESD; 17853d0407baSopenharmony_ci pdata->sleep_exit_current = DEFAULT_SLP_EXIT_CUR; 17863d0407baSopenharmony_ci pdata->sleep_enter_current = DEFAULT_SLP_ENTER_CUR; 17873d0407baSopenharmony_ci 17883d0407baSopenharmony_ci pdata->sleep_filter_current = DEFAULT_SLP_FILTER_CUR; 17893d0407baSopenharmony_ci pdata->bat_mode = MODE_BATTARY; 17903d0407baSopenharmony_ci pdata->max_soc_offset = DEFAULT_MAX_SOC_OFFSET; 17913d0407baSopenharmony_ci pdata->fb_temp = DEFAULT_FB_TEMP; 17923d0407baSopenharmony_ci pdata->energy_mode = DEFAULT_ENERGY_MODE; 17933d0407baSopenharmony_ci pdata->zero_reserve_dsoc = DEFAULT_ZERO_RESERVE_DSOC * 1000; 17943d0407baSopenharmony_ci 17953d0407baSopenharmony_ci pdata->sample_res = DEFAULT_SAMPLE_RES; 17963d0407baSopenharmony_ci 17973d0407baSopenharmony_ci /* parse necessary param */ 17983d0407baSopenharmony_ci if (!of_find_property(np, "ocv_table", &length)) { 17993d0407baSopenharmony_ci dev_err(dev, "ocv_table not found!\n"); 18003d0407baSopenharmony_ci return -EINVAL; 18013d0407baSopenharmony_ci } 18023d0407baSopenharmony_ci 18033d0407baSopenharmony_ci pdata->ocv_size = length / sizeof(u32); 18043d0407baSopenharmony_ci if (pdata->ocv_size <= 0) { 18053d0407baSopenharmony_ci dev_err(dev, "invalid ocv table\n"); 18063d0407baSopenharmony_ci return -EINVAL; 18073d0407baSopenharmony_ci } 18083d0407baSopenharmony_ci 18093d0407baSopenharmony_ci size = sizeof(*pdata->ocv_table) * pdata->ocv_size; 18103d0407baSopenharmony_ci pdata->ocv_table = devm_kzalloc(battery->dev, size, GFP_KERNEL); 18113d0407baSopenharmony_ci if (!pdata->ocv_table) 18123d0407baSopenharmony_ci return -ENOMEM; 18133d0407baSopenharmony_ci 18143d0407baSopenharmony_ci ret = of_property_read_u32_array(np, "ocv_table", pdata->ocv_table, 18153d0407baSopenharmony_ci pdata->ocv_size); 18163d0407baSopenharmony_ci if (ret < 0) 18173d0407baSopenharmony_ci return ret; 18183d0407baSopenharmony_ci 18193d0407baSopenharmony_ci ret = of_property_read_u32(np, "design_capacity", &out_value); 18203d0407baSopenharmony_ci if (ret < 0) { 18213d0407baSopenharmony_ci dev_err(dev, "design_capacity not found!\n"); 18223d0407baSopenharmony_ci return ret; 18233d0407baSopenharmony_ci } 18243d0407baSopenharmony_ci pdata->design_capacity = out_value; 18253d0407baSopenharmony_ci 18263d0407baSopenharmony_ci ret = of_property_read_u32(np, "design_qmax", &out_value); 18273d0407baSopenharmony_ci if (ret < 0) { 18283d0407baSopenharmony_ci dev_err(dev, "design_qmax not found!\n"); 18293d0407baSopenharmony_ci return ret; 18303d0407baSopenharmony_ci } 18313d0407baSopenharmony_ci pdata->design_qmax = out_value; 18323d0407baSopenharmony_ci 18333d0407baSopenharmony_ci /* parse unnecessary param */ 18343d0407baSopenharmony_ci ret = of_property_read_u32(np, "sample_res", &pdata->sample_res); 18353d0407baSopenharmony_ci if (ret < 0) 18363d0407baSopenharmony_ci dev_err(dev, "sample_res missing!\n"); 18373d0407baSopenharmony_ci 18383d0407baSopenharmony_ci ret = of_property_read_u32(np, "fb_temperature", &pdata->fb_temp); 18393d0407baSopenharmony_ci if (ret < 0) 18403d0407baSopenharmony_ci dev_err(dev, "fb_temperature missing!\n"); 18413d0407baSopenharmony_ci 18423d0407baSopenharmony_ci ret = of_property_read_u32(np, "energy_mode", &pdata->energy_mode); 18433d0407baSopenharmony_ci if (ret < 0) 18443d0407baSopenharmony_ci dev_err(dev, "energy_mode missing!\n"); 18453d0407baSopenharmony_ci 18463d0407baSopenharmony_ci ret = of_property_read_u32(np, "max_soc_offset", 18473d0407baSopenharmony_ci &pdata->max_soc_offset); 18483d0407baSopenharmony_ci if (ret < 0) 18493d0407baSopenharmony_ci dev_err(dev, "max_soc_offset missing!\n"); 18503d0407baSopenharmony_ci 18513d0407baSopenharmony_ci ret = of_property_read_u32(np, "monitor_sec", &pdata->monitor_sec); 18523d0407baSopenharmony_ci if (ret < 0) 18533d0407baSopenharmony_ci dev_err(dev, "monitor_sec missing!\n"); 18543d0407baSopenharmony_ci 18553d0407baSopenharmony_ci ret = of_property_read_u32(np, "zero_algorithm_vol", 18563d0407baSopenharmony_ci &pdata->zero_algorithm_vol); 18573d0407baSopenharmony_ci if (ret < 0) 18583d0407baSopenharmony_ci dev_err(dev, "zero_algorithm_vol missing!\n"); 18593d0407baSopenharmony_ci 18603d0407baSopenharmony_ci ret = of_property_read_u32(np, "zero_reserve_dsoc", 18613d0407baSopenharmony_ci &pdata->zero_reserve_dsoc); 18623d0407baSopenharmony_ci if (ret < 0) 18633d0407baSopenharmony_ci dev_err(dev, "zero_reserve_dsoc missing!\n"); 18643d0407baSopenharmony_ci pdata->zero_reserve_dsoc *= 1000; 18653d0407baSopenharmony_ci 18663d0407baSopenharmony_ci ret = of_property_read_u32(np, "virtual_power", &pdata->bat_mode); 18673d0407baSopenharmony_ci if (ret < 0) 18683d0407baSopenharmony_ci dev_err(dev, "virtual_power missing!\n"); 18693d0407baSopenharmony_ci 18703d0407baSopenharmony_ci ret = of_property_read_u32(np, "bat_res", &pdata->bat_res); 18713d0407baSopenharmony_ci if (ret < 0) 18723d0407baSopenharmony_ci dev_err(dev, "bat_res missing!\n"); 18733d0407baSopenharmony_ci 18743d0407baSopenharmony_ci ret = of_property_read_u32(np, "sleep_enter_current", 18753d0407baSopenharmony_ci &pdata->sleep_enter_current); 18763d0407baSopenharmony_ci if (ret < 0) 18773d0407baSopenharmony_ci dev_err(dev, "sleep_enter_current missing!\n"); 18783d0407baSopenharmony_ci 18793d0407baSopenharmony_ci ret = of_property_read_u32(np, "sleep_exit_current", 18803d0407baSopenharmony_ci &pdata->sleep_exit_current); 18813d0407baSopenharmony_ci if (ret < 0) 18823d0407baSopenharmony_ci dev_err(dev, "sleep_exit_current missing!\n"); 18833d0407baSopenharmony_ci 18843d0407baSopenharmony_ci ret = of_property_read_u32(np, "sleep_filter_current", 18853d0407baSopenharmony_ci &pdata->sleep_filter_current); 18863d0407baSopenharmony_ci if (ret < 0) 18873d0407baSopenharmony_ci dev_err(dev, "sleep_filter_current missing!\n"); 18883d0407baSopenharmony_ci 18893d0407baSopenharmony_ci ret = of_property_read_u32(np, "power_off_thresd", &pdata->pwroff_vol); 18903d0407baSopenharmony_ci if (ret < 0) 18913d0407baSopenharmony_ci dev_err(dev, "power_off_thresd missing!\n"); 18923d0407baSopenharmony_ci 18933d0407baSopenharmony_ci ret = of_property_read_u32(np, "low_power_sleep", &pdata->low_pwr_sleep); 18943d0407baSopenharmony_ci if (ret < 0) 18953d0407baSopenharmony_ci dev_info(dev, "low_power_sleep missing!\n"); 18963d0407baSopenharmony_ci 18973d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) { 18983d0407baSopenharmony_ci ret = of_property_read_u32(np, "bat_res_up", 18993d0407baSopenharmony_ci &pdata->bat_res_up); 19003d0407baSopenharmony_ci if (ret < 0) 19013d0407baSopenharmony_ci dev_err(dev, "battery res_up missing\n"); 19023d0407baSopenharmony_ci 19033d0407baSopenharmony_ci ret = of_property_read_u32(np, "bat_res_down", 19043d0407baSopenharmony_ci &pdata->bat_res_down); 19053d0407baSopenharmony_ci if (ret < 0) 19063d0407baSopenharmony_ci dev_err(dev, "battery res_down missing!\n"); 19073d0407baSopenharmony_ci 19083d0407baSopenharmony_ci ret = of_property_read_u32(np, "design_max_voltage", 19093d0407baSopenharmony_ci &pdata->design_max_voltage); 19103d0407baSopenharmony_ci if (ret < 0) 19113d0407baSopenharmony_ci dev_err(dev, "battery design_max_voltage missing!\n"); 19123d0407baSopenharmony_ci 19133d0407baSopenharmony_ci ret = of_property_read_u32(np, "register_chg_psy", 19143d0407baSopenharmony_ci &battery->is_register_chg_psy); 19153d0407baSopenharmony_ci if (ret < 0 || !battery->is_register_chg_psy) 19163d0407baSopenharmony_ci dev_err(dev, "not have to register chg psy!\n"); 19173d0407baSopenharmony_ci } 19183d0407baSopenharmony_ci 19193d0407baSopenharmony_ci DBG("the battery dts info dump:\n" 19203d0407baSopenharmony_ci "bat_res:%d\n" 19213d0407baSopenharmony_ci "res_sample:%d\n" 19223d0407baSopenharmony_ci "design_capacity:%d\n" 19233d0407baSopenharmony_ci "design_qmax :%d\n" 19243d0407baSopenharmony_ci "sleep_enter_current:%d\n" 19253d0407baSopenharmony_ci "sleep_exit_current:%d\n" 19263d0407baSopenharmony_ci "sleep_filter_current:%d\n" 19273d0407baSopenharmony_ci "zero_algorithm_vol:%d\n" 19283d0407baSopenharmony_ci "zero_reserve_dsoc:%d\n" 19293d0407baSopenharmony_ci "monitor_sec:%d\n" 19303d0407baSopenharmony_ci "max_soc_offset:%d\n" 19313d0407baSopenharmony_ci "virtual_power:%d\n" 19323d0407baSopenharmony_ci "pwroff_vol:%d\n", 19333d0407baSopenharmony_ci pdata->bat_res, 19343d0407baSopenharmony_ci pdata->sample_res, 19353d0407baSopenharmony_ci pdata->design_capacity, 19363d0407baSopenharmony_ci pdata->design_qmax, 19373d0407baSopenharmony_ci pdata->sleep_enter_current, 19383d0407baSopenharmony_ci pdata->sleep_exit_current, 19393d0407baSopenharmony_ci pdata->sleep_filter_current, 19403d0407baSopenharmony_ci pdata->zero_algorithm_vol, 19413d0407baSopenharmony_ci pdata->zero_reserve_dsoc, 19423d0407baSopenharmony_ci pdata->monitor_sec, 19433d0407baSopenharmony_ci pdata->max_soc_offset, 19443d0407baSopenharmony_ci pdata->bat_mode, 19453d0407baSopenharmony_ci pdata->pwroff_vol); 19463d0407baSopenharmony_ci 19473d0407baSopenharmony_ci return 0; 19483d0407baSopenharmony_ci} 19493d0407baSopenharmony_ci 19503d0407baSopenharmony_cistatic enum power_supply_property rk817_bat_props[] = { 19513d0407baSopenharmony_ci POWER_SUPPLY_PROP_STATUS, 19523d0407baSopenharmony_ci POWER_SUPPLY_PROP_CURRENT_NOW, 19533d0407baSopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_NOW, 19543d0407baSopenharmony_ci POWER_SUPPLY_PROP_HEALTH, 19553d0407baSopenharmony_ci POWER_SUPPLY_PROP_CAPACITY, 19563d0407baSopenharmony_ci POWER_SUPPLY_PROP_CAPACITY_LEVEL, 19573d0407baSopenharmony_ci POWER_SUPPLY_PROP_TEMP, 19583d0407baSopenharmony_ci POWER_SUPPLY_PROP_CHARGE_COUNTER, 19593d0407baSopenharmony_ci POWER_SUPPLY_PROP_CHARGE_FULL, 19603d0407baSopenharmony_ci POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 19613d0407baSopenharmony_ci POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 19623d0407baSopenharmony_ci}; 19633d0407baSopenharmony_ci 19643d0407baSopenharmony_cistatic int rk817_bat_get_usb_psy(struct device *dev, void *data) 19653d0407baSopenharmony_ci{ 19663d0407baSopenharmony_ci struct rk817_battery_device *battery = data; 19673d0407baSopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 19683d0407baSopenharmony_ci 19693d0407baSopenharmony_ci if (psy->desc->type == POWER_SUPPLY_TYPE_USB) { 19703d0407baSopenharmony_ci battery->usb_psy = psy; 19713d0407baSopenharmony_ci return 1; 19723d0407baSopenharmony_ci } 19733d0407baSopenharmony_ci 19743d0407baSopenharmony_ci return 0; 19753d0407baSopenharmony_ci} 19763d0407baSopenharmony_ci 19773d0407baSopenharmony_cistatic int rk817_bat_get_ac_psy(struct device *dev, void *data) 19783d0407baSopenharmony_ci{ 19793d0407baSopenharmony_ci struct rk817_battery_device *battery = data; 19803d0407baSopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 19813d0407baSopenharmony_ci 19823d0407baSopenharmony_ci if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) { 19833d0407baSopenharmony_ci battery->ac_psy = psy; 19843d0407baSopenharmony_ci return 1; 19853d0407baSopenharmony_ci } 19863d0407baSopenharmony_ci 19873d0407baSopenharmony_ci return 0; 19883d0407baSopenharmony_ci} 19893d0407baSopenharmony_ci 19903d0407baSopenharmony_cistatic void rk817_bat_get_chrg_psy(struct rk817_battery_device *battery) 19913d0407baSopenharmony_ci{ 19923d0407baSopenharmony_ci if (!battery->usb_psy) 19933d0407baSopenharmony_ci class_for_each_device(power_supply_class, NULL, (void *)battery, 19943d0407baSopenharmony_ci rk817_bat_get_usb_psy); 19953d0407baSopenharmony_ci if (!battery->ac_psy) 19963d0407baSopenharmony_ci class_for_each_device(power_supply_class, NULL, (void *)battery, 19973d0407baSopenharmony_ci rk817_bat_get_ac_psy); 19983d0407baSopenharmony_ci} 19993d0407baSopenharmony_ci 20003d0407baSopenharmony_cistatic int rk817_bat_get_charge_state(struct rk817_battery_device *battery) 20013d0407baSopenharmony_ci{ 20023d0407baSopenharmony_ci union power_supply_propval val; 20033d0407baSopenharmony_ci int ret; 20043d0407baSopenharmony_ci struct power_supply *psy; 20053d0407baSopenharmony_ci 20063d0407baSopenharmony_ci if (!battery->usb_psy || !battery->ac_psy) 20073d0407baSopenharmony_ci rk817_bat_get_chrg_psy(battery); 20083d0407baSopenharmony_ci 20093d0407baSopenharmony_ci psy = battery->usb_psy; 20103d0407baSopenharmony_ci if (psy) { 20113d0407baSopenharmony_ci ret = psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE, 20123d0407baSopenharmony_ci &val); 20133d0407baSopenharmony_ci if (!ret) 20143d0407baSopenharmony_ci battery->usb_in = val.intval; 20153d0407baSopenharmony_ci } 20163d0407baSopenharmony_ci 20173d0407baSopenharmony_ci psy = battery->ac_psy; 20183d0407baSopenharmony_ci if (psy) { 20193d0407baSopenharmony_ci ret = psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE, 20203d0407baSopenharmony_ci &val); 20213d0407baSopenharmony_ci if (!ret) 20223d0407baSopenharmony_ci battery->ac_in = val.intval; 20233d0407baSopenharmony_ci } 20243d0407baSopenharmony_ci 20253d0407baSopenharmony_ci DBG("%s: ac_online=%d, usb_online=%d\n", 20263d0407baSopenharmony_ci __func__, battery->ac_in, battery->usb_in); 20273d0407baSopenharmony_ci 20283d0407baSopenharmony_ci return (battery->usb_in || battery->ac_in); 20293d0407baSopenharmony_ci} 20303d0407baSopenharmony_ci 20313d0407baSopenharmony_cistatic int rk817_get_capacity_leve(struct rk817_battery_device *battery) 20323d0407baSopenharmony_ci{ 20333d0407baSopenharmony_ci int dsoc; 20343d0407baSopenharmony_ci 20353d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 20363d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 20373d0407baSopenharmony_ci 20383d0407baSopenharmony_ci dsoc = (battery->dsoc + 500) / 1000; 20393d0407baSopenharmony_ci if (dsoc < 1) 20403d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 20413d0407baSopenharmony_ci else if (dsoc <= 20) 20423d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_LOW; 20433d0407baSopenharmony_ci else if (dsoc <= 70) 20443d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 20453d0407baSopenharmony_ci else if (dsoc <= 90) 20463d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_HIGH; 20473d0407baSopenharmony_ci else 20483d0407baSopenharmony_ci return POWER_SUPPLY_CAPACITY_LEVEL_FULL; 20493d0407baSopenharmony_ci} 20503d0407baSopenharmony_ci 20513d0407baSopenharmony_cistatic int rk817_battery_time_to_full(struct rk817_battery_device *battery) 20523d0407baSopenharmony_ci{ 20533d0407baSopenharmony_ci int time_sec; 20543d0407baSopenharmony_ci int cap_temp; 20553d0407baSopenharmony_ci 20563d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) { 20573d0407baSopenharmony_ci time_sec = 3600; 20583d0407baSopenharmony_ci } else if (battery->voltage_avg > 0) { 20593d0407baSopenharmony_ci cap_temp = battery->design_cap - (battery->remain_cap / 1000); 20603d0407baSopenharmony_ci if (cap_temp < 0) 20613d0407baSopenharmony_ci cap_temp = 0; 20623d0407baSopenharmony_ci time_sec = (3600 * cap_temp) / battery->voltage_avg; 20633d0407baSopenharmony_ci } else { 20643d0407baSopenharmony_ci time_sec = 3600 * 24; /* One day */ 20653d0407baSopenharmony_ci } 20663d0407baSopenharmony_ci 20673d0407baSopenharmony_ci return time_sec; 20683d0407baSopenharmony_ci} 20693d0407baSopenharmony_ci 20703d0407baSopenharmony_cistatic int rk817_battery_get_property(struct power_supply *psy, 20713d0407baSopenharmony_ci enum power_supply_property psp, 20723d0407baSopenharmony_ci union power_supply_propval *val) 20733d0407baSopenharmony_ci{ 20743d0407baSopenharmony_ci struct rk817_battery_device *battery = power_supply_get_drvdata(psy); 20753d0407baSopenharmony_ci 20763d0407baSopenharmony_ci switch (psp) { 20773d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CURRENT_NOW: 20783d0407baSopenharmony_ci val->intval = battery->current_avg * 1000;/*uA*/ 20793d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 20803d0407baSopenharmony_ci val->intval = VIRTUAL_CURRENT * 1000; 20813d0407baSopenharmony_ci break; 20823d0407baSopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_NOW: 20833d0407baSopenharmony_ci val->intval = battery->voltage_avg * 1000;/*uV*/ 20843d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 20853d0407baSopenharmony_ci val->intval = VIRTUAL_VOLTAGE * 1000; 20863d0407baSopenharmony_ci break; 20873d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY: 20883d0407baSopenharmony_ci val->intval = (battery->dsoc + 500) / 1000; 20893d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 20903d0407baSopenharmony_ci val->intval = VIRTUAL_SOC; 20913d0407baSopenharmony_ci break; 20923d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 20933d0407baSopenharmony_ci val->intval = rk817_get_capacity_leve(battery); 20943d0407baSopenharmony_ci break; 20953d0407baSopenharmony_ci case POWER_SUPPLY_PROP_HEALTH: 20963d0407baSopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_GOOD; 20973d0407baSopenharmony_ci break; 20983d0407baSopenharmony_ci case POWER_SUPPLY_PROP_TEMP: 20993d0407baSopenharmony_ci val->intval = battery->temperature; 21003d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 21013d0407baSopenharmony_ci val->intval = VIRTUAL_TEMPERATURE; 21023d0407baSopenharmony_ci break; 21033d0407baSopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 21043d0407baSopenharmony_ci if (battery->pdata->bat_mode == MODE_VIRTUAL) 21053d0407baSopenharmony_ci val->intval = VIRTUAL_STATUS; 21063d0407baSopenharmony_ci else if (battery->dsoc == 100 * 1000) 21073d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_FULL; 21083d0407baSopenharmony_ci else { 21093d0407baSopenharmony_ci if ((battery->chip_id != RK809_ID) && 21103d0407baSopenharmony_ci rk817_bat_get_charge_state(battery)) 21113d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 21123d0407baSopenharmony_ci else if (battery->chip_id == RK809_ID && 21133d0407baSopenharmony_ci battery->plugin_trigger) 21143d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 21153d0407baSopenharmony_ci else 21163d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 21173d0407baSopenharmony_ci } 21183d0407baSopenharmony_ci break; 21193d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_COUNTER: 21203d0407baSopenharmony_ci val->intval = battery->charge_count; 21213d0407baSopenharmony_ci break; 21223d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_FULL: 21233d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 21243d0407baSopenharmony_ci val->intval = battery->pdata->design_capacity * 1000;/* uAh */ 21253d0407baSopenharmony_ci break; 21263d0407baSopenharmony_ci case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 21273d0407baSopenharmony_ci val->intval = rk817_battery_time_to_full(battery); 21283d0407baSopenharmony_ci break; 21293d0407baSopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 21303d0407baSopenharmony_ci val->intval = 4500 * 1000; 21313d0407baSopenharmony_ci break; 21323d0407baSopenharmony_ci case POWER_SUPPLY_PROP_CURRENT_MAX: 21333d0407baSopenharmony_ci val->intval = 5000 * 1000; 21343d0407baSopenharmony_ci break; 21353d0407baSopenharmony_ci default: 21363d0407baSopenharmony_ci return -EINVAL; 21373d0407baSopenharmony_ci } 21383d0407baSopenharmony_ci 21393d0407baSopenharmony_ci return 0; 21403d0407baSopenharmony_ci} 21413d0407baSopenharmony_ci 21423d0407baSopenharmony_cistatic const struct power_supply_desc rk817_bat_desc = { 21433d0407baSopenharmony_ci .name = "battery", 21443d0407baSopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 21453d0407baSopenharmony_ci .properties = rk817_bat_props, 21463d0407baSopenharmony_ci .num_properties = ARRAY_SIZE(rk817_bat_props), 21473d0407baSopenharmony_ci .get_property = rk817_battery_get_property, 21483d0407baSopenharmony_ci}; 21493d0407baSopenharmony_ci 21503d0407baSopenharmony_cistatic int rk817_bat_init_power_supply(struct rk817_battery_device *battery) 21513d0407baSopenharmony_ci{ 21523d0407baSopenharmony_ci struct power_supply_config psy_cfg = { .drv_data = battery, }; 21533d0407baSopenharmony_ci 21543d0407baSopenharmony_ci battery->bat = devm_power_supply_register(battery->dev, 21553d0407baSopenharmony_ci &rk817_bat_desc, 21563d0407baSopenharmony_ci &psy_cfg); 21573d0407baSopenharmony_ci if (IS_ERR(battery->bat)) { 21583d0407baSopenharmony_ci dev_err(battery->dev, "register bat power supply fail\n"); 21593d0407baSopenharmony_ci return PTR_ERR(battery->bat); 21603d0407baSopenharmony_ci } 21613d0407baSopenharmony_ci 21623d0407baSopenharmony_ci return 0; 21633d0407baSopenharmony_ci} 21643d0407baSopenharmony_ci 21653d0407baSopenharmony_cistatic enum power_supply_property rk809_chg_props[] = { 21663d0407baSopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 21673d0407baSopenharmony_ci POWER_SUPPLY_PROP_STATUS, 21683d0407baSopenharmony_ci}; 21693d0407baSopenharmony_ci 21703d0407baSopenharmony_cistatic int rk809_chg_get_property(struct power_supply *psy, 21713d0407baSopenharmony_ci enum power_supply_property psp, 21723d0407baSopenharmony_ci union power_supply_propval *val) 21733d0407baSopenharmony_ci{ 21743d0407baSopenharmony_ci struct rk817_battery_device *battery = power_supply_get_drvdata(psy); 21753d0407baSopenharmony_ci int online = 0; 21763d0407baSopenharmony_ci int ret = 0; 21773d0407baSopenharmony_ci 21783d0407baSopenharmony_ci if (battery->plugin_trigger) 21793d0407baSopenharmony_ci online = 1; 21803d0407baSopenharmony_ci switch (psp) { 21813d0407baSopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 21823d0407baSopenharmony_ci val->intval = online; 21833d0407baSopenharmony_ci dev_dbg(battery->dev, "report online: %d\n", val->intval); 21843d0407baSopenharmony_ci break; 21853d0407baSopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 21863d0407baSopenharmony_ci if (online) 21873d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 21883d0407baSopenharmony_ci else 21893d0407baSopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 21903d0407baSopenharmony_ci dev_dbg(battery->dev, "report prop: %d\n", val->intval); 21913d0407baSopenharmony_ci break; 21923d0407baSopenharmony_ci default: 21933d0407baSopenharmony_ci ret = -EINVAL; 21943d0407baSopenharmony_ci break; 21953d0407baSopenharmony_ci } 21963d0407baSopenharmony_ci 21973d0407baSopenharmony_ci return ret; 21983d0407baSopenharmony_ci} 21993d0407baSopenharmony_ci 22003d0407baSopenharmony_cistatic const struct power_supply_desc rk809_chg_desc = { 22013d0407baSopenharmony_ci .name = "charger", 22023d0407baSopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 22033d0407baSopenharmony_ci .properties = rk809_chg_props, 22043d0407baSopenharmony_ci .num_properties = ARRAY_SIZE(rk809_chg_props), 22053d0407baSopenharmony_ci .get_property = rk809_chg_get_property, 22063d0407baSopenharmony_ci}; 22073d0407baSopenharmony_ci 22083d0407baSopenharmony_cistatic int rk809_chg_init_power_supply(struct rk817_battery_device *battery) 22093d0407baSopenharmony_ci{ 22103d0407baSopenharmony_ci struct power_supply_config psy_cfg = { .drv_data = battery, }; 22113d0407baSopenharmony_ci 22123d0407baSopenharmony_ci battery->chg_psy = 22133d0407baSopenharmony_ci devm_power_supply_register(battery->dev, &rk809_chg_desc, 22143d0407baSopenharmony_ci &psy_cfg); 22153d0407baSopenharmony_ci if (IS_ERR(battery->chg_psy)) { 22163d0407baSopenharmony_ci dev_err(battery->dev, "register chg psy power supply fail\n"); 22173d0407baSopenharmony_ci return PTR_ERR(battery->chg_psy); 22183d0407baSopenharmony_ci } 22193d0407baSopenharmony_ci 22203d0407baSopenharmony_ci return 0; 22213d0407baSopenharmony_ci} 22223d0407baSopenharmony_ci 22233d0407baSopenharmony_cistatic void rk817_bat_power_supply_changed(struct rk817_battery_device *battery) 22243d0407baSopenharmony_ci{ 22253d0407baSopenharmony_ci static int old_soc = -1; 22263d0407baSopenharmony_ci 22273d0407baSopenharmony_ci if (battery->dsoc > 100 * 1000) 22283d0407baSopenharmony_ci battery->dsoc = 100 * 1000; 22293d0407baSopenharmony_ci else if (battery->dsoc < 0) 22303d0407baSopenharmony_ci battery->dsoc = 0; 22313d0407baSopenharmony_ci 22323d0407baSopenharmony_ci if (battery->dsoc == old_soc && !battery->change) 22333d0407baSopenharmony_ci return; 22343d0407baSopenharmony_ci 22353d0407baSopenharmony_ci battery->change = false; 22363d0407baSopenharmony_ci old_soc = battery->dsoc; 22373d0407baSopenharmony_ci battery->last_dsoc = battery->dsoc; 22383d0407baSopenharmony_ci power_supply_changed(battery->bat); 22393d0407baSopenharmony_ci DBG("changed: dsoc=%d, rsoc=%d, v=%d, ov=%d c=%d, cap=%d, f=%d\n", 22403d0407baSopenharmony_ci battery->dsoc, battery->rsoc, battery->voltage_avg, 22413d0407baSopenharmony_ci battery->voltage_ocv, battery->current_avg, 22423d0407baSopenharmony_ci battery->remain_cap, battery->fcc); 22433d0407baSopenharmony_ci 22443d0407baSopenharmony_ci DBG("dl=%d, rl=%d, v=%d, halt=%d, halt_n=%d, max=%d\n" 22453d0407baSopenharmony_ci "init=%d, sw=%d, calib=%d, below0=%d, force=%d\n", 22463d0407baSopenharmony_ci battery->dbg_pwr_dsoc, battery->dbg_pwr_rsoc, 22473d0407baSopenharmony_ci battery->dbg_pwr_vol, 22483d0407baSopenharmony_ci battery->is_halt, battery->halt_cnt, 22493d0407baSopenharmony_ci battery->is_max_soc_offset, 22503d0407baSopenharmony_ci battery->is_initialized, battery->is_sw_reset, 22513d0407baSopenharmony_ci battery->is_ocv_calib, 22523d0407baSopenharmony_ci battery->dbg_cap_low0, battery->is_force_calib); 22533d0407baSopenharmony_ci} 22543d0407baSopenharmony_ci 22553d0407baSopenharmony_cistatic void rk817_battery_debug_info(struct rk817_battery_device *battery) 22563d0407baSopenharmony_ci{ 22573d0407baSopenharmony_ci rk817_bat_get_battery_voltage(battery); 22583d0407baSopenharmony_ci rk817_bat_get_sys_voltage(battery); 22593d0407baSopenharmony_ci rk817_bat_get_USB_voltage(battery); 22603d0407baSopenharmony_ci rk817_bat_get_pwron_voltage(battery); 22613d0407baSopenharmony_ci rk817_bat_get_ocv_voltage(battery); 22623d0407baSopenharmony_ci rk817_bat_get_ocv0_voltage0(battery); 22633d0407baSopenharmony_ci 22643d0407baSopenharmony_ci rk817_bat_current_calibration(battery); 22653d0407baSopenharmony_ci rk817_bat_get_avg_current(battery); 22663d0407baSopenharmony_ci rk817_bat_get_relax_cur1(battery); 22673d0407baSopenharmony_ci rk817_bat_get_relax_cur2(battery); 22683d0407baSopenharmony_ci rk817_bat_get_relax_current(battery); 22693d0407baSopenharmony_ci rk817_bat_get_ocv_current(battery); 22703d0407baSopenharmony_ci rk817_bat_get_ocv_current0(battery); 22713d0407baSopenharmony_ci rk817_bat_get_pwron_current(battery); 22723d0407baSopenharmony_ci rk817_bat_get_ocv_count(battery); 22733d0407baSopenharmony_ci rk817_bat_save_dsoc(battery, battery->dsoc); 22743d0407baSopenharmony_ci DBG("capactiy = %d\n", rk817_bat_get_capacity_mah(battery)); 22753d0407baSopenharmony_ci} 22763d0407baSopenharmony_ci 22773d0407baSopenharmony_cistatic void 22783d0407baSopenharmony_cirk817_bat_update_charging_status(struct rk817_battery_device *battery) 22793d0407baSopenharmony_ci{ 22803d0407baSopenharmony_ci int is_charging; 22813d0407baSopenharmony_ci 22823d0407baSopenharmony_ci is_charging = rk817_bat_get_charge_state(battery); 22833d0407baSopenharmony_ci if (is_charging == battery->is_charging) 22843d0407baSopenharmony_ci return; 22853d0407baSopenharmony_ci 22863d0407baSopenharmony_ci battery->change = true; 22873d0407baSopenharmony_ci battery->is_charging = is_charging; 22883d0407baSopenharmony_ci if (is_charging) 22893d0407baSopenharmony_ci battery->charge_count++; 22903d0407baSopenharmony_ci} 22913d0407baSopenharmony_ci 22923d0407baSopenharmony_cistatic void rk817_bat_update_info(struct rk817_battery_device *battery) 22933d0407baSopenharmony_ci{ 22943d0407baSopenharmony_ci battery->voltage_avg = rk817_bat_get_battery_voltage(battery); 22953d0407baSopenharmony_ci battery->voltage_sys = rk817_bat_get_sys_voltage(battery); 22963d0407baSopenharmony_ci battery->current_avg = rk817_bat_get_avg_current(battery); 22973d0407baSopenharmony_ci battery->voltage_relax = rk817_bat_get_relax_voltage(battery); 22983d0407baSopenharmony_ci battery->rsoc = rk817_bat_get_rsoc(battery); 22993d0407baSopenharmony_ci battery->remain_cap = rk817_bat_get_capacity_uah(battery); 23003d0407baSopenharmony_ci battery->voltage_usb = rk817_bat_get_USB_voltage(battery); 23013d0407baSopenharmony_ci battery->chrg_status = get_charge_status(battery); 23023d0407baSopenharmony_ci rk817_bat_update_charging_status(battery); 23033d0407baSopenharmony_ci DBG("valtage usb: %d\n", battery->voltage_usb); 23043d0407baSopenharmony_ci DBG("UPDATE: voltage_avg = %d\n" 23053d0407baSopenharmony_ci "voltage_sys = %d\n" 23063d0407baSopenharmony_ci "curren_avg = %d\n" 23073d0407baSopenharmony_ci "rsoc = %d\n" 23083d0407baSopenharmony_ci "chrg_status = %d\n" 23093d0407baSopenharmony_ci "PWRON_CUR = %d\n" 23103d0407baSopenharmony_ci "remain_cap = %d\n", 23113d0407baSopenharmony_ci battery->voltage_avg, 23123d0407baSopenharmony_ci battery->voltage_sys, 23133d0407baSopenharmony_ci battery->current_avg, 23143d0407baSopenharmony_ci battery->rsoc, 23153d0407baSopenharmony_ci battery->chrg_status, 23163d0407baSopenharmony_ci rk817_bat_get_pwron_current(battery), 23173d0407baSopenharmony_ci battery->remain_cap); 23183d0407baSopenharmony_ci 23193d0407baSopenharmony_ci /* smooth charge */ 23203d0407baSopenharmony_ci if (battery->remain_cap / 1000 > battery->fcc) { 23213d0407baSopenharmony_ci /*battery->sm_remain_cap -=*/ 23223d0407baSopenharmony_ci /*(battery->remain_cap - battery->fcc * 1000);*/ 23233d0407baSopenharmony_ci battery->sm_remain_cap = battery->fcc * 1000; 23243d0407baSopenharmony_ci DBG("<%s>. cap: remain=%d, sm_remain=%d\n", 23253d0407baSopenharmony_ci __func__, battery->remain_cap, battery->sm_remain_cap); 23263d0407baSopenharmony_ci DBG("fcc: %d\n", battery->fcc); 23273d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, battery->fcc + 100); 23283d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, battery->fcc); 23293d0407baSopenharmony_ci rk817_bat_get_capacity_mah(battery); 23303d0407baSopenharmony_ci } 23313d0407baSopenharmony_ci 23323d0407baSopenharmony_ci if (battery->chrg_status != CHARGE_FINISH) 23333d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 23343d0407baSopenharmony_ci} 23353d0407baSopenharmony_ci 23363d0407baSopenharmony_cistatic void rk817_bat_save_data(struct rk817_battery_device *battery) 23373d0407baSopenharmony_ci{ 23383d0407baSopenharmony_ci rk817_bat_save_dsoc(battery, battery->dsoc); 23393d0407baSopenharmony_ci rk817_bat_save_cap(battery, battery->remain_cap / 1000); 23403d0407baSopenharmony_ci} 23413d0407baSopenharmony_ci 23423d0407baSopenharmony_ci/* high load: current < 0 with charger in. 23433d0407baSopenharmony_ci * System will not shutdown while dsoc=0% with charging state(ac_in), 23443d0407baSopenharmony_ci * which will cause over discharge, so oppose status before report states. 23453d0407baSopenharmony_ci */ 23463d0407baSopenharmony_cistatic void rk817_bat_lowpwr_check(struct rk817_battery_device *battery) 23473d0407baSopenharmony_ci{ 23483d0407baSopenharmony_ci static u64 time; 23493d0407baSopenharmony_ci int pwr_off_thresd = battery->pdata->pwroff_vol; 23503d0407baSopenharmony_ci 23513d0407baSopenharmony_ci if (battery->current_avg < 0 && battery->voltage_avg < pwr_off_thresd) { 23523d0407baSopenharmony_ci if (!time) 23533d0407baSopenharmony_ci time = get_boot_sec(); 23543d0407baSopenharmony_ci 23553d0407baSopenharmony_ci if ((base2sec(time) > MINUTE(1)) || 23563d0407baSopenharmony_ci (battery->voltage_avg <= pwr_off_thresd - 50)) { 23573d0407baSopenharmony_ci battery->fake_offline = 1; 23583d0407baSopenharmony_ci if (battery->voltage_avg <= pwr_off_thresd - 50) 23593d0407baSopenharmony_ci battery->dsoc -= 1000; 23603d0407baSopenharmony_ci DBG("low power, soc=%d, current=%d\n", 23613d0407baSopenharmony_ci battery->dsoc, battery->current_avg); 23623d0407baSopenharmony_ci } 23633d0407baSopenharmony_ci } else { 23643d0407baSopenharmony_ci time = 0; 23653d0407baSopenharmony_ci battery->fake_offline = 0; 23663d0407baSopenharmony_ci } 23673d0407baSopenharmony_ci 23683d0407baSopenharmony_ci DBG("<%s>. t=%lu, dsoc=%d, current=%d, fake_offline=%d\n", 23693d0407baSopenharmony_ci __func__, base2sec(time), battery->dsoc, 23703d0407baSopenharmony_ci battery->current_avg, battery->fake_offline); 23713d0407baSopenharmony_ci} 23723d0407baSopenharmony_ci 23733d0407baSopenharmony_cistatic void rk817_bat_calc_smooth_dischrg(struct rk817_battery_device *battery) 23743d0407baSopenharmony_ci{ 23753d0407baSopenharmony_ci int tmp_soc = 0; 23763d0407baSopenharmony_ci 23773d0407baSopenharmony_ci /* check new dsoc */ 23783d0407baSopenharmony_ci if (battery->smooth_soc < 0) 23793d0407baSopenharmony_ci battery->smooth_soc = 0; 23803d0407baSopenharmony_ci 23813d0407baSopenharmony_ci tmp_soc = battery->smooth_soc / 1000; 23823d0407baSopenharmony_ci 23833d0407baSopenharmony_ci if (tmp_soc != battery->dsoc / 1000) { 23843d0407baSopenharmony_ci if (battery->smooth_soc > battery->dsoc) 23853d0407baSopenharmony_ci return; 23863d0407baSopenharmony_ci 23873d0407baSopenharmony_ci if (battery->smooth_soc + 1000 > battery->dsoc) 23883d0407baSopenharmony_ci battery->dsoc = battery->smooth_soc; 23893d0407baSopenharmony_ci else 23903d0407baSopenharmony_ci battery->dsoc -= 1000; 23913d0407baSopenharmony_ci 23923d0407baSopenharmony_ci if (battery->dsoc <= 0) 23933d0407baSopenharmony_ci battery->dsoc = 0; 23943d0407baSopenharmony_ci } 23953d0407baSopenharmony_ci} 23963d0407baSopenharmony_ci 23973d0407baSopenharmony_cistatic void rk817_bat_smooth_algorithm(struct rk817_battery_device *battery) 23983d0407baSopenharmony_ci{ 23993d0407baSopenharmony_ci int ydsoc = 0, delta_cap = 0, old_cap = 0, tmp_soc; 24003d0407baSopenharmony_ci /*int linek;*/ 24013d0407baSopenharmony_ci int diff, delta; 24023d0407baSopenharmony_ci /*int current_avg = rk817_bat_get_avg_current(battery);*/ 24033d0407baSopenharmony_ci 24043d0407baSopenharmony_ci delta = abs(battery->dsoc - battery->rsoc); 24053d0407baSopenharmony_ci diff = delta * 3;/* speed:3/4 */ 24063d0407baSopenharmony_ci 24073d0407baSopenharmony_ci /* charge and discharge switch */ 24083d0407baSopenharmony_ci if ((battery->sm_linek * battery->current_avg <= 0)) { 24093d0407baSopenharmony_ci DBG("<%s>. linek mode, retinit sm linek..\n", __func__); 24103d0407baSopenharmony_ci rk817_bat_calc_sm_linek(battery); 24113d0407baSopenharmony_ci } 24123d0407baSopenharmony_ci 24133d0407baSopenharmony_ci /*battery->sm_linek = linek;*/ 24143d0407baSopenharmony_ci 24153d0407baSopenharmony_ci battery->remain_cap = rk817_bat_get_capacity_uah(battery); 24163d0407baSopenharmony_ci 24173d0407baSopenharmony_ci old_cap = battery->sm_remain_cap; 24183d0407baSopenharmony_ci DBG("smooth: smooth_soc = %d, dsoc = %d, battery->sm_linek = %d\n", 24193d0407baSopenharmony_ci battery->smooth_soc, battery->dsoc, battery->sm_linek); 24203d0407baSopenharmony_ci 24213d0407baSopenharmony_ci /* discharge status: sm_remain_cap > remain_cap, delta_cap > 0 */ 24223d0407baSopenharmony_ci /* from charge to discharge: 24233d0407baSopenharmony_ci * remain_cap may be above sm_remain_cap, delta_cap <= 0 24243d0407baSopenharmony_ci */ 24253d0407baSopenharmony_ci delta_cap = battery->remain_cap - battery->sm_remain_cap; 24263d0407baSopenharmony_ci DBG("smooth: sm_remain_cap = %d, remain_cap = %d\n", 24273d0407baSopenharmony_ci battery->sm_remain_cap, battery->remain_cap); 24283d0407baSopenharmony_ci DBG("smooth: delta_cap = %d, dsoc = %d\n", 24293d0407baSopenharmony_ci delta_cap, battery->dsoc); 24303d0407baSopenharmony_ci 24313d0407baSopenharmony_ci if (delta_cap == 0) { 24323d0407baSopenharmony_ci DBG("<%s>. delta_cap = 0\n", __func__); 24333d0407baSopenharmony_ci return; 24343d0407baSopenharmony_ci } 24353d0407baSopenharmony_ci 24363d0407baSopenharmony_ci /* discharge: sm_linek < 0, if delate_cap <0, ydsoc > 0 */ 24373d0407baSopenharmony_ci ydsoc = battery->sm_linek * abs(delta_cap / 10) / DIV(battery->fcc); 24383d0407baSopenharmony_ci 24393d0407baSopenharmony_ci DBG("smooth: ydsoc = %d, fcc = %d\n", ydsoc, battery->fcc); 24403d0407baSopenharmony_ci if (ydsoc == 0) { 24413d0407baSopenharmony_ci DBG("<%s>. ydsoc = 0\n", __func__); 24423d0407baSopenharmony_ci return; 24433d0407baSopenharmony_ci } 24443d0407baSopenharmony_ci battery->sm_remain_cap = battery->remain_cap; 24453d0407baSopenharmony_ci 24463d0407baSopenharmony_ci DBG("<%s>. k=%d, ydsoc=%d; cap:old=%d, new:%d; delta_cap=%d\n", 24473d0407baSopenharmony_ci __func__, battery->sm_linek, ydsoc, old_cap, 24483d0407baSopenharmony_ci battery->sm_remain_cap, delta_cap); 24493d0407baSopenharmony_ci 24503d0407baSopenharmony_ci /* discharge mode */ 24513d0407baSopenharmony_ci /* discharge mode, but ydsoc > 0, 24523d0407baSopenharmony_ci * from charge status to dischrage 24533d0407baSopenharmony_ci */ 24543d0407baSopenharmony_ci battery->smooth_soc += ydsoc; 24553d0407baSopenharmony_ci if (ydsoc < 0) { 24563d0407baSopenharmony_ci rk817_bat_calc_smooth_dischrg(battery); 24573d0407baSopenharmony_ci } else { 24583d0407baSopenharmony_ci if (battery->smooth_soc < 0) 24593d0407baSopenharmony_ci battery->smooth_soc = 0; 24603d0407baSopenharmony_ci 24613d0407baSopenharmony_ci tmp_soc = battery->smooth_soc / 1000; 24623d0407baSopenharmony_ci 24633d0407baSopenharmony_ci if (tmp_soc != battery->dsoc / 1000) { 24643d0407baSopenharmony_ci if (battery->smooth_soc < battery->dsoc) 24653d0407baSopenharmony_ci return; 24663d0407baSopenharmony_ci 24673d0407baSopenharmony_ci battery->dsoc = battery->smooth_soc; 24683d0407baSopenharmony_ci if (battery->dsoc <= 0) 24693d0407baSopenharmony_ci battery->dsoc = 0; 24703d0407baSopenharmony_ci } 24713d0407baSopenharmony_ci } 24723d0407baSopenharmony_ci 24733d0407baSopenharmony_ci if (battery->s2r) { 24743d0407baSopenharmony_ci battery->s2r = false; 24753d0407baSopenharmony_ci rk817_bat_calc_sm_linek(battery); 24763d0407baSopenharmony_ci } 24773d0407baSopenharmony_ci 24783d0407baSopenharmony_ci DBG("smooth: smooth_soc = %d, dsoc = %d\n", 24793d0407baSopenharmony_ci battery->smooth_soc, battery->dsoc); 24803d0407baSopenharmony_ci DBG("smooth: delta_cap = %d, dsoc = %d\n", 24813d0407baSopenharmony_ci delta_cap, battery->dsoc); 24823d0407baSopenharmony_ci} 24833d0407baSopenharmony_ci 24843d0407baSopenharmony_cistatic void rk817_bat_calc_zero_linek(struct rk817_battery_device *battery) 24853d0407baSopenharmony_ci{ 24863d0407baSopenharmony_ci int dead_voltage, ocv_voltage; 24873d0407baSopenharmony_ci int voltage_avg, current_avg, vsys; 24883d0407baSopenharmony_ci int ocv_cap, dead_cap, xsoc; 24893d0407baSopenharmony_ci int ocv_soc, dead_soc; 24903d0407baSopenharmony_ci int pwroff_vol; 24913d0407baSopenharmony_ci int min_gap_xsoc; 24923d0407baSopenharmony_ci int powerpatch_res; 24933d0407baSopenharmony_ci 24943d0407baSopenharmony_ci if ((abs(battery->current_avg) < 400) && (battery->dsoc / 1000 > 5)) 24953d0407baSopenharmony_ci pwroff_vol = battery->pdata->pwroff_vol + 50; 24963d0407baSopenharmony_ci else 24973d0407baSopenharmony_ci pwroff_vol = battery->pdata->pwroff_vol; 24983d0407baSopenharmony_ci 24993d0407baSopenharmony_ci /* calc estimate ocv voltage */ 25003d0407baSopenharmony_ci voltage_avg = rk817_bat_get_battery_voltage(battery); 25013d0407baSopenharmony_ci current_avg = rk817_bat_get_avg_current(battery); 25023d0407baSopenharmony_ci vsys = voltage_avg + (current_avg * DEF_PWRPATH_RES) / 1000; 25033d0407baSopenharmony_ci 25043d0407baSopenharmony_ci powerpatch_res = (voltage_avg - vsys) * 1000 / current_avg; 25053d0407baSopenharmony_ci 25063d0407baSopenharmony_ci battery->zero_voltage_avg = voltage_avg; 25073d0407baSopenharmony_ci battery->zero_current_avg = current_avg; 25083d0407baSopenharmony_ci battery->zero_vsys = vsys; 25093d0407baSopenharmony_ci 25103d0407baSopenharmony_ci DBG("Zero: voltage_avg = %d, Vsys = %d\n", voltage_avg, vsys); 25113d0407baSopenharmony_ci DBG("Zero: powerpatch_res = %d\n", powerpatch_res); 25123d0407baSopenharmony_ci DBG("ZERO0: shtd_vol: poweroff_vol(usr) = %d\n" 25133d0407baSopenharmony_ci "pwroff_vol = %d\n" 25143d0407baSopenharmony_ci "zero_reserve_dsoc = %d\n", 25153d0407baSopenharmony_ci battery->pdata->pwroff_vol, 25163d0407baSopenharmony_ci pwroff_vol, 25173d0407baSopenharmony_ci battery->pdata->zero_reserve_dsoc); 25183d0407baSopenharmony_ci 25193d0407baSopenharmony_ci /* get the dead ocv voltage, pwroff_vol is vsys */ 25203d0407baSopenharmony_ci dead_voltage = pwroff_vol - current_avg * 25213d0407baSopenharmony_ci (battery->bat_res + DEF_PWRPATH_RES) / 1000; 25223d0407baSopenharmony_ci 25233d0407baSopenharmony_ci ocv_voltage = voltage_avg - (current_avg * battery->bat_res) / 1000; 25243d0407baSopenharmony_ci DBG("ZERO0: dead_voltage(shtd) = %d, ocv_voltage(now) = %d\n", 25253d0407baSopenharmony_ci dead_voltage, ocv_voltage); 25263d0407baSopenharmony_ci 25273d0407baSopenharmony_ci /* calc estimate soc and cap */ 25283d0407baSopenharmony_ci dead_soc = rk817_bat_vol_to_soc(battery, dead_voltage); 25293d0407baSopenharmony_ci dead_cap = rk817_bat_vol_to_cap(battery, dead_voltage); 25303d0407baSopenharmony_ci DBG("ZERO0: dead_soc = %d, dead_cap = %d\n", 25313d0407baSopenharmony_ci dead_soc, dead_cap); 25323d0407baSopenharmony_ci 25333d0407baSopenharmony_ci ocv_soc = rk817_bat_vol_to_soc(battery, ocv_voltage); 25343d0407baSopenharmony_ci ocv_cap = rk817_bat_vol_to_cap(battery, ocv_voltage); 25353d0407baSopenharmony_ci DBG("ZERO0: ocv_soc = %d, ocv_cap = %d\n", 25363d0407baSopenharmony_ci ocv_soc, ocv_cap); 25373d0407baSopenharmony_ci 25383d0407baSopenharmony_ci /* xsoc: available rsoc */ 25393d0407baSopenharmony_ci xsoc = ocv_soc - dead_soc; 25403d0407baSopenharmony_ci 25413d0407baSopenharmony_ci battery->zero_dead_voltage = dead_voltage; 25423d0407baSopenharmony_ci battery->zero_dead_soc = dead_soc; 25433d0407baSopenharmony_ci battery->zero_dead_cap = dead_cap; 25443d0407baSopenharmony_ci 25453d0407baSopenharmony_ci battery->zero_batvol_to_ocv = ocv_voltage; 25463d0407baSopenharmony_ci battery->zero_batocv_to_soc = ocv_soc; 25473d0407baSopenharmony_ci battery->zero_batocv_to_cap = ocv_cap; 25483d0407baSopenharmony_ci 25493d0407baSopenharmony_ci battery->zero_xsoc = xsoc; 25503d0407baSopenharmony_ci 25513d0407baSopenharmony_ci DBG("Zero: xsoc = %d\n", xsoc); 25523d0407baSopenharmony_ci /* min_gap_xsoc: reserve xsoc */ 25533d0407baSopenharmony_ci if (abs(current_avg) > ZERO_LOAD_LVL1) 25543d0407baSopenharmony_ci min_gap_xsoc = MIN_ZERO_GAP_XSOC3; 25553d0407baSopenharmony_ci else if (abs(current_avg) > ZERO_LOAD_LVL2) 25563d0407baSopenharmony_ci min_gap_xsoc = MIN_ZERO_GAP_XSOC2; 25573d0407baSopenharmony_ci else 25583d0407baSopenharmony_ci min_gap_xsoc = MIN_ZERO_GAP_XSOC1; 25593d0407baSopenharmony_ci 25603d0407baSopenharmony_ci if ((xsoc <= 30) && 25613d0407baSopenharmony_ci (battery->dsoc >= battery->pdata->zero_reserve_dsoc)) 25623d0407baSopenharmony_ci min_gap_xsoc = min_gap_xsoc + MIN_ZERO_GAP_CALIB; 25633d0407baSopenharmony_ci 25643d0407baSopenharmony_ci battery->zero_remain_cap = battery->remain_cap; 25653d0407baSopenharmony_ci battery->zero_timeout_cnt = 0; 25663d0407baSopenharmony_ci if ((battery->dsoc / 1000 <= 1) && (xsoc > 0)) { 25673d0407baSopenharmony_ci battery->zero_linek = 400; 25683d0407baSopenharmony_ci battery->zero_drop_sec = 0; 25693d0407baSopenharmony_ci } else if (xsoc >= 0) { 25703d0407baSopenharmony_ci battery->zero_drop_sec = 0; 25713d0407baSopenharmony_ci battery->zero_linek = 25723d0407baSopenharmony_ci (battery->zero_dsoc + xsoc / 2) / DIV(xsoc); 25733d0407baSopenharmony_ci /* battery energy mode to use up voltage */ 25743d0407baSopenharmony_ci if ((battery->pdata->energy_mode) && 25753d0407baSopenharmony_ci (xsoc - battery->dsoc / 1000 >= MIN_ZERO_GAP_XSOC3) && 25763d0407baSopenharmony_ci (battery->dsoc / 1000 <= 10) && (battery->zero_linek < 300)) { 25773d0407baSopenharmony_ci battery->zero_linek = 300; 25783d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step0...\n"); 25793d0407baSopenharmony_ci /* reserve enough power yet, slow down any way */ 25803d0407baSopenharmony_ci } else if ((xsoc - battery->dsoc / 1000 >= min_gap_xsoc) || 25813d0407baSopenharmony_ci ((xsoc - battery->dsoc / 1000 >= MIN_ZERO_GAP_XSOC2) && 25823d0407baSopenharmony_ci (battery->dsoc / 1000 <= 10) && (xsoc > 15))) { 25833d0407baSopenharmony_ci if (xsoc <= 20 && 25843d0407baSopenharmony_ci battery->dsoc / 1000 >= battery->pdata->zero_reserve_dsoc) 25853d0407baSopenharmony_ci battery->zero_linek = 1200; 25863d0407baSopenharmony_ci else if (xsoc - battery->dsoc / 1000 >= 2 * min_gap_xsoc) 25873d0407baSopenharmony_ci battery->zero_linek = 400; 25883d0407baSopenharmony_ci else if (xsoc - battery->dsoc / 1000 >= 3 + min_gap_xsoc) 25893d0407baSopenharmony_ci battery->zero_linek = 600; 25903d0407baSopenharmony_ci else 25913d0407baSopenharmony_ci battery->zero_linek = 800; 25923d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step1...\n"); 25933d0407baSopenharmony_ci /* control zero mode beginning enter */ 25943d0407baSopenharmony_ci } else if ((battery->zero_linek > 1800) && 25953d0407baSopenharmony_ci (battery->dsoc / 1000 > 70)) { 25963d0407baSopenharmony_ci battery->zero_linek = 1800; 25973d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step2...\n"); 25983d0407baSopenharmony_ci /* dsoc close to xsoc: it must reserve power */ 25993d0407baSopenharmony_ci } else if ((battery->zero_linek > 1000) && 26003d0407baSopenharmony_ci (battery->zero_linek < 1200)) { 26013d0407baSopenharmony_ci battery->zero_linek = 1200; 26023d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step3...\n"); 26033d0407baSopenharmony_ci /* dsoc[5~15], dsoc < xsoc */ 26043d0407baSopenharmony_ci } else if ((battery->dsoc / 1000 <= 15 && battery->dsoc > 5) && 26053d0407baSopenharmony_ci (battery->zero_linek <= 1200)) { 26063d0407baSopenharmony_ci /* slow down */ 26073d0407baSopenharmony_ci if ((xsoc - battery->dsoc / 1000) >= min_gap_xsoc) 26083d0407baSopenharmony_ci battery->zero_linek = 800; 26093d0407baSopenharmony_ci /* reserve power */ 26103d0407baSopenharmony_ci else 26113d0407baSopenharmony_ci battery->zero_linek = 1200; 26123d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step4...\n"); 26133d0407baSopenharmony_ci /* dsoc[5, 100], dsoc < xsoc */ 26143d0407baSopenharmony_ci } else if ((battery->zero_linek < 1000) && 26153d0407baSopenharmony_ci (battery->dsoc / 1000 >= 5)) { 26163d0407baSopenharmony_ci if ((xsoc - battery->dsoc / 1000) < min_gap_xsoc) { 26173d0407baSopenharmony_ci /* reserve power */ 26183d0407baSopenharmony_ci battery->zero_linek = 1200; 26193d0407baSopenharmony_ci } else { 26203d0407baSopenharmony_ci if (abs(battery->current_avg) > 500)/* heavy */ 26213d0407baSopenharmony_ci battery->zero_linek = 900; 26223d0407baSopenharmony_ci else 26233d0407baSopenharmony_ci battery->zero_linek = 1000; 26243d0407baSopenharmony_ci } 26253d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step5...\n"); 26263d0407baSopenharmony_ci /* dsoc[0~5], dsoc < xsoc */ 26273d0407baSopenharmony_ci } else if ((battery->zero_linek < 1000) && 26283d0407baSopenharmony_ci (battery->dsoc / 1000 <= 5)) { 26293d0407baSopenharmony_ci if ((xsoc - battery->dsoc / 1000) <= 3) 26303d0407baSopenharmony_ci battery->zero_linek = 1200; 26313d0407baSopenharmony_ci else 26323d0407baSopenharmony_ci battery->zero_linek = 800; 26333d0407baSopenharmony_ci DBG("ZERO-new: zero_linek adjust step6...\n"); 26343d0407baSopenharmony_ci } 26353d0407baSopenharmony_ci } else { 26363d0407baSopenharmony_ci /* xsoc < 0 */ 26373d0407baSopenharmony_ci battery->zero_linek = 1000; 26383d0407baSopenharmony_ci if (!battery->zero_drop_sec) 26393d0407baSopenharmony_ci battery->zero_drop_sec = get_boot_sec(); 26403d0407baSopenharmony_ci if (base2sec(battery->zero_drop_sec) >= WAIT_DSOC_DROP_SEC) { 26413d0407baSopenharmony_ci DBG("ZERO0: t=%lu\n", base2sec(battery->zero_drop_sec)); 26423d0407baSopenharmony_ci battery->zero_drop_sec = 0; 26433d0407baSopenharmony_ci battery->dsoc -= 1000; 26443d0407baSopenharmony_ci if (battery->dsoc < 0) 26453d0407baSopenharmony_ci battery->dsoc = 0; 26463d0407baSopenharmony_ci battery->zero_dsoc = battery->dsoc; 26473d0407baSopenharmony_ci } 26483d0407baSopenharmony_ci } 26493d0407baSopenharmony_ci 26503d0407baSopenharmony_ci if (voltage_avg < pwroff_vol - 70) { 26513d0407baSopenharmony_ci if (!battery->shtd_drop_sec) 26523d0407baSopenharmony_ci battery->shtd_drop_sec = get_boot_sec(); 26533d0407baSopenharmony_ci if (base2sec(battery->shtd_drop_sec) > WAIT_SHTD_DROP_SEC) { 26543d0407baSopenharmony_ci DBG("voltage extreme low...soc:%d->0\n", battery->dsoc); 26553d0407baSopenharmony_ci battery->shtd_drop_sec = 0; 26563d0407baSopenharmony_ci battery->dsoc = 0; 26573d0407baSopenharmony_ci } 26583d0407baSopenharmony_ci } else { 26593d0407baSopenharmony_ci battery->shtd_drop_sec = 0; 26603d0407baSopenharmony_ci } 26613d0407baSopenharmony_ci 26623d0407baSopenharmony_ci DBG("Zero: zero_linek = %d\n", battery->zero_linek); 26633d0407baSopenharmony_ci} 26643d0407baSopenharmony_ci 26653d0407baSopenharmony_cistatic void rk817_bat_zero_algo_prepare(struct rk817_battery_device *battery) 26663d0407baSopenharmony_ci{ 26673d0407baSopenharmony_ci int tmp_dsoc; 26683d0407baSopenharmony_ci 26693d0407baSopenharmony_ci tmp_dsoc = battery->zero_dsoc / 1000; 26703d0407baSopenharmony_ci 26713d0407baSopenharmony_ci if (tmp_dsoc != battery->smooth_soc / 1000) 26723d0407baSopenharmony_ci battery->zero_dsoc = battery->smooth_soc; 26733d0407baSopenharmony_ci 26743d0407baSopenharmony_ci DBG("zero_smooth: zero_dsoc = %d\n", battery->zero_dsoc); 26753d0407baSopenharmony_ci 26763d0407baSopenharmony_ci rk817_bat_calc_zero_linek(battery); 26773d0407baSopenharmony_ci} 26783d0407baSopenharmony_ci 26793d0407baSopenharmony_cistatic void rk817_bat_calc_zero_algorithm(struct rk817_battery_device *battery) 26803d0407baSopenharmony_ci{ 26813d0407baSopenharmony_ci int tmp_soc; 26823d0407baSopenharmony_ci 26833d0407baSopenharmony_ci tmp_soc = battery->zero_dsoc / 1000; 26843d0407baSopenharmony_ci 26853d0407baSopenharmony_ci if (tmp_soc == battery->dsoc / 1000) 26863d0407baSopenharmony_ci return; 26873d0407baSopenharmony_ci 26883d0407baSopenharmony_ci if (battery->zero_dsoc > battery->dsoc) 26893d0407baSopenharmony_ci return; 26903d0407baSopenharmony_ci 26913d0407baSopenharmony_ci if (battery->zero_dsoc < battery->dsoc - 1000) 26923d0407baSopenharmony_ci battery->dsoc -= 1000; 26933d0407baSopenharmony_ci else 26943d0407baSopenharmony_ci battery->dsoc = battery->zero_dsoc; 26953d0407baSopenharmony_ci} 26963d0407baSopenharmony_ci 26973d0407baSopenharmony_cistatic void rk817_bat_zero_algorithm(struct rk817_battery_device *battery) 26983d0407baSopenharmony_ci{ 26993d0407baSopenharmony_ci int delta_cap = 0, delta_soc = 0; 27003d0407baSopenharmony_ci 27013d0407baSopenharmony_ci battery->zero_timeout_cnt++; 27023d0407baSopenharmony_ci delta_cap = battery->zero_remain_cap - battery->remain_cap; 27033d0407baSopenharmony_ci delta_soc = battery->zero_linek * delta_cap / DIV(battery->fcc) / 10; 27043d0407baSopenharmony_ci 27053d0407baSopenharmony_ci DBG("zero algorithm start\n"); 27063d0407baSopenharmony_ci DBG("DEAD: dead_voltage: %d\n" 27073d0407baSopenharmony_ci "dead_soc: %d\n" 27083d0407baSopenharmony_ci "dead_cap: %d\n" 27093d0407baSopenharmony_ci "powoff_vol: %d\n", 27103d0407baSopenharmony_ci battery->zero_dead_voltage, 27113d0407baSopenharmony_ci battery->zero_dead_soc, 27123d0407baSopenharmony_ci battery->zero_dead_cap, 27133d0407baSopenharmony_ci battery->pdata->pwroff_vol); 27143d0407baSopenharmony_ci DBG("DEAD: bat_voltage: %d\n" 27153d0407baSopenharmony_ci "bat_current: %d\n" 27163d0407baSopenharmony_ci "batvol_to_ocv: %d\n" 27173d0407baSopenharmony_ci "batocv_to_soc: %d\n" 27183d0407baSopenharmony_ci "batocv_to_cap: %d\n", 27193d0407baSopenharmony_ci battery->zero_voltage_avg, 27203d0407baSopenharmony_ci battery->zero_current_avg, 27213d0407baSopenharmony_ci battery->zero_batvol_to_ocv, 27223d0407baSopenharmony_ci battery->zero_batocv_to_soc, 27233d0407baSopenharmony_ci battery->zero_batocv_to_cap); 27243d0407baSopenharmony_ci DBG("DEAD: Xsoc: %d, zero_reserve_dsoc: %d\n", 27253d0407baSopenharmony_ci battery->zero_xsoc, battery->pdata->zero_reserve_dsoc); 27263d0407baSopenharmony_ci DBG("CAP: zero_remain_cap = %d, remain_cap = %d\n", 27273d0407baSopenharmony_ci battery->zero_remain_cap, battery->remain_cap); 27283d0407baSopenharmony_ci DBG("Zero: zero_delta_cap = %d, zero_link = %d, delta_soc = %d\n", 27293d0407baSopenharmony_ci delta_cap, battery->zero_linek, delta_soc); 27303d0407baSopenharmony_ci DBG("zero algorithm end\n"); 27313d0407baSopenharmony_ci 27323d0407baSopenharmony_ci if ((delta_soc >= MIN_ZERO_DSOC_ACCURACY) || 27333d0407baSopenharmony_ci (battery->zero_timeout_cnt > MIN_ZERO_OVERCNT) || 27343d0407baSopenharmony_ci (battery->zero_linek == 0)) { 27353d0407baSopenharmony_ci DBG("ZERO1:--------- enter calc -----------\n"); 27363d0407baSopenharmony_ci battery->zero_timeout_cnt = 0; 27373d0407baSopenharmony_ci battery->zero_dsoc -= delta_soc; 27383d0407baSopenharmony_ci rk817_bat_calc_zero_algorithm(battery); 27393d0407baSopenharmony_ci DBG("Zero: dsoc: %d\n", battery->dsoc); 27403d0407baSopenharmony_ci rk817_bat_calc_zero_linek(battery); 27413d0407baSopenharmony_ci } 27423d0407baSopenharmony_ci 27433d0407baSopenharmony_ci if ((battery->rsoc / 1000 < 1) && 27443d0407baSopenharmony_ci (battery->zero_batocv_to_cap > battery->fcc / 100)) { 27453d0407baSopenharmony_ci DBG("ZERO2:---------check step1 -----------\n"); 27463d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, 27473d0407baSopenharmony_ci battery->zero_batocv_to_cap); 27483d0407baSopenharmony_ci rk817_bat_calc_zero_linek(battery); 27493d0407baSopenharmony_ci } 27503d0407baSopenharmony_ci} 27513d0407baSopenharmony_ci 27523d0407baSopenharmony_cistatic void rk817_bat_finish_algorithm(struct rk817_battery_device *battery) 27533d0407baSopenharmony_ci{ 27543d0407baSopenharmony_ci unsigned long finish_sec, soc_sec; 27553d0407baSopenharmony_ci int plus_soc, finish_current, rest = 0; 27563d0407baSopenharmony_ci 27573d0407baSopenharmony_ci /* rsoc */ 27583d0407baSopenharmony_ci if ((battery->remain_cap != battery->fcc) && 27593d0407baSopenharmony_ci (get_charge_status(battery) == CHARGE_FINISH)) { 27603d0407baSopenharmony_ci battery->age_adjust_cap += 27613d0407baSopenharmony_ci (battery->fcc * 1000 - battery->remain_cap); 27623d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, battery->fcc); 27633d0407baSopenharmony_ci rk817_bat_get_capacity_mah(battery); 27643d0407baSopenharmony_ci } 27653d0407baSopenharmony_ci 27663d0407baSopenharmony_ci /* dsoc */ 27673d0407baSopenharmony_ci if (battery->dsoc < 100 * 1000) { 27683d0407baSopenharmony_ci if (!battery->finish_base) 27693d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 27703d0407baSopenharmony_ci 27713d0407baSopenharmony_ci finish_current = (battery->rsoc - battery->dsoc) > FINISH_MAX_SOC_DELAY ? 27723d0407baSopenharmony_ci FINISH_CHRG_CUR2 : FINISH_CHRG_CUR1; 27733d0407baSopenharmony_ci finish_sec = base2sec(battery->finish_base); 27743d0407baSopenharmony_ci 27753d0407baSopenharmony_ci soc_sec = battery->fcc * 3600 / 100 / DIV(finish_current); 27763d0407baSopenharmony_ci plus_soc = finish_sec / DIV(soc_sec); 27773d0407baSopenharmony_ci if (finish_sec > soc_sec) { 27783d0407baSopenharmony_ci rest = finish_sec % soc_sec; 27793d0407baSopenharmony_ci battery->dsoc += plus_soc * 1000; 27803d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 27813d0407baSopenharmony_ci if (battery->finish_base > rest) 27823d0407baSopenharmony_ci battery->finish_base = get_boot_sec() - rest; 27833d0407baSopenharmony_ci } 27843d0407baSopenharmony_ci DBG("CHARGE_FINISH:dsoc<100,dsoc=%d\n" 27853d0407baSopenharmony_ci "soc_time=%lu, sec_finish=%lu, plus_soc=%d, rest=%d\n", 27863d0407baSopenharmony_ci battery->dsoc, soc_sec, finish_sec, plus_soc, rest); 27873d0407baSopenharmony_ci DBG("battery->age_adjust_cap = %d\n", battery->age_adjust_cap); 27883d0407baSopenharmony_ci } 27893d0407baSopenharmony_ci} 27903d0407baSopenharmony_ci 27913d0407baSopenharmony_cistatic void rk817_bat_display_smooth(struct rk817_battery_device *battery) 27923d0407baSopenharmony_ci{ 27933d0407baSopenharmony_ci /* discharge: reinit "zero & smooth" algorithm to avoid handling dsoc */ 27943d0407baSopenharmony_ci if (battery->s2r && !battery->sleep_chrg_online) { 27953d0407baSopenharmony_ci DBG("s2r: discharge, reset algorithm...\n"); 27963d0407baSopenharmony_ci battery->s2r = false; 27973d0407baSopenharmony_ci rk817_bat_zero_algo_prepare(battery); 27983d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 27993d0407baSopenharmony_ci return; 28003d0407baSopenharmony_ci } 28013d0407baSopenharmony_ci 28023d0407baSopenharmony_ci if (battery->work_mode == MODE_FINISH) { 28033d0407baSopenharmony_ci DBG("step1: charge finish...\n"); 28043d0407baSopenharmony_ci rk817_bat_finish_algorithm(battery); 28053d0407baSopenharmony_ci 28063d0407baSopenharmony_ci if ((get_charge_status(battery) != CHARGE_FINISH) && 28073d0407baSopenharmony_ci !rk817_bat_fake_finish_mode(battery)) { 28083d0407baSopenharmony_ci if ((battery->current_avg < 0) && 28093d0407baSopenharmony_ci (battery->voltage_avg < battery->pdata->zero_algorithm_vol)) { 28103d0407baSopenharmony_ci DBG("step1: change to zero mode...\n"); 28113d0407baSopenharmony_ci rk817_bat_zero_algo_prepare(battery); 28123d0407baSopenharmony_ci battery->work_mode = MODE_ZERO; 28133d0407baSopenharmony_ci } else { 28143d0407baSopenharmony_ci DBG("step1: change to smooth mode...\n"); 28153d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 28163d0407baSopenharmony_ci battery->work_mode = MODE_SMOOTH; 28173d0407baSopenharmony_ci } 28183d0407baSopenharmony_ci } 28193d0407baSopenharmony_ci } else if (battery->work_mode == MODE_ZERO) { 28203d0407baSopenharmony_ci DBG("step2: zero algorithm...\n"); 28213d0407baSopenharmony_ci rk817_bat_zero_algorithm(battery); 28223d0407baSopenharmony_ci if ((battery->voltage_avg >= 28233d0407baSopenharmony_ci battery->pdata->zero_algorithm_vol + 50) || 28243d0407baSopenharmony_ci (battery->current_avg >= 0)) { 28253d0407baSopenharmony_ci DBG("step2: change to smooth mode...\n"); 28263d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 28273d0407baSopenharmony_ci battery->work_mode = MODE_SMOOTH; 28283d0407baSopenharmony_ci } else if ((get_charge_status(battery) == CHARGE_FINISH) || 28293d0407baSopenharmony_ci rk817_bat_fake_finish_mode(battery)) { 28303d0407baSopenharmony_ci DBG("step2: change to finish mode...\n"); 28313d0407baSopenharmony_ci rk817_bat_finish_algo_prepare(battery); 28323d0407baSopenharmony_ci battery->work_mode = MODE_FINISH; 28333d0407baSopenharmony_ci } 28343d0407baSopenharmony_ci } else { 28353d0407baSopenharmony_ci DBG("step3: smooth algorithm...\n"); 28363d0407baSopenharmony_ci rk817_bat_smooth_algorithm(battery); 28373d0407baSopenharmony_ci if ((battery->current_avg < 0) && 28383d0407baSopenharmony_ci (battery->voltage_avg < 28393d0407baSopenharmony_ci battery->pdata->zero_algorithm_vol)) { 28403d0407baSopenharmony_ci DBG("step3: change to zero mode...\n"); 28413d0407baSopenharmony_ci rk817_bat_zero_algo_prepare(battery); 28423d0407baSopenharmony_ci battery->work_mode = MODE_ZERO; 28433d0407baSopenharmony_ci } else if ((get_charge_status(battery) == CHARGE_FINISH) || 28443d0407baSopenharmony_ci rk817_bat_fake_finish_mode(battery)) { 28453d0407baSopenharmony_ci DBG("step3: change to finish mode...\n"); 28463d0407baSopenharmony_ci rk817_bat_finish_algo_prepare(battery); 28473d0407baSopenharmony_ci battery->work_mode = MODE_FINISH; 28483d0407baSopenharmony_ci } 28493d0407baSopenharmony_ci } 28503d0407baSopenharmony_ci} 28513d0407baSopenharmony_ci 28523d0407baSopenharmony_cistatic void rk817_bat_output_info(struct rk817_battery_device *battery) 28533d0407baSopenharmony_ci{ 28543d0407baSopenharmony_ci DBG("info start:\n"); 28553d0407baSopenharmony_ci DBG("info: voltage_k = %d\n", battery->voltage_k); 28563d0407baSopenharmony_ci DBG("info: voltage_b = %d\n", battery->voltage_b); 28573d0407baSopenharmony_ci DBG("info: voltage = %d\n", battery->voltage_avg); 28583d0407baSopenharmony_ci DBG("info: voltage_sys = %d\n", battery->voltage_sys); 28593d0407baSopenharmony_ci DBG("info: current = %d\n", battery->current_avg); 28603d0407baSopenharmony_ci 28613d0407baSopenharmony_ci DBG("info: FCC = %d\n", battery->fcc); 28623d0407baSopenharmony_ci DBG("info: remain_cap = %d\n", battery->remain_cap); 28633d0407baSopenharmony_ci DBG("info: sm_remain_cap = %d\n", battery->sm_remain_cap); 28643d0407baSopenharmony_ci DBG("info: sm_link = %d\n", battery->sm_linek); 28653d0407baSopenharmony_ci DBG("info: smooth_soc = %d\n", battery->smooth_soc); 28663d0407baSopenharmony_ci 28673d0407baSopenharmony_ci DBG("info: zero_remain_cap = %d\n", battery->zero_remain_cap); 28683d0407baSopenharmony_ci DBG("info: zero_link = %d\n", battery->zero_linek); 28693d0407baSopenharmony_ci DBG("info: zero_dsoc = %d\n", battery->zero_dsoc); 28703d0407baSopenharmony_ci 28713d0407baSopenharmony_ci DBG("info: remain_cap = %d\n", battery->remain_cap); 28723d0407baSopenharmony_ci DBG("info: dsoc = %d, dsoc/1000 = %d\n", 28733d0407baSopenharmony_ci battery->dsoc, battery->dsoc / 1000); 28743d0407baSopenharmony_ci DBG("info: rsoc = %d\n", battery->rsoc); 28753d0407baSopenharmony_ci DBG("info END.\n"); 28763d0407baSopenharmony_ci} 28773d0407baSopenharmony_ci 28783d0407baSopenharmony_cistatic void rk817_battery_work(struct work_struct *work) 28793d0407baSopenharmony_ci{ 28803d0407baSopenharmony_ci struct rk817_battery_device *battery = 28813d0407baSopenharmony_ci container_of(work, 28823d0407baSopenharmony_ci struct rk817_battery_device, 28833d0407baSopenharmony_ci bat_delay_work.work); 28843d0407baSopenharmony_ci 28853d0407baSopenharmony_ci rk817_bat_update_info(battery); 28863d0407baSopenharmony_ci rk817_bat_lowpwr_check(battery); 28873d0407baSopenharmony_ci rk817_bat_display_smooth(battery); 28883d0407baSopenharmony_ci rk817_bat_power_supply_changed(battery); 28893d0407baSopenharmony_ci rk817_bat_save_data(battery); 28903d0407baSopenharmony_ci rk817_bat_output_info(battery); 28913d0407baSopenharmony_ci 28923d0407baSopenharmony_ci if (rk817_bat_field_read(battery, CUR_CALIB_UPD)) { 28933d0407baSopenharmony_ci rk817_bat_current_calibration(battery); 28943d0407baSopenharmony_ci rk817_bat_init_voltage_kb(battery); 28953d0407baSopenharmony_ci rk817_bat_field_write(battery, CUR_CALIB_UPD, 0x01); 28963d0407baSopenharmony_ci } 28973d0407baSopenharmony_ci 28983d0407baSopenharmony_ci queue_delayed_work(battery->bat_monitor_wq, &battery->bat_delay_work, 28993d0407baSopenharmony_ci msecs_to_jiffies(battery->monitor_ms)); 29003d0407baSopenharmony_ci} 29013d0407baSopenharmony_ci 29023d0407baSopenharmony_cistatic irqreturn_t rk809_plug_in_isr(int irq, void *cg) 29033d0407baSopenharmony_ci{ 29043d0407baSopenharmony_ci struct rk817_battery_device *battery; 29053d0407baSopenharmony_ci 29063d0407baSopenharmony_ci battery = (struct rk817_battery_device *)cg; 29073d0407baSopenharmony_ci battery->plugin_trigger = 1; 29083d0407baSopenharmony_ci battery->plugout_trigger = 0; 29093d0407baSopenharmony_ci power_supply_changed(battery->bat); 29103d0407baSopenharmony_ci if (battery->is_register_chg_psy) 29113d0407baSopenharmony_ci power_supply_changed(battery->chg_psy); 29123d0407baSopenharmony_ci 29133d0407baSopenharmony_ci return IRQ_HANDLED; 29143d0407baSopenharmony_ci} 29153d0407baSopenharmony_ci 29163d0407baSopenharmony_cistatic irqreturn_t rk809_plug_out_isr(int irq, void *cg) 29173d0407baSopenharmony_ci{ 29183d0407baSopenharmony_ci struct rk817_battery_device *battery; 29193d0407baSopenharmony_ci 29203d0407baSopenharmony_ci battery = (struct rk817_battery_device *)cg; 29213d0407baSopenharmony_ci battery->plugin_trigger = 0; 29223d0407baSopenharmony_ci battery->plugout_trigger = 1; 29233d0407baSopenharmony_ci power_supply_changed(battery->bat); 29243d0407baSopenharmony_ci if (battery->is_register_chg_psy) 29253d0407baSopenharmony_ci power_supply_changed(battery->chg_psy); 29263d0407baSopenharmony_ci 29273d0407baSopenharmony_ci return IRQ_HANDLED; 29283d0407baSopenharmony_ci} 29293d0407baSopenharmony_ci 29303d0407baSopenharmony_cistatic int rk809_charge_init_irqs(struct rk817_battery_device *battery) 29313d0407baSopenharmony_ci{ 29323d0407baSopenharmony_ci struct rk808 *rk817 = battery->rk817; 29333d0407baSopenharmony_ci struct platform_device *pdev = battery->pdev; 29343d0407baSopenharmony_ci int ret, plug_in_irq, plug_out_irq; 29353d0407baSopenharmony_ci 29363d0407baSopenharmony_ci battery->plugin_trigger = 0; 29373d0407baSopenharmony_ci battery->plugout_trigger = 0; 29383d0407baSopenharmony_ci 29393d0407baSopenharmony_ci plug_in_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_IN); 29403d0407baSopenharmony_ci if (plug_in_irq < 0) { 29413d0407baSopenharmony_ci dev_err(battery->dev, "plug_in_irq request failed!\n"); 29423d0407baSopenharmony_ci return plug_in_irq; 29433d0407baSopenharmony_ci } 29443d0407baSopenharmony_ci 29453d0407baSopenharmony_ci plug_out_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_OUT); 29463d0407baSopenharmony_ci if (plug_out_irq < 0) { 29473d0407baSopenharmony_ci dev_err(battery->dev, "plug_out_irq request failed!\n"); 29483d0407baSopenharmony_ci return plug_out_irq; 29493d0407baSopenharmony_ci } 29503d0407baSopenharmony_ci 29513d0407baSopenharmony_ci ret = devm_request_threaded_irq(battery->dev, plug_in_irq, NULL, 29523d0407baSopenharmony_ci rk809_plug_in_isr, 29533d0407baSopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 29543d0407baSopenharmony_ci "rk817_plug_in", battery); 29553d0407baSopenharmony_ci if (ret) { 29563d0407baSopenharmony_ci dev_err(&pdev->dev, "plug_in_irq request failed!\n"); 29573d0407baSopenharmony_ci return ret; 29583d0407baSopenharmony_ci } 29593d0407baSopenharmony_ci 29603d0407baSopenharmony_ci ret = devm_request_threaded_irq(battery->dev, plug_out_irq, NULL, 29613d0407baSopenharmony_ci rk809_plug_out_isr, 29623d0407baSopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 29633d0407baSopenharmony_ci "rk817_plug_out", battery); 29643d0407baSopenharmony_ci if (ret) { 29653d0407baSopenharmony_ci dev_err(&pdev->dev, "plug_out_irq request failed!\n"); 29663d0407baSopenharmony_ci return ret; 29673d0407baSopenharmony_ci } 29683d0407baSopenharmony_ci 29693d0407baSopenharmony_ci if (rk817_bat_field_read(battery, PLUG_IN_STS)) { 29703d0407baSopenharmony_ci battery->plugin_trigger = 1; 29713d0407baSopenharmony_ci battery->plugout_trigger = 0; 29723d0407baSopenharmony_ci } 29733d0407baSopenharmony_ci 29743d0407baSopenharmony_ci return 0; 29753d0407baSopenharmony_ci} 29763d0407baSopenharmony_ci 29773d0407baSopenharmony_ci#ifdef CONFIG_OF 29783d0407baSopenharmony_cistatic const struct of_device_id rk817_bat_of_match[] = { 29793d0407baSopenharmony_ci { .compatible = "rk817,battery", }, 29803d0407baSopenharmony_ci { }, 29813d0407baSopenharmony_ci}; 29823d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, rk817_bat_of_match); 29833d0407baSopenharmony_ci#else 29843d0407baSopenharmony_cistatic const struct of_device_id rk817_bat_of_match[] = { 29853d0407baSopenharmony_ci { }, 29863d0407baSopenharmony_ci}; 29873d0407baSopenharmony_ci#endif 29883d0407baSopenharmony_ci 29893d0407baSopenharmony_cistatic int rk817_battery_probe(struct platform_device *pdev) 29903d0407baSopenharmony_ci{ 29913d0407baSopenharmony_ci const struct of_device_id *of_id = 29923d0407baSopenharmony_ci of_match_device(rk817_bat_of_match, &pdev->dev); 29933d0407baSopenharmony_ci struct rk817_battery_device *battery; 29943d0407baSopenharmony_ci struct rk808 *rk817 = dev_get_drvdata(pdev->dev.parent); 29953d0407baSopenharmony_ci struct i2c_client *client = rk817->i2c; 29963d0407baSopenharmony_ci int i, ret; 29973d0407baSopenharmony_ci 29983d0407baSopenharmony_ci if (!of_id) { 29993d0407baSopenharmony_ci dev_err(&pdev->dev, "Failed to find matching dt id\n"); 30003d0407baSopenharmony_ci return -ENODEV; 30013d0407baSopenharmony_ci } 30023d0407baSopenharmony_ci 30033d0407baSopenharmony_ci battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); 30043d0407baSopenharmony_ci if (!battery) 30053d0407baSopenharmony_ci return -EINVAL; 30063d0407baSopenharmony_ci 30073d0407baSopenharmony_ci battery->rk817 = rk817; 30083d0407baSopenharmony_ci battery->client = client; 30093d0407baSopenharmony_ci battery->dev = &pdev->dev; 30103d0407baSopenharmony_ci platform_set_drvdata(pdev, battery); 30113d0407baSopenharmony_ci battery->chip_id = rk817->variant; 30123d0407baSopenharmony_ci 30133d0407baSopenharmony_ci battery->regmap = rk817->regmap; 30143d0407baSopenharmony_ci if (IS_ERR(battery->regmap)) { 30153d0407baSopenharmony_ci dev_err(battery->dev, "Failed to initialize regmap\n"); 30163d0407baSopenharmony_ci return -EINVAL; 30173d0407baSopenharmony_ci } 30183d0407baSopenharmony_ci 30193d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk817_battery_reg_fields); i++) { 30203d0407baSopenharmony_ci const struct reg_field *reg_fields = rk817_battery_reg_fields; 30213d0407baSopenharmony_ci 30223d0407baSopenharmony_ci battery->rmap_fields[i] = 30233d0407baSopenharmony_ci devm_regmap_field_alloc(battery->dev, 30243d0407baSopenharmony_ci battery->regmap, 30253d0407baSopenharmony_ci reg_fields[i]); 30263d0407baSopenharmony_ci if (IS_ERR(battery->rmap_fields[i])) { 30273d0407baSopenharmony_ci dev_err(battery->dev, "cannot allocate regmap field\n"); 30283d0407baSopenharmony_ci return PTR_ERR(battery->rmap_fields[i]); 30293d0407baSopenharmony_ci } 30303d0407baSopenharmony_ci } 30313d0407baSopenharmony_ci 30323d0407baSopenharmony_ci ret = rk817_bat_parse_dt(battery); 30333d0407baSopenharmony_ci if (ret < 0) { 30343d0407baSopenharmony_ci dev_err(battery->dev, "battery parse dt failed!\n"); 30353d0407baSopenharmony_ci return ret; 30363d0407baSopenharmony_ci } 30373d0407baSopenharmony_ci 30383d0407baSopenharmony_ci rk817_bat_init_info(battery); 30393d0407baSopenharmony_ci rk817_bat_init_fg(battery); 30403d0407baSopenharmony_ci 30413d0407baSopenharmony_ci rk817_battery_debug_info(battery); 30423d0407baSopenharmony_ci rk817_bat_update_info(battery); 30433d0407baSopenharmony_ci 30443d0407baSopenharmony_ci rk817_bat_output_info(battery); 30453d0407baSopenharmony_ci battery->bat_monitor_wq = alloc_ordered_workqueue("%s", 30463d0407baSopenharmony_ci WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk817-bat-monitor-wq"); 30473d0407baSopenharmony_ci INIT_DELAYED_WORK(&battery->bat_delay_work, rk817_battery_work); 30483d0407baSopenharmony_ci queue_delayed_work(battery->bat_monitor_wq, &battery->bat_delay_work, 30493d0407baSopenharmony_ci msecs_to_jiffies(TIMER_MS_COUNTS * 5)); 30503d0407baSopenharmony_ci INIT_WORK(&battery->resume_work, rk817_bat_resume_work); 30513d0407baSopenharmony_ci 30523d0407baSopenharmony_ci ret = rk817_bat_init_power_supply(battery); 30533d0407baSopenharmony_ci if (ret) { 30543d0407baSopenharmony_ci dev_err(battery->dev, "rk817 power supply register failed!\n"); 30553d0407baSopenharmony_ci return ret; 30563d0407baSopenharmony_ci } 30573d0407baSopenharmony_ci if (battery->is_register_chg_psy) { 30583d0407baSopenharmony_ci ret = rk809_chg_init_power_supply(battery); 30593d0407baSopenharmony_ci if (ret) { 30603d0407baSopenharmony_ci dev_err(battery->dev, "rk809 chg psy init failed!\n"); 30613d0407baSopenharmony_ci return ret; 30623d0407baSopenharmony_ci } 30633d0407baSopenharmony_ci } 30643d0407baSopenharmony_ci 30653d0407baSopenharmony_ci if (battery->chip_id == RK809_ID) 30663d0407baSopenharmony_ci rk809_charge_init_irqs(battery); 30673d0407baSopenharmony_ci 30683d0407baSopenharmony_ci wake_lock_init(&battery->wake_lock, WAKE_LOCK_SUSPEND, 30693d0407baSopenharmony_ci "rk817_bat_lock"); 30703d0407baSopenharmony_ci 30713d0407baSopenharmony_ci DBG("name: 0x%x", rk817_bat_field_read(battery, CHIP_NAME_H)); 30723d0407baSopenharmony_ci DBG("%x\n", rk817_bat_field_read(battery, CHIP_NAME_L)); 30733d0407baSopenharmony_ci DBG("driver version %s\n", DRIVER_VERSION); 30743d0407baSopenharmony_ci 30753d0407baSopenharmony_ci return 0; 30763d0407baSopenharmony_ci} 30773d0407baSopenharmony_ci 30783d0407baSopenharmony_cistatic void rk817_battery_shutdown(struct platform_device *dev) 30793d0407baSopenharmony_ci{ 30803d0407baSopenharmony_ci} 30813d0407baSopenharmony_ci 30823d0407baSopenharmony_cistatic time64_t rk817_get_rtc_sec(void) 30833d0407baSopenharmony_ci{ 30843d0407baSopenharmony_ci int err; 30853d0407baSopenharmony_ci struct rtc_time tm; 30863d0407baSopenharmony_ci struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); 30873d0407baSopenharmony_ci 30883d0407baSopenharmony_ci err = rtc_read_time(rtc, &tm); 30893d0407baSopenharmony_ci if (err) { 30903d0407baSopenharmony_ci dev_err(rtc->dev.parent, "read hardware clk failed\n"); 30913d0407baSopenharmony_ci return 0; 30923d0407baSopenharmony_ci } 30933d0407baSopenharmony_ci 30943d0407baSopenharmony_ci err = rtc_valid_tm(&tm); 30953d0407baSopenharmony_ci if (err) { 30963d0407baSopenharmony_ci dev_err(rtc->dev.parent, "invalid date time\n"); 30973d0407baSopenharmony_ci return 0; 30983d0407baSopenharmony_ci } 30993d0407baSopenharmony_ci 31003d0407baSopenharmony_ci return rtc_tm_to_time64(&tm); 31013d0407baSopenharmony_ci} 31023d0407baSopenharmony_ci 31033d0407baSopenharmony_ci#ifdef CONFIG_PM_SLEEP 31043d0407baSopenharmony_cistatic int rk817_bat_pm_suspend(struct device *dev) 31053d0407baSopenharmony_ci{ 31063d0407baSopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 31073d0407baSopenharmony_ci struct rk817_battery_device *battery = dev_get_drvdata(&pdev->dev); 31083d0407baSopenharmony_ci 31093d0407baSopenharmony_ci cancel_delayed_work_sync(&battery->bat_delay_work); 31103d0407baSopenharmony_ci 31113d0407baSopenharmony_ci battery->s2r = false; 31123d0407baSopenharmony_ci battery->sleep_chrg_status = get_charge_status(battery); 31133d0407baSopenharmony_ci battery->current_avg = rk817_bat_get_avg_current(battery); 31143d0407baSopenharmony_ci if (battery->current_avg > 0 || 31153d0407baSopenharmony_ci (battery->sleep_chrg_status == CC_OR_CV_CHRG) || 31163d0407baSopenharmony_ci (battery->sleep_chrg_status == CHARGE_FINISH)) 31173d0407baSopenharmony_ci battery->sleep_chrg_online = 1; 31183d0407baSopenharmony_ci else 31193d0407baSopenharmony_ci battery->sleep_chrg_online = 0; 31203d0407baSopenharmony_ci 31213d0407baSopenharmony_ci battery->remain_cap = rk817_bat_get_capacity_uah(battery); 31223d0407baSopenharmony_ci battery->rsoc = rk817_bat_get_rsoc(battery); 31233d0407baSopenharmony_ci 31243d0407baSopenharmony_ci battery->rtc_base = rk817_get_rtc_sec(); 31253d0407baSopenharmony_ci rk817_bat_save_data(battery); 31263d0407baSopenharmony_ci 31273d0407baSopenharmony_ci if (battery->sleep_chrg_status != CHARGE_FINISH) 31283d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 31293d0407baSopenharmony_ci 31303d0407baSopenharmony_ci if ((battery->work_mode == MODE_ZERO) && 31313d0407baSopenharmony_ci (battery->current_avg >= 0)) { 31323d0407baSopenharmony_ci DBG("suspend: MODE_ZERO exit...\n"); 31333d0407baSopenharmony_ci /* it need't do prepare for mode finish and smooth, it will 31343d0407baSopenharmony_ci * be done in display_smooth 31353d0407baSopenharmony_ci */ 31363d0407baSopenharmony_ci if (battery->sleep_chrg_status == CHARGE_FINISH) { 31373d0407baSopenharmony_ci battery->work_mode = MODE_FINISH; 31383d0407baSopenharmony_ci battery->finish_base = get_boot_sec(); 31393d0407baSopenharmony_ci } else { 31403d0407baSopenharmony_ci battery->work_mode = MODE_SMOOTH; 31413d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 31423d0407baSopenharmony_ci } 31433d0407baSopenharmony_ci } 31443d0407baSopenharmony_ci 31453d0407baSopenharmony_ci DBG("suspend get_boot_sec: %lld\n", get_boot_sec()); 31463d0407baSopenharmony_ci 31473d0407baSopenharmony_ci DBG("suspend: dl=%d rl=%d c=%d v=%d cap=%d at=%ld ch=%d\n", 31483d0407baSopenharmony_ci battery->dsoc, battery->rsoc, battery->current_avg, 31493d0407baSopenharmony_ci rk817_bat_get_battery_voltage(battery), 31503d0407baSopenharmony_ci rk817_bat_get_capacity_uah(battery), 31513d0407baSopenharmony_ci battery->sleep_dischrg_sec, battery->sleep_chrg_online); 31523d0407baSopenharmony_ci DBG("battery->sleep_chrg_status=%d\n", battery->sleep_chrg_status); 31533d0407baSopenharmony_ci 31543d0407baSopenharmony_ci return 0; 31553d0407baSopenharmony_ci} 31563d0407baSopenharmony_ci 31573d0407baSopenharmony_cistatic int rk817_bat_rtc_sleep_sec(struct rk817_battery_device *battery) 31583d0407baSopenharmony_ci{ 31593d0407baSopenharmony_ci int interval_sec; 31603d0407baSopenharmony_ci 31613d0407baSopenharmony_ci interval_sec = rk817_get_rtc_sec() - battery->rtc_base; 31623d0407baSopenharmony_ci 31633d0407baSopenharmony_ci return (interval_sec > 0) ? interval_sec : 0; 31643d0407baSopenharmony_ci} 31653d0407baSopenharmony_ci 31663d0407baSopenharmony_cistatic void rk817_bat_relife_age_flag(struct rk817_battery_device *battery) 31673d0407baSopenharmony_ci{ 31683d0407baSopenharmony_ci u8 ocv_soc, ocv_cap, soc_level; 31693d0407baSopenharmony_ci 31703d0407baSopenharmony_ci if (battery->voltage_relax <= 0) 31713d0407baSopenharmony_ci return; 31723d0407baSopenharmony_ci 31733d0407baSopenharmony_ci ocv_soc = rk817_bat_vol_to_soc(battery, battery->voltage_relax); 31743d0407baSopenharmony_ci ocv_cap = rk817_bat_vol_to_cap(battery, battery->voltage_relax); 31753d0407baSopenharmony_ci DBG("<%s>. ocv_soc=%d, min=%lu, vol=%d\n", __func__, 31763d0407baSopenharmony_ci ocv_soc, battery->sleep_dischrg_sec / 60, battery->voltage_relax); 31773d0407baSopenharmony_ci 31783d0407baSopenharmony_ci /* sleep enough time and ocv_soc enough low */ 31793d0407baSopenharmony_ci if (!battery->age_allow_update && ocv_soc <= 10) { 31803d0407baSopenharmony_ci battery->age_voltage = battery->voltage_relax; 31813d0407baSopenharmony_ci battery->age_ocv_cap = ocv_cap; 31823d0407baSopenharmony_ci battery->age_ocv_soc = ocv_soc; 31833d0407baSopenharmony_ci battery->age_adjust_cap = 0; 31843d0407baSopenharmony_ci 31853d0407baSopenharmony_ci if (ocv_soc <= 1) 31863d0407baSopenharmony_ci battery->age_level = 100; 31873d0407baSopenharmony_ci else if (ocv_soc < 5) 31883d0407baSopenharmony_ci battery->age_level = 90; 31893d0407baSopenharmony_ci else 31903d0407baSopenharmony_ci battery->age_level = 80; 31913d0407baSopenharmony_ci 31923d0407baSopenharmony_ci /*soc_level = rk818_bat_get_age_level(battery);*/ 31933d0407baSopenharmony_ci soc_level = 0; 31943d0407baSopenharmony_ci if (soc_level > battery->age_level) { 31953d0407baSopenharmony_ci battery->age_allow_update = false; 31963d0407baSopenharmony_ci } else { 31973d0407baSopenharmony_ci battery->age_allow_update = true; 31983d0407baSopenharmony_ci battery->age_keep_sec = get_boot_sec(); 31993d0407baSopenharmony_ci } 32003d0407baSopenharmony_ci 32013d0407baSopenharmony_ci BAT_INFO("resume: age_vol:%d, age_ocv_cap:%d, age_ocv_soc:%d, " 32023d0407baSopenharmony_ci "soc_level:%d, age_allow_update:%d, " 32033d0407baSopenharmony_ci "age_level:%d\n", 32043d0407baSopenharmony_ci battery->age_voltage, battery->age_ocv_cap, 32053d0407baSopenharmony_ci ocv_soc, soc_level, 32063d0407baSopenharmony_ci battery->age_allow_update, battery->age_level); 32073d0407baSopenharmony_ci } 32083d0407baSopenharmony_ci} 32093d0407baSopenharmony_ci 32103d0407baSopenharmony_cistatic void rk817_bat_init_capacity(struct rk817_battery_device *battery, 32113d0407baSopenharmony_ci u32 cap) 32123d0407baSopenharmony_ci{ 32133d0407baSopenharmony_ci int delta_cap; 32143d0407baSopenharmony_ci 32153d0407baSopenharmony_ci delta_cap = cap - battery->remain_cap; 32163d0407baSopenharmony_ci if (!delta_cap) 32173d0407baSopenharmony_ci return; 32183d0407baSopenharmony_ci 32193d0407baSopenharmony_ci battery->age_adjust_cap += delta_cap; 32203d0407baSopenharmony_ci rk817_bat_init_coulomb_cap(battery, cap); 32213d0407baSopenharmony_ci rk817_bat_smooth_algo_prepare(battery); 32223d0407baSopenharmony_ci rk817_bat_zero_algo_prepare(battery); 32233d0407baSopenharmony_ci} 32243d0407baSopenharmony_ci 32253d0407baSopenharmony_cistatic void rk817_bat_relax_vol_calib(struct rk817_battery_device *battery) 32263d0407baSopenharmony_ci{ 32273d0407baSopenharmony_ci int soc, cap, vol; 32283d0407baSopenharmony_ci 32293d0407baSopenharmony_ci vol = battery->voltage_relax; 32303d0407baSopenharmony_ci soc = rk817_bat_vol_to_soc(battery, vol); 32313d0407baSopenharmony_ci cap = rk817_bat_vol_to_cap(battery, vol); 32323d0407baSopenharmony_ci rk817_bat_init_capacity(battery, cap); 32333d0407baSopenharmony_ci BAT_INFO("sleep ocv calib: rsoc=%d, cap=%d\n", soc, cap); 32343d0407baSopenharmony_ci} 32353d0407baSopenharmony_ci 32363d0407baSopenharmony_cistatic int rk817_bat_sleep_dischrg(struct rk817_battery_device *battery) 32373d0407baSopenharmony_ci{ 32383d0407baSopenharmony_ci bool ocv_soc_updated = false; 32393d0407baSopenharmony_ci int tgt_dsoc, gap_soc, sleep_soc = 0; 32403d0407baSopenharmony_ci int pwroff_vol = battery->pdata->pwroff_vol; 32413d0407baSopenharmony_ci unsigned long sleep_sec = battery->sleep_dischrg_sec; 32423d0407baSopenharmony_ci int sleep_cur; 32433d0407baSopenharmony_ci 32443d0407baSopenharmony_ci DBG("<%s>. enter: dsoc=%d, rsoc=%d, rv=%d, v=%d, sleep_min=%lu\n", 32453d0407baSopenharmony_ci __func__, battery->dsoc, battery->rsoc, battery->voltage_relax, 32463d0407baSopenharmony_ci battery->voltage_avg, sleep_sec / 60); 32473d0407baSopenharmony_ci 32483d0407baSopenharmony_ci if (battery->voltage_relax >= battery->voltage_avg) { 32493d0407baSopenharmony_ci rk817_bat_relax_vol_calib(battery); 32503d0407baSopenharmony_ci rk817_bat_restart_relax(battery); 32513d0407baSopenharmony_ci rk817_bat_relife_age_flag(battery); 32523d0407baSopenharmony_ci ocv_soc_updated = true; 32533d0407baSopenharmony_ci } 32543d0407baSopenharmony_ci 32553d0407baSopenharmony_ci /* handle dsoc */ 32563d0407baSopenharmony_ci if (battery->dsoc <= battery->rsoc) { 32573d0407baSopenharmony_ci if (battery->pdata->low_pwr_sleep) 32583d0407baSopenharmony_ci sleep_cur = LOW_PWR_SLP_CURR_MIN; 32593d0407baSopenharmony_ci else 32603d0407baSopenharmony_ci sleep_cur = SLP_CURR_MIN; 32613d0407baSopenharmony_ci battery->sleep_sum_cap = (sleep_cur * sleep_sec / 3600); 32623d0407baSopenharmony_ci sleep_soc = battery->sleep_sum_cap * 100 / DIV(battery->fcc); 32633d0407baSopenharmony_ci tgt_dsoc = battery->dsoc - sleep_soc * 1000; 32643d0407baSopenharmony_ci if (sleep_soc > 0) { 32653d0407baSopenharmony_ci BAT_INFO("calib0: rl=%d, dl=%d, intval=%d\n", 32663d0407baSopenharmony_ci battery->rsoc, battery->dsoc, sleep_soc); 32673d0407baSopenharmony_ci if (battery->dsoc / 1000 < 5) { 32683d0407baSopenharmony_ci battery->dsoc -= 1000; 32693d0407baSopenharmony_ci } else if ((tgt_dsoc / 1000 < 5) && 32703d0407baSopenharmony_ci (battery->dsoc / 1000 >= 5)) { 32713d0407baSopenharmony_ci if (battery->dsoc / 1000 == 5) 32723d0407baSopenharmony_ci battery->dsoc -= 1000; 32733d0407baSopenharmony_ci else 32743d0407baSopenharmony_ci battery->dsoc = 5 * 1000; 32753d0407baSopenharmony_ci } else if (tgt_dsoc / 1000 > 5) { 32763d0407baSopenharmony_ci battery->dsoc = tgt_dsoc; 32773d0407baSopenharmony_ci } 32783d0407baSopenharmony_ci } 32793d0407baSopenharmony_ci 32803d0407baSopenharmony_ci DBG("%s: dsoc<=rsoc, sum_cap=%d==>sleep_soc=%d, tgt_dsoc=%d\n", 32813d0407baSopenharmony_ci __func__, battery->sleep_sum_cap, sleep_soc, tgt_dsoc); 32823d0407baSopenharmony_ci } else { 32833d0407baSopenharmony_ci /* di->dsoc > di->rsoc */ 32843d0407baSopenharmony_ci if (battery->pdata->low_pwr_sleep) 32853d0407baSopenharmony_ci sleep_cur = LOW_PWR_SLP_CURR_MAX; 32863d0407baSopenharmony_ci else 32873d0407baSopenharmony_ci sleep_cur = SLP_CURR_MAX; 32883d0407baSopenharmony_ci battery->sleep_sum_cap = (sleep_cur * sleep_sec / 3600); 32893d0407baSopenharmony_ci sleep_soc = battery->sleep_sum_cap / DIV(battery->fcc / 100); 32903d0407baSopenharmony_ci gap_soc = battery->dsoc - battery->rsoc; 32913d0407baSopenharmony_ci 32923d0407baSopenharmony_ci DBG("calib1: rsoc=%d, dsoc=%d, intval=%d\n", 32933d0407baSopenharmony_ci battery->rsoc, battery->dsoc, sleep_soc); 32943d0407baSopenharmony_ci if (gap_soc / 1000 > sleep_soc) { 32953d0407baSopenharmony_ci if ((gap_soc - 5000) > (sleep_soc * 2 * 1000)) 32963d0407baSopenharmony_ci battery->dsoc -= (sleep_soc * 2 * 1000); 32973d0407baSopenharmony_ci else 32983d0407baSopenharmony_ci battery->dsoc -= sleep_soc * 1000; 32993d0407baSopenharmony_ci } else { 33003d0407baSopenharmony_ci battery->dsoc = battery->rsoc; 33013d0407baSopenharmony_ci } 33023d0407baSopenharmony_ci 33033d0407baSopenharmony_ci DBG("%s: dsoc>rsoc, sum_cap=%d=>sleep_soc=%d, gap_soc=%d\n", 33043d0407baSopenharmony_ci __func__, battery->sleep_sum_cap, sleep_soc, gap_soc); 33053d0407baSopenharmony_ci } 33063d0407baSopenharmony_ci 33073d0407baSopenharmony_ci if (battery->voltage_avg <= pwroff_vol - 70) { 33083d0407baSopenharmony_ci battery->dsoc = 0; 33093d0407baSopenharmony_ci DBG("low power sleeping, shutdown... %d\n", battery->dsoc); 33103d0407baSopenharmony_ci } 33113d0407baSopenharmony_ci 33123d0407baSopenharmony_ci if (ocv_soc_updated && sleep_soc && 33133d0407baSopenharmony_ci (battery->rsoc - battery->dsoc) < 5000 && 33143d0407baSopenharmony_ci battery->dsoc < 40 * 1000) { 33153d0407baSopenharmony_ci battery->dsoc -= 1000; 33163d0407baSopenharmony_ci DBG("low power sleeping, reserved... %d\n", battery->dsoc); 33173d0407baSopenharmony_ci } 33183d0407baSopenharmony_ci 33193d0407baSopenharmony_ci if (battery->dsoc <= 0) { 33203d0407baSopenharmony_ci battery->dsoc = 0; 33213d0407baSopenharmony_ci DBG("sleep dsoc is %d...\n", battery->dsoc); 33223d0407baSopenharmony_ci } 33233d0407baSopenharmony_ci 33243d0407baSopenharmony_ci DBG("<%s>. out: dsoc=%d, rsoc=%d, sum_cap=%d\n", 33253d0407baSopenharmony_ci __func__, battery->dsoc, battery->rsoc, battery->sleep_sum_cap); 33263d0407baSopenharmony_ci 33273d0407baSopenharmony_ci return sleep_soc; 33283d0407baSopenharmony_ci} 33293d0407baSopenharmony_ci 33303d0407baSopenharmony_cistatic void rk817_bat_resume_work(struct work_struct *work) 33313d0407baSopenharmony_ci{ 33323d0407baSopenharmony_ci struct rk817_battery_device *battery = container_of(work, struct rk817_battery_device, resume_work); 33333d0407baSopenharmony_ci int interval_sec = 0, time_step = 0, pwroff_vol; 33343d0407baSopenharmony_ci 33353d0407baSopenharmony_ci battery->s2r = true; 33363d0407baSopenharmony_ci battery->current_avg = rk817_bat_get_avg_current(battery); 33373d0407baSopenharmony_ci battery->voltage_relax = rk817_bat_get_relax_voltage(battery); 33383d0407baSopenharmony_ci battery->voltage_avg = rk817_bat_get_battery_voltage(battery); 33393d0407baSopenharmony_ci battery->remain_cap = rk817_bat_get_capacity_uah(battery); 33403d0407baSopenharmony_ci battery->rsoc = rk817_bat_get_rsoc(battery); 33413d0407baSopenharmony_ci interval_sec = rk817_bat_rtc_sleep_sec(battery); 33423d0407baSopenharmony_ci battery->sleep_sum_sec += interval_sec; 33433d0407baSopenharmony_ci pwroff_vol = battery->pdata->pwroff_vol; 33443d0407baSopenharmony_ci 33453d0407baSopenharmony_ci if (!battery->sleep_chrg_online) { 33463d0407baSopenharmony_ci /* only add up discharge sleep seconds */ 33473d0407baSopenharmony_ci battery->sleep_dischrg_sec += interval_sec; 33483d0407baSopenharmony_ci if (battery->voltage_avg <= pwroff_vol + 50) 33493d0407baSopenharmony_ci time_step = DISCHRG_TIME_STEP1; 33503d0407baSopenharmony_ci else 33513d0407baSopenharmony_ci time_step = DISCHRG_TIME_STEP2; 33523d0407baSopenharmony_ci } 33533d0407baSopenharmony_ci 33543d0407baSopenharmony_ci DBG("resume: dl=%d rl=%d c=%d v=%d rv=%d " 33553d0407baSopenharmony_ci "cap=%d dt=%d at=%ld ch=%d, sec = %d\n", 33563d0407baSopenharmony_ci battery->dsoc, battery->rsoc, battery->current_avg, 33573d0407baSopenharmony_ci battery->voltage_avg, battery->voltage_relax, 33583d0407baSopenharmony_ci rk817_bat_get_capacity_uah(battery), interval_sec, 33593d0407baSopenharmony_ci battery->sleep_dischrg_sec, battery->sleep_chrg_online, 33603d0407baSopenharmony_ci interval_sec); 33613d0407baSopenharmony_ci 33623d0407baSopenharmony_ci /* sleep: enough time and discharge */ 33633d0407baSopenharmony_ci if ((!battery->sleep_chrg_online) && 33643d0407baSopenharmony_ci (battery->sleep_dischrg_sec > time_step)) { 33653d0407baSopenharmony_ci if (rk817_bat_sleep_dischrg(battery)) 33663d0407baSopenharmony_ci battery->sleep_dischrg_sec = 0; 33673d0407baSopenharmony_ci } 33683d0407baSopenharmony_ci 33693d0407baSopenharmony_ci rk817_bat_save_data(battery); 33703d0407baSopenharmony_ci 33713d0407baSopenharmony_ci /* charge/lowpower lock: for battery work to update dsoc and rsoc */ 33723d0407baSopenharmony_ci if ((battery->sleep_chrg_online) || 33733d0407baSopenharmony_ci (!battery->sleep_chrg_online && 33743d0407baSopenharmony_ci battery->voltage_avg < battery->pdata->pwroff_vol)) 33753d0407baSopenharmony_ci wake_lock_timeout(&battery->wake_lock, msecs_to_jiffies(2000)); 33763d0407baSopenharmony_ci 33773d0407baSopenharmony_ci queue_delayed_work(battery->bat_monitor_wq, &battery->bat_delay_work, 33783d0407baSopenharmony_ci msecs_to_jiffies(1000)); 33793d0407baSopenharmony_ci} 33803d0407baSopenharmony_ci 33813d0407baSopenharmony_cistatic int rk817_bat_pm_resume(struct device *dev) 33823d0407baSopenharmony_ci{ 33833d0407baSopenharmony_ci struct rk817_battery_device *battery = dev_get_drvdata(dev); 33843d0407baSopenharmony_ci 33853d0407baSopenharmony_ci queue_work(battery->bat_monitor_wq, &battery->resume_work); 33863d0407baSopenharmony_ci 33873d0407baSopenharmony_ci return 0; 33883d0407baSopenharmony_ci} 33893d0407baSopenharmony_ci#endif 33903d0407baSopenharmony_ci 33913d0407baSopenharmony_cistatic SIMPLE_DEV_PM_OPS(rk817_bat_pm_ops, 33923d0407baSopenharmony_ci rk817_bat_pm_suspend, 33933d0407baSopenharmony_ci rk817_bat_pm_resume); 33943d0407baSopenharmony_ci 33953d0407baSopenharmony_cistatic struct platform_driver rk817_battery_driver = { 33963d0407baSopenharmony_ci .probe = rk817_battery_probe, 33973d0407baSopenharmony_ci .shutdown = rk817_battery_shutdown, 33983d0407baSopenharmony_ci .driver = { 33993d0407baSopenharmony_ci .name = "rk817-battery", 34003d0407baSopenharmony_ci .pm = &rk817_bat_pm_ops, 34013d0407baSopenharmony_ci .of_match_table = of_match_ptr(rk817_bat_of_match), 34023d0407baSopenharmony_ci }, 34033d0407baSopenharmony_ci}; 34043d0407baSopenharmony_ci 34053d0407baSopenharmony_cistatic int __init rk817_battery_init(void) 34063d0407baSopenharmony_ci{ 34073d0407baSopenharmony_ci return platform_driver_register(&rk817_battery_driver); 34083d0407baSopenharmony_ci} 34093d0407baSopenharmony_cifs_initcall_sync(rk817_battery_init); 34103d0407baSopenharmony_ci 34113d0407baSopenharmony_cistatic void __exit rk817_battery_exit(void) 34123d0407baSopenharmony_ci{ 34133d0407baSopenharmony_ci platform_driver_unregister(&rk817_battery_driver); 34143d0407baSopenharmony_ci} 34153d0407baSopenharmony_cimodule_exit(rk817_battery_exit); 34163d0407baSopenharmony_ci 34173d0407baSopenharmony_ciMODULE_DESCRIPTION("RK817 Battery driver"); 34183d0407baSopenharmony_ciMODULE_LICENSE("GPL"); 3419