This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

BQ27541-G1: BQ27541:the temperature is error (19286 ) from the temperature register address:0x06

Part Number: BQ27541-G1
Other Parts Discussed in Thread: BQ27500, BQ27541

hi:TI

we get the error temperature data from the register 0x06 sometime,but our i2c read function return normal!

When check the error temperature data 19286,we read the temperature register again,the data will be normal.

PS:we suspect the battery checksum maybe product the error temperature data,but we can not confirm

  • hi:TI

    our error log:temp_hot_no_delay_0305.txt

    [15396.247512] bq27x00_update:1279:update start

    [15396.259454] bq27x00_battery_read_temperature:temp = 19286,ilmd = 0,i = 0
    [15396.260592] bq27x00_battery_read_temperature:temp = 2928,read_count = 0
    [15396.261583] bq27x00_battery_read_temperature:temp = 2928,read_count = 1
    [15396.262553] bq27x00_battery_read_temperature:temp = 2928,read_count = 2

    our driver code:

    /*
     * BQ27x00 battery driver
     *
     * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
     * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
     * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
     * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
     *
     * Based on a previous work by Copyright (C) 2008 Texas Instruments, 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.
     *
     */
    
    /*
     * Datasheets:
     * http://focus.ti.com/docs/prod/folders/print/bq27000.html
     * http://focus.ti.com/docs/prod/folders/print/bq27500.html
     * http://www.ti.com/product/bq27425-g1
     * http://www.ti.com/product/BQ27742-G1
     */
    
    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/param.h>
    #include <linux/jiffies.h>
    #include <linux/workqueue.h>
    #include <linux/delay.h>
    #include <linux/platform_device.h>
    #include <linux/power_supply.h>
    #include <linux/idr.h>
    #include <linux/i2c.h>
    #include <linux/slab.h>
    #include <asm/unaligned.h>
    
    #include <linux/power/bq27x00_battery.h>
    
    /*Bug7815737, Begin , flash not work after change battery from low (less than 10 percent) to high */
    #ifdef CONFIG_T2M_PRODUCT_D01
    extern struct qpnp_qg *g_qgchip;
    extern int qg_write_monotonic_soc_from_bq27x00(struct qpnp_qg *chip, int msoc);
    extern int qg_read_monotonic_soc(struct qpnp_qg *chip, u8* msoc);
    #endif
    /*Bug7815737, End , flash not work after change battery from low (less than 10 percent) to high */
    #undef dev_dbg 
    /* Modify by jianfeng.ou, disable debug log. [PORION-1606] 2021-02-21 */
    /* #undef pr_debug */
    #undef dev_info 
    #define dev_info dev_err 
    #define dev_dbg dev_err 
    /* Modify by jianfeng.ou, disable debug log. [PORION-1606] 2021-02-21 */
    /* #define pr_debug pr_err */
    
    
    #define DRIVER_VERSION			"1.2.0"
    
    #define BQ27x00_REG_TEMP		0x06
    #define BQ27x00_REG_VOLT		0x08
    #define BQ27x00_REG_AI			0x14
    #define BQ27x00_REG_FLAGS		0x0A
    #define BQ27x00_REG_TTE			0x16
    #define BQ27x00_REG_TTF			0x18
    #define BQ27x00_REG_TTECP		0x26
    #define BQ27x00_REG_NAC			0x0C /* Nominal available capacity */
    #define BQ27x00_REG_LMD			0x12 /* Last measured discharge */
    #define BQ27x00_REG_CYCT		0x2A /* Cycle count total */
    #define BQ27x00_REG_AE			0x22 /* Available energy */
    #define BQ27x00_POWER_AVG		0x24
    
    /* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    #define BQ27x00_REG_CTRL		0x00
    #define BQ27x00_REG_DFCLS		0x3e
    #define BQ27x00_DATA_FLASH		0x3f
    #define BQ27x00_REG_ADF			0x40
    #define BQ27x00_AUTHENCHECKSUM	0x54
    #define BQ27x00_REG_DFDCKS		0x60
    #define BQ27x00_BLOCK_CTRL		0x61
    /* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    #define BQ27x00_REG_SOH		    0x2e//add the prop soh by zhaochuang.shao 20200929
    
    #define BQ27000_REG_RSOC		0x0B /* Relative State-of-Charge */
    #define BQ27000_REG_ILMD		0x76 /* Initial last measured discharge */
    #define BQ27000_FLAG_EDVF		BIT(0) /* Final End-of-Discharge-Voltage flag */
    #define BQ27000_FLAG_EDV1		BIT(1) /* First End-of-Discharge-Voltage flag */
    #define BQ27000_FLAG_CI			BIT(4) /* Capacity Inaccurate flag */
    #define BQ27000_FLAG_FC			BIT(5)
    #define BQ27000_FLAG_CHGS		BIT(7) /* Charge state flag */
    
    #define BQ27500_REG_SOC			0x2C
    #define BQ27500_REG_DCAP		0x3C /* Design capacity */
    #define BQ27500_FLAG_DSC		BIT(0)
    #define BQ27500_FLAG_SOCF		BIT(1) /* State-of-Charge threshold final */
    #define BQ27500_FLAG_SOC1		BIT(2) /* State-of-Charge threshold 1 */
    #define BQ27500_FLAG_FC			BIT(9)
    #define BQ27500_FLAG_OTC		BIT(15)
    
    #define BQ27742_POWER_AVG		0x76
    
    /* bq27425 register addresses are same as bq27x00 addresses minus 4 */
    #define BQ27425_REG_OFFSET		0x04
    #define BQ27425_REG_SOC			0x18 /* Register address plus offset */
    
    #define BQ27000_RS			20 /* Resistor sense */
    #define BQ27x00_POWER_CONSTANT		(256 * 29200 / 1000)
    
    
    #define CONFIG_BATTERY_BQ27X00_I2C
    
    
    struct bq27x00_device_info;
    struct bq27x00_access_methods {
    	int (*read)(struct bq27x00_device_info *di, u8 reg, bool single);
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	int (*write)(struct bq27x00_device_info *di, u8 reg, u8 *data, u8 len);
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    };
    
    enum bq27x00_chip { BQ27000, BQ27500, BQ27425, BQ27742};
    
    struct bq27x00_reg_cache {
    	int temperature;
    	int time_to_empty;
    	int time_to_empty_avg;
    	int time_to_full;
    	int charge_full;
    	int cycle_count;
    	int capacity;
    	int energy;
    	int flags;
    	int power_avg;
    	int health;
    	int remaining_life;//add the prop soh by zhaochuang.shao 20200929
    };
    
    struct bq27x00_device_info {
    	struct device 		*dev;
    	int			id;
    	enum bq27x00_chip	chip;
    
    	struct bq27x00_reg_cache cache;
    	int charge_design_full;
    
    	unsigned long last_update;
    	struct delayed_work work;
    
    	struct power_supply	*bat;
    	struct power_supply *smb5_psy;
    
    	struct bq27x00_access_methods bus;
    
    	struct mutex lock;
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	u8 serial_len;
    	char serial_no[32];
    	bool is_present;
    	bool doing_auth;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    };
    
    
    static enum power_supply_property bq27x00_battery_props[] = {
    	//POWER_SUPPLY_PROP_STATUS,
    	POWER_SUPPLY_PROP_PRESENT,
    	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    	POWER_SUPPLY_PROP_CURRENT_NOW,
    	POWER_SUPPLY_PROP_CAPACITY,
    	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
    	POWER_SUPPLY_PROP_TEMP,
    	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
    	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
    	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
    	POWER_SUPPLY_PROP_TECHNOLOGY,
    	POWER_SUPPLY_PROP_CHARGE_FULL,
    	POWER_SUPPLY_PROP_CHARGE_NOW,
    	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
    	POWER_SUPPLY_PROP_CYCLE_COUNT,
    	POWER_SUPPLY_PROP_ENERGY_NOW,
    	POWER_SUPPLY_PROP_POWER_AVG,
    	POWER_SUPPLY_PROP_HEALTH,
    	POWER_SUPPLY_PROP_SOH,//add the prop soh by zhaochuang.shao 20200929
    };
    
    
    #if 0
    
    static enum power_supply_property bq27425_battery_props[] = {
    	POWER_SUPPLY_PROP_STATUS,
    	POWER_SUPPLY_PROP_PRESENT,
    	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    	POWER_SUPPLY_PROP_CURRENT_NOW,
    	POWER_SUPPLY_PROP_CAPACITY,
    	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
    	POWER_SUPPLY_PROP_TEMP,
    	POWER_SUPPLY_PROP_TECHNOLOGY,
    	POWER_SUPPLY_PROP_CHARGE_FULL,
    	POWER_SUPPLY_PROP_CHARGE_NOW,
    	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
    };
    
    static enum power_supply_property bq27742_battery_props[] = {
    	POWER_SUPPLY_PROP_STATUS,
    	POWER_SUPPLY_PROP_PRESENT,
    	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    	POWER_SUPPLY_PROP_CURRENT_NOW,
    	POWER_SUPPLY_PROP_CAPACITY,
    	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
    	POWER_SUPPLY_PROP_TEMP,
    	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
    	POWER_SUPPLY_PROP_TECHNOLOGY,
    	POWER_SUPPLY_PROP_CHARGE_FULL,
    	POWER_SUPPLY_PROP_CHARGE_NOW,
    	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
    	POWER_SUPPLY_PROP_CYCLE_COUNT,
    	POWER_SUPPLY_PROP_POWER_AVG,
    	POWER_SUPPLY_PROP_HEALTH,
    };
    #endif
    
    static unsigned int poll_interval = 360;
    module_param(poll_interval, uint, 0644);
    MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \
    				"0 disables polling");
    
    /*
     * Common code for BQ27x00 devices
     */
    
    static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
    		bool single)
    {
    	if (di->chip == BQ27425)
    		return di->bus.read(di, reg - BQ27425_REG_OFFSET, single);
    	return di->bus.read(di, reg, single);
    }
    
    /* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    static inline int bq27xxx_read(struct bq27x00_device_info *di, u8 reg,
    		bool single)
    {
    	return di->bus.read(di, reg, single);
    }
    
    static inline int bq27xxx_write(struct bq27x00_device_info *di, u8 reg,
    		u8 *data, u8 len)
    {
    	return di->bus.write(di, reg, data, len);
    }
    
    #define BATTERY_CRITICAL_TEMP_HOT (700 + 2731) //if the battery temp up 70 deg,read more times by the i2c for PR:10204940
    #define READ_TEMP_DELAY 100 //delay 100ms when the temp error for PR:10204940
    #define RETRY_COUNT 5
    static int retry_sleep_ms[RETRY_COUNT] = {10, 20, 30, 40, 50};
    static int bq27xxx_battery_i2c_read(struct bq27x00_device_info *di, u8 reg,
    		bool single)
    {
    	struct i2c_client *client = to_i2c_client(di->dev);
    	struct i2c_msg msg[2];
    	unsigned char data[2];
    	int ret = 0;
    	int retry_count = 0;
    
    	if (!client->adapter)
    		return -ENODEV;
    
    	msg[0].addr = client->addr;
    	msg[0].flags = 0;
    	msg[0].buf = &reg;
    	msg[0].len = sizeof(reg);
    	msg[1].addr = client->addr;
    	msg[1].flags = I2C_M_RD;
    	msg[1].buf = data;
    	if (single)
    		msg[1].len = 1;
    	else
    		msg[1].len = 2;
    
    	if (ret < 0)
    		return ret;
    read_retry:
    	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    
    	if(ret < 0)
    	{
    		if(retry_count < RETRY_COUNT){
    			/* sleep for few ms before retrying */
    			msleep(retry_sleep_ms[retry_count++]);
    			goto read_retry;
    		} else {
    			return ret;
    		}
    	}
    
    	if (!single)
    		ret = get_unaligned_le16(data);
    	else
    		ret = data[0];
    
    	return ret;
    }
    
    static int bq27xxx_battery_i2c_write(struct bq27x00_device_info *di, u8 reg, u8 *data, u8 len)
    {
    	struct i2c_client *client = to_i2c_client(di->dev);
    	int i;
    	int ret = 0;
    	int retry_count = 0;
    
    	for(i=0;i < len;i++)
    	{
    		retry_count  = 0;
    retry:
    		ret = i2c_smbus_write_byte_data(client, reg+i, data[i]);
    
    		if(ret != 0)
    		{
    			if(retry_count < RETRY_COUNT){
    				/* sleep for few ms before retrying */
    				printk("%s :retry_count=%d.\n",__func__, retry_count);
    				msleep(retry_sleep_ms[retry_count++]);
    				goto retry;
    			} else {
    				printk("%s write reg=%x,data=%x, fail \n",__func__, reg+i,data[i]);
    				return -1;
    			}
    		}
    	}
    
    	return ret;
    }
    
    static int bq27xxx_read_block_data (struct bq27x00_device_info *di, u8 reg, u8 *data,u8 len)
    {
    	int i;
    	int ret;
    
    	for(i=0;i < len;i++){
    		ret = bq27xxx_battery_i2c_read(di, reg+i, true);
    		if(ret < 0){
    			dev_err(di->dev, "Failed to read\n");
    			return -1;
    		} else{
    			data[i] = (u8)ret;
    		}
    
    	}
    	return 0;
    }
    
    static int bq27541_i2c_txsubcmd(struct bq27x00_device_info *di, u8 reg, unsigned short subcmd)
    {
    	struct i2c_msg msg;
    	unsigned char data[3];
    	int ret;
    	struct i2c_client *client = to_i2c_client(di->dev);
    	if (!client)
    		return -ENODEV;
    
    	memset(data, 0, sizeof(data));
    	data[0] = reg;
    	data[1] = subcmd & 0x00FF;
    	data[2] = (subcmd & 0xFF00) >> 8;
    
    	msg.addr = client->addr;
    	msg.flags = 0;
    	msg.len = 3;
    	msg.buf = data;
    
    	ret = i2c_transfer(client->adapter, &msg, 1);
    	if (ret < 0)
    		return -EIO;
    
    	return 0;
    }
    
    static void bq27541_cntl_cmd(struct bq27x00_device_info *di, int subcmd)
    {
    	bq27541_i2c_txsubcmd(di, BQ27x00_REG_CTRL, subcmd);
    }
    
    #define CONTROL_STATUS			0x00
    #define MESSAGE_LEN				20
    #define KEY_LEN					16
    #define UNSEAL_KEY_LEN			4
    
    static u8 recv_buf[MESSAGE_LEN]={0x0};
    static u8 chellange_buf[MESSAGE_LEN]={0x2a, 0x04, 0x77, 0x72, 0x72, 0x1e, 0x89, 0xf5, 0x03, 0x16, 0x62, 0xae, 0x40, 0x80, 0xd4, 0x9e, 0xb6, 0x67, 0xae};
    
    static bool is_sealed(struct bq27x00_device_info *di)
    {
    	int value = 0;
    
    	bq27541_cntl_cmd(di, CONTROL_STATUS);
    	msleep(1);
    	value = bq27xxx_read(di, BQ27x00_REG_CTRL,false);
    	pr_debug("%s REG_CNTL: 0x%x\n", __func__, value);
    
    	return !!(value & BIT(13));
    }
    
    #ifdef GAUGE_ROM_DEBUG
    
    #define DEVICE_TYPE					0x01
    #define BQ27541_RESET_SUBCMD		0x0041
    #define SEAL_SUBCMD					0x0020
    #define SEAL_POLLING_RETRY_LIMIT	10
    
    static u32 unseal_key = 0x20180101;
    //static u32 unseal_key = 0x36720414;	/* default key */
    static u8 new_auth_key[KEY_LEN]={0x77,0x30,0xa1,0x28,0x0a,0xa1,0x13,0x20,0xef,0xcd,0xab,0x89,0x67,0x45,0x23,0x01};
    static u8 default_auth_key[KEY_LEN]={0x10,0x32,0x54,0x76,0x98,0xba,0xdc,0xfe,0xef,0xcd,0xab,0x01,0x01,0x01,0x18,0x20};
    
    static int seal(struct bq27x00_device_info *di)
    {
    	int i = 0;
    
    	if(is_sealed(di)){
    		pr_err("bq27541 sealed,return\n");
    		return 0;
    	}
    	bq27541_cntl_cmd(di, SEAL_SUBCMD);
    	msleep(1);
    	for(i = 0;i < SEAL_POLLING_RETRY_LIMIT;i++){
    		if(is_sealed(di))
    			return 0;
    		msleep(1);
    	}
    	pr_err( "bq27541 seal fail !\n");
    	return -1;
    }
    
    static int unseal(struct bq27x00_device_info *di, u32 key)
    {
    	int i = 0;
    
    		if (!is_sealed(di)){
    			pr_err("chip is unsealed.\n");
    			return 0;
    		}
    
    	for(i = 0; i < SEAL_POLLING_RETRY_LIMIT;i++){
    		bq27541_cntl_cmd(di, key&0x0000FFFF);
    		msleep(1);
    		bq27541_cntl_cmd(di, (key>>16)&0x0000FFFF);
    		msleep(1);
    
    		bq27541_cntl_cmd(di, 0xffff);
    		msleep(1);
    		bq27541_cntl_cmd(di, 0xffff);
    		msleep(1);
    
    		if (!is_sealed(di)){
    			pr_err("unsealed successful.\n");
    			return 0;
    		}
    	}
    	pr_err( "bq27541 unseal fail !\n");
    	return -1;
    }
    
    static int bq27541_reset(struct bq27x00_device_info *di)
    {
    	int value;
    	int ret = 0;
    
    	ret = unseal(di, unseal_key);
    	if(ret < 0){
    		return ret;
    	}
    
    	bq27541_cntl_cmd(di, BQ27541_RESET_SUBCMD);
    	msleep(1);
    	value = bq27xxx_read(di, BQ27x00_REG_CTRL,false);
    
    	printk(KERN_ERR "bq27541 CONTROL_STATUS: 0x%x\n", value);
    	ret = seal(di);
    	if (ret < 0){
    		return ret;
    	}
    
    	return ret;
    }
    
    static int bq27541_rw_blockdata(struct bq27x00_device_info *di, u8 subcmd, int offset)
    {
        int ret;
    	u8 temp;
    
    	temp = subcmd;
    	ret = bq27xxx_write(di, BQ27x00_REG_DFCLS, &temp,1);
    	temp = offset / 32;
    	ret = bq27xxx_write(di, BQ27x00_DATA_FLASH,&temp ,1);
    	temp = 0;
    	ret = bq27xxx_write(di, BQ27x00_BLOCK_CTRL,&temp,1);
    	return ret;
    }
    
    __maybe_unused static int bq27541_battery_set_auth_key(struct bq27x00_device_info *di, bool default_key)
    {
    	int ret;
    	char authen_cmd_buf = 0;
    	char block_data_buf[32] = {0x00};
    	u8 sum,i;
    
    	//step 1, unseal the fuel gauge
    	ret = unseal(di, unseal_key);
    	if (ret < 0)
    		return ret;
    	//step 2, send Authentication() command
    
    	//step 3, enable the authentication data commands
    	ret = bq27xxx_write(di,BQ27x00_BLOCK_CTRL,&authen_cmd_buf,1);
    	if (ret < 0)
    		return ret;
    	//step 4, set security class
    	bq27541_rw_blockdata(di,0x70,0);
    
    	//step 5, read 32 bytes from BlockData
    	bq27xxx_read_block_data(di,BQ27x00_REG_ADF,block_data_buf,32);
    
    	// MODIFY-BEGIN by jianfeng.ou, set debug unseal key to 20180101, ALM9030830 2020-03-20
    	for (i = 0; i < UNSEAL_KEY_LEN; i++) {
    		block_data_buf[UNSEAL_KEY_LEN - i - 1] = (unseal_key >> (8 * i)) & 0x000000ff;
    	}
    	// MODIFY-END by jianfeng.ou, set debug unseal key to 20180101, ALM9030830 2020-03-20
    
    	for(i=0;i< KEY_LEN;i++){
    		if(default_key)
    			block_data_buf[8+i] = default_auth_key[KEY_LEN-i-1];
    		else
    			block_data_buf[8+i] = new_auth_key[KEY_LEN-i-1];
    	}
    
    	for(i = 0;i < 32;i++){
    		pr_info("AUTHENDATA[%02d]:0x%02x\n",i,block_data_buf[i]);
    	}
    
    	//step 7, write new key back
    	bq27xxx_write(di, BQ27x00_REG_ADF, block_data_buf, 32);
    
    	//step 8, write checksum
    	sum = 0;
    	for (i=0; i<32; i++) {
    		sum += block_data_buf[i];
    	}
    	sum = 0xff - sum;
    
    	msleep(50);
    
    	bq27xxx_write(di, BQ27x00_REG_DFDCKS, &sum,1);
    
    	msleep(200);
    
    	bq27541_rw_blockdata(di,0x70,0);
    	bq27xxx_read_block_data(di,BQ27x00_REG_ADF,block_data_buf,32);
    
    	for(i = 0;i < 32;i++){
    		pr_info("BQ27XXX_AUTHENDATA[%02d]:0x%02x\n",i,block_data_buf[i]);
    	}
    
    	//step 9, seal the fuel gauge
    	ret = seal(di);
    	if (ret < 0)
    		return ret;
    	return 0;
    }
    
    __maybe_unused static int bq27541_device_type(struct bq27x00_device_info *di)
    {
    	int value = 0;
    
    	bq27541_cntl_cmd(di,DEVICE_TYPE);
    	msleep(1);
    	value = bq27xxx_read(di, BQ27x00_REG_CTRL,false);
    	pr_err("%s DEVICE_TYPE: 0x%x\n", __func__, value);
    
    	return value;
    }
    #endif /* GAUGE_ROM_DEBUG */
    
    u8 a2x(const char c)
    {
    	switch(c) {
    	case '0'...'9':
    		return c-'0';
    	case 'a'...'f':
    		return 0xa + (c-'a');
    	case 'A'...'F':
    		return 0xa + (c-'A');
    	default:
    		goto error;
    	}
    error:
    	printk("error %d",c);
    	return -1;
    }
    
    void strtohex(u8 *dst_str, const u8 *src_str)
    {
    	u8 i;
    	for(i = 0; i < MESSAGE_LEN; i++) {
    		dst_str[i] = (a2x(src_str[i*2]) << 4)|a2x(src_str[i*2 + 1]);
    	}
    	return;
    }
    
    #define MFG_BLOCK_SIZE 32
    #define MODEL_SIZE	10
    
    // Access Manufacturer Info Block A
    static int set_mfg_block_a(struct bq27x00_device_info *di, int sealed)
    {
    	u8 block = 1;
    	u8 temp;
    	int dfd_cntl_status = 0;
    
    	if (sealed) {
    		//when sealed , 1 : bloack A  2: block B
    		block = 1;
    	} else {
    		dfd_cntl_status = bq27xxx_read(di, BQ27x00_BLOCK_CTRL, true);
    		if (dfd_cntl_status != 0) {
    			temp = 0;
    			bq27xxx_write(di,BQ27x00_BLOCK_CTRL,&temp,1);
    		}
    
    		temp = 58;
    		bq27xxx_write(di, BQ27x00_REG_DFCLS, &temp,1);
    		// when unsealed , 0 : bloack A  1: block B
    		block = 0;
    	}
    
    	bq27xxx_write(di, BQ27x00_DATA_FLASH, &block ,1);
    	msleep(1);
    	return 0;
    }
    
    static bool bq27541_battery_read_serial(struct bq27x00_device_info *di)
    {
    	int data;
    	u8 sum = 0;
    	int sealed = 0;
    	int i;
    	char sn[MFG_BLOCK_SIZE];
    
    
    	sealed = is_sealed(di);
    	set_mfg_block_a(di, sealed);
    
    	memset(di->serial_no, 0, MFG_BLOCK_SIZE);
    	bq27xxx_read_block_data(di,BQ27x00_REG_ADF,sn,MFG_BLOCK_SIZE);
    	di->serial_len = sn[0];
    
    	/* [BEGIN] modify by jianfeng.ou for ALM8972958. 20200302 */
    	if (di->serial_len <= 0 || di->serial_len > MFG_BLOCK_SIZE - 1) {
    		dev_err(di->dev, "serial_len %d is not valid\n", di->serial_len);
    		return false;
    	}
    	/* [END] modify by jianfeng.ou for ALM8972958. 20200302 */
    
    	for (i = 0; i < MFG_BLOCK_SIZE; i++) {
    		sum += sn[i];
    	}
    
    	data = bq27xxx_read(di, BQ27x00_REG_DFDCKS,true);
    	sum += data;
    	if (sum != 0xFF) {
    		dev_err(di->dev, "check-sum 0x%x error\n", sum);
    		return false;
    	}
    
    	/* [BEGIN] modify by jianfeng.ou for ALM8972958. Separate MODEL and SN. 20200302 */
    	if(di->serial_len < 15 )
    	{//added by zhaochuang.shao because the PVT battery sn changed 20201013,ALM9500604
    		memcpy(di->serial_no, &sn[1], sn[0]);
    		di->serial_no[di->serial_len] = 0x0a;
    	}else{
    		memcpy(di->serial_no, &sn[MODEL_SIZE + 1], sn[0] - MODEL_SIZE);
    		di->serial_no[di->serial_len - MODEL_SIZE] = 0x0a;
    	/* [END] modify by jianfeng.ou for ALM8972958. 20200302 */
    	}
    	return true;
    }
    
    static int bq27541_battery_write_serial(struct bq27x00_device_info *di, const char* serial_no)
    {
    	u8 sum = 0;
    	int sealed = 0;
    	int serial_len = strlen(serial_no);
    	u8 buf_w[MFG_BLOCK_SIZE];
    	u8 buf_r[MFG_BLOCK_SIZE];
    	int i;
    
    	if (serial_len && serial_no[serial_len-1] == 0x0a) {
    		serial_len = serial_len - 1;
    	}
    
    	if (serial_len <= 0 || serial_len > 20) {
    		dev_err(di->dev, "serial_len %d is not valid\n", serial_len);
    		return -1;
    	}
    
    	sealed = is_sealed(di);
    	set_mfg_block_a(di, sealed);
    
    	// prepare data
    	memset(buf_w, 0, MFG_BLOCK_SIZE);
    	buf_w[0] = serial_len;
    	memcpy(&buf_w[1], serial_no, serial_len);
    	dev_info(di->dev, "Write serial [%s] to battery\n", &buf_w[1]);
    
    	// write it to battery
    	bq27xxx_write(di, BQ27x00_REG_ADF, buf_w, MFG_BLOCK_SIZE);
    	for (i = 0; i < MFG_BLOCK_SIZE; i++) {
    		sum += buf_w[i];
    	}
    	sum = 0xff - sum;
    
    	// read it back
    	memset(buf_r, 0, MFG_BLOCK_SIZE);
    	bq27xxx_read_block_data(di,BQ27x00_REG_ADF,buf_r,MFG_BLOCK_SIZE);
    	dev_info(di->dev, "read serial [%s] from battery\n", buf_r);
    
    	// check it
    	if(memcmp(buf_w, buf_r, sizeof(buf_w))) {
    		dev_err(di->dev, "Verification failed\n");
    		return -1;
    	}
    	// write check-sum to battery
    	dev_info(di->dev, "Check-sum=0x%x\n", sum);
    	bq27xxx_write(di, BQ27x00_REG_DFDCKS, &sum ,1);
    	msleep(200);
    
    	return serial_len;
    }
    
    static ssize_t authentication_store(struct device *dev,  struct device_attribute *attr, const char *buf,  size_t count)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    	int rc,i;
    	u8 checksum_buf = 0;
    	u8 authen_cmd_buf = 0;
    	int sealed;
    	pr_info("%s:sizeof(buf) = %d, %s.\n",__func__,(int)strlen(buf),buf);
    
    	//transfer string to array
    	strtohex(chellange_buf,buf);
    
    	pm_stay_awake(di->dev);
    	cancel_delayed_work_sync(&di->work);
    	di->doing_auth = true;
    
    	for(i = 0;i < MESSAGE_LEN;i++){
    		checksum_buf += chellange_buf[i];
    	}
    	checksum_buf = 0xff - (checksum_buf&0xff);
    
    	for(i=0;i<5;i++){
    		sealed = is_sealed(di);
    		pr_debug("%s sealed = %d \n",__func__,sealed);
    		if(!sealed){
    			// step 1: unseal mode->write 0x01 to blockdatactrl
    			authen_cmd_buf = 0x01;
    			rc = bq27xxx_write(di,BQ27x00_BLOCK_CTRL,&authen_cmd_buf,1);
    		} else {
    			// step 1: seal mode->write 0x00 to dataflashblock
    			rc = bq27xxx_write(di,BQ27x00_DATA_FLASH,&authen_cmd_buf,1);
    		}
    
    		if( rc < 0 ){
    			pr_info("%s write authen_cmd_buf  error\n",__func__);
    			continue;
    		}
    
    		msleep(10);
    
    		// step 2: write 20 bytes to authendata_reg
    		rc = bq27xxx_write(di, BQ27x00_REG_ADF, chellange_buf, MESSAGE_LEN);
    		if(rc < 0){
    			pr_info("%s write chellange_buf error\n",__func__);
    			continue;
    		}
    		msleep(10);
    
    		// step 3: write checksum to authenchecksum_reg for compute
    		rc = bq27xxx_write(di,BQ27x00_AUTHENCHECKSUM,&checksum_buf,1);
    		if(rc < 0){
    			pr_info("%s write checksum_buf = %d, error (%d)\n",__func__,checksum_buf,i);
    			msleep(2);
    			continue;
    		}
    
    		msleep(100);
    		memset(recv_buf, 0, MESSAGE_LEN);
    
    		// step 4: read Digest data
    		rc = bq27xxx_read_block_data(di,BQ27x00_REG_ADF,recv_buf,MESSAGE_LEN);
    		if((recv_buf[MESSAGE_LEN-1] == chellange_buf[MESSAGE_LEN-1]) &&
    			(recv_buf[MESSAGE_LEN-2] == chellange_buf[MESSAGE_LEN-2]) &&
    			(recv_buf[MESSAGE_LEN-3] == chellange_buf[MESSAGE_LEN-3])){
    			pr_info("%s : read invalid digist string. \n",__func__);
    			continue;
    		} else {
    			break;  //exit loop
    		}
    	}
    
        return count;
    }
    
    static ssize_t authentication_show(struct device *dev, struct device_attribute *attr, char *buf)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    	int i;
    	ssize_t ret;
    
    	di->doing_auth = false;
    	schedule_delayed_work(&di->work, HZ); //update battery info 1 second later after finished authentication.
    	pm_relax(di->dev);
    
    	for(i = 0; i < MESSAGE_LEN; i++) {
    		ret = sprintf(buf, "%s%02x",buf,recv_buf[i]);
    	}
    	ret = sprintf(buf, "%s\n",buf);
    
    	memset(recv_buf, 0, MESSAGE_LEN);
    
    	return ret;
    }
    
    __maybe_unused static ssize_t serial_no_store(struct device *dev,  struct device_attribute *attr,
    		const char *buf,  size_t count)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    
    	if (!di->is_present)
    		return -1;
    
    	di->serial_len = bq27541_battery_write_serial(di, buf);
    	dev_info(di->dev, "Serial=%s\n", di->serial_len ? di->serial_no : "unknown");
    
    	return count;
    }
    
    static ssize_t serial_no_show(struct device *dev, struct device_attribute *attr, char *buf)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    	int i;
    
    	if (!di->is_present)
    		return sprintf(buf,"Unknown\n");
    
    	for(i=0;i<5;i++){
    		if(bq27541_battery_read_serial(di))
    			goto serial_no_out;
    	}
    
    serial_no_out:
    	return sprintf(buf, "%s", di->serial_len ? di->serial_no : "unknown\n");
    }
    
    #ifdef GAUGE_ROM_DEBUG
    static ssize_t reset_store(struct device *dev,  struct device_attribute *attr, const char *buf,  size_t count)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    
    	int ret;
    	if (!di->is_present)
    		return -1;
    
    	ret = bq27541_reset(di);
    	if(ret < 0){
    		dev_info(dev, "[%s] failed to reset fuel gauge.\n",__func__);
    	}
    
    	return count;
    }
    
    static ssize_t set_auth_key_store(struct device *dev,  struct device_attribute *attr, const char *buf,  size_t count)
    {
    	struct power_supply *psy = dev_get_drvdata(dev);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    	bool default_key;
    	int ret;
    	if (!di->is_present)
    		return -1;
    
    	ret = kstrtobool(buf, &default_key);
    	if (ret){
    		dev_info(dev, "[%s] failed to get input parameters.\n",__func__);
    		return ret;
    	}
    
    	dev_info(dev, "[%s] default_key = %d.\n",__func__,default_key);
    
    	ret = bq27541_battery_set_auth_key(di,default_key);
    	if(ret < 0){
    		dev_info(dev, "[%s] failed to set key.\n",__func__);
    	}
    
    	return count;
    }
    #endif /* GAUGE_ROM_DEBUG */
    
    static struct device_attribute bq27541_battery_attrs[] = {
    	__ATTR_RW(authentication),
    #ifdef GAUGE_ROM_DEBUG
    	__ATTR_RW(serial_no),
    	__ATTR_WO(reset),
    	__ATTR_WO(set_auth_key),
    #else
    	__ATTR_RO(serial_no),
    #endif
    };
    
    static int bq27541_create_attrs(struct device *dev)
    {
    	unsigned int i;
    
    	for (i = 0; i < ARRAY_SIZE(bq27541_battery_attrs); i++)
    		if (device_create_file(dev, &bq27541_battery_attrs[i]))
    			goto bq27541_create_attrs_failed;
    
    	return 0;
    
    bq27541_create_attrs_failed:
    	dev_err(dev, "failed creating bq27541 battery attrs.\n");
    	while (i--)
    		device_remove_file(dev, &bq27541_battery_attrs[i]);
    
    	return -EIO;
    }
    /* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    /*
     * Higher versions of the chip like BQ27425 and BQ27500
     * differ from BQ27000 and BQ27200 in calculation of certain
     * parameters. Hence we need to check for the chip type.
     */
    static bool bq27xxx_is_chip_version_higher(struct bq27x00_device_info *di)
    {
    	if (di->chip == BQ27425 || di->chip == BQ27500 || di->chip == BQ27742)
    		return true;
    	return false;
    }
    
    /*
     * Return the battery Relative State-of-Charge
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
    {
    	int rsoc;
    
    	if (di->chip == BQ27500 || di->chip == BQ27742)
    		rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
    	else if (di->chip == BQ27425)
    		rsoc = bq27x00_read(di, BQ27425_REG_SOC, false);
    	else
    		rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
    
    	if (rsoc < 0)
    		dev_dbg(di->dev, "error reading relative State-of-Charge\n");
    
    	return rsoc;
    }
    
    /*
     * Return a battery charge value in µAh
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
    {
    	int charge;
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	static int last_charge = 0;
    
    	if(di->doing_auth)
    		return last_charge;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	charge = bq27x00_read(di, reg, false);
    	if (charge < 0) {
    		dev_dbg(di->dev, "error reading charge register %02x: %d\n",
    			reg, charge);
    		return charge;
    	}
    
    	if (bq27xxx_is_chip_version_higher(di))
    		charge *= 1000;
    	else
    		charge = charge * 3570 / BQ27000_RS;
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	last_charge = charge;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	return charge;
    }
    
    /*
     * Return the battery Nominal available capaciy in µAh
     * Or < 0 if something fails.
     */
    static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di)
    {
    	int flags;
    	bool is_bq27500 = di->chip == BQ27500;
    	bool is_bq27742 = di->chip == BQ27742;
    	bool is_higher = bq27xxx_is_chip_version_higher(di);
    	bool flags_1b = !(is_bq27500 || is_bq27742);
    
    	flags = bq27x00_read(di, BQ27x00_REG_FLAGS, flags_1b);
    	if (flags >= 0 && !is_higher && (flags & BQ27000_FLAG_CI))
    		return -ENODATA;
    
    	return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC);
    }
    
    /*
     * Return the battery Last measured discharge in µAh
     * Or < 0 if something fails.
     */
    static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di)
    {
    	return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD);
    }
    
    /*
     * Return the battery Initial last measured discharge in µAh
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
    {
    	int ilmd;
    
    	if (bq27xxx_is_chip_version_higher(di))
    		ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
    	else
    		ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
    
    	if (ilmd < 0) {
    		dev_dbg(di->dev, "error reading initial last measured discharge\n");
    		return ilmd;
    	}
    
    	if (bq27xxx_is_chip_version_higher(di))
    		ilmd *= 1000;
    	else
    		ilmd = ilmd * 256 * 3570 / BQ27000_RS;
    
    	return ilmd;
    }
    
    /*
     * Return the battery Available energy in µWh
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_energy(struct bq27x00_device_info *di)
    {
    	int ae;
    
    	ae = bq27x00_read(di, BQ27x00_REG_AE, false);
    	if (ae < 0) {
    		dev_dbg(di->dev, "error reading available energy\n");
    		return ae;
    	}
    
    	if (di->chip == BQ27500)
    		ae *= 1000;
    	else
    		ae = ae * 29200 / BQ27000_RS;
    
    	return ae;
    }
    
    /*
     * Return the battery temperature in tenths of degree Kelvin
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
    {
    	int temp,ilmd = 0;
    	int i,read_count;
            static int last_temp = 0;
            static int temp_hot_count = 0;
    
    	//printk("capacity = %d\n",bq27x00_read(di, BQ27500_REG_DCAP, false));
    
    	//printk("temp = %d,read_temp = %d,read_count = %d\n",temp,bq27x00_read(di, BQ27x00_REG_TEMP, false));
    
    	temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    	if (temp < 0) {
    		dev_err(di->dev, "error reading temperature\n");
    		return temp;
    	}
    
    	if (!bq27xxx_is_chip_version_higher(di))
    		temp = 5 * temp / 2;
    
    //[BEGIN]:added by zhaochuang.shao for the temp error 160 degreen sometime 20210226,PR:10204940
    	if(temp >= BATTERY_CRITICAL_TEMP_HOT ){
    			for(i = 0;i < 2;i++){
    				pr_err("%s:temp = %d,ilmd = %d,i = %d\n",__func__,temp,ilmd,i);
    
    				for(read_count = 0;read_count < 5;read_count++)
    					printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);
    
    				printk("%s:capacity = %d\n",__func__,bq27x00_read(di, BQ27500_REG_DCAP, false));
    
    				for(read_count = 0;read_count < 5;read_count++)
    					printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);
    
    				mdelay(READ_TEMP_DELAY);
    
    				temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    				if (temp < 0) {
    					dev_err(di->dev, "error reading temperature\n");
    					return temp;
    				}
    
    				if (!bq27xxx_is_chip_version_higher(di))
    					temp = 5 * temp / 2;
    				ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
    
    				//if(temp < BATTERY_CRITICAL_TEMP_HOT)
    					//break;
    			}
    	}
    
    	if(temp >= BATTERY_CRITICAL_TEMP_HOT){
    		pr_err("%s:last_temp_count = %d,temp = %d,last_temp = %d\n",__func__,temp_hot_count,temp,last_temp);
    		if(++temp_hot_count <= 3) //just recheck for 3 times,if it is still hot,we will report 
    			temp = last_temp;
    	}
    	else{
    		temp_hot_count = 0;
    	}
    
    	last_temp = temp;
    //[END]:by zhaochuang.shao 20210226
    
    	return temp;
    }
    //[BEGIN]:add the prop soh by zhaochuang.shao 20200929
    static int bq27x00_battery_read_remaining_life(struct bq27x00_device_info *di)
    {
    	int remaining_life = 0;
    
    	remaining_life = bq27x00_read(di, BQ27x00_REG_SOH, false);
    	if ((remaining_life < 0) || (remaining_life > 100))
    		dev_err(di->dev, "error reading remaining_life\n");
    	//pr_err("--bq27x00_battery_read_remaining_life,  remaining_life=%d--\n",remaining_life);
    
    	return remaining_life;
    }
    //[END]:by zhaochuang.shao 20200929
    /*
     * Return the battery Cycle count total
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di)
    {
    	int cyct;
    
    	cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false);
    	if (cyct < 0)
    		dev_err(di->dev, "error reading cycle count total\n");
    
    	return cyct;
    }
    
    /*
     * Read a time register.
     * Return < 0 if something fails.
     */
    static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
    {
    	int tval;
    
    	tval = bq27x00_read(di, reg, false);
    	if (tval < 0) {
    		dev_dbg(di->dev, "error reading time register %02x: %d\n",
    			reg, tval);
    		return tval;
    	}
    
    	if (tval == 65535)
    		return -ENODATA;
    
    	return tval * 60;
    }
    
    /*
     * Read a power avg register.
     * Return < 0 if something fails.
     */
    static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg)
    {
    	int tval;
    
    	tval = bq27x00_read(di, reg, false);
    	if (tval < 0) {
    		dev_err(di->dev, "error reading power avg rgister  %02x: %d\n",
    			reg, tval);
    		return tval;
    	}
    
    	if (di->chip == BQ27500)
    		return tval;
    	else
    		return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS;
    }
    
    /*
     * Read flag register.
     * Return < 0 if something fails.
     */
    static int bq27x00_battery_read_health(struct bq27x00_device_info *di)
    {
    	int tval;
    
    	tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
    	if (tval < 0) {
    		dev_err(di->dev, "error reading flag register:%d\n", tval);
    		return tval;
    	}
    	//pr_debug("zxz----bq27x00_battery_read_health--11--di->chip=%d--tval=%x-\n",di->chip,tval);
    
    	if (di->chip == BQ27500) {
    		if (tval & BQ27500_FLAG_SOCF)
    			tval = POWER_SUPPLY_HEALTH_DEAD;
    		else if (tval & BQ27500_FLAG_OTC)
    			tval = POWER_SUPPLY_HEALTH_OVERHEAT;
    		else
    			tval = POWER_SUPPLY_HEALTH_GOOD;
    		
    		//pr_debug("zxz----bq27x00_battery_read_health--22--tval=%d---\n",tval);
    		return tval;
    	} else {
    		if (tval & BQ27000_FLAG_EDV1)
    			tval = POWER_SUPPLY_HEALTH_DEAD;
    		else
    			tval = POWER_SUPPLY_HEALTH_GOOD;
    		
    		//pr_err("zxz----bq27x00_battery_read_health--33--tval=%d---\n",tval);
    		return tval;
    	}
    
    	return -1;
    }
    
    static void bq27x00_update(struct bq27x00_device_info *di)
    {
    	struct bq27x00_reg_cache cache = {0, };
    	bool is_bq27500 = di->chip == BQ27500;
    	bool is_bq27425 = di->chip == BQ27425;
    	bool is_bq27742 = di->chip == BQ27742;
    	bool flags_1b = !(is_bq27500 || is_bq27742);
    #ifdef CONFIG_T2M_PRODUCT_D01
    
    	u8 read_msoc;
    #endif
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	if(di->doing_auth){
    		dev_err(di->dev, "[%s]processing authentication.\n",__func__);
    		return;
    	}
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, flags_1b);
    	if ((cache.flags & 0xff) == 0xff)
    		{
    		/* read error */
    		cache.flags = -1;
    		//cache.capacity = -ENODATA;
    		cache.capacity=50;
    		pr_err("zxz-----bq27x00_update-00-read error !!!----cache.flags=%x---\n",cache.flags);
    		}
    	if (cache.flags >= 0) {
    		if (!is_bq27500 && !is_bq27425 && !is_bq27742
    				&& (cache.flags & BQ27000_FLAG_CI)) {
    			dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
    			cache.capacity = -ENODATA;
    			cache.energy = -ENODATA;
    			cache.time_to_empty = -ENODATA;
    			cache.time_to_empty_avg = -ENODATA;
    			cache.time_to_full = -ENODATA;
    			cache.charge_full = -ENODATA;
    			cache.health = -ENODATA;
    			cache.capacity=50;
    			pr_err("zxz-----bq27x00_update--set default to 50--\n");
    		} else {
    			cache.capacity = bq27x00_battery_read_rsoc(di);
    			if (is_bq27742)
    				cache.time_to_empty =
    					bq27x00_battery_read_time(di,
    							BQ27x00_REG_TTE);
    			else if (!is_bq27425) {
    				cache.energy = bq27x00_battery_read_energy(di);
    				cache.time_to_empty =
    					bq27x00_battery_read_time(di,
    							BQ27x00_REG_TTE);
    				cache.time_to_empty_avg =
    					bq27x00_battery_read_time(di,
    							BQ27x00_REG_TTECP);
    				cache.time_to_full =
    					bq27x00_battery_read_time(di,
    							BQ27x00_REG_TTF);
    			}
    			cache.charge_full = bq27x00_battery_read_lmd(di);
    			cache.health = bq27x00_battery_read_health(di);
    			cache.remaining_life = bq27x00_battery_read_remaining_life(di);//add the prop soh by zhaochuang.shao 20200929
    		}
    		cache.temperature = bq27x00_battery_read_temperature(di);
    		if (!is_bq27425)
    			cache.cycle_count = bq27x00_battery_read_cyct(di);
    		if (is_bq27742)
    			cache.power_avg =
    				bq27x00_battery_read_pwr_avg(di,
    						BQ27742_POWER_AVG);
    		else
    			cache.power_avg =
    				bq27x00_battery_read_pwr_avg(di,
    						BQ27x00_POWER_AVG);
    
    		/* We only have to read charge design full once */
    		if (di->charge_design_full <= 0)
    			di->charge_design_full = bq27x00_battery_read_ilmd(di);
    
    		/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    		di->is_present = true;
    		/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	}
    	else
    		{
    		cache.capacity=50;
    		pr_err("zxz-----bq27x00_update--read error !!!-cache.flags=%x-setdefault=50--\n",cache.flags);
    	}
    
    /*Bug7815737, Begin , flash not work after change battery from low (less than 10 percent) to high */
    /*the value 0x19 is the register'0x48bf' of 10 percent, if 0x18=9 percent the flash will not work,'qcom,flash-disable-soc' is the flash disable soc in dtsi  */
    #ifdef CONFIG_T2M_PRODUCT_D01
    		if (g_qgchip != NULL)
    			{
    				qg_read_monotonic_soc(g_qgchip,&read_msoc);
    				pr_err("zxz--bq27x00_update--read_msoc=%x--di->cache.capacity=%d--cache.capacity=%d--\n",read_msoc,di->cache.capacity,cache.capacity);
    
    				if(((read_msoc < 0x19 )||(cache.capacity < 10))&&(di->cache.capacity!=cache.capacity)){
    					pr_err("---bq27x00_update---cache.capacity=%d--qg_write_monotonic_soc-\n",cache.capacity);
    					qg_write_monotonic_soc_from_bq27x00(g_qgchip,cache.capacity);
    
    				}
    		}
    #endif
    /*Bug7815737, End , flash not work after change battery from low (less than 10 percent) to high */
    
    
    
    	if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
    		di->cache = cache;
    		power_supply_changed(di->bat);
    	}
    	pr_info("bq27x00_update-cache.capacity=%d,temp_k= %d,voltage = %d,current = %d,remaining_life = %d\n",di->cache.capacity,
    		di->cache.temperature,bq27x00_read(di, BQ27x00_REG_VOLT, false),bq27x00_read(di, BQ27x00_REG_AI, false),di->cache.remaining_life);
    
    	di->last_update = jiffies;
    }
    
    static void bq27x00_battery_poll(struct work_struct *work)
    {
    	struct bq27x00_device_info *di =
    		container_of(work, struct bq27x00_device_info, work.work);
    
    	bq27x00_update(di);
    	#if 0
    	if (poll_interval > 0) {
    		/* The timer does not have to be accurate. */
    		//set_timer_slack(&di->work.timer, poll_interval * HZ / 4);
    		schedule_delayed_work(&di->work, poll_interval * HZ);
    	}
    	#endif
    	
    }
    
    /*
     * Return the battery average current in µA
     * Note that current can be negative signed as well
     * Or 0 if something fails.
     */
    static int bq27x00_battery_current(struct bq27x00_device_info *di,
    	union power_supply_propval *val)
    {
    	int curr;
    	int flags;
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	static int last_curr = 0;
    
    	if(di->doing_auth){
    		val->intval = last_curr;
    		return 0;
    	}
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	curr = bq27x00_read(di, BQ27x00_REG_AI, false);
    	if (curr < 0) {
    		dev_err(di->dev, "error reading current\n");
    		return curr;
    	}
    
    	if (bq27xxx_is_chip_version_higher(di)) {
    		/* bq27500 returns signed value */
    		val->intval = (int)((s16)curr) * 1000;
    	} else {
    		flags = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
    		if (flags & BQ27000_FLAG_CHGS) {
    			dev_dbg(di->dev, "negative current!\n");
    			curr = -curr;
    		}
    
    		val->intval = curr * 3570 / BQ27000_RS;
    	}
    	//pr_debug("zxz--bq27x00_battery_current,  curr=%d--\n",val->intval);
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	last_curr = val->intval;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	return 0;
    }
    
    
    
    #if 0
    static int bq27x00_battery_status(struct bq27x00_device_info *di,
    	union power_supply_propval *val)
    {
    	int status;
    
    	if (bq27xxx_is_chip_version_higher(di)) {
    		if (di->cache.flags & BQ27500_FLAG_FC)
    			status = POWER_SUPPLY_STATUS_FULL;
    		else if (di->cache.flags & BQ27500_FLAG_DSC)
    			status = POWER_SUPPLY_STATUS_DISCHARGING;
    		else
    			status = POWER_SUPPLY_STATUS_CHARGING;
    	} else {
    		if (di->cache.flags & BQ27000_FLAG_FC)
    			status = POWER_SUPPLY_STATUS_FULL;
    		else if (di->cache.flags & BQ27000_FLAG_CHGS)
    			status = POWER_SUPPLY_STATUS_CHARGING;
    		else if (power_supply_am_i_supplied(di->bat))
    			status = POWER_SUPPLY_STATUS_NOT_CHARGING;
    		else
    			status = POWER_SUPPLY_STATUS_DISCHARGING;
    	}
    	dev_info(di->dev, "bq27x00_battery_status st %d\n", status);
    	val->intval = status;
    
    	return 0;
    }
    #endif
    
    static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
    	union power_supply_propval *val)
    {
    	int level;
    
    	if (bq27xxx_is_chip_version_higher(di)) {
    		if (di->cache.flags & BQ27500_FLAG_FC)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
    		else if (di->cache.flags & BQ27500_FLAG_SOC1)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
    		else if (di->cache.flags & BQ27500_FLAG_SOCF)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
    		else
    			level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
    	} else {
    		if (di->cache.flags & BQ27000_FLAG_FC)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
    		else if (di->cache.flags & BQ27000_FLAG_EDV1)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
    		else if (di->cache.flags & BQ27000_FLAG_EDVF)
    			level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
    		else
    			level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
    	}
    
    	val->intval = level;
    	//pr_debug("zxz--bq27x00_battery_capacity_level,  cap_lev=%d--\n",val->intval);
    
    	return 0;
    }
    
    /*
     * Return the battery Voltage in millivolts
     * Or < 0 if something fails.
     */
    static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
    	union power_supply_propval *val)
    {
    	int volt;
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	static int last_volt = 0;
    
    	if(di->doing_auth){
    		val->intval = last_volt;
    		return 0;
    	}
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
    	if (volt < 0) {
    		dev_err(di->dev, "error reading voltage\n");
    		pr_err("zxz--bq27x00_battery_voltage, read voltage error set default voltage to 3.8v--\n");
    		val->intval=3800000;
    		return volt;
    	}
    
    	val->intval = volt * 1000;
    	//pr_debug("zxz--bq27x00_battery_voltage,  vol=%d--\n",val->intval);
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	last_volt = val->intval;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	return 0;
    }
    
    static int bq27x00_simple_value(int value,
    	union power_supply_propval *val)
    {
    	if (value < 0)
    		return value;
    
    	val->intval = value;
    
    	return 0;
    }
    #if 0
    #define to_bq27x00_device_info(x) container_of((x), \
    				struct bq27x00_device_info, bat);
    #endif
    
    static int bq27x00_battery_get_property(struct power_supply *psy,
    					enum power_supply_property psp,
    					union power_supply_propval *val)
    {
    	int ret = 0;
    	//struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    	//pr_err("zxz---bq27x00_battery_get_property--psp=%d-11-\n",psp);
    	//union power_supply_propval smb5_psy_status = {0, };
    
    	mutex_lock(&di->lock);
    	if (time_is_before_jiffies(di->last_update + 5 * HZ)) {
    		//cancel_delayed_work_sync(&di->work);
    		bq27x00_battery_poll(&di->work.work);
    	}
    	mutex_unlock(&di->lock);
    
    	//if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
    		//return -ENODEV;
    	
    	//pr_err("zxz---bq27x00_battery_get_property--psp=%d-22-\n",psp);
    	switch (psp) {
    	#if 0
    	case POWER_SUPPLY_PROP_STATUS:
    		ret = bq27x00_battery_status(di, val);
    		break;
    	#endif
    	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
    		ret = bq27x00_battery_voltage(di, val);
    		break;
    	case POWER_SUPPLY_PROP_PRESENT:
    		val->intval = di->cache.flags < 0 ? 0 : 1;
    		break;
    	case POWER_SUPPLY_PROP_CURRENT_NOW:
    		ret = bq27x00_battery_current(di, val);
    		break;
    	case POWER_SUPPLY_PROP_CAPACITY:
    
    		#if 0
    		if(NULL==di->smb5_psy)
    			di->smb5_psy=power_supply_get_by_name("battery");
    		if(NULL!=di->smb5_psy){
    		power_supply_get_property(di->smb5_psy, POWER_SUPPLY_PROP_STATUS, &smb5_psy_status);
    		pr_err("bq27x00_battery_get_property ,smb5_psy_status=%d---\n",smb5_psy_status.intval);
    		if(POWER_SUPPLY_STATUS_FULL==smb5_psy_status.intval){
    			di->cache.capacity=100;
    			pr_err("bq27x00_battery_get_property ,smb5_psy_status=POWER_SUPPLY_STATUS_FULL, set capacity to 100---\n");
    			}
    		}
    		#endif
    		ret = bq27x00_simple_value(di->cache.capacity, val);
    		break;
    	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
    		ret = bq27x00_battery_capacity_level(di, val);
    		break;
    	case POWER_SUPPLY_PROP_TEMP:
    		ret = bq27x00_simple_value(di->cache.temperature, val);
    		if (ret == 0)
    			val->intval -= 2731;
    		if(val->intval >= 700){//added by zhaochuang.shao for debug the temp error 1655 degreen sometime 20210302,PR:10125492
    			pr_err("%s:%d: temp = %d,voltage = %d,current(mA) = %d,temp_i2c = %d\n",__FUNCTION__,__LINE__,
    				val->intval,bq27x00_read(di, BQ27x00_REG_VOLT, false),bq27x00_read(di, BQ27x00_REG_AI, false),
    				bq27x00_read(di, BQ27x00_REG_TEMP, false));
    		}
    		break;
    	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
    		ret = bq27x00_simple_value(di->cache.time_to_empty, val);
    		break;
    	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
    		ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val);
    		break;
    	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
    		ret = bq27x00_simple_value(di->cache.time_to_full, val);
    		break;
    	case POWER_SUPPLY_PROP_TECHNOLOGY:
    		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
    		break;
    	case POWER_SUPPLY_PROP_CHARGE_NOW:
    		ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val);
    		break;
    	case POWER_SUPPLY_PROP_CHARGE_FULL:
    		ret = bq27x00_simple_value(di->cache.charge_full, val);
    		break;
    	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
    		ret = bq27x00_simple_value(di->charge_design_full, val);
    		break;
    	case POWER_SUPPLY_PROP_CYCLE_COUNT:
    		ret = bq27x00_simple_value(di->cache.cycle_count, val);
    		break;
    	case POWER_SUPPLY_PROP_ENERGY_NOW:
    		ret = bq27x00_simple_value(di->cache.energy, val);
    		break;
    	case POWER_SUPPLY_PROP_POWER_AVG:
    		ret = bq27x00_simple_value(di->cache.power_avg, val);
    		break;
    	case POWER_SUPPLY_PROP_HEALTH:
    		ret = bq27x00_simple_value(di->cache.health, val);
    		break;
    	case POWER_SUPPLY_PROP_SOH://add the prop soh by zhaochuang.shao 20200929
    		ret = bq27x00_simple_value(di->cache.remaining_life, val);
    		break;
    	default:
    		return -EINVAL;
    	}
    
    	return ret;
    }
    
    static void bq27x00_external_power_changed(struct power_supply *psy)
    {
    	//struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
    	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);
    
    	cancel_delayed_work_sync(&di->work);
    	schedule_delayed_work(&di->work, 0);
    }
    
    static const struct power_supply_desc bq27x00_power_supply_desc = {
    	.name = "bq27x00-battery",
    	.type = POWER_SUPPLY_TYPE_BATTERY,
    	.properties = bq27x00_battery_props,
    	.num_properties = ARRAY_SIZE(bq27x00_battery_props),
    	.get_property = bq27x00_battery_get_property,
    	.external_power_changed = bq27x00_external_power_changed,
    };
    
    
    static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
    {
    	//int ret;
    
    	struct power_supply_config psy_cfg = { .drv_data = di, };
    
    pr_err("shao:%s:%d\n",__func__,__LINE__);
    #if 0
    	di->bat.type = POWER_SUPPLY_TYPE_BMS;
    	if (di->chip == BQ27425) {
    		di->bat.properties = bq27425_battery_props;
    		di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props);
    	} else if (di->chip == BQ27742) {
    		di->bat.properties = bq27742_battery_props;
    		di->bat.num_properties = ARRAY_SIZE(bq27742_battery_props);
    	} else {
    		di->bat.properties = bq27x00_battery_props;
    		di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
    	}
    	di->bat.get_property = bq27x00_battery_get_property;
    	di->bat.external_power_changed = bq27x00_external_power_changed;
    #endif
    	INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll);
    	mutex_init(&di->lock);
    
    #if 0
    	ret = power_supply_register(di->dev, &di->bat);
    	if (ret) {
    		dev_err(di->dev, "failed to register battery: %d\n", ret);
    		return ret;
    	}
    #endif
    
    	di->bat = devm_power_supply_register(di->dev,
    						 &bq27x00_power_supply_desc,
    						 &psy_cfg);
    
    
    	dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
    
    	bq27x00_update(di);
    
    	return 0;
    }
    
    static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
    {
    	/*
    	 * power_supply_unregister call bq27x00_battery_get_property which
    	 * call bq27x00_battery_poll.
    	 * Make sure that bq27x00_battery_poll will not call
    	 * schedule_delayed_work again after unregister (which cause OOPS).
    	 */
    	poll_interval = 0;
    
    	cancel_delayed_work_sync(&di->work);
    
    	power_supply_unregister(di->bat);
    
    	mutex_destroy(&di->lock);
    }
    
    
    /* i2c specific code */
    #ifdef CONFIG_BATTERY_BQ27X00_I2C
    
    /* If the system has several batteries we need a different name for each
     * of them...
     */
    static DEFINE_IDR(battery_id);
    static DEFINE_MUTEX(battery_mutex);
    
    static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single)
    {
    	struct i2c_client *client = to_i2c_client(di->dev);
    	struct i2c_msg msg[2];
    	unsigned char data[2];
    	int ret;
    
    	if (!client->adapter)
    		return -ENODEV;
    
    	msg[0].addr = client->addr;
    	msg[0].flags = 0;
    	msg[0].buf = &reg;
    	msg[0].len = sizeof(reg);
    	msg[1].addr = client->addr;
    	msg[1].flags = I2C_M_RD;
    	msg[1].buf = data;
    	if (single)
    		msg[1].len = 1;
    	else
    		msg[1].len = 2;
    
    	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    	if (ret < 0)
    		return ret;
    
    	if (!single)
    		ret = get_unaligned_le16(data);
    	else
    		ret = data[0];
    
    	return ret;
    }
    
    static int bq27x00_battery_probe(struct i2c_client *client,
    				 const struct i2c_device_id *id)
    {
    	char *name;
    	struct bq27x00_device_info *di;
    	int num;
    	int retval = 0;
    	int retry_times = 0;
    	pr_err("zxz----bq27000_battery_probe--I2C----11-\n");
    
    	/* Get new ID for the new battery device */
    	mutex_lock(&battery_mutex);
    	num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
    	mutex_unlock(&battery_mutex);
    	if (num < 0)
    		return num;
    	//pr_err("zxz----bq27000_battery_probe--I2C-22-\n");
    
    	name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
    	if (!name) {
    		dev_err(&client->dev, "failed to allocate device name\n");
    		retval = -ENOMEM;
    		goto batt_failed_1;
    	}
    	//pr_err("zxz----bq27000_battery_probe--I2C-33-\n");
    
    	di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
    	if (!di) {
    		dev_err(&client->dev, "failed to allocate device info data\n");
    		retval = -ENOMEM;
    		goto batt_failed_2;
    	}
    	//pr_err("zxz----bq27000_battery_probe--I2C-44-\n");
    
    	di->id = num;
    	di->dev = &client->dev;
    	di->chip = id->driver_data;
    	//di->bat.name = name;
    	di->bus.read = &bq27x00_read_i2c;
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	di->bus.write = &bq27xxx_battery_i2c_write;
    	di->doing_auth = false;
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	//pr_err("zxz----bq27000_battery_probe--I2C-55--di->chip=%d---\n",di->chip);
    
    	for (retry_times = 0; retry_times < 3; retry_times++) {
    		retval = bq27x00_battery_read_health(di);
    		udelay(100);
    		if (retval >= 0)
    			break;
    	}
    	if (retry_times >= 3) {
    		dev_err(&client->dev, "device not found\n");
    		retval = -ENODEV;
    		goto batt_failed_2;
    	}
    	//pr_err("zxz----bq27000_battery_probe--I2C-66-\n");
    
    	retval = bq27x00_powersupply_init(di);
    	if (retval)
    		goto batt_failed_2;
    	//pr_err("zxz----bq27000_battery_probe--I2C-77-\n");
    
    	i2c_set_clientdata(client, di);
    	pr_err("zxz----bq27000_battery_probe--I2C-88-\n");
    
    	/* [BEGIN] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    	retval = bq27541_create_attrs(&(di->bat->dev));
    	if (retval) {
    		dev_err(di->dev, "fail to create main sysfs: %d\n", retval);
    		return retval;
    	}
    	/* [END] add by jianfeng.ou, for ALM8402940. Battery Authentication. 2020-01-03 */
    
    	return 0;
    
    batt_failed_2:
    	kfree(name);
    	
    	pr_err("zxz----bq27000_battery_probe--I2C-99-\n");
    batt_failed_1:
    	
    	pr_err("zxz----bq27000_battery_probe--I2C-AA-\n");
    	mutex_lock(&battery_mutex);
    	idr_remove(&battery_id, num);
    	mutex_unlock(&battery_mutex);
    
    	return retval;
    }
    
    static int bq27x00_battery_remove(struct i2c_client *client)
    {
    	struct bq27x00_device_info *di = i2c_get_clientdata(client);
    
    	bq27x00_powersupply_unregister(di);
    
    	//kfree(di->bat.name);
    
    	mutex_lock(&battery_mutex);
    	idr_remove(&battery_id, di->id);
    	mutex_unlock(&battery_mutex);
    
    	return 0;
    }
    
    static const struct i2c_device_id bq27x00_id[] = {
    	{ "bq27200", BQ27000 },	/* bq27200 is same as bq27000, but with i2c */
    	{ "bq27500", BQ27500 },
    	{ "bq27425", BQ27425 },
    	{ "bq27742", BQ27742 },
    	{ "bq27541", BQ27500 },
    	{},
    };
    MODULE_DEVICE_TABLE(i2c, bq27x00_id);
    static struct of_device_id bq27541_match_table[] = {
            { .compatible = "bq,bq27541", },
            { },
    };
    MODULE_DEVICE_TABLE(of, bq27541_match_table);
    
    static struct i2c_driver bq27x00_battery_driver = {
    	.driver = {
    		.name = "bq27x00-battery",
    		.owner = THIS_MODULE,			
    		.of_match_table = of_match_ptr(bq27541_match_table),
    	},
    	.probe = bq27x00_battery_probe,
    	.remove = bq27x00_battery_remove,
    	.id_table = bq27x00_id,
    };
    
    static inline int bq27x00_battery_i2c_init(void)
    {
    
    	int ret = i2c_add_driver(&bq27x00_battery_driver);
    	
    	pr_err("zxz----bq27x00_battery_i2c_init----%s:%d,ret == %d\n",__func__,__LINE__,ret);
    	if (ret)
    		printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n");
    
    	return ret;
    }
    
    static inline void bq27x00_battery_i2c_exit(void)
    {
    	i2c_del_driver(&bq27x00_battery_driver);
    }
    
    #else
    
    static inline int bq27x00_battery_i2c_init(void) { greturn 0; }
    static inline void bq27x00_battery_i2c_exit(void) {};
    
    #endif
    
    /* platform specific code */
    #ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
    
    static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg,
    			bool single)
    {
    	struct device *dev = di->dev;
    	struct bq27000_platform_data *pdata = dev->platform_data;
    	unsigned int timeout = 3;
    	int upper, lower;
    	int temp;
    
    	if (!single) {
    		/* Make sure the value has not changed in between reading the
    		 * lower and the upper part */
    		upper = pdata->read(dev, reg + 1);
    		do {
    			temp = upper;
    			if (upper < 0)
    				return upper;
    
    			lower = pdata->read(dev, reg);
    			if (lower < 0)
    				return lower;
    
    			upper = pdata->read(dev, reg + 1);
    		} while (temp != upper && --timeout);
    
    		if (timeout == 0)
    			return -EIO;
    
    		return (upper << 8) | lower;
    	}
    
    	return pdata->read(dev, reg);
    }
    
    static int bq27000_battery_probe(struct platform_device *pdev)
    {
    	struct bq27x00_device_info *di;
    	struct bq27000_platform_data *pdata = pdev->dev.platform_data;
    	//pr_err("zxz----bq27000_battery_probe--platform--\n");
    	if (!pdata) {
    		dev_err(&pdev->dev, "no platform_data supplied\n");
    		return -EINVAL;
    	}
    
    	if (!pdata->read) {
    		dev_err(&pdev->dev, "no hdq read callback supplied\n");
    		return -EINVAL;
    	}
    
    	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
    	if (!di) {
    		dev_err(&pdev->dev, "failed to allocate device info data\n");
    		return -ENOMEM;
    	}
    
    	platform_set_drvdata(pdev, di);
    
    	di->dev = &pdev->dev;
    	di->chip = BQ27000;
    
    	//di->bat.name = pdata->name ?: dev_name(&pdev->dev);
    	di->bus.read = &bq27000_read_platform;
    
    	return bq27x00_powersupply_init(di);
    }
    
    static int bq27000_battery_remove(struct platform_device *pdev)
    {
    	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
    
    	bq27x00_powersupply_unregister(di);
    
    	return 0;
    }
    
    static struct platform_driver bq27000_battery_driver = {
    	.probe	= bq27000_battery_probe,
    	.remove = bq27000_battery_remove,
    	.driver = {
    		.name = "bq27000-battery",
    		.owner = THIS_MODULE,
    	},
    };
    
    static inline int bq27x00_battery_platform_init(void)
    {
    	int ret = platform_driver_register(&bq27000_battery_driver);
    	
    	//pr_err("zxz----bq27x00_battery_platform_init----\n");
    	if (ret)
    		printk(KERN_ERR "Unable to register BQ27000 platform driver\n");
    
    	return ret;
    }
    
    static inline void bq27x00_battery_platform_exit(void)
    {
    	platform_driver_unregister(&bq27000_battery_driver);
    }
    
    #else
    
    static inline int bq27x00_battery_platform_init(void) { return 0; }
    static inline void bq27x00_battery_platform_exit(void) {};
    
    #endif
    
    /*
     * Module stuff
     */
    
    static int __init bq27x00_battery_init(void)
    {
    	int ret;
    	//pr_err("zxz----bq27x00_battery_init--11--\n");
    
    	ret = bq27x00_battery_i2c_init();
    	if (ret)
    		return ret;
    	pr_err("zxz----bq27x00_battery_init--22--\n");
    
    	ret = bq27x00_battery_platform_init();
    	
    	pr_err("zxz----bq27x00_battery_init--33-ret=%d-\n",ret);
    	if (ret)
    		bq27x00_battery_i2c_exit();
    	pr_err("zxz----bq27x00_battery_init--44--\n");
    
    	return ret;
    }
    module_init(bq27x00_battery_init);
    
    static void __exit bq27x00_battery_exit(void)
    {
    	bq27x00_battery_platform_exit();
    	bq27x00_battery_i2c_exit();
    }
    module_exit(bq27x00_battery_exit);
    
    MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
    MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
    MODULE_LICENSE("GPL");
    
    bq27x00_battery.h

    static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
    {
    int temp,ilmd = 0;
    int i,read_count;
    static int last_temp = 0;
    static int temp_hot_count = 0;

    //printk("capacity = %d\n",bq27x00_read(di, BQ27500_REG_DCAP, false));

    //printk("temp = %d,read_temp = %d,read_count = %d\n",temp,bq27x00_read(di, BQ27x00_REG_TEMP, false));

    temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    if (temp < 0) {
    dev_err(di->dev, "error reading temperature\n");
    return temp;
    }

    if (!bq27xxx_is_chip_version_higher(di))
    temp = 5 * temp / 2;

    //[BEGIN]:added by zhaochuang.shao for the temp error 160 degreen sometime 20210226,PR:10204940
    if(temp >= BATTERY_CRITICAL_TEMP_HOT ){
    for(i = 0;i < 2;i++){
    pr_err("%s:temp = %d,ilmd = %d,i = %d\n",__func__,temp,ilmd,i);

    for(read_count = 0;read_count < 5;read_count++)
    printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);

    printk("%s:capacity = %d\n",__func__,bq27x00_read(di, BQ27500_REG_DCAP, false));

    for(read_count = 0;read_count < 5;read_count++)
    printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);

    mdelay(READ_TEMP_DELAY);

    temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    if (temp < 0) {
    dev_err(di->dev, "error reading temperature\n");
    return temp;
    }

    if (!bq27xxx_is_chip_version_higher(di))
    temp = 5 * temp / 2;
    ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);

    //if(temp < BATTERY_CRITICAL_TEMP_HOT)
    //break;
    }
    }

    if(temp >= BATTERY_CRITICAL_TEMP_HOT){
    pr_err("%s:last_temp_count = %d,temp = %d,last_temp = %d\n",__func__,temp_hot_count,temp,last_temp);
    if(++temp_hot_count <= 3) //just recheck for 3 times,if it is still hot,we will report
    temp = last_temp;
    }
    else{
    temp_hot_count = 0;
    }

    last_temp = temp;
    //[END]:by zhaochuang.shao 20210226

    return temp;
    }

    thanks

  • hi:TI

    our error log:4503.temp_hot_no_delay_0305.txt

    [15396.247512] bq27x00_update:1279:update start

    [15396.259454] bq27x00_battery_read_temperature:temp = 19286,ilmd = 0,i = 0
    [15396.260592] bq27x00_battery_read_temperature:temp = 2928,read_count = 0
    [15396.261583] bq27x00_battery_read_temperature:temp = 2928,read_count = 1
    [15396.262553] bq27x00_battery_read_temperature:temp = 2928,read_count = 2

    our driver code:2728.bq27x00_battery.h

    static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
    {
    int temp,ilmd = 0;
    int i,read_count;
    static int last_temp = 0;
    static int temp_hot_count = 0;

    //printk("capacity = %d\n",bq27x00_read(di, BQ27500_REG_DCAP, false));

    //printk("temp = %d,read_temp = %d,read_count = %d\n",temp,bq27x00_read(di, BQ27x00_REG_TEMP, false));

    temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    if (temp < 0) {
    dev_err(di->dev, "error reading temperature\n");
    return temp;
    }

    if (!bq27xxx_is_chip_version_higher(di))
    temp = 5 * temp / 2;

    //[BEGIN]:added by zhaochuang.shao for the temp error 160 degreen sometime 20210226,PR:10204940
    if(temp >= BATTERY_CRITICAL_TEMP_HOT ){
    for(i = 0;i < 2;i++){
    pr_err("%s:temp = %d,ilmd = %d,i = %d\n",__func__,temp,ilmd,i);

    for(read_count = 0;read_count < 5;read_count++)
    printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);

    printk("%s:capacity = %d\n",__func__,bq27x00_read(di, BQ27500_REG_DCAP, false));

    for(read_count = 0;read_count < 5;read_count++)
    printk("%s:temp = %d,read_count = %d\n",__func__,bq27x00_read(di, BQ27x00_REG_TEMP, false),read_count);

    mdelay(READ_TEMP_DELAY);

    temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
    if (temp < 0) {
    dev_err(di->dev, "error reading temperature\n");
    return temp;
    }

    if (!bq27xxx_is_chip_version_higher(di))
    temp = 5 * temp / 2;
    ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);

    //if(temp < BATTERY_CRITICAL_TEMP_HOT)
    //break;
    }
    }

    if(temp >= BATTERY_CRITICAL_TEMP_HOT){
    pr_err("%s:last_temp_count = %d,temp = %d,last_temp = %d\n",__func__,temp_hot_count,temp,last_temp);
    if(++temp_hot_count <= 3) //just recheck for 3 times,if it is still hot,we will report
    temp = last_temp;
    }
    else{
    temp_hot_count = 0;
    }

    last_temp = temp;
    //[END]:by zhaochuang.shao 20210226

    return temp;
    }

    thanks

  • Hi Zhaochuang,

    You may want to do some error checking on the package in the firmware.

    Can you attach any scope captures showing this issue.

    Best regards,

  • hi:TI

    we can not change the firmware of the bq27541,we just read the temp data by the i2c bus in android!

    base on the error log ,the first read function is return ok,but the data is error 19286,but the othor temperature data is ok

    Did othor vendors read the error temperature data 19286?

    In the firmware, may be the temperature data is error to 19286 random?

    thanks

  • Hi,

    Can you replicate this and show us the waveforms when trying to read the temperature?  It would be good to verirfiy this with a logic analyzer.

    Best regards,

  • Because the error temp is random,we can not capture the error waveform!

    may be the temperature register error in theory?what about other vendors?

  • How many units are you seeing this on? Can you confirm the issue is with the fuel gauge and only one specific register? Best to upload scope capture. 

    Thanks