From 8b0eb5a56046b0934fe3be026e96aa4ba1ebbb63 Mon Sep 17 00:00:00 2001
From: Jianhua Lu <lujianhua000@gmail.com>
Date: Wed, 18 Sep 2024 14:27:53 +0800
Subject: [PATCH] power: supply: add bq25970 charger driver

---
 drivers/power/supply/Kconfig           |    9 +
 drivers/power/supply/Makefile          |    1 +
 drivers/power/supply/bq25970_charger.c | 2321 ++++++++++++++++++++++++
 drivers/power/supply/bq25970_reg.h     |  821 +++++++++
 4 files changed, 3152 insertions(+)
 create mode 100644 drivers/power/supply/bq25970_charger.c
 create mode 100644 drivers/power/supply/bq25970_reg.h

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 9f2eef6787f7a..655969eeb44e0 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -738,6 +738,15 @@ config CHARGER_BQ25890
 	help
 	  Say Y to enable support for the TI BQ25890 battery charger.
 
+config CHARGER_BQ25970
+	tristate "TI BQ25970 battery charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the TI BQ25970, BQ25971
+	  series of fast battery chargers.
+
 config CHARGER_BQ25980
 	tristate "TI BQ25980 battery charger driver"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 59c4a9f40d28a..fafab152c95d0 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CHARGER_BQ24257)	+= bq24257_charger.o
 obj-$(CONFIG_CHARGER_BQ24735)	+= bq24735-charger.o
 obj-$(CONFIG_CHARGER_BQ2515X)	+= bq2515x_charger.o
 obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
+obj-$(CONFIG_CHARGER_BQ25970)	+= bq25970_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
diff --git a/drivers/power/supply/bq25970_charger.c b/drivers/power/supply/bq25970_charger.c
new file mode 100644
index 0000000000000..1aeb1873f9fd5
--- /dev/null
+++ b/drivers/power/supply/bq25970_charger.c
@@ -0,0 +1,2321 @@
+/*
+ * BQ2570x battery charging driver
+ *
+ * Copyright (C) 2017 Texas Instruments *
+ * Copyright (C) 2021 XiaoMi, Inc.
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define pr_fmt(fmt)	"[bq2597x] %s: " fmt, __func__
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/math64.h>
+#include <asm/neon.h>
+#include "bq25970_reg.h"
+/*#include "bq2597x.h"*/
+
+enum {
+	VBUS_ERROR_NONE,
+	VBUS_ERROR_LOW,
+	VBUS_ERROR_HIGH,
+};
+
+enum {
+	ADC_IBUS,
+	ADC_VBUS,
+	ADC_VAC,
+	ADC_VOUT,
+	ADC_VBAT,
+	ADC_IBAT,
+	ADC_TBUS,
+	ADC_TBAT,
+	ADC_TDIE,
+	ADC_MAX_NUM,
+};
+
+#define BQ25970_ROLE_STDALONE   0
+#define BQ25970_ROLE_SLAVE	1
+#define BQ25970_ROLE_MASTER	2
+
+enum {
+	BQ25970_STDALONE,
+	BQ25970_SLAVE,
+	BQ25970_MASTER,
+};
+
+enum {
+	BQ25968,
+	BQ25970,
+	SC8551,
+};
+
+static int bq2597x_mode_data[] = {
+	[BQ25970_STDALONE] = BQ25970_STDALONE,
+	[BQ25970_MASTER] = BQ25970_ROLE_MASTER,
+	[BQ25970_SLAVE] = BQ25970_ROLE_SLAVE,
+};
+
+
+#define	BAT_OVP_ALARM		BIT(7)
+#define BAT_OCP_ALARM		BIT(6)
+#define	BUS_OVP_ALARM		BIT(5)
+#define	BUS_OCP_ALARM		BIT(4)
+#define	BAT_UCP_ALARM		BIT(3)
+#define	VBUS_INSERT		BIT(2)
+#define VBAT_INSERT		BIT(1)
+#define	ADC_DONE		BIT(0)
+
+#define BAT_OVP_FAULT		BIT(7)
+#define BAT_OCP_FAULT		BIT(6)
+#define BUS_OVP_FAULT		BIT(5)
+#define BUS_OCP_FAULT		BIT(4)
+#define TBUS_TBAT_ALARM		BIT(3)
+#define TS_BAT_FAULT		BIT(2)
+#define	TS_BUS_FAULT		BIT(1)
+#define	TS_DIE_FAULT		BIT(0)
+
+/*below used for comm with other module*/
+#define	BAT_OVP_FAULT_SHIFT			0
+#define	BAT_OCP_FAULT_SHIFT			1
+#define	BUS_OVP_FAULT_SHIFT			2
+#define	BUS_OCP_FAULT_SHIFT			3
+#define	BAT_THERM_FAULT_SHIFT			4
+#define	BUS_THERM_FAULT_SHIFT			5
+#define	DIE_THERM_FAULT_SHIFT			6
+
+#define	BAT_OVP_FAULT_MASK		(1 << BAT_OVP_FAULT_SHIFT)
+#define	BAT_OCP_FAULT_MASK		(1 << BAT_OCP_FAULT_SHIFT)
+#define	BUS_OVP_FAULT_MASK		(1 << BUS_OVP_FAULT_SHIFT)
+#define	BUS_OCP_FAULT_MASK		(1 << BUS_OCP_FAULT_SHIFT)
+#define	BAT_THERM_FAULT_MASK		(1 << BAT_THERM_FAULT_SHIFT)
+#define	BUS_THERM_FAULT_MASK		(1 << BUS_THERM_FAULT_SHIFT)
+#define	DIE_THERM_FAULT_MASK		(1 << DIE_THERM_FAULT_SHIFT)
+
+#define	BAT_OVP_ALARM_SHIFT			0
+#define	BAT_OCP_ALARM_SHIFT			1
+#define	BUS_OVP_ALARM_SHIFT			2
+#define	BUS_OCP_ALARM_SHIFT			3
+#define	BAT_THERM_ALARM_SHIFT			4
+#define	BUS_THERM_ALARM_SHIFT			5
+#define	DIE_THERM_ALARM_SHIFT			6
+#define BAT_UCP_ALARM_SHIFT			7
+
+#define	BAT_OVP_ALARM_MASK		(1 << BAT_OVP_ALARM_SHIFT)
+#define	BAT_OCP_ALARM_MASK		(1 << BAT_OCP_ALARM_SHIFT)
+#define	BUS_OVP_ALARM_MASK		(1 << BUS_OVP_ALARM_SHIFT)
+#define	BUS_OCP_ALARM_MASK		(1 << BUS_OCP_ALARM_SHIFT)
+#define	BAT_THERM_ALARM_MASK		(1 << BAT_THERM_ALARM_SHIFT)
+#define	BUS_THERM_ALARM_MASK		(1 << BUS_THERM_ALARM_SHIFT)
+#define	DIE_THERM_ALARM_MASK		(1 << DIE_THERM_ALARM_SHIFT)
+#define	BAT_UCP_ALARM_MASK		(1 << BAT_UCP_ALARM_SHIFT)
+
+#define VBAT_REG_STATUS_SHIFT			0
+#define IBAT_REG_STATUS_SHIFT			1
+
+#define VBAT_REG_STATUS_MASK		(1 << VBAT_REG_STATUS_SHIFT)
+#define IBAT_REG_STATUS_MASK		(1 << VBAT_REG_STATUS_SHIFT)
+
+#define bq_err(fmt, ...)								\
+do {											\
+	if (bq->mode == BQ25970_ROLE_MASTER)						\
+		printk(KERN_ERR "[bq2597x-MASTER]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else if (bq->mode == BQ25970_ROLE_SLAVE)					\
+		printk(KERN_ERR "[bq2597x-SLAVE]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else										\
+		printk(KERN_ERR "[bq2597x-STANDALONE]:%s:" fmt, __func__, ##__VA_ARGS__);\
+} while (0);
+
+#define bq_info(fmt, ...)								\
+do {											\
+	if (bq->mode == BQ25970_ROLE_MASTER)						\
+		printk(KERN_INFO "[bq2597x-MASTER]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else if (bq->mode == BQ25970_ROLE_SLAVE)					\
+		printk(KERN_INFO "[bq2597x-SLAVE]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else										\
+		printk(KERN_INFO "[bq2597x-STANDALONE]:%s:" fmt, __func__, ##__VA_ARGS__);\
+} while (0);
+
+#define bq_dbg(fmt, ...)								\
+do {											\
+	if (bq->mode == BQ25970_ROLE_MASTER)						\
+		printk(KERN_DEBUG "[bq2597x-MASTER]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else if (bq->mode == BQ25970_ROLE_SLAVE)					\
+		printk(KERN_DEBUG "[bq2597x-SLAVE]:%s:" fmt, __func__, ##__VA_ARGS__);	\
+	else										\
+		printk(KERN_DEBUG "[bq2597x-STANDALONE]:%s:" fmt, __func__, ##__VA_ARGS__);\
+} while (0);
+
+enum hvdcp3_type {
+	HVDCP3_NONE = 0,
+	HVDCP3_CLASSA_18W,
+	HVDCP3_CLASSB_27W,
+	HVDCP3P5_CLASSA_18W,
+	HVDCP3P5_CLASSB_27W,
+};
+
+#define BUS_OVP_FOR_QC			10500
+#define BUS_OVP_ALARM_FOR_QC			9500
+#define BUS_OCP_FOR_QC_CLASS_A			3250
+#define BUS_OCP_ALARM_FOR_QC_CLASS_A			2000
+#define BUS_OCP_FOR_QC_CLASS_B			4000
+#define BUS_OCP_ALARM_FOR_QC_CLASS_B			3000
+#define BUS_OCP_FOR_QC3P5_CLASS_A			3000
+#define BUS_OCP_ALARM_FOR_QC3P5_CLASS_A		2500
+#define BUS_OCP_FOR_QC3P5_CLASS_B			3500
+#define BUS_OCP_ALARM_FOR_QC3P5_CLASS_B		3200
+
+/*end*/
+
+struct bq2597x_cfg {
+	bool bat_ovp_disable;
+	bool bat_ocp_disable;
+	bool bat_ovp_alm_disable;
+	bool bat_ocp_alm_disable;
+
+	int bat_ovp_th;
+	int bat_ovp_alm_th;
+	int bat_ocp_th;
+	int bat_ocp_alm_th;
+
+	bool bus_ovp_alm_disable;
+	bool bus_ocp_disable;
+	bool bus_ocp_alm_disable;
+
+	int bus_ovp_th;
+	int bus_ovp_alm_th;
+	int bus_ocp_th;
+	int bus_ocp_alm_th;
+
+	bool bat_ucp_alm_disable;
+
+	int bat_ucp_alm_th;
+	int ac_ovp_th;
+
+	bool bat_therm_disable;
+	bool bus_therm_disable;
+	bool die_therm_disable;
+
+	int bat_therm_th; /*in %*/
+	int bus_therm_th; /*in %*/
+	int die_therm_th; /*in degC*/
+
+	int sense_r_mohm;
+};
+
+struct bq2597x {
+	struct device *dev;
+	struct i2c_client *client;
+
+	int part_no;
+	int revision;
+
+	int chip_vendor;
+	int mode;
+
+
+
+	struct mutex data_lock;
+	struct mutex i2c_rw_lock;
+	struct mutex charging_disable_lock;
+	struct mutex irq_complete;
+
+	bool irq_waiting;
+	bool irq_disabled;
+	bool resume_completed;
+
+	bool batt_present;
+	bool vbus_present;
+
+	bool usb_present;
+	bool charge_enabled;	/* Register bit status */
+
+	/* ADC reading */
+	int vbat_volt;
+	int vbus_volt;
+	int vout_volt;
+	int vac_volt;
+
+	int ibat_curr;
+	int ibus_curr;
+
+	int bat_temp;
+	int bus_temp;
+	int die_temp;
+
+	/* alarm/fault status */
+	bool bat_ovp_fault;
+	bool bat_ocp_fault;
+	bool bus_ovp_fault;
+	bool bus_ocp_fault;
+
+	bool bat_ovp_alarm;
+	bool bat_ocp_alarm;
+	bool bus_ovp_alarm;
+	bool bus_ocp_alarm;
+
+	bool bat_ucp_alarm;
+
+	bool bat_therm_alarm;
+	bool bus_therm_alarm;
+	bool die_therm_alarm;
+
+	bool bat_therm_fault;
+	bool bus_therm_fault;
+	bool die_therm_fault;
+
+	bool therm_shutdown_flag;
+	bool therm_shutdown_stat;
+
+	bool vbat_reg;
+	bool ibat_reg;
+
+	int  prev_alarm;
+	int  prev_fault;
+
+	int chg_ma;
+	int chg_mv;
+
+	int charge_state;
+
+	struct bq2597x_cfg *cfg;
+
+	int skip_writes;
+	int skip_reads;
+
+	struct bq2597x_platform_data *platform_data;
+
+	struct delayed_work monitor_work;
+
+	struct dentry *debug_root;
+
+	struct power_supply_desc psy_desc;
+	struct power_supply_config psy_cfg;
+	struct power_supply *fc2_psy;
+	struct power_supply *typec_psy;
+
+    struct notifier_block nb;
+    //struct delayed_work status_changed_work;
+};
+
+static int bq2597x_set_acovp_th(struct bq2597x *bq, int threshold);
+static int bq2597x_set_busovp_th(struct bq2597x *bq, int threshold);
+
+/************************************************************************/
+static int __bq2597x_read_byte(struct bq2597x *bq, u8 reg, u8 *data)
+{
+	s32 ret;
+
+	ret = i2c_smbus_read_byte_data(bq->client, reg);
+	if (ret < 0) {
+		bq_err("i2c read fail: can't read from reg 0x%02X\n", reg);
+		return ret;
+	}
+
+	*data = (u8) ret;
+
+	return 0;
+}
+
+static int __bq2597x_write_byte(struct bq2597x *bq, int reg, u8 val)
+{
+	s32 ret;
+
+	ret = i2c_smbus_write_byte_data(bq->client, reg, val);
+	if (ret < 0) {
+		bq_err("i2c write fail: can't write 0x%02X to reg 0x%02X: %d\n",
+		       val, reg, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int bq2597x_read_byte(struct bq2597x *bq, u8 reg, u8 *data)
+{
+	int ret;
+
+	if (bq->skip_reads) {
+		*data = 0;
+		return 0;
+	}
+
+	mutex_lock(&bq->i2c_rw_lock);
+	ret = __bq2597x_read_byte(bq, reg, data);
+	mutex_unlock(&bq->i2c_rw_lock);
+
+	return ret;
+}
+
+static int bq2597x_write_byte(struct bq2597x *bq, u8 reg, u8 data)
+{
+	int ret;
+
+	if (bq->skip_writes)
+		return 0;
+
+	mutex_lock(&bq->i2c_rw_lock);
+	ret = __bq2597x_write_byte(bq, reg, data);
+	mutex_unlock(&bq->i2c_rw_lock);
+
+	return ret;
+}
+
+static int bq2597x_update_bits(struct bq2597x *bq, u8 reg,
+				    u8 mask, u8 data)
+{
+	int ret;
+	u8 tmp;
+
+	if (bq->skip_reads || bq->skip_writes)
+		return 0;
+
+	mutex_lock(&bq->i2c_rw_lock);
+	ret = __bq2597x_read_byte(bq, reg, &tmp);
+	if (ret) {
+		bq_err("Failed: reg=%02X, ret=%d\n", reg, ret);
+		goto out;
+	}
+
+	tmp &= ~mask;
+	tmp |= data & mask;
+
+	ret = __bq2597x_write_byte(bq, reg, tmp);
+	if (ret)
+		bq_err("Failed: reg=%02X, ret=%d\n", reg, ret);
+
+out:
+	mutex_unlock(&bq->i2c_rw_lock);
+	return ret;
+}
+
+static int bq2597x_enable_charge(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_CHG_ENABLE;
+	else
+		val = BQ2597X_CHG_DISABLE;
+
+	val <<= BQ2597X_CHG_EN_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_0C,
+				BQ2597X_CHG_EN_MASK, val);
+
+	return ret;
+}
+
+static int bq2597x_check_charge_enabled(struct bq2597x *bq, bool *enabled)
+{
+	int ret;
+	u8 val;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0C, &val);
+	if (!ret)
+		*enabled = !!(val & BQ2597X_CHG_EN_MASK);
+	return ret;
+}
+
+static int bq2597x_enable_wdt(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_WATCHDOG_ENABLE;
+	else
+		val = BQ2597X_WATCHDOG_DISABLE;
+
+	val <<= BQ2597X_WATCHDOG_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_0B,
+				BQ2597X_WATCHDOG_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_batovp(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BAT_OVP_ENABLE;
+	else
+		val = BQ2597X_BAT_OVP_DISABLE;
+
+	val <<= BQ2597X_BAT_OVP_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_00,
+				BQ2597X_BAT_OVP_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_batovp_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BAT_OVP_BASE)
+		threshold = BQ2597X_BAT_OVP_BASE;
+
+	val = (threshold - BQ2597X_BAT_OVP_BASE) / BQ2597X_BAT_OVP_LSB;
+
+	val <<= BQ2597X_BAT_OVP_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_00,
+				BQ2597X_BAT_OVP_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_batovp_alarm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BAT_OVP_ALM_ENABLE;
+	else
+		val = BQ2597X_BAT_OVP_ALM_DISABLE;
+
+	val <<= BQ2597X_BAT_OVP_ALM_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_01,
+				BQ2597X_BAT_OVP_ALM_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_batovp_alarm_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BAT_OVP_ALM_BASE)
+		threshold = BQ2597X_BAT_OVP_ALM_BASE;
+
+	val = (threshold - BQ2597X_BAT_OVP_ALM_BASE) / BQ2597X_BAT_OVP_ALM_LSB;
+
+	val <<= BQ2597X_BAT_OVP_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_01,
+				BQ2597X_BAT_OVP_ALM_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_batocp(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BAT_OCP_ENABLE;
+	else
+		val = BQ2597X_BAT_OCP_DISABLE;
+
+	val <<= BQ2597X_BAT_OCP_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_02,
+				BQ2597X_BAT_OCP_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_batocp_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BAT_OCP_BASE)
+		threshold = BQ2597X_BAT_OCP_BASE;
+
+	val = (threshold - BQ2597X_BAT_OCP_BASE) / BQ2597X_BAT_OCP_LSB;
+
+	val <<= BQ2597X_BAT_OCP_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_02,
+				BQ2597X_BAT_OCP_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_batocp_alarm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BAT_OCP_ALM_ENABLE;
+	else
+		val = BQ2597X_BAT_OCP_ALM_DISABLE;
+
+	val <<= BQ2597X_BAT_OCP_ALM_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_03,
+				BQ2597X_BAT_OCP_ALM_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_batocp_alarm_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BAT_OCP_ALM_BASE)
+		threshold = BQ2597X_BAT_OCP_ALM_BASE;
+
+	val = (threshold - BQ2597X_BAT_OCP_ALM_BASE) / BQ2597X_BAT_OCP_ALM_LSB;
+
+	val <<= BQ2597X_BAT_OCP_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_03,
+				BQ2597X_BAT_OCP_ALM_MASK, val);
+	return ret;
+}
+
+
+static int bq2597x_set_busovp_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BUS_OVP_BASE)
+		threshold = BQ2597X_BUS_OVP_BASE;
+
+	val = (threshold - BQ2597X_BUS_OVP_BASE) / BQ2597X_BUS_OVP_LSB;
+
+	val <<= BQ2597X_BUS_OVP_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_06,
+				BQ2597X_BUS_OVP_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_busovp_alarm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BUS_OVP_ALM_ENABLE;
+	else
+		val = BQ2597X_BUS_OVP_ALM_DISABLE;
+
+	val <<= BQ2597X_BUS_OVP_ALM_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_07,
+				BQ2597X_BUS_OVP_ALM_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_busovp_alarm_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BUS_OVP_ALM_BASE)
+		threshold = BQ2597X_BUS_OVP_ALM_BASE;
+
+	val = (threshold - BQ2597X_BUS_OVP_ALM_BASE) / BQ2597X_BUS_OVP_ALM_LSB;
+
+	val <<= BQ2597X_BUS_OVP_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_07,
+				BQ2597X_BUS_OVP_ALM_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_busocp(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BUS_OCP_ENABLE;
+	else
+		val = BQ2597X_BUS_OCP_DISABLE;
+
+	val <<= BQ2597X_BUS_OCP_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_08,
+				BQ2597X_BUS_OCP_DIS_MASK, val);
+	return ret;
+}
+
+
+static int bq2597x_set_busocp_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BUS_OCP_BASE)
+		threshold = BQ2597X_BUS_OCP_BASE;
+
+	val = (threshold - BQ2597X_BUS_OCP_BASE) / BQ2597X_BUS_OCP_LSB;
+
+	val <<= BQ2597X_BUS_OCP_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_08,
+				BQ2597X_BUS_OCP_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_busocp_alarm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BUS_OCP_ALM_ENABLE;
+	else
+		val = BQ2597X_BUS_OCP_ALM_DISABLE;
+
+	val <<= BQ2597X_BUS_OCP_ALM_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_09,
+				BQ2597X_BUS_OCP_ALM_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_busocp_alarm_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BUS_OCP_ALM_BASE)
+		threshold = BQ2597X_BUS_OCP_ALM_BASE;
+
+	val = (threshold - BQ2597X_BUS_OCP_ALM_BASE) / BQ2597X_BUS_OCP_ALM_LSB;
+
+	val <<= BQ2597X_BUS_OCP_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_09,
+				BQ2597X_BUS_OCP_ALM_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_batucp_alarm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_BAT_UCP_ALM_ENABLE;
+	else
+		val = BQ2597X_BAT_UCP_ALM_DISABLE;
+
+	val <<= BQ2597X_BAT_UCP_ALM_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_04,
+				BQ2597X_BAT_UCP_ALM_DIS_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_batucp_alarm_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_BAT_UCP_ALM_BASE)
+		threshold = BQ2597X_BAT_UCP_ALM_BASE;
+
+	val = (threshold - BQ2597X_BAT_UCP_ALM_BASE) / BQ2597X_BAT_UCP_ALM_LSB;
+
+	val <<= BQ2597X_BAT_UCP_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_04,
+				BQ2597X_BAT_UCP_ALM_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_acovp_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold < BQ2597X_AC_OVP_BASE)
+		threshold = BQ2597X_AC_OVP_BASE;
+
+	if (threshold == BQ2597X_AC_OVP_6P5V)
+		val = 0x07;
+	else
+		val = (threshold - BQ2597X_AC_OVP_BASE) /  BQ2597X_AC_OVP_LSB;
+
+	val <<= BQ2597X_AC_OVP_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_05,
+				BQ2597X_AC_OVP_MASK, val);
+
+	return ret;
+
+}
+
+static int bq2597x_set_vdrop_th(struct bq2597x *bq, int threshold)
+{
+	int ret;
+	u8 val;
+
+	if (threshold == 300)
+		val = BQ2597X_VDROP_THRESHOLD_300MV;
+	else
+		val = BQ2597X_VDROP_THRESHOLD_400MV;
+
+	val <<= BQ2597X_VDROP_THRESHOLD_SET_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_05,
+				BQ2597X_VDROP_THRESHOLD_SET_MASK,
+				val);
+
+	return ret;
+}
+
+static int bq2597x_set_vdrop_deglitch(struct bq2597x *bq, int us)
+{
+	int ret;
+	u8 val;
+
+	if (us == 8)
+		val = BQ2597X_VDROP_DEGLITCH_8US;
+	else
+		val = BQ2597X_VDROP_DEGLITCH_5MS;
+
+	val <<= BQ2597X_VDROP_DEGLITCH_SET_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_05,
+				BQ2597X_VDROP_DEGLITCH_SET_MASK,
+				val);
+	return ret;
+}
+
+static int bq2597x_enable_bat_therm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_TSBAT_ENABLE;
+	else
+		val = BQ2597X_TSBAT_DISABLE;
+
+	val <<= BQ2597X_TSBAT_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_0C,
+				BQ2597X_TSBAT_DIS_MASK, val);
+	return ret;
+}
+
+/*
+ * the input threshold is the raw value that would write to register directly.
+ */
+static int bq2597x_set_bat_therm_th(struct bq2597x *bq, u8 threshold)
+{
+	int ret;
+
+	ret = bq2597x_write_byte(bq, BQ2597X_REG_29, threshold);
+	return ret;
+}
+
+static int bq2597x_enable_bus_therm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_TSBUS_ENABLE;
+	else
+		val = BQ2597X_TSBUS_DISABLE;
+
+	val <<= BQ2597X_TSBUS_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_0C,
+				BQ2597X_TSBUS_DIS_MASK, val);
+	return ret;
+}
+
+/*
+ * the input threshold is the raw value that would write to register directly.
+ */
+static int bq2597x_set_bus_therm_th(struct bq2597x *bq, u8 threshold)
+{
+	int ret;
+
+	ret = bq2597x_write_byte(bq, BQ2597X_REG_28, threshold);
+	return ret;
+}
+
+
+static int bq2597x_enable_die_therm(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_TDIE_ENABLE;
+	else
+		val = BQ2597X_TDIE_DISABLE;
+
+	val <<= BQ2597X_TDIE_DIS_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_0C,
+				BQ2597X_TDIE_DIS_MASK, val);
+	return ret;
+}
+
+/*
+ * please be noted that the unit here is degC
+ */
+static int bq2597x_set_die_therm_th(struct bq2597x *bq, u8 threshold)
+{
+	int ret;
+	u8 val;
+
+	/*BE careful, LSB is here is 1/LSB, so we use multiply here*/
+	val = (threshold - BQ2597X_TDIE_ALM_BASE) * BQ2597X_TDIE_ALM_LSB;
+	val <<= BQ2597X_TDIE_ALM_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2A,
+				BQ2597X_TDIE_ALM_MASK, val);
+	return ret;
+}
+
+static int bq2597x_enable_adc(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_ADC_ENABLE;
+	else
+		val = BQ2597X_ADC_DISABLE;
+
+	val <<= BQ2597X_ADC_EN_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_14,
+				BQ2597X_ADC_EN_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_adc_average(struct bq2597x *bq, bool avg)
+{
+	int ret;
+	u8 val;
+
+	if (avg)
+		val = BQ2597X_ADC_AVG_ENABLE;
+	else
+		val = BQ2597X_ADC_AVG_DISABLE;
+
+	val <<= BQ2597X_ADC_AVG_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_14,
+				BQ2597X_ADC_AVG_MASK, val);
+	return 0;
+}
+
+static int bq2597x_set_adc_scanrate(struct bq2597x *bq, bool oneshot)
+{
+	int ret;
+	u8 val;
+
+	if (oneshot)
+		val = BQ2597X_ADC_RATE_ONESHOT;
+	else
+		val = BQ2597X_ADC_RATE_CONTINOUS;
+
+	val <<= BQ2597X_ADC_RATE_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_14,
+				BQ2597X_ADC_EN_MASK, val);
+	return ret;
+}
+
+static int bq2597x_set_adc_bits(struct bq2597x *bq, int bits)
+{
+	int ret;
+	u8 val;
+
+	if (bits > 15)
+		bits = 15;
+	if (bits < 12)
+		bits = 12;
+	val = 15 - bits;
+
+	val <<= BQ2597X_ADC_SAMPLE_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_14,
+				BQ2597X_ADC_SAMPLE_MASK, val);
+	return ret;
+}
+
+#define ADC_REG_BASE 0x16
+static int bq2597x_set_adc_scan(struct bq2597x *bq, int channel, bool enable)
+{
+	int ret;
+	u8 reg;
+	u8 mask;
+	u8 shift;
+	u8 val;
+
+	if (channel > ADC_MAX_NUM)
+		return -EINVAL;
+
+	if (channel == ADC_IBUS) {
+		reg = BQ2597X_REG_14;
+		shift = BQ2597X_IBUS_ADC_DIS_SHIFT;
+		mask = BQ2597X_IBUS_ADC_DIS_MASK;
+	} else {
+		reg = BQ2597X_REG_15;
+		shift = 8 - channel;
+		mask = 1 << shift;
+	}
+
+	if (enable)
+		val = 0 << shift;
+	else
+		val = 1 << shift;
+
+	ret = bq2597x_update_bits(bq, reg, mask, val);
+
+	return ret;
+}
+
+static int sc8551_init_adc(struct bq2597x *bq)
+{
+	int ret;
+	/* improve adc accuracy */
+	ret = bq2597x_write_byte(bq, SC8551_REG_34, 0x01);
+	return ret;
+}
+
+static int bq2597x_set_alarm_int_mask(struct bq2597x *bq, u8 mask)
+{
+	int ret;
+	u8 val;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0F, &val);
+	if (ret)
+		return ret;
+
+	val |= mask;
+
+	ret = bq2597x_write_byte(bq, BQ2597X_REG_0F, val);
+
+	return ret;
+}
+
+static int bq2597x_set_fault_int_mask(struct bq2597x *bq, u8 mask)
+{
+	int ret;
+	u8 val;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_12, &val);
+	if (ret)
+		return ret;
+
+	val |= mask;
+
+	ret = bq2597x_write_byte(bq, BQ2597X_REG_12, val);
+
+	return ret;
+}
+
+static int bq2597x_set_sense_resistor(struct bq2597x *bq, int r_mohm)
+{
+	int ret;
+	u8 val;
+
+	if (r_mohm == 2)
+		val = BQ2597X_SET_IBAT_SNS_RES_2MHM;
+	else if (r_mohm == 5)
+		val = BQ2597X_SET_IBAT_SNS_RES_5MHM;
+	else
+		return -EINVAL;
+
+	val <<= BQ2597X_SET_IBAT_SNS_RES_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2B,
+				BQ2597X_SET_IBAT_SNS_RES_MASK,
+				val);
+	return ret;
+}
+
+static int bq2597x_set_ibus_ucp_thr(struct bq2597x *bq, int ibus_ucp_thr)
+{
+	int ret;
+	u8 val;
+
+	if (ibus_ucp_thr == 300)
+		val = BQ2597X_IBUS_UCP_RISE_300MA;
+	else if (ibus_ucp_thr == 500)
+		val = BQ2597X_IBUS_UCP_RISE_500MA;
+	else
+		return -EINVAL;
+
+	val <<= BQ2597X_IBUS_UCP_RISE_TH_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2B,
+				BQ2597X_IBUS_UCP_RISE_TH_MASK,
+				val);
+	return ret;
+}
+
+static int bq2597x_enable_regulation(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_EN_REGULATION_ENABLE;
+	else
+		val = BQ2597X_EN_REGULATION_DISABLE;
+
+	val <<= BQ2597X_EN_REGULATION_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2B,
+				BQ2597X_EN_REGULATION_MASK,
+				val);
+
+	return ret;
+
+}
+
+static int bq2597x_enable_ucp(struct bq2597x *bq, bool enable)
+{
+	int ret;
+	u8 val;
+
+	if (enable)
+		val = BQ2597X_IBUS_LOW_DG_5MS;
+	else
+		val = BQ2597X_IBUS_LOW_DG_10US;
+
+	val <<= BQ2597X_IBUS_LOW_DG_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2E,
+				BQ2597X_IBUS_LOW_DG_MASK,
+				val);
+
+	return ret;
+
+}
+
+static int bq2597x_set_ss_timeout(struct bq2597x *bq, int timeout)
+{
+	int ret;
+	u8 val;
+
+	switch (timeout) {
+	case 0:
+		val = BQ2597X_SS_TIMEOUT_DISABLE;
+		break;
+	case 12:
+		val = BQ2597X_SS_TIMEOUT_12P5MS;
+		break;
+	case 25:
+		val = BQ2597X_SS_TIMEOUT_25MS;
+		break;
+	case 50:
+		val = BQ2597X_SS_TIMEOUT_50MS;
+		break;
+	case 100:
+		val = BQ2597X_SS_TIMEOUT_100MS;
+		break;
+	case 400:
+		val = BQ2597X_SS_TIMEOUT_400MS;
+		break;
+	case 1500:
+		val = BQ2597X_SS_TIMEOUT_1500MS;
+		break;
+	case 100000:
+		val = BQ2597X_SS_TIMEOUT_100000MS;
+		break;
+	default:
+		val = BQ2597X_SS_TIMEOUT_DISABLE;
+		break;
+	}
+
+	val <<= BQ2597X_SS_TIMEOUT_SET_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2B,
+				BQ2597X_SS_TIMEOUT_SET_MASK,
+				val);
+
+	return ret;
+}
+
+static int bq2597x_set_ibat_reg_th(struct bq2597x *bq, int th_ma)
+{
+	int ret;
+	u8 val;
+
+	if (th_ma == 200)
+		val = BQ2597X_IBAT_REG_200MA;
+	else if (th_ma == 300)
+		val = BQ2597X_IBAT_REG_300MA;
+	else if (th_ma == 400)
+		val = BQ2597X_IBAT_REG_400MA;
+	else if (th_ma == 500)
+		val = BQ2597X_IBAT_REG_500MA;
+	else
+		val = BQ2597X_IBAT_REG_500MA;
+
+	val <<= BQ2597X_IBAT_REG_SHIFT;
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2C,
+				BQ2597X_IBAT_REG_MASK,
+				val);
+
+	return ret;
+
+}
+
+static int bq2597x_set_vbat_reg_th(struct bq2597x *bq, int th_mv)
+{
+	int ret;
+	u8 val;
+
+	if (th_mv == 50)
+		val = BQ2597X_VBAT_REG_50MV;
+	else if (th_mv == 100)
+		val = BQ2597X_VBAT_REG_100MV;
+	else if (th_mv == 150)
+		val = BQ2597X_VBAT_REG_150MV;
+	else
+		val = BQ2597X_VBAT_REG_200MV;
+
+	val <<= BQ2597X_VBAT_REG_SHIFT;
+
+	ret = bq2597x_update_bits(bq, BQ2597X_REG_2C,
+				BQ2597X_VBAT_REG_MASK,
+				val);
+
+	return ret;
+}
+
+static int bq2597x_get_work_mode(struct bq2597x *bq, int *mode)
+{
+	int ret;
+	u8 val;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0C, &val);
+
+	if (ret) {
+		bq_err("Failed to read operation mode register\n");
+		return ret;
+	}
+
+	val = (val & BQ2597X_MS_MASK) >> BQ2597X_MS_SHIFT;
+	if (val == BQ2597X_MS_MASTER)
+		*mode = BQ25970_ROLE_MASTER;
+	else if (val == BQ2597X_MS_SLAVE)
+		*mode = BQ25970_ROLE_SLAVE;
+	else
+		*mode = BQ25970_ROLE_STDALONE;
+
+	bq_info("work mode:%s\n", *mode == BQ25970_ROLE_STDALONE ? "Standalone" :
+			(*mode == BQ25970_ROLE_SLAVE ? "Slave" : "Master"));
+	return ret;
+}
+
+static int bq2597x_detect_device(struct bq2597x *bq)
+{
+	int ret;
+	u8 data;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_13, &data);
+	if (ret == 0) {
+		bq->part_no = (data & BQ2597X_DEV_ID_MASK);
+		bq->part_no >>= BQ2597X_DEV_ID_SHIFT;
+
+		pr_err("detect device:%d\n", data);
+		if (data == SC8551_DEVICE_ID || data == SC8551A_DEVICE_ID)
+			bq->chip_vendor = SC8551;
+		else if (data == BQ25968_DEV_ID)
+			bq->chip_vendor = BQ25968;
+		else
+			bq->chip_vendor = BQ25970;
+	}
+
+	return ret;
+}
+
+static int bq2597x_parse_dt(struct bq2597x *bq, struct device *dev)
+{
+	int ret;
+	struct device_node *np = dev->of_node;
+
+	bq->cfg = devm_kzalloc(dev, sizeof(struct bq2597x_cfg),
+					GFP_KERNEL);
+
+	if (!bq->cfg)
+		return -ENOMEM;
+
+	bq->cfg->bat_ovp_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-ovp-disable");
+	bq->cfg->bat_ocp_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-ocp-disable");
+	bq->cfg->bat_ovp_alm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-ovp-alarm-disable");
+	bq->cfg->bat_ocp_alm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-ocp-alarm-disable");
+	bq->cfg->bus_ocp_disable = of_property_read_bool(np,
+			"ti,bq2597x,bus-ocp-disable");
+	bq->cfg->bus_ovp_alm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bus-ovp-alarm-disable");
+	bq->cfg->bus_ocp_alm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bus-ocp-alarm-disable");
+	bq->cfg->bat_ucp_alm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-ucp-alarm-disable");
+	bq->cfg->bat_therm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bat-therm-disable");
+	bq->cfg->bus_therm_disable = of_property_read_bool(np,
+			"ti,bq2597x,bus-therm-disable");
+	bq->cfg->die_therm_disable = of_property_read_bool(np,
+			"ti,bq2597x,die-therm-disable");
+
+	ret = of_property_read_u32(np, "ti,bq2597x,bat-ovp-threshold",
+			&bq->cfg->bat_ovp_th);
+	if (ret) {
+		bq_err("failed to read bat-ovp-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bat-ovp-alarm-threshold",
+			&bq->cfg->bat_ovp_alm_th);
+	if (ret) {
+		bq_err("failed to read bat-ovp-alarm-threshold\n");
+		return ret;
+	}
+	/*ret = of_property_read_u32(np, "ti,bq2597x,bat-ocp-threshold",
+			&bq->cfg->bat_ocp_th);
+	if (ret) {
+		bq_err("failed to read bat-ocp-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bat-ocp-alarm-threshold",
+			&bq->cfg->bat_ocp_alm_th);
+	if (ret) {
+		bq_err("failed to read bat-ocp-alarm-threshold\n");
+		return ret;
+	}*/
+	ret = of_property_read_u32(np, "ti,bq2597x,bus-ovp-threshold",
+			&bq->cfg->bus_ovp_th);
+	if (ret) {
+		bq_err("failed to read bus-ovp-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bus-ovp-alarm-threshold",
+			&bq->cfg->bus_ovp_alm_th);
+	if (ret) {
+		bq_err("failed to read bus-ovp-alarm-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bus-ocp-threshold",
+			&bq->cfg->bus_ocp_th);
+	if (ret) {
+		bq_err("failed to read bus-ocp-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bus-ocp-alarm-threshold",
+			&bq->cfg->bus_ocp_alm_th);
+	if (ret) {
+		bq_err("failed to read bus-ocp-alarm-threshold\n");
+		return ret;
+	}
+	/*ret = of_property_read_u32(np, "ti,bq2597x,bat-ucp-alarm-threshold",
+			&bq->cfg->bat_ucp_alm_th);
+	if (ret) {
+		bq_err("failed to read bat-ucp-alarm-threshold\n");
+		return ret;
+	}*/
+	ret = of_property_read_u32(np, "ti,bq2597x,bat-therm-threshold",
+			&bq->cfg->bat_therm_th);
+	if (ret) {
+		bq_err("failed to read bat-therm-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,bus-therm-threshold",
+			&bq->cfg->bus_therm_th);
+	if (ret) {
+		bq_err("failed to read bus-therm-threshold\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "ti,bq2597x,die-therm-threshold",
+			&bq->cfg->die_therm_th);
+	if (ret) {
+		bq_err("failed to read die-therm-threshold\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "ti,bq2597x,ac-ovp-threshold",
+			&bq->cfg->ac_ovp_th);
+	if (ret) {
+		bq_err("failed to read ac-ovp-threshold\n");
+		return ret;
+	}
+
+	if (bq->chip_vendor == SC8551) {
+		ret = of_property_read_u32(np, "sc8551,ac-ovp-threshold",
+				&bq->cfg->ac_ovp_th);
+		if (ret) {
+			bq_err("failed to read sc8551 ac-ovp-threshold\n");
+			return ret;
+		}
+	}
+
+	/*ret = of_property_read_u32(np, "ti,bq2597x,sense-resistor-mohm",
+			&bq->cfg->sense_r_mohm);
+	if (ret) {
+		bq_err("failed to read sense-resistor-mohm\n");
+		return ret;
+	}*/
+
+
+	return 0;
+}
+
+static int bq2597x_init_protection(struct bq2597x *bq)
+{
+	int ret;
+
+	ret = bq2597x_enable_batovp(bq, !bq->cfg->bat_ovp_disable);
+	bq_info("%s bat ovp %s\n",
+		bq->cfg->bat_ovp_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_batocp(bq, !bq->cfg->bat_ocp_disable);
+	bq_info("%s bat ocp %s\n",
+		bq->cfg->bat_ocp_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_batovp_alarm(bq, !bq->cfg->bat_ovp_alm_disable);
+	bq_info("%s bat ovp alarm %s\n",
+		bq->cfg->bat_ovp_alm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_batocp_alarm(bq, !bq->cfg->bat_ocp_alm_disable);
+	bq_info("%s bat ocp alarm %s\n",
+		bq->cfg->bat_ocp_alm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_batucp_alarm(bq, !bq->cfg->bat_ucp_alm_disable);
+	bq_info("%s bat ocp alarm %s\n",
+		bq->cfg->bat_ucp_alm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_busovp_alarm(bq, !bq->cfg->bus_ovp_alm_disable);
+	bq_info("%s bus ovp alarm %s\n",
+		bq->cfg->bus_ovp_alm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_busocp(bq, !bq->cfg->bus_ocp_disable);
+	bq_info("%s bus ocp %s\n",
+		bq->cfg->bus_ocp_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_busocp_alarm(bq, !bq->cfg->bus_ocp_alm_disable);
+	bq_info("%s bus ocp alarm %s\n",
+		bq->cfg->bus_ocp_alm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_bat_therm(bq, !bq->cfg->bat_therm_disable);
+	bq_info("%s bat therm %s\n",
+		bq->cfg->bat_therm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_bus_therm(bq, !bq->cfg->bus_therm_disable);
+	bq_info("%s bus therm %s\n",
+		bq->cfg->bus_therm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_enable_die_therm(bq, !bq->cfg->die_therm_disable);
+	bq_info("%s die therm %s\n",
+		bq->cfg->die_therm_disable ? "disable" : "enable",
+		!ret ? "successfullly" : "failed");
+
+	ret = bq2597x_set_batovp_th(bq, bq->cfg->bat_ovp_th);
+	bq_info("set bat ovp th %d %s\n", bq->cfg->bat_ovp_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_batovp_alarm_th(bq, bq->cfg->bat_ovp_alm_th);
+	bq_info("set bat ovp alarm threshold %d %s\n", bq->cfg->bat_ovp_alm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_batocp_th(bq, bq->cfg->bat_ocp_th);
+	bq_info("set bat ocp threshold %d %s\n", bq->cfg->bat_ocp_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_batocp_alarm_th(bq, bq->cfg->bat_ocp_alm_th);
+	bq_info("set bat ocp alarm threshold %d %s\n", bq->cfg->bat_ocp_alm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_busovp_th(bq, bq->cfg->bus_ovp_th);
+	bq_info("set bus ovp threshold %d %s\n", bq->cfg->bus_ovp_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_busovp_alarm_th(bq, bq->cfg->bus_ovp_alm_th);
+	bq_info("set bus ovp alarm threshold %d %s\n", bq->cfg->bus_ovp_alm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_busocp_th(bq, bq->cfg->bus_ocp_th);
+	bq_info("set bus ocp threshold %d %s\n", bq->cfg->bus_ocp_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_busocp_alarm_th(bq, bq->cfg->bus_ocp_alm_th);
+	bq_info("set bus ocp alarm th %d %s\n", bq->cfg->bus_ocp_alm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_batucp_alarm_th(bq, bq->cfg->bat_ucp_alm_th);
+	bq_info("set bat ucp threshold %d %s\n", bq->cfg->bat_ucp_alm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_bat_therm_th(bq, bq->cfg->bat_therm_th);
+	bq_info("set die therm threshold %d %s\n", bq->cfg->bat_therm_th,
+		!ret ? "successfully" : "failed");
+	ret = bq2597x_set_bus_therm_th(bq, bq->cfg->bus_therm_th);
+	bq_info("set bus therm threshold %d %s\n", bq->cfg->bus_therm_th,
+		!ret ? "successfully" : "failed");
+	ret = bq2597x_set_die_therm_th(bq, bq->cfg->die_therm_th);
+	bq_info("set die therm threshold %d %s\n", bq->cfg->die_therm_th,
+		!ret ? "successfully" : "failed");
+
+	ret = bq2597x_set_acovp_th(bq, bq->cfg->ac_ovp_th);
+	bq_info("set ac ovp threshold %d %s\n", bq->cfg->ac_ovp_th,
+		!ret ? "successfully" : "failed");
+
+	return 0;
+}
+
+static int bq2597x_init_adc(struct bq2597x *bq)
+{
+	bq2597x_set_adc_scanrate(bq, false);
+	bq2597x_set_adc_bits(bq, 13);
+	bq2597x_set_adc_average(bq, true);
+	bq2597x_set_adc_scan(bq, ADC_IBUS, true);
+	bq2597x_set_adc_scan(bq, ADC_VBUS, true);
+	bq2597x_set_adc_scan(bq, ADC_VOUT, false);
+	bq2597x_set_adc_scan(bq, ADC_VBAT, true);
+	bq2597x_set_adc_scan(bq, ADC_IBAT, false);
+	bq2597x_set_adc_scan(bq, ADC_TBUS, false);
+	bq2597x_set_adc_scan(bq, ADC_TBAT, false);
+	bq2597x_set_adc_scan(bq, ADC_TDIE, false);
+	bq2597x_set_adc_scan(bq, ADC_VAC, true);
+
+	if (bq->chip_vendor == SC8551)
+		sc8551_init_adc(bq);
+
+	bq2597x_enable_adc(bq, true);
+
+	return 0;
+}
+
+static int bq2597x_init_int_src(struct bq2597x *bq)
+{
+	int ret;
+	/*TODO:be careful ts bus and ts bat alarm bit mask is in
+	 *	fault mask register, so you need call
+	 *	bq2597x_set_fault_int_mask for tsbus and tsbat alarm
+	 */
+	ret = bq2597x_set_alarm_int_mask(bq, ADC_DONE
+					| BAT_OCP_ALARM | BAT_UCP_ALARM
+					| BAT_OVP_ALARM);
+	if (ret) {
+		bq_err("failed to set alarm mask:%d\n", ret);
+		return ret;
+	}
+//#if 0
+	ret = bq2597x_set_fault_int_mask(bq,
+			TS_BUS_FAULT | TS_DIE_FAULT | TS_BAT_FAULT | BAT_OCP_FAULT);
+	if (ret) {
+		bq_err("failed to set fault mask:%d\n", ret);
+		return ret;
+	}
+//#endif
+	return ret;
+}
+
+static int bq2597x_init_regulation(struct bq2597x *bq)
+{
+	bq2597x_set_ibat_reg_th(bq, 200);
+	bq2597x_set_vbat_reg_th(bq, 50);
+
+	bq2597x_set_vdrop_deglitch(bq, 5000);
+	bq2597x_set_vdrop_th(bq, 400);
+
+	bq2597x_enable_regulation(bq, true);
+
+	return 0;
+}
+
+static int bq2597x_init_device(struct bq2597x *bq)
+{
+	int ret;
+	u8 val;
+	bq2597x_enable_wdt(bq, false);
+
+	bq2597x_set_ss_timeout(bq, 1500);
+	bq2597x_set_ibus_ucp_thr(bq, 300);
+	bq2597x_enable_ucp(bq,1);
+	bq2597x_set_sense_resistor(bq, bq->cfg->sense_r_mohm);
+
+	bq2597x_init_protection(bq);
+	bq2597x_init_adc(bq);
+	bq2597x_init_int_src(bq);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_13, &val);
+	bq_err("Bq device ID = 0x%02X\n", val);
+	if (!ret && val == BQ25968_DEV_ID) {
+		bq_err("Bq device ID = 0x%02X\n", val);
+		return 0;
+	}
+
+	bq2597x_init_regulation(bq);
+
+	return 0;
+}
+
+static int bq2597x_set_present(struct bq2597x *bq, bool present)
+{
+    if (present != bq->usb_present) {
+        bq_info("changed usb_present [%d] -> [%d]\n", bq->usb_present, present);
+        if (present) {
+            bq2597x_init_device(bq);
+        }
+        bq->usb_present = present;
+    }
+
+	return 0;
+}
+
+static ssize_t bq2597x_show_registers(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct bq2597x *bq = dev_get_drvdata(dev);
+	u8 addr;
+	u8 val;
+	u8 tmpbuf[300];
+	int len;
+	int idx = 0;
+	int ret;
+
+	idx = snprintf(buf, PAGE_SIZE, "%s:\n", "bq25970");
+	for (addr = 0x0; addr <= 0x36; addr++) {
+		ret = bq2597x_read_byte(bq, addr, &val);
+		if (ret == 0) {
+			len = snprintf(tmpbuf, PAGE_SIZE - idx,
+					"Reg[%.2X] = 0x%.2x\n", addr, val);
+			memcpy(&buf[idx], tmpbuf, len);
+			idx += len;
+		}
+	}
+
+	return idx;
+}
+
+static ssize_t bq2597x_store_register(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct bq2597x *bq = dev_get_drvdata(dev);
+	int ret;
+	unsigned int reg;
+	unsigned int val;
+
+	ret = sscanf(buf, "%x %x", &reg, &val);
+	if (ret == 2 && reg <= 0x36)
+		bq2597x_write_byte(bq, (unsigned char)reg, (unsigned char)val);
+
+	return count;
+}
+
+static DEVICE_ATTR(registers, 0660, bq2597x_show_registers, bq2597x_store_register);
+
+#ifdef CONFIG_DUAL_BQ2597X
+static ssize_t bq2597x_show_diff_ti_bus_current(struct device *dev,struct device_attribute *attr,char *buf)
+{
+	struct bq2597x *bq = dev_get_drvdata(dev);
+	static struct power_supply *bq2597x_slave = NULL;
+	int diff_ti_bus_current = -1;
+	int ti_bus_current_master = 0;
+	int ti_bus_current_slave = 0;
+	int result = 0;
+	int rc;
+	int len;
+	union power_supply_propval pval = {
+		0,
+	};
+	if(bq->mode == BQ25970_ROLE_MASTER){
+		/*get bq2597x_slave ti_bus_current*/
+		if(!bq2597x_slave){
+			bq2597x_slave = power_supply_get_by_name("bq2597x-slave");
+			if(!bq2597x_slave){
+				bq_dbg("failed get bq2597x-slave \n");
+				return 0;
+			}
+			bq_dbg("success get bq2597x-slave \n");
+		}
+		rc = power_supply_get_property(bq2597x_slave,POWER_SUPPLY_PROP_TI_BUS_CURRENT,&pval);
+		if (rc < 0) {
+			bq_dbg("failed get bq2597x-slave ti_bus_current \n");
+			return -EINVAL;
+		}
+		ti_bus_current_slave = pval.intval;
+		/*get bq2597x_master ti_bus_current*/
+		rc = bq2597x_get_adc_data(bq, ADC_IBUS, &result);
+		if (!rc)
+			ti_bus_current_master = result;
+		else
+			ti_bus_current_master = bq->ibus_curr;
+		/* get diff_ti_bus_current = ti_bus_current_master - ti_bus_current_slave */
+		if(ti_bus_current_master > ti_bus_current_slave)
+			diff_ti_bus_current = ti_bus_current_master - ti_bus_current_slave;
+		else
+			diff_ti_bus_current = ti_bus_current_slave - ti_bus_current_master;
+	} else if (bq->mode == BQ25970_ROLE_SLAVE) {
+		diff_ti_bus_current = -1;
+	}
+	len = snprintf(buf, 1024, "%d\n", diff_ti_bus_current);
+	return len;
+}
+static DEVICE_ATTR(diff_ti_bus_current,0660,bq2597x_show_diff_ti_bus_current,NULL);
+#endif
+static struct attribute *bq2597x_attributes[] = {
+	&dev_attr_registers.attr,
+#ifdef CONFIG_DUAL_BQ2597X
+	&dev_attr_diff_ti_bus_current.attr,
+#endif
+	NULL,
+};
+
+static const struct attribute_group bq2597x_attr_group = {
+	.attrs = bq2597x_attributes,
+};
+
+static enum power_supply_property bq2597x_charger_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+};
+static void bq2597x_check_alarm_status(struct bq2597x *bq);
+static void bq2597x_check_fault_status(struct bq2597x *bq);
+
+static int bq2597x_charger_get_property(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	struct bq2597x *bq = power_supply_get_drvdata(psy);
+	bool result;
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		bq2597x_check_charge_enabled(bq, &result);
+		val->intval = result;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = bq->usb_present;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		ret = bq2597x_get_work_mode(bq, &bq->mode);
+		if (ret) {
+			val->strval = "unknown";
+		} else {
+			if (bq->mode == BQ25970_ROLE_MASTER)
+				val->strval = "bq2597x-master";
+			else if (bq->mode == BQ25970_ROLE_SLAVE)
+				val->strval = "bq2597x-slave";
+			else
+				val->strval = "bq2597x-standalone";
+		}
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+static int bq2597x_charger_set_property(struct power_supply *psy,
+				       enum power_supply_property prop,
+				       const union power_supply_propval *val)
+{
+	struct bq2597x *bq = power_supply_get_drvdata(psy);
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		bq2597x_set_present(bq, !!val->intval);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bq2597x_charger_is_writeable(struct power_supply *psy,
+				       enum power_supply_property prop)
+{
+	int ret;
+
+	switch (prop) {
+	//case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+	//case POWER_SUPPLY_PROP_TI_SET_BUS_PROTECTION_FOR_QC3:
+	//	ret = 1;
+	//	break;
+	default:
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+static int bq2597x_psy_register(struct bq2597x *bq)
+{
+	bq->psy_cfg.drv_data = bq;
+	bq->psy_cfg.of_node = bq->dev->of_node;
+
+	if (bq->mode == BQ25970_ROLE_MASTER)
+		bq->psy_desc.name = "bq2597x-master";
+	else if (bq->mode == BQ25970_ROLE_SLAVE)
+		bq->psy_desc.name = "bq2597x-slave";
+	else
+		bq->psy_desc.name = "bq2597x-standalone";
+
+	bq->psy_desc.type = POWER_SUPPLY_TYPE_USB;
+	bq->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) |
+		     BIT(POWER_SUPPLY_USB_TYPE_SDP)     |
+		     BIT(POWER_SUPPLY_USB_TYPE_DCP)     |
+		     BIT(POWER_SUPPLY_USB_TYPE_CDP)     |
+		     BIT(POWER_SUPPLY_USB_TYPE_ACA)     |
+		     BIT(POWER_SUPPLY_USB_TYPE_C)       |
+		     BIT(POWER_SUPPLY_USB_TYPE_PD)      |
+		     BIT(POWER_SUPPLY_USB_TYPE_PD_DRP)  |
+		     BIT(POWER_SUPPLY_USB_TYPE_PD_PPS)  |
+		     BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID),
+	bq->psy_desc.properties = bq2597x_charger_props;
+	bq->psy_desc.num_properties = ARRAY_SIZE(bq2597x_charger_props);
+	bq->psy_desc.get_property = bq2597x_charger_get_property;
+	bq->psy_desc.set_property = bq2597x_charger_set_property;
+	bq->psy_desc.property_is_writeable = bq2597x_charger_is_writeable;
+
+	bq->fc2_psy = devm_power_supply_register(bq->dev,
+			&bq->psy_desc, &bq->psy_cfg);
+	if (IS_ERR(bq->fc2_psy)) {
+		bq_err("failed to register fc2_psy\n");
+		return PTR_ERR(bq->fc2_psy);
+	}
+
+	bq_info("%s power supply register successfully\n", bq->psy_desc.name);
+
+	return 0;
+}
+
+static void bq2597x_dump_important_regs(struct bq2597x *bq)
+{
+
+	int ret;
+	u8 val;
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0A, &val);
+	if (!ret)
+		bq_err("dump converter state Reg [%02X] = 0x%02X\n",
+				BQ2597X_REG_0A, val);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0D, &val);
+	if (!ret)
+		bq_err("dump int stat Reg[%02X] = 0x%02X\n",
+				BQ2597X_REG_0D, val);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0E, &val);
+	if (!ret)
+		bq_err("dump int flag Reg[%02X] = 0x%02X\n",
+				BQ2597X_REG_0E, val);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_10, &val);
+	if (!ret)
+		bq_err("dump fault stat Reg[%02X] = 0x%02X\n",
+				BQ2597X_REG_10, val);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_11, &val);
+	if (!ret)
+		bq_err("dump fault flag Reg[%02X] = 0x%02X\n",
+				BQ2597X_REG_11, val);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_2D, &val);
+	if (!ret)
+		bq_err("dump regulation flag Reg[%02X] = 0x%02X\n",
+				BQ2597X_REG_2D, val);
+}
+
+static void bq2597x_check_alarm_status(struct bq2597x *bq)
+{
+	int ret;
+	u8 flag = 0;
+	u8 stat = 0;
+
+	mutex_lock(&bq->data_lock);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_08, &flag);
+	if (!ret && (flag & BQ2597X_IBUS_UCP_FALL_FLAG_MASK))
+		bq_info("UCP_FLAG =0x%02X\n",
+			!!(flag & BQ2597X_IBUS_UCP_FALL_FLAG_MASK));
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_2D, &flag);
+	if (!ret && (flag & BQ2597X_VDROP_OVP_FLAG_MASK))
+		bq_info("VDROP_OVP_FLAG =0x%02X\n",
+			!!(flag & BQ2597X_VDROP_OVP_FLAG_MASK));
+
+	/*read to clear alarm flag*/
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0E, &flag);
+	if (!ret && flag)
+		bq_info("INT_FLAG =0x%02X\n", flag);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0D, &stat);
+	if (!ret && stat != bq->prev_alarm) {
+		bq_info("INT_STAT = 0X%02x\n", stat);
+		bq->prev_alarm = stat;
+		bq->bat_ovp_alarm = !!(stat & BAT_OVP_ALARM);
+		bq->bat_ocp_alarm = !!(stat & BAT_OCP_ALARM);
+		bq->bus_ovp_alarm = !!(stat & BUS_OVP_ALARM);
+		bq->bus_ocp_alarm = !!(stat & BUS_OCP_ALARM);
+		bq->batt_present  = !!(stat & VBAT_INSERT);
+		bq->vbus_present  = !!(stat & VBUS_INSERT);
+		bq->bat_ucp_alarm = !!(stat & BAT_UCP_ALARM);
+	}
+
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_08, &stat);
+	if (!ret && (stat & 0x50))
+		bq_err("Reg[08]BUS_UCPOVP = 0x%02X\n", stat);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_0A, &stat);
+	if (!ret && (stat & 0x02))
+		bq_err("Reg[0A]CONV_OCP = 0x%02X\n", stat);
+
+	mutex_unlock(&bq->data_lock);
+}
+
+static void bq2597x_check_fault_status(struct bq2597x *bq)
+{
+	int ret;
+	u8 flag = 0;
+	u8 stat = 0;
+	bool changed = false;
+
+	mutex_lock(&bq->data_lock);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_10, &stat);
+	if (!ret && stat)
+		bq_err("FAULT_STAT = 0x%02X\n", stat);
+
+	ret = bq2597x_read_byte(bq, BQ2597X_REG_11, &flag);
+	if (!ret && flag)
+		bq_err("FAULT_FLAG = 0x%02X\n", flag);
+
+	if (!ret && flag != bq->prev_fault) {
+		changed = true;
+		bq->prev_fault = flag;
+		bq->bat_ovp_fault = !!(flag & BAT_OVP_FAULT);
+		bq->bat_ocp_fault = !!(flag & BAT_OCP_FAULT);
+		bq->bus_ovp_fault = !!(flag & BUS_OVP_FAULT);
+		bq->bus_ocp_fault = !!(flag & BUS_OCP_FAULT);
+		bq->bat_therm_fault = !!(flag & TS_BAT_FAULT);
+		bq->bus_therm_fault = !!(flag & TS_BUS_FAULT);
+
+		bq->bat_therm_alarm = !!(flag & TBUS_TBAT_ALARM);
+		bq->bus_therm_alarm = !!(flag & TBUS_TBAT_ALARM);
+	}
+
+	mutex_unlock(&bq->data_lock);
+}
+
+/*
+ * interrupt does nothing, just info event chagne, other module could get info
+ * through power supply interface
+ */
+static irqreturn_t bq2597x_charger_interrupt(int irq, void *dev_id)
+{
+	struct bq2597x *bq = dev_id;
+
+	bq_info("INT OCCURED\n");
+
+	mutex_lock(&bq->irq_complete);
+	bq->irq_waiting = true;
+	if (!bq->resume_completed) {
+		dev_dbg(bq->dev, "IRQ triggered before device-resume\n");
+		if (!bq->irq_disabled) {
+			disable_irq_nosync(irq);
+			bq->irq_disabled = true;
+		}
+		bq->irq_waiting = false;
+		mutex_unlock(&bq->irq_complete);
+		return IRQ_HANDLED;
+	}
+	bq->irq_waiting = false;
+	/* dump some impoartant registers and alarm fault status for debug */
+	bq2597x_dump_important_regs(bq);
+	bq2597x_check_alarm_status(bq);
+	bq2597x_check_fault_status(bq);
+	mutex_unlock(&bq->irq_complete);
+
+	/* power_supply_changed(bq->fc2_psy); */
+
+	return IRQ_HANDLED;
+}
+
+
+static void determine_initial_status(struct bq2597x *bq)
+{
+	if (bq->client->irq)
+		bq2597x_charger_interrupt(bq->client->irq, bq);
+}
+
+static int show_registers(struct seq_file *m, void *data)
+{
+	struct bq2597x *bq = m->private;
+	u8 addr;
+	int ret;
+	u8 val;
+
+	for (addr = 0x0; addr <= 0x36; addr++) {
+		ret = bq2597x_read_byte(bq, addr, &val);
+		if (!ret)
+			seq_printf(m, "Reg[%02X] = 0x%02X\n", addr, val);
+	}
+	return 0;
+}
+
+
+static int reg_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct bq2597x *bq = inode->i_private;
+
+	return single_open(file, show_registers, bq);
+}
+
+
+static const struct file_operations reg_debugfs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= reg_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void create_debugfs_entry(struct bq2597x *bq)
+{
+	if (bq->mode == BQ25970_ROLE_MASTER)
+		bq->debug_root = debugfs_create_dir("bq2597x-master", NULL);
+	else if (bq->mode == BQ25970_ROLE_SLAVE)
+		bq->debug_root = debugfs_create_dir("bq2597x-slave", NULL);
+	else
+		bq->debug_root = debugfs_create_dir("bq2597x-standalone", NULL);
+
+	if (!bq->debug_root)
+		bq_err("Failed to create debug dir\n");
+
+	if (bq->debug_root) {
+		debugfs_create_file("registers",
+					S_IFREG | S_IRUGO,
+					bq->debug_root, bq, &reg_debugfs_ops);
+
+		debugfs_create_x32("skip_reads",
+					S_IFREG | S_IWUSR | S_IRUGO,
+					bq->debug_root,
+					&(bq->skip_reads));
+		debugfs_create_x32("skip_writes",
+					S_IFREG | S_IWUSR | S_IRUGO,
+					bq->debug_root,
+					&(bq->skip_writes));
+	}
+}
+
+static struct of_device_id bq2597x_charger_match_table[] = {
+	{
+		.compatible = "ti,bq2597x-standalone",
+		.data = &bq2597x_mode_data[BQ25970_STDALONE],
+	},
+	{
+		.compatible = "ti,bq2597x-master",
+		.data = &bq2597x_mode_data[BQ25970_MASTER],
+	},
+
+	{
+		.compatible = "ti,bq2597x-slave",
+		.data = &bq2597x_mode_data[BQ25970_SLAVE],
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, bq2597x_charger_match_table);
+
+static int bq2597x_notifier_call(struct notifier_block *nb,
+		unsigned long val, void *v)
+{
+	struct bq2597x *chip = container_of(nb, struct bq2597x, nb);
+	struct power_supply *psy = v;
+	union power_supply_propval propval;
+
+	if (psy == chip->typec_psy) {
+		power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &propval);
+
+		chip->charge_state = propval.intval;
+        chip->usb_present = !!propval.intval;
+
+		power_supply_changed(chip->fc2_psy);
+
+        if (chip->usb_present) {
+            msleep(30000);
+			bq2597x_enable_charge(chip, true);
+			bq2597x_check_charge_enabled(chip, &chip->charge_enabled);
+        }
+        else {
+			bq2597x_enable_charge(chip, false);
+			bq2597x_check_charge_enabled(chip, &chip->charge_enabled);
+        }
+	}
+
+	return NOTIFY_OK;
+}
+
+static int bq2597x_charger_probe(struct i2c_client *client)
+{
+	struct bq2597x *bq;
+	const struct of_device_id *match;
+	struct device_node *node = client->dev.of_node;
+	int ret;
+
+	bq = devm_kzalloc(&client->dev, sizeof(struct bq2597x), GFP_KERNEL);
+	if (!bq)
+		return -ENOMEM;
+
+	bq->dev = &client->dev;
+
+	bq->client = client;
+	i2c_set_clientdata(client, bq);
+
+	mutex_init(&bq->i2c_rw_lock);
+	mutex_init(&bq->data_lock);
+	mutex_init(&bq->charging_disable_lock);
+	mutex_init(&bq->irq_complete);
+
+	bq->resume_completed = true;
+	bq->irq_waiting = false;
+
+	ret = bq2597x_detect_device(bq);
+	if (ret) {
+		bq_err("No bq2597x device found!\n");
+		return -ENODEV;
+	}
+
+	match = of_match_node(bq2597x_charger_match_table, node);
+	if (match == NULL) {
+		bq_err("device tree match not found!\n");
+		return -ENODEV;
+	}
+
+	bq2597x_get_work_mode(bq, &bq->mode);
+
+	if (bq->mode !=  *(int *)match->data) {
+		bq_err("device operation mode mismatch with dts configuration\n");
+		return -EINVAL;
+	}
+
+	ret = bq2597x_parse_dt(bq, &client->dev);
+	if (ret)
+		return -EIO;
+
+	ret = bq2597x_init_device(bq);
+	if (ret) {
+		bq_err("Failed to init device\n");
+		return ret;
+	}
+
+	determine_initial_status(bq);
+
+	ret = bq2597x_psy_register(bq);
+	if (ret)
+		return ret;
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+				NULL, bq2597x_charger_interrupt,
+				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				"bq2597x charger irq", bq);
+		if (ret < 0) {
+			bq_err("request irq for irq=%d failed, ret =%d\n",
+							client->irq, ret);
+			goto err_1;
+		}
+		/* no need to enable this irq as a wakeup source */
+		/* enable_irq_wake(client->irq); */
+	}
+
+	device_init_wakeup(bq->dev, 1);
+	create_debugfs_entry(bq);
+
+	ret = sysfs_create_group(&bq->dev->kobj, &bq2597x_attr_group);
+	if (ret) {
+		bq_err("failed to register sysfs. err: %d\n", ret);
+		goto err_1;
+	}
+
+	/* determine_initial_status(bq); */
+
+	bq_info("bq2597x probe successfully, Part Num:%d\n!",
+				bq->part_no);
+
+	bq->typec_psy = power_supply_get_by_name(
+			"tcpm-source-psy-c440000.spmi:pmic@2:typec@1500");
+	if (IS_ERR(bq->typec_psy)) {
+		ret = PTR_ERR(bq->typec_psy);
+		dev_warn(bq->dev, "Failed to get USB Type-C: %d\n", ret);
+		bq->typec_psy = NULL;
+	}
+
+	if (bq->typec_psy) {
+		bq->nb.notifier_call = bq2597x_notifier_call;
+		ret = power_supply_reg_notifier(&bq->nb);
+		if (ret) {
+			dev_err(bq->dev,
+				"Failed to register notifier: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+
+err_1:
+	power_supply_unregister(bq->fc2_psy);
+	return ret;
+}
+
+
+static inline bool is_device_suspended(struct bq2597x *bq)
+{
+	return !bq->resume_completed;
+}
+
+static int bq2597x_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bq2597x *bq = i2c_get_clientdata(client);
+
+	mutex_lock(&bq->irq_complete);
+	bq->resume_completed = false;
+	mutex_unlock(&bq->irq_complete);
+	bq2597x_enable_adc(bq, false);
+	bq_err("Suspend successfully!");
+
+	return 0;
+}
+
+static int bq2597x_suspend_noirq(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bq2597x *bq = i2c_get_clientdata(client);
+
+	if (bq->irq_waiting) {
+		pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n");
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static int bq2597x_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bq2597x *bq = i2c_get_clientdata(client);
+
+	mutex_lock(&bq->irq_complete);
+	bq->resume_completed = true;
+	if (bq->irq_waiting) {
+		bq->irq_disabled = false;
+		enable_irq(client->irq);
+		mutex_unlock(&bq->irq_complete);
+		//bq2597x_charger_interrupt(client->irq, bq);
+	} else {
+		mutex_unlock(&bq->irq_complete);
+	}
+	bq2597x_enable_adc(bq, true);
+	power_supply_changed(bq->fc2_psy);
+	bq_err("Resume successfully!");
+
+	return 0;
+}
+static void bq2597x_charger_remove(struct i2c_client *client)
+{
+	struct bq2597x *bq = i2c_get_clientdata(client);
+
+	bq2597x_enable_adc(bq, false);
+
+	power_supply_unregister(bq->fc2_psy);
+
+	mutex_destroy(&bq->charging_disable_lock);
+	mutex_destroy(&bq->data_lock);
+	mutex_destroy(&bq->i2c_rw_lock);
+	mutex_destroy(&bq->irq_complete);
+
+	debugfs_remove_recursive(bq->debug_root);
+
+	sysfs_remove_group(&bq->dev->kobj, &bq2597x_attr_group);
+}
+
+
+static void bq2597x_charger_shutdown(struct i2c_client *client)
+{
+	struct bq2597x *bq = i2c_get_clientdata(client);
+
+	bq2597x_enable_adc(bq, false);
+}
+
+static const struct dev_pm_ops bq2597x_pm_ops = {
+	.resume		= bq2597x_resume,
+	.suspend_noirq = bq2597x_suspend_noirq,
+	.suspend	= bq2597x_suspend,
+};
+
+static const struct i2c_device_id bq2597x_charger_id[] = {
+	{"bq2597x-standalone", BQ25970_ROLE_STDALONE},
+	{"bq2597x-master", BQ25970_ROLE_MASTER},
+	{"bq2597x-slave", BQ25970_ROLE_SLAVE},
+	{},
+};
+
+static struct i2c_driver bq2597x_charger_driver = {
+	.driver		= {
+		.name	= "bq2597x-charger",
+		.owner	= THIS_MODULE,
+		.of_match_table = bq2597x_charger_match_table,
+		.pm	= &bq2597x_pm_ops,
+	},
+	.id_table	= bq2597x_charger_id,
+
+	.probe		= bq2597x_charger_probe,
+	.remove		= bq2597x_charger_remove,
+	.shutdown	= bq2597x_charger_shutdown,
+};
+
+module_i2c_driver(bq2597x_charger_driver);
+
+MODULE_DESCRIPTION("TI BQ2597x Charger Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/power/supply/bq25970_reg.h b/drivers/power/supply/bq25970_reg.h
new file mode 100644
index 0000000000000..7f4515befc6dc
--- /dev/null
+++ b/drivers/power/supply/bq25970_reg.h
@@ -0,0 +1,821 @@
+
+#ifndef __BQ2597X_HEADER__
+#define __BQ2597X_HEADER__
+
+/* Register 00h */
+#define BQ2597X_REG_00					0x00
+#define	BQ2597X_BAT_OVP_DIS_MASK			0x80
+#define	BQ2597X_BAT_OVP_DIS_SHIFT			7
+#define	BQ2597X_BAT_OVP_ENABLE				0
+#define	BQ2597X_BAT_OVP_DISABLE				1
+
+#define BQ2597X_BAT_OVP_MASK				0x3F
+#define BQ2597X_BAT_OVP_SHIFT				0
+#define BQ2597X_BAT_OVP_BASE				3475
+#define BQ2597X_BAT_OVP_LSB				25
+
+/* Register 01h */
+#define BQ2597X_REG_01					0x01
+#define BQ2597X_BAT_OVP_ALM_DIS_MASK			0x80
+#define BQ2597X_BAT_OVP_ALM_DIS_SHIFT			7
+#define BQ2597X_BAT_OVP_ALM_ENABLE			0
+#define BQ2597X_BAT_OVP_ALM_DISABLE			1
+
+#define BQ2597X_BAT_OVP_ALM_MASK			0x3F
+#define BQ2597X_BAT_OVP_ALM_SHIFT			0
+#define BQ2597X_BAT_OVP_ALM_BASE			3500
+#define BQ2597X_BAT_OVP_ALM_LSB				25
+
+/* Register 02h */
+#define BQ2597X_REG_02					0x02
+#define	BQ2597X_BAT_OCP_DIS_MASK			0x80
+#define	BQ2597X_BAT_OCP_DIS_SHIFT			7
+#define BQ2597X_BAT_OCP_ENABLE				0
+#define BQ2597X_BAT_OCP_DISABLE				1
+
+#define BQ2597X_BAT_OCP_MASK				0x7F
+#define BQ2597X_BAT_OCP_SHIFT				0
+#define BQ2597X_BAT_OCP_BASE				2000
+#define BQ2597X_BAT_OCP_LSB				100
+
+/* Register 03h */
+#define BQ2597X_REG_03					0x03
+#define BQ2597X_BAT_OCP_ALM_DIS_MASK			0x80
+#define BQ2597X_BAT_OCP_ALM_DIS_SHIFT			7
+#define BQ2597X_BAT_OCP_ALM_ENABLE			0
+#define BQ2597X_BAT_OCP_ALM_DISABLE			1
+
+#define BQ2597X_BAT_OCP_ALM_MASK			0x7F
+#define BQ2597X_BAT_OCP_ALM_SHIFT			0
+#define BQ2597X_BAT_OCP_ALM_BASE			2000
+#define BQ2597X_BAT_OCP_ALM_LSB				100
+
+/* Register 04h */
+#define BQ2597X_REG_04					0x04
+#define	BQ2597X_BAT_UCP_ALM_DIS_MASK			0x80
+#define	BQ2597X_BAT_UCP_ALM_DIS_SHIFT			7
+#define	BQ2597X_BAT_UCP_ALM_ENABLE			0
+#define	BQ2597X_BAT_UCP_ALM_DISABLE			1
+
+#define	BQ2597X_BAT_UCP_ALM_MASK			0x7F
+#define	BQ2597X_BAT_UCP_ALM_SHIFT			0
+#define	BQ2597X_BAT_UCP_ALM_BASE			0
+#define	BQ2597X_BAT_UCP_ALM_LSB				50
+
+/* Register 05h */
+#define BQ2597X_REG_05					0x05
+#define BQ2597X_AC_OVP_STAT_MASK			0x80
+#define BQ2597X_AC_OVP_STAT_SHIFT			7
+
+#define BQ2597X_AC_OVP_FLAG_MASK			0x40
+#define BQ2597X_AC_OVP_FLAG_SHIFT			6
+
+#define BQ2597X_AC_OVP_MASK_MASK			0x20
+#define BQ2597X_AC_OVP_MASK_SHIFT			5
+
+#define BQ2597X_VDROP_THRESHOLD_SET_MASK		0x10
+#define BQ2597X_VDROP_THRESHOLD_SET_SHIFT		4
+#define BQ2597X_VDROP_THRESHOLD_300MV			0
+#define BQ2597X_VDROP_THRESHOLD_400MV			1
+
+#define BQ2597X_VDROP_DEGLITCH_SET_MASK			0x08
+#define BQ2597X_VDROP_DEGLITCH_SET_SHIFT		3
+#define BQ2597X_VDROP_DEGLITCH_8US			0
+#define BQ2597X_VDROP_DEGLITCH_5MS			1
+
+#define BQ2597X_AC_OVP_MASK				0x07
+#define BQ2597X_AC_OVP_SHIFT				0
+#define BQ2597X_AC_OVP_BASE				11
+#define BQ2597X_AC_OVP_LSB				1
+#define BQ2597X_AC_OVP_6P5V				65
+
+/* Register 06h */
+#define BQ2597X_REG_06					0x06
+#define BQ2597X_VBUS_PD_EN_MASK				0x80
+#define BQ2597X_VBUS_PD_EN_SHIFT			7
+#define BQ2597X_VBUS_PD_ENABLE				1
+#define BQ2597X_VBUS_PD_DISABLE				0
+
+#define BQ2597X_BUS_OVP_MASK				0x7F
+#define BQ2597X_BUS_OVP_SHIFT				0
+#define BQ2597X_BUS_OVP_BASE				5950
+#define BQ2597X_BUS_OVP_LSB				50
+
+/* Register 07h */
+#define BQ2597X_REG_07					0x07
+#define BQ2597X_BUS_OVP_ALM_DIS_MASK			0x80
+#define BQ2597X_BUS_OVP_ALM_DIS_SHIFT			7
+#define BQ2597X_BUS_OVP_ALM_ENABLE			0
+#define BQ2597X_BUS_OVP_ALM_DISABLE			1
+
+#define BQ2597X_BUS_OVP_ALM_MASK			0x7F
+#define BQ2597X_BUS_OVP_ALM_SHIFT			0
+#define BQ2597X_BUS_OVP_ALM_BASE			6000
+#define BQ2597X_BUS_OVP_ALM_LSB				50
+
+/* Register 08h */
+#define BQ2597X_REG_08					0x08
+#define BQ2597X_BUS_OCP_DIS_MASK			0x80
+#define BQ2597X_BUS_OCP_DIS_SHIFT			7
+#define	BQ2597X_BUS_OCP_ENABLE				0
+#define	BQ2597X_BUS_OCP_DISABLE				1
+
+#define BQ2597X_IBUS_UCP_RISE_FLAG_MASK			0x40
+#define BQ2597X_IBUS_UCP_RISE_FLAG_SHIFT		6
+
+#define BQ2597X_IBUS_UCP_RISE_MASK_MASK			0x20
+#define BQ2597X_IBUS_UCP_RISE_MASK_SHIFT		5
+#define BQ2597X_IBUS_UCP_RISE_MASK_ENABLE		1
+#define BQ2597X_IBUS_UCP_RISE_MASK_DISABLE		0
+
+#define BQ2597X_IBUS_UCP_FALL_FLAG_MASK			0x10
+#define BQ2597X_IBUS_UCP_FALL_FLAG_SHIFT		4
+
+#define BQ2597X_BUS_OCP_MASK				0x0F
+#define BQ2597X_BUS_OCP_SHIFT				0
+#define BQ2597X_BUS_OCP_BASE				1000
+#define BQ2597X_BUS_OCP_LSB				250
+
+/* Register 09h */
+#define BQ2597X_REG_09					0x09
+#define BQ2597X_BUS_OCP_ALM_DIS_MASK			0x80
+#define BQ2597X_BUS_OCP_ALM_DIS_SHIFT			7
+#define BQ2597X_BUS_OCP_ALM_ENABLE			0
+#define BQ2597X_BUS_OCP_ALM_DISABLE			1
+
+#define BQ2597X_BUS_OCP_ALM_MASK			0x7F
+#define BQ2597X_BUS_OCP_ALM_SHIFT			0
+#define BQ2597X_BUS_OCP_ALM_BASE			0
+#define BQ2597X_BUS_OCP_ALM_LSB				50
+
+/* Register 0Ah */
+#define BQ2597X_REG_0A					0x0A
+#define BQ2597X_TSHUT_FLAG_MASK				0x80
+#define BQ2597X_TSHUT_FLAG_SHIFT			7
+#define	VBUS_ERROR_LOW_MASK				BIT(5)
+#define	VBUS_ERROR_HIGH_MASK				BIT(4)
+
+#define BQ2597X_TSHUT_STAT_MASK				0x40
+#define BQ2597X_TSHUT_STAT_SHIFT			6
+
+#define BQ2597X_VBUS_ERRORLO_STAT_MASK			0x20
+#define BQ2597X_VBUS_ERRORLO_STAT_SHIFT			5
+
+#define BQ2597X_VBUS_ERRORHI_STAT_MASK			0x10
+#define BQ2597X_VBUS_ERRORHI_STAT_SHIFT			4
+
+#define BQ2597X_SS_TIMEOUT_FLAG_MASK			0x08
+#define BQ2597X_SS_TIMEOUT_FLAG_SHIFT			3
+
+#define BQ2597X_CONV_SWITCHING_STAT_MASK		0x04
+#define BQ2597X_CONV_SWITCHING_STAT_SHIFT		2
+
+#define BQ2597X_CONV_OCP_FLAG_MASK			0x02
+#define BQ2597X_CONV_OCP_FLAG_SHIFT			1
+
+#define BQ2597X_PIN_DIAG_FALL_FLAG_MASK			0x01
+#define BQ2597X_PIN_DIAG_FALL_FLAG_SHIFT		0
+
+/* Register 0Bh */
+#define BQ2597X_REG_0B					0x0B
+#define BQ2597X_REG_RST_MASK				0x80
+#define BQ2597X_REG_RST_SHIFT				7
+#define BQ2597X_REG_RST_ENABLE				1
+#define BQ2597X_REG_RST_DISABLE				0
+
+#define BQ2597X_FSW_SET_MASK				0x70
+#define BQ2597X_FSW_SET_SHIFT				4
+#define BQ2597X_FSW_SET_187P5KHZ			0
+#define BQ2597X_FSW_SET_250KHZ				1
+#define BQ2597X_FSW_SET_300KHZ				2
+#define BQ2597X_FSW_SET_375KHZ				3
+#define BQ2597X_FSW_SET_500KHZ				4
+#define BQ2597X_FSW_SET_750KHZ				5
+
+#define BQ2597X_WD_TIMEOUT_FLAG_MASK			0x08
+#define BQ2597X_WD_TIMEOUT_SHIFT			3
+
+#define BQ2597X_WATCHDOG_DIS_MASK			0x04
+#define BQ2597X_WATCHDOG_DIS_SHIFT			2
+#define BQ2597X_WATCHDOG_ENABLE				0
+#define BQ2597X_WATCHDOG_DISABLE			1
+
+#define BQ2597X_WATCHDOG_MASK				0x03
+#define BQ2597X_WATCHDOG_SHIFT				0
+#define BQ2597X_WATCHDOG_0P5S				0
+#define BQ2597X_WATCHDOG_1S				1
+#define BQ2597X_WATCHDOG_5S				2
+#define BQ2597X_WATCHDOG_30S				3
+
+/* Register 0Ch */
+#define BQ2597X_REG_0C					0x0C
+#define BQ2597X_CHG_EN_MASK				0x80
+#define BQ2597X_CHG_EN_SHIFT				7
+#define BQ2597X_CHG_ENABLE				1
+#define BQ2597X_CHG_DISABLE				0
+
+#define BQ2597X_MS_MASK					0x60
+#define BQ2597X_MS_SHIFT				5
+#define BQ2597X_MS_STANDALONE				0
+#define BQ2597X_MS_SLAVE				1
+#define BQ2597X_MS_MASTER				2
+
+#define BQ2597X_FREQ_SHIFT_MASK				0x18
+#define BQ2597X_FREQ_SHIFT_SHIFT			3
+#define BQ2597X_FREQ_SHIFT_NORMINAL			0
+#define BQ2597X_FREQ_SHIFT_POSITIVE10			1
+#define BQ2597X_FREQ_SHIFT_NEGATIVE10			2
+#define BQ2597X_FREQ_SHIFT_SPREAD_SPECTRUM		3
+
+#define BQ2597X_TSBUS_DIS_MASK				0x04
+#define BQ2597X_TSBUS_DIS_SHIFT				2
+#define BQ2597X_TSBUS_ENABLE				0
+#define BQ2597X_TSBUS_DISABLE				1
+
+#define BQ2597X_TSBAT_DIS_MASK				0x02
+#define BQ2597X_TSBAT_DIS_SHIFT				1
+#define BQ2597X_TSBAT_ENABLE				0
+#define BQ2597X_TSBAT_DISABLE				1
+
+#define BQ2597X_TDIE_DIS_MASK				0x01
+#define BQ2597X_TDIE_DIS_SHIFT				0
+#define BQ2597X_TDIE_ENABLE				0
+#define BQ2597X_TDIE_DISABLE				1
+
+/* Register 0Dh */
+#define BQ2597X_REG_0D					0x0D
+#define BQ2597X_BAT_OVP_ALM_STAT_MASK			0x80
+#define BQ2597X_BAT_OVP_ALM_STAT_SHIFT			7
+
+#define BQ2597X_BAT_OCP_ALM_STAT_MASK			0x40
+#define BQ2597X_BAT_OCP_ALM_STAT_SHIFT			6
+
+#define BQ2597X_BUS_OVP_ALM_STAT_MASK			0x20
+#define BQ2597X_BUS_OVP_ALM_STAT_SHIFT			5
+
+#define BQ2597X_BUS_OCP_ALM_STAT_MASK			0x10
+#define BQ2597X_BUS_OCP_ALM_STAT_SHIFT			4
+
+#define BQ2597X_BAT_UCP_ALM_STAT_MASK			0x08
+#define BQ2597X_BAT_UCP_ALM_STAT_SHIFT			3
+
+#define BQ2597X_ADAPTER_INSERT_STAT_MASK		0x04
+#define BQ2597X_ADAPTER_INSERT_STAT_SHIFT		2
+
+#define BQ2597X_VBAT_INSERT_STAT_MASK			0x02
+#define BQ2597X_VBAT_INSERT_STAT_SHIFT			1
+
+#define BQ2597X_ADC_DONE_STAT_MASK			0x01
+#define BQ2597X_ADC_DONE_STAT_SHIFT			0
+#define BQ2597X_ADC_DONE_STAT_COMPLETE			1
+#define BQ2597X_ADC_DONE_STAT_NOTCOMPLETE		0
+
+/* Register 0Eh */
+#define BQ2597X_REG_0E					0x0E
+#define BQ2597X_BAT_OVP_ALM_FLAG_MASK			0x80
+#define BQ2597X_BAT_OVP_ALM_FLAG_SHIFT			7
+
+#define BQ2597X_BAT_OCP_ALM_FLAG_MASK			0x40
+#define BQ2597X_BAT_OCP_ALM_FLAG_SHIFT			6
+
+#define BQ2597X_BUS_OVP_ALM_FLAG_MASK			0x20
+#define BQ2597X_BUS_OVP_ALM_FLAG_SHIFT			5
+
+#define BQ2597X_BUS_OCP_ALM_FLAG_MASK			0x10
+#define BQ2597X_BUS_OCP_ALM_FLAG_SHIFT			4
+
+#define BQ2597X_BAT_UCP_ALM_FLAG_MASK			0x08
+#define BQ2597X_BAT_UCP_ALM_FLAG_SHIFT			3
+
+#define BQ2597X_ADAPTER_INSERT_FLAG_MASK		0x04
+#define BQ2597X_ADAPTER_INSERT_FLAG_SHIFT		2
+
+#define BQ2597X_VBAT_INSERT_FLAG_MASK			0x02
+#define BQ2597X_VBAT_INSERT_FLAG_SHIFT			1
+
+#define BQ2597X_ADC_DONE_FLAG_MASK			0x01
+#define BQ2597X_ADC_DONE_FLAG_SHIFT			0
+#define BQ2597X_ADC_DONE_FLAG_COMPLETE			1
+#define BQ2597X_ADC_DONE_FLAG_NOTCOMPLETE		0
+
+/* Register 0Fh */
+#define BQ2597X_REG_0F					0x0F
+#define BQ2597X_BAT_OVP_ALM_MASK_MASK			0x80
+#define BQ2597X_BAT_OVP_ALM_MASK_SHIFT			7
+#define BQ2597X_BAT_OVP_ALM_MASK_ENABLE			1
+#define BQ2597X_BAT_OVP_ALM_MASK_DISABLE		0
+
+#define BQ2597X_BAT_OCP_ALM_MASK_MASK			0x40
+#define BQ2597X_BAT_OCP_ALM_MASK_SHIFT			6
+#define BQ2597X_BAT_OCP_ALM_MASK_ENABLE			1
+#define BQ2597X_BAT_OCP_ALM_MASK_DISABLE		0
+
+#define BQ2597X_BUS_OVP_ALM_MASK_MASK			0x20
+#define BQ2597X_BUS_OVP_ALM_MASK_SHIFT			5
+#define BQ2597X_BUS_OVP_ALM_MASK_ENABLE			1
+#define BQ2597X_BUS_OVP_ALM_MASK_DISABLE		0
+
+#define BQ2597X_BUS_OCP_ALM_MASK_MASK			0x10
+#define BQ2597X_BUS_OCP_ALM_MASK_SHIFT			4
+#define BQ2597X_BUS_OCP_ALM_MASK_ENABLE			1
+#define BQ2597X_BUS_OCP_ALM_MASK_DISABLE		0
+
+#define BQ2597X_BAT_UCP_ALM_MASK_MASK			0x08
+#define BQ2597X_BAT_UCP_ALM_MASK_SHIFT			3
+#define BQ2597X_BAT_UCP_ALM_MASK_ENABLE			1
+#define BQ2597X_BAT_UCP_ALM_MASK_DISABLE		0
+
+#define BQ2597X_ADAPTER_INSERT_MASK_MASK		0x04
+#define BQ2597X_ADAPTER_INSERT_MASK_SHIFT		2
+#define BQ2597X_ADAPTER_INSERT_MASK_ENABLE		1
+#define BQ2597X_ADAPTER_INSERT_MASK_DISABLE		0
+
+#define BQ2597X_VBAT_INSERT_MASK_MASK			0x02
+#define BQ2597X_VBAT_INSERT_MASK_SHIFT			1
+#define BQ2597X_VBAT_INSERT_MASK_ENABLE			1
+#define BQ2597X_VBAT_INSERT_MASK_DISABLE		0
+
+#define BQ2597X_ADC_DONE_MASK_MASK			0x01
+#define BQ2597X_ADC_DONE_MASK_SHIFT			0
+#define BQ2597X_ADC_DONE_MASK_ENABLE			1
+#define BQ2597X_ADC_DONE_MASK_DISABLE			0
+
+/* Register 10h */
+#define BQ2597X_REG_10					0x10
+#define BQ2597X_BAT_OVP_FLT_STAT_MASK			0x80
+#define BQ2597X_BAT_OVP_FLT_STAT_SHIFT			7
+
+#define BQ2597X_BAT_OCP_FLT_STAT_MASK			0x40
+#define BQ2597X_BAT_OCP_FLT_STAT_SHIFT			6
+
+#define BQ2597X_BUS_OVP_FLT_STAT_MASK			0x20
+#define BQ2597X_BUS_OVP_FLT_STAT_SHIFT			5
+
+#define BQ2597X_BUS_OCP_FLT_STAT_MASK			0x10
+#define BQ2597X_BUS_OCP_FLT_STAT_SHIFT			4
+
+#define BQ2597X_TSBUS_TSBAT_ALM_STAT_MASK		0x08
+#define BQ2597X_TSBUS_TSBAT_ALM_STAT_SHIFT		3
+
+#define BQ2597X_TSBAT_FLT_STAT_MASK			0x04
+#define BQ2597X_TSBAT_FLT_STAT_SHIFT			2
+
+#define BQ2597X_TSBUS_FLT_STAT_MASK			0x02
+#define BQ2597X_TSBUS_FLT_STAT_SHIFT			1
+
+#define BQ2597X_TDIE_ALM_STAT_MASK			0x01
+#define BQ2597X_TDIE_ALM_STAT_SHIFT			0
+
+/* Register 11h */
+#define BQ2597X_REG_11					0x11
+#define BQ2597X_BAT_OVP_FLT_FLAG_MASK			0x80
+#define BQ2597X_BAT_OVP_FLT_FLAG_SHIFT			7
+
+#define BQ2597X_BAT_OCP_FLT_FLAG_MASK			0x40
+#define BQ2597X_BAT_OCP_FLT_FLAG_SHIFT			6
+
+#define BQ2597X_BUS_OVP_FLT_FLAG_MASK			0x20
+#define BQ2597X_BUS_OVP_FLT_FLAG_SHIFT			5
+
+#define BQ2597X_BUS_OCP_FLT_FLAG_MASK			0x10
+#define BQ2597X_BUS_OCP_FLT_FLAG_SHIFT			4
+
+#define BQ2597X_TSBUS_TSBAT_ALM_FLAG_MASK		0x08
+#define BQ2597X_TSBUS_TSBAT_ALM_FLAG_SHIFT		3
+
+#define BQ2597X_TSBAT_FLT_FLAG_MASK			0x04
+#define BQ2597X_TSBAT_FLT_FLAG_SHIFT			2
+
+#define BQ2597X_TSBUS_FLT_FLAG_MASK			0x02
+#define BQ2597X_TSBUS_FLT_FLAG_SHIFT			1
+
+#define BQ2597X_TDIE_ALM_FLAG_MASK			0x01
+#define BQ2597X_TDIE_ALM_FLAG_SHIFT			0
+
+/* Register 12h */
+#define BQ2597X_REG_12					0x12
+#define BQ2597X_BAT_OVP_FLT_MASK_MASK			0x80
+#define BQ2597X_BAT_OVP_FLT_MASK_SHIFT			7
+#define BQ2597X_BAT_OVP_FLT_MASK_ENABLE			1
+#define BQ2597X_BAT_OVP_FLT_MASK_DISABLE		0
+
+#define BQ2597X_BAT_OCP_FLT_MASK_MASK			0x40
+#define BQ2597X_BAT_OCP_FLT_MASK_SHIFT			6
+#define BQ2597X_BAT_OCP_FLT_MASK_ENABLE			1
+#define BQ2597X_BAT_OCP_FLT_MASK_DISABLE		0
+
+#define BQ2597X_BUS_OVP_FLT_MASK_MASK			0x20
+#define BQ2597X_BUS_OVP_FLT_MASK_SHIFT			5
+#define BQ2597X_BUS_OVP_FLT_MASK_ENABLE			1
+#define BQ2597X_BUS_OVP_FLT_MASK_DISABLE		0
+
+#define BQ2597X_BUS_OCP_FLT_MASK_MASK			0x10
+#define BQ2597X_BUS_OCP_FLT_MASK_SHIFT			4
+#define BQ2597X_BUS_OCP_FLT_MASK_ENABLE			1
+#define BQ2597X_BUS_OCP_FLT_MASK_DISABLE		0
+
+#define BQ2597X_TSBUS_TSBAT_ALM_MASK_MASK		0x08
+#define BQ2597X_TSBUS_TSBAT_ALM_MASK_SHIFT		3
+#define BQ2597X_TSBUS_TSBAT_ALM_MASK_ENABLE		1
+#define BQ2597X_TSBUS_TSBAT_ALM_MASK_DISABLE		0
+
+#define BQ2597X_TSBAT_FLT_MASK_MASK			0x04
+#define BQ2597X_TSBAT_FLT_MASK_SHIFT			2
+#define BQ2597X_TSBAT_FLT_MASK_ENABLE			1
+#define BQ2597X_TSBAT_FLT_MASK_DISABLE			0
+
+#define BQ2597X_TSBUS_FLT_MASK_MASK			0x02
+#define BQ2597X_TSBUS_FLT_MASK_SHIFT			1
+#define BQ2597X_TSBUS_FLT_MASK_ENABLE			1
+#define BQ2597X_TSBUS_FLT_MASK_DISABLE			0
+
+#define BQ2597X_TDIE_ALM_MASK_MASK			0x01
+#define BQ2597X_TDIE_ALM_MASK_SHIFT			0
+#define BQ2597X_TDIE_ALM_MASK_ENABLE			1
+#define BQ2597X_TDIE_ALM_MASK_DISABLE			0
+
+/* Register 13h */
+#define BQ2597X_REG_13					0x13
+#define BQ2597X_DEV_ID_MASK				0x0F
+#define BQ2597X_DEV_ID_SHIFT				0
+#define BQ25968_DEV_ID					0x16
+
+#define BQ25970_DEVICE_ID				0x10
+#define SC8551_DEVICE_ID				0x00
+#define SC8551A_DEVICE_ID				0x51
+
+
+/* Register 14h */
+#define BQ2597X_REG_14					0x14
+#define BQ2597X_ADC_EN_MASK				0x80
+#define BQ2597X_ADC_EN_SHIFT				7
+#define BQ2597X_ADC_ENABLE				1
+#define BQ2597X_ADC_DISABLE				0
+
+#define BQ2597X_ADC_RATE_MASK				0x40
+#define BQ2597X_ADC_RATE_SHIFT				6
+#define BQ2597X_ADC_RATE_CONTINOUS			0
+#define BQ2597X_ADC_RATE_ONESHOT			1
+
+#define BQ2597X_ADC_AVG_MASK				0x20
+#define BQ2597X_ADC_AVG_SHIFT				5
+#define BQ2597X_ADC_AVG_DISABLE				0
+#define BQ2597X_ADC_AVG_ENABLE				1
+
+#define BQ2597X_ADC_AVG_INIT_MASK			0x10
+#define BQ2597X_ADC_AVG_INIT_SHIFT			4
+#define BQ2597X_ADC_AVG_INIT_EXIST_REG_VAL		0
+#define BQ2597X_ADC_AVG_INIT_NEW_CONVERSION		1
+
+#define BQ2597X_ADC_SAMPLE_MASK				0x0C
+#define BQ2597X_ADC_SAMPLE_SHIFT			2
+#define BQ2597X_ADC_SAMPLE_15BITS			0
+#define BQ2597X_ADC_SAMPLE_14BITS			1
+#define BQ2597X_ADC_SAMPLE_13BITS			2
+#define BQ2597X_ADC_SAMPLE_12BITS			3
+
+#define BQ2597X_IBUS_ADC_DIS_MASK			0x01
+#define BQ2597X_IBUS_ADC_DIS_SHIFT			0
+#define BQ2597X_IBUS_ADC_ENABLE				0
+#define BQ2597X_IBUS_ADC_DISABLE			1
+
+/* Register 15h */
+#define BQ2597X_REG_15					0x15
+#define BQ2597X_VBUS_ADC_DIS_MASK			0x80
+#define BQ2597X_VBUS_ADC_DIS_SHIFT			7
+#define BQ2597X_VBUS_ADC_ENABLE				0
+#define BQ2597X_VBUS_ADC_DISABLE			1
+
+#define BQ2597X_VAC_ADC_DIS_MASK			0x40
+#define BQ2597X_VAC_ADC_DIS_SHIFT			6
+#define BQ2597X_VAC_ADC_ENABLE				0
+#define BQ2597X_VAC_ADC_DISABLE				1
+
+#define BQ2597X_VOUT_ADC_DIS_MASK			0x20
+#define BQ2597X_VOUT_ADC_DIS_SHIFT			5
+#define BQ2597X_VOUT_ADC_ENABLE				0
+#define BQ2597X_VOUT_ADC_DISABLE			1
+
+#define BQ2597X_VBAT_ADC_DIS_MASK			0x10
+#define BQ2597X_VBAT_ADC_DIS_SHIFT			4
+#define BQ2597X_VBAT_ADC_ENABLE				0
+#define BQ2597X_VBAT_ADC_DISABLE			1
+
+#define BQ2597X_IBAT_ADC_DIS_MASK			0x08
+#define BQ2597X_IBAT_ADC_DIS_SHIFT			3
+#define BQ2597X_IBAT_ADC_ENABLE				0
+#define BQ2597X_IBAT_ADC_DISABLE			1
+
+#define BQ2597X_TSBUS_ADC_DIS_MASK			0x04
+#define BQ2597X_TSBUS_ADC_DIS_SHIFT			2
+#define BQ2597X_TSBUS_ADC_ENABLE			0
+#define BQ2597X_TSBUS_ADC_DISABLE			1
+
+#define BQ2597X_TSBAT_ADC_DIS_MASK			0x02
+#define BQ2597X_TSBAT_ADC_DIS_SHIFT			1
+#define BQ2597X_TSBAT_ADC_ENABLE			0
+#define BQ2597X_TSBAT_ADC_DISABLE			1
+
+#define BQ2597X_TDIE_ADC_DIS_MASK			0x01
+#define BQ2597X_TDIE_ADC_DIS_SHIFT			0
+#define BQ2597X_TDIE_ADC_ENABLE				0
+#define BQ2597X_TDIE_ADC_DISABLE			1
+
+/* Register 16h */
+#define BQ2597X_REG_16					0x16
+#define BQ2597X_IBUS_POL_MASK				0x80
+#define BQ2597X_IBUS_POL_SHIFT				7
+#define BQ2597X_IBUS_POL_POSITIVE			0
+#define BQ2597X_IBUS_POL_NAGETIVE			1
+
+#define BQ2597X_IBUS_ADC1_MASK				0x7F
+#define BQ2597X_IBUS_ADC1_SHIFT				0
+#define BQ2597X_IBUS_ADC1_BASE				0
+#define BQ2597X_IBUS_ADC1_LSB				256
+
+/* Register 17h */
+#define BQ2597X_REG_17					0x17
+#define BQ2597X_IBUS_ADC0_MASK				0xFF
+#define BQ2597X_IBUS_ADC0_SHIFT				0
+#define BQ2597X_IBUS_ADC0_BASE				0
+#define BQ2597X_IBUS_ADC0_LSB				1
+
+/* Register 18h */
+#define BQ2597X_REG_18					0x18
+#define BQ2597X_VBUS_POL_MASK				0x80
+#define BQ2597X_VBUS_POL_SHIFT				7
+#define BQ2597X_VBUS_POL_POSITIVE			0
+#define BQ2597X_VBUS_POL_NEGATIVE			1
+
+#define BQ2597X_VBUS_ADC1_MASK				0x7F
+#define BQ2597X_VBUS_ADC1_SHIFT				0
+#define BQ2597X_VBUS_ADC1_BASE				0
+#define BQ2597X_VBUS_ADC1_LSB				256
+
+/* Register 19h */
+#define BQ2597X_REG_19					0x19
+#define BQ2597X_VBUS_ADC0_MASK				0xFF
+#define BQ2597X_VBUS_ADC0_SHIFT				0
+#define BQ2597X_VBUS_ADC0_BASE				0
+#define BQ2597X_VBUS_ADC0_LSB				1
+
+/* Register 1Ah */
+#define BQ2597X_REG_1A					0x1A
+#define BQ2597X_VAC_POL_MASK				0x80
+#define BQ2597X_VAC_POL_SHIFT				7
+#define BQ2597X_VAC_POL_POSITIVE			0
+#define BQ2597X_VAC_POL_NEGATIVE			1
+
+#define BQ2597X_VAC_ADC1_MASK				0x7F
+#define BQ2597X_VAC_ADC1_SHIFT				0
+#define BQ2597X_VAC_ADC1_BASE				0
+#define BQ2597X_VAC_ADC1_LSB				256
+
+/* Register 1Bh */
+#define BQ2597X_REG_1B					0x1B
+#define BQ2597X_VAC_ADC0_MASK				0xFF
+#define BQ2597X_VAC_ADC0_SHIFT				0
+#define BQ2597X_VAC_ADC0_BASE				0
+#define BQ2597X_VAC_ADC0_LSB				1
+
+/* Register 1Ch */
+#define BQ2597X_REG_1C					0x1C
+#define BQ2597X_VOUT_POL_MASK				0x80
+#define BQ2597X_VOUT_POL_SHIFT				7
+#define BQ2597X_VOUT_POL_POSITIVE			0
+#define BQ2597X_VOUT_POL_NEGATIVE			1
+
+#define BQ2597X_VOUT_ADC1_MASK				0x7F
+#define BQ2597X_VOUT_ADC1_SHIFT				0
+#define BQ2597X_VOUT_ADC1_BASE				0
+#define BQ2597X_VOUT_ADC1_LSB				256
+
+/* Register 1Dh */
+#define BQ2597X_REG_1D					0x1D
+#define BQ2597X_VOUT_ADC0_MASK				0xFF
+#define BQ2597X_VOUT_ADC0_SHIFT				0
+#define BQ2597X_VOUT_ADC0_BASE				0
+#define BQ2597X_VOUT_ADC0_LSB				1
+
+/* Register 1Eh */
+#define BQ2597X_REG_1E					0x1E
+#define BQ2597X_VBAT_POL_MASK				0x80
+#define BQ2597X_VBAT_POL_SHIFT				7
+#define BQ2597X_VBAT_POL_POSITIVE			0
+#define BQ2597X_VBAT_POL_NEGATIVE			1
+
+#define BQ2597X_VBAT_ADC1_MASK				0x7F
+#define BQ2597X_VBAT_ADC1_SHIFT				0
+#define BQ2597X_VBAT_ADC1_BASE				0
+#define BQ2597X_VBAT_ADC1_LSB				256
+
+/* Register 1Fh */
+#define BQ2597X_REG_1F					0x1F
+#define BQ2597X_VBAT_ADC0_MASK				0xFF
+#define BQ2597X_VBAT_ADC0_SHIFT				0
+#define BQ2597X_VBAT_ADC0_BASE				0
+#define BQ2597X_VBAT_ADC0_LSB				1
+
+/* Register 20h */
+#define BQ2597X_REG_20					0x20
+#define BQ2597X_IBAT_POL_MASK				0x80
+#define BQ2597X_IBAT_POL_SHIFT				7
+#define BQ2597X_IBAT_POL_POSITIVE			0
+#define BQ2597X_IBAT_POL_NEGATIVE			1
+
+#define BQ2597X_IBAT_ADC1_MASK				0x7F
+#define BQ2597X_IBAT_ADC1_SHIFT				0
+#define BQ2597X_IBAT_ADC1_BASE				0
+#define BQ2597X_IBAT_ADC1_LSB				256
+
+/* Register 21h */
+#define BQ2597X_REG_21					0x21
+#define BQ2597X_IBAT_ADC0_MASK				0xFF
+#define BQ2597X_IBAT_ADC0_SHIFT				0
+#define BQ2597X_IBAT_ADC0_BASE				0
+#define BQ2597X_IBAT_ADC0_LSB				1
+
+/* Register 22h */
+#define BQ2597X_REG_22					0x22
+#define BQ2597X_TSBUS_POL_MASK				0x80
+#define BQ2597X_TSBUS_POL_SHIFT				7
+#define BQ2597X_TSBUS_POL_POSITIVE			0
+#define BQ2597X_TSBUS_POL_NEGATIVE			1
+
+#define BQ2597X_TSBUS_ADC1_MASK				0x7F
+#define BQ2597X_TSBUS_ADC1_SHIFT			0
+#define BQ2597X_TSBUS_ADC1_BASE				0
+#define BQ2597X_TSBUS_ADC1_LSB				25
+
+/* Register 23h */
+#define BQ2597X_REG_23					0x23
+#define BQ2597X_TSBUS_ADC0_MASK				0xFF
+#define BQ2597X_TSBUS_ADC0_SHIFT			0
+#define BQ2597X_TSBUS_ADC0_BASE				0
+#define BQ2597X_TSBUS_ADC0_LSB				0.09766
+
+/* Register 24h */
+#define BQ2597X_REG_24					0x24
+#define BQ2597X_TSBAT_POL_MASK				0x80
+#define BQ2597X_TSBAT_POL_SHIFT				7
+#define BQ2597X_TSBAT_POL_POSITIVE			0
+#define BQ2597X_TSBAT_POL_NEGATIVE			1
+
+#define BQ2597X_TSBAT_ADC1_MASK				0x7F
+#define BQ2597X_TSBAT_ADC1_SHIFT			0
+#define BQ2597X_TSBAT_ADC1_BASE				0
+#define BQ2597X_TSBAT_ADC1_LSB				25
+
+/* Register 25h */
+#define BQ2597X_REG_25					0x25
+#define BQ2597X_TSBAT_ADC0_MASK				0xFF
+#define BQ2597X_TSBAT_ADC0_SHIFT			0
+#define BQ2597X_TSBAT_ADC0_BASE				0
+#define BQ2597X_TSBAT_ADC0_LSB				0.09766
+
+/* Register 26h */
+#define BQ2597X_REG_26					0x26
+#define BQ2597X_TDIE_POL_MASK				0x80
+#define BQ2597X_TDIE_POL_SHIFT				7
+#define BQ2597X_TDIE_POL_POSITIVE			0
+#define BQ2597X_TDIE_POL_NEGATIVE			1
+
+#define BQ2597X_TDIE_ADC1_MASK				0x7F
+#define BQ2597X_TDIE_ADC1_SHIFT				0
+#define BQ2597X_TDIE_ADC1_BASE				0
+#define BQ2597X_TDIE_ADC1_LSB				128
+
+/* Register 27h */
+#define BQ2597X_REG_27					0x27
+#define BQ2597X_TDIE_ADC0_MASK				0xFF
+#define BQ2597X_TDIE_ADC0_SHIFT				0
+#define BQ2597X_TDIE_ADC0_BASE				0
+#define BQ2597X_TDIE_ADC0_LSB				0.5
+
+/* Register 28h */
+#define BQ2597X_REG_28					0x28
+#define BQ2597X_TSBUS_FLT1_MASK				0xFF
+#define BQ2597X_TSBUS_FLT1_SHIFT			0
+#define BQ2597X_TSBUS_FLT1_BASE				0
+#define BQ2597X_TSBUS_FLT1_LSB				0.19531
+
+/* Register 29h */
+#define BQ2597X_REG_29					0x29
+#define BQ2597X_TSBAT_FLT0_MASK				0xFF
+#define BQ2597X_TSBAT_FLT0_SHIFT			0
+#define BQ2597X_TSBAT_FLT0_BASE				0
+#define BQ2597X_TSBAT_FLT0_LSB				0.19531
+
+/* Register 2Ah */
+#define BQ2597X_REG_2A					0x2A
+#define BQ2597X_TDIE_ALM_MASK				0xFF
+#define BQ2597X_TDIE_ALM_SHIFT				0
+#define BQ2597X_TDIE_ALM_BASE				30
+
+#define BQ2597X_TDIE_ALM_LSB				2 /*careful
+					    multiply is used for calc*/
+
+/* Register 2Bh */
+#define BQ2597X_REG_2B					0x2B
+#define BQ2597X_SS_TIMEOUT_SET_MASK			0xE0
+#define BQ2597X_SS_TIMEOUT_SET_SHIFT			5
+#define BQ2597X_SS_TIMEOUT_DISABLE			0
+#define BQ2597X_SS_TIMEOUT_12P5MS			1
+#define BQ2597X_SS_TIMEOUT_25MS				2
+#define BQ2597X_SS_TIMEOUT_50MS				3
+#define BQ2597X_SS_TIMEOUT_100MS			4
+#define BQ2597X_SS_TIMEOUT_400MS			5
+#define BQ2597X_SS_TIMEOUT_1500MS			6
+#define BQ2597X_SS_TIMEOUT_100000MS			7
+
+#define BQ2597X_EN_REGULATION_MASK			0x10
+#define BQ2597X_EN_REGULATION_SHIFT			4
+#define BQ2597X_EN_REGULATION_ENABLE			1
+#define BQ2597X_EN_REGULATION_DISABLE			0
+
+#define BQ2597X_VOUT_OVP_DIS_MASK			0x08
+#define BQ2597X_VOUT_OVP_DIS_SHIFT			3
+#define BQ2597X_VOUT_OVP_ENABLE				1
+#define BQ2597X_VOUT_OVP_DISABLE			0
+
+#define BQ2597X_IBUS_UCP_RISE_TH_MASK			0x04
+#define BQ2597X_IBUS_UCP_RISE_TH_SHIFT			2
+#define BQ2597X_IBUS_UCP_RISE_300MA			0
+#define BQ2597X_IBUS_UCP_RISE_500MA			1
+
+#define BQ2597X_SET_IBAT_SNS_RES_MASK			0x02
+#define BQ2597X_SET_IBAT_SNS_RES_SHIFT			1
+#define BQ2597X_SET_IBAT_SNS_RES_2MHM			0
+#define BQ2597X_SET_IBAT_SNS_RES_5MHM			1
+
+
+#define BQ2597X_VAC_PD_EN_MASK				0x01
+#define BQ2597X_VAC_PD_EN_SHIFT				0
+#define BQ2597X_VAC_PD_ENABLE				1
+#define BQ2597X_VAC_PD_DISABLE				0
+
+/* Register 2Ch */
+#define BQ2597X_REG_2C					0x2C
+#define BQ2597X_IBAT_REG_MASK				0xC0
+#define BQ2597X_IBAT_REG_SHIFT				6
+#define BQ2597X_IBAT_REG_200MA				0
+#define BQ2597X_IBAT_REG_300MA				1
+#define BQ2597X_IBAT_REG_400MA				2
+#define BQ2597X_IBAT_REG_500MA				3
+#define BQ2597X_VBAT_REG_MASK				0x30
+#define BQ2597X_VBAT_REG_SHIFT				4
+#define BQ2597X_VBAT_REG_50MV				0
+#define BQ2597X_VBAT_REG_100MV				1
+#define BQ2597X_VBAT_REG_150MV				2
+#define BQ2597X_VBAT_REG_200MV				3
+
+#define BQ2597X_VBAT_REG_ACTIVE_STAT_MASK		0x08
+#define BQ2597X_IBAT_REG_ACTIVE_STAT_MASK		0x04
+#define BQ2597X_VDROP_OVP_ACTIVE_STAT_MASK		0x02
+#define BQ2597X_VOUT_OVP_ACTIVE_STAT_MASK		0x01
+
+
+#define BQ2597X_REG_2D					0x2D
+#define BQ2597X_VBAT_REG_ACTIVE_FLAG_MASK		0x80
+#define BQ2597X_IBAT_REG_ACTIVE_FLAG_MASK		0x40
+#define BQ2597X_VDROP_OVP_FLAG_MASK			0x20
+#define BQ2597X_VOUT_OVP_FLAG_MASK			0x10
+#define BQ2597X_VBAT_REG_ACTIVE_MASK_MASK		0x08
+#define BQ2597X_IBAT_REG_ACTIVE_MASK_MASK		0x04
+#define BQ2597X_VDROP_OVP_MASK_MASK			0x02
+#define BQ2597X_VOUT_OVP_MASK_MASK			0x01
+
+
+#define BQ2597X_REG_2E					0x2E
+#define BQ2597X_VBUS_ERR_LOW_DG_MASK			0x10
+#define BQ2597X_VBUS_ERR_LOW_DG_SHIFT			4
+#define BQ2597X_VBUS_ERR_LOW_DG_10US			0
+#define BQ2597X_VBUS_ERR_LOW_DG_10MS			1
+#define BQ2597X_IBUS_LOW_DG_MASK			0x08
+#define BQ2597X_IBUS_LOW_DG_SHIFT			3
+#define BQ2597X_IBUS_LOW_DG_10US			0
+#define BQ2597X_IBUS_LOW_DG_5MS				1
+
+#define SC8551_IBUS_ADC_LSB				1.5625
+#define SC8551_VBUS_ADC_LSB				3.75
+#define SC8551_VAC_ADC_LSB				5
+#define SC8551_VOUT_ADC_LSB				1.25
+#define SC8551_VBAT_ADC_LSB				1.2575
+#define SC8551_IBAT_ADC_LSB				3.125
+#define SC8551_TSBUS_ADC_LSB				0.0009766
+#define SC8551_TSBAT_ADC_LSB				0.0009766
+#define SC8551_TDIE_ADC_LSB				0.5
+/* Register 00h */
+#define SC8551_BAT_OVP_BASE				3500
+#define SC8551_REG_2F					0x2F
+#define SC8551_CHIP_VENDOR_MASK				GENMASK(7, 4)
+#define SC8551_REG_30					0x30
+#define SC8551_REG_31					0x31
+#define SC8551_CHARGE_MODE_MASK				0x01
+#define SC8551_CHARGE_MODE_SHIFT			0
+#define SC8551_CHARGE_MODE_DIV2				0
+#define SC8551_CHARGE_MODE_BYPASS			1
+#define SC8551_REG_34					0x34
+#define SC8551_REG_36					0x36
+
+#endif
-- 
GitLab