diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 5342fcb245c4c2..3a16e22bd5864f 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -21,127 +21,312 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* subclass 64 & 82 needs 5ms delay */ -#define BQ274XX_SUBCLASS_DELAY 5 +#define BQ274XX_SUBCLASS_DELAY K_MSEC(5) + +/* Time to wait for CFGUP bit to be set */ +#define BQ274XX_CFGUP_DELAY K_MSEC(50) /* Time to set pin in order to exit shutdown mode */ -#define PIN_DELAY_TIME 1U +#define PIN_DELAY_TIME K_MSEC(1) /* Time it takes device to initialize before doing any configuration */ -#define INIT_TIME 100U +#define INIT_TIME K_MSEC(100) + +/* Data memory size */ +#define BQ27XXX_DM_SZ 32 + +/* Config update mode flag */ +#define BQ27XXX_FLAG_CFGUP BIT(4) -static int gauge_configure(const struct device *dev); +static const struct bq274xx_regs bq27421_regs = { + .dm_design_capacity = 10, + .dm_design_energy = 12, + .dm_terminate_voltage = 16, + .dm_taper_rate = 27, +}; + +static const struct bq274xx_regs bq27427_regs = { + .dm_design_capacity = 6, + .dm_design_energy = 8, + .dm_terminate_voltage = 10, + .dm_taper_rate = 21, +}; -static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) +static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, + int16_t *val) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data[2]; int ret; - ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, 2); + ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, sizeof(i2c_data)); if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; } - *val = (i2c_data[1] << 8) | i2c_data[0]; + *val = sys_get_le16(i2c_data); return 0; } -static int ctrl_reg_write(const struct device *dev, uint16_t subcommand) +static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; - uint8_t i2c_data, reg_addr; - int ret = 0; + int ret; - reg_addr = BQ274XX_CMD_CONTROL_LOW; - i2c_data = (uint8_t)((subcommand)&0x00FF); + uint8_t tx_buf[3] = { + BQ274XX_CMD_CONTROL_LOW, + subcommand & 0xff, + subcommand >> 8, + }; - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); + ret = i2c_write_dt(&config->i2c, tx_buf, sizeof(tx_buf)); if (ret < 0) { - LOG_ERR("Failed to write into control low register"); + LOG_ERR("Failed to write into control register"); return -EIO; } - k_msleep(BQ274XX_SUBCLASS_DELAY); + return 0; +} - reg_addr = BQ274XX_CMD_CONTROL_HIGH; - i2c_data = (uint8_t)((subcommand >> 8) & 0x00FF); +static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, + uint8_t *data, uint8_t bytes) +{ + const struct bq274xx_config *config = dev->config; + uint8_t i2c_data; + int ret; + + i2c_data = BQ274XX_EXT_BLKDAT_START + offset; - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); + ret = i2c_burst_read_dt(&config->i2c, i2c_data, data, bytes); if (ret < 0) { - LOG_ERR("Failed to write into control high register"); + LOG_ERR("Failed to read block"); return -EIO; } + k_sleep(BQ274XX_SUBCLASS_DELAY); + return 0; } -static int cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data) +static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) { - const struct bq274xx_config *config = dev->config; - uint8_t i2c_data, reg_addr; - int ret = 0; + int ret; - reg_addr = command; - i2c_data = data; + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); + if (ret < 0) { + LOG_ERR("Unable to write control register"); + return -EIO; + } - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); if (ret < 0) { - LOG_ERR("Failed to write into control register"); + LOG_ERR("Unable to read register"); return -EIO; } return 0; } -static int read_data_block(const struct device *dev, uint8_t offset, - uint8_t *data, uint8_t bytes) +static int bq274xx_gauge_configure(const struct device *dev) { - const struct bq274xx_config *config = dev->config; - uint8_t i2c_data; - int ret = 0; + const struct bq274xx_config *const config = dev->config; + struct bq274xx_data *data = dev->data; + const struct bq274xx_regs *regs = data->regs; + int ret; + uint8_t tmp_checksum, checksum_old, checksum_new; + uint16_t flags, designenergy_mwh, taperrate, reg_val; + uint8_t block[BQ27XXX_DM_SZ]; + uint8_t try; - i2c_data = BQ274XX_EXT_BLKDAT_START + offset; + designenergy_mwh = (uint32_t)config->design_capacity * 37 / 10; /* x3.7 */ + taperrate = config->design_capacity * 10 / config->taper_current; - ret = i2c_burst_read_dt(&config->i2c, i2c_data, data, bytes); + /* Unseal the battery control register */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_A); if (ret < 0) { - LOG_ERR("Failed to read block"); + LOG_ERR("Unable to unseal the battery"); return -EIO; } - k_msleep(BQ274XX_SUBCLASS_DELAY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_B); + if (ret < 0) { + LOG_ERR("Unable to unseal the battery"); + return -EIO; + } - return 0; -} + /* Send CFG_UPDATE */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); + if (ret < 0) { + LOG_ERR("Unable to set CFGUpdate"); + return -EIO; + } -static int get_device_type(const struct device *dev, uint16_t *val) -{ - int ret; + /* Step to place the Gauge into CONFIG UPDATE Mode */ + try = 100; + do { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + if (ret < 0) { + LOG_ERR("Unable to read flags"); + return -EIO; + } + + if (!(flags & BQ27XXX_FLAG_CFGUP)) { + k_sleep(BQ274XX_CFGUP_DELAY); + } + } while (!(flags & BQ27XXX_FLAG_CFGUP) && --try); - ret = ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); + if (!try) { + LOG_ERR("Config mode change timeout"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { - LOG_ERR("Unable to write control register"); + LOG_ERR("Failed to enable block data memory"); + return -EIO; + } + + /* Access State subclass */ + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_CLASS, 0x52); + if (ret < 0) { + LOG_ERR("Failed to update state subclass"); return -EIO; } - ret = cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); + /* Write the block offset */ + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_BLOCK, 0x00); + if (ret < 0) { + LOG_ERR("Failed to update block offset"); + return -EIO; + } + ret = bq274xx_read_data_block(dev, 0, block, sizeof(block)); if (ret < 0) { - LOG_ERR("Unable to read register"); + LOG_ERR("Unable to read block data"); + return -EIO; + } + + tmp_checksum = 0; + for (uint8_t i = 0; i < ARRAY_SIZE(block); i++) { + tmp_checksum += block[i]; + } + tmp_checksum = 255 - tmp_checksum; + + /* Read the block checksum */ + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &checksum_old); + if (ret < 0) { + LOG_ERR("Unable to read block checksum"); + return -EIO; + } + + reg_val = sys_cpu_to_be16(config->design_capacity); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_design_capacity), + (uint8_t *)®_val, sizeof(reg_val)); + if (ret < 0) { + LOG_ERR("Failed to write design capacity"); + return -EIO; + } + + reg_val = sys_cpu_to_be16(designenergy_mwh); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_design_energy), + (uint8_t *)®_val, sizeof(reg_val)); + if (ret < 0) { + LOG_ERR("Failed to write design energy"); + return -EIO; + } + + reg_val = sys_cpu_to_be16(config->terminate_voltage); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_terminate_voltage), + (uint8_t *)®_val, sizeof(reg_val)); + if (ret < 0) { + LOG_ERR("Failed to write terminate voltage"); + return -EIO; + } + + reg_val = sys_cpu_to_be16(taperrate); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_taper_rate), + (uint8_t *)®_val, sizeof(reg_val)); + if (ret < 0) { + LOG_ERR("Failed to write taper rate"); + return -EIO; + } + + ret = bq274xx_read_data_block(dev, 0, block, sizeof(block)); + if (ret < 0) { + LOG_ERR("Unable to read block data"); + return -EIO; + } + + checksum_new = 0; + for (uint8_t i = 0; i < ARRAY_SIZE(block); i++) { + checksum_new += block[i]; + } + checksum_new = 255 - checksum_new; + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, checksum_new); + if (ret < 0) { + LOG_ERR("Failed to update new checksum"); + return -EIO; + } + + tmp_checksum = 0; + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &tmp_checksum); + if (ret < 0) { + LOG_ERR("Failed to read checksum"); + return -EIO; + } + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); + if (ret < 0) { + LOG_ERR("Unable to configure BAT Detect"); + return -EIO; + } + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); + if (ret < 0) { + LOG_ERR("Failed to soft reset the gauge"); return -EIO; } + /* Poll Flags */ + try = 100; + do { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + if (ret < 0) { + LOG_ERR("Unable to read flags"); + return -EIO; + } + + if (flags & BQ27XXX_FLAG_CFGUP) { + k_sleep(BQ274XX_CFGUP_DELAY); + } + } while ((flags & BQ27XXX_FLAG_CFGUP) & --try); + + if (!try) { + LOG_ERR("Config mode change timeout"); + return -EIO; + } + + /* Seal the gauge */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); + if (ret < 0) { + LOG_ERR("Failed to seal the gauge"); + return -EIO; + } + + data->configured = true; + return 0; } -/** - * @brief sensor value get - * - * @return -ENOTSUP for unsupported channels - */ -static int channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) +static int bq274xx_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { struct bq274xx_data *data = dev->data; float int_temp; @@ -216,118 +401,120 @@ static int channel_get(const struct device *dev, enum sensor_channel chan, return 0; } -static int sample_fetch(const struct device *dev, enum sensor_channel chan) +static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; - int ret = 0; + int ret = -ENOTSUP; if (!data->configured) { - ret = gauge_configure(dev); - + ret = bq274xx_gauge_configure(dev); if (ret < 0) { return ret; } } - switch (chan) { - case SENSOR_CHAN_GAUGE_VOLTAGE: - ret = cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, &data->voltage); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_VOLTAGE) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, + &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_AVG_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, - &data->avg_current); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_AVG_CURRENT) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, + &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_TEMP: - ret = cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, - &data->internal_temperature); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_TEMP) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, + &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, - &data->stdby_current); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STDBY_CURRENT) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, + &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, - &data->max_load_current); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, + &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOC, &data->state_of_charge); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STATE_OF_CHARGE) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOC, + &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_AVG_POWER: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, &data->avg_power); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_AVG_POWER) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, + &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOH, &data->state_of_health); + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STATE_OF_HEALTH) { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOH, + &data->state_of_health); data->state_of_health = (data->state_of_health) & 0x00FF; @@ -335,13 +522,9 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) LOG_ERR("Failed to read state of health"); return -EIO; } - break; - - default: - return -ENOTSUP; } - return 0; + return ret; } /** @@ -349,10 +532,11 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) * * @return 0 for success */ -static int gauge_init(const struct device *dev) +static int bq274xx_gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int ret = 0; + struct bq274xx_data *data = dev->data; + int ret; uint16_t id; if (!device_is_ready(config->i2c.bus)) { @@ -367,15 +551,19 @@ static int gauge_init(const struct device *dev) } #endif - ret = get_device_type(dev, &id); + ret = bq274xx_get_device_type(dev, &id); if (ret < 0) { LOG_ERR("Unable to get device ID"); return -EIO; } - if (id != BQ274XX_DEVICE_ID) { - LOG_ERR("Invalid Device"); - return -EINVAL; + if (id == BQ27421_DEVICE_ID) { + data->regs = &bq27421_regs; + } else if (id == BQ27427_DEVICE_ID) { + data->regs = &bq27427_regs; + } else { + LOG_ERR("Unsupported device ID: 0x%04x", id); + return -ENOTSUP; } #ifdef CONFIG_BQ274XX_TRIGGER @@ -387,265 +575,42 @@ static int gauge_init(const struct device *dev) #endif if (!config->lazy_loading) { - ret = gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); } return ret; } -static int gauge_configure(const struct device *dev) -{ - const struct bq274xx_config *const config = dev->config; - struct bq274xx_data *data = dev->data; - - int ret = 0; - uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; - uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; - uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, - terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; - uint8_t block[32]; - - designenergy_mwh = (uint16_t)3.7 * config->design_capacity; - taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); - - /** Unseal the battery control register **/ - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (ret < 0) { - LOG_ERR("Unable to unseal the battery"); - return -EIO; - } - - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (ret < 0) { - LOG_ERR("Unable to unseal the battery"); - return -EIO; - } - - /* Send CFG_UPDATE */ - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); - if (ret < 0) { - LOG_ERR("Unable to set CFGUpdate"); - return -EIO; - } - - /** Step to place the Gauge into CONFIG UPDATE Mode **/ - do { - ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); - if (ret < 0) { - LOG_ERR("Unable to read flags"); - return -EIO; - } - - if (!(flags & 0x0010)) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); - } - - } while (!(flags & 0x0010)); - - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); - if (ret < 0) { - LOG_ERR("Failed to enable block data memory"); - return -EIO; - } - - /* Access State subclass */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); - if (ret < 0) { - LOG_ERR("Failed to update state subclass"); - return -EIO; - } - - /* Write the block offset */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); - if (ret < 0) { - LOG_ERR("Failed to update block offset"); - return -EIO; - } - - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - - ret = read_data_block(dev, 0x00, block, 32); - if (ret < 0) { - LOG_ERR("Unable to read block data"); - return -EIO; - } - - tmp_checksum = 0; - for (uint8_t i = 0; i < 32; i++) { - tmp_checksum += block[i]; - } - tmp_checksum = 255 - tmp_checksum; - - /* Read the block checksum */ - ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &checksum_old); - if (ret < 0) { - LOG_ERR("Unable to read block checksum"); - return -EIO; - } - - designcap_msb = config->design_capacity >> 8; - designcap_lsb = config->design_capacity & 0x00FF; - designenergy_msb = designenergy_mwh >> 8; - designenergy_lsb = designenergy_mwh & 0x00FF; - terminatevolt_msb = config->terminate_voltage >> 8; - terminatevolt_lsb = config->terminate_voltage & 0x00FF; - taperrate_msb = taperrate >> 8; - taperrate_lsb = taperrate & 0x00FF; - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, - designcap_msb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, - designcap_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, - designenergy_msb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, - designenergy_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, - terminatevolt_msb); - if (ret < 0) { - LOG_ERR("Failed to write terminateVolt MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, - terminatevolt_lsb); - if (ret < 0) { - LOG_ERR("Failed to write terminateVolt LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, - taperrate_msb); - if (ret < 0) { - LOG_ERR("Failed to write taperRate MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); - if (ret < 0) { - LOG_ERR("Failed to write taperRate LSB"); - return -EIO; - } - - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - - ret = read_data_block(dev, 0x00, block, 32); - if (ret < 0) { - LOG_ERR("Unable to read block data"); - return -EIO; - } - - checksum_new = 0; - for (uint8_t i = 0; i < 32; i++) { - checksum_new += block[i]; - } - checksum_new = 255 - checksum_new; - - ret = cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); - if (ret < 0) { - LOG_ERR("Failed to update new checksum"); - return -EIO; - } - - tmp_checksum = 0; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &tmp_checksum); - if (ret < 0) { - LOG_ERR("Failed to read checksum"); - return -EIO; - } - - ret = ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); - if (ret < 0) { - LOG_ERR("Unable to configure BAT Detect"); - return -EIO; - } - - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); - if (ret < 0) { - LOG_ERR("Failed to soft reset the gauge"); - return -EIO; - } - - flags = 0; - /* Poll Flags */ - do { - ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); - if (ret < 0) { - LOG_ERR("Unable to read flags"); - return -EIO; - } - - if (flags & 0x0010) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); - } - } while (flags & 0x0010); - - /* Seal the gauge */ - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); - if (ret < 0) { - LOG_ERR("Failed to seal the gauge"); - return -EIO; - } - - data->configured = true; - - return 0; -} - #ifdef CONFIG_BQ274XX_PM -static int enter_shutdown_mode(const struct device *dev) +static int bq274xx_enter_shutdown_mode(const struct device *dev) { int ret; - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_A); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_B); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN_ENABLE); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN_ENABLE); if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN); if (ret < 0) { LOG_ERR("Unable to enter shutdown mode"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return ret; @@ -654,10 +619,10 @@ static int enter_shutdown_mode(const struct device *dev) return 0; } -static int exit_shutdown_mode(const struct device *dev) +static int bq274xx_exit_shutdown_mode(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int ret = 0; + int ret; ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_OUTPUT | GPIO_OPEN_DRAIN); if (ret < 0) { @@ -671,7 +636,7 @@ static int exit_shutdown_mode(const struct device *dev) return ret; } - k_msleep(PIN_DELAY_TIME); + k_sleep(PIN_DELAY_TIME); ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); if (ret < 0) { @@ -680,9 +645,9 @@ static int exit_shutdown_mode(const struct device *dev) } if (!config->lazy_loading) { - k_msleep(INIT_TIME); + k_sleep(INIT_TIME); - ret = gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); if (ret < 0) { LOG_ERR("Unable to configure bq274xx gauge"); return ret; @@ -692,16 +657,17 @@ static int exit_shutdown_mode(const struct device *dev) return 0; } -static int pm_action(const struct device *dev, enum pm_device_action action) +static int bq274xx_pm_action(const struct device *dev, + enum pm_device_action action) { int ret; switch (action) { case PM_DEVICE_ACTION_TURN_OFF: - ret = enter_shutdown_mode(dev); + ret = bq274xx_enter_shutdown_mode(dev); break; case PM_DEVICE_ACTION_RESUME: - ret = exit_shutdown_mode(dev); + ret = bq274xx_exit_shutdown_mode(dev); break; default: ret = -ENOTSUP; @@ -713,8 +679,8 @@ static int pm_action(const struct device *dev, enum pm_device_action action) #endif /* CONFIG_BQ274XX_PM */ static const struct sensor_driver_api bq274xx_battery_driver_api = { - .sample_fetch = sample_fetch, - .channel_get = channel_get, + .sample_fetch = bq274xx_sample_fetch, + .channel_get = bq274xx_channel_get, #ifdef CONFIG_BQ274XX_TRIGGER .trigger_set = bq274xx_trigger_set, #endif @@ -723,12 +689,12 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) #define BQ274XX_INT_CFG(index) \ .int_gpios = GPIO_DT_SPEC_INST_GET(index, int_gpios), -#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) \ - PM_DEVICE_DT_INST_DEFINE(index, pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) \ + PM_DEVICE_DT_INST_DEFINE(index, bq274xx_pm_action) #define PM_BQ274XX_DT_INST_GET(index) PM_DEVICE_DT_INST_GET(index) #else #define BQ274XX_INT_CFG(index) -#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) #define PM_BQ274XX_DT_INST_GET(index) NULL #endif @@ -745,9 +711,9 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ - PM_BQ274XX_DT_INST_DEFINE(index, pm_action); \ + PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action); \ \ - SENSOR_DEVICE_DT_INST_DEFINE(index, &gauge_init, \ + SENSOR_DEVICE_DT_INST_DEFINE(index, &bq274xx_gauge_init, \ PM_BQ274XX_DT_INST_GET(index), \ &bq274xx_driver_##index, \ &bq274xx_config_##index, POST_KERNEL, \ diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index 96bb9e83edf80b..ea81b9f2489e1a 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -11,8 +11,10 @@ #include /*** General Constant ***/ -#define BQ274XX_UNSEAL_KEY 0x8000 /* Secret code to unseal the BQ27441-G1A */ -#define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ +#define BQ274XX_UNSEAL_KEY_A 0x8000 /* Unseal code one on BQ27441-G1A and similar */ +#define BQ274XX_UNSEAL_KEY_B 0x8000 /* Unseal code two on BQ27441-G1A and similar */ +#define BQ27421_DEVICE_ID 0x0421 +#define BQ27427_DEVICE_ID 0x0427 /*** Standard Commands ***/ #define BQ274XX_CMD_CONTROL_LOW 0x00 /* Control() low register */ @@ -67,18 +69,18 @@ #define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ #define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ #define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH 0x4A /* BlockData */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW 0x4B -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH 0x4C -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW 0x4D -#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH 0x50 -#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW 0x51 -#define BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH 0x5B -#define BQ274XX_EXT_BLKDAT_TAPERRATE_LOW 0x5C +#define BQ274XX_EXT_BLKDAT(off) (BQ274XX_EXT_BLKDAT_START + off) -#define BQ274XX_DELAY 1000 +/* Hold the register offset for a device variant. */ +struct bq274xx_regs { + uint8_t dm_design_capacity; + uint8_t dm_design_energy; + uint8_t dm_terminate_voltage; + uint8_t dm_taper_rate; +}; struct bq274xx_data { + const struct bq274xx_regs *regs; bool configured; uint16_t voltage; int16_t avg_current; diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 658fef2f72cc4c..b13662904683e6 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(bq274xx, CONFIG_SENSOR_LOG_LEVEL); -static void handle_interrupts(const struct device *dev) +static void bq274xx_handle_interrupts(const struct device *dev) { struct bq274xx_data *data = dev->data; @@ -31,26 +31,27 @@ static void handle_interrupts(const struct device *dev) static K_KERNEL_STACK_DEFINE(bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE); static struct k_thread bq274xx_thread; -static void thread_main(struct bq274xx_data *data) +static void bq274xx_thread_main(struct bq274xx_data *data) { while (1) { k_sem_take(&data->sem, K_FOREVER); - handle_interrupts(data->dev); + bq274xx_handle_interrupts(data->dev); } } #endif #ifdef CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD -static void work_handler(struct k_work *work) +static void bq274xx_work_handler(struct k_work *work) { struct bq274xx_data *data = CONTAINER_OF(work, struct bq274xx_data, work); - handle_interrupts(data->dev); + bq274xx_handle_interrupts(data->dev); } #endif -static void ready_callback_handler(const struct device *port, struct gpio_callback *cb, - gpio_port_pins_t pins) +static void bq274xx_ready_callback_handler(const struct device *port, + struct gpio_callback *cb, + gpio_port_pins_t pins) { struct bq274xx_data *data = CONTAINER_OF(cb, struct bq274xx_data, ready_callback); @@ -69,7 +70,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - int ret = 0; + int ret; data->dev = dev; @@ -78,12 +79,12 @@ int bq274xx_trigger_mode_init(const struct device *dev) k_thread_create(&bq274xx_thread, bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE, - (k_thread_entry_t)thread_main, + (k_thread_entry_t)bq274xx_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_BQ274XX_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD) - k_work_init(&data->work, work_handler); + k_work_init(&data->work, bq274xx_work_handler); #endif ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); @@ -92,7 +93,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) return ret; } gpio_init_callback(&data->ready_callback, - ready_callback_handler, + bq274xx_ready_callback_handler, BIT(config->int_gpios.pin)); return 0;