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 <adc.h> */
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun #include <fdtdec.h>
13*4882a593Smuzhiyun #include <asm/gpio.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <power/pmic.h>
16*4882a593Smuzhiyun #include <dm/uclass-internal.h>
17*4882a593Smuzhiyun #include <power/charge_display.h>
18*4882a593Smuzhiyun #include <power/charge_animation.h>
19*4882a593Smuzhiyun #include <power/fuel_gauge.h>
20*4882a593Smuzhiyun #include <power/rk8xx_pmic.h>
21*4882a593Smuzhiyun #include <linux/usb/phy-rockchip-usb2.h>
22*4882a593Smuzhiyun #include "fg_regs.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun static int dbg_enable = 0;
27*4882a593Smuzhiyun #define DBG(args...) \
28*4882a593Smuzhiyun do { \
29*4882a593Smuzhiyun if (dbg_enable) { \
30*4882a593Smuzhiyun printf(args); \
31*4882a593Smuzhiyun } \
32*4882a593Smuzhiyun } while (0)
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define BAT_INFO(fmt, args...) printf("rk816-bat: "fmt, ##args)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define DRIVER_VERSION "2.0"
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* THERMAL_REG */
39*4882a593Smuzhiyun #define TEMP_115C (0x03 << 2)
40*4882a593Smuzhiyun #define FB_TEMP_MSK 0x0c
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* CHRG_CTRL_REG2*/
43*4882a593Smuzhiyun #define FINISH_100MA (0x00 << 6)
44*4882a593Smuzhiyun #define FINISH_150MA (0x01 << 6)
45*4882a593Smuzhiyun #define FINISH_200MA (0x02 << 6)
46*4882a593Smuzhiyun #define FINISH_250MA (0x03 << 6)
47*4882a593Smuzhiyun #define FINISH_CUR_MSK 0xc7
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* CHRG_CTRL_REG3*/
50*4882a593Smuzhiyun #define CHRG_TERM_DIG_SIGNAL (1 << 5)
51*4882a593Smuzhiyun #define CHRG_TIMER_CCCV_EN (1 << 2)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* CHRG_CTRL_REG */
54*4882a593Smuzhiyun #define ILIM_450MA (0x00)
55*4882a593Smuzhiyun #define ILIM_2000MA (0x07)
56*4882a593Smuzhiyun #define CHRG_CT_EN (1 << 7)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* USB_CTRL_REG */
59*4882a593Smuzhiyun #define INPUT_CUR_MSK 0x0f
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* VB_MON_REG */
62*4882a593Smuzhiyun #define PLUG_IN_STS (1 << 6)
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* GGSTS */
65*4882a593Smuzhiyun #define BAT_CON (1 << 4)
66*4882a593Smuzhiyun #define VOL_INSTANT (1 << 0)
67*4882a593Smuzhiyun #define VOL_AVG (0 << 0)
68*4882a593Smuzhiyun #define VOL_AVG_MASK (1 << 0)
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* TS_CTRL_REG */
71*4882a593Smuzhiyun #define GG_EN (1 << 7)
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* CHRG_USB_CTRL*/
74*4882a593Smuzhiyun #define CHRG_EN (1 << 7)
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* BAT_CTRL_REG */
77*4882a593Smuzhiyun #define USB_SYS_EN (1 << 6)
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /*SUP_STS_REG*/
80*4882a593Smuzhiyun #define BAT_EXS (1 << 7)
81*4882a593Smuzhiyun #define USB_EXIST (1 << 1)
82*4882a593Smuzhiyun #define USB_EFF (1 << 0)
83*4882a593Smuzhiyun #define CHARGE_OFF (0x00 << 4)
84*4882a593Smuzhiyun #define DEAD_CHARGE (0x01 << 4)
85*4882a593Smuzhiyun #define TRICKLE_CHARGE (0x02 << 4)
86*4882a593Smuzhiyun #define CC_OR_CV (0x03 << 4)
87*4882a593Smuzhiyun #define CHARGE_FINISH (0x04 << 4)
88*4882a593Smuzhiyun #define USB_OVER_VOL (0x05 << 4)
89*4882a593Smuzhiyun #define BAT_TMP_ERR (0x06 << 4)
90*4882a593Smuzhiyun #define TIMER_ERR (0x07 << 4)
91*4882a593Smuzhiyun #define USB_VLIMIT_EN (1 << 3)
92*4882a593Smuzhiyun #define USB_CLIMIT_EN (1 << 2)
93*4882a593Smuzhiyun #define BAT_STATUS_MSK 0x70
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* GGCON */
96*4882a593Smuzhiyun #define ADC_CUR_MODE (1 << 1)
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* CALI PARAM */
99*4882a593Smuzhiyun #define FINISH_CALI_CURR 1500
100*4882a593Smuzhiyun #define TERM_CALI_CURR 600
101*4882a593Smuzhiyun #define VIRTUAL_POWER_VOL 4200
102*4882a593Smuzhiyun #define VIRTUAL_POWER_CUR 1000
103*4882a593Smuzhiyun #define VIRTUAL_POWER_SOC 66
104*4882a593Smuzhiyun #define SECONDS(n) ((n) * 1000)
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* CALC PARAM */
107*4882a593Smuzhiyun #define MAX_PERCENTAGE 100
108*4882a593Smuzhiyun #define MAX_INTERPOLATE 1000
109*4882a593Smuzhiyun #define MAX_INT 0x7fff
110*4882a593Smuzhiyun #define MIN_FCC 500
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* DC ADC */
113*4882a593Smuzhiyun #define FG_INIT (1 << 3)
114*4882a593Smuzhiyun #define FG_RESET_LATE (1 << 1)
115*4882a593Smuzhiyun #define FG_RESET_NOW (1 << 0)
116*4882a593Smuzhiyun #define CHRG_TERM_DSOC 90
117*4882a593Smuzhiyun #define CHRG_TERM_K 650
118*4882a593Smuzhiyun #define CHRG_FULL_K 400
119*4882a593Smuzhiyun #define ADC_CALIB_THRESHOLD 4
120*4882a593Smuzhiyun #define DC_ADC_TRIGGER 150
121*4882a593Smuzhiyun #define DIV(x) ((x) ? (x) : 1)
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun #define SAMPLE_RES_20MR 20
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /***********************************************************/
126*4882a593Smuzhiyun struct battery_priv {
127*4882a593Smuzhiyun struct udevice *dev;
128*4882a593Smuzhiyun int chrg_type;
129*4882a593Smuzhiyun int poffset;
130*4882a593Smuzhiyun int bat_res;
131*4882a593Smuzhiyun int current_avg;
132*4882a593Smuzhiyun int voltage_avg;
133*4882a593Smuzhiyun int voltage_ocv;
134*4882a593Smuzhiyun int voltage_k;
135*4882a593Smuzhiyun int voltage_b;
136*4882a593Smuzhiyun int dsoc;
137*4882a593Smuzhiyun int rsoc;
138*4882a593Smuzhiyun int fcc;
139*4882a593Smuzhiyun u32 qmax;
140*4882a593Smuzhiyun int remain_cap;
141*4882a593Smuzhiyun u32 design_cap;
142*4882a593Smuzhiyun int nac;
143*4882a593Smuzhiyun u32 *ocv_table;
144*4882a593Smuzhiyun u32 ocv_size;
145*4882a593Smuzhiyun int virtual_power;
146*4882a593Smuzhiyun int sample_res;
147*4882a593Smuzhiyun int pwroff_min;
148*4882a593Smuzhiyun int sm_old_cap;
149*4882a593Smuzhiyun int sm_linek;
150*4882a593Smuzhiyun int sm_chrg_dsoc;
151*4882a593Smuzhiyun int adc_allow_update;
152*4882a593Smuzhiyun int chrg_vol_sel;
153*4882a593Smuzhiyun int chrg_cur_input;
154*4882a593Smuzhiyun int chrg_cur_sel;
155*4882a593Smuzhiyun int dts_vol_sel;
156*4882a593Smuzhiyun int dts_cur_input;
157*4882a593Smuzhiyun int dts_cur_sel;
158*4882a593Smuzhiyun int max_soc_offset;
159*4882a593Smuzhiyun struct gpio_desc dc_det;
160*4882a593Smuzhiyun int dc_type;
161*4882a593Smuzhiyun int dc_det_adc;
162*4882a593Smuzhiyun ulong vol_mode_base;
163*4882a593Smuzhiyun ulong finish_chrg_base;
164*4882a593Smuzhiyun u8 calc_dsoc;
165*4882a593Smuzhiyun u8 calc_rsoc;
166*4882a593Smuzhiyun int sm_meet_soc;
167*4882a593Smuzhiyun u8 halt_cnt;
168*4882a593Smuzhiyun bool is_halt;
169*4882a593Smuzhiyun bool is_ocv_calib;
170*4882a593Smuzhiyun bool is_max_soc_offset;
171*4882a593Smuzhiyun bool is_first_power_on;
172*4882a593Smuzhiyun bool is_sw_reset;
173*4882a593Smuzhiyun int pwr_dsoc;
174*4882a593Smuzhiyun int pwr_rsoc;
175*4882a593Smuzhiyun int pwr_vol;
176*4882a593Smuzhiyun int res_fac;
177*4882a593Smuzhiyun int over_20mR;
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun enum charger_type {
181*4882a593Smuzhiyun NO_CHARGER = 0,
182*4882a593Smuzhiyun USB_CHARGER,
183*4882a593Smuzhiyun AC_CHARGER,
184*4882a593Smuzhiyun DC_CHARGER,
185*4882a593Smuzhiyun UNDEF_CHARGER,
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun enum dc_type {
189*4882a593Smuzhiyun DC_TYPE_OF_NONE = 0,
190*4882a593Smuzhiyun DC_TYPE_OF_GPIO,
191*4882a593Smuzhiyun DC_TYPE_OF_ADC,
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun static const char *charger_type_to_name[] = {
195*4882a593Smuzhiyun "NONE",
196*4882a593Smuzhiyun "USB",
197*4882a593Smuzhiyun "AC",
198*4882a593Smuzhiyun "DC",
199*4882a593Smuzhiyun "UNKN",
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /*
203*4882a593Smuzhiyun * If sample resistor changes, we need caculate a new CHRG_CUR_SEL[] table.
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * Calculation method:
206*4882a593Smuzhiyun * 1. find 20mR(default) current charge table, that is:
207*4882a593Smuzhiyun * 20mR: [1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400]
208*4882a593Smuzhiyun *
209*4882a593Smuzhiyun * 2. caculate Rfac(not care much, just using it) by sample resistor(ie. Rsam);
210*4882a593Smuzhiyun * Rsam = 20mR: Rfac = 10;
211*4882a593Smuzhiyun * Rsam > 20mR: Rfac = Rsam * 10 / 20;
212*4882a593Smuzhiyun * Rsam < 20mR: Rfac = 20 * 10 / Rsam;
213*4882a593Smuzhiyun *
214*4882a593Smuzhiyun * 3. from step2, we get Rfac, then we can get new charge current table by 20mR
215*4882a593Smuzhiyun * charge table:
216*4882a593Smuzhiyun * Iorg: member from 20mR charge table; Inew: new member for charge table.
217*4882a593Smuzhiyun *
218*4882a593Smuzhiyun * Rsam > 20mR: Inew = Iorg * 10 / Rfac;
219*4882a593Smuzhiyun * Rsam < 20mR: Inew = Iorg * Rfac / 10;
220*4882a593Smuzhiyun *
221*4882a593Smuzhiyun * Notice: Inew should round up if it is not a integer!!!
222*4882a593Smuzhiyun *
223*4882a593Smuzhiyun * Example:
224*4882a593Smuzhiyun * 10mR: [2000, 2400, 2800, 3200, 3600, 4000, 4500, 4800]
225*4882a593Smuzhiyun * 20mR: [1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400]
226*4882a593Smuzhiyun * 40mR: [500, 600, 700, 800, 900, 1000, 1125, 1200]
227*4882a593Smuzhiyun * 50mR: [400, 480, 560, 640, 720, 800, 900, 960]
228*4882a593Smuzhiyun * 60mR: [334, 400, 467, 534, 600, 667, 750, 800]
229*4882a593Smuzhiyun *
230*4882a593Smuzhiyun * You should add property 'sample_res = <Rsam>' at battery node.
231*4882a593Smuzhiyun */
232*4882a593Smuzhiyun static const u32 CHRG_VOL_SEL[] = {
233*4882a593Smuzhiyun 4050, 4100, 4150, 4200, 4250, 4300, 4350
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun static const u32 CHRG_CUR_SEL[] = {
237*4882a593Smuzhiyun 1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400
238*4882a593Smuzhiyun };
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static const u32 CHRG_CUR_INPUT[] = {
241*4882a593Smuzhiyun 450, 800, 850, 1000, 1250, 1500, 1750, 2000
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /* 'res_fac' has been *10, so we need divide 10 */
245*4882a593Smuzhiyun #define RES_FAC_MUX(value, res_fac) ((value) * res_fac / 10)
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* 'res_fac' has been *10, so we need 'value * 10' before divide 'res_fac' */
248*4882a593Smuzhiyun #define RES_FAC_DIV(value, res_fac) ((value) * 10 / res_fac)
249*4882a593Smuzhiyun
rk816_bat_read(struct battery_priv * di,u8 reg)250*4882a593Smuzhiyun static int rk816_bat_read(struct battery_priv *di, u8 reg)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun return pmic_reg_read(di->dev->parent, reg);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
rk816_bat_write(struct battery_priv * di,u8 reg,u8 buf)255*4882a593Smuzhiyun static void rk816_bat_write(struct battery_priv *di, u8 reg, u8 buf)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun pmic_reg_write(di->dev->parent, reg, buf);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
rk816_bat_dwc_otg_check_dpdm(void)260*4882a593Smuzhiyun static int rk816_bat_dwc_otg_check_dpdm(void)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun #if defined(CONFIG_PHY_ROCKCHIP_INNO_USB2) && !defined(CONFIG_SPL_BUILD)
263*4882a593Smuzhiyun return rockchip_chg_get_type();
264*4882a593Smuzhiyun #else
265*4882a593Smuzhiyun BAT_INFO("rockchip_chg_get_type() is not implement\n");
266*4882a593Smuzhiyun return NO_CHARGER;
267*4882a593Smuzhiyun #endif
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
rk816_bat_get_rsoc(struct battery_priv * di)270*4882a593Smuzhiyun static int rk816_bat_get_rsoc(struct battery_priv *di)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun return (di->remain_cap + di->fcc / 200) * 100 / DIV(di->fcc);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
rk816_bat_get_dsoc(struct battery_priv * di)275*4882a593Smuzhiyun static int rk816_bat_get_dsoc(struct battery_priv *di)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun return rk816_bat_read(di, SOC_REG);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
rk816_bat_enable_input_current(struct battery_priv * di)280*4882a593Smuzhiyun static void rk816_bat_enable_input_current(struct battery_priv *di)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun u8 val;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun val = rk816_bat_read(di, BAT_CTRL_REG);
285*4882a593Smuzhiyun val |= USB_SYS_EN;
286*4882a593Smuzhiyun rk816_bat_write(di, BAT_CTRL_REG, val);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
rk816_bat_enable_gauge(struct battery_priv * di)289*4882a593Smuzhiyun static void rk816_bat_enable_gauge(struct battery_priv *di)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun u8 val;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun val = rk816_bat_read(di, TS_CTRL_REG);
294*4882a593Smuzhiyun val |= GG_EN;
295*4882a593Smuzhiyun rk816_bat_write(di, TS_CTRL_REG, val);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
rk816_bat_set_vol_instant_mode(struct battery_priv * di)298*4882a593Smuzhiyun static void rk816_bat_set_vol_instant_mode(struct battery_priv *di)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun u8 val;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun val = rk816_bat_read(di, GGSTS_REG);
303*4882a593Smuzhiyun val |= VOL_INSTANT;
304*4882a593Smuzhiyun rk816_bat_write(di, GGSTS_REG, val);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
rk816_bat_set_vol_avg_mode(struct battery_priv * di)307*4882a593Smuzhiyun static void rk816_bat_set_vol_avg_mode(struct battery_priv *di)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun u8 val;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun val = rk816_bat_read(di, GGSTS_REG);
312*4882a593Smuzhiyun val &= ~VOL_AVG_MASK;
313*4882a593Smuzhiyun val |= VOL_AVG;
314*4882a593Smuzhiyun rk816_bat_write(di, GGSTS_REG, val);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
rk816_bat_get_vcalib0(struct battery_priv * di)317*4882a593Smuzhiyun static int rk816_bat_get_vcalib0(struct battery_priv *di)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun int val = 0;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun val |= rk816_bat_read(di, VCALIB0_REGL) << 0;
322*4882a593Smuzhiyun val |= rk816_bat_read(di, VCALIB0_REGH) << 8;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return val;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
rk816_bat_get_vcalib1(struct battery_priv * di)327*4882a593Smuzhiyun static int rk816_bat_get_vcalib1(struct battery_priv *di)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun int val = 0;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun val |= rk816_bat_read(di, VCALIB1_REGL) << 0;
332*4882a593Smuzhiyun val |= rk816_bat_read(di, VCALIB1_REGH) << 8;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun return val;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
rk816_bat_set_coffset(struct battery_priv * di,int val)337*4882a593Smuzhiyun static void rk816_bat_set_coffset(struct battery_priv *di, int val)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun u8 buf;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun buf = (val >> 0) & 0xff;
342*4882a593Smuzhiyun rk816_bat_write(di, CAL_OFFSET_REGL, buf);
343*4882a593Smuzhiyun buf = (val >> 8) & 0xff;
344*4882a593Smuzhiyun rk816_bat_write(di, CAL_OFFSET_REGH, buf);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
rk816_bat_get_ioffset(struct battery_priv * di)347*4882a593Smuzhiyun static int rk816_bat_get_ioffset(struct battery_priv *di)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun int val = 0;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun val |= rk816_bat_read(di, IOFFSET_REGL) << 0;
352*4882a593Smuzhiyun val |= rk816_bat_read(di, IOFFSET_REGH) << 8;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun return val;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
rk816_bat_save_dsoc(struct battery_priv * di,u8 save_soc)357*4882a593Smuzhiyun static void rk816_bat_save_dsoc(struct battery_priv *di, u8 save_soc)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun static int old_soc = -1;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (old_soc != save_soc) {
362*4882a593Smuzhiyun old_soc = save_soc;
363*4882a593Smuzhiyun rk816_bat_write(di, SOC_REG, save_soc);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
rk816_bat_save_cap(struct battery_priv * di,int cap)367*4882a593Smuzhiyun static void rk816_bat_save_cap(struct battery_priv *di, int cap)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun u8 buf;
370*4882a593Smuzhiyun static int old_cap;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (old_cap == cap)
373*4882a593Smuzhiyun return;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (cap >= di->qmax)
376*4882a593Smuzhiyun cap = di->qmax;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun old_cap = cap;
379*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
380*4882a593Smuzhiyun rk816_bat_write(di, REMAIN_CAP_REG3, buf);
381*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
382*4882a593Smuzhiyun rk816_bat_write(di, REMAIN_CAP_REG2, buf);
383*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
384*4882a593Smuzhiyun rk816_bat_write(di, REMAIN_CAP_REG1, buf);
385*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
386*4882a593Smuzhiyun rk816_bat_write(di, REMAIN_CAP_REG0, buf);
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
rk816_bat_init_voltage_kb(struct battery_priv * di)389*4882a593Smuzhiyun static void rk816_bat_init_voltage_kb(struct battery_priv *di)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun int vcalib0, vcalib1;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun vcalib0 = rk816_bat_get_vcalib0(di);
394*4882a593Smuzhiyun vcalib1 = rk816_bat_get_vcalib1(di);
395*4882a593Smuzhiyun di->voltage_k = (4200 - 3000) * 1000 / DIV(vcalib1 - vcalib0);
396*4882a593Smuzhiyun di->voltage_b = 4200 - (di->voltage_k * vcalib1) / 1000;
397*4882a593Smuzhiyun DBG("%s. vk=%d, vb=%d\n", __func__, di->voltage_k, di->voltage_b);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
rk816_bat_get_ocv_voltage(struct battery_priv * di)400*4882a593Smuzhiyun static int rk816_bat_get_ocv_voltage(struct battery_priv *di)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun int vol, val = 0;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_OCV_REGL) << 0;
405*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_OCV_REGH) << 8;
406*4882a593Smuzhiyun vol = di->voltage_k * val / 1000 + di->voltage_b;
407*4882a593Smuzhiyun vol = vol * 1100 / 1000;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun return vol;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
rk816_bat_get_avg_current(struct battery_priv * di)412*4882a593Smuzhiyun static int rk816_bat_get_avg_current(struct battery_priv *di)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun int cur, val = 0;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_CUR_AVG_REGL) << 0;
417*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_CUR_AVG_REGH) << 8;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (val & 0x800)
420*4882a593Smuzhiyun val -= 4096;
421*4882a593Smuzhiyun if (!di->over_20mR)
422*4882a593Smuzhiyun cur = RES_FAC_MUX(val * 1506, di->res_fac) / 1000;
423*4882a593Smuzhiyun else
424*4882a593Smuzhiyun cur = RES_FAC_DIV(val * 1506, di->res_fac) / 1000;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun return cur;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
rk816_bat_get_avg_voltage(struct battery_priv * di)429*4882a593Smuzhiyun static int rk816_bat_get_avg_voltage(struct battery_priv *di)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun int vol, val = 0;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_VOL_REGL) << 0;
434*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_VOL_REGH) << 8;
435*4882a593Smuzhiyun vol = di->voltage_k * val / 1000 + di->voltage_b;
436*4882a593Smuzhiyun vol = vol * 1100 / 1000;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun return vol;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
rk816_bat_get_est_voltage(struct battery_priv * di)441*4882a593Smuzhiyun static int rk816_bat_get_est_voltage(struct battery_priv *di)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun int est_vol, vol, curr;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun vol = rk816_bat_get_avg_voltage(di);
446*4882a593Smuzhiyun curr = rk816_bat_get_avg_current(di);
447*4882a593Smuzhiyun est_vol = vol - (di->bat_res * curr / 1000);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun return (est_vol > 2800) ? est_vol : vol;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
rk816_bat_finish_ma(struct battery_priv * di,int fcc)452*4882a593Smuzhiyun static u8 rk816_bat_finish_ma(struct battery_priv *di, int fcc)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun u8 ma;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (fcc > 5000)
457*4882a593Smuzhiyun ma = FINISH_250MA;
458*4882a593Smuzhiyun else if (fcc >= 4000)
459*4882a593Smuzhiyun ma = FINISH_200MA;
460*4882a593Smuzhiyun else if (fcc >= 3000)
461*4882a593Smuzhiyun ma = FINISH_150MA;
462*4882a593Smuzhiyun else
463*4882a593Smuzhiyun ma = FINISH_100MA;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun /* adjust ma according to sample resistor */
466*4882a593Smuzhiyun if (di->sample_res < 20) {
467*4882a593Smuzhiyun /* ma should div 2 */
468*4882a593Smuzhiyun if (ma == FINISH_200MA)
469*4882a593Smuzhiyun ma = FINISH_100MA;
470*4882a593Smuzhiyun else if (ma == FINISH_250MA)
471*4882a593Smuzhiyun ma = FINISH_150MA;
472*4882a593Smuzhiyun } else if (di->sample_res > 20) {
473*4882a593Smuzhiyun /* ma should mux 2 */
474*4882a593Smuzhiyun if (ma == FINISH_100MA)
475*4882a593Smuzhiyun ma = FINISH_200MA;
476*4882a593Smuzhiyun else if (ma == FINISH_150MA)
477*4882a593Smuzhiyun ma = FINISH_250MA;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun return ma;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
rk816_bat_select_chrg_cv(struct battery_priv * di)483*4882a593Smuzhiyun static void rk816_bat_select_chrg_cv(struct battery_priv *di)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun int index, chrg_vol_sel, chrg_cur_sel, chrg_cur_input;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun chrg_vol_sel = di->dts_vol_sel;
488*4882a593Smuzhiyun chrg_cur_sel = di->dts_cur_sel;
489*4882a593Smuzhiyun chrg_cur_input = di->dts_cur_input;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (di->sample_res < 20) {
492*4882a593Smuzhiyun if (chrg_cur_sel > 2000)
493*4882a593Smuzhiyun chrg_cur_sel = RES_FAC_DIV(chrg_cur_sel, di->res_fac);
494*4882a593Smuzhiyun else
495*4882a593Smuzhiyun chrg_cur_sel = 1000;
496*4882a593Smuzhiyun } else if (di->sample_res > 20) {
497*4882a593Smuzhiyun chrg_cur_sel = RES_FAC_MUX(chrg_cur_sel, di->res_fac);
498*4882a593Smuzhiyun if (chrg_cur_sel > 2400)
499*4882a593Smuzhiyun chrg_cur_sel = 2400;
500*4882a593Smuzhiyun if (chrg_cur_sel < 1000)
501*4882a593Smuzhiyun chrg_cur_sel = 1000;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_VOL_SEL); index++) {
505*4882a593Smuzhiyun if (chrg_vol_sel < CHRG_VOL_SEL[index])
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun di->chrg_vol_sel = (index << 4);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_CUR_INPUT); index++) {
511*4882a593Smuzhiyun if (chrg_cur_input < CHRG_CUR_INPUT[index])
512*4882a593Smuzhiyun break;
513*4882a593Smuzhiyun di->chrg_cur_input = (index << 0);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(CHRG_CUR_SEL); index++) {
517*4882a593Smuzhiyun if (chrg_cur_sel < CHRG_CUR_SEL[index])
518*4882a593Smuzhiyun break;
519*4882a593Smuzhiyun di->chrg_cur_sel = (index << 0);
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun DBG("<%s>. vol=0x%x, input=0x%x, sel=0x%x\n",
523*4882a593Smuzhiyun __func__, di->chrg_vol_sel, di->chrg_cur_input, di->chrg_cur_sel);
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
rk816_bat_init_chrg_config(struct battery_priv * di)526*4882a593Smuzhiyun static void rk816_bat_init_chrg_config(struct battery_priv *di)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun u8 chrg_ctrl1, usb_ctrl, chrg_ctrl2, chrg_ctrl3;
529*4882a593Smuzhiyun u8 sup_sts, ggcon, thermal, finish_ma;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun rk816_bat_select_chrg_cv(di);
532*4882a593Smuzhiyun finish_ma = rk816_bat_finish_ma(di, di->fcc);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun ggcon = rk816_bat_read(di, GGCON_REG);
535*4882a593Smuzhiyun sup_sts = rk816_bat_read(di, SUP_STS_REG);
536*4882a593Smuzhiyun usb_ctrl = rk816_bat_read(di, USB_CTRL_REG);
537*4882a593Smuzhiyun thermal = rk816_bat_read(di, THERMAL_REG);
538*4882a593Smuzhiyun chrg_ctrl2 = rk816_bat_read(di, CHRG_CTRL_REG2);
539*4882a593Smuzhiyun chrg_ctrl3 = rk816_bat_read(di, CHRG_CTRL_REG3);
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* set charge current and voltage */
542*4882a593Smuzhiyun usb_ctrl &= ~INPUT_CUR_MSK;
543*4882a593Smuzhiyun usb_ctrl |= di->chrg_cur_input;
544*4882a593Smuzhiyun chrg_ctrl1 = (CHRG_EN | di->chrg_vol_sel | di->chrg_cur_sel);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun /* digital signal and finish current*/
547*4882a593Smuzhiyun chrg_ctrl3 |= CHRG_TERM_DIG_SIGNAL;
548*4882a593Smuzhiyun chrg_ctrl2 &= ~FINISH_CUR_MSK;
549*4882a593Smuzhiyun chrg_ctrl2 |= finish_ma;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /* cccv mode */
552*4882a593Smuzhiyun chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /* enable voltage limit and enable input current limit */
555*4882a593Smuzhiyun sup_sts |= USB_VLIMIT_EN;
556*4882a593Smuzhiyun sup_sts |= USB_CLIMIT_EN;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /* set feedback temperature */
559*4882a593Smuzhiyun usb_ctrl |= CHRG_CT_EN;
560*4882a593Smuzhiyun thermal &= ~FB_TEMP_MSK;
561*4882a593Smuzhiyun thermal |= TEMP_115C;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun /* adc current mode */
564*4882a593Smuzhiyun ggcon |= ADC_CUR_MODE;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun rk816_bat_write(di, GGCON_REG, ggcon);
567*4882a593Smuzhiyun rk816_bat_write(di, SUP_STS_REG, sup_sts);
568*4882a593Smuzhiyun rk816_bat_write(di, USB_CTRL_REG, usb_ctrl);
569*4882a593Smuzhiyun rk816_bat_write(di, THERMAL_REG, thermal);
570*4882a593Smuzhiyun rk816_bat_write(di, CHRG_CTRL_REG1, chrg_ctrl1);
571*4882a593Smuzhiyun rk816_bat_write(di, CHRG_CTRL_REG2, chrg_ctrl2);
572*4882a593Smuzhiyun rk816_bat_write(di, CHRG_CTRL_REG3, chrg_ctrl3);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
interpolate(int value,u32 * table,int size)575*4882a593Smuzhiyun static u32 interpolate(int value, u32 *table, int size)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun uint8_t i;
578*4882a593Smuzhiyun uint16_t d;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun for (i = 0; i < size; i++) {
581*4882a593Smuzhiyun if (value < table[i])
582*4882a593Smuzhiyun break;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if ((i > 0) && (i < size)) {
586*4882a593Smuzhiyun d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1));
587*4882a593Smuzhiyun d /= table[i] - table[i - 1];
588*4882a593Smuzhiyun d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1));
589*4882a593Smuzhiyun } else {
590*4882a593Smuzhiyun d = i * ((MAX_INTERPOLATE + size / 2) / size);
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (d > 1000)
594*4882a593Smuzhiyun d = 1000;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun return d;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /* returns (a * b) / c */
ab_div_c(u32 a,u32 b,u32 c)600*4882a593Smuzhiyun static int32_t ab_div_c(u32 a, u32 b, u32 c)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun bool sign;
603*4882a593Smuzhiyun u32 ans = MAX_INT;
604*4882a593Smuzhiyun int32_t tmp;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun sign = ((((a ^ b) ^ c) & 0x80000000) != 0);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (c != 0) {
609*4882a593Smuzhiyun if (sign)
610*4882a593Smuzhiyun c = -c;
611*4882a593Smuzhiyun tmp = ((int32_t)a * b + (c >> 1)) / c;
612*4882a593Smuzhiyun if (tmp < MAX_INT)
613*4882a593Smuzhiyun ans = tmp;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun if (sign)
617*4882a593Smuzhiyun ans = -ans;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun return ans;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
rk816_bat_vol_to_cap(struct battery_priv * di,int voltage)622*4882a593Smuzhiyun static int rk816_bat_vol_to_cap(struct battery_priv *di, int voltage)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun u32 *ocv_table, tmp;
625*4882a593Smuzhiyun int ocv_size, ocv_cap;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun ocv_table = di->ocv_table;
628*4882a593Smuzhiyun ocv_size = di->ocv_size;
629*4882a593Smuzhiyun tmp = interpolate(voltage, ocv_table, ocv_size);
630*4882a593Smuzhiyun ocv_cap = ab_div_c(tmp, di->fcc, MAX_INTERPOLATE);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun return ocv_cap;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
rk816_bat_vol_to_soc(struct battery_priv * di,int voltage)635*4882a593Smuzhiyun static int rk816_bat_vol_to_soc(struct battery_priv *di, int voltage)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun u32 *ocv_table, tmp;
638*4882a593Smuzhiyun int ocv_size, ocv_soc;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun ocv_table = di->ocv_table;
641*4882a593Smuzhiyun ocv_size = di->ocv_size;
642*4882a593Smuzhiyun tmp = interpolate(voltage, ocv_table, ocv_size);
643*4882a593Smuzhiyun ocv_soc = ab_div_c(tmp, MAX_PERCENTAGE, MAX_INTERPOLATE);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun return ocv_soc;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
rk816_bat_get_prev_cap(struct battery_priv * di)648*4882a593Smuzhiyun static int rk816_bat_get_prev_cap(struct battery_priv *di)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun int val = 0;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun val |= rk816_bat_read(di, REMAIN_CAP_REG3) << 24;
653*4882a593Smuzhiyun val |= rk816_bat_read(di, REMAIN_CAP_REG2) << 16;
654*4882a593Smuzhiyun val |= rk816_bat_read(di, REMAIN_CAP_REG1) << 8;
655*4882a593Smuzhiyun val |= rk816_bat_read(di, REMAIN_CAP_REG0) << 0;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun return val;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
rk816_bat_save_fcc(struct battery_priv * di,u32 cap)660*4882a593Smuzhiyun static void rk816_bat_save_fcc(struct battery_priv *di, u32 cap)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun u8 buf;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
665*4882a593Smuzhiyun rk816_bat_write(di, NEW_FCC_REG3, buf);
666*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
667*4882a593Smuzhiyun rk816_bat_write(di, NEW_FCC_REG2, buf);
668*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
669*4882a593Smuzhiyun rk816_bat_write(di, NEW_FCC_REG1, buf);
670*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
671*4882a593Smuzhiyun rk816_bat_write(di, NEW_FCC_REG0, buf);
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
rk816_bat_get_fcc(struct battery_priv * di)674*4882a593Smuzhiyun static int rk816_bat_get_fcc(struct battery_priv *di)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun int val = 0;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun val |= rk816_bat_read(di, NEW_FCC_REG3) << 24;
679*4882a593Smuzhiyun val |= rk816_bat_read(di, NEW_FCC_REG2) << 16;
680*4882a593Smuzhiyun val |= rk816_bat_read(di, NEW_FCC_REG1) << 8;
681*4882a593Smuzhiyun val |= rk816_bat_read(di, NEW_FCC_REG0) << 0;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun if (val < MIN_FCC)
684*4882a593Smuzhiyun val = di->design_cap;
685*4882a593Smuzhiyun else if (val > di->qmax)
686*4882a593Smuzhiyun val = di->qmax;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun return val;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
rk816_bat_get_pwroff_min(struct battery_priv * di)691*4882a593Smuzhiyun static u8 rk816_bat_get_pwroff_min(struct battery_priv *di)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun u8 cur, last;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun cur = rk816_bat_read(di, NON_ACT_TIMER_CNT_REG);
696*4882a593Smuzhiyun last = rk816_bat_read(di, NON_ACT_TIMER_CNT_SAVE_REG);
697*4882a593Smuzhiyun rk816_bat_write(di, NON_ACT_TIMER_CNT_SAVE_REG, cur);
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun return (cur != last) ? cur : 0;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
rk816_bat_get_coulomb_cap(struct battery_priv * di)702*4882a593Smuzhiyun static int rk816_bat_get_coulomb_cap(struct battery_priv *di)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun int cap, val = 0;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun val |= rk816_bat_read(di, GASCNT_REG3) << 24;
707*4882a593Smuzhiyun val |= rk816_bat_read(di, GASCNT_REG2) << 16;
708*4882a593Smuzhiyun val |= rk816_bat_read(di, GASCNT_REG1) << 8;
709*4882a593Smuzhiyun val |= rk816_bat_read(di, GASCNT_REG0) << 0;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun if (!di->over_20mR)
712*4882a593Smuzhiyun cap = RES_FAC_MUX(val / 2390, di->res_fac);
713*4882a593Smuzhiyun else
714*4882a593Smuzhiyun cap = RES_FAC_DIV(val / 2390, di->res_fac);
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun return cap;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
rk816_bat_init_capacity(struct battery_priv * di,u32 capacity)719*4882a593Smuzhiyun static void rk816_bat_init_capacity(struct battery_priv *di, u32 capacity)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun u8 buf;
722*4882a593Smuzhiyun u32 cap;
723*4882a593Smuzhiyun int delta;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun delta = capacity - di->remain_cap;
726*4882a593Smuzhiyun if (!delta)
727*4882a593Smuzhiyun return;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun if (!di->over_20mR)
730*4882a593Smuzhiyun cap = RES_FAC_DIV(capacity * 2390, di->res_fac);
731*4882a593Smuzhiyun else
732*4882a593Smuzhiyun cap = RES_FAC_MUX(capacity * 2390, di->res_fac);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun buf = (cap >> 24) & 0xff;
735*4882a593Smuzhiyun rk816_bat_write(di, GASCNT_CAL_REG3, buf);
736*4882a593Smuzhiyun buf = (cap >> 16) & 0xff;
737*4882a593Smuzhiyun rk816_bat_write(di, GASCNT_CAL_REG2, buf);
738*4882a593Smuzhiyun buf = (cap >> 8) & 0xff;
739*4882a593Smuzhiyun rk816_bat_write(di, GASCNT_CAL_REG1, buf);
740*4882a593Smuzhiyun buf = (cap >> 0) & 0xff;
741*4882a593Smuzhiyun rk816_bat_write(di, GASCNT_CAL_REG0, buf);
742*4882a593Smuzhiyun udelay(75);
743*4882a593Smuzhiyun di->remain_cap = rk816_bat_get_coulomb_cap(di);
744*4882a593Smuzhiyun di->rsoc = rk816_bat_get_rsoc(di);
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
is_rk816_bat_ocv_valid(struct battery_priv * di)747*4882a593Smuzhiyun static bool is_rk816_bat_ocv_valid(struct battery_priv *di)
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun return di->pwroff_min >= 30 ? true : false;
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
rk816_bat_get_usb_state(struct battery_priv * di)752*4882a593Smuzhiyun static int rk816_bat_get_usb_state(struct battery_priv *di)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun int charger_type;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun switch (rk816_bat_dwc_otg_check_dpdm()) {
757*4882a593Smuzhiyun case 0:
758*4882a593Smuzhiyun if ((rk816_bat_read(di, VB_MON_REG) & PLUG_IN_STS) != 0)
759*4882a593Smuzhiyun charger_type = DC_CHARGER;
760*4882a593Smuzhiyun else
761*4882a593Smuzhiyun charger_type = NO_CHARGER;
762*4882a593Smuzhiyun break;
763*4882a593Smuzhiyun case 1:
764*4882a593Smuzhiyun case 3:
765*4882a593Smuzhiyun charger_type = USB_CHARGER;
766*4882a593Smuzhiyun break;
767*4882a593Smuzhiyun case 2:
768*4882a593Smuzhiyun case 4:
769*4882a593Smuzhiyun charger_type = AC_CHARGER;
770*4882a593Smuzhiyun break;
771*4882a593Smuzhiyun default:
772*4882a593Smuzhiyun charger_type = NO_CHARGER;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun return charger_type;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
rk816_bat_clr_initialized_state(struct battery_priv * di)778*4882a593Smuzhiyun static void rk816_bat_clr_initialized_state(struct battery_priv *di)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun u8 val;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun val = rk816_bat_read(di, MISC_MARK_REG);
783*4882a593Smuzhiyun val &= ~FG_INIT;
784*4882a593Smuzhiyun rk816_bat_write(di, MISC_MARK_REG, val);
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
rk816_bat_is_initialized(struct battery_priv * di)787*4882a593Smuzhiyun static bool rk816_bat_is_initialized(struct battery_priv *di)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun return (rk816_bat_read(di, MISC_MARK_REG) & FG_INIT) ? true : false;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
rk816_bat_set_initialized_state(struct battery_priv * di)792*4882a593Smuzhiyun static void rk816_bat_set_initialized_state(struct battery_priv *di)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun u8 val;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun val = rk816_bat_read(di, MISC_MARK_REG);
797*4882a593Smuzhiyun if (rk816_bat_get_usb_state(di) != NO_CHARGER) {
798*4882a593Smuzhiyun val |= FG_INIT;
799*4882a593Smuzhiyun rk816_bat_write(di, MISC_MARK_REG, val);
800*4882a593Smuzhiyun BAT_INFO("fuel gauge initialized... estv=%d, ch=%d\n",
801*4882a593Smuzhiyun rk816_bat_get_est_voltage(di),
802*4882a593Smuzhiyun rk816_bat_get_usb_state(di));
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
rk816_bat_first_pwron(struct battery_priv * di)806*4882a593Smuzhiyun static void rk816_bat_first_pwron(struct battery_priv *di)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun int ocv_vol;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun rk816_bat_save_fcc(di, di->design_cap);
811*4882a593Smuzhiyun ocv_vol = rk816_bat_get_ocv_voltage(di);
812*4882a593Smuzhiyun di->fcc = rk816_bat_get_fcc(di);
813*4882a593Smuzhiyun di->nac = rk816_bat_vol_to_cap(di, ocv_vol);
814*4882a593Smuzhiyun di->rsoc = rk816_bat_vol_to_soc(di, ocv_vol);
815*4882a593Smuzhiyun di->dsoc = di->rsoc;
816*4882a593Smuzhiyun rk816_bat_init_capacity(di, di->nac);
817*4882a593Smuzhiyun rk816_bat_set_initialized_state(di);
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun BAT_INFO("first power on: soc=%d\n", di->dsoc);
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
rk816_bat_get_halt_cnt(struct battery_priv * di)822*4882a593Smuzhiyun static u8 rk816_bat_get_halt_cnt(struct battery_priv *di)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun return rk816_bat_read(di, HALT_CNT_REG);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
rk816_bat_inc_halt_cnt(struct battery_priv * di)827*4882a593Smuzhiyun static void rk816_bat_inc_halt_cnt(struct battery_priv *di)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun u8 cnt;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun cnt = rk816_bat_read(di, HALT_CNT_REG);
832*4882a593Smuzhiyun rk816_bat_write(di, HALT_CNT_REG, ++cnt);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
is_rk816_bat_last_halt(struct battery_priv * di)835*4882a593Smuzhiyun static bool is_rk816_bat_last_halt(struct battery_priv *di)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun int pre_cap = rk816_bat_get_prev_cap(di);
838*4882a593Smuzhiyun int now_cap = rk816_bat_get_coulomb_cap(di);
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun /* over 5%: system halt last time */
841*4882a593Smuzhiyun if (abs(now_cap - pre_cap) > (di->fcc / 20)) {
842*4882a593Smuzhiyun rk816_bat_inc_halt_cnt(di);
843*4882a593Smuzhiyun return true;
844*4882a593Smuzhiyun } else {
845*4882a593Smuzhiyun return false;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
rk816_bat_not_first_pwron(struct battery_priv * di)849*4882a593Smuzhiyun static void rk816_bat_not_first_pwron(struct battery_priv *di)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun int pre_soc, pre_cap, ocv_cap, ocv_soc, ocv_vol, now_cap;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun di->fcc = rk816_bat_get_fcc(di);
854*4882a593Smuzhiyun pre_soc = rk816_bat_get_dsoc(di);
855*4882a593Smuzhiyun pre_cap = rk816_bat_get_prev_cap(di);
856*4882a593Smuzhiyun now_cap = rk816_bat_get_coulomb_cap(di);
857*4882a593Smuzhiyun di->pwr_dsoc = pre_soc;
858*4882a593Smuzhiyun di->pwr_rsoc = (now_cap + di->fcc / 200) * 100 / DIV(di->fcc);
859*4882a593Smuzhiyun di->is_halt = is_rk816_bat_last_halt(di);
860*4882a593Smuzhiyun di->halt_cnt = rk816_bat_get_halt_cnt(di);
861*4882a593Smuzhiyun di->is_ocv_calib = is_rk816_bat_ocv_valid(di);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (di->is_halt) {
864*4882a593Smuzhiyun BAT_INFO("system halt last time... cap: pre=%d, now=%d\n",
865*4882a593Smuzhiyun pre_cap, now_cap);
866*4882a593Smuzhiyun if (now_cap < 0)
867*4882a593Smuzhiyun now_cap = 0;
868*4882a593Smuzhiyun rk816_bat_init_capacity(di, now_cap);
869*4882a593Smuzhiyun pre_cap = di->remain_cap;
870*4882a593Smuzhiyun pre_soc = di->rsoc;
871*4882a593Smuzhiyun goto finish;
872*4882a593Smuzhiyun } else if (di->is_ocv_calib) {
873*4882a593Smuzhiyun ocv_vol = rk816_bat_get_ocv_voltage(di);
874*4882a593Smuzhiyun ocv_soc = rk816_bat_vol_to_soc(di, ocv_vol);
875*4882a593Smuzhiyun ocv_cap = rk816_bat_vol_to_cap(di, ocv_vol);
876*4882a593Smuzhiyun pre_cap = ocv_cap;
877*4882a593Smuzhiyun BAT_INFO("do ocv calib.. rsoc=%d\n", ocv_soc);
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun if (abs(ocv_soc - pre_soc) >= di->max_soc_offset) {
880*4882a593Smuzhiyun BAT_INFO("trigger max soc offset, soc: %d -> %d\n",
881*4882a593Smuzhiyun pre_soc, ocv_soc);
882*4882a593Smuzhiyun pre_soc = ocv_soc;
883*4882a593Smuzhiyun di->is_max_soc_offset = true;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun BAT_INFO("OCV calib: cap=%d, rsoc=%d\n", ocv_cap, ocv_soc);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun finish:
888*4882a593Smuzhiyun di->dsoc = pre_soc;
889*4882a593Smuzhiyun di->nac = pre_cap;
890*4882a593Smuzhiyun rk816_bat_init_capacity(di, di->nac);
891*4882a593Smuzhiyun rk816_bat_set_initialized_state(di);
892*4882a593Smuzhiyun BAT_INFO("dl=%d rl=%d cap=%d m=%d v=%d ov=%d c=%d pl=%d ch=%d Ver=%s\n",
893*4882a593Smuzhiyun di->dsoc, di->rsoc, di->remain_cap, di->pwroff_min,
894*4882a593Smuzhiyun rk816_bat_get_avg_voltage(di), rk816_bat_get_ocv_voltage(di),
895*4882a593Smuzhiyun rk816_bat_get_avg_current(di), rk816_bat_get_dsoc(di),
896*4882a593Smuzhiyun rk816_bat_get_usb_state(di), DRIVER_VERSION
897*4882a593Smuzhiyun );
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun
is_rk816_bat_first_poweron(struct battery_priv * di)900*4882a593Smuzhiyun static bool is_rk816_bat_first_poweron(struct battery_priv *di)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun u8 buf;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun buf = rk816_bat_read(di, GGSTS_REG);
905*4882a593Smuzhiyun if (buf & BAT_CON) {
906*4882a593Smuzhiyun buf &= ~BAT_CON;
907*4882a593Smuzhiyun rk816_bat_write(di, GGSTS_REG, buf);
908*4882a593Smuzhiyun return true;
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun return false;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun
rk816_bat_ocv_sw_reset(struct battery_priv * di)914*4882a593Smuzhiyun static bool rk816_bat_ocv_sw_reset(struct battery_priv *di)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun u8 buf;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun buf = rk816_bat_read(di, MISC_MARK_REG);
919*4882a593Smuzhiyun if (((buf & FG_RESET_LATE) && di->pwroff_min >= 30) ||
920*4882a593Smuzhiyun (buf & FG_RESET_NOW)) {
921*4882a593Smuzhiyun buf &= ~FG_RESET_LATE;
922*4882a593Smuzhiyun buf &= ~FG_RESET_NOW;
923*4882a593Smuzhiyun rk816_bat_write(di, MISC_MARK_REG, buf);
924*4882a593Smuzhiyun BAT_INFO("manual reset fuel gauge\n");
925*4882a593Smuzhiyun return true;
926*4882a593Smuzhiyun } else {
927*4882a593Smuzhiyun return false;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
rk816_bat_calc_linek(struct battery_priv * di)931*4882a593Smuzhiyun static int rk816_bat_calc_linek(struct battery_priv *di)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun int linek, diff, delta;
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun di->calc_dsoc = di->dsoc;
936*4882a593Smuzhiyun di->calc_rsoc = di->rsoc;
937*4882a593Smuzhiyun di->sm_old_cap = di->remain_cap;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun delta = abs(di->dsoc - di->rsoc);
940*4882a593Smuzhiyun diff = delta * 3;
941*4882a593Smuzhiyun di->sm_meet_soc = (di->dsoc >= di->rsoc) ?
942*4882a593Smuzhiyun (di->dsoc + diff) : (di->rsoc + diff);
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if (di->dsoc < di->rsoc)
945*4882a593Smuzhiyun linek = 1000 * (delta + diff) / DIV(diff);
946*4882a593Smuzhiyun else if (di->dsoc > di->rsoc)
947*4882a593Smuzhiyun linek = 1000 * diff / DIV(delta + diff);
948*4882a593Smuzhiyun else
949*4882a593Smuzhiyun linek = 1000;
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun DBG("<%s>. meet=%d, diff=%d, link=%d, calc: dsoc=%d, rsoc=%d\n",
954*4882a593Smuzhiyun __func__, di->sm_meet_soc, diff, linek,
955*4882a593Smuzhiyun di->calc_dsoc, di->calc_rsoc);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun return linek;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
rk816_bat_get_coffset(struct battery_priv * di)960*4882a593Smuzhiyun static int rk816_bat_get_coffset(struct battery_priv *di)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun int val = 0;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun val |= rk816_bat_read(di, CAL_OFFSET_REGL) << 0;
965*4882a593Smuzhiyun val |= rk816_bat_read(di, CAL_OFFSET_REGH) << 8;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun return val;
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
rk816_bat_init_poffset(struct battery_priv * di)970*4882a593Smuzhiyun static void rk816_bat_init_poffset(struct battery_priv *di)
971*4882a593Smuzhiyun {
972*4882a593Smuzhiyun int coffset, ioffset;
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun coffset = rk816_bat_get_coffset(di);
975*4882a593Smuzhiyun ioffset = rk816_bat_get_ioffset(di);
976*4882a593Smuzhiyun di->poffset = coffset - ioffset;
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
rk816_bat_select_sample_res(struct battery_priv * di)979*4882a593Smuzhiyun static void rk816_bat_select_sample_res(struct battery_priv *di)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun /* Here, res_fac is 10 times of real value for good calcuation */
982*4882a593Smuzhiyun if (di->sample_res == SAMPLE_RES_20MR) {
983*4882a593Smuzhiyun di->over_20mR = 0;
984*4882a593Smuzhiyun di->res_fac = 10;
985*4882a593Smuzhiyun } else if (di->sample_res > SAMPLE_RES_20MR) {
986*4882a593Smuzhiyun di->over_20mR = 1;
987*4882a593Smuzhiyun di->res_fac = di->sample_res * 10 / SAMPLE_RES_20MR;
988*4882a593Smuzhiyun } else {
989*4882a593Smuzhiyun di->over_20mR = 0;
990*4882a593Smuzhiyun di->res_fac = SAMPLE_RES_20MR * 10 / di->sample_res;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun }
is_rk816_bat_exist(struct battery_priv * di)993*4882a593Smuzhiyun static bool is_rk816_bat_exist(struct battery_priv *di)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun return (rk816_bat_read(di, SUP_STS_REG) & BAT_EXS) ? true : false;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun
rk816_bat_set_current(struct battery_priv * di,int input_current)998*4882a593Smuzhiyun static void rk816_bat_set_current(struct battery_priv *di, int input_current)
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun u8 usb_ctrl;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun usb_ctrl = rk816_bat_read(di, USB_CTRL_REG);
1003*4882a593Smuzhiyun usb_ctrl &= ~INPUT_CUR_MSK;
1004*4882a593Smuzhiyun usb_ctrl |= (input_current);
1005*4882a593Smuzhiyun rk816_bat_write(di, USB_CTRL_REG, usb_ctrl);
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun
rk816_bat_charger_setting(struct battery_priv * di,int charger)1008*4882a593Smuzhiyun static void rk816_bat_charger_setting(struct battery_priv *di, int charger)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun static u8 old_charger = UNDEF_CHARGER;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun /*charger changed*/
1013*4882a593Smuzhiyun if (old_charger != charger) {
1014*4882a593Smuzhiyun if (charger == NO_CHARGER)
1015*4882a593Smuzhiyun rk816_bat_set_current(di, ILIM_450MA);
1016*4882a593Smuzhiyun else if (charger == USB_CHARGER)
1017*4882a593Smuzhiyun rk816_bat_set_current(di, ILIM_450MA);
1018*4882a593Smuzhiyun else if (charger == DC_CHARGER || charger == AC_CHARGER)
1019*4882a593Smuzhiyun rk816_bat_set_current(di, di->chrg_cur_input);
1020*4882a593Smuzhiyun else
1021*4882a593Smuzhiyun BAT_INFO("charger setting error %d\n", charger);
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun old_charger = charger;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun
rk816_bat_get_dc_state(struct battery_priv * di)1027*4882a593Smuzhiyun static int rk816_bat_get_dc_state(struct battery_priv *di)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun /* struct adc_channel val; */
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun if (di->dc_type == DC_TYPE_OF_NONE) {
1032*4882a593Smuzhiyun return NO_CHARGER;
1033*4882a593Smuzhiyun } else if (di->dc_type == DC_TYPE_OF_ADC) {
1034*4882a593Smuzhiyun /*
1035*4882a593Smuzhiyun if (adc_channels_single_shot("saradc", 0, &val)) {
1036*4882a593Smuzhiyun printf("read saradc value failed\n");
1037*4882a593Smuzhiyun return NO_CHARGER;
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun return (val.data >= DC_ADC_TRIGGER) ? DC_CHARGER : NO_CHARGER;
1041*4882a593Smuzhiyun */
1042*4882a593Smuzhiyun return NO_CHARGER;
1043*4882a593Smuzhiyun } else {
1044*4882a593Smuzhiyun return (dm_gpio_get_value(&di->dc_det)) ?
1045*4882a593Smuzhiyun DC_CHARGER : NO_CHARGER;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun
rk816_bat_get_charger_type(struct battery_priv * di)1049*4882a593Smuzhiyun static int rk816_bat_get_charger_type(struct battery_priv *di)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun int charger_type = NO_CHARGER;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /* check by ic hardware: this check make check work safer */
1054*4882a593Smuzhiyun if ((rk816_bat_read(di, VB_MON_REG) & PLUG_IN_STS) == 0)
1055*4882a593Smuzhiyun return NO_CHARGER;
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun /* virtual or bat not exist */
1058*4882a593Smuzhiyun if (di->virtual_power)
1059*4882a593Smuzhiyun return DC_CHARGER;
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun /* check DC first */
1062*4882a593Smuzhiyun charger_type = rk816_bat_get_dc_state(di);
1063*4882a593Smuzhiyun if (charger_type == DC_CHARGER)
1064*4882a593Smuzhiyun return charger_type;
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun /* check USB second */
1067*4882a593Smuzhiyun return rk816_bat_get_usb_state(di);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
rk816_bat_need_initialize(struct battery_priv * di)1070*4882a593Smuzhiyun static bool rk816_bat_need_initialize(struct battery_priv *di)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun bool initialize = false;
1073*4882a593Smuzhiyun #ifdef CONFIG_DM_CHARGE_DISPLAY
1074*4882a593Smuzhiyun struct charge_animation_pdata *pdata;
1075*4882a593Smuzhiyun struct udevice *dev;
1076*4882a593Smuzhiyun int est_voltage;
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun if (!uclass_find_first_device(UCLASS_CHARGE_DISPLAY, &dev)) {
1079*4882a593Smuzhiyun pdata = dev_get_platdata(dev);
1080*4882a593Smuzhiyun est_voltage = rk816_bat_get_avg_voltage(di);
1081*4882a593Smuzhiyun if ((pdata->uboot_charge) ||
1082*4882a593Smuzhiyun (pdata->low_power_voltage >= est_voltage))
1083*4882a593Smuzhiyun initialize = true;
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun #endif
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun return initialize;
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun
rk816_bat_init_rsoc(struct battery_priv * di)1090*4882a593Smuzhiyun void rk816_bat_init_rsoc(struct battery_priv *di)
1091*4882a593Smuzhiyun {
1092*4882a593Smuzhiyun bool initialize = false;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun di->is_first_power_on = is_rk816_bat_first_poweron(di);
1095*4882a593Smuzhiyun /* If first power on, we must do initialization */
1096*4882a593Smuzhiyun if (di->is_first_power_on)
1097*4882a593Smuzhiyun initialize = true;
1098*4882a593Smuzhiyun /* Only charger online and under threshold, we do initialization */
1099*4882a593Smuzhiyun else if (rk816_bat_get_charger_type(di) != NO_CHARGER)
1100*4882a593Smuzhiyun initialize = rk816_bat_need_initialize(di);
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun printf("Fuel gauge initialize = %d\n", initialize);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun if (!initialize)
1105*4882a593Smuzhiyun return;
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun di->pwroff_min = rk816_bat_get_pwroff_min(di);
1108*4882a593Smuzhiyun di->is_sw_reset = rk816_bat_ocv_sw_reset(di);
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun if (di->is_first_power_on || di->is_sw_reset)
1111*4882a593Smuzhiyun rk816_bat_first_pwron(di);
1112*4882a593Smuzhiyun else
1113*4882a593Smuzhiyun rk816_bat_not_first_pwron(di);
1114*4882a593Smuzhiyun
1115*4882a593Smuzhiyun rk816_bat_save_dsoc(di, di->dsoc);
1116*4882a593Smuzhiyun rk816_bat_save_cap(di, di->remain_cap);
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
rk816_fg_init(struct battery_priv * di)1119*4882a593Smuzhiyun static int rk816_fg_init(struct battery_priv *di)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun rk816_bat_enable_input_current(di);
1122*4882a593Smuzhiyun rk816_bat_enable_gauge(di);
1123*4882a593Smuzhiyun rk816_bat_set_vol_instant_mode(di);
1124*4882a593Smuzhiyun rk816_bat_init_voltage_kb(di);
1125*4882a593Smuzhiyun rk816_bat_init_poffset(di);
1126*4882a593Smuzhiyun rk816_bat_select_sample_res(di);
1127*4882a593Smuzhiyun rk816_bat_clr_initialized_state(di);
1128*4882a593Smuzhiyun di->dsoc = rk816_bat_get_dsoc(di);
1129*4882a593Smuzhiyun di->remain_cap = rk816_bat_get_prev_cap(di);
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun /*
1132*4882a593Smuzhiyun * It's better to init fg in kernel,
1133*4882a593Smuzhiyun * so avoid init in uboot as far as possible.
1134*4882a593Smuzhiyun */
1135*4882a593Smuzhiyun rk816_bat_init_rsoc(di);
1136*4882a593Smuzhiyun rk816_bat_init_chrg_config(di);
1137*4882a593Smuzhiyun di->chrg_type = rk816_bat_get_charger_type(di);
1138*4882a593Smuzhiyun di->voltage_avg = rk816_bat_get_avg_voltage(di);
1139*4882a593Smuzhiyun di->voltage_ocv = rk816_bat_get_ocv_voltage(di);
1140*4882a593Smuzhiyun di->current_avg = rk816_bat_get_avg_current(di);
1141*4882a593Smuzhiyun di->sm_linek = rk816_bat_calc_linek(di);
1142*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1143*4882a593Smuzhiyun di->pwr_vol = di->voltage_avg;
1144*4882a593Smuzhiyun rk816_bat_charger_setting(di, di->chrg_type);
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun printf("Battery: soc=%d%%, cap=%dmAh, voltage=%dmv, Charger: %s%s\n",
1147*4882a593Smuzhiyun di->dsoc, di->remain_cap, di->voltage_avg,
1148*4882a593Smuzhiyun charger_type_to_name[di->chrg_type],
1149*4882a593Smuzhiyun di->virtual_power ? "(virtual)" : "");
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun return 0;
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun
rk816_bat_get_chrg_status(struct battery_priv * di)1154*4882a593Smuzhiyun static u8 rk816_bat_get_chrg_status(struct battery_priv *di)
1155*4882a593Smuzhiyun {
1156*4882a593Smuzhiyun u8 status;
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun status = rk816_bat_read(di, SUP_STS_REG) & BAT_STATUS_MSK;
1159*4882a593Smuzhiyun switch (status) {
1160*4882a593Smuzhiyun case CHARGE_OFF:
1161*4882a593Smuzhiyun DBG("CHARGE-OFF...\n");
1162*4882a593Smuzhiyun break;
1163*4882a593Smuzhiyun case DEAD_CHARGE:
1164*4882a593Smuzhiyun DBG("DEAD CHARGE...\n");
1165*4882a593Smuzhiyun break;
1166*4882a593Smuzhiyun case TRICKLE_CHARGE:
1167*4882a593Smuzhiyun DBG("TRICKLE CHARGE...\n ");
1168*4882a593Smuzhiyun break;
1169*4882a593Smuzhiyun case CC_OR_CV:
1170*4882a593Smuzhiyun DBG("CC or CV...\n");
1171*4882a593Smuzhiyun break;
1172*4882a593Smuzhiyun case CHARGE_FINISH:
1173*4882a593Smuzhiyun DBG("CHARGE FINISH...\n");
1174*4882a593Smuzhiyun break;
1175*4882a593Smuzhiyun case USB_OVER_VOL:
1176*4882a593Smuzhiyun DBG("USB OVER VOL...\n");
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun case BAT_TMP_ERR:
1179*4882a593Smuzhiyun DBG("BAT TMP ERROR...\n");
1180*4882a593Smuzhiyun break;
1181*4882a593Smuzhiyun case TIMER_ERR:
1182*4882a593Smuzhiyun DBG("TIMER ERROR...\n");
1183*4882a593Smuzhiyun break;
1184*4882a593Smuzhiyun case USB_EXIST:
1185*4882a593Smuzhiyun DBG("USB EXIST...\n");
1186*4882a593Smuzhiyun break;
1187*4882a593Smuzhiyun case USB_EFF:
1188*4882a593Smuzhiyun DBG(" USB EFF...\n");
1189*4882a593Smuzhiyun break;
1190*4882a593Smuzhiyun default:
1191*4882a593Smuzhiyun return -EINVAL;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun return status;
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun
rk816_bat_finish_chrg(struct battery_priv * di)1197*4882a593Smuzhiyun static void rk816_bat_finish_chrg(struct battery_priv *di)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun u32 tgt_sec = 0;
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun if (di->dsoc < 100) {
1202*4882a593Smuzhiyun tgt_sec = di->fcc * 3600 / 100 / FINISH_CALI_CURR;
1203*4882a593Smuzhiyun if (get_timer(di->finish_chrg_base) > SECONDS(tgt_sec)) {
1204*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1205*4882a593Smuzhiyun di->dsoc++;
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun DBG("<%s>. sec=%d, finish_sec=%lu\n", __func__, SECONDS(tgt_sec),
1209*4882a593Smuzhiyun get_timer(di->finish_chrg_base));
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun
rk816_bat_debug_info(struct battery_priv * di)1212*4882a593Smuzhiyun static void rk816_bat_debug_info(struct battery_priv *di)
1213*4882a593Smuzhiyun {
1214*4882a593Smuzhiyun u8 sup_sts, ggcon, ggsts, vb_mod, rtc, thermal, misc;
1215*4882a593Smuzhiyun u8 usb_ctrl, chrg_ctrl1, chrg_ctrl2, chrg_ctrl3;
1216*4882a593Smuzhiyun uint32_t chrg_cur;
1217*4882a593Smuzhiyun static const char *name[] = {"NONE", "USB", "AC", "DC", "UNDEF"};
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun if (!dbg_enable)
1220*4882a593Smuzhiyun return;
1221*4882a593Smuzhiyun ggcon = rk816_bat_read(di, GGCON_REG);
1222*4882a593Smuzhiyun ggsts = rk816_bat_read(di, GGSTS_REG);
1223*4882a593Smuzhiyun sup_sts = rk816_bat_read(di, SUP_STS_REG);
1224*4882a593Smuzhiyun usb_ctrl = rk816_bat_read(di, USB_CTRL_REG);
1225*4882a593Smuzhiyun thermal = rk816_bat_read(di, THERMAL_REG);
1226*4882a593Smuzhiyun vb_mod = rk816_bat_read(di, VB_MON_REG);
1227*4882a593Smuzhiyun misc = rk816_bat_read(di, MISC_MARK_REG);
1228*4882a593Smuzhiyun rtc = rk816_bat_read(di, SECONDS_REG);
1229*4882a593Smuzhiyun chrg_ctrl1 = rk816_bat_read(di, CHRG_CTRL_REG1);
1230*4882a593Smuzhiyun chrg_ctrl2 = rk816_bat_read(di, CHRG_CTRL_REG2);
1231*4882a593Smuzhiyun chrg_ctrl3 = rk816_bat_read(di, CHRG_CTRL_REG3);
1232*4882a593Smuzhiyun if (!di->over_20mR)
1233*4882a593Smuzhiyun chrg_cur = RES_FAC_MUX(CHRG_CUR_SEL[chrg_ctrl1 & 0x0f],
1234*4882a593Smuzhiyun di->res_fac);
1235*4882a593Smuzhiyun else
1236*4882a593Smuzhiyun chrg_cur = RES_FAC_DIV(CHRG_CUR_SEL[chrg_ctrl1 & 0x0f],
1237*4882a593Smuzhiyun di->res_fac);
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun DBG("\n---------------------- DEBUG REGS ------------------------\n"
1240*4882a593Smuzhiyun "GGCON=0x%2x, GGSTS=0x%2x, RTC=0x%2x, SUP_STS= 0x%2x\n"
1241*4882a593Smuzhiyun "VB_MOD=0x%2x, USB_CTRL=0x%2x, THERMAL=0x%2x, MISC=0x%2x\n"
1242*4882a593Smuzhiyun "CHRG_CTRL:REG1=0x%2x, REG2=0x%2x, REG3=0x%2x\n",
1243*4882a593Smuzhiyun ggcon, ggsts, rtc, sup_sts, vb_mod, usb_ctrl,
1244*4882a593Smuzhiyun thermal, misc, chrg_ctrl1, chrg_ctrl2, chrg_ctrl3
1245*4882a593Smuzhiyun );
1246*4882a593Smuzhiyun DBG("----------------------------------------------------------\n"
1247*4882a593Smuzhiyun "Dsoc=%d, Rsoc=%d, Vavg=%d, Iavg=%d, Cap=%d, Fcc=%d, d=%d\n"
1248*4882a593Smuzhiyun "K=%d, old_cap=%d, charger=%s, Is=%d, Ip=%d, Vs=%d, Rfac=%d\n"
1249*4882a593Smuzhiyun "min=%d, meet: soc=%d, calc: dsoc=%d, rsoc=%d, Vocv=%d, Rsam=%d\n"
1250*4882a593Smuzhiyun "off: i=0x%x, c=0x%x, max=%d, ocv_c=%d, halt: st=%d, cnt=%d\n"
1251*4882a593Smuzhiyun "pwr: dsoc=%d, rsoc=%d, vol=%d, exist=%d\n",
1252*4882a593Smuzhiyun di->dsoc, rk816_bat_get_rsoc(di), rk816_bat_get_avg_voltage(di),
1253*4882a593Smuzhiyun rk816_bat_get_avg_current(di), di->remain_cap, di->fcc,
1254*4882a593Smuzhiyun di->rsoc - di->dsoc,
1255*4882a593Smuzhiyun di->sm_linek, di->sm_old_cap, name[di->chrg_type],
1256*4882a593Smuzhiyun chrg_cur,
1257*4882a593Smuzhiyun CHRG_CUR_INPUT[usb_ctrl & 0x0f],
1258*4882a593Smuzhiyun CHRG_VOL_SEL[(chrg_ctrl1 & 0x70) >> 4], di->res_fac,
1259*4882a593Smuzhiyun di->pwroff_min,
1260*4882a593Smuzhiyun di->sm_meet_soc, di->calc_dsoc, di->calc_rsoc,
1261*4882a593Smuzhiyun rk816_bat_get_ocv_voltage(di), di->sample_res,
1262*4882a593Smuzhiyun rk816_bat_get_ioffset(di),
1263*4882a593Smuzhiyun rk816_bat_get_coffset(di), di->is_max_soc_offset,
1264*4882a593Smuzhiyun di->is_ocv_calib, di->is_halt, di->halt_cnt, di->pwr_dsoc,
1265*4882a593Smuzhiyun di->pwr_rsoc, di->pwr_vol, is_rk816_bat_exist(di)
1266*4882a593Smuzhiyun );
1267*4882a593Smuzhiyun rk816_bat_get_chrg_status(di);
1268*4882a593Smuzhiyun DBG("###########################################################\n");
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun
rk816_bat_linek_algorithm(struct battery_priv * di)1271*4882a593Smuzhiyun static void rk816_bat_linek_algorithm(struct battery_priv *di)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun int delta_cap, ydsoc, tmp;
1274*4882a593Smuzhiyun u8 chg_st = rk816_bat_get_chrg_status(di);
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun /* slow down */
1277*4882a593Smuzhiyun if (di->dsoc == 99)
1278*4882a593Smuzhiyun di->sm_linek = CHRG_FULL_K;
1279*4882a593Smuzhiyun else if (di->dsoc >= CHRG_TERM_DSOC && di->current_avg > TERM_CALI_CURR)
1280*4882a593Smuzhiyun di->sm_linek = CHRG_TERM_K;
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun delta_cap = di->remain_cap - di->sm_old_cap;
1283*4882a593Smuzhiyun ydsoc = di->sm_linek * delta_cap * 100 / DIV(di->fcc);
1284*4882a593Smuzhiyun if (ydsoc > 0) {
1285*4882a593Smuzhiyun tmp = (di->sm_chrg_dsoc + 1) / 1000;
1286*4882a593Smuzhiyun if (tmp != di->dsoc)
1287*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
1288*4882a593Smuzhiyun di->sm_chrg_dsoc += ydsoc;
1289*4882a593Smuzhiyun di->dsoc = (di->sm_chrg_dsoc + 1) / 1000;
1290*4882a593Smuzhiyun di->sm_old_cap = di->remain_cap;
1291*4882a593Smuzhiyun if (di->dsoc == di->rsoc && di->sm_linek != CHRG_FULL_K &&
1292*4882a593Smuzhiyun di->sm_linek != CHRG_TERM_K)
1293*4882a593Smuzhiyun di->sm_linek = 1000;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
1296*4882a593Smuzhiyun if ((di->sm_linek == 1000 || di->dsoc >= 100) &&
1297*4882a593Smuzhiyun (chg_st != CHARGE_FINISH)) {
1298*4882a593Smuzhiyun if (di->sm_linek == 1000)
1299*4882a593Smuzhiyun di->dsoc = di->rsoc;
1300*4882a593Smuzhiyun di->sm_chrg_dsoc = di->dsoc * 1000;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun DBG("linek=%d, sm_dsoc=%d, delta_cap=%d, ydsoc=%d, old_cap=%d\n"
1304*4882a593Smuzhiyun "calc: dsoc=%d, rsoc=%d, meet=%d\n",
1305*4882a593Smuzhiyun di->sm_linek, di->sm_chrg_dsoc, delta_cap, ydsoc, di->sm_old_cap,
1306*4882a593Smuzhiyun di->calc_dsoc, di->calc_rsoc, di->sm_meet_soc);
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun
rk816_bat_get_iadc(struct battery_priv * di)1309*4882a593Smuzhiyun static int rk816_bat_get_iadc(struct battery_priv *di)
1310*4882a593Smuzhiyun {
1311*4882a593Smuzhiyun int val = 0;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_CUR_AVG_REGL) << 0;
1314*4882a593Smuzhiyun val |= rk816_bat_read(di, BAT_CUR_AVG_REGH) << 8;
1315*4882a593Smuzhiyun if (val > 2047)
1316*4882a593Smuzhiyun val -= 4096;
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun return val;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun
rk816_bat_adc_calib(struct battery_priv * di)1321*4882a593Smuzhiyun static bool rk816_bat_adc_calib(struct battery_priv *di)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun int i, ioffset, coffset, adc;
1324*4882a593Smuzhiyun
1325*4882a593Smuzhiyun if (abs(di->current_avg) < ADC_CALIB_THRESHOLD)
1326*4882a593Smuzhiyun return false;
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
1329*4882a593Smuzhiyun adc = rk816_bat_get_iadc(di);
1330*4882a593Smuzhiyun coffset = rk816_bat_get_coffset(di);
1331*4882a593Smuzhiyun rk816_bat_set_coffset(di, coffset + adc);
1332*4882a593Smuzhiyun mdelay(200);
1333*4882a593Smuzhiyun adc = rk816_bat_get_iadc(di);
1334*4882a593Smuzhiyun if (abs(adc) < ADC_CALIB_THRESHOLD) {
1335*4882a593Smuzhiyun coffset = rk816_bat_get_coffset(di);
1336*4882a593Smuzhiyun ioffset = rk816_bat_get_ioffset(di);
1337*4882a593Smuzhiyun di->poffset = coffset - ioffset;
1338*4882a593Smuzhiyun rk816_bat_write(di, POFFSET_REG, di->poffset);
1339*4882a593Smuzhiyun BAT_INFO("new offset:c=0x%x, i=0x%x, p=0x%x\n",
1340*4882a593Smuzhiyun coffset, ioffset, di->poffset);
1341*4882a593Smuzhiyun return true;
1342*4882a593Smuzhiyun } else {
1343*4882a593Smuzhiyun BAT_INFO("coffset calib again %d..\n", i);
1344*4882a593Smuzhiyun rk816_bat_set_coffset(di, coffset);
1345*4882a593Smuzhiyun mdelay(200);
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun return false;
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun
rk816_bat_smooth_charge(struct battery_priv * di)1352*4882a593Smuzhiyun static void rk816_bat_smooth_charge(struct battery_priv *di)
1353*4882a593Smuzhiyun {
1354*4882a593Smuzhiyun u8 chg_st = rk816_bat_get_chrg_status(di);
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun if (di->vol_mode_base && get_timer(di->vol_mode_base) > SECONDS(10)) {
1357*4882a593Smuzhiyun rk816_bat_set_vol_avg_mode(di);
1358*4882a593Smuzhiyun di->vol_mode_base = 0;
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun /* not charge mode and not keep in uboot charge: exit */
1362*4882a593Smuzhiyun if ((di->chrg_type == NO_CHARGER) ||
1363*4882a593Smuzhiyun !rk816_bat_is_initialized(di)) {
1364*4882a593Smuzhiyun DBG("chrg=%d, initialized=%d\n", di->chrg_type,
1365*4882a593Smuzhiyun rk816_bat_is_initialized(di));
1366*4882a593Smuzhiyun goto out;
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun /* update rsoc and remain cap */
1370*4882a593Smuzhiyun di->remain_cap = rk816_bat_get_coulomb_cap(di);
1371*4882a593Smuzhiyun di->rsoc = rk816_bat_get_rsoc(di);
1372*4882a593Smuzhiyun if (di->remain_cap > di->fcc) {
1373*4882a593Smuzhiyun di->sm_old_cap -= (di->remain_cap - di->fcc);
1374*4882a593Smuzhiyun rk816_bat_init_capacity(di, di->fcc);
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun /* finish charge step */
1378*4882a593Smuzhiyun if (chg_st == CHARGE_FINISH) {
1379*4882a593Smuzhiyun DBG("finish charge step...\n");
1380*4882a593Smuzhiyun if (di->adc_allow_update)
1381*4882a593Smuzhiyun di->adc_allow_update = !rk816_bat_adc_calib(di);
1382*4882a593Smuzhiyun rk816_bat_finish_chrg(di);
1383*4882a593Smuzhiyun rk816_bat_init_capacity(di, di->fcc);
1384*4882a593Smuzhiyun } else {
1385*4882a593Smuzhiyun DBG("smooth charge step...\n");
1386*4882a593Smuzhiyun di->adc_allow_update = true;
1387*4882a593Smuzhiyun di->finish_chrg_base = get_timer(0);
1388*4882a593Smuzhiyun rk816_bat_linek_algorithm(di);
1389*4882a593Smuzhiyun }
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun /* dsoc limit */
1392*4882a593Smuzhiyun if (di->dsoc > 100)
1393*4882a593Smuzhiyun di->dsoc = 100;
1394*4882a593Smuzhiyun else if (di->dsoc < 0)
1395*4882a593Smuzhiyun di->dsoc = 0;
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun rk816_bat_save_dsoc(di, di->dsoc);
1398*4882a593Smuzhiyun rk816_bat_save_cap(di, di->remain_cap);
1399*4882a593Smuzhiyun out:
1400*4882a593Smuzhiyun rk816_bat_debug_info(di);
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun
rk816_bat_bat_is_exit(struct udevice * dev)1403*4882a593Smuzhiyun static int rk816_bat_bat_is_exit(struct udevice *dev)
1404*4882a593Smuzhiyun {
1405*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun return is_rk816_bat_exist(di);
1408*4882a593Smuzhiyun }
1409*4882a593Smuzhiyun
rk816_bat_update_get_soc(struct udevice * dev)1410*4882a593Smuzhiyun static int rk816_bat_update_get_soc(struct udevice *dev)
1411*4882a593Smuzhiyun {
1412*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1413*4882a593Smuzhiyun static ulong seconds;
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun /* set charge current */
1416*4882a593Smuzhiyun di->chrg_type =
1417*4882a593Smuzhiyun rk816_bat_get_charger_type(di);
1418*4882a593Smuzhiyun rk816_bat_charger_setting(di, di->chrg_type);
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun /* fg calc every 5 seconds */
1421*4882a593Smuzhiyun if (!seconds)
1422*4882a593Smuzhiyun seconds = get_timer(0);
1423*4882a593Smuzhiyun if (get_timer(seconds) >= SECONDS(5)) {
1424*4882a593Smuzhiyun seconds = get_timer(0);
1425*4882a593Smuzhiyun rk816_bat_smooth_charge(di);
1426*4882a593Smuzhiyun }
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun /* bat exist, fg init success(dts pass) and uboot charge: report data */
1429*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1430*4882a593Smuzhiyun return di->dsoc;
1431*4882a593Smuzhiyun else
1432*4882a593Smuzhiyun return VIRTUAL_POWER_SOC;
1433*4882a593Smuzhiyun }
1434*4882a593Smuzhiyun
rk816_bat_update_get_voltage(struct udevice * dev)1435*4882a593Smuzhiyun static int rk816_bat_update_get_voltage(struct udevice *dev)
1436*4882a593Smuzhiyun {
1437*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1440*4882a593Smuzhiyun return rk816_bat_get_est_voltage(di);
1441*4882a593Smuzhiyun else
1442*4882a593Smuzhiyun return VIRTUAL_POWER_VOL;
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun
rk816_bat_update_get_current(struct udevice * dev)1445*4882a593Smuzhiyun static int rk816_bat_update_get_current(struct udevice *dev)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun if (!di->virtual_power && di->voltage_k)
1450*4882a593Smuzhiyun return rk816_bat_get_avg_current(di);
1451*4882a593Smuzhiyun else
1452*4882a593Smuzhiyun return VIRTUAL_POWER_CUR;
1453*4882a593Smuzhiyun }
1454*4882a593Smuzhiyun
rk816_bat_update_get_chrg_online(struct udevice * dev)1455*4882a593Smuzhiyun static bool rk816_bat_update_get_chrg_online(struct udevice *dev)
1456*4882a593Smuzhiyun {
1457*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun return rk816_bat_get_charger_type(di);
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun
1462*4882a593Smuzhiyun static struct dm_fuel_gauge_ops fg_ops = {
1463*4882a593Smuzhiyun .bat_is_exist = rk816_bat_bat_is_exit,
1464*4882a593Smuzhiyun .get_soc = rk816_bat_update_get_soc,
1465*4882a593Smuzhiyun .get_voltage = rk816_bat_update_get_voltage,
1466*4882a593Smuzhiyun .get_current = rk816_bat_update_get_current,
1467*4882a593Smuzhiyun .get_chrg_online = rk816_bat_update_get_chrg_online,
1468*4882a593Smuzhiyun };
1469*4882a593Smuzhiyun
rk816_fg_ofdata_to_platdata(struct udevice * dev)1470*4882a593Smuzhiyun static int rk816_fg_ofdata_to_platdata(struct udevice *dev)
1471*4882a593Smuzhiyun {
1472*4882a593Smuzhiyun struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
1473*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1474*4882a593Smuzhiyun const char *prop;
1475*4882a593Smuzhiyun int len;
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun if (rk8xx->variant != 0x8160) {
1478*4882a593Smuzhiyun debug("%s: Not support pmic variant: rk%x\n",
1479*4882a593Smuzhiyun __func__, rk8xx->variant);
1480*4882a593Smuzhiyun return -EINVAL;
1481*4882a593Smuzhiyun } else {
1482*4882a593Smuzhiyun di->dev = dev;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun /* Parse ocv table */
1486*4882a593Smuzhiyun prop = dev_read_prop(dev, "ocv_table", &len);
1487*4882a593Smuzhiyun if (!prop) {
1488*4882a593Smuzhiyun printf("can't find ocv_table prop\n");
1489*4882a593Smuzhiyun return -EINVAL;
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun di->ocv_table = calloc(len, 1);
1493*4882a593Smuzhiyun if (!di->ocv_table) {
1494*4882a593Smuzhiyun printf("can't calloc ocv_table\n");
1495*4882a593Smuzhiyun return -ENOMEM;
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun di->ocv_size = len / 4;
1499*4882a593Smuzhiyun if (dev_read_u32_array(dev, "ocv_table",
1500*4882a593Smuzhiyun di->ocv_table, di->ocv_size)) {
1501*4882a593Smuzhiyun printf("can't read ocv_table\n");
1502*4882a593Smuzhiyun free(di->ocv_table);
1503*4882a593Smuzhiyun return -EINVAL;
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun /* Parse neccessay */
1507*4882a593Smuzhiyun di->design_cap = dev_read_u32_default(dev, "design_capacity", -1);
1508*4882a593Smuzhiyun if (di->design_cap < 0) {
1509*4882a593Smuzhiyun printf("can't read design_capacity\n");
1510*4882a593Smuzhiyun return -EINVAL;
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun di->qmax = dev_read_u32_default(dev, "design_qmax", -1);
1514*4882a593Smuzhiyun if (di->qmax < 0) {
1515*4882a593Smuzhiyun printf("can't read design_qmax\n");
1516*4882a593Smuzhiyun return -EINVAL;
1517*4882a593Smuzhiyun }
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun /* Parse un-neccessay */
1520*4882a593Smuzhiyun di->dts_vol_sel = dev_read_u32_default(dev, "max_chrg_voltage", 4200);
1521*4882a593Smuzhiyun di->dts_cur_input = dev_read_u32_default(dev, "max_input_current", 2000);
1522*4882a593Smuzhiyun di->dts_cur_sel = dev_read_u32_default(dev, "max_chrg_current", 1200);
1523*4882a593Smuzhiyun di->max_soc_offset = dev_read_u32_default(dev, "max_soc_offset", 70);
1524*4882a593Smuzhiyun di->virtual_power = dev_read_u32_default(dev, "virtual_power", 0);
1525*4882a593Smuzhiyun di->sample_res = dev_read_u32_default(dev, "sample_res", 20);
1526*4882a593Smuzhiyun di->bat_res = dev_read_u32_default(dev, "bat_res", 135);
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun /* Parse dc type */
1529*4882a593Smuzhiyun di->dc_det_adc = dev_read_u32_default(dev, "dc_det_adc", 0);
1530*4882a593Smuzhiyun if (di->dc_det_adc <= 0) {
1531*4882a593Smuzhiyun if (!gpio_request_by_name_nodev(dev_ofnode(dev), "dc_det_gpio",
1532*4882a593Smuzhiyun 0, &di->dc_det, GPIOD_IS_IN)) {
1533*4882a593Smuzhiyun di->dc_type = DC_TYPE_OF_GPIO;
1534*4882a593Smuzhiyun } else {
1535*4882a593Smuzhiyun di->dc_type = DC_TYPE_OF_NONE;
1536*4882a593Smuzhiyun }
1537*4882a593Smuzhiyun } else {
1538*4882a593Smuzhiyun di->dc_type = DC_TYPE_OF_ADC;
1539*4882a593Smuzhiyun }
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun /* Is battery attached */
1542*4882a593Smuzhiyun if (!is_rk816_bat_exist(di))
1543*4882a593Smuzhiyun di->virtual_power = 1;
1544*4882a593Smuzhiyun
1545*4882a593Smuzhiyun DBG("-------------------------------:\n");
1546*4882a593Smuzhiyun DBG("max_input_current:%d\n", di->dts_cur_input);
1547*4882a593Smuzhiyun DBG("max_chrg_current:%d\n", di->dts_cur_sel);
1548*4882a593Smuzhiyun DBG("max_chrg_voltage:%d\n", di->dts_vol_sel);
1549*4882a593Smuzhiyun DBG("design_capacity :%d\n", di->design_cap);
1550*4882a593Smuzhiyun DBG("design_qmax:%d\n", di->qmax);
1551*4882a593Smuzhiyun DBG("max_soc_offset:%d\n", di->max_soc_offset);
1552*4882a593Smuzhiyun DBG("dc_det_adc:%d\n", di->dc_det_adc);
1553*4882a593Smuzhiyun DBG("res_sample:%d\n", di->sample_res);
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun return 0;
1556*4882a593Smuzhiyun }
1557*4882a593Smuzhiyun
rk816_fg_probe(struct udevice * dev)1558*4882a593Smuzhiyun static int rk816_fg_probe(struct udevice *dev)
1559*4882a593Smuzhiyun {
1560*4882a593Smuzhiyun struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
1561*4882a593Smuzhiyun struct battery_priv *di = dev_get_priv(dev);
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun if (rk8xx->variant != 0x8160) {
1564*4882a593Smuzhiyun printf("Not support pmic variant: rk%x\n", rk8xx->variant);
1565*4882a593Smuzhiyun return -EINVAL;
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun
1568*4882a593Smuzhiyun return rk816_fg_init(di);
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun U_BOOT_DRIVER(rk816_fg) = {
1572*4882a593Smuzhiyun .name = "rk816_fg",
1573*4882a593Smuzhiyun .id = UCLASS_FG,
1574*4882a593Smuzhiyun .probe = rk816_fg_probe,
1575*4882a593Smuzhiyun .ops = &fg_ops,
1576*4882a593Smuzhiyun .ofdata_to_platdata = rk816_fg_ofdata_to_platdata,
1577*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct battery_priv),
1578*4882a593Smuzhiyun };
1579