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