SLVAF93A october 2022 – april 2023 LP8764-Q1 , TPS6594-Q1
The process for updating the register CRC for the Page 3 and Page 1 contents uses the CRC update feature within the PMIC. Before running the CRC update, clear the register CRC contents in address 0xF0 through 0xFB. The CRC update is performed when bit 1 of register 0xEF in page 0 is set. This bit is self-clearing. Once the update is complete, the content of address 0xFB, page 0, becomes a non-zero value. This check of register 0xFB changing from a 0 to non-zero number is recommended to confirm that the CRC is complete before attempting move on to the next step.
The PMIC CRC update feature calculates the CRC for pages 0,1,3, and 4. Page 2 is protected memory space as well as the associated CRC and is not described in this document. In most applications the calculation for the user registers, the combination of pages 1 and 4, is incorrect. The value of register 0x82 on page 0 does not match the default value, see Appendix B, and the bits SPMI_LPM_EN and FORCE_EN_DRV_LOW, found in the register are read only from the serial interface.
The Page 0 and Page 4 register CRC has two components: include persist and exclude persist. As shown in Table 5-4, the include persist CRC information is stored in registers 0xF0 and 0xF1 of page 0 and the exclude persist is stored in registers 0xF2 and 0xF3 of page 0.
Register | Address, Page 0 | Bit7-Bit0 |
---|---|---|
CRC_1 | 0xF0 | REGMAP_USER_INCLUDE_PERSIST_CRC16_LOW |
CRC_2 | 0xF1 | REGMAP_USER_INCLUDE_PERSIST_CRC16_HIGH |
CRC_3 | 0xF2 | REGMAP_USER_EXCLUDE_PERSIST_CRC16_LOW |
CRC_4 | 0xF3 | REGMAP_USER_EXCLUDE_PERSIST_CRC16_HIGH |
The CRC calculation shown in the following code-snippet is taken from the Scalable PMIC GUI (see Reference 3). Appendix C is provided as an array of the register information. The information associated with the watchdog is mapped to the appropriate locations and registers are populated with default settings if not backed by NVM and with 0x00, if undefined.
const CRC_POLYNOMIAL = 0x755b;
var calculate_register_crc = function(registers, regmap_json, include_persist, page) {
crc = 0xffff;
for (var address = 0; address < 0x100; address++) {
var data;
var json_address;
if (address >= 0xf0 && page === 0) {
// Watchdog registers is mapped from 0x0fX in array to 0x40X in register map
// Offset by 1 since 0x0f0 is mapped to 0x401
json_address = address + 0x310 + 1;
} else {
json_address = address + (page * 0x100);
}
if (registers[address] === undefined) {
if (json_address in regmap_json) {
// Non-NVM register uses reset value
data = regmap_json[json_address].reset;
} else {
// Register does not exist, so reads 0s
data = 0;
}
} else {
// Regsiter is NVM-backed, use value from device
data = registers[address];
}
var crc_mask = 0x00;
if (json_address in regmap_json) {
if (include_persist) {
crc_mask = regmap_json[json_address].crc_mask_include_persist;
} else {
crc_mask = regmap_json[json_address].crc_mask_exclude_persist;
}
}
data = data & crc_mask;
crc = crc_d8(crc, data);
}
return crc;
};
// Calculate CRC based on look-up table
var crc_d8 = function(crc, data) {
var table_index = data ^ ((crc & 0xff00) >> 8);
crc = (crc << 8) ^ lookup_table[table_index];
return crc & 0xffff;
};
// Compute lookup-table used for CRC calculation
crc = 0x8000;
for (var i = 1; i < 256; i <<= 1) {
if ((crc & 0x8000) !== 0) {
crc = ((crc << 1) ^ CRC_POLYNOMIAL) & 0xffff;
} else {
crc = (crc << 1) & 0xffff;
}
for (var j = 0; j < i; j++) {
lookup_table[i+j] = crc ^ lookup_table[j];
}
}