Hi team,
customer use BQ27621-G1, have below questions
1. In the initialize, customer change to unseal mode, and check the register status,confirm that the device enter to unseal mode. then, write register, change to seal mode, check the status register foun it still unseal mode. quesiton is how to enter seal mode correctly?
2. firstly, customer read 0x40 register data, it is 0x8a. then, they change 32bit of 0x40, read reg 0x60 again, found the data of reg 0x60 still is 0x8a. they can't unpdate checksum registers.
I attached customer code file, please help check what cause this issue. thanks
/* * * Battery driver for BQ27621-G1 */ #include <ti/devices/cc13x2_cc26x2/driverlib/cpu.h> #include "Alipower.h" #include "board_uart.h" #include "Bq.h" #include "onboard.h" #define BQ27621_ADDR 0x55 #define BQ27621_ADDR_FLAGS 0x55 #define BQ27621_TYPE_ID 0x0621 #define REG_CTRL 0x00 #define REG_TEMPERATURE 0x02 #define REG_VOLTAGE 0x04 #define REG_FLAGS 0x06 #define REG_NOMINAL_CAPACITY 0x08 #define REG_FULL_AVAILABLE_CAPACITY 0x0a #define REG_REMAINING_CAPACITY 0x0c #define REG_FULL_CHARGE_CAPACITY 0x0e #define REG_EFFECTIVE_CURRENT 0x10 #define REG_AVERAGE_POWER 0x18 #define REG_STATE_OF_CHARGE 0x1c #define REG_INTERNAL_TEMPERATURE 0x1e #define REG_REMAINING_CAPACITY_UNFILTERED 0x28 #define REG_REMAINING_CAPACITY_FILTERED 0x2a #define REG_FULL_CHARGE_CAPACITY_UNFILTERED 0x28 #define REG_FULL_CHARGE_CAPACITY_FILTERED 0x2a #define REG_STATE_OF_CHARGE_UNFILTERED 0x30 #define REG_OP_CONFIG 0x3a #define REG_DESIGN_CAPACITY 0x3c #define REG_DATA_CLASS 0x3e #define REG_DATA_BLOCK 0x3f // #define REG_BLOCK_DATA_CHECKSUM 0x60 #define REG_BLOCK_DATA_CONTROL 0x61 #define REGISTERS_BLOCK_OFFSET 64 #define REGISTERS_BLOCK_OP_CONFIG 0x40 #define REGISTERS_BLOCK_OP_CONFIG_B 0x42 #define REGISTERS_BLOCK_DF_VERSION 0x43 /* State block */ #define STATE_BLOCK_OFFSET 82 #if 1 #define STATE_BLOCK_DESIGN_CAPACITY 0x43 #define STATE_BLOCK_DESIGN_ENERGY 0x45 #define STATE_BLOCK_TERMINATE_VOLTAGE 0x49 #define STATE_BLOCK_TAPER_RATE 0x54 #else #define STATE_BLOCK_DESIGN_CAPACITY 0x4A #define STATE_BLOCK_DESIGN_ENERGY 0x4C #define STATE_BLOCK_TERMINATE_VOLTAGE 0x50 #define STATE_BLOCK_TAPER_RATE 0x5B #endif /* BQ27621 Control subcommands */ #define CONTROL_CONTROL_STATUS 0x00 #define CONTROL_DEVICE_TYPE 0x01 #define CONTROL_FW_VERSION 0x02 #define CONTROL_PREV_MACWRITE 0x07 #define CONTROL_CHEM_ID 0x08 #define CONTROL_BAT_INSERT 0x0C #define CONTROL_BAT_REMOVE 0x0D #define CONTROL_TOGGLE_POWERMIN 0x10 #define CONTROL_SET_HIBERNATE 0x11 #define CONTROL_CLEAR_HIBERNATE 0x12 #define CONTROL_SET_CFGUPDATE 0x13 #define CONTROL_SHUTDOWN_ENABLE 0x1B #define CONTROL_SHUTDOWN 0x1C #define CONTROL_SEALED 0x20 #define CONTROL_TOGGLE_GPOUT 0x23 #define CONTROL_ALT_CHEM1 0x31 #define CONTROL_ALT_CHEM2 0x32 #define CONTROL_RESET 0x41 #define CONTROL_SOFT_RESET 0x42 #define CONTROL_EXIT_CFGUPDATE 0x43 #define CONTROL_EXIT_RESIM 0x44 #define CONTROL_UNSEAL 0x8000 /* BQ27621 Status bits */ #define STATUS_SHUTDOWNEN 0x8000 #define STATUS_WDRESET 0x4000 #define STATUS_SS 0x2000 #define STATUS_CALMODE 0x1000 #define STATUS_OCVCMDCOMP 0x0200 #define STATUS_OCVFAIL 0x0100 #define STATUS_INITCOMP 0x0080 #define STATUS_HIBERNATE 0x0040 #define STATUS_POWERMIN 0x0020 #define STATUS_SLEEP 0x0010 #define STATUS_LDMD 0x0008 #define STATUS_CHEMCHNG 0x0001 /* BQ27621 Flags bits */ #define FLAGS_OT 0x8000 #define FLAGS_UT 0x4000 #define FLAGS_FC 0x0200 #define FLAGS_CHG 0x0100 #define FLAGS_OCVTAKEN 0x0080 #define FLAGS_ITPOR 0x0020 #define FLAGS_CFGUPD 0x0010 #define FLAGS_BAT_DET 0x0008 #define FLAGS_SOC1 0x0004 #define FLAGS_SOCF 0x0002 #define FLAGS_DSG 0x0001 #define I2C_PORT_BATTERY 0x55 #define EC_ERROR_UNKNOWN 1 #define EC_SUCCESS 0 #define EC_ERROR_UNIMPLEMENTED 1 #define BQ27621_DM_DATA 0x40 #define BQ27621_DM_SZ 32 union ComTpye { uint16_t iRet; uint8_t NumArrary[2]; }; void Udelay(unsigned int per) { CPUdelay(per); } struct bq27621_dm_buf { uint8_t class; uint8_t block; uint8_t data[BQ27621_DM_SZ]; bool has_data, dirty; }; struct bq27621_dm_reg { uint8_t subclass_id; uint8_t offset; uint8_t bytes; uint16_t min, max; }; enum bq27621_dm_reg_id { BQ27621_DM_DESIGN_CAPACITY = 0, BQ27621_DM_DESIGN_ENERGY, BQ27621_DM_TERMINATE_VOLTAGE, }; /* * There are some parameters that need to be defined in the board file: * BQ27621_TOGGLE_POWER_MIN - Put it in minimum power mode * (may affect I2C timing) * BQ27621_DESIGN_CAPACITY - mAh 450 * BQ27621_DESIGN_ENERGY - Design Capacity x 3.7 * BQ27621_TERMINATE_VOLTAGE - mV 3000 * BQ27621_TAPER_CURRENT - mA 25 * BQ27621_CHEM_ID - 0x1202 (DEFAULT) 0x1210 (ALT_CHEM1) * 0x354 (ALT_CHEM2) * * For extra large or extra small batteries, this driver scales everything but * voltages. The recommended range is 150mAh - 6Ah * */ #define BQ27621_DESIGN_CAPACITY 450//450 #define BQ27621_DESIGN_ENERGY 1665//1665 //(450*3.7) #define BQ27621_TERMINATE_VOLTAGE 3300//3300 #define BQ27621_TAPER_CURRENT 90//500// 90 //25 #define BQ27621_CHEM_ID 0x1202 #define BQ27621_SCALE_FACTOR (BQ27621_DESIGN_CAPACITY < 150 ? 10.0 : \ (BQ27621_DESIGN_CAPACITY > 6000 ? 0.1 : 1)) #define BQ27621_UNSCALE(x) (BQ27621_SCALE_FACTOR == 10 ? (x) / 10 : \ (BQ27621_SCALE_FACTOR == 0.1 ? (x) * 10 : (x))) #define BQ27621_TAPER_RATE ((int)(BQ27621_DESIGN_CAPACITY/ \ (0.1 * BQ27621_TAPER_CURRENT))) #define BQ27621_SCALED_DESIGN_CAPACITY ((int)(BQ27621_DESIGN_CAPACITY * \ BQ27621_SCALE_FACTOR)) #define BQ27621_SCALED_DESIGN_ENERGY ((int)(BQ27621_DESIGN_CAPACITY * \ BQ27621_SCALE_FACTOR)) /* *Everything is LSB first. Parameters need to be converted. * * The values from the data sheet are already LSB-first. */ #define ENDIAN_SWAP_2B(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) #define DESIGN_CAPACITY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_CAPACITY) #define DESIGN_ENERGY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_ENERGY) #define TAPER_RATE ENDIAN_SWAP_2B(BQ27621_TAPER_RATE) #define TERMINATE_VOLTAGE ENDIAN_SWAP_2B(BQ27621_TERMINATE_VOLTAGE) static uint8_t bq27621_read(int offset, int *data) { uint8_t status=1; union ComTpye CommandData; uint8_t data1[2]={0}; status=Ali_I2c_read( (uint8_t*)(&offset) ,data1, 2, BQ27621_ADDR ); //(uint8_t*) #if 1 CommandData.NumArrary[0]=data1[0]; CommandData.NumArrary[1]=data1[1]; #else CommandData.NumArrary[0]=data1[1]; CommandData.NumArrary[1]=data1[0]; #endif *data=CommandData.iRet ; return status ; } static uint8_t bq27621_read8(int offset, int *data) { return Ali_I2c_read((uint8_t*)(&offset),(uint8_t*)data,1,BQ27621_ADDR); } static uint8_t bq27621_write(int offset, int data) { union ComTpye CommandData; CommandData.iRet=(uint16_t)(data); // Printf("CommandData.NumArrary[0]->[0x%x]\n",CommandData.NumArrary[0]); // Printf("CommandData.NumArrary[1]->[0x%x]\n",CommandData.NumArrary[1]); #if 1 uint8_t txBuffer[ ]={(uint8_t)offset,CommandData.NumArrary[0],CommandData.NumArrary[1]}; #else uint8_t txBuffer[ ]={(uint8_t)offset,CommandData.NumArrary[1],CommandData.NumArrary[0]}; #endif return Ali_I2c_write(txBuffer, 3, BQ27621_ADDR); } static uint8_t bq27621_write8(int offset, int data) { uint8_t txBuffer[2]={(uint8_t)offset,(uint8_t)data}; return Ali_I2c_write(txBuffer, 2, BQ27621_ADDR); } //added by lee void bq27621_delay_msek(uint32_t msek) { /*Here you can write your own delay routine*/ CPUdelay(12000 * msek); } static uint8_t bq27621_battery_cfgupdate_priv(bool active) { const uint8_t limit = 100; int cmd = active ? CONTROL_SET_CFGUPDATE : CONTROL_SOFT_RESET; int try = limit; int flags = 0; uint8_t ret; ret = bq27621_write(REG_CTRL, &cmd); if (ret == 1) return ret; do { bq27621_delay_msek(25); if(cmd==CONTROL_SOFT_RESET) ret = bq27621_write(REG_CTRL, &cmd); ret = bq27621_read(REG_FLAGS,&flags); if (ret ==1 ) return ret; } while (!!(flags & ((1 << 4))) != active && --try); return 0; } static uint8_t bq27621_battery_set_cfgupdate(void) { int ret = bq27621_battery_cfgupdate_priv(true); if (ret ==1 ) { Printf("bus error on set_cfgupdate: %d\n", ret); } return ret; } static int bq27621_battery_soft_reset(void) { int ret = bq27621_battery_cfgupdate_priv(false); if (ret ==1) { Printf("bus error on soft_reset: %d\n", ret); } return ret; } //added end static int bq27621_probe(void) { uint8_t rv; int battery_type_id,RecData; rv=bq27621_write(REG_CTRL, CONTROL_DEVICE_TYPE); rv |=bq27621_read(REG_CTRL, &battery_type_id); Printf(" battery type id is 0x%04x\n",battery_type_id); rv |= bq27621_write(REG_CTRL , CONTROL_CHEM_ID); // 0x08 CONTROL_CHEM_ID rv |= bq27621_read(REG_CTRL, &RecData); Printf("CONTROL CHEM ID[0x%04x]\n",RecData); if (rv) return rv; if (battery_type_id == BQ27621_TYPE_ID) { Printf("identify the BQ27621\n"); return EC_SUCCESS; } return EC_ERROR_UNKNOWN; } static int bq27621_unseal(void) { bq27621_write(REG_CTRL, CONTROL_UNSEAL); bq27621_write(REG_CTRL, CONTROL_UNSEAL); return 1; } static int bq27621_enter_config_update(void) { int tries, flags = 0, rv = EC_SUCCESS; /* Enter Config Update Mode (Can take up to a second) */ for (tries = 2000; tries > 0 && !(flags & FLAGS_CFGUPD) && (rv == EC_SUCCESS); tries--) { rv |= bq27621_write(REG_CTRL, CONTROL_SET_CFGUPDATE); //step 3 rv |= bq27621_read(REG_FLAGS, &flags); } Printf("tries[%d]\n",tries); if (tries == 0) { return 1; } else return 0; } static int bq27621_enter_block_mode(int block) { int rv; Printf("step 4 before\n"); //step 4 rv = bq27621_write8(REG_BLOCK_DATA_CONTROL, 0); //REG_BLOCK_DATA_CONTROL 0x61 Printf("step 4 after\n"); Printf("step 5 before\n"); //setp 5 rv |= bq27621_write8(REG_DATA_CLASS, block); // 0x52 Printf("step 5 after\n"); Printf("step 6 before\n"); //step 6 rv |= bq27621_write8(REG_DATA_BLOCK, 0); Printf("step 6 after\n"); CPUdelay(12000);//udelay(500); /* Shouldn't be needed, doesn't work without it. */ return rv; } static int verity_ramupdate_correctly(uint8_t newchecknum) { int rv; uint32_t chksum=0; rv = bq27621_write8(REG_DATA_CLASS, 0x52); // 0x52 if(rv==1) { Printf("write reg data class faile\n"); } rv = bq27621_write8(REG_DATA_BLOCK, 0); if(rv ==1) { Printf("write reg data block faile\n"); } rv = bq27621_read(REG_BLOCK_DATA_CHECKSUM,&chksum); if(rv ==1) { Printf("read reg block data checksum faile\n"); } if (newchecknum !=chksum) { Printf("newchecknum[0x%x] !=chksum[0x%x]\n",newchecknum,chksum); return 1; } return 0; } #if 0 static int bq27621_seal(void) { lulu: int rv = 0; int status = 0, param = 0, checksum = 0; rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal Already sealed\n"); return EC_SUCCESS; } #if 1 /* Enter Config Update Mode */ #if 0 rv = bq27621_enter_config_update(); #else rv = bq27621_battery_set_cfgupdate( ); #endif if (rv) { Printf("Enter Config Update Mode faile\n"); return rv; } /* Set up block RAM update */ rv = bq27621_enter_block_mode(REGISTERS_BLOCK_OFFSET); if (rv) { Printf("Set up block RAM update faile\n"); return rv; } rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); if (rv) { Printf("Read REG_BLOCK_DATA_CHECKSUM faile\n"); return rv; } checksum = 0xff - checksum; rv = bq27621_read8(REGISTERS_BLOCK_OP_CONFIG_B, ¶m); checksum -= param; /* 1B */ param |= 1<<5; /* Set DEF_SEAL */ rv = bq27621_write8(REGISTERS_BLOCK_OP_CONFIG_B, param); checksum += param; /* 1B */ checksum = 0xff - (0xff & checksum); rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); if (rv) { Printf("REG BLOCK DATA CHECKSUM FAILE.....\n"); return rv; } CPUdelay(12000*100); #endif /* Exit Update */ rv = bq27621_battery_soft_reset(); rv = bq27621_write(REG_CTRL, CONTROL_SEALED); rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal Already sealed\n"); return EC_SUCCESS; } else { Printf("bq27621 seal set up faile.........\n"); // goto lulu; } return rv; } #else static int bq27621_seal(void) { int rv = 0; int status = 0, param = 0, checksum = 0; rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ return EC_SUCCESS; /* Enter Config Update Mode */ rv = bq27621_enter_config_update(); // rv = bq27621_battery_set_cfgupdate(); if (rv) return rv; /* Set up block RAM update */ rv = bq27621_enter_block_mode(REGISTERS_BLOCK_OFFSET); if (rv) return rv; rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); if (rv) return rv; checksum = 0xff - checksum; rv = bq27621_read8(REGISTERS_BLOCK_OP_CONFIG_B, ¶m); checksum -= param; /* 1B */ param |= 1<<5; /* Set DEF_SEAL */ rv = bq27621_write8(REGISTERS_BLOCK_OP_CONFIG_B, param); checksum += param; /* 1B */ checksum = 0xff - (0xff & checksum); rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); if (rv) return rv; /* Exit Update */ rv = bq27621_battery_soft_reset(); return rv; } #endif #define CHECKSUM_2B(x) ((x & 0xff) + ((x>>8) & 0xff)) //閹跺﹨顕伴崙铏规畱16bit閻ㄥ嫭鏆熼幑顔藉閸掑棛娴夐崝锟? static uint8_t bq27621_read_block(int offset, uint8_t *data,uint8_t len); static uint8_t bq27621_battery_checksum_dm_block(struct bq27621_dm_buf *buf); static uint8_t bq27621_write_block(int offset, uint8_t *data,uint8_t len); uint8_t Checkdata[BQ27621_DM_SZ]={0}; uint8_t Checknum1; #if 1 int bq27621_init(void) { int rv; int status = 0, param = 0, checksum = 1; cool: // bq27621_write(REG_CTRL, CONTROL_RESET); //added by lee for debug rv = bq27621_probe(); if (rv) { Printf("return bq27621 probe\n"); } /* Unseal the device if necessary */ rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); //step 1 if (status & STATUS_SS) { Printf("will set unseal ...[0x%x]\n",status & STATUS_SS); rv |= bq27621_unseal(); } //added by lee rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv = bq27621_read(REG_CTRL, &status); if (!(status & STATUS_SS)) { Printf("set unseal modem success\n"); } else { Printf("status is [0x%x]\n",status & STATUS_SS); goto cool; } //added end /* Select the alternate chemistry if needed */ rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID); rv |= bq27621_read(REG_CTRL, ¶m); param = BQ27621_CHEM_ID; //added for test by lee if (param != BQ27621_CHEM_ID) { /* Change needed */ if (BQ27621_CHEM_ID == 0x1202) { /* Return to default */ rv |= bq27621_write(REG_CTRL, CONTROL_RESET); Printf("Return to default 0x1202\n"); } else { rv |= bq27621_enter_config_update(); if (BQ27621_CHEM_ID == 0x1210) { Printf("chem id is 0x1210\n"); rv |= bq27621_write(REG_CTRL,CONTROL_ALT_CHEM1); } if (BQ27621_CHEM_ID == 0x0354) { Printf("chem id is 0x0354\n"); rv |= bq27621_write(REG_CTRL,CONTROL_ALT_CHEM2); } /* * The datasheet recommends checking the status here. * * If the CHEMCHG is active, it wasn't successful. * * There's no recommendation for what to do if it isn't. */ rv |= bq27621_write(REG_CTRL, CONTROL_EXIT_CFGUPDATE); } } //step 2 // rv = bq27621_enter_config_update(); rv=bq27621_battery_set_cfgupdate(); if (rv) { Printf("return bq27621 enter config update faile\n"); } CPUdelay(120000); /* Set up block RAM update */ rv = bq27621_enter_block_mode(STATE_BLOCK_OFFSET); if (rv) { Printf("return bq27621 enter block mode faile\n"); } struct bq27621_dm_buf databuf={0}; struct bq27621_dm_buf databuf1={0}; bq27621_read_block(BQ27621_DM_DATA, &databuf.data[0], BQ27621_DM_SZ); bq27621_battery_checksum_dm_block(&databuf); lolo: //step 7 rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); //绗竴姝ュ厛璇诲嚭checksum Printf("read the org reg block data checksum is 0x%x\n",checksum); databuf.data[0]=1; databuf.data[1]=2; databuf.data[2]=3; databuf.data[3]=4; databuf.data[4]=5; databuf.data[5]=6; databuf.data[6]=7; bq27621_write_block(BQ27621_DM_DATA, &databuf.data[0],BQ27621_DM_SZ); bq27621_read_block(BQ27621_DM_DATA, &databuf1.data[0], BQ27621_DM_SZ); checksum=bq27621_battery_checksum_dm_block(&databuf1); databuf.data[0]=checksum; #if 0 checksum = 0xff - checksum; //step 8 rv = bq27621_read(STATE_BLOCK_DESIGN_CAPACITY, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_DESIGN_ENERGY, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_TERMINATE_VOLTAGE, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_TAPER_RATE, ¶m); checksum -= CHECKSUM_2B(param); rv = bq27621_write(STATE_BLOCK_DESIGN_CAPACITY, DESIGN_CAPACITY); checksum += CHECKSUM_2B(DESIGN_CAPACITY); //寮�濮嬭绠梟ew_Csum rv |= bq27621_write(STATE_BLOCK_DESIGN_ENERGY, DESIGN_ENERGY); checksum += CHECKSUM_2B(DESIGN_ENERGY); rv |= bq27621_write(STATE_BLOCK_TERMINATE_VOLTAGE, TERMINATE_VOLTAGE); checksum += CHECKSUM_2B(TERMINATE_VOLTAGE); rv |= bq27621_write(STATE_BLOCK_TAPER_RATE, TAPER_RATE); checksum += CHECKSUM_2B(TAPER_RATE); checksum = 0xff - (0xff & checksum); Printf("step 10 before\n"); Printf("checksum[0x%x]\n",checksum); // bq27621_enter_block_mode(STATE_BLOCK_OFFSET); #endif rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); // Printf("now read checksum from reg[0x%x]\n",checksum); if(checksum==0x8a) { Printf("updata faile"); } Printf("step 10 after\n"); /* Exit CONFIG UPDATE mode by sending SOFT_RESET subcommand, */ #if 0 bq27621_battery_soft_reset(); #else bq27621_write(REG_CTRL, CONTROL_RESET); #endif // bq27621_write(REG_CTRL, CONTROL_SEALED); CPUdelay(12000); bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal success\n"); // return EC_SUCCESS; } else { Printf("bq27621 seal set up faile.........\n"); } #if 0 lulu: // bq27621_seal(); // bq27621_battery_soft_reset(); // bq27621_write(REG_CTRL, CONTROL_SEALED); rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal success\n"); // return EC_SUCCESS; } else { Printf("bq27621 seal set up faile.........\n"); // goto lulu; } #endif int capacity=0; #if 0 battery_design_capacity(&capacity); if(capacity !=BQ27621_DESIGN_CAPACITY) { Printf("<<<<<capacity !=BQ27621_DESIGN_CAPACITY2>>>>>>>>>\n"); // bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); // SystemReset(); CPUdelay(12000*10); // goto cool; } else { Printf("<<<<<<<<<<<<BQ27621_DESIGN_CAPACITY[%d]2>>>>>>>>>>>>\n",capacity); } #endif rv |=battery_remaining_capacity(&capacity); Printf("capacity[%%%d]\n",capacity); return rv; } #else int bq27621_init(void) { int rv; int status = 0, param = 0, checksum = 0,capacity =0; cool: #if 1 //added by lee bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); CPUdelay(12000*100); //added end #endif Printf("==============================\n"); Printf("==============================\n"); Printf("==============================\n"); Printf("==============================\n"); rv = bq27621_probe(); if (rv) return rv; /* Unseal the device if necessary */ rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) { Printf("set unseal modem\n"); rv |= bq27621_unseal(); } //added by lee rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv = bq27621_read(REG_CTRL, &status); if (!(status & STATUS_SS)) { Printf("set unseal modem success\n"); } else { Printf("status is [0x%x]\n",status & STATUS_SS); goto cool; } //added end // if (rv) // return rv; /* Select the alternate chemistry if needed */ rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID); rv |= bq27621_read(REG_CTRL, ¶m); if (param != BQ27621_CHEM_ID) { /* Change needed */ if (BQ27621_CHEM_ID == 0x1202) { /* Return to default */ rv |= bq27621_write(REG_CTRL, CONTROL_RESET); } else { rv |= bq27621_enter_config_update(); if (BQ27621_CHEM_ID == 0x1210) rv |= bq27621_write(REG_CTRL, CONTROL_ALT_CHEM1); if (BQ27621_CHEM_ID == 0x0354) rv |= bq27621_write(REG_CTRL, CONTROL_ALT_CHEM2); /* * The datasheet recommends checking the status here. * * If the CHEMCHG is active, it wasn't successful. * * There's no recommendation for what to do if it isn't. */ rv |= bq27621_write(REG_CTRL, CONTROL_EXIT_CFGUPDATE); } } // if (rv) // return rv; #if 0 rv = bq27621_enter_config_update(); #else rv = bq27621_battery_set_cfgupdate( ); #endif // if (rv) // return rv; /* Set up block RAM update */ rv = bq27621_enter_block_mode(STATE_BLOCK_OFFSET); // if (rv) // return rv; Printf("REG_BLOCK_DATA_CHECKSUM before\n"); rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); // rv = bq27621_read(REG_BLOCK_DATA_CHECKSUM, &checksum); Printf("REG_BLOCK_DATA_CHECKSUM after\n"); // if (rv) // return rv; checksum = 0xff - checksum; rv = bq27621_read(STATE_BLOCK_DESIGN_CAPACITY, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_DESIGN_ENERGY, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_TERMINATE_VOLTAGE, ¶m); checksum -= CHECKSUM_2B(param); rv |= bq27621_read(STATE_BLOCK_TAPER_RATE, ¶m); checksum -= CHECKSUM_2B(param); // if (rv) // return rv; rv = bq27621_write(STATE_BLOCK_DESIGN_CAPACITY, DESIGN_CAPACITY); checksum += CHECKSUM_2B(DESIGN_CAPACITY); rv |= bq27621_write(STATE_BLOCK_DESIGN_ENERGY, DESIGN_ENERGY); checksum += CHECKSUM_2B(DESIGN_ENERGY); rv |= bq27621_write(STATE_BLOCK_TERMINATE_VOLTAGE, TERMINATE_VOLTAGE); checksum += CHECKSUM_2B(TERMINATE_VOLTAGE); rv |= bq27621_write(STATE_BLOCK_TAPER_RATE, TAPER_RATE); checksum += CHECKSUM_2B(TAPER_RATE); checksum = 0xff - (0xff & checksum); // if (rv) // return rv; rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); //Exit CONFIG UPDATE mode by sending SOFT_RESET subcommand, #if 0 rv |= bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); if (rv) return rv; #else lulu: rv |=bq27621_battery_soft_reset(); bq27621_write(REG_CTRL, CONTROL_SEALED); // if (rv) // return rv; #endif #if 1 bq27621_seal(); //#else bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal success\n"); // return EC_SUCCESS; } else { Printf("bq27621 seal faile[0x%x]\n",status & STATUS_SS); // goto lulu; } #endif battery_design_capacity(&capacity); if(capacity !=BQ27621_DESIGN_CAPACITY) { Printf("<<<<<capacity[%d] !=BQ27621_DESIGN_CAPACITY2>>>>>>>>>\n",capacity); // bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); // SystemReset(); CPUdelay(12000*10); goto cool; } else { Printf("<<<<<<<<<<<<BQ27621_DESIGN_CAPACITY[%d]2>>>>>>>>>>>>\n",capacity); } battery_remaining_capacity(&capacity); Printf("capacity[%%%d]\n",capacity); } #endif static int bq27621_battery_unseal(void) { int ret,status; ret =bq27621_write(REG_CTRL, CONTROL_UNSEAL); if (ret == 1) goto out; ret = bq27621_write(REG_CTRL, CONTROL_UNSEAL); if (ret == 1) goto out; bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); bq27621_read(REG_CTRL, &status); if (!(status & STATUS_SS)) { Printf("set unseal modem success\n"); } else { Printf("set unseal modem faile status is [0x%x]\n",status & STATUS_SS); goto out; } return 0; out: Printf("error on unseal: %d\n", ret); return ret; } static int bq27621_battery_seal(void) { int ret,status; ret = bq27621_write(REG_CTRL, CONTROL_SEALED); if (ret == 1) { Printf("bus error on seal: %d\n", ret); return ret; } ret = bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal Already sealed\n"); return 0; } else { Printf("bq27621 seal set up faile.........\n"); return 1; } return 0; } static uint8_t bq27621_read_block(int offset, uint8_t *data,uint8_t len) { return Ali_I2c_read((uint8_t*)(&offset),(uint8_t*)data,len,BQ27621_ADDR); } //err static uint8_t bq27621_write_block(int offset, uint8_t *data,uint8_t len) { uint8_t txBuffer[BQ27621_DM_SZ +1]={0}; txBuffer[0]=(uint8_t)offset; memcpy(&txBuffer[1],data,len); return Ali_I2c_write(txBuffer, len+1, BQ27621_ADDR); } static uint8_t bq27621_battery_checksum_dm_block(struct bq27621_dm_buf *buf) { uint16_t sum = 0; int i; Printf("checksum_dm_block:\n"); for (i = 0; i < BQ27621_DM_SZ; i++) { Printf("0x%02x ",buf->data[i]); sum += buf->data[i]; } Printf("\n"); sum &= 0xff; Printf("myself compute checksum dm block is [0x%x]\n",0xff - sum); return 0xff - sum; } static uint16_t *bq27621_dm_reg_ptr(struct bq27621_dm_buf *buf, struct bq27621_dm_reg *reg) { Printf("reg->offset[%d]\n",reg->offset); return (uint16_t *) (buf->data + reg->offset % BQ27621_DM_SZ); } static void bq27621_battery_update_dm_block(struct bq27621_dm_buf *buf,enum bq27621_dm_reg_id reg_id, uint32_t val) { static struct bq27621_dm_reg bq27621_dm_regs[] = { [BQ27621_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, DESIGN_CAPACITY }, [BQ27621_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, DESIGN_ENERGY }, [BQ27621_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 0, TERMINATE_VOLTAGE }, }; struct bq27621_dm_reg *reg = bq27621_dm_regs; uint16_t *prev = bq27621_dm_reg_ptr(buf, ®[reg_id]); //鑾峰彇鎸囧悜prev鐨勫湴鍧� if (prev == NULL) { Printf("buffer does not match dm spec\n"); return; } Printf("DESIGN_CAPACITY[0x%x]\n",DESIGN_CAPACITY); Printf("DESIGN_ENERGY[0x%x]\n",DESIGN_ENERGY); Printf("TERMINATE_VOLTAGE[0x%x]\n",TERMINATE_VOLTAGE); if (reg->bytes != 2) { Printf("dm spec has unsupported byte size\n"); return; } if (!buf->has_data) //鍦╞q27621_battery_read_dm_block()鍑芥暟涓疄锟? return; *prev =val; //杩欐鏄繖涓嚱鏁扮殑鍏抽敭 Printf("val[0x%x]\n",*prev); buf->dirty = true; } static int bq27621_battery_read_dm_block(struct bq27621_dm_buf *buf) { int ret; buf->has_data = false; bq27621_write8(REG_BLOCK_DATA_CONTROL, 0); /* bd.class=82; bd.block=3/BQ27621_DM_SZ ; */ //step 5 ret = bq27621_write(REG_DATA_CLASS, 82); //Data Class buf->class if (ret ==1) { Printf("read reg data class err\n"); goto out; } //step 6 ret = bq27621_write(REG_DATA_BLOCK,0); //Data Block buf->block if (ret ==1) { Printf("read reg data block err\n"); goto out; } bq27621_delay_msek(1); #if 1 ret = bq27621_read_block(BQ27621_DM_DATA, buf->data, BQ27621_DM_SZ); // Block Data if (ret ==1) { Printf("read dm data err\n"); goto out; } else { Printf("dm data buf :\n"); for(int i=0;i<BQ27621_DM_SZ;i++) { Printf("0x%x ",buf->data[i]); } Printf("\n"); } #endif //ret鏄痓q27xxx_read璇诲嚭瀵勫瓨鍣ㄧ殑鏁版嵁 bq27621_read(REG_BLOCK_DATA_CHECKSUM, &ret); //璇诲彇BQ27XXX_DM_CKSUM瀵勫瓨锟? Printf("the read reg block local data checsum data is 0x%x\n",ret); if ((uint8_t)ret != bq27621_battery_checksum_dm_block(buf)) { ret = 1; Printf("========>battery checksum dm block err\n"); // goto out; } else { Printf("reg block data checksum right\n"); } buf->has_data = true; //琛ㄧず鏁版嵁宸茬粡璇诲嚭鏉ヤ簡 buf->dirty = false; return 0; out: return ret; } static int bq27621_battery_write_dm_block(struct bq27621_dm_buf *buf) { int ret; ret = bq27621_battery_set_cfgupdate(); // if (ret ==1) // return ret; ret = bq27621_write(REG_CTRL,0); // if (ret == 1) // goto out; ret = bq27621_write(REG_DATA_CLASS, buf->class); // if (ret == 1) // goto out; ret = bq27621_write(REG_DATA_BLOCK, buf->block); // if (ret == 1) // goto out; bq27621_delay_msek(1); ret = bq27621_write_block(BQ27621_DM_DATA, buf->data, BQ27621_DM_SZ); // if (ret == 1) // goto out; Printf("-----1-----\n"); ret = bq27621_write8(REG_BLOCK_DATA_CHECKSUM,bq27621_battery_checksum_dm_block(buf)); bq27621_read(REG_BLOCK_DATA_CHECKSUM,&Checknum1); Printf("read myself checknum from register is [0x%x]\n",Checknum1); Printf("-----2-----\n"); // if (ret == 1) // goto out; /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM * corruption on the '425 chip (and perhaps others), which can damage * the chip. */ bq27621_delay_msek(1); ret = bq27621_battery_soft_reset(); if (ret == 1) return ret; return 0; out: bq27621_battery_soft_reset(); Printf("bus error writing chip memory: %d\n", ret); return ret; } int bq27621_init0(void) { int rv; int status = 0, param = 0, checksum = 0,capacity =0; struct bq27621_dm_buf bd = {0}; struct bq27621_dm_buf bt = {0}; bd.class=82; bd.block=3/BQ27621_DM_SZ ; bt.class=82; bt.block=9/BQ27621_DM_SZ; bq27621_probe(); bq27621_battery_unseal(); /* 鎶奲d.class鍜宐d.block鍐欏叆鍒板搴斿瘎瀛樺櫒 璇诲嚭bd.data鏁版嵁 */ bq27621_battery_read_dm_block(&bd); //瀹屽杽bd /* assume design energy & capacity are in same block */ bq27621_battery_update_dm_block(&bd, BQ27621_DM_DESIGN_CAPACITY, DESIGN_CAPACITY); bq27621_battery_update_dm_block(&bd, BQ27621_DM_DESIGN_ENERGY, DESIGN_ENERGY); bq27621_battery_read_dm_block(&bt); bq27621_battery_update_dm_block(&bt, BQ27621_DM_TERMINATE_VOLTAGE, TERMINATE_VOLTAGE); bq27621_battery_write_dm_block(&bd); bq27621_battery_write_dm_block(&bt); bq27621_battery_seal(); bq27621_write(REG_CTRL, CONTROL_RESET); battery_design_capacity(&capacity); if(capacity !=BQ27621_DESIGN_CAPACITY) { Printf("<<<<<capacity[%d]->[%d] !=BQ27621_DESIGN_CAPACITY2>>>>>>>>>\n",capacity,DESIGN_CAPACITY); // bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); // SystemReset(); CPUdelay(12000*10); } else { Printf("<<<<<<<<<<<<BQ27621_DESIGN_CAPACITY[%d]2>>>>>>>>>>>>\n",capacity); } battery_remaining_capacity(&capacity); Printf("capacity[%%%d]\n",capacity); return 0; } void probe_type_id_init(void) { int rv = EC_SUCCESS; bq27621_write(REG_CTRL, CONTROL_RESET); rv = bq27621_probe(); if (rv) return; rv = bq27621_init(); if (rv) { /* Try it once more */ rv = bq27621_write(REG_CTRL, CONTROL_RESET); rv |= bq27621_init(); } } void sleep_bq27621(void) { bq27621_write(REG_CTRL, CONTROL_SHUTDOWN_ENABLE); bq27621_write(REG_CTRL, CONTROL_SHUTDOWN); } #if 1 //DECLARE_HOOK(HOOK_INIT, probe_type_id_init, HOOK_PRIO_DEFAULT); /* Some of the functions to make this battery "smart" */ int battery_device_name(char *device_name, int buf_size) { return EC_ERROR_UNIMPLEMENTED; } int battery_state_of_charge_abs(int *percent) { return EC_ERROR_UNIMPLEMENTED; } unsigned int recount=0; int battery_remaining_capacity(int *capacity) { int scaled_value, err_code,status,param,rv; bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); rv |= bq27621_read(REG_CTRL, &status); if (status & STATUS_SS) /* Already sealed */ { Printf("bq27621 seal Already sealed\n"); // return EC_SUCCESS; } battery_design_capacity(&scaled_value) ; Printf("REG DESIGN CAPACITY %d\n",scaled_value); err_code = bq27621_read(REG_REMAINING_CAPACITY, &scaled_value); //REG_NOMINAL_CAPACITY REG_REMAINING_CAPACITY Printf("scaled_value->[%d]\n",scaled_value); // if(scaled_value>460) // SystemReset(); *capacity = BQ27621_UNSCALE(scaled_value); //*100/458 Printf("*capacity[%d]\n",*capacity); *capacity = *capacity >439?439:*capacity; Printf("capacity->[%d]\n",*capacity); *capacity=(*capacity)*100/439; return err_code; } int battery_full_charge_capacity(int *capacity) { int scaled_value, err_code; err_code = bq27621_read(REG_FULL_CHARGE_CAPACITY, &scaled_value); *capacity = BQ27621_UNSCALE(scaled_value); return err_code; } int battery_time_to_empty(int *minutes) { return EC_ERROR_UNIMPLEMENTED; } int battery_time_to_full(int *minutes) { return EC_ERROR_UNIMPLEMENTED; } int battery_cycle_count(int *count) { return EC_ERROR_UNIMPLEMENTED; } int battery_time_at_rate(int rate, int *minutes) { return EC_ERROR_UNIMPLEMENTED; } int battery_design_capacity(int *capacity) { int scaled_value, err_code; err_code = bq27621_read(REG_DESIGN_CAPACITY, &scaled_value); *capacity = BQ27621_UNSCALE(scaled_value); return err_code; } #endif int battery_device_chemistry(void) { uint32_t rv; int param; rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID); rv |= bq27621_read(REG_CTRL, ¶m); if (param == 0x1202) { Printf("0x1202 (default)\n"); } if (param == 0x1210) { Printf("0x1210 (ALT_CHEM1)\n"); } if (param == 0x0354) { Printf("0x0354 (ALT_CHEM2)\n"); } return EC_SUCCESS; } #if 0 int battery_serial_number(int *serial) { return EC_ERROR_UNIMPLEMENTED; } int battery_manufacture_date(int *year, int *month, int *day) { return EC_ERROR_UNIMPLEMENTED; } int battery_design_voltage(int *voltage) { *voltage = BATTERY_VOLTAGE_NORMAL; return EC_SUCCESS; } int battery_get_mode(int *mode) { return EC_ERROR_UNIMPLEMENTED; } int battery_status(int *status) { return EC_ERROR_UNIMPLEMENTED; } enum battery_present battery_is_present(void) { return EC_ERROR_UNIMPLEMENTED; } void battery_get_params(struct batt_params *batt) { /* Reset flags */ batt->flags = 0; if (bq27621_read(REG_TEMPERATURE, &batt->temperature)) batt->flags |= BATT_FLAG_BAD_TEMPERATURE; else batt->flags |= BATT_FLAG_RESPONSIVE; /* Battery is responding */ if (bq27621_read8(REG_STATE_OF_CHARGE, &batt->state_of_charge)) batt->flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; if (bq27621_read(REG_VOLTAGE, &batt->voltage)) batt->flags |= BATT_FLAG_BAD_VOLTAGE; batt->flags |= BATT_FLAG_BAD_CURRENT; batt->current = 0; /* Default to not desiring voltage and current */ batt->desired_voltage = batt->desired_current = 0; } /* Wait until battery is totally stable */ int battery_wait_for_stable(void) { /* TODO(crosbug.com/p/30426): implement me */ return EC_SUCCESS; } #ifdef CONFIG_CMD_BATDEBUG #define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) #else #define CPRINTF(format, args...) #endif #ifdef CONFIG_CMD_BATDEBUG static int command_fgunseal(int argc, char **argv) { int rv = EC_SUCCESS; if (argc > 1) return EC_ERROR_PARAM_COUNT; rv = bq27621_unseal(); return rv; } DECLARE_CONSOLE_COMMAND(fgunseal, command_fgunseal, "", "Unseal the fg"); static int command_fgseal(int argc, char **argv) { int rv = EC_SUCCESS; if (argc > 1) return EC_ERROR_PARAM_COUNT; rv = bq27621_seal(); return rv; } DECLARE_CONSOLE_COMMAND(fgseal, command_fgseal, "", "Seal the fg"); static int command_fginit(int argc, char **argv) { int rv = EC_SUCCESS; int force = 0; int flags = 0; int unconfigured = 0; char *e; if (argc > 2) return EC_ERROR_PARAM_COUNT; if (argc == 2) { force = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; } rv = bq27621_read(REG_FLAGS, &flags); unconfigured = flags & FLAGS_ITPOR; if (!unconfigured && force) { rv |= bq27621_write(REG_CTRL, CONTROL_RESET); unconfigured = (rv == EC_SUCCESS); } if (unconfigured) rv |= bq27621_init(); return rv; } DECLARE_CONSOLE_COMMAND(fginit, command_fginit, "[force]", "Initialize the fg"); static int command_fgprobe(int argc, char **argv) { int rv = EC_SUCCESS; if (argc != 1) return EC_ERROR_PARAM_COUNT; rv = bq27621_probe(); return rv; } DECLARE_CONSOLE_COMMAND(fgprobe, command_fgprobe, "", "Probe the fg"); static int command_fgrd(int argc, char **argv) { int cmd, len; int rv = EC_SUCCESS; int data; char *e; if (argc < 3) return EC_ERROR_PARAM_COUNT; cmd = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; len = strtoi(argv[2], &e, 0); if (*e) return EC_ERROR_PARAM2; if (len == 2) rv = bq27621_read(cmd, &data); else if (len == 1) rv = bq27621_read8(cmd, &data); else return EC_ERROR_PARAM2; CPRINTF("Read %d bytes @0xaa %0x: 0x%0x\n", len, cmd, data); return rv; } DECLARE_CONSOLE_COMMAND(fgrd, command_fgrd, "cmd len", "Read _len_ words from the fg"); static int command_fgcmd(int argc, char **argv) { int cmd, data, byte = 0; char *e; if (argc < 3 || argc > 4) return EC_ERROR_PARAM_COUNT; cmd = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; data = strtoi(argv[2], &e, 0); if (*e) return EC_ERROR_PARAM2; if (argc >= 4) { byte = strtoi(argv[3], &e, 0); if (*e) return EC_ERROR_PARAM3; } if (byte) { CPRINTF("Write a byte @0xaa %0x: 0x%0x\n", cmd, data); return bq27621_write8(cmd, data); } else { CPRINTF("Write 2 bytes @0xaa %0x: 0x%0x\n", cmd, data); return bq27621_write(cmd, data); } } DECLARE_CONSOLE_COMMAND(fgcmd, command_fgcmd, "cmd data [byte]", "Send a cmd to the fg"); static int command_fgcmdrd(int argc, char **argv) { int cmd, data, val; int rv = EC_SUCCESS; char *e; if (argc < 3) return EC_ERROR_PARAM_COUNT; cmd = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; data = strtoi(argv[2], &e, 0); if (*e) return EC_ERROR_PARAM2; rv = bq27621_write(cmd, data); rv |= bq27621_read(cmd, &val); CPRINTF("Read: @0xaa (%x %x) %x\n", cmd, data, val); return rv; } DECLARE_CONSOLE_COMMAND(fgcmdrd, command_fgcmdrd, "cmd data", "Send a 2-byte cmd to the fg, read back the 2-byte result"); #endif /* CONFIG_CMD_BATDEBUG */ #endif