From 0605363869633f8ba83bc8acb384bd88a61dac2a Mon Sep 17 00:00:00 2001 From: xuwei9 Date: Tue, 9 Feb 2021 15:19:12 +0800 Subject: [PATCH] kernel:bq25980 charger driver Bq25980 charger driver bring up Change-Id: I451b907d39168f83d43ce28af89c269918171586 Signed-off-by: xuwei9 Reviewed-on: https://gerrit.mot.com/1881081 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- drivers/power/bq2597x_mmi/Android.mk | 7 +- drivers/power/bq2597x_mmi/Kbuild | 6 + drivers/power/bq2597x_mmi/bq25980_charger.c | 1900 +++++++++++++++++++ drivers/power/bq2597x_mmi/bq25980_charger.h | 206 ++ 4 files changed, 2118 insertions(+), 1 deletion(-) create mode 100644 drivers/power/bq2597x_mmi/bq25980_charger.c create mode 100644 drivers/power/bq2597x_mmi/bq25980_charger.h diff --git a/drivers/power/bq2597x_mmi/Android.mk b/drivers/power/bq2597x_mmi/Android.mk index 302321ac2ad0..87a40bfabcb0 100644 --- a/drivers/power/bq2597x_mmi/Android.mk +++ b/drivers/power/bq2597x_mmi/Android.mk @@ -2,8 +2,12 @@ DLKM_DIR := motorola/kernel/modules LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := bq2597x_mmi.ko LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := bq2597x_mmi.ko + +ifeq ($(BQ2597X_DUAL_ENABLE),true) + KERNEL_CFLAGS += CONFIG_BQ2597X_DUAL=y +endif ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true) LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/ @@ -11,4 +15,5 @@ else LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) endif + include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/power/bq2597x_mmi/Kbuild b/drivers/power/bq2597x_mmi/Kbuild index 7cdd828485b5..8fbfa78a8359 100644 --- a/drivers/power/bq2597x_mmi/Kbuild +++ b/drivers/power/bq2597x_mmi/Kbuild @@ -4,3 +4,9 @@ EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \ -I$(TOP)/motorola/kernel/modules/drivers/power/bq2597x_mmi obj-m += bq2597x_mmi.o + +ifneq ($(filter m y,$(CONFIG_BQ2597X_DUAL)),) + bq2597x_mmi-objs += bq25980_charger.o +else + bq2597x_mmi-objs += bq2597x_single_mmi.o +endif diff --git a/drivers/power/bq2597x_mmi/bq25980_charger.c b/drivers/power/bq2597x_mmi/bq25980_charger.c new file mode 100644 index 000000000000..169261cea384 --- /dev/null +++ b/drivers/power/bq2597x_mmi/bq25980_charger.c @@ -0,0 +1,1900 @@ +// SPDX-License-Identifier: GPL-2.0 +// BQ25980 Battery Charger Driver +// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bq25980_charger.h" + +//undef because of pinctrl +//#define CONFIG_INTERRUPT_AS_GPIO + +struct bq25980_state { + bool dischg; + bool ovp; + bool ocp; + bool wdt; + bool tflt; + bool online; + bool ce; + bool hiz; + bool bypass; + + u32 vbat_adc; + u32 vsys_adc; + u32 ibat_adc; + u32 fault_status; +}; + +enum bq_work_mode { + BQ_STANDALONE, + BQ_SLAVE, + BQ_MASTER, +}; + +#define BQ_MODE_COUNT 3 + +enum bq_device_id { + BQ25980 = 0, + BQ25960 = 8, + BQ25975, +}; + +enum bq_compatible_id { + BQ25960_STANDALONE, + BQ25960_SLAVE, + BQ25960_MASTER, + + BQ25980_STANDALONE, + BQ25980_SLAVE, + BQ25980_MASTER, + + BQ25975_STANDALONE, +}; + +struct bq25980_chip_info { + + int model_id; + + const struct regmap_config *regmap_config; + + const struct reg_default *reg_init_values; + + int busocp_sc_def; + int busocp_byp_def; + int busocp_sc_max; + int busocp_byp_max; + int busocp_sc_min; + int busocp_byp_min; + int busocp_step; + int busocp_offset; + + int busovp_sc_def; + int busovp_byp_def; + int busovp_sc_step; + + int busovp_sc_offset; + int busovp_byp_step; + int busovp_byp_offset; + int busovp_sc_min; + int busovp_sc_max; + int busovp_byp_min; + int busovp_byp_max; + + int batovp_def; + int batovp_max; + int batovp_min; + int batovp_step; + int batovp_offset; + + int batocp_def; + int batocp_max; + + int vac_sc_ovp; + int vac_byp_ovp; + + int adc_curr_step; + int adc_vbat_volt_step; + int adc_vbus_volt_step; + int adc_vbus_volt_offset; +}; + +struct bq25980_init_data { + u32 ichg; + u32 bypass_ilim; + u32 sc_ilim; + u32 vreg; + u32 iterm; + u32 iprechg; + u32 bypass_vlim; + u32 sc_vlim; + u32 ichg_max; + u32 vreg_max; +}; + +struct bq25980_device { + struct i2c_client *client; + struct device *dev; + struct power_supply *charger; + struct power_supply *battery; + struct mutex lock; + struct regmap *regmap; + + char model_name[I2C_NAME_SIZE]; + + struct bq25980_init_data init_data; + const struct bq25980_chip_info *chip_info; + struct bq25980_state state; + int watchdog_timer; + int mode; + int device_id; + struct power_supply_desc psy_desc; + struct pinctrl *irq_pinctrl; + bool usb_present; + int irq_counts; + bool irq_waiting; + bool irq_disabled; + bool resume_completed; + struct mutex irq_complete; +}; + +static struct reg_default bq25980_reg_init_val[] = { + {BQ25980_BATOVP, 0x69},//0x69:9100mV + {BQ25980_BATOVP_ALM, 0x61},//0x61:8940mV + {BQ25980_BATOCP, 0xEE},//0xEE:disable for dual //0x64:11000mA for standalone + {BQ25980_BATOCP_ALM, 0x7F},//0x7F:12700mA + {BQ25980_CHRGR_CFG_1, 0xA8}, + {BQ25980_CHRGR_CTRL_1, 0x4A}, + {BQ25980_BUSOVP, 0x3C},//0X3c:20000mV + {BQ25980_BUSOVP_ALM, 0x32},//0X32:19000mV + {BQ25980_BUSOCP, 0x0C},//0X0c:4200mA + {BQ25980_REG_09, 0x8C}, + {BQ25980_TEMP_CONTROL, 0x2C}, + {BQ25980_TDIE_ALM, 0x78},//0x78:85C + {BQ25980_TSBUS_FLT, 0x15}, + {BQ25980_TSBAT_FLG, 0x15}, + {BQ25980_VAC_CONTROL, 0xD8},//0xD8:22V + {BQ25980_CHRGR_CTRL_2, 0x00}, + {BQ25980_CHRGR_CTRL_3, 0x74},//0x74:watchdog disable 5s,275kHz + {BQ25980_CHRGR_CTRL_4, 0x01}, + {BQ25980_CHRGR_CTRL_5, 0x00}, + + {BQ25980_MASK1, 0x00}, + {BQ25980_MASK2, 0x00}, + {BQ25980_MASK3, 0x00}, + {BQ25980_MASK4, 0x00}, + {BQ25980_MASK5, 0x80}, + + {BQ25980_ADC_CONTROL1, 0x04},//sample 14 bit + {BQ25980_ADC_CONTROL2, 0xE6}, +}; + +static struct reg_default bq25960_reg_init_val[] = { + {BQ25980_BATOVP, 0x69},//0x69:4550mV + {BQ25980_BATOVP_ALM, 0x61},//0x61:4470mV + {BQ25980_BATOCP, 0xEE},//0xEE:disable for dual //0x46:7000mA for standalone + {BQ25980_BATOCP_ALM, 0x7F},//0x7F:12700mA + {BQ25980_CHRGR_CFG_1, 0xA8}, + {BQ25980_CHRGR_CTRL_1, 0x49}, + {BQ25980_BUSOVP, 0x50},//0X50:11000mV + {BQ25980_BUSOVP_ALM, 0x46},//0X46:10500mV + {BQ25980_BUSOCP, 0x0C},//0X0c:4000mA + {BQ25980_REG_09, 0x8C}, + {BQ25980_TEMP_CONTROL, 0x2C}, + {BQ25980_TDIE_ALM, 0x78},//0x78:85C + {BQ25980_TSBUS_FLT, 0x15}, + {BQ25980_TSBAT_FLG, 0x15}, + {BQ25980_VAC_CONTROL, 0x48},//0x48:12V*2 + {BQ25980_CHRGR_CTRL_2, 0x00}, + {BQ25980_CHRGR_CTRL_3, 0x94},//0x94:watchdog disable 5s,500kHz + {BQ25980_CHRGR_CTRL_4, 0x81},//5m oum battery sense resister + {BQ25980_CHRGR_CTRL_5, 0x00}, + + {BQ25980_MASK1, 0x00}, + {BQ25980_MASK2, 0x00}, + {BQ25980_MASK3, 0x00}, + {BQ25980_MASK4, 0x00}, + {BQ25980_MASK5, 0x80}, + + {BQ25980_ADC_CONTROL1, 0x84},//sample 14 bit + {BQ25980_ADC_CONTROL2, 0xE6}, + +}; + +static struct reg_default bq25980_reg_defs[] = { + {BQ25980_BATOVP, 0x5A}, + {BQ25980_BATOVP_ALM, 0x46}, + {BQ25980_BATOCP, 0x51}, + {BQ25980_BATOCP_ALM, 0x50}, + {BQ25980_CHRGR_CFG_1, 0x28}, + {BQ25980_CHRGR_CTRL_1, 0x0}, + {BQ25980_BUSOVP, 0x26}, + {BQ25980_BUSOVP_ALM, 0x22}, + {BQ25980_BUSOCP, 0xD}, + {BQ25980_REG_09, 0xC}, + {BQ25980_TEMP_CONTROL, 0x30}, + {BQ25980_TDIE_ALM, 0xC8}, + {BQ25980_TSBUS_FLT, 0x15}, + {BQ25980_TSBAT_FLG, 0x15}, + {BQ25980_VAC_CONTROL, 0x0}, + {BQ25980_CHRGR_CTRL_2, 0x0}, + {BQ25980_CHRGR_CTRL_3, 0x20}, + {BQ25980_CHRGR_CTRL_4, 0x1D}, + {BQ25980_CHRGR_CTRL_5, 0x18}, + {BQ25980_STAT1, 0x0}, + {BQ25980_STAT2, 0x0}, + {BQ25980_STAT3, 0x0}, + {BQ25980_STAT4, 0x0}, + {BQ25980_STAT5, 0x0}, + {BQ25980_FLAG1, 0x0}, + {BQ25980_FLAG2, 0x0}, + {BQ25980_FLAG3, 0x0}, + {BQ25980_FLAG4, 0x0}, + {BQ25980_FLAG5, 0x0}, + {BQ25980_MASK1, 0x0}, + {BQ25980_MASK2, 0x0}, + {BQ25980_MASK3, 0x0}, + {BQ25980_MASK4, 0x0}, + {BQ25980_MASK5, 0x0}, + {BQ25980_DEVICE_INFO, 0x8}, + {BQ25980_ADC_CONTROL1, 0x0}, + {BQ25980_ADC_CONTROL2, 0x0}, + {BQ25980_IBUS_ADC_LSB, 0x0}, + {BQ25980_IBUS_ADC_MSB, 0x0}, + {BQ25980_VBUS_ADC_LSB, 0x0}, + {BQ25980_VBUS_ADC_MSB, 0x0}, + {BQ25980_VAC1_ADC_LSB, 0x0}, + {BQ25980_VAC2_ADC_LSB, 0x0}, + {BQ25980_VOUT_ADC_LSB, 0x0}, + {BQ25980_VBAT_ADC_LSB, 0x0}, + {BQ25980_IBAT_ADC_MSB, 0x0}, + {BQ25980_IBAT_ADC_LSB, 0x0}, + {BQ25980_TSBUS_ADC_LSB, 0x0}, + {BQ25980_TSBAT_ADC_LSB, 0x0}, + {BQ25980_TDIE_ADC_LSB, 0x0}, + {BQ25980_DEGLITCH_TIME, 0x0}, + {BQ25980_CHRGR_CTRL_6, 0x0}, +}; + +static struct reg_default bq25975_reg_defs[] = { + {BQ25980_BATOVP, 0x5A}, + {BQ25980_BATOVP_ALM, 0x46}, + {BQ25980_BATOCP, 0x51}, + {BQ25980_BATOCP_ALM, 0x50}, + {BQ25980_CHRGR_CFG_1, 0x28}, + {BQ25980_CHRGR_CTRL_1, 0x0}, + {BQ25980_BUSOVP, 0x26}, + {BQ25980_BUSOVP_ALM, 0x22}, + {BQ25980_BUSOCP, 0xD}, + {BQ25980_REG_09, 0xC}, + {BQ25980_TEMP_CONTROL, 0x30}, + {BQ25980_TDIE_ALM, 0xC8}, + {BQ25980_TSBUS_FLT, 0x15}, + {BQ25980_TSBAT_FLG, 0x15}, + {BQ25980_VAC_CONTROL, 0x0}, + {BQ25980_CHRGR_CTRL_2, 0x0}, + {BQ25980_CHRGR_CTRL_3, 0x20}, + {BQ25980_CHRGR_CTRL_4, 0x1D}, + {BQ25980_CHRGR_CTRL_5, 0x18}, + {BQ25980_STAT1, 0x0}, + {BQ25980_STAT2, 0x0}, + {BQ25980_STAT3, 0x0}, + {BQ25980_STAT4, 0x0}, + {BQ25980_STAT5, 0x0}, + {BQ25980_FLAG1, 0x0}, + {BQ25980_FLAG2, 0x0}, + {BQ25980_FLAG3, 0x0}, + {BQ25980_FLAG4, 0x0}, + {BQ25980_FLAG5, 0x0}, + {BQ25980_MASK1, 0x0}, + {BQ25980_MASK2, 0x0}, + {BQ25980_MASK3, 0x0}, + {BQ25980_MASK4, 0x0}, + {BQ25980_MASK5, 0x0}, + {BQ25980_DEVICE_INFO, 0x8}, + {BQ25980_ADC_CONTROL1, 0x0}, + {BQ25980_ADC_CONTROL2, 0x0}, + {BQ25980_IBUS_ADC_LSB, 0x0}, + {BQ25980_IBUS_ADC_MSB, 0x0}, + {BQ25980_VBUS_ADC_LSB, 0x0}, + {BQ25980_VBUS_ADC_MSB, 0x0}, + {BQ25980_VAC1_ADC_LSB, 0x0}, + {BQ25980_VAC2_ADC_LSB, 0x0}, + {BQ25980_VOUT_ADC_LSB, 0x0}, + {BQ25980_VBAT_ADC_LSB, 0x0}, + {BQ25980_IBAT_ADC_MSB, 0x0}, + {BQ25980_IBAT_ADC_LSB, 0x0}, + {BQ25980_TSBUS_ADC_LSB, 0x0}, + {BQ25980_TSBAT_ADC_LSB, 0x0}, + {BQ25980_TDIE_ADC_LSB, 0x0}, + {BQ25980_DEGLITCH_TIME, 0x0}, + {BQ25980_CHRGR_CTRL_6, 0x0}, +}; + +static struct reg_default bq25960_reg_defs[] = { + {BQ25980_BATOVP, 0x5A}, + {BQ25980_BATOVP_ALM, 0x46}, + {BQ25980_BATOCP, 0x51}, + {BQ25980_BATOCP_ALM, 0x50}, + {BQ25980_CHRGR_CFG_1, 0x28}, + {BQ25980_CHRGR_CTRL_1, 0x0}, + {BQ25980_BUSOVP, 0x26}, + {BQ25980_BUSOVP_ALM, 0x22}, + {BQ25980_BUSOCP, 0xD}, + {BQ25980_REG_09, 0xC}, + {BQ25980_TEMP_CONTROL, 0x30}, + {BQ25980_TDIE_ALM, 0xC8}, + {BQ25980_TSBUS_FLT, 0x15}, + {BQ25980_TSBAT_FLG, 0x15}, + {BQ25980_VAC_CONTROL, 0x0}, + {BQ25980_CHRGR_CTRL_2, 0x0}, + {BQ25980_CHRGR_CTRL_3, 0x20}, + {BQ25980_CHRGR_CTRL_4, 0x1D}, + {BQ25980_CHRGR_CTRL_5, 0x18}, + {BQ25980_STAT1, 0x0}, + {BQ25980_STAT2, 0x0}, + {BQ25980_STAT3, 0x0}, + {BQ25980_STAT4, 0x0}, + {BQ25980_STAT5, 0x0}, + {BQ25980_FLAG1, 0x0}, + {BQ25980_FLAG2, 0x0}, + {BQ25980_FLAG3, 0x0}, + {BQ25980_FLAG4, 0x0}, + {BQ25980_FLAG5, 0x0}, + {BQ25980_MASK1, 0x0}, + {BQ25980_MASK2, 0x0}, + {BQ25980_MASK3, 0x0}, + {BQ25980_MASK4, 0x0}, + {BQ25980_MASK5, 0x0}, + {BQ25980_DEVICE_INFO, 0x8}, + {BQ25980_ADC_CONTROL1, 0x0}, + {BQ25980_ADC_CONTROL2, 0x0}, + {BQ25980_IBUS_ADC_LSB, 0x0}, + {BQ25980_IBUS_ADC_MSB, 0x0}, + {BQ25980_VBUS_ADC_LSB, 0x0}, + {BQ25980_VBUS_ADC_MSB, 0x0}, + {BQ25980_VAC1_ADC_LSB, 0x0}, + {BQ25980_VAC2_ADC_LSB, 0x0}, + {BQ25980_VOUT_ADC_LSB, 0x0}, + {BQ25980_VBAT_ADC_LSB, 0x0}, + {BQ25980_IBAT_ADC_MSB, 0x0}, + {BQ25980_IBAT_ADC_LSB, 0x0}, + {BQ25980_TSBUS_ADC_LSB, 0x0}, + {BQ25980_TSBAT_ADC_LSB, 0x0}, + {BQ25980_TDIE_ADC_LSB, 0x0}, + {BQ25980_DEGLITCH_TIME, 0x0}, + {BQ25980_CHRGR_CTRL_6, 0x0}, +}; + +static int bq25980_reg_init(struct bq25980_device *bq); +//static int bq25980_watchdog_time[BQ25980_NUM_WD_VAL] = {5000, 10000, 50000, +// 300000}; + +static void dump_reg(struct bq25980_device *bq, int start, int end) +{ + int ret; + unsigned int val; + int addr; + + for (addr = start; addr <= end; addr++) { + ret = regmap_read(bq->regmap, addr, &val); + if (!ret) + dev_err(bq->dev, "Reg[%02X] = 0x%02X\n", addr, val); + } +} +static void dump_all_reg(struct bq25980_device *bq) +{ + int ret; + unsigned int val; + int addr; + + for (addr = 0x00; addr <= 0x37; addr++) { + ret = regmap_read(bq->regmap, addr, &val); + if (!ret) + dev_err(bq->dev, "Reg[%02X] = 0x%02X\n", addr, val); + } +} +/* +static int bq25980_get_adc_enable(struct bq25980_device *bq) +{ + unsigned int reg_code; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_ADC_CONTROL1, ®_code); + if (ret) + return ret; + + return !!(reg_code & BQ25980_ADC_EN); +} +*/ +static int bq25980_set_adc_enable(struct bq25980_device *bq, bool enable) +{ + int ret; + + dev_notice(bq->dev, "%s %d", __FUNCTION__, enable); + + if (enable) + ret = regmap_update_bits(bq->regmap, BQ25980_ADC_CONTROL1, + BQ25980_ADC_EN, BQ25980_ADC_EN); + else + ret = regmap_update_bits(bq->regmap, BQ25980_ADC_CONTROL1, + BQ25980_ADC_EN, 0); + + return ret; +} + +/* +static int bq25980_get_input_curr_lim(struct bq25980_device *bq) +{ + unsigned int busocp_reg_code; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_BUSOCP, &busocp_reg_code); + if (ret) + return ret; + + return (busocp_reg_code * bq->chip_info->busocp_step) + bq->chip_info->busocp_offset; +} + +static int bq25980_set_hiz(struct bq25980_device *bq, int setting) +{ + return regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_EN_HIZ, setting); +}*/ +/* +static int bq25980_set_input_curr_lim(struct bq25980_device *bq, int busocp) +{ + unsigned int busocp_reg_code; + + if (!busocp) + return bq25980_set_hiz(bq, BQ25980_ENABLE_HIZ); + + bq25980_set_hiz(bq, BQ25980_DISABLE_HIZ); + + if (bq->state.bypass) { + busocp = max(busocp, bq->chip_info->busocp_byp_min); + busocp = min(busocp, bq->chip_info->busocp_byp_max); + } else { + busocp = max(busocp, bq->chip_info->busocp_sc_min); + busocp = min(busocp, bq->chip_info->busocp_sc_max); + } + + busocp_reg_code = (busocp - bq->chip_info->busocp_offset) + / bq->chip_info->busocp_step; + + return regmap_write(bq->regmap, BQ25980_BUSOCP, busocp_reg_code); +} + +static int bq25980_get_input_volt_lim(struct bq25980_device *bq) +{ + unsigned int busovp_reg_code; + unsigned int busovp_offset; + unsigned int busovp_step; + int ret; + + if (bq->state.bypass) { + busovp_step = bq->chip_info->busovp_byp_step; + busovp_offset = bq->chip_info->busovp_byp_offset; + } else { + busovp_step = bq->chip_info->busovp_sc_step; + busovp_offset = bq->chip_info->busovp_sc_offset; + } + + ret = regmap_read(bq->regmap, BQ25980_BUSOVP, &busovp_reg_code); + if (ret) + return ret; + + return (busovp_reg_code * busovp_step) + busovp_offset; +} + +static int bq25980_set_input_volt_lim(struct bq25980_device *bq, int busovp) +{ + unsigned int busovp_reg_code; + unsigned int busovp_step; + unsigned int busovp_offset; + int ret; + + if (bq->state.bypass) { + busovp_step = bq->chip_info->busovp_byp_step; + busovp_offset = bq->chip_info->busovp_byp_offset; + if (busovp > bq->chip_info->busovp_byp_max) + busovp = bq->chip_info->busovp_byp_max; + else if (busovp < bq->chip_info->busovp_byp_min) + busovp = bq->chip_info->busovp_byp_min; + } else { + busovp_step = bq->chip_info->busovp_sc_step; + busovp_offset = bq->chip_info->busovp_sc_offset; + if (busovp > bq->chip_info->busovp_sc_max) + busovp = bq->chip_info->busovp_sc_max; + else if (busovp < bq->chip_info->busovp_sc_min) + busovp = bq->chip_info->busovp_sc_min; + } + + busovp_reg_code = (busovp - busovp_offset) / busovp_step; + + ret = regmap_write(bq->regmap, BQ25980_BUSOVP, busovp_reg_code); + if (ret) + return ret; + + return regmap_write(bq->regmap, BQ25980_BUSOVP_ALM, busovp_reg_code); +} +*/ +static int bq25980_get_const_charge_curr(struct bq25980_device *bq) +{ + unsigned int batocp_reg_code; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_BATOCP, &batocp_reg_code); + if (ret) + return ret; + + return (batocp_reg_code & BQ25980_BATOCP_MASK) * + BQ25980_BATOCP_STEP_uA; +} +/* +static int bq25980_set_const_charge_curr(struct bq25980_device *bq, int batocp) +{ + unsigned int batocp_reg_code; + int ret; + + batocp = max(batocp, BQ25980_BATOCP_MIN_uA); + batocp = min(batocp, bq->chip_info->batocp_max); + + batocp_reg_code = batocp / BQ25980_BATOCP_STEP_uA; + + ret = regmap_update_bits(bq->regmap, BQ25980_BATOCP, + BQ25980_BATOCP_MASK, batocp_reg_code); + if (ret) + return ret; + + return regmap_update_bits(bq->regmap, BQ25980_BATOCP_ALM, + BQ25980_BATOCP_MASK, batocp_reg_code); +} +*/ +static int bq25980_get_const_charge_volt(struct bq25980_device *bq) +{ + unsigned int batovp_reg_code; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_BATOVP, &batovp_reg_code); + if (ret) + return ret; + + return ((batovp_reg_code * bq->chip_info->batovp_step) + + bq->chip_info->batovp_offset); +} +/* +static int bq25980_set_const_charge_volt(struct bq25980_device *bq, int batovp) +{ + unsigned int batovp_reg_code; + int ret; + + if (batovp < bq->chip_info->batovp_min) + batovp = bq->chip_info->batovp_min; + + if (batovp > bq->chip_info->batovp_max) + batovp = bq->chip_info->batovp_max; + + batovp_reg_code = (batovp - bq->chip_info->batovp_offset) / + bq->chip_info->batovp_step; + + ret = regmap_write(bq->regmap, BQ25980_BATOVP, batovp_reg_code); + if (ret) + return ret; + + return regmap_write(bq->regmap, BQ25980_BATOVP_ALM, batovp_reg_code); +}*/ +/* +static int bq25980_set_bypass(struct bq25980_device *bq, bool en_bypass) +{ + int ret; + + if (en_bypass) + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_EN_BYPASS, BQ25980_EN_BYPASS); + else + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_EN_BYPASS, en_bypass); + if (ret) + return ret; + + bq->state.bypass = en_bypass; + + return 0; +} +*/ +static int bq25980_set_chg_en(struct bq25980_device *bq, bool en_chg) +{ + int ret; + + if (en_chg) + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_CHG_EN, BQ25980_CHG_EN); + else + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_CHG_EN, en_chg); + if (ret) + return ret; + + bq->state.ce = en_chg; + + return 0; +} + +static int bq25980_get_adc_ibus(struct bq25980_device *bq) +{ + int ibus_adc_lsb, ibus_adc_msb; + u16 ibus_adc; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_IBUS_ADC_MSB, &ibus_adc_msb); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_IBUS_ADC_LSB, &ibus_adc_lsb); + if (ret) + return ret; + + ibus_adc = (ibus_adc_msb << 8) | ibus_adc_lsb; + + if (ibus_adc_msb & BQ25980_ADC_POLARITY_BIT) + return ((ibus_adc ^ 0xffff) + 1) * bq->chip_info->adc_curr_step; + + return ibus_adc * bq->chip_info->adc_curr_step; +} + +static int bq25980_get_adc_vbus(struct bq25980_device *bq) +{ + int vbus_adc_lsb, vbus_adc_msb; + u16 vbus_adc; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_VBUS_ADC_MSB, &vbus_adc_msb); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_VBUS_ADC_LSB, &vbus_adc_lsb); + if (ret) + return ret; + + vbus_adc = (vbus_adc_msb << 8) | vbus_adc_lsb; + + return bq->chip_info->adc_vbus_volt_offset + vbus_adc * bq->chip_info->adc_vbus_volt_step /10; +} + +static int bq25980_get_ibat_adc(struct bq25980_device *bq) +{ + int ret; + int ibat_adc_lsb, ibat_adc_msb; + int ibat_adc; + + ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_MSB, &ibat_adc_msb); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_LSB, &ibat_adc_lsb); + if (ret) + return ret; + + ibat_adc = (ibat_adc_msb << 8) | ibat_adc_lsb; + + if (ibat_adc_msb & BQ25980_ADC_POLARITY_BIT) + return ((ibat_adc ^ 0xffff) + 1) * BQ25960_ADC_CURR_STEP_uA; + + return ibat_adc * BQ25960_ADC_CURR_STEP_uA; +} + +static int bq25980_get_adc_vbat(struct bq25980_device *bq) +{ + int vsys_adc_lsb, vsys_adc_msb; + u16 vsys_adc; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_VBAT_ADC_MSB, &vsys_adc_msb); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_VBAT_ADC_LSB, &vsys_adc_lsb); + if (ret) + return ret; + + vsys_adc = (vsys_adc_msb << 8) | vsys_adc_lsb; + + return vsys_adc * bq->chip_info->adc_vbat_volt_step / 10; +} + +static int bq25980_get_state(struct bq25980_device *bq, + struct bq25980_state *state) +{ + unsigned int chg_ctrl_2; + unsigned int stat1; + unsigned int stat2; + unsigned int stat3; + unsigned int stat4; + unsigned int ibat_adc_msb; + int ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT1, &stat1); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT2, &stat2); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT3, &stat3); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT4, &stat4); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_CHRGR_CTRL_2, &chg_ctrl_2); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_MSB, &ibat_adc_msb); + if (ret) + return ret; + + state->dischg = ibat_adc_msb & BQ25980_ADC_POLARITY_BIT; + state->ovp = (stat1 & BQ25980_STAT1_OVP_MASK) | + (stat3 & BQ25980_STAT3_OVP_MASK); + state->ocp = (stat1 & BQ25980_STAT1_OCP_MASK) | + (stat2 & BQ25980_STAT2_OCP_MASK); + state->tflt = stat4 & BQ25980_STAT4_TFLT_MASK; + state->wdt = stat4 & BQ25980_WD_STAT; + state->online = stat3 & BQ25980_PRESENT_MASK; + state->ce = chg_ctrl_2 & BQ25980_CHG_EN; + state->hiz = chg_ctrl_2 & BQ25980_EN_HIZ; + state->bypass = chg_ctrl_2 & BQ25980_EN_BYPASS; + + return 0; +} +#if 0 +static int bq25980_set_battery_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct bq25980_device *bq = power_supply_get_drvdata(psy); + int ret = 0; + + if (ret) + return ret; + + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = bq25980_set_const_charge_curr(bq, val->intval); + if (ret) + return ret; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = bq25980_set_const_charge_volt(bq, val->intval); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int bq25980_get_battery_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct bq25980_device *bq = power_supply_get_drvdata(psy); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + val->intval = bq->init_data.ichg_max; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + val->intval = bq->init_data.vreg_max; + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = bq25980_get_ibat_adc(bq); + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = bq25980_get_adc_vbat(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + default: + return -EINVAL; + } + + return 0; +} +#endif +static int bq25980_set_present(struct bq25980_device *bq, bool present) +{ + bq->usb_present = present; + + if (present) + bq25980_reg_init(bq); + return 0; +} + +static int bq25980_set_charger_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct bq25980_device *bq = power_supply_get_drvdata(psy); + int ret = -EINVAL; + + switch (prop) { +/* + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq25980_set_input_curr_lim(bq, val->intval); + if (ret) + return ret; + break; + + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = bq25980_set_input_volt_lim(bq, val->intval); + if (ret) + return ret; + break; +*/ + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + dev_err(bq->dev,"%s,POWER_SUPPLY_PROP_CHARGING_ENABLED prop:%d,value:%d\n",__func__,prop,val->intval); + ret = bq25980_set_chg_en(bq, val->intval); + if (ret) + return ret; + break; +/* + case POWER_SUPPLY_PROP_TI_ADC: + ret = bq25980_set_adc_enable(bq, val->intval); + if (ret) + return ret; + break; + + case POWER_SUPPLY_PROP_TI_BYPASS: + ret = bq25980_set_bypass(bq, val->intval); + if (ret) + return ret; + if (val->intval) + ret = bq25980_set_input_curr_lim(bq, bq->chip_info->busocp_byp_def); + else + ret = bq25980_set_input_curr_lim(bq, bq->chip_info->busocp_sc_def); + if (ret) + return ret; + break; +*/ + case POWER_SUPPLY_PROP_PRESENT: + bq25980_set_present(bq, !!val->intval); +// sc_info("set present :%d\n", val->intval); + dev_err(bq->dev,"%s,POWER_SUPPLY_PROP_PRESENT prop:%d,value:%d\n",__func__,prop,val->intval); + break; + case POWER_SUPPLY_PROP_UPDATE_NOW: + dev_err(bq->dev,"%s,POWER_SUPPLY_PROP_UPDATE_NOW prop:%d,value:%d\n",__func__,prop,val->intval); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bq25980_get_charger_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct bq25980_device *bq = power_supply_get_drvdata(psy); + struct bq25980_state state; + int ret = 0; + unsigned int chg_ctrl_2 = 0; + unsigned int stat1 = 0; + unsigned int stat2 = 0; + unsigned int stat3 = 0; + unsigned int stat4 = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CHIP_VERSION: + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = BQ25980_MANUFACTURER; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = bq->model_name; + break; + case POWER_SUPPLY_PROP_ONLINE: + ret = regmap_read(bq->regmap, BQ25980_STAT3, &stat3); + if (ret) + return ret; + + state.online = stat3 & BQ25980_PRESENT_MASK; + val->intval = state.online; + break; +/* + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = bq25980_get_input_volt_lim(bq); + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq25980_get_input_curr_lim(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; +*/ + case POWER_SUPPLY_PROP_CP_STATUS1: + val->intval = 0; + /* + ((sc->bat_ovp_fault << SC8549_VBAT_OVP_FLAG_SHIFT) + | (sc->bat_ocp_fault << SC8549_IBAT_OCP_FLAG_SHIFT) + | (sc->bus_ovp_fault << SC8549_VBUS_OVP_FLAG_SHIFT) + | (sc->bus_ocp_fault << SC8549_IBUS_OCP_FLAG_SHIFT)); + */ + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + + ret = regmap_read(bq->regmap, BQ25980_STAT1, &stat1); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT2, &stat2); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT3, &stat3); + if (ret) + return ret; + + ret = regmap_read(bq->regmap, BQ25980_STAT4, &stat4); + if (ret) + return ret; + + state.ovp = (stat1 & BQ25980_STAT1_OVP_MASK) | + (stat3 & BQ25980_STAT3_OVP_MASK); + state.ocp = (stat1 & BQ25980_STAT1_OCP_MASK) | + (stat2 & BQ25980_STAT2_OCP_MASK); + state.tflt = stat4 & BQ25980_STAT4_TFLT_MASK; + + if (state.tflt) + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (state.ovp) + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else if (state.ocp) + val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; + + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = bq25980_get_ibat_adc(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = bq25980_get_adc_vbat(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = bq25980_get_const_charge_curr(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = bq25980_get_const_charge_volt(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED: + ret = bq25980_get_adc_vbus(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: + ret = bq25980_get_adc_ibus(bq); + if (ret < 0) + return ret; + + val->intval = ret; + //dump_all_reg(bq); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + ret = regmap_read(bq->regmap, BQ25980_CHRGR_CTRL_2, &chg_ctrl_2); + if (ret) + return ret; + + state.ce = chg_ctrl_2 & BQ25980_CHG_EN; + val->intval = state.ce; + break; +/* + case POWER_SUPPLY_PROP_TI_ADC: + ret = bq25980_get_adc_enable(bq); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_TI_BYPASS: + ret = regmap_read(bq->regmap, BQ25980_CHRGR_CTRL_2, &chg_ctrl_2); + if (ret) + return ret; + + state.bypass = chg_ctrl_2 & BQ25980_EN_BYPASS; + val->intval = state.bypass; + break; +*/ + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bq->usb_present; + break; + case POWER_SUPPLY_PROP_UPDATE_NOW: + break; + case POWER_SUPPLY_PROP_CP_IRQ_STATUS: + val->intval = bq->irq_counts; + break; + default: + return -EINVAL; + } + dev_err(bq->dev,"%s,psp:%d,value:%d\n",__func__,psp,val->intval); + return 0; +} + +static bool bq25980_state_changed(struct bq25980_device *bq, + struct bq25980_state *new_state) +{ + struct bq25980_state old_state; + + mutex_lock(&bq->lock); + old_state = bq->state; + mutex_unlock(&bq->lock); + + return (old_state.dischg != new_state->dischg || + old_state.ovp != new_state->ovp || + old_state.ocp != new_state->ocp || + old_state.online != new_state->online || + old_state.wdt != new_state->wdt || + old_state.tflt != new_state->tflt || + old_state.ce != new_state->ce || + old_state.hiz != new_state->hiz || + old_state.bypass != new_state->bypass); +} + +static irqreturn_t bq25980_irq_handler_thread(int irq, void *private) +{ + struct bq25980_device *bq = private; + struct bq25980_state state; + int ret; + + dev_err(bq->dev,"%s enter\n",__func__); + 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; + } + mutex_unlock(&bq->irq_complete); + return IRQ_HANDLED; + } + bq->irq_waiting = false; + + if(bq->irq_counts > INT_MAX -1) + bq->irq_counts = 0; + else + bq->irq_counts++; + +// dump_all_reg(bq); + mutex_unlock(&bq->irq_complete); + + ret = bq25980_get_state(bq, &state); + if (ret < 0) + goto irq_out; + + if (!bq25980_state_changed(bq, &state)) + goto irq_out; + + mutex_lock(&bq->lock); + bq->state = state; + mutex_unlock(&bq->lock); + + power_supply_changed(bq->charger); + +irq_out: + return IRQ_HANDLED; +} + +static enum power_supply_property bq25980_power_supply_props[] = { + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_HEALTH, +// POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, +// POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CHARGING_ENABLED, +/* + POWER_SUPPLY_PROP_TI_ADC, + POWER_SUPPLY_PROP_TI_BYPASS, +*/ + + POWER_SUPPLY_PROP_CP_STATUS1, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, + POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, + POWER_SUPPLY_PROP_CP_IRQ_STATUS, + POWER_SUPPLY_PROP_CHIP_VERSION, +}; +#if 0 +static enum power_supply_property bq25980_battery_props[] = { + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; +#endif +static char *bq25980_charger_supplied_to[] = { + "main-battery", +}; + +static int bq25980_property_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + switch (prop) { +// case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CHARGING_ENABLED: +// case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_UPDATE_NOW: + // case POWER_SUPPLY_PROP_TI_ADC: +// case POWER_SUPPLY_PROP_TI_BYPASS: + return true; + default: + return false; + } +} + +#if 0 +static struct power_supply_desc bq25980_battery_desc = { + .name = "bq25980-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .get_property = bq25980_get_battery_property, + .set_property = bq25980_set_battery_property, + .properties = bq25980_battery_props, + .num_properties = ARRAY_SIZE(bq25980_battery_props), + .property_is_writeable = bq25980_property_is_writeable, +}; +#endif + +static bool bq25980_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BQ25980_CHRGR_CTRL_2: + case BQ25980_STAT1...BQ25980_FLAG5: + case BQ25980_ADC_CONTROL1...BQ25980_TDIE_ADC_LSB: + return true; + default: + return false; + } +} + +static const struct regmap_config bq25980_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BQ25980_CHRGR_CTRL_6, + .reg_defaults = bq25980_reg_defs, + .num_reg_defaults = ARRAY_SIZE(bq25980_reg_defs), + .cache_type = REGCACHE_NONE, + .volatile_reg = bq25980_is_volatile_reg, +}; + +static const struct regmap_config bq25975_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BQ25980_CHRGR_CTRL_6, + .reg_defaults = bq25975_reg_defs, + .num_reg_defaults = ARRAY_SIZE(bq25975_reg_defs), + .cache_type = REGCACHE_NONE, + .volatile_reg = bq25980_is_volatile_reg, +}; + +static const struct regmap_config bq25960_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BQ25980_CHRGR_CTRL_6, + .reg_defaults = bq25960_reg_defs, + .num_reg_defaults = ARRAY_SIZE(bq25960_reg_defs), + .cache_type = REGCACHE_NONE, + .volatile_reg = bq25980_is_volatile_reg, +}; + +static const struct bq25980_chip_info bq25980_chip_info_tbl[] = { + [BQ25980] = { + .model_id = BQ25980, + .regmap_config = &bq25980_regmap_config, + .reg_init_values = bq25980_reg_init_val, + + .busocp_sc_def = BQ25980_BUSOCP_SC_DFLT_uA, + .busocp_byp_def = BQ25980_BUSOCP_BYP_DFLT_uA, + .busocp_sc_min = BQ25980_BUSOCP_MIN_uA, + .busocp_sc_max = BQ25980_BUSOCP_SC_MAX_uA, + .busocp_byp_max = BQ25980_BUSOCP_BYP_MAX_uA, + .busocp_byp_min = BQ25980_BUSOCP_MIN_uA, + .busocp_step = BQ25980_BUSOCP_STEP_uA, + .busocp_offset = BQ25980_BUSOCP_OFFSET_uA, + + .busovp_sc_def = BQ25980_BUSOVP_DFLT_uV, + .busovp_byp_def = BQ25980_BUSOVP_BYPASS_DFLT_uV, + .busovp_sc_step = BQ25980_BUSOVP_SC_STEP_uV, + .busovp_sc_offset = BQ25980_BUSOVP_SC_OFFSET_uV, + .busovp_byp_step = BQ25980_BUSOVP_BYP_STEP_uV, + .busovp_byp_offset = BQ25980_BUSOVP_BYP_OFFSET_uV, + .busovp_sc_min = BQ25980_BUSOVP_SC_MIN_uV, + .busovp_sc_max = BQ25980_BUSOVP_SC_MAX_uV, + .busovp_byp_min = BQ25980_BUSOVP_BYP_MIN_uV, + .busovp_byp_max = BQ25980_BUSOVP_BYP_MAX_uV, + + .batovp_def = BQ25980_BATOVP_DFLT_uV, + .batovp_max = BQ25980_BATOVP_MAX_uV, + .batovp_min = BQ25980_BATOVP_MIN_uV, + .batovp_step = BQ25980_BATOVP_STEP_uV, + .batovp_offset = BQ25980_BATOVP_OFFSET_uV, + + .batocp_def = BQ25980_BATOCP_DFLT_uA, + .batocp_max = BQ25980_BATOCP_MAX_uA, + + .adc_curr_step = BQ25980_ADC_CURR_STEP_IBUS_uA, + .adc_vbat_volt_step = BQ25980_ADC_VOLT_STEP_VBAT_deciuV, + .adc_vbus_volt_step = BQ25980_ADC_VOLT_STEP_VBUS_deciuV, + .adc_vbus_volt_offset = BQ25980_ADC_VOLT_OFFSET_VBUS, + }, + + [BQ25960] = { + .model_id = BQ25960, + .regmap_config = &bq25960_regmap_config, + .reg_init_values = bq25960_reg_init_val, + + .busocp_sc_def = BQ25960_BUSOCP_SC_DFLT_uA, + .busocp_byp_def = BQ25960_BUSOCP_BYP_DFLT_uA, + .busocp_sc_min = BQ25960_BUSOCP_MIN_uA, + .busocp_sc_max = BQ25960_BUSOCP_SC_MAX_uA, + .busocp_byp_min = BQ25960_BUSOCP_MIN_uA, + .busocp_byp_max = BQ25960_BUSOCP_BYP_MAX_uA, + .busocp_step = BQ25960_BUSOCP_STEP_uA, + .busocp_offset = BQ25960_BUSOCP_OFFSET_uA, + + .busovp_sc_def = BQ25975_BUSOVP_DFLT_uV, + .busovp_byp_def = BQ25975_BUSOVP_BYPASS_DFLT_uV, + .busovp_sc_step = BQ25960_BUSOVP_SC_STEP_uV, + .busovp_sc_offset = BQ25960_BUSOVP_SC_OFFSET_uV, + .busovp_byp_step = BQ25960_BUSOVP_BYP_STEP_uV, + .busovp_byp_offset = BQ25960_BUSOVP_BYP_OFFSET_uV, + .busovp_sc_min = BQ25960_BUSOVP_SC_MIN_uV, + .busovp_sc_max = BQ25960_BUSOVP_SC_MAX_uV, + .busovp_byp_min = BQ25960_BUSOVP_BYP_MIN_uV, + .busovp_byp_max = BQ25960_BUSOVP_BYP_MAX_uV, + + .batovp_def = BQ25960_BATOVP_DFLT_uV, + .batovp_max = BQ25960_BATOVP_MAX_uV, + .batovp_min = BQ25960_BATOVP_MIN_uV, + .batovp_step = BQ25960_BATOVP_STEP_uV, + .batovp_offset = BQ25960_BATOVP_OFFSET_uV, + + .batocp_def = BQ25960_BATOCP_DFLT_uA, + .batocp_max = BQ25960_BATOCP_MAX_uA, + + .adc_curr_step = BQ25960_ADC_CURR_STEP_uA, + .adc_vbat_volt_step = BQ25960_ADC_VOLT_STEP_deciuV, + .adc_vbus_volt_step = BQ25960_ADC_VOLT_STEP_deciuV, + .adc_vbus_volt_offset = 0, + }, + + [BQ25975] = { + .model_id = BQ25975, + .regmap_config = &bq25975_regmap_config, + + .busocp_sc_def = BQ25975_BUSOCP_DFLT_uA, + .busocp_byp_def = BQ25975_BUSOCP_DFLT_uA, + .busocp_sc_min = BQ25960_BUSOCP_MIN_uA, + .busocp_sc_max = BQ25975_BUSOCP_SC_MAX_uA, + .busocp_byp_min = BQ25960_BUSOCP_MIN_uA, + .busocp_byp_max = BQ25975_BUSOCP_BYP_MAX_uA, + .busocp_step = BQ25960_BUSOCP_STEP_uA, + .busocp_offset = BQ25960_BUSOCP_OFFSET_uA, + + .busovp_sc_def = BQ25975_BUSOVP_DFLT_uV, + .busovp_byp_def = BQ25975_BUSOVP_BYPASS_DFLT_uV, + .busovp_sc_step = BQ25975_BUSOVP_SC_STEP_uV, + .busovp_sc_offset = BQ25975_BUSOVP_SC_OFFSET_uV, + .busovp_byp_step = BQ25975_BUSOVP_BYP_STEP_uV, + .busovp_byp_offset = BQ25975_BUSOVP_BYP_OFFSET_uV, + .busovp_sc_min = BQ25975_BUSOVP_SC_MIN_uV, + .busovp_sc_max = BQ25975_BUSOVP_SC_MAX_uV, + .busovp_byp_min = BQ25975_BUSOVP_BYP_MIN_uV, + .busovp_byp_max = BQ25975_BUSOVP_BYP_MAX_uV, + + .batovp_def = BQ25975_BATOVP_DFLT_uV, + .batovp_max = BQ25975_BATOVP_MAX_uV, + .batovp_min = BQ25975_BATOVP_MIN_uV, + .batovp_step = BQ25975_BATOVP_STEP_uV, + .batovp_offset = BQ25975_BATOVP_OFFSET_uV, + + .batocp_def = BQ25980_BATOCP_DFLT_uA, + .batocp_max = BQ25980_BATOCP_MAX_uA, + + .adc_curr_step = BQ25960_ADC_CURR_STEP_uA, + .adc_vbat_volt_step = BQ25960_ADC_VOLT_STEP_deciuV, + .adc_vbus_volt_step = BQ25960_ADC_VOLT_STEP_deciuV, + .adc_vbus_volt_offset = 0, + }, + +}; + +static int bq25980_power_supply_init(struct bq25980_device *bq, + struct device *dev, + int driver_data) +{ + struct power_supply_config psy_cfg = { .drv_data = bq, + .of_node = dev->of_node, }; + + psy_cfg.supplied_to = bq25980_charger_supplied_to; + psy_cfg.num_supplicants = ARRAY_SIZE(bq25980_charger_supplied_to); + + switch (driver_data) { + case BQ25980_MASTER: + bq->psy_desc.name = "bq25980-master"; + break; + case BQ25980_SLAVE: + bq->psy_desc.name = "bq25980-slave"; + break; + case BQ25980_STANDALONE: + bq->psy_desc.name = "bq25980-standalone"; + break; + case BQ25960_MASTER: + bq->psy_desc.name = "bq25960-master"; + break; + case BQ25960_SLAVE: + bq->psy_desc.name = "bq25960-slave"; + break; + case BQ25960_STANDALONE: + bq->psy_desc.name = "bq25960-standalone"; + break; + default: + return -EINVAL; + } + + bq->psy_desc.type = POWER_SUPPLY_TYPE_MAINS, + bq->psy_desc.properties = bq25980_power_supply_props, + bq->psy_desc.num_properties = ARRAY_SIZE(bq25980_power_supply_props), + bq->psy_desc.get_property = bq25980_get_charger_property, + bq->psy_desc.set_property = bq25980_set_charger_property, + bq->psy_desc.property_is_writeable = bq25980_property_is_writeable, + + bq->charger = devm_power_supply_register(bq->dev, + &bq->psy_desc, + &psy_cfg); + if (IS_ERR(bq->charger)) { + dev_err(bq->dev, "bq register power supply fail"); + return -EINVAL; + } +/* + if (bq->mode != BQ_SLAVE) { + bq->battery = devm_power_supply_register(bq->dev, + &bq25980_battery_desc, + &psy_cfg); + if (IS_ERR(bq->battery)) { + dev_err(bq->dev, "battery register power supply fail"); + return -EINVAL; + } + } +*/ + return 0; +} + +static int bq25980_reg_init(struct bq25980_device *bq) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(bq25980_reg_init_val); i++) { + ret = regmap_update_bits(bq->regmap, bq->chip_info->reg_init_values[i].reg, + 0xFF, bq->chip_info->reg_init_values[i].def); + dev_notice(bq->dev, "init Reg[%02X] = 0x%02X\n", + bq->chip_info->reg_init_values[i].reg, + bq->chip_info->reg_init_values[i].def); + if (ret) + { + dev_err(bq->dev, "Reg init fail ret=%d", ret); + return ret; + } + } + return 0; +} +#if 0 +static int bq25980_hw_init(struct bq25980_device *bq) +{ + struct power_supply_battery_info bat_info = { }; + int wd_reg_val; + int ret = 0; + int curr_val; + int volt_val; + int i; + + if (!bq->watchdog_timer) { + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_3, + BQ25980_WATCHDOG_DIS, + BQ25980_WATCHDOG_DIS); + } else { + for (i = 0; i < BQ25980_NUM_WD_VAL; i++) { + if (bq->watchdog_timer > bq25980_watchdog_time[i] && + bq->watchdog_timer < bq25980_watchdog_time[i + 1]) { + wd_reg_val = i; + break; + } + } + + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_3, + BQ25980_WATCHDOG_MASK, wd_reg_val); + } + if (ret) + return ret; + + ret = power_supply_get_battery_info(bq->charger, &bat_info); + if (ret) { + dev_warn(bq->dev, "battery info missing\n"); + return -EINVAL; + } + + bq->init_data.ichg_max = bat_info.constant_charge_current_max_ua; + bq->init_data.vreg_max = bat_info.constant_charge_voltage_max_uv; + + if (bq->state.bypass) { + ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, + BQ25980_EN_BYPASS, BQ25980_EN_BYPASS); + if (ret) + return ret; + + curr_val = bq->init_data.bypass_ilim; + volt_val = bq->init_data.bypass_vlim; + } else { + curr_val = bq->init_data.sc_ilim; + volt_val = bq->init_data.sc_vlim; + } + + ret = bq25980_set_input_curr_lim(bq, curr_val); + if (ret) + return ret; + + ret = bq25980_set_input_volt_lim(bq, volt_val); + if (ret) + return ret; + + return regmap_update_bits(bq->regmap, BQ25980_ADC_CONTROL1, + BQ25980_ADC_EN, BQ25980_ADC_EN); +} +#endif +static int bq25980_parse_dt(struct bq25980_device *bq) +{ + int ret; + + ret = device_property_read_u32(bq->dev, "ti,watchdog-timeout-ms", + &bq->watchdog_timer); + if (ret) + bq->watchdog_timer = BQ25980_WATCHDOG_MIN; + + if (bq->watchdog_timer > BQ25980_WATCHDOG_MAX || + bq->watchdog_timer < BQ25980_WATCHDOG_MIN) + return -EINVAL; + + ret = device_property_read_u32(bq->dev, + "ti,sc-ovp-limit-microvolt", + &bq->init_data.sc_vlim); + if (ret) + bq->init_data.sc_vlim = bq->chip_info->busovp_sc_def; + + if (bq->init_data.sc_vlim > bq->chip_info->busovp_sc_max || + bq->init_data.sc_vlim < bq->chip_info->busovp_sc_min) { + dev_err(bq->dev, "SC ovp limit is out of range\n"); + return -EINVAL; + } + + ret = device_property_read_u32(bq->dev, + "ti,sc-ocp-limit-microamp", + &bq->init_data.sc_ilim); + if (ret) + bq->init_data.sc_ilim = bq->chip_info->busocp_sc_def; + + if (bq->init_data.sc_ilim > bq->chip_info->busocp_sc_max || + bq->init_data.sc_ilim < bq->chip_info->busocp_sc_min) { + dev_err(bq->dev, "SC ocp limit is out of range\n"); + return -EINVAL; + } + + ret = device_property_read_u32(bq->dev, + "ti,bypass-ovp-limit-microvolt", + &bq->init_data.bypass_vlim); + if (ret) + bq->init_data.bypass_vlim = bq->chip_info->busovp_byp_def; + + if (bq->init_data.bypass_vlim > bq->chip_info->busovp_byp_max || + bq->init_data.bypass_vlim < bq->chip_info->busovp_byp_min) { + dev_err(bq->dev, "Bypass ovp limit is out of range\n"); + return -EINVAL; + } + + ret = device_property_read_u32(bq->dev, + "ti,bypass-ocp-limit-microamp", + &bq->init_data.bypass_ilim); + if (ret) + bq->init_data.bypass_ilim = bq->chip_info->busocp_byp_def; + + if (bq->init_data.bypass_ilim > bq->chip_info->busocp_byp_max || + bq->init_data.bypass_ilim < bq->chip_info->busocp_byp_min) { + dev_err(bq->dev, "Bypass ocp limit is out of range\n"); + return -EINVAL; + } + + + bq->state.bypass = device_property_read_bool(bq->dev, + "ti,bypass-enable"); + return 0; +} + +static int bq25980_check_work_mode(struct bq25980_device *bq) +{ + int ret; + int val; + + ret = regmap_read(bq->regmap, BQ25980_CHRGR_CTRL_5, &val); + if (ret) { + dev_err(bq->dev, "Failed to read operation mode register\n"); + return ret; + } + + val = (val & BQ25980_MS_MASK); + if (bq->mode != val) { + dev_err(bq->dev, "dts mode %d mismatch with hardware mode %d\n", bq->mode, val); + return -EINVAL; + } + + dev_info(bq->dev, "work mode:%s\n", bq->mode == BQ_STANDALONE ? "Standalone" : + (bq->mode == BQ_SLAVE ? "Slave" : "Master")); + return 0; +} + +static int bq25980_check_device_id(struct bq25980_device *bq) +{ +#if 0 //IC device id not confirmed + int ret; + int val; + + ret = regmap_read(bq->regmap, BQ25980_DEVICE_INFO, &val); + if (ret) { + dev_err(bq->dev, "Failed to read device id\n"); + return ret; + } + + val = (val & BQ25980_DEVICE_ID_MASK); + if (bq->device_id != val) { + dev_err(bq->dev, "dts id %d mismatch with hardware id %d\n", bq->device_id, val); + return -EINVAL; + } +#endif + return 0; +} + +static int bq25980_parse_dt_id(struct bq25980_device *bq, int driver_data) +{ + switch (driver_data) { + case BQ25960_STANDALONE: + bq->device_id = BQ25960; + bq->mode = BQ_STANDALONE; + break; + case BQ25960_SLAVE: + bq->device_id = BQ25960; + bq->mode = BQ_SLAVE; + break; + case BQ25960_MASTER: + bq->device_id = BQ25960; + bq->mode = BQ_MASTER; + break; + case BQ25980_STANDALONE: + bq->device_id = BQ25980; + bq->mode = BQ_STANDALONE; + break; + case BQ25980_SLAVE: + bq->device_id = BQ25980; + bq->mode = BQ_SLAVE; + break; + case BQ25980_MASTER: + bq->device_id = BQ25980; + bq->mode = BQ_MASTER; + break; + default: + dev_err(bq->dev, "dts compatible id %d is unknown", driver_data); + return -EINVAL; + break; + } + + return 0; +} + +static int bq25980_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct bq25980_device *bq; + int ret;//, irq_gpio, irqn; + + printk("-------bq25980 driver probe--------\n"); + bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); + if (!bq) + return -ENOMEM; + + bq->client = client; + bq->dev = dev; + + mutex_init(&bq->lock); + mutex_init(&bq->irq_complete); + + bq->resume_completed = true; + bq->irq_waiting = false; + + strncpy(bq->model_name, id->name, I2C_NAME_SIZE); + + ret = bq25980_parse_dt_id(bq, id->driver_data); + if (ret) + return ret; + + bq->chip_info = &bq25980_chip_info_tbl[bq->device_id]; + + bq->regmap = devm_regmap_init_i2c(client, + bq->chip_info->regmap_config); + if (IS_ERR(bq->regmap)) { + dev_err(dev, "Failed to allocate register map\n"); + return PTR_ERR(bq->regmap); + } + + i2c_set_clientdata(client, bq); + + ret = bq25980_check_device_id(bq); + if (ret) + return ret; + + ret = bq25980_check_work_mode(bq); + if (ret) + return ret; + + ret = bq25980_parse_dt(bq); + if (ret) { + dev_err(dev, "Failed to read device tree properties%d\n", ret); + return ret; + } + +#ifdef CONFIG_INTERRUPT_AS_GPIO + irq_gpio = of_get_named_gpio(client->dev.of_node, "ti,irq-gpio", 0); + if (!gpio_is_valid(irq_gpio)) + { + dev_err(bq->dev, "%s: %d gpio get failed\n", __func__, irq_gpio); + return -EINVAL; + } + ret = gpio_request(irq_gpio, "bq25980 irq pin"); + if (ret) { + dev_err(bq->dev, "%s: %d gpio request failed\n", __func__, irq_gpio); + return ret; + } + gpio_direction_input(irq_gpio); + irqn = gpio_to_irq(irq_gpio); + if (irqn < 0) { + dev_err(bq->dev, "%s:%d gpio_to_irq failed\n", __func__, irqn); + return irqn; + } + client->irq = irqn; +#else + + bq->irq_pinctrl = + pinctrl_get_select(bq->dev, "bq25960_int_default"); + if (!bq->irq_pinctrl) { + dev_err(bq->dev,"Couldn't set pinctrl bq25960_int_default\n"); + return ret; + //goto err_1; + } +#endif + + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + dev_name(&client->dev), bq); + if (ret < 0) { + dev_err(bq->dev,"request irq for irq=%d failed, ret =%d\n", + client->irq, ret); + return ret; + } + //enable_irq_wake(client->irq); + } + + ret = bq25980_power_supply_init(bq, dev, id->driver_data); + if (ret) + return ret; + + ret = bq25980_reg_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); + return ret; + } + + dump_reg(bq,0x00,0x37); + + return 0; +} +static int bq25980_charger_remove(struct i2c_client *client) +{ + struct bq25980_device *bq = i2c_get_clientdata(client); + + + bq25980_set_adc_enable(bq, false); + + power_supply_unregister(bq->charger); + + mutex_destroy(&bq->lock); + mutex_destroy(&bq->irq_complete); + dev_err(bq->dev,"remove Successfully\n"); + return 0; +} + + +static void bq25980_charger_shutdown(struct i2c_client *client) +{ + struct bq25980_device *bq = i2c_get_clientdata(client); + + bq25980_set_adc_enable(bq, false); + dev_err(bq->dev,"Shutdown Successfully\n"); +} + +static int bq25980_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq25980_device *bq = i2c_get_clientdata(client); + + mutex_lock(&bq->irq_complete); + bq->resume_completed = false; + mutex_unlock(&bq->irq_complete); + dev_err(bq->dev, "Suspend successfully!"); + + return 0; +} + +static int bq25980_suspend_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq25980_device *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 bq25980_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq25980_device *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); + bq25980_irq_handler_thread(client->irq, bq); + } else { + mutex_unlock(&bq->irq_complete); + } + + power_supply_changed(bq->charger); + dev_err(bq->dev,"Resume successfully!"); + + return 0; +} + +static const struct dev_pm_ops bq25980_pm_ops = { + .resume = bq25980_resume, + .suspend_noirq = bq25980_suspend_noirq, + .suspend = bq25980_suspend, +}; + +static const struct i2c_device_id bq25980_i2c_ids[] = { + { "bq25980-standalone", BQ25980_STANDALONE }, + { "bq25980-master", BQ25980_MASTER }, + { "bq25980-slave", BQ25980_SLAVE }, + { "bq25960-standalone", BQ25960_STANDALONE }, + { "bq25960-master", BQ25960_MASTER }, + { "bq25960-slave", BQ25960_SLAVE }, + { "bq25975", BQ25975 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, bq25980_i2c_ids); + +static const struct of_device_id bq25980_of_match[] = { + { .compatible = "ti,bq25980-standalone", .data = (void *)BQ25980_STANDALONE}, + { .compatible = "ti,bq25980-master", .data = (void *)BQ25980_MASTER}, + { .compatible = "ti,bq25980-slave", .data = (void *)BQ25980_SLAVE}, + { .compatible = "ti,bq25960-standalone", .data = (void *)BQ25960_STANDALONE}, + { .compatible = "ti,bq25960-master", .data = (void *)BQ25960_MASTER}, + { .compatible = "ti,bq25960-slave", .data = (void *)BQ25960_SLAVE}, + { .compatible = "ti,bq25975", .data = (void *)BQ25975 }, + { }, +}; +MODULE_DEVICE_TABLE(of, bq25980_of_match); + +static struct i2c_driver bq25980_driver = { + .driver = { + .name = "bq25980-charger", + .of_match_table = bq25980_of_match, + .pm = &bq25980_pm_ops, + }, + .probe = bq25980_probe, + .id_table = bq25980_i2c_ids, + .remove = bq25980_charger_remove, + .shutdown = bq25980_charger_shutdown, +}; +module_i2c_driver(bq25980_driver); + +MODULE_AUTHOR("Dan Murphy "); +MODULE_AUTHOR("Ricardo Rivera-Matos "); +MODULE_DESCRIPTION("bq25980 charger driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/bq2597x_mmi/bq25980_charger.h b/drivers/power/bq2597x_mmi/bq25980_charger.h new file mode 100644 index 000000000000..b4b94d405b23 --- /dev/null +++ b/drivers/power/bq2597x_mmi/bq25980_charger.h @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ */ + +#ifndef BQ25980_CHARGER_H +#define BQ25980_CHARGER_H + +#define BQ25980_MANUFACTURER "Texas Instruments" + +#define BQ25980_BATOVP 0x0 +#define BQ25980_BATOVP_ALM 0x1 +#define BQ25980_BATOCP 0x2 +#define BQ25980_BATOCP_ALM 0x3 +#define BQ25980_CHRGR_CFG_1 0x4 +#define BQ25980_CHRGR_CTRL_1 0x5 +#define BQ25980_BUSOVP 0x6 +#define BQ25980_BUSOVP_ALM 0x7 +#define BQ25980_BUSOCP 0x8 +#define BQ25980_REG_09 0x9 +#define BQ25980_TEMP_CONTROL 0xA +#define BQ25980_TDIE_ALM 0xB +#define BQ25980_TSBUS_FLT 0xC +#define BQ25980_TSBAT_FLG 0xD +#define BQ25980_VAC_CONTROL 0xE +#define BQ25980_CHRGR_CTRL_2 0xF +#define BQ25980_CHRGR_CTRL_3 0x10 +#define BQ25980_CHRGR_CTRL_4 0x11 +#define BQ25980_CHRGR_CTRL_5 0x12 +#define BQ25980_STAT1 0x13 +#define BQ25980_STAT2 0x14 +#define BQ25980_STAT3 0x15 +#define BQ25980_STAT4 0x16 +#define BQ25980_STAT5 0x17 +#define BQ25980_FLAG1 0x18 +#define BQ25980_FLAG2 0x19 +#define BQ25980_FLAG3 0x1A +#define BQ25980_FLAG4 0x1B +#define BQ25980_FLAG5 0x1C +#define BQ25980_MASK1 0x1D +#define BQ25980_MASK2 0x1E +#define BQ25980_MASK3 0x1F +#define BQ25980_MASK4 0x20 +#define BQ25980_MASK5 0x21 +#define BQ25980_DEVICE_INFO 0x22 +#define BQ25980_ADC_CONTROL1 0x23 +#define BQ25980_ADC_CONTROL2 0x24 +#define BQ25980_IBUS_ADC_MSB 0x25 +#define BQ25980_IBUS_ADC_LSB 0x26 +#define BQ25980_VBUS_ADC_MSB 0x27 +#define BQ25980_VBUS_ADC_LSB 0x28 +#define BQ25980_VAC1_ADC_MSB 0x29 +#define BQ25980_VAC1_ADC_LSB 0x2A +#define BQ25980_VAC2_ADC_MSB 0x2B +#define BQ25980_VAC2_ADC_LSB 0x2C +#define BQ25980_VOUT_ADC_MSB 0x2D +#define BQ25980_VOUT_ADC_LSB 0x2E +#define BQ25980_VBAT_ADC_MSB 0x2F +#define BQ25980_VBAT_ADC_LSB 0x30 +#define BQ25980_IBAT_ADC_MSB 0x31 +#define BQ25980_IBAT_ADC_LSB 0x32 +#define BQ25980_TSBUS_ADC_MSB 0x33 +#define BQ25980_TSBUS_ADC_LSB 0x34 +#define BQ25980_TSBAT_ADC_MSB 0x35 +#define BQ25980_TSBAT_ADC_LSB 0x36 +#define BQ25980_TDIE_ADC_MSB 0x37 +#define BQ25980_TDIE_ADC_LSB 0x38 +#define BQ25980_DEGLITCH_TIME 0x39 +#define BQ25980_CHRGR_CTRL_6 0x3A + +#define BQ25980_BUSOCP_STEP_uA 262500 +#define BQ25980_BUSOCP_OFFSET_uA 1050000 +#define BQ25960_BUSOCP_STEP_uA 250000 +#define BQ25960_BUSOCP_OFFSET_uA 1000000 + + +#define BQ25980_BUSOCP_SC_DFLT_uA 4200000 +#define BQ25980_BUSOCP_BYP_DFLT_uA 8000000 +#define BQ25975_BUSOCP_DFLT_uA 4250000 +#define BQ25960_BUSOCP_SC_DFLT_uA 4000000 +#define BQ25960_BUSOCP_BYP_DFLT_uA 5000000 + +#define BQ25980_BUSOCP_MIN_uA 1050000 +#define BQ25960_BUSOCP_MIN_uA 1000000 + +#define BQ25980_BUSOCP_SC_MAX_uA 6037500 +#define BQ25975_BUSOCP_SC_MAX_uA 5750000 +#define BQ25960_BUSOCP_SC_MAX_uA 4500000 + +#define BQ25980_BUSOCP_BYP_MAX_uA 8925000 +#define BQ25975_BUSOCP_BYP_MAX_uA 8500000 +#define BQ25960_BUSOCP_BYP_MAX_uA 6500000 + +#define BQ25980_BUSOVP_SC_STEP_uV 100000 +#define BQ25975_BUSOVP_SC_STEP_uV 50000 +#define BQ25960_BUSOVP_SC_STEP_uV 50000 +#define BQ25980_BUSOVP_SC_OFFSET_uV 14000000 +#define BQ25975_BUSOVP_SC_OFFSET_uV 7000000 +#define BQ25960_BUSOVP_SC_OFFSET_uV 7000000 + +#define BQ25980_BUSOVP_BYP_STEP_uV 50000 +#define BQ25975_BUSOVP_BYP_STEP_uV 25000 +#define BQ25960_BUSOVP_BYP_STEP_uV 25000 +#define BQ25980_BUSOVP_BYP_OFFSET_uV 7000000 +#define BQ25975_BUSOVP_BYP_OFFSET_uV 3500000 +#define BQ25960_BUSOVP_BYP_OFFSET_uV 3500000 + +#define BQ25980_BUSOVP_DFLT_uV 17800000 +#define BQ25980_BUSOVP_BYPASS_DFLT_uV 8900000 +#define BQ25975_BUSOVP_DFLT_uV 8900000 +#define BQ25975_BUSOVP_BYPASS_DFLT_uV 4450000 +#define BQ25960_BUSOVP_DFLT_uV 8900000 + +#define BQ25980_BUSOVP_SC_MIN_uV 14000000 +#define BQ25975_BUSOVP_SC_MIN_uV 7000000 +#define BQ25960_BUSOVP_SC_MIN_uV 7000000 +#define BQ25980_BUSOVP_BYP_MIN_uV 7000000 +#define BQ25975_BUSOVP_BYP_MIN_uV 3500000 +#define BQ25960_BUSOVP_BYP_MIN_uV 3500000 + +#define BQ25980_BUSOVP_SC_MAX_uV 22000000 +#define BQ25975_BUSOVP_SC_MAX_uV 12750000 +#define BQ25960_BUSOVP_SC_MAX_uV 12750000 + +#define BQ25980_BUSOVP_BYP_MAX_uV 12750000 +#define BQ25975_BUSOVP_BYP_MAX_uV 6500000 +#define BQ25960_BUSOVP_BYP_MAX_uV 6500000 + +#define BQ25980_BATOVP_STEP_uV 20000 +#define BQ25975_BATOVP_STEP_uV 10000 +#define BQ25960_BATOVP_STEP_uV 10000 + +#define BQ25980_BATOVP_OFFSET_uV 7000000 +#define BQ25975_BATOVP_OFFSET_uV 3500000 +#define BQ25960_BATOVP_OFFSET_uV 3500000 + +#define BQ25980_BATOVP_DFLT_uV 14000000 +#define BQ25975_BATOVP_DFLT_uV 8900000 +#define BQ25960_BATOVP_DFLT_uV 8900000 + +#define BQ25980_BATOVP_MIN_uV 7000000 +#define BQ25975_BATOVP_MIN_uV 3500000 +#define BQ25960_BATOVP_MIN_uV 3500000 + +#define BQ25980_BATOVP_MAX_uV 9540000 +#define BQ25975_BATOVP_MAX_uV 4770000 +#define BQ25960_BATOVP_MAX_uV 4770000 + +#define BQ25980_BATOCP_STEP_uA 100000 + +#define BQ25980_BATOCP_MASK GENMASK(6, 0) + +#define BQ25980_BATOCP_DFLT_uA 8100000 +#define BQ25960_BATOCP_DFLT_uA 6100000 + +#define BQ25980_BATOCP_MIN_uA 2000000 + +#define BQ25980_BATOCP_MAX_uA 11000000 +#define BQ25975_BATOCP_MAX_uA 11000000 +#define BQ25960_BATOCP_MAX_uA 8500000 + +#define BQ25980_ENABLE_HIZ 0xff +#define BQ25980_DISABLE_HIZ 0x0 +#define BQ25980_EN_BYPASS BIT(3) +#define BQ25980_STAT1_OVP_MASK (BIT(7) | BIT(5) | BIT(1)) +#define BQ25980_STAT3_OVP_MASK (BIT(7) | BIT(6)) +#define BQ25980_STAT1_OCP_MASK BIT(4) +#define BQ25980_STAT2_OCP_MASK BIT(7) +#define BQ25980_STAT4_TFLT_MASK GENMASK(4, 2) +#define BQ25980_WD_STAT BIT(0) +#define BQ25980_PRESENT_MASK GENMASK(4, 2) +#define BQ25980_CHG_EN BIT(4) +#define BQ25980_EN_HIZ BIT(6) +#define BQ25980_ADC_EN BIT(7) +#define BQ25980_MS_MASK GENMASK(1, 0) +#define BQ25980_DEVICE_ID_MASK GENMASK(3, 0) + +#define BQ25980_ADC_CURR_STEP_IBUS_uA 1070 +#define BQ25980_ADC_VOLT_STEP_VBAT_deciuV 10055 +#define BQ25980_ADC_VOLT_STEP_VBUS_deciuV 10066 +#define BQ25980_ADC_VOLT_OFFSET_VBUS -60000 +#define BQ25960_ADC_VOLT_STEP_deciuV 10000 +#define BQ25960_ADC_VOLT_STEP_uV 1000 +#define BQ25960_ADC_CURR_STEP_uA 1000 +#define BQ25980_ADC_POLARITY_BIT BIT(7) + +#define BQ25980_WATCHDOG_MASK GENMASK(4, 3) +#define BQ25980_WATCHDOG_DIS BIT(2) +#define BQ25980_WATCHDOG_MAX 300000 +#define BQ25980_WATCHDOG_MIN 0 +#define BQ25980_NUM_WD_VAL 4 + +#define BQ25980_VAC1_CONTROL_MASK GENMASK(7, 5) +#define BQ25980_VAC1_CONTROL_SHIFT 5 +#define BQ25980_VAC2_CONTROL_MASK GENMASK(4, 2) +#define BQ25980_VAC2_CONTROL_SHIFT 2 + +#define BQ25980_STAT1_BAT_OVP_MASK BIT(7) +#define BQ25980_STAT1_BAT_OVP_ALM_MASK BIT(6) +#define BQ25980_STAT1_BAT_OCP_MASK BIT(4) +#define BQ25980_STAT1_BAT_OCP_ALM_MASK BIT(3) +#define BQ25980_STAT1_BUS_OVP_MASK BIT(1) +#define BQ25980_STAT1_BUS_OVP_ALM_MASK BIT(0) +#define BQ25980_STAT2_BUS_OCP_MASK BIT(7) +#define BQ25980_STAT2_BUS_OCP_ALM_MASK BIT(6) //reserved +#define BQ25980_STAT4_TSBAT_FLT_MASK BIT(3) + +#endif /* BQ25980_CHARGER_H */ \ No newline at end of file