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", ®, &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, ®_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