From 8edcc9702a9240a56f02acf0906748c131f0ca13 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Tue, 18 Feb 2025 17:11:34 +0100
Subject: [PATCH 356/484] power: supply: rk818-battery: Re-organize code

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/power/supply/rk818_battery.c | 1147 +++++++++++++-------------
 1 file changed, 596 insertions(+), 551 deletions(-)

diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c
index 13dfbfed544b..b2a2a4b105c5 100644
--- a/drivers/power/supply/rk818_battery.c
+++ b/drivers/power/supply/rk818_battery.c
@@ -1,20 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * rk818 battery driver
- *
  * Copyright (C) 2016 Rockchip Electronics Co., Ltd
  * chenjh <chenjh@rock-chips.com>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * Modified by: Ondrej Jirman <megi@xff.cz> 2025
  *
+ * - allow integration into charger driver
+ * - split up into marked sections for easier orientation
  */
 
+// {{{ Includes
+
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/gpio.h>
@@ -37,6 +34,9 @@
 
 #include "rk818_battery.h"
 
+// }}}
+// {{{ Constants/macros
+
 /* RK818_INT_STS_MSK_REG2 */
 #define PLUG_IN_MSK		BIT(0)
 #define PLUG_OUT_MSK		BIT(1)
@@ -121,35 +121,6 @@
 #define MAX_INTERPOLATE		1000
 #define MAX_INT			0x7FFF
 
-#define DRIVER_VERSION		"7.1"
-
-struct battery_platform_data {
-	u32 *ocv_table;
-	u32 *zero_table;
-	u32 *ntc_table;
-	u32 ocv_size;
-	u32 max_chrg_voltage;
-	u32 ntc_size;
-	int ntc_degree_from;
-	u32 pwroff_vol;
-	u32 monitor_sec;
-	u32 zero_algorithm_vol;
-	u32 zero_reserve_dsoc;
-	u32 bat_res;
-	u32 design_capacity;
-	u32 design_qmax;
-	u32 sleep_enter_current;
-	u32 sleep_exit_current;
-	u32 max_soc_offset;
-	u32 sample_res;
-	u32 bat_mode;
-	u32 fb_temp;
-	u32 energy_mode;
-	u32 cccv_hour;
-	u32 ntc_uA;
-	u32 ntc_factor;
-};
-
 enum work_mode {
 	MODE_ZERO = 0,
 	MODE_FINISH,
@@ -163,34 +134,6 @@ enum bat_mode {
 	MODE_MISSING,
 };
 
-static const u16 feedback_temp_array[] = {
-	85, 95, 105, 115
-};
-
-static const u16 chrg_vol_sel_array[] = {
-	4050, 4100, 4150, 4200, 4250, 4300, 4350
-};
-
-static const u16 chrg_cur_sel_array[] = {
-	1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400, 2600, 2800, 3000
-};
-
-static const u16 chrg_cur_input_array[] = {
-	450, 80, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
-};
-
-static int dbg_enable = 0;
-module_param_named(dbg_level, dbg_enable, int, 0644);
-
-#define DBG(args...) \
-	do { \
-		if (dbg_enable) { \
-			pr_info(args); \
-		} \
-	} while (0)
-
-#define BAT_INFO(fmt, args...) pr_info("rk818-bat: "fmt, ##args)
-
 /* default param */
 #define DEFAULT_BAT_RES			135
 #define DEFAULT_SLP_ENTER_CUR		300
@@ -281,11 +224,75 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
 #define NTC_40UA_MAX_MEASURE		55000
 #define NTC_20UA_MAX_MEASURE		110000
 
+// }}}
+// {{{ Data arrays
+
 static const char *bat_status[] = {
 	"charge off", "dead charge", "trickle charge", "cc cv",
 	"finish", "usb over vol", "bat temp error", "timer error",
 };
 
+static const u16 feedback_temp_array[] = {
+	85, 95, 105, 115
+};
+
+static const u16 chrg_vol_sel_array[] = {
+	4050, 4100, 4150, 4200, 4250, 4300, 4350
+};
+
+static const u16 chrg_cur_sel_array[] = {
+	1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400, 2600, 2800, 3000
+};
+
+static const u16 chrg_cur_input_array[] = {
+	450, 80, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
+};
+
+// }}}
+// {{{ Debug macros
+
+static int dbg_enable = 0;
+module_param_named(dbg_level, dbg_enable, int, 0644);
+
+#define DBG(args...) \
+	do { \
+		if (dbg_enable) { \
+			pr_info(args); \
+		} \
+	} while (0)
+
+#define BAT_INFO(fmt, args...) pr_info("rk818-bat: "fmt, ##args)
+
+// }}}
+// {{{ Main struct
+
+struct battery_platform_data {
+	u32 *ocv_table;
+	u32 *zero_table;
+	u32 *ntc_table;
+	u32 ocv_size;
+	u32 max_chrg_voltage;
+	u32 ntc_size;
+	int ntc_degree_from;
+	u32 pwroff_vol;
+	u32 monitor_sec;
+	u32 zero_algorithm_vol;
+	u32 zero_reserve_dsoc;
+	u32 bat_res;
+	u32 design_capacity;
+	u32 design_qmax;
+	u32 sleep_enter_current;
+	u32 sleep_exit_current;
+	u32 max_soc_offset;
+	u32 sample_res;
+	u32 bat_mode;
+	u32 fb_temp;
+	u32 energy_mode;
+	u32 cccv_hour;
+	u32 ntc_uA;
+	u32 ntc_factor;
+};
+
 struct rk818_battery {
 	struct platform_device		*pdev;
 	struct rk808			*rk818;
@@ -379,6 +386,9 @@ struct rk818_battery {
 	unsigned long			charge_count;
 };
 
+// }}}
+// {{{ Utils (time/avg)
+
 #define DIV(x)	((x) ? (x) : 1)
 
 static u64 get_boot_sec(void)
@@ -449,6 +459,9 @@ static int32_t ab_div_c(u32 a, u32 b, u32 c)
 	return ans;
 }
 
+// }}}
+// {{{ Register access helpers
+
 static int rk818_bat_read(struct rk818_battery *di, u8 reg)
 {
 	int ret, val;
@@ -494,6 +507,9 @@ static void rk818_bat_dump_regs(struct rk818_battery *di, u8 start, u8 end)
 		DBG("0x%x: 0x%0x\n", i, rk818_bat_read(di, i));
 }
 
+// }}}
+// {{{ SoC Algorithm
+
 static bool rk818_bat_chrg_online(struct rk818_battery *di)
 {
 	u8 buf;
@@ -961,60 +977,6 @@ static int rk818_bat_get_charge_state(struct rk818_battery *di)
 	return di->current_avg > 0;
 }
 
-int rk818_battery_get_property(struct rk818_battery *di,
-			       enum power_supply_property psp,
-			       union power_supply_propval *val)
-{
-	switch (psp) {
-	case POWER_SUPPLY_PROP_CURRENT_NOW:
-		val->intval = rk818_bat_get_avg_current(di) * 1000;/*uA*/
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = 0;
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = rk818_bat_get_avg_voltage(di) * 1000;/*uV*/
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = 0;
-		break;
-	case POWER_SUPPLY_PROP_PRESENT:
-		val->intval = is_rk818_bat_exist(di);
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = 0;
-		break;
-	case POWER_SUPPLY_PROP_CAPACITY:
-		val->intval = di->dsoc;
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = 100;
-		break;
-	case POWER_SUPPLY_PROP_TEMP:
-		val->intval = di->temperature;
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = 0;
-		break;
-	case POWER_SUPPLY_PROP_STATUS:
-		if (di->pdata->bat_mode == MODE_MISSING)
-			val->intval = POWER_SUPPLY_STATUS_FULL;
-		else if (di->dsoc == 100)
-			val->intval = POWER_SUPPLY_STATUS_FULL;
-		else if (rk818_bat_get_charge_state(di))
-			val->intval = POWER_SUPPLY_STATUS_CHARGING;
-		else
-			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-		break;
-	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
-		val->intval = di->charge_count;
-		break;
-	case POWER_SUPPLY_PROP_CHARGE_FULL:
-		val->intval = di->pdata->design_capacity * 1000;/* uAh */
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rk818_battery_get_property);
-
 static void rk818_bat_save_cap(struct rk818_battery *di, int cap)
 {
 	u8 buf;
@@ -1328,136 +1290,38 @@ static u8 rk818_bat_parse_finish_ma(struct rk818_battery *di, int fcc)
 	return ma;
 }
 
-static void rk818_bat_init_chrg_config(struct rk818_battery *di)
-{
-	u8 usb_ctrl, chrg_ctrl2, chrg_ctrl3;
-	u8 thermal, ggcon, finish_ma, fb_temp;
-
-	finish_ma = rk818_bat_parse_finish_ma(di, di->fcc);
-	fb_temp = rk818_bat_parse_fb_temperature(di);
-
-	ggcon = rk818_bat_read(di, RK818_GGCON_REG);
-	thermal = rk818_bat_read(di, RK818_THERMAL_REG);
-	usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG);
-	chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2);
-	chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3);
-
-	/* set charge finish current */
-	chrg_ctrl3 |= CHRG_TERM_DIG_SIGNAL;
-	chrg_ctrl2 &= ~FINISH_CUR_MSK;
-	chrg_ctrl2 |= finish_ma;
-
-	/* disable cccv mode */
-	chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN;
-
-	/* set feed back temperature */
-	if (di->pdata->fb_temp)
-		usb_ctrl |= CHRG_CT_EN;
-	else
-		usb_ctrl &= ~CHRG_CT_EN;
-	thermal &= ~FB_TEMP_MSK;
-	thermal |= fb_temp;
-
-	/* adc current mode */
-	ggcon |= ADC_CUR_MODE;
-
-	rk818_bat_write(di, RK818_GGCON_REG, ggcon);
-	rk818_bat_write(di, RK818_THERMAL_REG, thermal);
-	rk818_bat_write(di, RK818_USB_CTRL_REG, usb_ctrl);
-	rk818_bat_write(di, RK818_CHRG_CTRL_REG2, chrg_ctrl2);
-	rk818_bat_write(di, RK818_CHRG_CTRL_REG3, chrg_ctrl3);
-}
-
-static void rk818_bat_init_coffset(struct rk818_battery *di)
+static void rk818_bat_init_zero_table(struct rk818_battery *di)
 {
-	int coffset, ioffset;
+	int i, diff, min, max;
+	size_t ocv_size, length;
 
-	ioffset = rk818_bat_get_ioffset(di);
-	di->poffset = rk818_bat_read(di, RK818_POFFSET_REG);
-	if (!di->poffset)
-		di->poffset = DEFAULT_POFFSET;
+	ocv_size = di->pdata->ocv_size;
+	length = sizeof(di->pdata->zero_table) * ocv_size;
+	di->pdata->zero_table =
+			devm_kzalloc(di->dev, length, GFP_KERNEL);
+	if (!di->pdata->zero_table) {
+		di->pdata->zero_table = di->pdata->ocv_table;
+		dev_err(di->dev, "malloc zero table fail\n");
+		return;
+	}
 
-	coffset = di->poffset + ioffset;
-	if (coffset < INVALID_COFFSET_MIN || coffset > INVALID_COFFSET_MAX)
-		coffset = DEFAULT_COFFSET;
+	min = di->pdata->pwroff_vol,
+	max = di->pdata->ocv_table[ocv_size - 4];
+	diff = (max - min) / DIV(ocv_size - 1);
+	for (i = 0; i < ocv_size; i++)
+		di->pdata->zero_table[i] = min + (i * diff);
 
-	rk818_bat_set_coffset(di, coffset);
+	for (i = 0; i < ocv_size; i++)
+		DBG("zero[%d] = %d\n", i, di->pdata->zero_table[i]);
 
-	DBG("<%s>. offset: p=0x%x, i=0x%x, c=0x%x\n",
-	    __func__, di->poffset, ioffset, rk818_bat_get_coffset(di));
+	for (i = 0; i < ocv_size; i++)
+		DBG("ocv[%d] = %d\n", i, di->pdata->ocv_table[i]);
 }
 
-static void rk818_bat_caltimer_isr(struct timer_list *t)
+static void rk818_bat_calc_sm_linek(struct rk818_battery *di)
 {
-	struct rk818_battery *di = from_timer(di, t, caltimer);
-
-	mod_timer(&di->caltimer, jiffies + MINUTE(8) * HZ);
-	queue_delayed_work(di->bat_monitor_wq, &di->calib_delay_work,
-			   msecs_to_jiffies(10));
-}
-
-static void rk818_bat_internal_calib(struct work_struct *work)
-{
-	int ioffset, poffset;
-	struct rk818_battery *di = container_of(work,
-			struct rk818_battery, calib_delay_work.work);
-
-	/* calib coffset */
-	poffset = rk818_bat_read(di, RK818_POFFSET_REG);
-	if (poffset)
-		di->poffset = poffset;
-	else
-		di->poffset = DEFAULT_POFFSET;
-
-	ioffset = rk818_bat_get_ioffset(di);
-	rk818_bat_set_coffset(di, ioffset + di->poffset);
-
-	/* calib voltage kb */
-	rk818_bat_init_voltage_kb(di);
-	BAT_INFO("caltimer: ioffset=0x%x, coffset=0x%x, poffset=%d\n",
-		 ioffset, rk818_bat_get_coffset(di), di->poffset);
-}
-
-static void rk818_bat_init_caltimer(struct rk818_battery *di)
-{
-	timer_setup(&di->caltimer, rk818_bat_caltimer_isr, 0);
-	di->caltimer.expires = jiffies + MINUTE(8) * HZ;
-	add_timer(&di->caltimer);
-	INIT_DELAYED_WORK(&di->calib_delay_work, rk818_bat_internal_calib);
-}
-
-static void rk818_bat_init_zero_table(struct rk818_battery *di)
-{
-	int i, diff, min, max;
-	size_t ocv_size, length;
-
-	ocv_size = di->pdata->ocv_size;
-	length = sizeof(di->pdata->zero_table) * ocv_size;
-	di->pdata->zero_table =
-			devm_kzalloc(di->dev, length, GFP_KERNEL);
-	if (!di->pdata->zero_table) {
-		di->pdata->zero_table = di->pdata->ocv_table;
-		dev_err(di->dev, "malloc zero table fail\n");
-		return;
-	}
-
-	min = di->pdata->pwroff_vol,
-	max = di->pdata->ocv_table[ocv_size - 4];
-	diff = (max - min) / DIV(ocv_size - 1);
-	for (i = 0; i < ocv_size; i++)
-		di->pdata->zero_table[i] = min + (i * diff);
-
-	for (i = 0; i < ocv_size; i++)
-		DBG("zero[%d] = %d\n", i, di->pdata->zero_table[i]);
-
-	for (i = 0; i < ocv_size; i++)
-		DBG("ocv[%d] = %d\n", i, di->pdata->ocv_table[i]);
-}
-
-static void rk818_bat_calc_sm_linek(struct rk818_battery *di)
-{
-	int linek, current_avg;
-	u8 diff, delta;
+	int linek, current_avg;
+	u8 diff, delta;
 
 	delta = abs(di->dsoc - di->rsoc);
 	diff = delta * 3;/* speed:3/4 */
@@ -1851,14 +1715,14 @@ static void rk818_bat_debug_info(struct rk818_battery *di)
 	dcdc_en = rk818_bat_read(di, RK818_DCDC_EN_REG);
 	reboot_cnt = rk818_bat_read(di, RK818_REBOOT_CNT_REG);
 
-	DBG("\n------- DEBUG REGS, [Ver: %s] -------------------\n"
+	DBG("\n------- DEBUG REGS -------------------\n"
 	    "GGCON=0x%2x, GGSTS=0x%2x, RTC=0x%2x, DCDC_EN2=0x%2x\n"
 	    "SUP_STS= 0x%2x, VB_MOD=0x%2x, USB_CTRL=0x%2x\n"
 	    "THERMAL=0x%2x, MISC_MARK=0x%2x, TS_CTRL=0x%2x\n"
 	    "CHRG_CTRL:REG1=0x%2x, REG2=0x%2x, REG3=0x%2x\n"
 	    "INT_STS:  REG1=0x%2x, REG2=0x%2x\n"
 	    "INT_MSK:  REG1=0x%2x, REG2=0x%2x\n",
-	    DRIVER_VERSION, ggcon, ggsts, rtc, dcdc_en,
+	    ggcon, ggsts, rtc, dcdc_en,
 	    sup_tst, vb_mod, usb_ctrl,
 	    thermal, misc, ts_ctrl,
 	    chrg_ctrl1, chrg_ctrl2, chrg_ctrl3,
@@ -2545,174 +2409,6 @@ static void rk818_bat_update_info(struct rk818_battery *di)
 	}
 }
 
-static void rk818_bat_init_ts1_detect(struct rk818_battery *di)
-{
-	u8 buf;
-	u32 *ntc_table = di->pdata->ntc_table;
-
-	if (!di->pdata->ntc_size)
-		return;
-
-	/* select ua */
-	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
-	buf &= ~TS1_CUR_MSK;
-	/* chose suitable UA for temperature detect */
-	if (ntc_table[0] < NTC_80UA_MAX_MEASURE) {
-		di->pdata->ntc_factor = NTC_CALC_FACTOR_80UA;
-		di->pdata->ntc_uA = 80;
-		buf |= ADC_CUR_80UA;
-	} else if (ntc_table[0] < NTC_60UA_MAX_MEASURE) {
-		di->pdata->ntc_factor = NTC_CALC_FACTOR_60UA;
-		di->pdata->ntc_uA = 60;
-		buf |= ADC_CUR_60UA;
-	} else if (ntc_table[0] < NTC_40UA_MAX_MEASURE) {
-		di->pdata->ntc_factor = NTC_CALC_FACTOR_40UA;
-		di->pdata->ntc_uA = 40;
-		buf |= ADC_CUR_40UA;
-	} else {
-		di->pdata->ntc_factor = NTC_CALC_FACTOR_20UA;
-		di->pdata->ntc_uA = 20;
-		buf |= ADC_CUR_20UA;
-	}
-	rk818_bat_write(di, RK818_TS_CTRL_REG, buf);
-
-	/* enable ADC_TS1_EN */
-	buf = rk818_bat_read(di, RK818_ADC_CTRL_REG);
-	buf |= ADC_TS1_EN;
-	rk818_bat_write(di, RK818_ADC_CTRL_REG, buf);
-}
-
-/*
- * Due to hardware design issue, Vdelta = "(R_sample + R_other) * I_avg" will be
- * included into TS1 adc value. We must subtract it to get correct adc value.
- * The solution:
- *
- * (1) calculate Vdelta:
- *
- *   adc1 - Vdelta    ua1			  (adc2 * ua1) - (adc1 * ua2)
- *   ------------- = -----  ==> equals: Vdelta = -----------------------------
- *   adc2 - Vdelta    ua2				ua1 - ua2
- *
- *
- * (2) calculate correct ADC value:
- *
- *     charging: ADC = adc1 - abs(Vdelta);
- *  discharging: ADC = adc1 + abs(Vdelta);
- */
-static int rk818_bat_get_ntc_res(struct rk818_battery *di)
-{
-	int adc1 = 0, adc2 = 0;
-	int ua1, ua2, v_delta, res, val;
-	u8 buf;
-
-	/* read sample ua1 */
-	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
-	DBG("<%s>. read adc1, sample uA=%d\n",
-	    __func__, ((buf & 0x03) + 1) * 20);
-
-	/* read adc adc1 */
-	ua1 = di->pdata->ntc_uA;
-	adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0;
-	adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8;
-
-	/* chose reference UA for adc2 */
-	ua2 = (ua1 != 20) ? 20 : 40;
-	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
-	buf &= ~TS1_CUR_MSK;
-	buf |= ((ua2 - 20) / 20);
-	rk818_bat_write(di, RK818_TS_CTRL_REG, buf);
-
-	/* read adc adc2 */
-	msleep(1000);
-
-	/* read sample ua2 */
-	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
-	DBG("<%s>. read adc2, sample uA=%d\n",
-	    __func__, ((buf & 0x03) + 1) * 20);
-
-	adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0;
-	adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8;
-
-	DBG("<%s>. ua1=%d, ua2=%d, adc1=%d, adc2=%d\n",
-	    __func__, ua1, ua2, adc1, adc2);
-
-	/* calculate delta voltage */
-	if (adc2 != adc1)
-		v_delta = abs((adc2 * ua1 - adc1 * ua2) / (ua2 - ua1));
-	else
-		v_delta = 0;
-
-	/* considering current avg direction, calcuate real adc value */
-	val = (di->current_avg >= 0) ? (adc1 - v_delta) : (adc1 + v_delta);
-
-	DBG("<%s>. Iavg=%d, Vdelta=%d, Vadc=%d\n",
-	    __func__, di->current_avg, v_delta, val);
-
-	res = val * di->pdata->ntc_factor;
-
-	DBG("<%s>. val=%d, ntc_res=%d, ntc_factor=%d, Rdelta=%d\n",
-	    __func__, val, res, di->pdata->ntc_factor,
-	    v_delta * di->pdata->ntc_factor);
-
-	DBG("<%s>. t=[%d'C(%d) ~ %dC(%d)]\n", __func__,
-	    di->pdata->ntc_degree_from, di->pdata->ntc_table[0],
-	    di->pdata->ntc_degree_from + di->pdata->ntc_size - 1,
-	    di->pdata->ntc_table[di->pdata->ntc_size - 1]);
-
-	rk818_bat_init_ts1_detect(di);
-
-	return res;
-}
-
-static void rk818_bat_update_temperature(struct rk818_battery *di)
-{
-	static int old_temp, first_time = 1;
-	u32 ntc_size, *ntc_table;
-	int i, res, temp;
-
-	ntc_table = di->pdata->ntc_table;
-	ntc_size = di->pdata->ntc_size;
-	di->temperature = 200;
-
-	if (ntc_size) {
-		res = rk818_bat_get_ntc_res(di);
-		if (res < ntc_table[ntc_size - 1]) {
-			di->temperature = di->pdata->ntc_degree_from +
-					  di->pdata->ntc_size - 1;
-			BAT_INFO("bat ntc upper max degree: R=%d\n", res);
-		} else if (res > ntc_table[0]) {
-			di->temperature = di->pdata->ntc_degree_from;
-			BAT_INFO("bat ntc lower min degree: R=%d\n", res);
-		} else {
-			for (i = 0; i < ntc_size; i++) {
-				if (res >= ntc_table[i])
-					break;
-			}
-
-			/* if first in, init old_temp */
-			temp = (i + di->pdata->ntc_degree_from) * 10;
-			if (first_time == 1) {
-				di->temperature = temp;
-				old_temp = temp;
-				first_time = 0;
-			}
-
-			/*
-			 * compare with old one, it's invalid when over 50
-			 * and we should use old data.
-			 */
-			if (abs(temp - old_temp) > 50)
-				temp = old_temp;
-			else
-				old_temp = temp;
-
-			di->temperature = temp;
-			DBG("<%s>. temperature = %d\n",
-			    __func__, di->temperature);
-		}
-	}
-}
-
 static void rk818_bat_init_dsoc_algorithm(struct rk818_battery *di)
 {
 	u8 buf;
@@ -2890,121 +2586,424 @@ static void rk818_bat_save_data(struct rk818_battery *di)
 	rk818_bat_save_algo_rest(di);
 }
 
-static void rk818_battery_work(struct work_struct *work)
+static time64_t rk818_get_rtc_sec(void)
 {
-	struct rk818_battery *di =
-		container_of(work, struct rk818_battery, bat_delay_work.work);
+	int err;
+	struct rtc_time tm;
+	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
 
-	rk818_bat_update_info(di);
-	rk818_bat_wait_finish_sig(di);
-	rk818_bat_rsoc_daemon(di);
-	rk818_bat_update_temperature(di);
-	rk818_bat_display_smooth(di);
-	rk818_bat_power_supply_changed(di);
-	rk818_bat_save_data(di);
-	rk818_bat_debug_info(di);
+	err = rtc_read_time(rtc, &tm);
+	if (err) {
+		dev_err(rtc->dev.parent, "read hardware clk failed\n");
+		return 0;
+	}
 
-	queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
-			   msecs_to_jiffies(di->monitor_ms));
-}
+	err = rtc_valid_tm(&tm);
+	if (err) {
+		dev_err(rtc->dev.parent, "invalid date time\n");
+		return 0;
+	}
 
-static irqreturn_t rk818_vb_low_irq(int irq, void *bat)
+	return rtc_tm_to_time64(&tm);
+}
+
+static int rk818_bat_rtc_sleep_sec(struct rk818_battery *di)
 {
-	struct rk818_battery *di = (struct rk818_battery *)bat;
+	int interval_sec;
 
-	BAT_INFO("lower power yet, power off system! v=%d, c=%d, dsoc=%d\n",
-		 di->voltage_avg, di->current_avg, di->dsoc);
+	interval_sec = rk818_get_rtc_sec() - di->rtc_base;
 
-	return IRQ_HANDLED;
+	return (interval_sec > 0) ? interval_sec : 0;
 }
 
-static int rk818_bat_init_irqs(struct rk818_battery *di)
+static void rk818_bat_set_shtd_vol(struct rk818_battery *di)
 {
-	struct rk808 *rk818 = di->rk818;
-	struct platform_device *pdev = di->pdev;
-	int ret, vb_lo_irq;
+	u8 val;
 
-	vb_lo_irq = regmap_irq_get_virq(rk818->irq_data, RK818_IRQ_VB_LO);
-	if (vb_lo_irq < 0) {
-		dev_err(di->dev, "vb_lo_irq request failed!\n");
-		return vb_lo_irq;
+#if 0
+	/* set vbat lowest 3.0v shutdown */
+	val = rk818_bat_read(di, RK818_VB_MON_REG);
+	val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK);
+	val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN);
+	rk818_bat_write(di, RK818_VB_MON_REG, val);
+
+	/* disable low irq */
+	rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1,
+			   VB_LOW_INT_EN, VB_LOW_INT_EN);
+#endif
+
+	val = rk818_bat_read(di, RK818_VB_MON_REG);
+	val &= (~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK));
+	val |= (RK818_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ);
+	rk818_bat_write(di, RK818_VB_MON_REG, val);
+	rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, VB_LOW_INT_EN, 0);
+}
+
+// }}}
+// {{{ Temperature
+
+static void rk818_bat_init_ts1_detect(struct rk818_battery *di)
+{
+	u8 buf;
+	u32 *ntc_table = di->pdata->ntc_table;
+
+	if (!di->pdata->ntc_size)
+		return;
+
+	/* select ua */
+	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
+	buf &= ~TS1_CUR_MSK;
+	/* chose suitable UA for temperature detect */
+	if (ntc_table[0] < NTC_80UA_MAX_MEASURE) {
+		di->pdata->ntc_factor = NTC_CALC_FACTOR_80UA;
+		di->pdata->ntc_uA = 80;
+		buf |= ADC_CUR_80UA;
+	} else if (ntc_table[0] < NTC_60UA_MAX_MEASURE) {
+		di->pdata->ntc_factor = NTC_CALC_FACTOR_60UA;
+		di->pdata->ntc_uA = 60;
+		buf |= ADC_CUR_60UA;
+	} else if (ntc_table[0] < NTC_40UA_MAX_MEASURE) {
+		di->pdata->ntc_factor = NTC_CALC_FACTOR_40UA;
+		di->pdata->ntc_uA = 40;
+		buf |= ADC_CUR_40UA;
+	} else {
+		di->pdata->ntc_factor = NTC_CALC_FACTOR_20UA;
+		di->pdata->ntc_uA = 20;
+		buf |= ADC_CUR_20UA;
 	}
+	rk818_bat_write(di, RK818_TS_CTRL_REG, buf);
 
-	ret = devm_request_threaded_irq(di->dev, vb_lo_irq, NULL,
-					rk818_vb_low_irq,
-					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-					"rk818_vb_low", di);
-	if (ret) {
-		dev_err(&pdev->dev, "vb_lo_irq request failed!\n");
-		return ret;
+	/* enable ADC_TS1_EN */
+	buf = rk818_bat_read(di, RK818_ADC_CTRL_REG);
+	buf |= ADC_TS1_EN;
+	rk818_bat_write(di, RK818_ADC_CTRL_REG, buf);
+}
+
+/*
+ * Due to hardware design issue, Vdelta = "(R_sample + R_other) * I_avg" will be
+ * included into TS1 adc value. We must subtract it to get correct adc value.
+ * The solution:
+ *
+ * (1) calculate Vdelta:
+ *
+ *   adc1 - Vdelta    ua1			  (adc2 * ua1) - (adc1 * ua2)
+ *   ------------- = -----  ==> equals: Vdelta = -----------------------------
+ *   adc2 - Vdelta    ua2				ua1 - ua2
+ *
+ *
+ * (2) calculate correct ADC value:
+ *
+ *     charging: ADC = adc1 - abs(Vdelta);
+ *  discharging: ADC = adc1 + abs(Vdelta);
+ */
+static int rk818_bat_get_ntc_res(struct rk818_battery *di)
+{
+	int adc1 = 0, adc2 = 0;
+	int ua1, ua2, v_delta, res, val;
+	u8 buf;
+
+	/* read sample ua1 */
+	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
+	DBG("<%s>. read adc1, sample uA=%d\n",
+	    __func__, ((buf & 0x03) + 1) * 20);
+
+	/* read adc adc1 */
+	ua1 = di->pdata->ntc_uA;
+	adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0;
+	adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8;
+
+	/* chose reference UA for adc2 */
+	ua2 = (ua1 != 20) ? 20 : 40;
+	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
+	buf &= ~TS1_CUR_MSK;
+	buf |= ((ua2 - 20) / 20);
+	rk818_bat_write(di, RK818_TS_CTRL_REG, buf);
+
+	/* read adc adc2 */
+	msleep(1000);
+
+	/* read sample ua2 */
+	buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
+	DBG("<%s>. read adc2, sample uA=%d\n",
+	    __func__, ((buf & 0x03) + 1) * 20);
+
+	adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0;
+	adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8;
+
+	DBG("<%s>. ua1=%d, ua2=%d, adc1=%d, adc2=%d\n",
+	    __func__, ua1, ua2, adc1, adc2);
+
+	/* calculate delta voltage */
+	if (adc2 != adc1)
+		v_delta = abs((adc2 * ua1 - adc1 * ua2) / (ua2 - ua1));
+	else
+		v_delta = 0;
+
+	/* considering current avg direction, calcuate real adc value */
+	val = (di->current_avg >= 0) ? (adc1 - v_delta) : (adc1 + v_delta);
+
+	DBG("<%s>. Iavg=%d, Vdelta=%d, Vadc=%d\n",
+	    __func__, di->current_avg, v_delta, val);
+
+	res = val * di->pdata->ntc_factor;
+
+	DBG("<%s>. val=%d, ntc_res=%d, ntc_factor=%d, Rdelta=%d\n",
+	    __func__, val, res, di->pdata->ntc_factor,
+	    v_delta * di->pdata->ntc_factor);
+
+	DBG("<%s>. t=[%d'C(%d) ~ %dC(%d)]\n", __func__,
+	    di->pdata->ntc_degree_from, di->pdata->ntc_table[0],
+	    di->pdata->ntc_degree_from + di->pdata->ntc_size - 1,
+	    di->pdata->ntc_table[di->pdata->ntc_size - 1]);
+
+	rk818_bat_init_ts1_detect(di);
+
+	return res;
+}
+
+static void rk818_bat_update_temperature(struct rk818_battery *di)
+{
+	static int old_temp, first_time = 1;
+	u32 ntc_size, *ntc_table;
+	int i, res, temp;
+
+	ntc_table = di->pdata->ntc_table;
+	ntc_size = di->pdata->ntc_size;
+	di->temperature = 200;
+
+	if (ntc_size) {
+		res = rk818_bat_get_ntc_res(di);
+		if (res < ntc_table[ntc_size - 1]) {
+			di->temperature = di->pdata->ntc_degree_from +
+					  di->pdata->ntc_size - 1;
+			BAT_INFO("bat ntc upper max degree: R=%d\n", res);
+		} else if (res > ntc_table[0]) {
+			di->temperature = di->pdata->ntc_degree_from;
+			BAT_INFO("bat ntc lower min degree: R=%d\n", res);
+		} else {
+			for (i = 0; i < ntc_size; i++) {
+				if (res >= ntc_table[i])
+					break;
+			}
+
+			/* if first in, init old_temp */
+			temp = (i + di->pdata->ntc_degree_from) * 10;
+			if (first_time == 1) {
+				di->temperature = temp;
+				old_temp = temp;
+				first_time = 0;
+			}
+
+			/*
+			 * compare with old one, it's invalid when over 50
+			 * and we should use old data.
+			 */
+			if (abs(temp - old_temp) > 50)
+				temp = old_temp;
+			else
+				old_temp = temp;
+
+			di->temperature = temp;
+			DBG("<%s>. temperature = %d\n",
+			    __func__, di->temperature);
+		}
+	}
+}
+
+// }}}
+// {{{ Charger configuration
+
+static void rk818_bat_init_chrg_config(struct rk818_battery *di)
+{
+	u8 usb_ctrl, chrg_ctrl2, chrg_ctrl3;
+	u8 thermal, ggcon, finish_ma, fb_temp;
+
+	finish_ma = rk818_bat_parse_finish_ma(di, di->fcc);
+	fb_temp = rk818_bat_parse_fb_temperature(di);
+
+	ggcon = rk818_bat_read(di, RK818_GGCON_REG);
+	thermal = rk818_bat_read(di, RK818_THERMAL_REG);
+	usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG);
+	chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2);
+	chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3);
+
+	/* set charge finish current */
+	chrg_ctrl3 |= CHRG_TERM_DIG_SIGNAL;
+	chrg_ctrl2 &= ~FINISH_CUR_MSK;
+	chrg_ctrl2 |= finish_ma;
+
+	/* disable cccv mode */
+	chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN;
+
+	/* set feed back temperature */
+	if (di->pdata->fb_temp)
+		usb_ctrl |= CHRG_CT_EN;
+	else
+		usb_ctrl &= ~CHRG_CT_EN;
+	thermal &= ~FB_TEMP_MSK;
+	thermal |= fb_temp;
+
+	/* adc current mode */
+	ggcon |= ADC_CUR_MODE;
+
+	rk818_bat_write(di, RK818_GGCON_REG, ggcon);
+	rk818_bat_write(di, RK818_THERMAL_REG, thermal);
+	rk818_bat_write(di, RK818_USB_CTRL_REG, usb_ctrl);
+	rk818_bat_write(di, RK818_CHRG_CTRL_REG2, chrg_ctrl2);
+	rk818_bat_write(di, RK818_CHRG_CTRL_REG3, chrg_ctrl3);
+}
+
+// }}}
+// {{{ Current offset calibration
+
+static void rk818_bat_init_coffset(struct rk818_battery *di)
+{
+	int coffset, ioffset;
+
+	ioffset = rk818_bat_get_ioffset(di);
+	di->poffset = rk818_bat_read(di, RK818_POFFSET_REG);
+	if (!di->poffset)
+		di->poffset = DEFAULT_POFFSET;
+
+	coffset = di->poffset + ioffset;
+	if (coffset < INVALID_COFFSET_MIN || coffset > INVALID_COFFSET_MAX)
+		coffset = DEFAULT_COFFSET;
+
+	rk818_bat_set_coffset(di, coffset);
+
+	DBG("<%s>. offset: p=0x%x, i=0x%x, c=0x%x\n",
+	    __func__, di->poffset, ioffset, rk818_bat_get_coffset(di));
+}
+
+// }}}
+// {{{ Power supply interface integration (properties)
+
+int rk818_battery_get_property(struct rk818_battery *di,
+			       enum power_supply_property psp,
+			       union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = rk818_bat_get_avg_current(di) * 1000;/*uA*/
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = rk818_bat_get_avg_voltage(di) * 1000;/*uV*/
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = is_rk818_bat_exist(di);
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = di->dsoc;
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = 100;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = di->temperature;
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		if (di->pdata->bat_mode == MODE_MISSING)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else if (di->dsoc == 100)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else if (rk818_bat_get_charge_state(di))
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		else
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		val->intval = di->charge_count;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = di->pdata->design_capacity * 1000;/* uAh */
+		break;
+	default:
+		return -EINVAL;
 	}
-	enable_irq_wake(vb_lo_irq);
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(rk818_battery_get_property);
 
-static void rk818_bat_init_info(struct rk818_battery *di)
+// }}}
+// {{{ Timers/workqueues
+
+static void rk818_bat_caltimer_isr(struct timer_list *t)
 {
-	di->design_cap = di->pdata->design_capacity;
-	di->qmax = di->pdata->design_qmax;
-	di->bat_res = di->pdata->bat_res;
-	di->monitor_ms = di->pdata->monitor_sec * TIMER_MS_COUNTS;
-	di->boot_base = POWER_ON_SEC_BASE;
-	di->res_div = (di->pdata->sample_res == SAMPLE_RES_20MR) ?
-		       SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
+	struct rk818_battery *di = from_timer(di, t, caltimer);
+
+	mod_timer(&di->caltimer, jiffies + MINUTE(8) * HZ);
+	queue_delayed_work(di->bat_monitor_wq, &di->calib_delay_work,
+			   msecs_to_jiffies(10));
 }
 
-static time64_t rk818_get_rtc_sec(void)
+static void rk818_bat_internal_calib(struct work_struct *work)
 {
-	int err;
-	struct rtc_time tm;
-	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	int ioffset, poffset;
+	struct rk818_battery *di = container_of(work,
+			struct rk818_battery, calib_delay_work.work);
 
-	err = rtc_read_time(rtc, &tm);
-	if (err) {
-		dev_err(rtc->dev.parent, "read hardware clk failed\n");
-		return 0;
-	}
+	/* calib coffset */
+	poffset = rk818_bat_read(di, RK818_POFFSET_REG);
+	if (poffset)
+		di->poffset = poffset;
+	else
+		di->poffset = DEFAULT_POFFSET;
 
-	err = rtc_valid_tm(&tm);
-	if (err) {
-		dev_err(rtc->dev.parent, "invalid date time\n");
-		return 0;
-	}
+	ioffset = rk818_bat_get_ioffset(di);
+	rk818_bat_set_coffset(di, ioffset + di->poffset);
 
-	return rtc_tm_to_time64(&tm);
+	/* calib voltage kb */
+	rk818_bat_init_voltage_kb(di);
+	BAT_INFO("caltimer: ioffset=0x%x, coffset=0x%x, poffset=%d\n",
+		 ioffset, rk818_bat_get_coffset(di), di->poffset);
 }
 
-static int rk818_bat_rtc_sleep_sec(struct rk818_battery *di)
+static void rk818_bat_init_caltimer(struct rk818_battery *di)
 {
-	int interval_sec;
-
-	interval_sec = rk818_get_rtc_sec() - di->rtc_base;
-
-	return (interval_sec > 0) ? interval_sec : 0;
+	timer_setup(&di->caltimer, rk818_bat_caltimer_isr, 0);
+	di->caltimer.expires = jiffies + MINUTE(8) * HZ;
+	add_timer(&di->caltimer);
+	INIT_DELAYED_WORK(&di->calib_delay_work, rk818_bat_internal_calib);
 }
 
-static void rk818_bat_set_shtd_vol(struct rk818_battery *di)
+static void rk818_battery_work(struct work_struct *work)
 {
-	u8 val;
+	struct rk818_battery *di =
+		container_of(work, struct rk818_battery, bat_delay_work.work);
 
-#if 0
-	/* set vbat lowest 3.0v shutdown */
-	val = rk818_bat_read(di, RK818_VB_MON_REG);
-	val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK);
-	val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN);
-	rk818_bat_write(di, RK818_VB_MON_REG, val);
+	rk818_bat_update_info(di);
+	rk818_bat_wait_finish_sig(di);
+	rk818_bat_rsoc_daemon(di);
+	rk818_bat_update_temperature(di);
+	rk818_bat_display_smooth(di);
+	rk818_bat_power_supply_changed(di);
+	rk818_bat_save_data(di);
+	rk818_bat_debug_info(di);
 
-	/* disable low irq */
-	rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1,
-			   VB_LOW_INT_EN, VB_LOW_INT_EN);
-#endif
+	queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
+			   msecs_to_jiffies(di->monitor_ms));
+}
 
-	val = rk818_bat_read(di, RK818_VB_MON_REG);
-	val &= (~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK));
-	val |= (RK818_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ);
-	rk818_bat_write(di, RK818_VB_MON_REG, val);
-	rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, VB_LOW_INT_EN, 0);
+// }}}
+// {{{ Initialization/DT parsing
+
+static void rk818_bat_init_info(struct rk818_battery *di)
+{
+	di->design_cap = di->pdata->design_capacity;
+	di->qmax = di->pdata->design_qmax;
+	di->bat_res = di->pdata->bat_res;
+	di->monitor_ms = di->pdata->monitor_sec * TIMER_MS_COUNTS;
+	di->boot_base = POWER_ON_SEC_BASE;
+	di->res_div = (di->pdata->sample_res == SAMPLE_RES_20MR) ?
+		       SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
 }
 
 static void rk818_bat_init_fg(struct rk818_battery *di)
@@ -3040,6 +3039,41 @@ static void rk818_bat_init_fg(struct rk818_battery *di)
 	    di->voltage_relax, di->dsoc, di->rsoc, di->current_avg);
 }
 
+static irqreturn_t rk818_vb_low_irq(int irq, void *bat)
+{
+	struct rk818_battery *di = (struct rk818_battery *)bat;
+
+	BAT_INFO("lower power yet, power off system! v=%d, c=%d, dsoc=%d\n",
+		 di->voltage_avg, di->current_avg, di->dsoc);
+
+	return IRQ_HANDLED;
+}
+
+static int rk818_bat_init_irqs(struct rk818_battery *di)
+{
+	struct rk808 *rk818 = di->rk818;
+	struct platform_device *pdev = di->pdev;
+	int ret, vb_lo_irq;
+
+	vb_lo_irq = regmap_irq_get_virq(rk818->irq_data, RK818_IRQ_VB_LO);
+	if (vb_lo_irq < 0) {
+		dev_err(di->dev, "vb_lo_irq request failed!\n");
+		return vb_lo_irq;
+	}
+
+	ret = devm_request_threaded_irq(di->dev, vb_lo_irq, NULL,
+					rk818_vb_low_irq,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					"rk818_vb_low", di);
+	if (ret) {
+		dev_err(&pdev->dev, "vb_lo_irq request failed!\n");
+		return ret;
+	}
+	enable_irq_wake(vb_lo_irq);
+
+	return 0;
+}
+
 static int rk818_bat_parse_dt(struct rk818_battery *di)
 {
 	u32 out_value;
@@ -3225,63 +3259,8 @@ static int rk818_bat_parse_dt(struct rk818_battery *di)
 	return 0;
 }
 
-static const struct of_device_id rk818_battery_of_match[] = {
-	{ .compatible = "rockchip,rk818-battery", },
-	{ },
-};
-
-static struct rk818_battery* bat;
-
-struct rk818_battery* rk818_battery_get(void)
-{
-	return bat;
-}
-EXPORT_SYMBOL_GPL(rk818_battery_get);
-
-static int rk818_battery_probe(struct platform_device *pdev)
-{
-	struct rk818_battery *di;
-	struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent);
-	int ret;
-
-	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-	if (!di)
-		return -ENOMEM;
-
-	di->rk818 = rk818;
-	di->pdev = pdev;
-	di->dev = &pdev->dev;
-	di->regmap = rk818->regmap;
-	platform_set_drvdata(pdev, di);
-
-	ret = rk818_bat_parse_dt(di);
-	if (ret < 0) {
-		dev_err(di->dev, "rk818 battery parse dt failed!\n");
-		return ret;
-	}
-
-	if (!is_rk818_bat_exist(di)) {
-		di->pdata->bat_mode = MODE_MISSING;
-		dev_err(di->dev, "no battery, virtual power mode\n");
-	}
-
-	ret = rk818_bat_init_irqs(di);
-	if (ret != 0) {
-		dev_err(di->dev, "rk818 bat init irqs failed!\n");
-		return ret;
-	}
-
-	rk818_bat_init_info(di);
-	rk818_bat_init_fg(di);
-	di->bat_monitor_wq = alloc_ordered_workqueue("%s",
-			WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk818-bat-monitor-wq");
-	INIT_DELAYED_WORK(&di->bat_delay_work, rk818_battery_work);
-	queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
-			   msecs_to_jiffies(TIMER_MS_COUNTS * 5));
-
-	bat = di;
-	return ret;
-}
+// }}}
+// {{{ Suspend/resume
 
 static int rk818_battery_suspend(struct platform_device *dev,
 				 pm_message_t state)
@@ -3392,6 +3371,62 @@ static int rk818_battery_resume(struct platform_device *dev)
 	return 0;
 }
 
+// }}}
+// {{{ Probe/shutdown
+
+static struct rk818_battery* bat;
+
+struct rk818_battery* rk818_battery_get(void)
+{
+	return bat;
+}
+EXPORT_SYMBOL_GPL(rk818_battery_get);
+
+static int rk818_battery_probe(struct platform_device *pdev)
+{
+	struct rk818_battery *di;
+	struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent);
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	di->rk818 = rk818;
+	di->pdev = pdev;
+	di->dev = &pdev->dev;
+	di->regmap = rk818->regmap;
+	platform_set_drvdata(pdev, di);
+
+	ret = rk818_bat_parse_dt(di);
+	if (ret < 0) {
+		dev_err(di->dev, "rk818 battery parse dt failed!\n");
+		return ret;
+	}
+
+	if (!is_rk818_bat_exist(di)) {
+		di->pdata->bat_mode = MODE_MISSING;
+		dev_err(di->dev, "no battery, virtual power mode\n");
+	}
+
+	ret = rk818_bat_init_irqs(di);
+	if (ret != 0) {
+		dev_err(di->dev, "rk818 bat init irqs failed!\n");
+		return ret;
+	}
+
+	rk818_bat_init_info(di);
+	rk818_bat_init_fg(di);
+	di->bat_monitor_wq = alloc_ordered_workqueue("%s",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk818-bat-monitor-wq");
+	INIT_DELAYED_WORK(&di->bat_delay_work, rk818_battery_work);
+	queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
+			   msecs_to_jiffies(TIMER_MS_COUNTS * 5));
+
+	bat = di;
+	return ret;
+}
+
 static void rk818_battery_shutdown(struct platform_device *dev)
 {
 	u8 cnt = 0;
@@ -3412,6 +3447,14 @@ static void rk818_battery_shutdown(struct platform_device *dev)
 		 di->algo_rest_mode, di->algo_rest_val);
 }
 
+// }}}
+// {{{ Platform driver init
+
+static const struct of_device_id rk818_battery_of_match[] = {
+	{ .compatible = "rockchip,rk818-battery", },
+	{ },
+};
+
 static struct platform_driver rk818_battery_driver = {
 	.probe = rk818_battery_probe,
 	.suspend = rk818_battery_suspend,
@@ -3427,4 +3470,6 @@ module_platform_driver(rk818_battery_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rk818-battery");
-MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");
+MODULE_AUTHOR("chenjh <chenjh@rock-chips.com>");
+
+// }}}
-- 
2.49.0

