1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <dm.h>
8*4882a593Smuzhiyun #include <errno.h>
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <malloc.h>
11*4882a593Smuzhiyun #include <fdtdec.h>
12*4882a593Smuzhiyun #include <asm/gpio.h>
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <power/pmic.h>
15*4882a593Smuzhiyun #include <dm/uclass-internal.h>
16*4882a593Smuzhiyun #include <power/charge_display.h>
17*4882a593Smuzhiyun #include <power/charge_animation.h>
18*4882a593Smuzhiyun #include <power/fuel_gauge.h>
19*4882a593Smuzhiyun #include <power/rk8xx_pmic.h>
20*4882a593Smuzhiyun #include <linux/usb/phy-rockchip-usb2.h>
21*4882a593Smuzhiyun #include "fg_regs.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static int dbg_enable = 0;
26*4882a593Smuzhiyun #define DBG(args...) \
27*4882a593Smuzhiyun do { \
28*4882a593Smuzhiyun if (dbg_enable) { \
29*4882a593Smuzhiyun printf(args); \
30*4882a593Smuzhiyun } \
31*4882a593Smuzhiyun } while (0)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define BAT_INFO(fmt, args...) printf("rk818-bat: "fmt, ##args)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define DRIVER_VERSION "2.0"
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* THERMAL_REG */
38*4882a593Smuzhiyun #define TEMP_105C (0x02 << 2)
39*4882a593Smuzhiyun #define FB_TEMP_MSK 0x0c
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* CHRG_CTRL_REG2 */
42*4882a593Smuzhiyun #define FINISH_100MA (0x00 << 6)
43*4882a593Smuzhiyun #define FINISH_150MA (0x01 << 6)
44*4882a593Smuzhiyun #define FINISH_200MA (0x02 << 6)
45*4882a593Smuzhiyun #define FINISH_250MA (0x03 << 6)
46*4882a593Smuzhiyun #define FINISH_CUR_MSK 0xc7
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* CHRG_CTRL_REG3 */
49*4882a593Smuzhiyun #define CHRG_TERM_DIG_SIGNAL (1 << 5)
50*4882a593Smuzhiyun #define CHRG_TERM_ANA_SIGNAL (0 << 5)
51*4882a593Smuzhiyun #define CHRG_TIMER_CCCV_EN (1 << 2)
52*4882a593Smuzhiyun #define CHRG_TERM_SIG_MSK (1 << 5)
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* CHRG_CTRL_REG */
55*4882a593Smuzhiyun #define ILIM_450MA (0x00)
56*4882a593Smuzhiyun #define ILIM_80MA (0x01)
57*4882a593Smuzhiyun #define ILIM_850MA (0x02)
58*4882a593Smuzhiyun #define ILIM_2000MA (0x07)
59*4882a593Smuzhiyun #define CHRG_CT_EN (1 << 7)
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* USB_CTRL_REG */
62*4882a593Smuzhiyun #define INPUT_CUR_MSK 0x0f
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* VB_MON_REG */
65*4882a593Smuzhiyun #define PLUG_IN_STS (1 << 6)
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* GGSTS */
68*4882a593Smuzhiyun #define BAT_CON (1 << 4)
69*4882a593Smuzhiyun #define VOL_INSTANT (1 << 0)
70*4882a593Smuzhiyun #define VOL_AVG (0 << 0)
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* TS_CTRL_REG */
73*4882a593Smuzhiyun #define GG_EN (1 << 7)
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* CHRG_USB_CTRL */
76*4882a593Smuzhiyun #define CHRG_EN (1 << 7)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* ADC_CTRL_REG */
79*4882a593Smuzhiyun #define ADC_TS2_EN (1 << 4)
80*4882a593Smuzhiyun #define ADC_TS1_EN (1 << 5)
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* TS_CTRL_REG */
83*4882a593Smuzhiyun #define TS2_ADC_MODE (1 << 5)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* SUP_STS_REG */
86*4882a593Smuzhiyun #define BAT_EXS (1 << 7)
87*4882a593Smuzhiyun #define USB_EXIST (1 << 1)
88*4882a593Smuzhiyun #define USB_EFF (1 << 0)
89*4882a593Smuzhiyun #define CHARGE_OFF (0x00 << 4)
90*4882a593Smuzhiyun #define DEAD_CHARGE (0x01 << 4)
91*4882a593Smuzhiyun #define TRICKLE_CHARGE (0x02 << 4)
92*4882a593Smuzhiyun #define CC_OR_CV (0x03 << 4)
93*4882a593Smuzhiyun #define CHARGE_FINISH (0x04 << 4)
94*4882a593Smuzhiyun #define USB_OVER_VOL (0x05 << 4)
95*4882a593Smuzhiyun #define BAT_TMP_ERR (0x06 << 4)
96*4882a593Smuzhiyun #define TIMER_ERR (0x07 << 4)
97*4882a593Smuzhiyun #define USB_VLIMIT_EN (1 << 3)
98*4882a593Smuzhiyun #define USB_CLIMIT_EN (1 << 2)
99*4882a593Smuzhiyun #define BAT_STATUS_MSK 0x70
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* GGCON */
102*4882a593Smuzhiyun #define ADC_CUR_MODE (1 << 1)
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* CALI PARAM */
105*4882a593Smuzhiyun #define FINISH_CALI_CURR 1500
106*4882a593Smuzhiyun #define TERM_CALI_CURR 600
107*4882a593Smuzhiyun #define VIRTUAL_POWER_VOL 4200
108*4882a593Smuzhiyun #define VIRTUAL_POWER_CUR 1000
109*4882a593Smuzhiyun #define VIRTUAL_POWER_SOC 66
110*4882a593Smuzhiyun #define SECONDS(n) ((n) * 1000)
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* CALC PARAM */
113*4882a593Smuzhiyun #define MAX_PERCENTAGE 100
114*4882a593Smuzhiyun #define MAX_INTERPOLATE 1000
115*4882a593Smuzhiyun #define MAX_INT 0x7fff
116*4882a593Smuzhiyun #define MIN_FCC 500
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* sample resistor and division */
119*4882a593Smuzhiyun #define SAMPLE_RES_10mR 10
120*4882a593Smuzhiyun #define SAMPLE_RES_20mR 20
121*4882a593Smuzhiyun #define SAMPLE_RES_DIV1 1
122*4882a593Smuzhiyun #define SAMPLE_RES_DIV2 2
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #define FG_INIT (1 << 5)
125*4882a593Smuzhiyun #define FG_RESET_LATE (1 << 4)
126*4882a593Smuzhiyun #define FG_RESET_NOW (1 << 3)
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun #define DEFAULT_POFFSET 42
129*4882a593Smuzhiyun #define DEFAULT_COFFSET 0x832
130*4882a593Smuzhiyun #define INVALID_COFFSET_MIN 0x780
131*4882a593Smuzhiyun #define INVALID_COFFSET_MAX 0x980
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #define CHRG_TERM_DSOC 90
134*4882a593Smuzhiyun #define CHRG_TERM_K 650
135*4882a593Smuzhiyun #define CHRG_FULL_K 400
136*4882a593Smuzhiyun #define ADC_CALIB_THRESHOLD 4
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun #define TS2_THRESHOLD_VOL 4350
139*4882a593Smuzhiyun #define TS2_VALID_VOL 1000
140*4882a593Smuzhiyun #define TS2_VOL_MULTI 0
141*4882a593Smuzhiyun #define TS2_CHECK_CNT 5
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun #define ADC_CUR_MSK 0x03
144*4882a593Smuzhiyun #define ADC_CUR_20UA 0x00
145*4882a593Smuzhiyun #define ADC_CUR_40UA 0x01
146*4882a593Smuzhiyun #define ADC_CUR_60UA 0x02
147*4882a593Smuzhiyun #define ADC_CUR_80UA 0x03
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #define NTC_CALC_FACTOR_80UA 7
150*4882a593Smuzhiyun #define NTC_CALC_FACTOR_60UA 9
151*4882a593Smuzhiyun #define NTC_CALC_FACTOR_40UA 13
152*4882a593Smuzhiyun #define NTC_CALC_FACTOR_20UA 27
153*4882a593Smuzhiyun #define NTC_80UA_MAX_MEASURE 27500
154*4882a593Smuzhiyun #define NTC_60UA_MAX_MEASURE 36666
155*4882a593Smuzhiyun #define NTC_40UA_MAX_MEASURE 55000
156*4882a593Smuzhiyun #define NTC_20UA_MAX_MEASURE 110000
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun #define ZERO_MIN_VOLTAGE 3800
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun #define TS1_NOT_READY 0xabcdabcd
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun #define DIV(x) ((x) ? (x) : 1)
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /***********************************************************/
165*4882a593Smuzhiyun struct battery_priv {
166*4882a593Smuzhiyun struct udevice *dev;
167*4882a593Smuzhiyun int chrg_type;
168*4882a593Smuzhiyun int poffset;
169*4882a593Smuzhiyun int bat_res;
170*4882a593Smuzhiyun int current_avg;
171*4882a593Smuzhiyun int voltage_avg;
172*4882a593Smuzhiyun int voltage_ocv;
173*4882a593Smuzhiyun int voltage_k;
174*4882a593Smuzhiyun int voltage_b;
175*4882a593Smuzhiyun int dsoc;
176*4882a593Smuzhiyun int rsoc;
177*4882a593Smuzhiyun int fcc;
178*4882a593Smuzhiyun int qmax;
179*4882a593Smuzhiyun int remain_cap;
180*4882a593Smuzhiyun int design_cap;
181*4882a593Smuzhiyun int nac;
182*4882a593Smuzhiyun u32 *ocv_table;
183*4882a593Smuzhiyun u32 ocv_size;
184*4882a593Smuzhiyun u32 *ntc_table;
185*4882a593Smuzhiyun u32 ntc_size;
186*4882a593Smuzhiyun u32 ntc_factor;
187*4882a593Smuzhiyun u32 ntc_uA;
188*4882a593Smuzhiyun int ntc_degree_from;
189*4882a593Smuzhiyun int temperature;
190*4882a593Smuzhiyun int virtual_power;
191*4882a593Smuzhiyun int ts2_vol_multi;
192*4882a593Smuzhiyun int pwroff_min;
193*4882a593Smuzhiyun int sm_old_cap;
194*4882a593Smuzhiyun int sm_linek;
195*4882a593Smuzhiyun int sm_chrg_dsoc;
196*4882a593Smuzhiyun int adc_allow_update;
197*4882a593Smuzhiyun int chrg_vol_sel;
198*4882a593Smuzhiyun int chrg_cur_input;
199*4882a593Smuzhiyun int chrg_cur_sel;
200*4882a593Smuzhiyun int dts_vol_sel;
201*4882a593Smuzhiyun int dts_cur_input;
202*4882a593Smuzhiyun int dts_cur_sel;
203*4882a593Smuzhiyun int max_soc_offset;
204*4882a593Smuzhiyun int sample_res;
205*4882a593Smuzhiyun int res_div;
206*4882a593Smuzhiyun struct gpio_desc dc_det;
207*4882a593Smuzhiyun int dc_det_adc;
208*4882a593Smuzhiyun ulong finish_chrg_base;
209*4882a593Smuzhiyun ulong term_sig_base;
210*4882a593Smuzhiyun u8 calc_dsoc;
211*4882a593Smuzhiyun u8 calc_rsoc;
212*4882a593Smuzhiyun int sm_meet_soc;
213*4882a593Smuzhiyun u8 halt_cnt;
214*4882a593Smuzhiyun u8 dc_active_level;
215*4882a593Smuzhiyun u8 dc_is_valid;
216*4882a593Smuzhiyun bool is_halt;
217*4882a593Smuzhiyun bool is_ocv_calib;
218*4882a593Smuzhiyun bool is_max_soc_offset;
219*4882a593Smuzhiyun bool is_first_power_on;
220*4882a593Smuzhiyun bool is_sw_reset;
221*4882a593Smuzhiyun int pwr_dsoc;
222*4882a593Smuzhiyun int pwr_rsoc;
223*4882a593Smuzhiyun int pwr_vol;
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun enum charger_type {
227*4882a593Smuzhiyun NO_CHARGER = 0,
228*4882a593Smuzhiyun USB_CHARGER,
229*4882a593Smuzhiyun AC_CHARGER,
230*4882a593Smuzhiyun DC_CHARGER,
231*4882a593Smuzhiyun UNDEF_CHARGER,
232*4882a593Smuzhiyun };
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun static const u32 CHRG_VOL_SEL[] = {
235*4882a593Smuzhiyun 4050, 4100, 4150, 4200, 4250, 4300, 4350
236*4882a593Smuzhiyun };
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun static const u32 CHRG_CUR_SEL[] = {
239*4882a593Smuzhiyun 1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400, 2600, 2800, 3000
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun static const u32 CHRG_CUR_INPUT[] = {
243*4882a593Smuzhiyun 450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
rk818_bat_read(struct battery_priv * di,u8 reg)246*4882a593Smuzhiyun static int rk818_bat_read(struct battery_priv *di, u8 reg)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun return pmic_reg_read(di->dev->parent, reg);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
rk818_bat_write(struct battery_priv * di,u8 reg,u8 buf)251*4882a593Smuzhiyun static void rk818_bat_write(struct battery_priv *di, u8 reg, u8 buf)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun pmic_reg_write(di->dev->parent, reg, buf);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
rk818_bat_dwc_otg_check_dpdm(void)256*4882a593Smuzhiyun static int rk818_bat_dwc_otg_check_dpdm(void)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun #if defined(CONFIG_PHY_ROCKCHIP_INNO_USB2) && !defined(CONFIG_SPL_BUILD)
259*4882a593Smuzhiyun return rockchip_chg_get_type();
260*4882a593Smuzhiyun #else
261*4882a593Smuzhiyun debug("rockchip_chg_get_type() is not implement\n");
262*4882a593Smuzhiyun return NO_CHARGER;
263*4882a593Smuzhiyun #endif
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
rk818_bat_get_rsoc(struct battery_priv * di)266*4882a593Smuzhiyun static int rk818_bat_get_rsoc(struct battery_priv *di)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun return (di->remain_cap + di->fcc / 200) * 100 / DIV(di->fcc);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
rk818_bat_get_dsoc(struct battery_priv * di)271*4882a593Smuzhiyun static int rk818_bat_get_dsoc(struct battery_priv *di)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun return rk818_bat_read(di, SOC_REG);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
rk818_bat_enable_gauge(struct battery_priv * di)276*4882a593Smuzhiyun static void rk818_bat_enable_gauge(struct battery_priv *di)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun u8 val;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun val = rk818_bat_read(di, TS_CTRL_REG);
281*4882a593Smuzhiyun val |= GG_EN;
282*4882a593Smuzhiyun rk818_bat_write(di, TS_CTRL_REG, val);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
rk818_bat_get_vcalib0(struct battery_priv * di)285*4882a593Smuzhiyun static int rk818_bat_get_vcalib0(struct battery_priv *di)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun int val = 0;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun val |= rk818_bat_read(di, VCALIB0_REGL) << 0;
290*4882a593Smuzhiyun val |= rk818_bat_read(di, VCALIB0_REGH) << 8;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun return val;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
rk818_bat_get_vcalib1(struct battery_priv * di)295*4882a593Smuzhiyun static int rk818_bat_get_vcalib1(struct battery_priv *di)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun int val = 0;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun val |= rk818_bat_read(di, VCALIB1_REGL) << 0;
300*4882a593Smuzhiyun val |= rk818_bat_read(di, VCALIB1_REGH) << 8;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun return val;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
rk818_bat_get_ioffset(struct battery_priv * di)305*4882a593Smuzhiyun static int rk818_bat_get_ioffset(struct battery_priv *di)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun int val = 0;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun val |= rk818_bat_read(di, IOFFSET_REGL) << 0;
310*4882a593Smuzhiyun val |= rk818_bat_read(di, IOFFSET_REGH) << 8;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun DBG("<%s>. ioffset: 0x%x\n", __func__, val);
313*4882a593Smuzhiyun return val;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
rk818_bat_get_coffset(struct battery_priv * di)316*4882a593Smuzhiyun static int rk818_bat_get_coffset(struct battery_priv *di)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun int val = 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun val |= rk818_bat_read(di, CAL_OFFSET_REGL) << 0;
321*4882a593Smuzhiyun val |= rk818_bat_read(di, CAL_OFFSET_REGH) << 8;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun DBG("<%s>. coffset: 0x%x\n", __func__, val);
324*4882a593Smuzhiyun return val;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
rk818_bat_set_coffset(struct battery_priv * di,int val)327*4882a593Smuzhiyun static void rk818_bat_set_coffset(struct battery_priv *di, int val)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun u8 buf;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun buf = (val >> 0) & 0xff;
332*4882a593Smuzhiyun rk818_bat_write(di, CAL_OFFSET_REGL, buf);
333*4882a593Smuzhiyun buf = (val >> 8) & 0xff;
334*4882a593Smuzhiyun rk818_bat_write(di, CAL_OFFSET_REGH, buf);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun DBG("<%s>. set coffset: 0x%x\n", __func__, val);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
rk818_bat_init_coffset(struct battery_priv * di)339*4882a593Smuzhiyun static void rk818_bat_init_coffset(struct battery_priv *di)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun int ioffset, coffset;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun ioffset = rk818_bat_get_ioffset(di);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun di->poffset = rk818_bat_read(di, POFFSET_REG);
346*4882a593Smuzhiyun if (!di->poffset)
347*4882a593Smuzhiyun di->poffset = DEFAULT_POFFSET;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun coffset = di->poffset + ioffset;
350*4882a593Smuzhiyun if (coffset < INVALID_COFFSET_MIN || coffset > INVALID_COFFSET_MAX)
351*4882a593Smuzhiyun coffset = DEFAULT_COFFSET;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun rk818_bat_set_coffset(di, coffset);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
rk818_bat_init_voltage_kb(struct battery_priv * di)356*4882a593Smuzhiyun static void rk818_bat_init_voltage_kb(struct battery_priv *di)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun int vcalib0, vcalib1;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun vcalib0 = rk818_bat_get_vcalib0(di);
361*4882a593Smuzhiyun vcalib1 = rk818_bat_get_vcalib1(di);
362*4882a593Smuzhiyun di->voltage_k = (4200 - 3000) * 1000 / DIV(vcalib1 - vcalib0);
363*4882a593Smuzhiyun di->voltage_b = 4200 - (di->voltage_k * vcalib1) / 1000;
364*4882a593Smuzhiyun DBG("%s. vk=%d, vb=%d\n", __func__, di->voltage_k, di->voltage_b);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
rk818_bat_get_ocv_voltage(struct battery_priv * di)367*4882a593Smuzhiyun static int rk818_bat_get_ocv_voltage(struct battery_priv *di)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun int vol, val = 0;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_OCV_REGL) << 0;
372*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_OCV_REGH) << 8;
373*4882a593Smuzhiyun vol = di->voltage_k * val / 1000 + di->voltage_b;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun return vol;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
rk818_bat_get_avg_current(struct battery_priv * di)378*4882a593Smuzhiyun static int rk818_bat_get_avg_current(struct battery_priv *di)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun int val = 0;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_CUR_AVG_REGL) << 0;
383*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_CUR_AVG_REGH) << 8;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (val & 0x800)
386*4882a593Smuzhiyun val -= 4096;
387*4882a593Smuzhiyun val = val * di->res_div * 1506 / 1000;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun return val;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
rk818_bat_get_avg_voltage(struct battery_priv * di)392*4882a593Smuzhiyun static int rk818_bat_get_avg_voltage(struct battery_priv *di)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun int vol, val = 0;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_VOL_REGL) << 0;
397*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_VOL_REGH) << 8;
398*4882a593Smuzhiyun vol = di->voltage_k * val / 1000 + di->voltage_b;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return vol;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
rk818_bat_get_est_voltage(struct battery_priv * di)403*4882a593Smuzhiyun static int rk818_bat_get_est_voltage(struct battery_priv *di)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun struct charge_animation_pdata *pdata = NULL;
406*4882a593Smuzhiyun struct udevice *dev;
407*4882a593Smuzhiyun int est_vol, vol, curr;
408*4882a593Smuzhiyun int plugin, timeout = 0;
409*4882a593Smuzhiyun int low_power_voltage = 0;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun uclass_find_first_device(UCLASS_CHARGE_DISPLAY, &dev);
412*4882a593Smuzhiyun pdata = dev_get_platdata(dev);
413*4882a593Smuzhiyun low_power_voltage = pdata->low_power_voltage;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun vol = rk818_bat_get_avg_voltage(di);
416*4882a593Smuzhiyun curr = rk818_bat_get_avg_current(di);
417*4882a593Smuzhiyun plugin = rk818_bat_read(di, VB_MON_REG) & PLUG_IN_STS ? 1 : 0;
418*4882a593Smuzhiyun if (di->is_first_power_on || (!plugin && curr >= 0) || (plugin && curr <= 0)) {
419*4882a593Smuzhiyun DBG("%s: curr=%d, plugin=%d, first_on=%d\n",
420*4882a593Smuzhiyun __func__, curr, plugin, di->is_first_power_on);
421*4882a593Smuzhiyun curr = 0;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun est_vol = vol - (di->bat_res * curr / 1000);
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun while ((est_vol <= low_power_voltage) &&
426*4882a593Smuzhiyun (vol <= low_power_voltage)) {
427*4882a593Smuzhiyun mdelay(100);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun /* Update */
430*4882a593Smuzhiyun vol = rk818_bat_get_avg_voltage(di);
431*4882a593Smuzhiyun curr = rk818_bat_get_avg_current(di);
432*4882a593Smuzhiyun plugin = rk818_bat_read(di, VB_MON_REG) & PLUG_IN_STS;
433*4882a593Smuzhiyun if (di->is_first_power_on || (!plugin && curr >= 0) || (plugin && curr <= 0)) {
434*4882a593Smuzhiyun DBG("%s: while curr=%d, plugin=%d, first_on=%d\n",
435*4882a593Smuzhiyun __func__, curr, plugin, di->is_first_power_on);
436*4882a593Smuzhiyun curr = 0;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun est_vol = vol - (di->bat_res * curr / 1000);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun timeout++;
441*4882a593Smuzhiyun if (timeout >= 5)
442*4882a593Smuzhiyun break;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun return (est_vol >= low_power_voltage) ? est_vol : vol;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
rk818_bat_finish_ma(struct battery_priv * di,int fcc)448*4882a593Smuzhiyun static u8 rk818_bat_finish_ma(struct battery_priv *di, int fcc)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun u8 ma;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (di->res_div == 2)
453*4882a593Smuzhiyun ma = FINISH_100MA;
454*4882a593Smuzhiyun else if (fcc > 5000)
455*4882a593Smuzhiyun ma = FINISH_250MA;
456*4882a593Smuzhiyun else if (fcc >= 4000)
457*4882a593Smuzhiyun ma = FINISH_200MA;
458*4882a593Smuzhiyun else if (fcc >= 3000)
459*4882a593Smuzhiyun ma = FINISH_150MA;
460*4882a593Smuzhiyun else
461*4882a593Smuzhiyun ma = FINISH_100MA;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun return ma;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
rk818_bat_select_chrg_cv(struct battery_priv * di)466*4882a593Smuzhiyun static void rk818_bat_select_chrg_cv(struct battery_priv *di)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun int index, chrg_vol_sel, chrg_cur_sel, chrg_cur_input;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun chrg_vol_sel = di->dts_vol_sel;
471*4882a593Smuzhiyun chrg_cur_sel = di->dts_cur_sel;
472*4882a593Smuzhiyun chrg_cur_input = di->dts_cur_input;
473*4882a593Smuzhiyun if (di->sample_res == SAMPLE_RES_10mR) {
474*4882a593Smuzhiyun if (chrg_cur_sel > 2000)
475*4882a593Smuzhiyun chrg_cur_sel /= di->res_div;
476*4882a593Smuzhiyun else
477*4882a593Smuzhiyun chrg_cur_sel = 1000;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_VOL_SEL); index++) {
481*4882a593Smuzhiyun if (chrg_vol_sel < CHRG_VOL_SEL[index])
482*4882a593Smuzhiyun break;
483*4882a593Smuzhiyun di->chrg_vol_sel = (index << 4);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_CUR_INPUT); index++) {
487*4882a593Smuzhiyun if (chrg_cur_input < CHRG_CUR_INPUT[index])
488*4882a593Smuzhiyun break;
489*4882a593Smuzhiyun di->chrg_cur_input = (index << 0);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_CUR_SEL); index++) {
493*4882a593Smuzhiyun if (chrg_cur_sel < CHRG_CUR_SEL[index])
494*4882a593Smuzhiyun break;
495*4882a593Smuzhiyun di->chrg_cur_sel = (index << 0);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun DBG("<%s>. vol=0x%x, input=0x%x, sel=0x%x\n",
499*4882a593Smuzhiyun __func__, di->chrg_vol_sel, di->chrg_cur_input, di->chrg_cur_sel);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
rk818_bat_init_chrg_config(struct battery_priv * di)502*4882a593Smuzhiyun static void rk818_bat_init_chrg_config(struct battery_priv *di)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun u8 chrg_ctrl1, usb_ctrl, chrg_ctrl2, chrg_ctrl3;
505*4882a593Smuzhiyun u8 sup_sts, ggcon, thermal, finish_ma;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun rk818_bat_select_chrg_cv(di);
508*4882a593Smuzhiyun finish_ma = rk818_bat_finish_ma(di, di->fcc);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun ggcon = rk818_bat_read(di, GGCON_REG);
511*4882a593Smuzhiyun sup_sts = rk818_bat_read(di, SUP_STS_REG);
512*4882a593Smuzhiyun usb_ctrl = rk818_bat_read(di, USB_CTRL_REG);
513*4882a593Smuzhiyun thermal = rk818_bat_read(di, THERMAL_REG);
514*4882a593Smuzhiyun chrg_ctrl2 = rk818_bat_read(di, CHRG_CTRL_REG2);
515*4882a593Smuzhiyun chrg_ctrl3 = rk818_bat_read(di, CHRG_CTRL_REG3);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* set charge current and voltage */
518*4882a593Smuzhiyun usb_ctrl &= ~INPUT_CUR_MSK;
519*4882a593Smuzhiyun usb_ctrl |= di->chrg_cur_input;
520*4882a593Smuzhiyun chrg_ctrl1 = (CHRG_EN | di->chrg_vol_sel | di->chrg_cur_sel);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* digital signal and finish current*/
523*4882a593Smuzhiyun chrg_ctrl3 &= ~CHRG_TERM_SIG_MSK;
524*4882a593Smuzhiyun chrg_ctrl3 |= CHRG_TERM_ANA_SIGNAL;
525*4882a593Smuzhiyun chrg_ctrl2 &= ~FINISH_CUR_MSK;
526*4882a593Smuzhiyun chrg_ctrl2 |= finish_ma;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun /* cccv mode */
529*4882a593Smuzhiyun chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /* enable voltage limit and enable input current limit */
532*4882a593Smuzhiyun sup_sts &= ~USB_VLIMIT_EN;
533*4882a593Smuzhiyun sup_sts |= USB_CLIMIT_EN;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun /* set feedback temperature */
536*4882a593Smuzhiyun usb_ctrl |= CHRG_CT_EN;
537*4882a593Smuzhiyun thermal &= ~FB_TEMP_MSK;
538*4882a593Smuzhiyun thermal |= TEMP_105C;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /* adc current mode */
541*4882a593Smuzhiyun ggcon |= ADC_CUR_MODE;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun rk818_bat_write(di, GGCON_REG, ggcon);
544*4882a593Smuzhiyun rk818_bat_write(di, SUP_STS_REG, sup_sts);
545*4882a593Smuzhiyun rk818_bat_write(di, USB_CTRL_REG, usb_ctrl);
546*4882a593Smuzhiyun rk818_bat_write(di, THERMAL_REG, thermal);
547*4882a593Smuzhiyun rk818_bat_write(di, CHRG_CTRL_REG1, chrg_ctrl1);
548*4882a593Smuzhiyun rk818_bat_write(di, CHRG_CTRL_REG2, chrg_ctrl2);
549*4882a593Smuzhiyun rk818_bat_write(di, CHRG_CTRL_REG3, chrg_ctrl3);
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
interpolate(int value,u32 * table,int size)552*4882a593Smuzhiyun static u32 interpolate(int value, u32 *table, int size)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun uint8_t i;
555*4882a593Smuzhiyun uint16_t d;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun for (i = 0; i < size; i++) {
558*4882a593Smuzhiyun if (value < table[i])
559*4882a593Smuzhiyun break;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun if ((i > 0) && (i < size)) {
563*4882a593Smuzhiyun d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1));
564*4882a593Smuzhiyun d /= table[i] - table[i - 1];
565*4882a593Smuzhiyun d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1));
566*4882a593Smuzhiyun } else {
567*4882a593Smuzhiyun d = i * ((MAX_INTERPOLATE + size / 2) / size);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (d > 1000)
571*4882a593Smuzhiyun d = 1000;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun return d;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun /* returns (a * b) / c */
ab_div_c(u32 a,u32 b,u32 c)577*4882a593Smuzhiyun static int32_t ab_div_c(u32 a, u32 b, u32 c)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun bool sign;
580*4882a593Smuzhiyun u32 ans = MAX_INT;
581*4882a593Smuzhiyun int32_t tmp;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun sign = ((((a ^ b) ^ c) & 0x80000000) != 0);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (c != 0) {
586*4882a593Smuzhiyun if (sign)
587*4882a593Smuzhiyun c = -c;
588*4882a593Smuzhiyun tmp = ((int32_t)a * b + (c >> 1)) / c;
589*4882a593Smuzhiyun if (tmp < MAX_INT)
590*4882a593Smuzhiyun ans = tmp;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (sign)
594*4882a593Smuzhiyun ans = -ans;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun return ans;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
rk818_bat_vol_to_cap(struct battery_priv * di,int voltage)599*4882a593Smuzhiyun static int rk818_bat_vol_to_cap(struct battery_priv *di, int voltage)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun u32 *ocv_table, tmp;
602*4882a593Smuzhiyun int ocv_size, ocv_cap;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun ocv_table = di->ocv_table;
605*4882a593Smuzhiyun ocv_size = di->ocv_size;
606*4882a593Smuzhiyun tmp = interpolate(voltage, ocv_table, ocv_size);
607*4882a593Smuzhiyun ocv_cap = ab_div_c(tmp, di->fcc, MAX_INTERPOLATE);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun return ocv_cap;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
rk818_bat_vol_to_soc(struct battery_priv * di,int voltage)612*4882a593Smuzhiyun static int rk818_bat_vol_to_soc(struct battery_priv *di, int voltage)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun u32 *ocv_table, tmp;
615*4882a593Smuzhiyun int ocv_size, ocv_soc;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun ocv_table = di->ocv_table;
618*4882a593Smuzhiyun ocv_size = di->ocv_size;
619*4882a593Smuzhiyun tmp = interpolate(voltage, ocv_table, ocv_size);
620*4882a593Smuzhiyun ocv_soc = ab_div_c(tmp, MAX_PERCENTAGE, MAX_INTERPOLATE);
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun return ocv_soc;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
rk818_bat_get_prev_cap(struct battery_priv * di)625*4882a593Smuzhiyun static int rk818_bat_get_prev_cap(struct battery_priv *di)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun int val = 0;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun val |= rk818_bat_read(di, REMAIN_CAP_REG3) << 24;
630*4882a593Smuzhiyun val |= rk818_bat_read(di, REMAIN_CAP_REG2) << 16;
631*4882a593Smuzhiyun val |= rk818_bat_read(di, REMAIN_CAP_REG1) << 8;
632*4882a593Smuzhiyun val |= rk818_bat_read(di, REMAIN_CAP_REG0) << 0;
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun return val;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
rk818_bat_save_fcc(struct battery_priv * di,u32 cap)637*4882a593Smuzhiyun static void rk818_bat_save_fcc(struct battery_priv *di, u32 cap)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun u8 buf;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
642*4882a593Smuzhiyun rk818_bat_write(di, NEW_FCC_REG3, buf);
643*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
644*4882a593Smuzhiyun rk818_bat_write(di, NEW_FCC_REG2, buf);
645*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
646*4882a593Smuzhiyun rk818_bat_write(di, NEW_FCC_REG1, buf);
647*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
648*4882a593Smuzhiyun rk818_bat_write(di, NEW_FCC_REG0, buf);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
rk818_bat_get_fcc(struct battery_priv * di)651*4882a593Smuzhiyun static int rk818_bat_get_fcc(struct battery_priv *di)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun int val = 0;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun val |= rk818_bat_read(di, NEW_FCC_REG3) << 24;
656*4882a593Smuzhiyun val |= rk818_bat_read(di, NEW_FCC_REG2) << 16;
657*4882a593Smuzhiyun val |= rk818_bat_read(di, NEW_FCC_REG1) << 8;
658*4882a593Smuzhiyun val |= rk818_bat_read(di, NEW_FCC_REG0) << 0;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if (val < MIN_FCC)
661*4882a593Smuzhiyun val = di->design_cap;
662*4882a593Smuzhiyun else if (val > di->qmax)
663*4882a593Smuzhiyun val = di->qmax;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun return val;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
rk818_bat_get_pwroff_min(struct battery_priv * di)668*4882a593Smuzhiyun static int rk818_bat_get_pwroff_min(struct battery_priv *di)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun u8 cur, last;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun cur = rk818_bat_read(di, NON_ACT_TIMER_CNT_REG);
673*4882a593Smuzhiyun last = rk818_bat_read(di, NON_ACT_TIMER_CNT_SAVE_REG);
674*4882a593Smuzhiyun rk818_bat_write(di, NON_ACT_TIMER_CNT_SAVE_REG, cur);
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun return (cur != last) ? cur : 0;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
rk818_bat_get_coulomb_cap(struct battery_priv * di)679*4882a593Smuzhiyun static int rk818_bat_get_coulomb_cap(struct battery_priv *di)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun int val = 0;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun val |= rk818_bat_read(di, GASCNT_REG3) << 24;
684*4882a593Smuzhiyun val |= rk818_bat_read(di, GASCNT_REG2) << 16;
685*4882a593Smuzhiyun val |= rk818_bat_read(di, GASCNT_REG1) << 8;
686*4882a593Smuzhiyun val |= rk818_bat_read(di, GASCNT_REG0) << 0;
687*4882a593Smuzhiyun val /= 2390;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun return val * di->res_div;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
rk818_bat_save_cap(struct battery_priv * di,int cap)692*4882a593Smuzhiyun static void rk818_bat_save_cap(struct battery_priv *di, int cap)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun u8 buf;
695*4882a593Smuzhiyun static int old_cap;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun if (old_cap == cap)
698*4882a593Smuzhiyun return;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun if (cap >= di->qmax)
701*4882a593Smuzhiyun cap = di->qmax;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun old_cap = cap;
704*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
705*4882a593Smuzhiyun rk818_bat_write(di, REMAIN_CAP_REG3, buf);
706*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
707*4882a593Smuzhiyun rk818_bat_write(di, REMAIN_CAP_REG2, buf);
708*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
709*4882a593Smuzhiyun rk818_bat_write(di, REMAIN_CAP_REG1, buf);
710*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
711*4882a593Smuzhiyun rk818_bat_write(di, REMAIN_CAP_REG0, buf);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
rk818_bat_init_capacity(struct battery_priv * di,u32 capacity)714*4882a593Smuzhiyun static void rk818_bat_init_capacity(struct battery_priv *di, u32 capacity)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun u8 buf;
717*4882a593Smuzhiyun u32 cap;
718*4882a593Smuzhiyun int delta;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun delta = capacity - di->remain_cap;
721*4882a593Smuzhiyun if (!delta)
722*4882a593Smuzhiyun return;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun cap = capacity * 2390 / di->res_div;
725*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
726*4882a593Smuzhiyun rk818_bat_write(di, GASCNT_CAL_REG3, buf);
727*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
728*4882a593Smuzhiyun rk818_bat_write(di, GASCNT_CAL_REG2, buf);
729*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
730*4882a593Smuzhiyun rk818_bat_write(di, GASCNT_CAL_REG1, buf);
731*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
732*4882a593Smuzhiyun rk818_bat_write(di, GASCNT_CAL_REG0, buf);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun di->remain_cap = rk818_bat_get_coulomb_cap(di);
735*4882a593Smuzhiyun di->rsoc = rk818_bat_get_rsoc(di);
736*4882a593Smuzhiyun rk818_bat_save_cap(di, di->remain_cap);
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun
is_rk818_bat_ocv_valid(struct battery_priv * di)739*4882a593Smuzhiyun static bool is_rk818_bat_ocv_valid(struct battery_priv *di)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun return di->pwroff_min >= 30 ? true : false;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
rk818_bat_get_usb_state(struct battery_priv * di)744*4882a593Smuzhiyun static int rk818_bat_get_usb_state(struct battery_priv *di)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun int charger_type;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun switch (rk818_bat_dwc_otg_check_dpdm()) {
749*4882a593Smuzhiyun case 0:
750*4882a593Smuzhiyun if ((rk818_bat_read(di, VB_MON_REG) & PLUG_IN_STS) != 0)
751*4882a593Smuzhiyun charger_type = DC_CHARGER;
752*4882a593Smuzhiyun else
753*4882a593Smuzhiyun charger_type = NO_CHARGER;
754*4882a593Smuzhiyun break;
755*4882a593Smuzhiyun case 1:
756*4882a593Smuzhiyun case 3:
757*4882a593Smuzhiyun charger_type = USB_CHARGER;
758*4882a593Smuzhiyun break;
759*4882a593Smuzhiyun case 2:
760*4882a593Smuzhiyun case 4:
761*4882a593Smuzhiyun charger_type = AC_CHARGER;
762*4882a593Smuzhiyun break;
763*4882a593Smuzhiyun default:
764*4882a593Smuzhiyun charger_type = NO_CHARGER;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun return charger_type;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
rk818_bat_clr_initialized_state(struct battery_priv * di)770*4882a593Smuzhiyun static void rk818_bat_clr_initialized_state(struct battery_priv *di)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun u8 val;
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun val = rk818_bat_read(di, MISC_MARK_REG);
775*4882a593Smuzhiyun val &= ~FG_INIT;
776*4882a593Smuzhiyun rk818_bat_write(di, MISC_MARK_REG, val);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
rk818_bat_is_initialized(struct battery_priv * di)779*4882a593Smuzhiyun static bool rk818_bat_is_initialized(struct battery_priv *di)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun return (rk818_bat_read(di, MISC_MARK_REG) & FG_INIT) ? true : false;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun
rk818_bat_set_initialized_state(struct battery_priv * di)784*4882a593Smuzhiyun static void rk818_bat_set_initialized_state(struct battery_priv *di)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun u8 val;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun val = rk818_bat_read(di, MISC_MARK_REG);
789*4882a593Smuzhiyun if (rk818_bat_get_usb_state(di) != NO_CHARGER) {
790*4882a593Smuzhiyun val |= FG_INIT;
791*4882a593Smuzhiyun rk818_bat_write(di, MISC_MARK_REG, val);
792*4882a593Smuzhiyun BAT_INFO("initialized... estv=%d, ch=%d\n",
793*4882a593Smuzhiyun rk818_bat_get_est_voltage(di),
794*4882a593Smuzhiyun rk818_bat_get_usb_state(di));
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun
rk818_bat_save_dsoc(struct battery_priv * di,u8 save_soc)798*4882a593Smuzhiyun static void rk818_bat_save_dsoc(struct battery_priv *di, u8 save_soc)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun static int old_soc = -1;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun if (old_soc != save_soc) {
803*4882a593Smuzhiyun old_soc = save_soc;
804*4882a593Smuzhiyun rk818_bat_write(di, SOC_REG, save_soc);
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
rk818_bat_first_pwron(struct battery_priv * di)808*4882a593Smuzhiyun static void rk818_bat_first_pwron(struct battery_priv *di)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun int ocv_vol, vol, curr;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun rk818_bat_save_fcc(di, di->design_cap);
813*4882a593Smuzhiyun ocv_vol = rk818_bat_get_ocv_voltage(di);
814*4882a593Smuzhiyun curr = rk818_bat_get_avg_current(di);
815*4882a593Smuzhiyun di->fcc = rk818_bat_get_fcc(di);
816*4882a593Smuzhiyun di->nac = rk818_bat_vol_to_cap(di, ocv_vol);
817*4882a593Smuzhiyun di->rsoc = rk818_bat_vol_to_soc(di, ocv_vol);
818*4882a593Smuzhiyun di->dsoc = di->rsoc;
819*4882a593Smuzhiyun vol = rk818_bat_get_avg_voltage(di);
820*4882a593Smuzhiyun if (ocv_vol < vol) {
821*4882a593Smuzhiyun BAT_INFO("%s: ocv voltage %d\n", __func__, ocv_vol);
822*4882a593Smuzhiyun ocv_vol = vol;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun rk818_bat_save_dsoc(di, di->dsoc);
825*4882a593Smuzhiyun rk818_bat_init_capacity(di, di->nac);
826*4882a593Smuzhiyun rk818_bat_set_initialized_state(di);
827*4882a593Smuzhiyun BAT_INFO("first power on: soc=%d, Vavg=%d, Vocv=%d, c=%d, ch=%d, fcc=%d\n",
828*4882a593Smuzhiyun di->dsoc, vol, ocv_vol, curr, rk818_bat_get_usb_state(di), di->fcc);
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
rk818_bat_get_halt_cnt(struct battery_priv * di)831*4882a593Smuzhiyun static u8 rk818_bat_get_halt_cnt(struct battery_priv *di)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun return rk818_bat_read(di, HALT_CNT_REG);
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
rk818_bat_inc_halt_cnt(struct battery_priv * di)836*4882a593Smuzhiyun static void rk818_bat_inc_halt_cnt(struct battery_priv *di)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun u8 cnt;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun cnt = rk818_bat_read(di, HALT_CNT_REG);
841*4882a593Smuzhiyun rk818_bat_write(di, HALT_CNT_REG, ++cnt);
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
is_rk818_bat_last_halt(struct battery_priv * di)844*4882a593Smuzhiyun static bool is_rk818_bat_last_halt(struct battery_priv *di)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun int pre_cap = rk818_bat_get_prev_cap(di);
847*4882a593Smuzhiyun int now_cap = rk818_bat_get_coulomb_cap(di);
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun /* over 5%: system halt last time */
850*4882a593Smuzhiyun if (abs(now_cap - pre_cap) > (di->fcc / 20)) {
851*4882a593Smuzhiyun rk818_bat_inc_halt_cnt(di);
852*4882a593Smuzhiyun return true;
853*4882a593Smuzhiyun } else {
854*4882a593Smuzhiyun return false;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
rk818_bat_not_first_pwron(struct battery_priv * di)858*4882a593Smuzhiyun static void rk818_bat_not_first_pwron(struct battery_priv *di)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun int pre_soc, pre_cap, ocv_cap = 0, ocv_soc = 0, ocv_vol, now_cap;
861*4882a593Smuzhiyun int voltage;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun di->fcc = rk818_bat_get_fcc(di);
864*4882a593Smuzhiyun pre_soc = rk818_bat_get_dsoc(di);
865*4882a593Smuzhiyun pre_cap = rk818_bat_get_prev_cap(di);
866*4882a593Smuzhiyun now_cap = rk818_bat_get_coulomb_cap(di);
867*4882a593Smuzhiyun voltage = rk818_bat_get_est_voltage(di);
868*4882a593Smuzhiyun di->pwr_dsoc = pre_soc;
869*4882a593Smuzhiyun di->pwr_rsoc = (now_cap + di->fcc / 200) * 100 / DIV(di->fcc);
870*4882a593Smuzhiyun di->is_halt = is_rk818_bat_last_halt(di);
871*4882a593Smuzhiyun di->halt_cnt = rk818_bat_get_halt_cnt(di);
872*4882a593Smuzhiyun di->is_ocv_calib = is_rk818_bat_ocv_valid(di);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun if (di->is_halt) {
875*4882a593Smuzhiyun BAT_INFO("system halt last time... cap: pre=%d, now=%d\n",
876*4882a593Smuzhiyun pre_cap, now_cap);
877*4882a593Smuzhiyun if (now_cap < 0)
878*4882a593Smuzhiyun now_cap = 0;
879*4882a593Smuzhiyun rk818_bat_init_capacity(di, now_cap);
880*4882a593Smuzhiyun pre_cap = di->remain_cap;
881*4882a593Smuzhiyun pre_soc = di->rsoc;
882*4882a593Smuzhiyun goto finish;
883*4882a593Smuzhiyun } else if (di->is_ocv_calib) {
884*4882a593Smuzhiyun ocv_vol = rk818_bat_get_ocv_voltage(di);
885*4882a593Smuzhiyun ocv_soc = rk818_bat_vol_to_soc(di, ocv_vol);
886*4882a593Smuzhiyun ocv_cap = rk818_bat_vol_to_cap(di, ocv_vol);
887*4882a593Smuzhiyun pre_cap = ocv_cap;
888*4882a593Smuzhiyun BAT_INFO("do ocv calib.. rsoc=%d\n", ocv_soc);
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun if (abs(ocv_soc - pre_soc) >= di->max_soc_offset) {
891*4882a593Smuzhiyun BAT_INFO("trigger max soc offset, soc: %d -> %d\n",
892*4882a593Smuzhiyun pre_soc, ocv_soc);
893*4882a593Smuzhiyun pre_soc = ocv_soc;
894*4882a593Smuzhiyun di->is_max_soc_offset = true;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun BAT_INFO("OCV calib: cap=%d, rsoc=%d\n", ocv_cap, ocv_soc);
897*4882a593Smuzhiyun } else if ((pre_soc == 0) && (voltage >= ZERO_MIN_VOLTAGE)) {
898*4882a593Smuzhiyun if (now_cap < 0)
899*4882a593Smuzhiyun now_cap = 0;
900*4882a593Smuzhiyun rk818_bat_init_capacity(di, now_cap);
901*4882a593Smuzhiyun pre_cap = di->remain_cap;
902*4882a593Smuzhiyun pre_soc = di->rsoc;
903*4882a593Smuzhiyun BAT_INFO("zero calib: voltage=%d\n", voltage);
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun finish:
906*4882a593Smuzhiyun di->dsoc = pre_soc;
907*4882a593Smuzhiyun di->nac = pre_cap;
908*4882a593Smuzhiyun rk818_bat_init_capacity(di, di->nac);
909*4882a593Smuzhiyun rk818_bat_save_dsoc(di, di->dsoc);
910*4882a593Smuzhiyun rk818_bat_set_initialized_state(di);
911*4882a593Smuzhiyun BAT_INFO("dl=%d rl=%d cap=%d m=%d v=%d ov=%d c=%d pl=%d ch=%d fcc=%d, Ver=%s\n",
912*4882a593Smuzhiyun di->dsoc, di->rsoc, di->remain_cap, di->pwroff_min,
913*4882a593Smuzhiyun rk818_bat_get_avg_voltage(di), rk818_bat_get_ocv_voltage(di),
914*4882a593Smuzhiyun rk818_bat_get_avg_current(di), rk818_bat_get_dsoc(di),
915*4882a593Smuzhiyun rk818_bat_get_usb_state(di), di->fcc, DRIVER_VERSION
916*4882a593Smuzhiyun );
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
is_rk818_bat_first_poweron(struct battery_priv * di)919*4882a593Smuzhiyun static bool is_rk818_bat_first_poweron(struct battery_priv *di)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun u8 buf;
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun buf = rk818_bat_read(di, GGSTS_REG);
924*4882a593Smuzhiyun if (buf & BAT_CON) {
925*4882a593Smuzhiyun buf &= ~BAT_CON;
926*4882a593Smuzhiyun rk818_bat_write(di, GGSTS_REG, buf);
927*4882a593Smuzhiyun return true;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun return false;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
rk818_bat_ocv_sw_reset(struct battery_priv * di)933*4882a593Smuzhiyun static bool rk818_bat_ocv_sw_reset(struct battery_priv *di)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun u8 buf;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun buf = rk818_bat_read(di, MISC_MARK_REG);
938*4882a593Smuzhiyun if (((buf & FG_RESET_LATE) && di->pwroff_min >= 30) ||
939*4882a593Smuzhiyun (buf & FG_RESET_NOW)) {
940*4882a593Smuzhiyun buf &= ~FG_RESET_LATE;
941*4882a593Smuzhiyun buf &= ~FG_RESET_NOW;
942*4882a593Smuzhiyun rk818_bat_write(di, MISC_MARK_REG, buf);
943*4882a593Smuzhiyun BAT_INFO("manual reset fuel gauge\n");
944*4882a593Smuzhiyun return true;
945*4882a593Smuzhiyun } else {
946*4882a593Smuzhiyun return false;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
rk818_bat_init_rsoc(struct battery_priv * di)950*4882a593Smuzhiyun static void rk818_bat_init_rsoc(struct battery_priv *di)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun int charger, voltage, initialize = 0;
953*4882a593Smuzhiyun struct charge_animation_pdata *pdata;
954*4882a593Smuzhiyun struct udevice *dev;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun uclass_find_first_device(UCLASS_CHARGE_DISPLAY, &dev);
957*4882a593Smuzhiyun pdata = dev_get_platdata(dev);
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun charger = rk818_bat_get_usb_state(di);
960*4882a593Smuzhiyun voltage = rk818_bat_get_est_voltage(di);
961*4882a593Smuzhiyun di->is_first_power_on = is_rk818_bat_first_poweron(di);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun /*
964*4882a593Smuzhiyun * Do rsoc initialization only when:
965*4882a593Smuzhiyun *
966*4882a593Smuzhiyun * 1. first power on;
967*4882a593Smuzhiyun * 2. charger online + voltage lower than low_power_voltage;
968*4882a593Smuzhiyun * 3. charger online + uboot_charge enabled.
969*4882a593Smuzhiyun * 4. dsoc is 0 but voltage high, obvious wrong.
970*4882a593Smuzhiyun */
971*4882a593Smuzhiyun if (di->is_first_power_on) {
972*4882a593Smuzhiyun initialize = 1;
973*4882a593Smuzhiyun } else if ((di->dsoc == 0) && (voltage >= ZERO_MIN_VOLTAGE)) {
974*4882a593Smuzhiyun initialize = 1;
975*4882a593Smuzhiyun } else if (charger != NO_CHARGER) {
976*4882a593Smuzhiyun if (voltage < pdata->low_power_voltage + 50)
977*4882a593Smuzhiyun initialize = 1;
978*4882a593Smuzhiyun else if (pdata->uboot_charge)
979*4882a593Smuzhiyun initialize = 1;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun if (!initialize)
983*4882a593Smuzhiyun return;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun di->pwroff_min = rk818_bat_get_pwroff_min(di);
986*4882a593Smuzhiyun di->is_sw_reset = rk818_bat_ocv_sw_reset(di);
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun if (di->is_first_power_on || di->is_sw_reset)
989*4882a593Smuzhiyun rk818_bat_first_pwron(di);
990*4882a593Smuzhiyun else
991*4882a593Smuzhiyun rk818_bat_not_first_pwron(di);
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun
rk818_bat_calc_linek(struct battery_priv * di)994*4882a593Smuzhiyun static int rk818_bat_calc_linek(struct battery_priv *di)
995*4882a593Smuzhiyun {
996*4882a593Smuzhiyun int linek, diff, delta;
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun di->calc_dsoc = di->dsoc;
999*4882a593Smuzhiyun di->calc_rsoc = di->rsoc;
1000*4882a593Smuzhiyun di->sm_old_cap = di->remain_cap;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun delta = abs(di->dsoc - di->rsoc);
1003*4882a593Smuzhiyun diff = delta * 3;
1004*4882a593Smuzhiyun di->sm_meet_soc = (di->dsoc >= di->rsoc) ?
1005*4882a593Smuzhiyun (di->dsoc + diff) : (di->rsoc + diff);
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun if (di->dsoc < di->rsoc)
1008*4882a593Smuzhiyun linek = 1000 * (delta + diff) / DIV(diff);
1009*4882a593Smuzhiyun else if (di->dsoc > di->rsoc)
1010*4882a593Smuzhiyun linek = 1000 * diff / DIV(delta + diff);
1011*4882a593Smuzhiyun else
1012*4882a593Smuzhiyun linek = 1000;
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun DBG("<%s>. meet=%d, diff=%d, link=%d, calc: dsoc=%d, rsoc=%d\n",
1017*4882a593Smuzhiyun __func__, di->sm_meet_soc, diff, linek,
1018*4882a593Smuzhiyun di->calc_dsoc, di->calc_rsoc);
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun return linek;
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
rk818_bat_init_ts1(struct battery_priv * di)1023*4882a593Smuzhiyun static void rk818_bat_init_ts1(struct battery_priv *di)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun u8 buf;
1026*4882a593Smuzhiyun u32 *ntc_table = di->ntc_table;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun if (!di->ntc_size)
1029*4882a593Smuzhiyun return;
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* select uA */
1032*4882a593Smuzhiyun buf = rk818_bat_read(di, TS_CTRL_REG);
1033*4882a593Smuzhiyun buf &= ~ADC_CUR_MSK;
1034*4882a593Smuzhiyun /* chose suitable UA for temperature detect */
1035*4882a593Smuzhiyun if (ntc_table[0] < NTC_80UA_MAX_MEASURE) {
1036*4882a593Smuzhiyun di->ntc_factor = NTC_CALC_FACTOR_80UA;
1037*4882a593Smuzhiyun di->ntc_uA = 80;
1038*4882a593Smuzhiyun buf |= ADC_CUR_80UA;
1039*4882a593Smuzhiyun } else if (ntc_table[0] < NTC_60UA_MAX_MEASURE) {
1040*4882a593Smuzhiyun di->ntc_factor = NTC_CALC_FACTOR_60UA;
1041*4882a593Smuzhiyun di->ntc_uA = 60;
1042*4882a593Smuzhiyun buf |= ADC_CUR_60UA;
1043*4882a593Smuzhiyun } else if (ntc_table[0] < NTC_40UA_MAX_MEASURE) {
1044*4882a593Smuzhiyun di->ntc_factor = NTC_CALC_FACTOR_40UA;
1045*4882a593Smuzhiyun di->ntc_uA = 40;
1046*4882a593Smuzhiyun buf |= ADC_CUR_40UA;
1047*4882a593Smuzhiyun } else {
1048*4882a593Smuzhiyun di->ntc_factor = NTC_CALC_FACTOR_20UA;
1049*4882a593Smuzhiyun di->ntc_uA = 20;
1050*4882a593Smuzhiyun buf |= ADC_CUR_20UA;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun rk818_bat_write(di, TS_CTRL_REG, buf);
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun /* ADC_TS1_EN */
1055*4882a593Smuzhiyun buf = rk818_bat_read(di, ADC_CTRL_REG);
1056*4882a593Smuzhiyun buf |= ADC_TS1_EN;
1057*4882a593Smuzhiyun rk818_bat_write(di, ADC_CTRL_REG, buf);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
rk818_bat_init_ts2(struct battery_priv * di)1060*4882a593Smuzhiyun static void rk818_bat_init_ts2(struct battery_priv *di)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun u8 buf;
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun if (!di->ts2_vol_multi)
1065*4882a593Smuzhiyun return;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun /* TS2 adc mode */
1068*4882a593Smuzhiyun buf = rk818_bat_read(di, TS_CTRL_REG);
1069*4882a593Smuzhiyun buf |= TS2_ADC_MODE;
1070*4882a593Smuzhiyun rk818_bat_write(di, TS_CTRL_REG, buf);
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun /* TS2 adc enable */
1073*4882a593Smuzhiyun buf = rk818_bat_read(di, ADC_CTRL_REG);
1074*4882a593Smuzhiyun buf |= ADC_TS2_EN;
1075*4882a593Smuzhiyun rk818_bat_write(di, ADC_CTRL_REG, buf);
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
rk818_fg_init(struct battery_priv * di)1078*4882a593Smuzhiyun static int rk818_fg_init(struct battery_priv *di)
1079*4882a593Smuzhiyun {
1080*4882a593Smuzhiyun int cap;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun rk818_bat_enable_gauge(di);
1083*4882a593Smuzhiyun rk818_bat_init_voltage_kb(di);
1084*4882a593Smuzhiyun rk818_bat_init_coffset(di);
1085*4882a593Smuzhiyun rk818_bat_init_ts1(di);
1086*4882a593Smuzhiyun rk818_bat_init_ts2(di);
1087*4882a593Smuzhiyun rk818_bat_clr_initialized_state(di);
1088*4882a593Smuzhiyun cap = rk818_bat_get_coulomb_cap(di);
1089*4882a593Smuzhiyun di->dsoc = rk818_bat_get_dsoc(di);
1090*4882a593Smuzhiyun di->rsoc = (cap + di->fcc / 200) * 100 / DIV(di->fcc);
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun /* dsoc and rsoc maybe initialized here */
1093*4882a593Smuzhiyun rk818_bat_init_rsoc(di);
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun rk818_bat_init_chrg_config(di);
1096*4882a593Smuzhiyun di->voltage_avg = rk818_bat_get_avg_voltage(di);
1097*4882a593Smuzhiyun di->voltage_ocv = rk818_bat_get_ocv_voltage(di);
1098*4882a593Smuzhiyun di->current_avg = rk818_bat_get_avg_current(di);
1099*4882a593Smuzhiyun di->sm_linek = rk818_bat_calc_linek(di);
1100*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1101*4882a593Smuzhiyun di->term_sig_base = get_timer(0);
1102*4882a593Smuzhiyun di->pwr_vol = di->voltage_avg;
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun DBG("%s: dsoc=%d, rsoc=%d, v=%d, ov=%d, c=%d, estv=%d\n",
1105*4882a593Smuzhiyun __func__, di->dsoc, di->rsoc, di->voltage_avg, di->voltage_ocv,
1106*4882a593Smuzhiyun di->current_avg, rk818_bat_get_est_voltage(di));
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun return 0;
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun
is_rk818_bat_exist(struct battery_priv * di)1111*4882a593Smuzhiyun static bool is_rk818_bat_exist(struct battery_priv *di)
1112*4882a593Smuzhiyun {
1113*4882a593Smuzhiyun return (rk818_bat_read(di, SUP_STS_REG) & BAT_EXS) ? true : false;
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
rk818_bat_set_current(struct battery_priv * di,int input_current)1116*4882a593Smuzhiyun static void rk818_bat_set_current(struct battery_priv *di, int input_current)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun u8 usb_ctrl;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun usb_ctrl = rk818_bat_read(di, USB_CTRL_REG);
1121*4882a593Smuzhiyun usb_ctrl &= ~INPUT_CUR_MSK;
1122*4882a593Smuzhiyun usb_ctrl |= (input_current);
1123*4882a593Smuzhiyun rk818_bat_write(di, USB_CTRL_REG, usb_ctrl);
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun
rk818_bat_get_ts2_voltage(struct battery_priv * di)1126*4882a593Smuzhiyun static int rk818_bat_get_ts2_voltage(struct battery_priv *di)
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun u32 val = 0;
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun val |= rk818_bat_read(di, RK818_TS2_ADC_REGL) << 0;
1131*4882a593Smuzhiyun val |= rk818_bat_read(di, RK818_TS2_ADC_REGH) << 8;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* refer voltage 2.2V, 12bit adc accuracy */
1134*4882a593Smuzhiyun val = val * 2200 * di->ts2_vol_multi / 4095;
1135*4882a593Smuzhiyun DBG("<%s>. ts2 voltage=%d\n", __func__, val);
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun return val;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
rk818_bat_ts2_update_current(struct battery_priv * di)1140*4882a593Smuzhiyun static void rk818_bat_ts2_update_current(struct battery_priv *di)
1141*4882a593Smuzhiyun {
1142*4882a593Smuzhiyun int ts2_vol, input_current, invalid_cnt = 0, confirm_cnt = 0;
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun rk818_bat_set_current(di, ILIM_450MA);
1145*4882a593Smuzhiyun input_current = ILIM_850MA;
1146*4882a593Smuzhiyun while (input_current < di->chrg_cur_input) {
1147*4882a593Smuzhiyun mdelay(100);
1148*4882a593Smuzhiyun ts2_vol = rk818_bat_get_ts2_voltage(di);
1149*4882a593Smuzhiyun DBG("******** ts2 vol=%d\n", ts2_vol);
1150*4882a593Smuzhiyun /* filter invalid voltage */
1151*4882a593Smuzhiyun if (ts2_vol <= TS2_VALID_VOL) {
1152*4882a593Smuzhiyun invalid_cnt++;
1153*4882a593Smuzhiyun DBG("%s: invalid ts2 voltage: %d\n, cnt=%d",
1154*4882a593Smuzhiyun __func__, ts2_vol, invalid_cnt);
1155*4882a593Smuzhiyun if (invalid_cnt < TS2_CHECK_CNT)
1156*4882a593Smuzhiyun continue;
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun /* if fail, set max input current as default */
1159*4882a593Smuzhiyun input_current = di->chrg_cur_input;
1160*4882a593Smuzhiyun rk818_bat_set_current(di, input_current);
1161*4882a593Smuzhiyun break;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun /* update input current */
1165*4882a593Smuzhiyun if (ts2_vol >= TS2_THRESHOLD_VOL) {
1166*4882a593Smuzhiyun /* update input current */
1167*4882a593Smuzhiyun input_current++;
1168*4882a593Smuzhiyun rk818_bat_set_current(di, input_current);
1169*4882a593Smuzhiyun DBG("********* input=%d\n",
1170*4882a593Smuzhiyun CHRG_CUR_INPUT[input_current & 0x0f]);
1171*4882a593Smuzhiyun } else {
1172*4882a593Smuzhiyun /* confirm lower threshold voltage */
1173*4882a593Smuzhiyun confirm_cnt++;
1174*4882a593Smuzhiyun if (confirm_cnt < TS2_CHECK_CNT) {
1175*4882a593Smuzhiyun DBG("%s: confirm ts2 voltage: %d\n, cnt=%d",
1176*4882a593Smuzhiyun __func__, ts2_vol, confirm_cnt);
1177*4882a593Smuzhiyun continue;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun /* trigger threshold, so roll back 1 step */
1181*4882a593Smuzhiyun input_current--;
1182*4882a593Smuzhiyun if (input_current == ILIM_80MA ||
1183*4882a593Smuzhiyun input_current < 0)
1184*4882a593Smuzhiyun input_current = ILIM_450MA;
1185*4882a593Smuzhiyun rk818_bat_set_current(di, input_current);
1186*4882a593Smuzhiyun break;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun BAT_INFO("DC_CHARGER charge_cur_input=%d\n",
1191*4882a593Smuzhiyun CHRG_CUR_INPUT[input_current]);
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
rk818_bat_charger_setting(struct battery_priv * di,int charger)1194*4882a593Smuzhiyun static void rk818_bat_charger_setting(struct battery_priv *di, int charger)
1195*4882a593Smuzhiyun {
1196*4882a593Smuzhiyun static u8 old_charger = UNDEF_CHARGER;
1197*4882a593Smuzhiyun struct charge_animation_pdata *pdata;
1198*4882a593Smuzhiyun struct udevice *dev;
1199*4882a593Smuzhiyun int low_power_voltage = 0;
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun uclass_find_first_device(UCLASS_CHARGE_DISPLAY, &dev);
1202*4882a593Smuzhiyun pdata = dev_get_platdata(dev);
1203*4882a593Smuzhiyun low_power_voltage = pdata->low_power_voltage;
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun /* charger changed */
1206*4882a593Smuzhiyun if (old_charger != charger) {
1207*4882a593Smuzhiyun if (charger == NO_CHARGER) {
1208*4882a593Smuzhiyun BAT_INFO("NO_CHARGER\n");
1209*4882a593Smuzhiyun rk818_bat_set_current(di, ILIM_450MA);
1210*4882a593Smuzhiyun } else if (charger == USB_CHARGER) {
1211*4882a593Smuzhiyun BAT_INFO("USB_CHARGER\n");
1212*4882a593Smuzhiyun rk818_bat_set_current(di, ILIM_450MA);
1213*4882a593Smuzhiyun } else if (charger == DC_CHARGER || charger == AC_CHARGER) {
1214*4882a593Smuzhiyun if (pdata->uboot_charge && di->ts2_vol_multi) {
1215*4882a593Smuzhiyun rk818_bat_ts2_update_current(di);
1216*4882a593Smuzhiyun } else if ((rk818_bat_get_est_voltage(di) < low_power_voltage) &&
1217*4882a593Smuzhiyun (di->ts2_vol_multi)) {
1218*4882a593Smuzhiyun rk818_bat_ts2_update_current(di);
1219*4882a593Smuzhiyun } else {
1220*4882a593Smuzhiyun rk818_bat_set_current(di, di->chrg_cur_input);
1221*4882a593Smuzhiyun BAT_INFO("DC_CHARGER\n");
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun } else {
1224*4882a593Smuzhiyun BAT_INFO("charger setting error %d\n", charger);
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun old_charger = charger;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun
rk818_bat_get_dc_state(struct battery_priv * di)1231*4882a593Smuzhiyun static int rk818_bat_get_dc_state(struct battery_priv *di)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun if (!di->dc_is_valid)
1234*4882a593Smuzhiyun return NO_CHARGER;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun return dm_gpio_get_value(&di->dc_det) ? DC_CHARGER : NO_CHARGER;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
rk818_bat_get_charger_type(struct battery_priv * di)1239*4882a593Smuzhiyun static int rk818_bat_get_charger_type(struct battery_priv *di)
1240*4882a593Smuzhiyun {
1241*4882a593Smuzhiyun int charger_type = NO_CHARGER;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun /* check by ic hardware: this check make check work safer */
1244*4882a593Smuzhiyun if ((rk818_bat_read(di, VB_MON_REG) & PLUG_IN_STS) == 0)
1245*4882a593Smuzhiyun return NO_CHARGER;
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun /* virtual or bat not exist */
1248*4882a593Smuzhiyun if (di->virtual_power)
1249*4882a593Smuzhiyun return DC_CHARGER;
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun /* check DC firstly */
1252*4882a593Smuzhiyun charger_type = rk818_bat_get_dc_state(di);
1253*4882a593Smuzhiyun if (charger_type == DC_CHARGER)
1254*4882a593Smuzhiyun return charger_type;
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun /* check USB secondly */
1257*4882a593Smuzhiyun return rk818_bat_get_usb_state(di);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun
rk818_bat_get_chrg_status(struct battery_priv * di)1260*4882a593Smuzhiyun static u8 rk818_bat_get_chrg_status(struct battery_priv *di)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun u8 status;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun status = rk818_bat_read(di, SUP_STS_REG) & BAT_STATUS_MSK;
1265*4882a593Smuzhiyun switch (status) {
1266*4882a593Smuzhiyun case CHARGE_OFF:
1267*4882a593Smuzhiyun DBG("CHARGE-OFF...\n");
1268*4882a593Smuzhiyun break;
1269*4882a593Smuzhiyun case DEAD_CHARGE:
1270*4882a593Smuzhiyun DBG("DEAD CHARGE...\n");
1271*4882a593Smuzhiyun break;
1272*4882a593Smuzhiyun case TRICKLE_CHARGE:
1273*4882a593Smuzhiyun DBG("TRICKLE CHARGE...\n ");
1274*4882a593Smuzhiyun break;
1275*4882a593Smuzhiyun case CC_OR_CV:
1276*4882a593Smuzhiyun DBG("CC or CV...\n");
1277*4882a593Smuzhiyun break;
1278*4882a593Smuzhiyun case CHARGE_FINISH:
1279*4882a593Smuzhiyun DBG("CHARGE FINISH...\n");
1280*4882a593Smuzhiyun break;
1281*4882a593Smuzhiyun case USB_OVER_VOL:
1282*4882a593Smuzhiyun DBG("USB OVER VOL...\n");
1283*4882a593Smuzhiyun break;
1284*4882a593Smuzhiyun case BAT_TMP_ERR:
1285*4882a593Smuzhiyun DBG("BAT TMP ERROR...\n");
1286*4882a593Smuzhiyun break;
1287*4882a593Smuzhiyun case TIMER_ERR:
1288*4882a593Smuzhiyun DBG("TIMER ERROR...\n");
1289*4882a593Smuzhiyun break;
1290*4882a593Smuzhiyun case USB_EXIST:
1291*4882a593Smuzhiyun DBG("USB EXIST...\n");
1292*4882a593Smuzhiyun break;
1293*4882a593Smuzhiyun case USB_EFF:
1294*4882a593Smuzhiyun DBG("USB EFF...\n");
1295*4882a593Smuzhiyun break;
1296*4882a593Smuzhiyun default:
1297*4882a593Smuzhiyun return -EINVAL;
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun return status;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun
rk818_bat_finish_chrg(struct battery_priv * di)1303*4882a593Smuzhiyun static void rk818_bat_finish_chrg(struct battery_priv *di)
1304*4882a593Smuzhiyun {
1305*4882a593Smuzhiyun u32 tgt_sec = 0;
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun if (di->dsoc < 100) {
1308*4882a593Smuzhiyun tgt_sec = di->fcc * 3600 / 100 / FINISH_CALI_CURR;
1309*4882a593Smuzhiyun if (get_timer(di->finish_chrg_base) > SECONDS(tgt_sec)) {
1310*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1311*4882a593Smuzhiyun di->dsoc++;
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun }
1314*4882a593Smuzhiyun DBG("<%s>. sec=%d, finish_sec=%lu\n", __func__, SECONDS(tgt_sec),
1315*4882a593Smuzhiyun get_timer(di->finish_chrg_base));
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
rk818_bat_debug_info(struct battery_priv * di)1318*4882a593Smuzhiyun static void rk818_bat_debug_info(struct battery_priv *di)
1319*4882a593Smuzhiyun {
1320*4882a593Smuzhiyun u8 sup_sts, ggcon, ggsts, vb_mod, rtc, thermal, misc;
1321*4882a593Smuzhiyun u8 usb_ctrl, chrg_ctrl1, chrg_ctrl2, chrg_ctrl3;
1322*4882a593Smuzhiyun static const char *name[] = {"NONE", "USB", "AC", "DC", "UNDEF"};
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun if (!dbg_enable)
1325*4882a593Smuzhiyun return;
1326*4882a593Smuzhiyun ggcon = rk818_bat_read(di, GGCON_REG);
1327*4882a593Smuzhiyun ggsts = rk818_bat_read(di, GGSTS_REG);
1328*4882a593Smuzhiyun sup_sts = rk818_bat_read(di, SUP_STS_REG);
1329*4882a593Smuzhiyun usb_ctrl = rk818_bat_read(di, USB_CTRL_REG);
1330*4882a593Smuzhiyun thermal = rk818_bat_read(di, THERMAL_REG);
1331*4882a593Smuzhiyun vb_mod = rk818_bat_read(di, VB_MON_REG);
1332*4882a593Smuzhiyun misc = rk818_bat_read(di, MISC_MARK_REG);
1333*4882a593Smuzhiyun rtc = rk818_bat_read(di, SECONDS_REG);
1334*4882a593Smuzhiyun chrg_ctrl1 = rk818_bat_read(di, CHRG_CTRL_REG1);
1335*4882a593Smuzhiyun chrg_ctrl2 = rk818_bat_read(di, CHRG_CTRL_REG2);
1336*4882a593Smuzhiyun chrg_ctrl3 = rk818_bat_read(di, CHRG_CTRL_REG3);
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun DBG("\n---------------------- DEBUG REGS ------------------------\n"
1339*4882a593Smuzhiyun "GGCON=0x%2x, GGSTS=0x%2x, RTC=0x%2x, SUP_STS= 0x%2x\n"
1340*4882a593Smuzhiyun "VB_MOD=0x%2x, USB_CTRL=0x%2x, THERMAL=0x%2x, MISC=0x%2x\n"
1341*4882a593Smuzhiyun "CHRG_CTRL:REG1=0x%2x, REG2=0x%2x, REG3=0x%2x\n",
1342*4882a593Smuzhiyun ggcon, ggsts, rtc, sup_sts, vb_mod, usb_ctrl,
1343*4882a593Smuzhiyun thermal, misc, chrg_ctrl1, chrg_ctrl2, chrg_ctrl3
1344*4882a593Smuzhiyun );
1345*4882a593Smuzhiyun DBG("----------------------------------------------------------\n"
1346*4882a593Smuzhiyun "Dsoc=%d, Rsoc=%d, Vavg=%d, Iavg=%d, Cap=%d, Fcc=%d, d=%d\n"
1347*4882a593Smuzhiyun "K=%d, old_cap=%d, charger=%s, Is=%d, Ip=%d, Vs=%d\n"
1348*4882a593Smuzhiyun "min=%d, meet: soc=%d, calc: dsoc=%d, rsoc=%d, Vocv=%d\n"
1349*4882a593Smuzhiyun "off: i=0x%x, c=0x%x, max=%d, ocv_c=%d, halt: st=%d, cnt=%d\n"
1350*4882a593Smuzhiyun "pwr: dsoc=%d, rsoc=%d, vol=%d, Res=%d, mode=%s, T=%d'C\n",
1351*4882a593Smuzhiyun di->dsoc, rk818_bat_get_rsoc(di), rk818_bat_get_avg_voltage(di),
1352*4882a593Smuzhiyun rk818_bat_get_avg_current(di), di->remain_cap, di->fcc,
1353*4882a593Smuzhiyun di->rsoc - di->dsoc,
1354*4882a593Smuzhiyun di->sm_linek, di->sm_old_cap, name[di->chrg_type],
1355*4882a593Smuzhiyun di->res_div * CHRG_CUR_SEL[chrg_ctrl1 & 0x0f],
1356*4882a593Smuzhiyun CHRG_CUR_INPUT[usb_ctrl & 0x0f],
1357*4882a593Smuzhiyun CHRG_VOL_SEL[(chrg_ctrl1 & 0x70) >> 4], di->pwroff_min,
1358*4882a593Smuzhiyun di->sm_meet_soc, di->calc_dsoc, di->calc_rsoc,
1359*4882a593Smuzhiyun rk818_bat_get_ocv_voltage(di), rk818_bat_get_ioffset(di),
1360*4882a593Smuzhiyun rk818_bat_get_coffset(di), di->is_max_soc_offset,
1361*4882a593Smuzhiyun di->is_ocv_calib, di->is_halt, di->halt_cnt, di->pwr_dsoc,
1362*4882a593Smuzhiyun di->pwr_rsoc, di->pwr_vol, di->sample_res,
1363*4882a593Smuzhiyun di->virtual_power ? "VIRTUAL" : "BAT",
1364*4882a593Smuzhiyun di->temperature
1365*4882a593Smuzhiyun );
1366*4882a593Smuzhiyun rk818_bat_get_chrg_status(di);
1367*4882a593Smuzhiyun DBG("###########################################################\n");
1368*4882a593Smuzhiyun }
1369*4882a593Smuzhiyun
rk818_bat_linek_algorithm(struct battery_priv * di)1370*4882a593Smuzhiyun static void rk818_bat_linek_algorithm(struct battery_priv *di)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun int delta_cap, ydsoc, tmp;
1373*4882a593Smuzhiyun u8 chg_st = rk818_bat_get_chrg_status(di);
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* slow down */
1376*4882a593Smuzhiyun if (di->dsoc == 99)
1377*4882a593Smuzhiyun di->sm_linek = CHRG_FULL_K;
1378*4882a593Smuzhiyun else if (di->dsoc >= CHRG_TERM_DSOC && di->current_avg > TERM_CALI_CURR)
1379*4882a593Smuzhiyun di->sm_linek = CHRG_TERM_K;
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun delta_cap = di->remain_cap - di->sm_old_cap;
1382*4882a593Smuzhiyun ydsoc = di->sm_linek * delta_cap * 100 / DIV(di->fcc);
1383*4882a593Smuzhiyun if (ydsoc > 0) {
1384*4882a593Smuzhiyun tmp = (di->sm_chrg_dsoc + 1) / 1000;
1385*4882a593Smuzhiyun if (tmp != di->dsoc)
1386*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
1387*4882a593Smuzhiyun di->sm_chrg_dsoc += ydsoc;
1388*4882a593Smuzhiyun di->dsoc = (di->sm_chrg_dsoc + 1) / 1000;
1389*4882a593Smuzhiyun di->sm_old_cap = di->remain_cap;
1390*4882a593Smuzhiyun if (di->dsoc == di->rsoc && di->sm_linek != CHRG_FULL_K &&
1391*4882a593Smuzhiyun di->sm_linek != CHRG_TERM_K)
1392*4882a593Smuzhiyun di->sm_linek = 1000;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun if ((di->sm_linek == 1000 || di->dsoc >= 100) &&
1396*4882a593Smuzhiyun (chg_st != CHARGE_FINISH)) {
1397*4882a593Smuzhiyun if (di->sm_linek == 1000)
1398*4882a593Smuzhiyun di->dsoc = di->rsoc;
1399*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
1400*4882a593Smuzhiyun }
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun DBG("linek=%d, sm_dsoc=%d, delta_cap=%d, ydsoc=%d, old_cap=%d\n"
1403*4882a593Smuzhiyun "calc: dsoc=%d, rsoc=%d, meet=%d\n",
1404*4882a593Smuzhiyun di->sm_linek, di->sm_chrg_dsoc, delta_cap, ydsoc, di->sm_old_cap,
1405*4882a593Smuzhiyun di->calc_dsoc, di->calc_rsoc, di->sm_meet_soc);
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun
rk818_bat_set_term_mode(struct battery_priv * di,int mode)1408*4882a593Smuzhiyun static void rk818_bat_set_term_mode(struct battery_priv *di, int mode)
1409*4882a593Smuzhiyun {
1410*4882a593Smuzhiyun u8 buf;
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun buf = rk818_bat_read(di, CHRG_CTRL_REG3);
1413*4882a593Smuzhiyun buf &= ~CHRG_TERM_SIG_MSK;
1414*4882a593Smuzhiyun buf |= mode;
1415*4882a593Smuzhiyun rk818_bat_write(di, CHRG_CTRL_REG3, buf);
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun DBG("set charge to %s term mode\n", mode ? "digital" : "analog");
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun
rk818_bat_get_iadc(struct battery_priv * di)1420*4882a593Smuzhiyun static int rk818_bat_get_iadc(struct battery_priv *di)
1421*4882a593Smuzhiyun {
1422*4882a593Smuzhiyun int val = 0;
1423*4882a593Smuzhiyun
1424*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_CUR_AVG_REGL) << 0;
1425*4882a593Smuzhiyun val |= rk818_bat_read(di, BAT_CUR_AVG_REGH) << 8;
1426*4882a593Smuzhiyun if (val > 2047)
1427*4882a593Smuzhiyun val -= 4096;
1428*4882a593Smuzhiyun
1429*4882a593Smuzhiyun return val;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun
rk818_bat_adc_calib(struct battery_priv * di)1432*4882a593Smuzhiyun static bool rk818_bat_adc_calib(struct battery_priv *di)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun int i, ioffset, coffset, adc;
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun if (abs(di->current_avg) < ADC_CALIB_THRESHOLD)
1437*4882a593Smuzhiyun return false;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
1440*4882a593Smuzhiyun adc = rk818_bat_get_iadc(di);
1441*4882a593Smuzhiyun coffset = rk818_bat_get_coffset(di);
1442*4882a593Smuzhiyun rk818_bat_set_coffset(di, coffset + adc);
1443*4882a593Smuzhiyun mdelay(200);
1444*4882a593Smuzhiyun adc = rk818_bat_get_iadc(di);
1445*4882a593Smuzhiyun if (abs(adc) < ADC_CALIB_THRESHOLD) {
1446*4882a593Smuzhiyun coffset = rk818_bat_get_coffset(di);
1447*4882a593Smuzhiyun ioffset = rk818_bat_get_ioffset(di);
1448*4882a593Smuzhiyun di->poffset = coffset - ioffset;
1449*4882a593Smuzhiyun rk818_bat_write(di, POFFSET_REG, di->poffset);
1450*4882a593Smuzhiyun BAT_INFO("new offset:c=0x%x, i=0x%x, p=0x%x\n",
1451*4882a593Smuzhiyun coffset, ioffset, di->poffset);
1452*4882a593Smuzhiyun return true;
1453*4882a593Smuzhiyun } else {
1454*4882a593Smuzhiyun BAT_INFO("coffset calib again %d..\n", i);
1455*4882a593Smuzhiyun rk818_bat_set_coffset(di, coffset);
1456*4882a593Smuzhiyun mdelay(200);
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun return false;
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
rk818_bat_smooth_charge(struct battery_priv * di)1463*4882a593Smuzhiyun static void rk818_bat_smooth_charge(struct battery_priv *di)
1464*4882a593Smuzhiyun {
1465*4882a593Smuzhiyun u8 chg_st = rk818_bat_get_chrg_status(di);
1466*4882a593Smuzhiyun
1467*4882a593Smuzhiyun /* set terminal charge mode */
1468*4882a593Smuzhiyun if (di->term_sig_base && get_timer(di->term_sig_base) > SECONDS(1)) {
1469*4882a593Smuzhiyun DBG("%s: terminal signal finish mode\n", __func__);
1470*4882a593Smuzhiyun rk818_bat_set_term_mode(di, CHRG_TERM_DIG_SIGNAL);
1471*4882a593Smuzhiyun di->term_sig_base = 0;
1472*4882a593Smuzhiyun }
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun /* not charge mode and not keep in uboot charge: exit */
1475*4882a593Smuzhiyun if ((di->chrg_type == NO_CHARGER) ||
1476*4882a593Smuzhiyun !rk818_bat_is_initialized(di)) {
1477*4882a593Smuzhiyun DBG("chrg=%d, initialized=%d\n", di->chrg_type,
1478*4882a593Smuzhiyun rk818_bat_is_initialized(di));
1479*4882a593Smuzhiyun goto out;
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun
1482*4882a593Smuzhiyun /* update rsoc and remain cap */
1483*4882a593Smuzhiyun di->remain_cap = rk818_bat_get_coulomb_cap(di);
1484*4882a593Smuzhiyun di->rsoc = rk818_bat_get_rsoc(di);
1485*4882a593Smuzhiyun if (di->remain_cap > di->fcc) {
1486*4882a593Smuzhiyun di->sm_old_cap -= (di->remain_cap - di->fcc);
1487*4882a593Smuzhiyun rk818_bat_init_capacity(di, di->fcc);
1488*4882a593Smuzhiyun DBG("%s: init capacity: %d\n", __func__, di->fcc);
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun /* finish charge step */
1492*4882a593Smuzhiyun if (chg_st == CHARGE_FINISH) {
1493*4882a593Smuzhiyun DBG("%s: finish charge step...\n", __func__);
1494*4882a593Smuzhiyun if (di->adc_allow_update)
1495*4882a593Smuzhiyun di->adc_allow_update = !rk818_bat_adc_calib(di);
1496*4882a593Smuzhiyun rk818_bat_finish_chrg(di);
1497*4882a593Smuzhiyun rk818_bat_init_capacity(di, di->fcc);
1498*4882a593Smuzhiyun } else {
1499*4882a593Smuzhiyun DBG("%s: smooth charge step...\n", __func__);
1500*4882a593Smuzhiyun di->adc_allow_update = true;
1501*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1502*4882a593Smuzhiyun rk818_bat_linek_algorithm(di);
1503*4882a593Smuzhiyun }
1504*4882a593Smuzhiyun
1505*4882a593Smuzhiyun /* dsoc limit */
1506*4882a593Smuzhiyun if (di->dsoc > 100)
1507*4882a593Smuzhiyun di->dsoc = 100;
1508*4882a593Smuzhiyun else if (di->dsoc < 0)
1509*4882a593Smuzhiyun di->dsoc = 0;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun DBG("%s: save dsoc=%d and rsoc=%d\n",
1512*4882a593Smuzhiyun __func__, di->dsoc, rk818_bat_get_rsoc(di));
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun rk818_bat_save_dsoc(di, di->dsoc);
1515*4882a593Smuzhiyun rk818_bat_save_cap(di, di->remain_cap);
1516*4882a593Smuzhiyun out:
1517*4882a593Smuzhiyun rk818_bat_debug_info(di);
1518*4882a593Smuzhiyun }
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun /*
1521*4882a593Smuzhiyun * Due to hardware design issue, Vdelta = "(R_sample + R_other) * I_avg" will be
1522*4882a593Smuzhiyun * included into TS1 adc value. We must subtract it to get correct adc value.
1523*4882a593Smuzhiyun * The solution:
1524*4882a593Smuzhiyun *
1525*4882a593Smuzhiyun * (1) calculate Vdelta:
1526*4882a593Smuzhiyun *
1527*4882a593Smuzhiyun * adc1 - Vdelta ua1 (adc2 * ua1) - (adc1 * ua2)
1528*4882a593Smuzhiyun * ------------- = ----- ==> equals: Vdelta = -----------------------------
1529*4882a593Smuzhiyun * adc2 - Vdelta ua2 ua1 - ua2
1530*4882a593Smuzhiyun *
1531*4882a593Smuzhiyun *
1532*4882a593Smuzhiyun * (2) calculate correct ADC value:
1533*4882a593Smuzhiyun *
1534*4882a593Smuzhiyun * charging: ADC = adc1 - abs(Vdelta);
1535*4882a593Smuzhiyun * discharging: ADC = adc1 + abs(Vdelta);
1536*4882a593Smuzhiyun */
rk818_bat_get_ntc_res(struct battery_priv * di)1537*4882a593Smuzhiyun static int rk818_bat_get_ntc_res(struct battery_priv *di)
1538*4882a593Smuzhiyun {
1539*4882a593Smuzhiyun static int adc1 = 0, adc2 = 0, ua1 = 0, ua2 = 0;
1540*4882a593Smuzhiyun static int adc1_update = 0, first_in = 1;
1541*4882a593Smuzhiyun static ulong seconds;
1542*4882a593Smuzhiyun int v_delta, val, res;
1543*4882a593Smuzhiyun u8 buf;
1544*4882a593Smuzhiyun
1545*4882a593Smuzhiyun /* hold adc1 and wait 1s for adc2 updated */
1546*4882a593Smuzhiyun if (!adc1_update) {
1547*4882a593Smuzhiyun /* update flag and init adc1,adc2 !! */
1548*4882a593Smuzhiyun adc1_update = 1;
1549*4882a593Smuzhiyun seconds = get_timer(0);
1550*4882a593Smuzhiyun adc1 = 0;
1551*4882a593Smuzhiyun adc2 = 0;
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun /* read sample ua1 */
1554*4882a593Smuzhiyun buf = rk818_bat_read(di, TS_CTRL_REG);
1555*4882a593Smuzhiyun DBG("<%s>. read adc1, sample uA=%d\n",
1556*4882a593Smuzhiyun __func__, ((buf & 0x03) + 1) * 20);
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun /* read adc adc1 */
1559*4882a593Smuzhiyun ua1 = di->ntc_uA;
1560*4882a593Smuzhiyun adc1 |= rk818_bat_read(di, TS_ADC_REGL) << 0;
1561*4882a593Smuzhiyun adc1 |= rk818_bat_read(di, TS_ADC_REGH) << 8;
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun /* chose reference UA for adc2 */
1564*4882a593Smuzhiyun ua2 = (ua1 != 20) ? 20 : 40;
1565*4882a593Smuzhiyun buf = rk818_bat_read(di, TS_CTRL_REG);
1566*4882a593Smuzhiyun buf &= ~ADC_CUR_MSK;
1567*4882a593Smuzhiyun buf |= ((ua2 - 20) / 20);
1568*4882a593Smuzhiyun rk818_bat_write(di, TS_CTRL_REG, buf);
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun /* wait 1s for adc2 updated */
1572*4882a593Smuzhiyun if (get_timer(seconds) < SECONDS(1)) {
1573*4882a593Smuzhiyun if (first_in)
1574*4882a593Smuzhiyun first_in = 0;
1575*4882a593Smuzhiyun else
1576*4882a593Smuzhiyun return TS1_NOT_READY;
1577*4882a593Smuzhiyun }
1578*4882a593Smuzhiyun
1579*4882a593Smuzhiyun /* update flags ! */
1580*4882a593Smuzhiyun adc1_update = 0;
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun /* read sample ua2 */
1583*4882a593Smuzhiyun buf = rk818_bat_read(di, TS_CTRL_REG);
1584*4882a593Smuzhiyun DBG("<%s>. read adc2, sample uA=%d\n",
1585*4882a593Smuzhiyun __func__, ((buf & 0x03) + 1) * 20);
1586*4882a593Smuzhiyun
1587*4882a593Smuzhiyun /* read adc adc2 */
1588*4882a593Smuzhiyun adc2 |= rk818_bat_read(di, TS_ADC_REGL) << 0;
1589*4882a593Smuzhiyun adc2 |= rk818_bat_read(di, TS_ADC_REGH) << 8;
1590*4882a593Smuzhiyun
1591*4882a593Smuzhiyun DBG("<%s>. ua1=%d, ua2=%d, adc1=%d, adc2=%d\n",
1592*4882a593Smuzhiyun __func__, ua1, ua2, adc1, adc2);
1593*4882a593Smuzhiyun
1594*4882a593Smuzhiyun /* calculate delta voltage */
1595*4882a593Smuzhiyun if (adc2 != adc1)
1596*4882a593Smuzhiyun v_delta = abs((adc2 * ua1 - adc1 * ua2) / (ua2 - ua1));
1597*4882a593Smuzhiyun else
1598*4882a593Smuzhiyun v_delta = 0;
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun /* considering current avg direction, calcuate real adc value */
1601*4882a593Smuzhiyun val = (di->current_avg >= 0) ? (adc1 - v_delta) : (adc1 + v_delta);
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun DBG("<%s>. Iavg=%d, Vdelta=%d, Vadc=%d\n",
1604*4882a593Smuzhiyun __func__, di->current_avg, v_delta, val);
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun res = val * di->ntc_factor;
1607*4882a593Smuzhiyun
1608*4882a593Smuzhiyun DBG("<%s>. val=%d, ntc_res=%d, ntc_factor=%d\n",
1609*4882a593Smuzhiyun __func__, val, res, di->ntc_factor);
1610*4882a593Smuzhiyun
1611*4882a593Smuzhiyun DBG("<%s>. t=[%d'C(%d) ~ %dC(%d)]\n", __func__,
1612*4882a593Smuzhiyun di->ntc_degree_from, di->ntc_table[0],
1613*4882a593Smuzhiyun di->ntc_degree_from + di->ntc_size - 1,
1614*4882a593Smuzhiyun di->ntc_table[di->ntc_size - 1]);
1615*4882a593Smuzhiyun
1616*4882a593Smuzhiyun rk818_bat_init_ts1(di);
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun return res;
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun
rk818_bat_update_temperature(struct battery_priv * di)1621*4882a593Smuzhiyun static int rk818_bat_update_temperature(struct battery_priv *di)
1622*4882a593Smuzhiyun {
1623*4882a593Smuzhiyun static int first_time = 1, old_temperature = 25;
1624*4882a593Smuzhiyun u32 ntc_size, *ntc_table;
1625*4882a593Smuzhiyun int i, res, temp;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun ntc_table = di->ntc_table;
1628*4882a593Smuzhiyun ntc_size = di->ntc_size;
1629*4882a593Smuzhiyun
1630*4882a593Smuzhiyun if (ntc_size) {
1631*4882a593Smuzhiyun res = rk818_bat_get_ntc_res(di);
1632*4882a593Smuzhiyun if (res == TS1_NOT_READY) {
1633*4882a593Smuzhiyun di->temperature = old_temperature;
1634*4882a593Smuzhiyun return TS1_NOT_READY;
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun if (res < ntc_table[ntc_size - 1]) {
1638*4882a593Smuzhiyun di->temperature = di->ntc_degree_from;
1639*4882a593Smuzhiyun old_temperature = di->ntc_degree_from;
1640*4882a593Smuzhiyun printf("bat ntc upper max degree: R=%d\n", res);
1641*4882a593Smuzhiyun } else if (res > ntc_table[0]) {
1642*4882a593Smuzhiyun di->temperature = di->ntc_degree_from + di->ntc_size - 1;
1643*4882a593Smuzhiyun old_temperature = di->ntc_degree_from + di->ntc_size - 1;
1644*4882a593Smuzhiyun printf("bat ntc lower min degree: R=%d\n", res);
1645*4882a593Smuzhiyun } else {
1646*4882a593Smuzhiyun for (i = 0; i < ntc_size; i++) {
1647*4882a593Smuzhiyun if (res >= ntc_table[i])
1648*4882a593Smuzhiyun break;
1649*4882a593Smuzhiyun }
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun /* if first in, init old_temperature */
1652*4882a593Smuzhiyun temp = (i + di->ntc_degree_from);
1653*4882a593Smuzhiyun if (first_time) {
1654*4882a593Smuzhiyun di->temperature = temp;
1655*4882a593Smuzhiyun old_temperature = temp;
1656*4882a593Smuzhiyun first_time = 0;
1657*4882a593Smuzhiyun }
1658*4882a593Smuzhiyun
1659*4882a593Smuzhiyun old_temperature = temp;
1660*4882a593Smuzhiyun di->temperature = temp;
1661*4882a593Smuzhiyun }
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun
1664*4882a593Smuzhiyun DBG("temperature=%d\n", di->temperature);
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun return 0;
1667*4882a593Smuzhiyun }
1668*4882a593Smuzhiyun
rk818_bat_bat_is_exit(struct udevice * dev)1669*4882a593Smuzhiyun static int rk818_bat_bat_is_exit(struct udevice *dev)
1670*4882a593Smuzhiyun {
1671*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun return is_rk818_bat_exist(di);
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun
rk818_bat_update_get_soc(struct udevice * dev)1676*4882a593Smuzhiyun static int rk818_bat_update_get_soc(struct udevice *dev)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1679*4882a593Smuzhiyun static ulong seconds, ts1_seconds;
1680*4882a593Smuzhiyun int wait;
1681*4882a593Smuzhiyun
1682*4882a593Smuzhiyun /* set charge current */
1683*4882a593Smuzhiyun di->chrg_type =
1684*4882a593Smuzhiyun rk818_bat_get_charger_type(di);
1685*4882a593Smuzhiyun rk818_bat_charger_setting(di, di->chrg_type);
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun /* fg calc every 5 seconds */
1688*4882a593Smuzhiyun if (!seconds || !ts1_seconds) {
1689*4882a593Smuzhiyun seconds = get_timer(0);
1690*4882a593Smuzhiyun ts1_seconds = get_timer(0);
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun
1693*4882a593Smuzhiyun /* temperature calc every 5 seconds */
1694*4882a593Smuzhiyun if (get_timer(ts1_seconds) >= SECONDS(5)) {
1695*4882a593Smuzhiyun DBG("%s: update temperature\n", __func__);
1696*4882a593Smuzhiyun wait = rk818_bat_update_temperature(di);
1697*4882a593Smuzhiyun if (!wait)
1698*4882a593Smuzhiyun ts1_seconds = get_timer(0);
1699*4882a593Smuzhiyun }
1700*4882a593Smuzhiyun
1701*4882a593Smuzhiyun if (get_timer(seconds) >= SECONDS(5)) {
1702*4882a593Smuzhiyun DBG("%s: smooth charge\n", __func__);
1703*4882a593Smuzhiyun seconds = get_timer(0);
1704*4882a593Smuzhiyun rk818_bat_smooth_charge(di);
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun /* bat exist, fg init success(dts pass) and uboot charge: report data */
1708*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1709*4882a593Smuzhiyun return di->dsoc;
1710*4882a593Smuzhiyun else
1711*4882a593Smuzhiyun return VIRTUAL_POWER_SOC;
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun
rk818_bat_update_get_current(struct udevice * dev)1714*4882a593Smuzhiyun static int rk818_bat_update_get_current(struct udevice *dev)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1719*4882a593Smuzhiyun return rk818_bat_get_avg_current(di);
1720*4882a593Smuzhiyun else
1721*4882a593Smuzhiyun return VIRTUAL_POWER_CUR;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun
rk818_bat_update_get_voltage(struct udevice * dev)1724*4882a593Smuzhiyun static int rk818_bat_update_get_voltage(struct udevice *dev)
1725*4882a593Smuzhiyun {
1726*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1727*4882a593Smuzhiyun
1728*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1729*4882a593Smuzhiyun return rk818_bat_get_est_voltage(di);
1730*4882a593Smuzhiyun else
1731*4882a593Smuzhiyun return VIRTUAL_POWER_VOL;
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun
rk818_bat_update_get_chrg_online(struct udevice * dev)1734*4882a593Smuzhiyun static bool rk818_bat_update_get_chrg_online(struct udevice *dev)
1735*4882a593Smuzhiyun {
1736*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun return rk818_bat_get_charger_type(di);
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun static struct dm_fuel_gauge_ops fg_ops = {
1742*4882a593Smuzhiyun .bat_is_exist = rk818_bat_bat_is_exit,
1743*4882a593Smuzhiyun .get_soc = rk818_bat_update_get_soc,
1744*4882a593Smuzhiyun .get_voltage = rk818_bat_update_get_voltage,
1745*4882a593Smuzhiyun .get_current = rk818_bat_update_get_current,
1746*4882a593Smuzhiyun .get_chrg_online = rk818_bat_update_get_chrg_online,
1747*4882a593Smuzhiyun };
1748*4882a593Smuzhiyun
rk818_fg_ofdata_to_platdata(struct udevice * dev)1749*4882a593Smuzhiyun static int rk818_fg_ofdata_to_platdata(struct udevice *dev)
1750*4882a593Smuzhiyun {
1751*4882a593Smuzhiyun struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
1752*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1753*4882a593Smuzhiyun u32 sign, degree_from[2];
1754*4882a593Smuzhiyun const char *prop;
1755*4882a593Smuzhiyun int len, ret;
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun if (rk8xx->variant != 0x8180) {
1758*4882a593Smuzhiyun debug("%s: Not support pmic variant: rk%x\n",
1759*4882a593Smuzhiyun __func__, rk8xx->variant);
1760*4882a593Smuzhiyun return -EINVAL;
1761*4882a593Smuzhiyun } else {
1762*4882a593Smuzhiyun di->dev = dev;
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun
1765*4882a593Smuzhiyun /* Parse ocv table */
1766*4882a593Smuzhiyun prop = dev_read_prop(dev, "ocv_table", &len);
1767*4882a593Smuzhiyun if (!prop) {
1768*4882a593Smuzhiyun printf("can't find ocv_table prop\n");
1769*4882a593Smuzhiyun return -EINVAL;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun di->ocv_table = calloc(len, 1);
1773*4882a593Smuzhiyun if (!di->ocv_table) {
1774*4882a593Smuzhiyun printf("can't calloc ocv_table\n");
1775*4882a593Smuzhiyun return -ENOMEM;
1776*4882a593Smuzhiyun }
1777*4882a593Smuzhiyun
1778*4882a593Smuzhiyun di->ocv_size = len / 4;
1779*4882a593Smuzhiyun if (dev_read_u32_array(dev, "ocv_table",
1780*4882a593Smuzhiyun di->ocv_table, di->ocv_size)) {
1781*4882a593Smuzhiyun printf("can't read ocv_table\n");
1782*4882a593Smuzhiyun free(di->ocv_table);
1783*4882a593Smuzhiyun return -EINVAL;
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun /* Parse neccessay */
1787*4882a593Smuzhiyun di->design_cap = dev_read_u32_default(dev, "design_capacity", -1);
1788*4882a593Smuzhiyun if (di->design_cap < 0) {
1789*4882a593Smuzhiyun printf("can't read design_capacity\n");
1790*4882a593Smuzhiyun return -EINVAL;
1791*4882a593Smuzhiyun }
1792*4882a593Smuzhiyun
1793*4882a593Smuzhiyun di->qmax = dev_read_u32_default(dev, "design_qmax", -1);
1794*4882a593Smuzhiyun if (di->qmax < 0) {
1795*4882a593Smuzhiyun printf("can't read design_qmax\n");
1796*4882a593Smuzhiyun return -EINVAL;
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun
1799*4882a593Smuzhiyun /* Parse un-neccessay */
1800*4882a593Smuzhiyun di->dts_vol_sel = dev_read_u32_default(dev, "max_chrg_voltage", 4200);
1801*4882a593Smuzhiyun if (di->dts_vol_sel < 0)
1802*4882a593Smuzhiyun di->dts_vol_sel = dev_read_u32_default(dev,
1803*4882a593Smuzhiyun "max_charge_voltagemV", 4200);
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun di->dts_cur_input = dev_read_u32_default(dev, "max_input_current", 2000);
1806*4882a593Smuzhiyun if (di->dts_cur_input < 0)
1807*4882a593Smuzhiyun di->dts_cur_input = dev_read_u32_default(dev,
1808*4882a593Smuzhiyun "max_input_currentmA", 2000);
1809*4882a593Smuzhiyun
1810*4882a593Smuzhiyun di->dts_cur_sel = dev_read_u32_default(dev, "max_chrg_current", 1200);
1811*4882a593Smuzhiyun if (di->dts_cur_sel < 0)
1812*4882a593Smuzhiyun di->dts_cur_sel = dev_read_u32_default(dev,
1813*4882a593Smuzhiyun "max_chrg_currentmA", 1400);
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun di->max_soc_offset = dev_read_u32_default(dev, "max_soc_offset", 70);
1816*4882a593Smuzhiyun di->virtual_power = dev_read_u32_default(dev, "virtual_power", 0);
1817*4882a593Smuzhiyun di->bat_res = dev_read_u32_default(dev, "bat_res", 135);
1818*4882a593Smuzhiyun di->sample_res = dev_read_u32_default(dev, "sample_res", SAMPLE_RES_20mR);
1819*4882a593Smuzhiyun di->ts2_vol_multi = dev_read_u32_default(dev, "ts2_vol_multi", 0);
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun di->res_div = (di->sample_res == SAMPLE_RES_20mR) ?
1822*4882a593Smuzhiyun SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun ret = gpio_request_by_name_nodev(dev_ofnode(dev), "dc_det_gpio",
1825*4882a593Smuzhiyun 0, &di->dc_det, GPIOD_IS_IN);
1826*4882a593Smuzhiyun if (!ret) {
1827*4882a593Smuzhiyun di->dc_is_valid = 1;
1828*4882a593Smuzhiyun debug("DC is valid\n");
1829*4882a593Smuzhiyun } else {
1830*4882a593Smuzhiyun debug("DC is invalid, ret=%d\n", ret);
1831*4882a593Smuzhiyun }
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun prop = dev_read_prop(dev, "ntc_table", &len);
1834*4882a593Smuzhiyun if (!prop) {
1835*4882a593Smuzhiyun di->ntc_size = 0;
1836*4882a593Smuzhiyun } else {
1837*4882a593Smuzhiyun ret = dev_read_u32_array(dev, "ntc_degree_from",
1838*4882a593Smuzhiyun degree_from, ARRAY_SIZE(degree_from));
1839*4882a593Smuzhiyun if (ret < 0) {
1840*4882a593Smuzhiyun printf("invalid ntc_degree_from\n");
1841*4882a593Smuzhiyun return -EINVAL;
1842*4882a593Smuzhiyun }
1843*4882a593Smuzhiyun
1844*4882a593Smuzhiyun sign = degree_from[0];
1845*4882a593Smuzhiyun di->ntc_degree_from = degree_from[1];
1846*4882a593Smuzhiyun if (sign)
1847*4882a593Smuzhiyun di->ntc_degree_from = -di->ntc_degree_from;
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun di->ntc_size = len / sizeof(u32);
1850*4882a593Smuzhiyun }
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun if (di->ntc_size) {
1853*4882a593Smuzhiyun di->ntc_table = calloc(len, 1);
1854*4882a593Smuzhiyun if (!di->ntc_table) {
1855*4882a593Smuzhiyun printf("calloc ocv_table fail\n");
1856*4882a593Smuzhiyun return -ENOMEM;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun
1859*4882a593Smuzhiyun ret = dev_read_u32_array(dev, "ntc_table",
1860*4882a593Smuzhiyun di->ntc_table, di->ntc_size);
1861*4882a593Smuzhiyun if (ret < 0) {
1862*4882a593Smuzhiyun printf("read ntc_table array failed\n");
1863*4882a593Smuzhiyun return ret;
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun }
1866*4882a593Smuzhiyun
1867*4882a593Smuzhiyun /* Is battery attached */
1868*4882a593Smuzhiyun if (!is_rk818_bat_exist(di))
1869*4882a593Smuzhiyun di->virtual_power = 1;
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun DBG("-------------------------------:\n");
1872*4882a593Smuzhiyun DBG("max_input_current:%d\n", di->dts_cur_input);
1873*4882a593Smuzhiyun DBG("max_chrg_current:%d\n", di->dts_cur_sel);
1874*4882a593Smuzhiyun DBG("max_chrg_voltage:%d\n", di->dts_vol_sel);
1875*4882a593Smuzhiyun DBG("design_capacity :%d\n", di->design_cap);
1876*4882a593Smuzhiyun DBG("design_qmax:%d\n", di->qmax);
1877*4882a593Smuzhiyun DBG("max_soc_offset:%d\n", di->max_soc_offset);
1878*4882a593Smuzhiyun DBG("sample_res:%d\n", di->sample_res);
1879*4882a593Smuzhiyun DBG("virtual_power:%d\n", di->virtual_power);
1880*4882a593Smuzhiyun DBG("ts2_vol_multi:%d\n", di->ts2_vol_multi);
1881*4882a593Smuzhiyun DBG("dc det: %d\n", di->dc_is_valid);
1882*4882a593Smuzhiyun DBG("ntc_size:%d\n", di->ntc_size);
1883*4882a593Smuzhiyun DBG("ntc_degree_from:%d\n", di->ntc_degree_from);
1884*4882a593Smuzhiyun DBG("ntc_degree_to:%d\n", di->ntc_degree_from + di->ntc_size - 1);
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun return 0;
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun
rk818_fg_probe(struct udevice * dev)1889*4882a593Smuzhiyun static int rk818_fg_probe(struct udevice *dev)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
1892*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1893*4882a593Smuzhiyun
1894*4882a593Smuzhiyun if (rk8xx->variant != 0x8180) {
1895*4882a593Smuzhiyun printf("Not support pmic variant: rk%x\n", rk8xx->variant);
1896*4882a593Smuzhiyun return -EINVAL;
1897*4882a593Smuzhiyun }
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun return rk818_fg_init(di);
1900*4882a593Smuzhiyun }
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun U_BOOT_DRIVER(rk818_fg) = {
1903*4882a593Smuzhiyun .name = "rk818_fg",
1904*4882a593Smuzhiyun .id = UCLASS_FG,
1905*4882a593Smuzhiyun .probe = rk818_fg_probe,
1906*4882a593Smuzhiyun .ops = &fg_ops,
1907*4882a593Smuzhiyun .ofdata_to_platdata = rk818_fg_ofdata_to_platdata,
1908*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct battery_priv),
1909*4882a593Smuzhiyun };
1910