From 8f6d815c88be764cc1834bdb6b90d66f7a565485 Mon Sep 17 00:00:00 2001 From: Jean Yuan Date: Wed, 13 Aug 2025 15:37:17 +0800 Subject: [PATCH] drivers: charger: ba2562x: add support for BQ2562X charger - Add new configuration options for BQ2562X charger - Implement new functions for charger control and status - Update device API to include USB type and timer status - Add support for NTC feedback and ADC sampling - Implement charge current and voltage settings - Add protection features like overvoltage and overcurrent - Update documentation and header files for new functionality Signed-off-by: Jean Yuan --- drivers/charger/charger_bq2562x.c | 367 +++++++++++++++++++++-- drivers/charger/charger_bq2562x.h | 30 +- dts/bindings/charger/ti,bq2562x.yaml | 155 +++++++++- include/zephyr/drivers/charger.h | 20 ++ include/zephyr/drivers/charger/bq2562x.h | 264 ++++++++++++++++ 5 files changed, 801 insertions(+), 35 deletions(-) create mode 100644 include/zephyr/drivers/charger/bq2562x.h diff --git a/drivers/charger/charger_bq2562x.c b/drivers/charger/charger_bq2562x.c index 3d26b94084cec..57faf60153316 100644 --- a/drivers/charger/charger_bq2562x.c +++ b/drivers/charger/charger_bq2562x.c @@ -17,9 +17,12 @@ #include #include #include +#include LOG_MODULE_REGISTER(ti_bq25620, CONFIG_CHARGER_LOG_LEVEL); +#define BQ2562X_TIMEOUT_MS 50 + struct bq2562x_config { struct i2c_dt_spec i2c; struct gpio_dt_spec ce_gpio; @@ -44,6 +47,19 @@ struct bq2562x_data { uint32_t thermal_regulation_threshold; uint32_t switching_converter_freq; uint32_t switching_converter_strength; + uint32_t q1_fullon; + uint32_t q4_fullon; + uint32_t vindpm_bat_track; + uint32_t verchg_bat_offset; + uint32_t enable_dcp_bias; + uint32_t enable_savety_tmrs; + uint32_t timer2x_en; + uint32_t precharge_timer; + uint32_t fast_charge_timer; + uint32_t auto_battery_discharging; + uint32_t vbus_ovp; + uint32_t peak_current_protection_threshold; + uint32_t charge_rate_stage; enum charger_status state; enum charger_online online; }; @@ -85,6 +101,11 @@ static int bq2562x_set_charge_enable(const struct device *dev, const bool enable const struct bq2562x_config *const config = dev->config; int ret; + ret = bq2562x_config_watchdog(dev, CHARGER_WDT_DISABLE); + if (ret < 0) { + return ret; + } + if (config->ce_gpio.port != NULL) { ret = gpio_pin_set_dt(&config->ce_gpio, enable); if (ret) { @@ -100,7 +121,7 @@ static int bq2562x_set_charge_enable(const struct device *dev, const bool enable static int bq2562x_get_ichrg_curr(const struct device *dev, uint32_t *current_ua) { const struct bq2562x_config *const config = dev->config; - uint8_t ichg[2]; + uint8_t ichg[2] = {0}; int ret; ret = i2c_burst_read_dt(&config->i2c, BQ2562X_CHRG_I_LIM_LSB, ichg, ARRAY_SIZE(ichg)); @@ -114,26 +135,21 @@ static int bq2562x_get_ichrg_curr(const struct device *dev, uint32_t *current_ua return 0; } -static int bq2562x_set_ichrg_curr(const struct device *dev, uint32_t chrg_curr) +static int bq2562x_set_ichrg_curr(const struct device *dev, int chrg_curr) { const struct bq2562x_config *const config = dev->config; struct bq2562x_data *data = dev->data; - uint32_t chrg_curr_max = data->constant_charge_current_max_ua; + int chrg_curr_max = data->constant_charge_current_max_ua; uint8_t ichg[2] = {0}; int ret; chrg_curr = CLAMP(chrg_curr, BQ2562X_ICHG_I_MIN_UA, chrg_curr_max); - - (void)bq2562x_set_charge_enable(dev, 0); - chrg_curr = ((chrg_curr / BQ2562X_ICHG_I_STEP_UA) << BQ2562X_ICHG_I_SHIFT); ichg[1] = (chrg_curr >> 8) & BQ2562X_ICHG_MSB_MSK; ichg[0] = chrg_curr & BQ2562X_ICHG_LSB_MSK; ret = i2c_burst_write_dt(&config->i2c, BQ2562X_CHRG_I_LIM_LSB, ichg, ARRAY_SIZE(ichg)); - (void)bq2562x_set_charge_enable(dev, 1); - return ret; } @@ -277,9 +293,6 @@ static int bq2562x_set_prechrg_curr(const struct device *dev, int pre_current) int ret; pre_current = CLAMP(pre_current, BQ2562X_PRECHRG_I_MIN_UA, BQ2562X_PRECHRG_I_MAX_UA); - - (void)bq2562x_set_charge_enable(dev, 0); - pre_current = (pre_current / BQ2562X_PRECHRG_I_STEP_UA) << BQ2562X_PRECHRG_I_SHIFT; prechrg_curr[1] = (pre_current >> 8) & BQ2562X_PRECHRG_I_MSB_MSK; prechrg_curr[0] = pre_current & BQ2562X_PRECHRG_I_LSB_MSK; @@ -287,8 +300,6 @@ static int bq2562x_set_prechrg_curr(const struct device *dev, int pre_current) ret = i2c_burst_write_dt(&config->i2c, BQ2562X_PRECHRG_CTRL_LSB, prechrg_curr, ARRAY_SIZE(prechrg_curr)); - (void)bq2562x_set_charge_enable(dev, 1); - return ret; } @@ -324,6 +335,136 @@ static int bq2562x_set_term_curr(const struct device *dev, int term_current) return i2c_burst_write_dt(&config->i2c, BQ2562X_TERM_CTRL_LSB, iterm, ARRAY_SIZE(iterm)); } +int bq2562x_config_watchdog(const struct device *dev, enum charger_watchdog_state watchdog_state) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t reg_value = 0; + + switch (watchdog_state) { + case CHARGER_WDT_DISABLE: + reg_value = 0; + break; + case CHARGER_WDT_50S: + reg_value = 1; + break; + case CHARGER_WDT_100S: + reg_value = 2; + break; + case CHARGER_WDT_200S: + reg_value = 3; + break; + default: + reg_value = 0; + break; + } + + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, BQ2562X_WATCHDOG_MASK, + FIELD_PREP(BQ2562X_WATCHDOG_MASK, reg_value)); +} + +int bq2562x_config_ntc_feedback(const struct device *dev, enum charger_ntc_state state) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t reg_value = 0; + + if (state == CHARGER_NTC_IGNORE) { + reg_value = CHARGER_NTC_IGNORE; + } else { + reg_value = CHARGER_NTC_NOT_IGNORE; + } + + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_NTC_CTRL_0, BQ2562X_NTC_MASK, + FIELD_PREP(BIT(7), reg_value)); +} +int bq2562x_set_charge_current_threshold(const struct device *dev, + enum charger_current_threshold current_threshold) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t reg_value = 0; + + switch (current_threshold) { + case CHARGER_CURRENT_THRESHOLD_1_5_A: + reg_value = 0; + break; + case CHARGER_CURRENT_THRESHOLD_3_A: + reg_value = 1; + break; + case CHARGER_CURRENT_THRESHOLD_6_A: + reg_value = 2; + break; + case CHARGER_CURRENT_THRESHOLD_12_A: + reg_value = 3; + break; + default: + reg_value = 3; + break; + } + + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_4, BQ2562X_CTRL4_IBAT_PEAK, + FIELD_PREP(GENMASK(7, 6), reg_value)); +} + +int bq2562x_set_charge_rate(const struct device *dev, enum charger_rate charge_rate) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t reg_value = 0; + + switch (charge_rate) { + case CHARGER_RATE_1_C: + reg_value = 0; + break; + case CHARGER_RATE_2_C: + reg_value = 1; + break; + case CHARGER_RATE_4_C: + reg_value = 2; + break; + case CHARGER_RATE_6_C: + reg_value = 3; + break; + default: + break; + } + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_4, BQ2562X_CTRL4_RATE, + FIELD_PREP(GENMASK(1, 0), reg_value)); +} + +int bq2562x_set_battery_recharge_threshold_offset(const struct device *dev, + enum charger_recharge_threshold_offset offset) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t reg_value = 0; + + switch (offset) { + case CHARGER_VREG_100_MV: + reg_value = 0; + break; + case CHARGER_VREG_200_MV: + reg_value = 1; + break; + default: + break; + } + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_0, BQ2562X_CHG_VRECHG, + FIELD_PREP(BIT(0), reg_value)); +} + +int bq2562x_set_adc_sampling(const struct device *dev, enum charger_battery_adc_sampling enable) +{ + const struct bq2562x_config *const config = dev->config; + + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_ADC_CTRL, BQ2562X_ADC_EN, + FIELD_PREP(BIT(7), (enable ? 1 : 0))); +} + +int bq2562x_set_dpdm_detection(const struct device *dev, enum charger_dpdm_detection enable) +{ + const struct bq2562x_config *const config = dev->config; + + return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_TIMER_CTRL, BQ2562X_TIMER_FORCE_INDET, + FIELD_PREP(BIT(6), (enable ? 1 : 0))); +} + static int bq2562x_get_vbat_adc(const struct device *dev, uint32_t *vbat) { const struct bq2562x_config *const config = dev->config; @@ -561,6 +702,87 @@ static int bq2562x_get_charger_status(const struct device *dev, enum charger_sta return 0; } +static int bq2562x_get_usb_type(const struct device *dev, enum charger_usb_type *type) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t chrg_stat_1; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_STAT_1, &chrg_stat_1); + if (ret) { + return ret; + } + + chrg_stat_1 = FIELD_GET(BQ2562X_VBUS_STAT_MSK, chrg_stat_1); + switch (chrg_stat_1) { + case BQ2562X_USB_SDP: + *type = CHARGER_USB_TYPE_SDP; + break; + case BQ2562X_USB_CDP: + *type = CHARGER_USB_TYPE_CDP; + break; + case BQ2562X_USB_DCP: + *type = CHARGER_USB_TYPE_DCP; + break; + case BQ2562X_OTG_MODE: + *type = CHARGER_USB_TYPE_ACA; + break; + case BQ2562X_UNKNOWN_500MA: + __fallthrough; + case BQ2562X_NON_STANDARD: + __fallthrough; + case BQ2562X_HVDCP: /* TODO */ + __fallthrough; + default: + *type = CHARGER_USB_TYPE_UNKNOWN; + } + + return 0; +} + +int bq2562x_get_timer_status(const struct device *dev, enum charger_timer_state *state) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t chrg_stat_0; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_STAT_0, &chrg_stat_0); + if (ret) { + return ret; + } + + if ((chrg_stat_0 & BQ2562X_CHG_TMR_STATE) > 0) { + *state = CHARGER_TMR_STATE_TIMER_EXPIRED; + } else { + *state = CHARGER_TMR_STATE_NORMAL; + } + + return 0; +} + +int bq2562x_get_tdie_adc(const struct device *dev, int32_t *temperature) +{ + const struct bq2562x_config *const config = dev->config; + uint8_t tdie_adc[2] = {0}; + uint16_t temp; + int ret; + + ret = i2c_burst_read_dt(&config->i2c, BQ2562X_ADC_TDIE_LSB, tdie_adc, ARRAY_SIZE(tdie_adc)); + if (ret) { + return ret; + } + + temp = sys_get_le16(tdie_adc); + if (temp & BIT(11)) { + temp = ~temp + 1; + *temperature = ((temp & BQ2562X_ADC_TDIE_MASK) / 2) * -1; + } else { + *temperature = (temp & BQ2562X_ADC_TDIE_MASK) / 2; + } + + return 0; +} + static int bq2562x_get_prop(const struct device *dev, charger_prop_t prop, union charger_propval *val) { @@ -573,6 +795,8 @@ static int bq2562x_get_prop(const struct device *dev, charger_prop_t prop, return bq2562x_get_health(dev, &val->health); case CHARGER_PROP_STATUS: return bq2562x_get_charger_status(dev, &val->status); + case CHARGER_PROP_USB_TYPE: + return bq2562x_get_usb_type(dev, &val->usb_type); case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: return bq2562x_get_ichrg_curr(dev, &val->const_charge_current_ua); case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: @@ -603,8 +827,14 @@ static int bq2562x_get_prop(const struct device *dev, charger_prop_t prop, static int bq2562x_set_prop(const struct device *dev, charger_prop_t prop, const union charger_propval *val) { + int ret = 0; struct bq2562x_data *data = dev->data; + ret = bq2562x_config_watchdog(dev, CHARGER_WDT_DISABLE); + if (ret < 0) { + return ret; + } + switch (prop) { case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: return bq2562x_set_ichrg_curr(dev, val->const_charge_current_ua); @@ -648,6 +878,26 @@ static int bq2562x_validate_dt(struct bq2562x_data *data) data->input_current_max_ua = BQ2562X_IINDPM_I_DEF_UA; } + if (!IN_RANGE(data->constant_charge_current_max_ua, BQ2562X_ICHG_I_MIN_UA, + BQ2562X_ICHG_I_MAX_UA)) { + data->constant_charge_current_max_ua = BQ2562X_ICHG_I_DEF_UA; + } + + if (!IN_RANGE(data->constant_charge_voltage_max_uv, BQ2562X_VREG_V_MIN_UV, + BQ2562X_VREG_V_MAX_UV)) { + data->constant_charge_voltage_max_uv = BQ2562X_VREG_V_DEF_UV; + } + + if (!IN_RANGE(data->precharge_current_ua, BQ2562X_PRECHRG_I_MIN_UA, + BQ2562X_PRECHRG_I_MAX_UA)) { + data->precharge_current_ua = BQ2562X_PRECHRG_I_DEF_UA; + } + + if (!IN_RANGE(data->charge_term_current_ua, BQ2562X_TERMCHRG_I_MIN_UA, + BQ2562X_TERMCHRG_I_MAX_UA)) { + data->charge_term_current_ua = BQ2562X_TERMCHRG_I_DEF_UA; + } + return 0; } @@ -682,52 +932,94 @@ static int bq2562x_hw_init(const struct device *dev) { const struct bq2562x_config *const config = dev->config; struct bq2562x_data *data = dev->data; - int ret; + int ret = 0; + uint8_t value = 0; + uint8_t mask = 0; + + /* It is common use to start with charging disabled and reset devices before initializing + * it's settings. */ + bq2562x_set_charge_enable(dev, false); + value = BQ2562X_CTRL2_REG_RST; + ret = i2c_reg_write_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, value); + if (ret != 0) { + return ret; + } + k_msleep(BQ2562X_TIMEOUT_MS); /* Give some time to execute the reset */ - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_REG_RST, - BQ2562X_CTRL2_REG_RST); - if (ret) { + value = FIELD_PREP(BQ2562X_CHG_Q1_FULLON, data->q1_fullon); + value |= FIELD_PREP(BQ2562X_CHG_Q4_FULLON, data->q4_fullon); + value |= FIELD_PREP(BQ2562X_CHG_VINDPM_BAT_TRACK, data->vindpm_bat_track); + value |= FIELD_PREP(BQ2562X_CHG_VRECHG, data->verchg_bat_offset); + + mask = BQ2562X_CHG_Q1_FULLON | BQ2562X_CHG_Q4_FULLON | BQ2562X_CHG_VINDPM_BAT_TRACK | + BQ2562X_CHG_VRECHG; + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_0, mask, value); + + if (ret != 0) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_NTC_CTRL_0, BQ2562X_NTC_MASK, - BQ2562X_NTC_MASK); - if (ret) { + value = FIELD_PREP(BQ2562X_CHG_AUTO_IBATDIS, data->auto_battery_discharging); + value |= FIELD_PREP(BQ2562X_WATCHDOG_MASK, BQ2562X_WATCHDOG_DIS); + mask = BQ2562X_CHG_AUTO_IBATDIS | BQ2562X_WATCHDOG_MASK; + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, mask, value); + if (ret != 0) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, BQ2562X_WATCHDOG_MASK, - BQ2562X_WATCHDOG_DIS); - if (ret) { + value = FIELD_PREP(BQ2562X_CTRL2_VBUS_OVP, data->vbus_ovp); + mask = BQ2562X_CTRL2_VBUS_OVP; + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, mask, value); + if (ret != 0) { return ret; } - ret = bq2562x_set_ichrg_curr(dev, data->constant_charge_current_max_ua); - if (ret) { + value = FIELD_PREP(BQ2562X_CTRL4_IBAT_PEAK, data->peak_current_protection_threshold); + value |= FIELD_PREP(BQ2562X_CTRL4_RATE, data->charge_rate_stage); + mask = BQ2562X_CTRL4_IBAT_PEAK | BQ2562X_CTRL4_RATE; + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_4, mask, value); + if (ret != 0) { return ret; } - ret = bq2562x_set_chrg_volt(dev, data->constant_charge_voltage_max_uv); + value = FIELD_PREP(BQ2562X_TIMER_DCP_BIAS, data->enable_dcp_bias); + value |= FIELD_PREP(BQ2562X_TIMER_TIMER2X_EN, data->timer2x_en); + value |= FIELD_PREP(BQ2562X_TIMER_SAFETY_TMRS, data->enable_savety_tmrs); + value |= FIELD_PREP(BQ2562X_TIMER_PRECHARGE_TMR, data->precharge_timer); + value |= FIELD_PREP(BQ2562X_TIMER_FAST_CHARGE_TMR, data->fast_charge_timer); + mask = BQ2562X_TIMER_DCP_BIAS | BQ2562X_TIMER_SAFETY_TMRS | BQ2562X_TIMER_PRECHARGE_TMR | + BQ2562X_TIMER_FAST_CHARGE_TMR | BQ2562X_TIMER_TIMER2X_EN; + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_TIMER_CTRL, mask, value); + if (ret != 0) { + return ret; + } + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_NTC_CTRL_0, BQ2562X_NTC_MASK, + FIELD_PREP(BIT(7), BQ2562X_NTC_DIS)); if (ret) { return ret; } - ret = bq2562x_set_prechrg_curr(dev, data->precharge_current_ua); + ret = bq2562x_set_input_volt_lim(dev, data->input_voltage_min_uv); if (ret) { return ret; } - ret = bq2562x_set_term_curr(dev, data->charge_term_current_ua); + ret = bq2562x_set_input_curr_lim(dev, data->input_current_max_ua); if (ret) { return ret; } - ret = bq2562x_set_input_volt_lim(dev, data->input_voltage_min_uv); + ret = bq2562x_set_term_curr(dev, data->charge_term_current_ua); if (ret) { return ret; } - ret = bq2562x_set_input_curr_lim(dev, data->input_current_max_ua); + ret = bq2562x_set_prechrg_curr(dev, data->precharge_current_ua); if (ret) { return ret; } @@ -800,6 +1092,7 @@ static void bq2562x_gpio_callback(const struct device *dev, struct gpio_callback ret = k_work_submit(&data->int_routine_work); if (ret < 0) { + (void)bq2562x_enable_interrupt_pin(data->dev, true); LOG_WRN("Could not submit int work: %d", ret); } } @@ -938,6 +1231,20 @@ static DEVICE_API(charger, bq2562x_driver_api) = { .switching_converter_freq = DT_INST_PROP(inst, ti_switching_converter_freq), \ .switching_converter_strength = \ DT_INST_PROP(inst, ti_switching_converter_strength), \ + .q1_fullon = DT_INST_PROP(inst, ti_q1_fullon), \ + .q4_fullon = DT_INST_PROP(inst, ti_q4_fullon), \ + .vindpm_bat_track = DT_INST_PROP(inst, ti_vindpm_bat_track), \ + .verchg_bat_offset = DT_INST_PROP(inst, ti_verchg_bat_offset), \ + .enable_dcp_bias = DT_INST_PROP(inst, ti_enable_dcp_bias), \ + .enable_savety_tmrs = DT_INST_PROP(inst, ti_enable_savety_tmrs), \ + .timer2x_en = DT_INST_PROP(inst, ti_timer2x_en), \ + .precharge_timer = DT_INST_PROP(inst, ti_precharge_timer), \ + .fast_charge_timer = DT_INST_PROP(inst, ti_fast_charge_timer), \ + .auto_battery_discharging = DT_INST_PROP(inst, ti_auto_battery_discharging), \ + .vbus_ovp = DT_INST_PROP(inst, ti_vbus_ovp), \ + .peak_current_protection_threshold = \ + DT_INST_PROP(inst, ti_peak_current_protection_threshold), \ + .charge_rate_stage = DT_INST_PROP(inst, ti_charge_rate_stage), \ }; \ \ DEVICE_DT_INST_DEFINE(inst, bq2562x_init, NULL, &bq2562x_data_##inst, \ diff --git a/drivers/charger/charger_bq2562x.h b/drivers/charger/charger_bq2562x.h index 9f57918975845..0dabceb7bbb0e 100644 --- a/drivers/charger/charger_bq2562x.h +++ b/drivers/charger/charger_bq2562x.h @@ -129,25 +129,46 @@ #define BQ2562X_TERMCHRG_I_LSB_MSK GENMASK(7, 3) /* REG0x14_Charge_Control_0 */ +#define BQ2562X_CHG_Q1_FULLON BIT(7) +#define BQ2562X_CHG_Q4_FULLON BIT(6) #define BQ2562X_CHG_CTL_ITRICKLE BIT(5) +#define BQ2562X_CHG_VINDPM_BAT_TRACK BIT(1) +#define BQ2562X_CHG_VRECHG BIT(0) #define BQ2562X_CHG_CTL_ITRICKLE_DEF_UA 20000 #define BQ2562X_CHG_CTL_ITRICKLE_MAX_UA 80000 +/* REG0x15_Charge_Timer_Control */ +#define BQ2562X_TIMER_FORCE_INDET BIT(6) +#define BQ2562X_TIMER_DCP_BIAS BIT(4) +#define BQ2562X_TIMER_TIMER2X_EN BIT(3) +#define BQ2562X_TIMER_SAFETY_TMRS BIT(2) +#define BQ2562X_TIMER_PRECHARGE_TMR BIT(1) +#define BQ2562X_TIMER_FAST_CHARGE_TMR BIT(0) + /* REG0x16_Charger_Control_1 */ -#define BQ2562X_CHRG_EN BIT(5) -#define BQ2562X_WATCHDOG_MASK GENMASK(1, 0) -#define BQ2562X_WATCHDOG_DIS 0 +#define BQ2562X_CHG_AUTO_IBATDIS BIT(7) +#define BQ2562X_CHRG_EN BIT(5) +#define BQ2562X_WATCHDOG_MASK GENMASK(1, 0) +#define BQ2562X_WATCHDOG_DIS 0 /* REG0x17_Charger_Control_2 */ #define BQ2562X_CTRL2_REG_RST BIT(7) #define BQ2562X_CTRL2_TREG BIT(6) #define BQ2562X_CTRL2_SET_CONV_FREQ GENMASK(5, 4) #define BQ2562X_CTRL2_SET_CONV_STRN GENMASK(3, 2) +#define BQ2562X_CTRL2_VBUS_OVP BIT(0) + +/* REG0x19_Charger_Control_4 */ +#define BQ2562X_CTRL4_IBAT_PEAK GENMASK(7, 6) +#define BQ2562X_CTRL4_RATE GENMASK(1, 0) /* REG0x1A_NTC_Control_0 */ #define BQ2562X_NTC_MASK BIT(7) #define BQ2562X_NTC_DIS 1 +/* REG0x1D_Charger_Status_0 */ +#define BQ2562X_CHG_TMR_STATE BIT(1) + /* REG0x1E_Charger_Status_1 */ #define BQ2562X_CHG_STAT_MSK GENMASK(4, 3) #define BQ2562X_NOT_CHRGING 0 @@ -213,6 +234,9 @@ #define BQ2562X_ADC_VBAT_MASK GENMASK(12, 1) #define BQ2562X_ADC_VBAT_SHIFT 1 +/* REG0x36_TDIE_ADC */ +#define BQ2562X_ADC_TDIE_MASK GENMASK(11, 0) + /* REG0x38_Part_Information */ #define BQ2562X_PART_NO_MASK GENMASK(5, 3) diff --git a/dts/bindings/charger/ti,bq2562x.yaml b/dts/bindings/charger/ti,bq2562x.yaml index 501ca9cd98899..c1823c80c1d89 100644 --- a/dts/bindings/charger/ti,bq2562x.yaml +++ b/dts/bindings/charger/ti,bq2562x.yaml @@ -50,7 +50,7 @@ properties: ti,min-sys-voltage-microvolt: type: int - default: 3600000 + default: 3520000 description: | Minimum system voltage in micro volts with a 100000 micro volt step. @@ -92,7 +92,7 @@ properties: ti,switching-converter-strength: type: int - default: 0 + default: 3 enum: - 0 - 1 @@ -102,3 +102,154 @@ properties: 0: weak 1: normal 3: strong + + ti,q1-fullon: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Forces RBFET (Q1) into low resistance state (26 m¦¸) , regardless of IINDPM setting. + 0: RBFET RDSON determined by IINDPM setting + 1: RBFET RDSON is always 26 m¦¸ + + ti,q4-fullon: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Forces BATFET (Q4) into low resistance state (15 m¦¸), regardless of ICHG setting. + 0: BATFET RDSON determined by charge current + 1: BATFET RDSON is always 15 m¦¸ + + ti,vindpm-bat-track: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Sets VINDPM to track BAT voltage. Actual VINDPM is higher of the VINDPM register value and VBAT + VINDPM_BAT_TRACK. + 0: Disable function + 1: VBAT + 400 mV + + ti,verchg-bat-offset: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Battery Recharge Threshold Offset. + 0: 100 mV + 1: 200 mV + + ti,enable-dcp-bias: + type: int + default: 1 + enum: + - 0 + - 1 + description: | + Enable 600 mV bias on D+ pin whenever DCP is detected by BC1.2 detection algorithm. + 0: Disable 600 mV bias on D+ pin + 1: Enable 600 mV bias on D+ pin if DCP detected + + ti,enable-savety-tmrs: + type: int + default: 1 + enum: + - 0 + - 1 + description: | + Enable fast charge, pre-charge and trickle charge timers. + 0: Disable + 1: Enable + + ti,precharge_timer: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Set precharge safety timeout. + 0: 2.5h + 1: 0.62h + + ti,fast_charge_timer: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Set fast charge safety timeout. + 0: 12h + 1: 24h + + ti,timer2x_en: + type: int + default: 1 + enum: + - 0 + - 1 + description: | + Allow timeout-doubling in DPM mode or thermal regulation. + 0: Not allowed + 1: allowed + + ti,auto-battery-discharging: + type: int + default: 1 + enum: + - 0 + - 1 + description: | + Enable the auto battery discharging during the battery OVP fault. + 0: The charger does NOT apply a discharging current on BAT during battery OVP triggered + 1: The charger does apply a discharging current on BAT during battery OVP triggered + + ti,vbus-ovp: + type: int + default: 1 + enum: + - 0 + - 1 + description: | + Sets VBUS overvoltage protection threshold. + 0: 6.3v + 1: 18.5v + + ti,peak-current-protection-threshold: + type: int + default: 3 + enum: + - 0 + - 1 + - 2 + - 3 + description: | + Battery discharging peak current protection threshold setting. + 0: 1.5 A + 1: 3 A + 2: 6 A + 3: 12 A + + ti,charge-rate-stage: + type: int + default: 0 + enum: + - 0 + - 1 + - 2 + - 3 + description: | + The charge rate definition for the fast charge stage. + 0: 1 C + 1: 2 C + 2: 4 C + 3: 6 C \ No newline at end of file diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index e3bfb311e7dd3..d5a29cdc3a996 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -45,6 +45,8 @@ enum charger_property { /** Represents the charging algo type of the charger. */ /** Value should be of type enum charger_charge_type */ CHARGER_PROP_CHARGE_TYPE, + /** Represents USB charge type based on BC 1.2 */ + CHARGER_PROP_USB_TYPE, /** Represents the health of the charger. */ /** Value should be of type enum charger_health */ CHARGER_PROP_HEALTH, @@ -189,6 +191,22 @@ enum charger_charge_type { CHARGER_CHARGE_TYPE_BYPASS, }; +/** + * @brief Charger USB types + */ +enum charger_usb_type { + CHARGER_USB_TYPE_UNKNOWN = 0, + CHARGER_USB_TYPE_SDP, /* Standard Downstream Port */ + CHARGER_USB_TYPE_DCP, /* Dedicated Charging Port */ + CHARGER_USB_TYPE_CDP, /* Charging Downstream Port */ + CHARGER_USB_TYPE_ACA, /* Accessory Charger Adapters */ + CHARGER_USB_TYPE_C, /* Type C Port */ + CHARGER_USB_TYPE_PD, /* Power Delivery Port */ + CHARGER_USB_TYPE_PD_DRP, /* PD Dual Role Port */ + CHARGER_USB_TYPE_PD_PPS, /* PD Programmable Power Supply */ + CHARGER_USB_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */ +}; + /** * @brief Charger health conditions * @@ -283,6 +301,8 @@ union charger_propval { enum charger_status status; /** CHARGER_PROP_CHARGE_TYPE */ enum charger_charge_type charge_type; + /** CHARGER_PROP_USB_TYPE */ + enum charger_usb_type usb_type; /** CHARGER_PROP_HEALTH */ enum charger_health health; /** CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA */ diff --git a/include/zephyr/drivers/charger/bq2562x.h b/include/zephyr/drivers/charger/bq2562x.h new file mode 100644 index 0000000000000..a2e20a58a1d38 --- /dev/null +++ b/include/zephyr/drivers/charger/bq2562x.h @@ -0,0 +1,264 @@ +/** + * Copyright 2025 Testo SE & Co. KGaA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Charger APIs + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_BQ2562X_H_ +#define ZEPHYR_INCLUDE_DRIVERS_BQ2562X_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Charger Interface + * @defgroup charger_interface Charger Interface + * @ingroup io_interfaces + * @{ + */ + +/** + * @brief Charger current protection threshold + */ +enum charger_current_threshold { + /*setting charger current protection threshold 1.5 A*/ + CHARGER_CURRENT_THRESHOLD_1_5_A = 0, + /*setting charger current protection threshold 3 A*/ + CHARGER_CURRENT_THRESHOLD_3_A = 1, + /*setting charger current protection threshold 6 A*/ + CHARGER_CURRENT_THRESHOLD_6_A = 2, + /*setting charger current protection threshold 12 A*/ + CHARGER_CURRENT_THRESHOLD_12_A = 3, +}; + +/** + * @brief The charge rate definition for the fast charge stage + */ +enum charger_rate { + /*setting charge rate 1 C*/ + CHARGER_RATE_1_C = 0, + /*setting charge rate 2 C*/ + CHARGER_RATE_2_C = 1, + /*setting charge rate 4 C*/ + CHARGER_RATE_4_C = 2, + /*setting charge rate 6 C*/ + CHARGER_RATE_6_C = 3, +}; + +/** + * @brief Battery Recharge Threshold Offset + */ +enum charger_recharge_threshold_offset { + /*setting recharge threshold offset 100 mV*/ + CHARGER_VREG_100_MV = 0, + /*setting recharge threshold offset 200 mV*/ + CHARGER_VREG_200_MV = 1, +}; + +/** + * @brief Whether to turn on the ADC sampling function of the charging chip + */ +enum charger_battery_adc_sampling { + /* turn off the ADC sampling function of the charging chip*/ + CHARGER_ADC_DISABLE = 0, + /* turn on the ADC sampling function of the charging chip*/ + CHARGER_ADC_ENABLE = 1, +}; + +/** + * @brief Force D+/D- detection + */ +enum charger_dpdm_detection { + /* Do not force DPDM detection*/ + CHARGER_INDET_DISABLE = 0, + /* Force DPDM algorithm detection*/ + CHARGER_INDET_ENABLE = 1, +}; + +/** + * @brief Fast charge, trickle charge and pre-charge timer status + */ +enum charger_timer_state { + /*charge timer is normal*/ + CHARGER_TMR_STATE_NORMAL = 0, + /*charge timer is expired*/ + CHARGER_TMR_STATE_TIMER_EXPIRED = 1, +}; + +/** + * @brief Watchdog timer status + */ +enum charger_watchdog_state { + /*watchdog timer is disabled*/ + CHARGER_WDT_DISABLE = 0, + /*watchdog 50s timer is enabled*/ + CHARGER_WDT_50S, + /*watchdog 100S timer is enabled*/ + CHARGER_WDT_100S, + /*watchdog 200S timer is enabled*/ + CHARGER_WDT_200S, +}; + +/** + * @brief config the NTC feedback state + */ +enum charger_ntc_state { + /*the TS feedback state is not ignored*/ + CHARGER_NTC_NOT_IGNORE = 0, + /*the TS feedback state is ignored*/ + CHARGER_NTC_IGNORE, +}; + +/** + * @brief Set the charge current threshold for the bq2562x charger. + * + * This function configures the charge current threshold on the bq2562x charger + * device. The charge current threshold determines the point at which the charger + * switches between different charging states. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param current_threshold The desired charge current threshold to set. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_set_charge_current_threshold(const struct device *dev, + enum charger_current_threshold current_threshold); + +/** + * @brief Set the charge rate for the bq2562x charger. + * + * This function sets the charge rate on the bq2562x charger device. The charge + * rate determines the speed at which the battery is charged. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param charge_rate The desired charge rate to set. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_set_charge_rate(const struct device *dev, enum charger_rate charge_rate); + +/** + * @brief Set the battery recharge threshold offset for the bq2562x charger. + * + * This function configures the recharge threshold offset on the bq2562x charger + * device. The recharge threshold determines the voltage level at which the + * charger considers the battery to be in need of recharging. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param offset The desired recharge threshold offset to set. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_set_battery_recharge_threshold_offset(const struct device *dev, + enum charger_recharge_threshold_offset offset); + +/** + * @brief Enable or disable ADC sampling for the bq2562x charger. + * + * This function enables or disables the ADC (Analog-to-Digital Converter) + * sampling feature on the bq2562x charger device. ADC sampling is used to + * measure various electrical parameters. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param enable Flag to enable or disable ADC sampling. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_set_adc_sampling(const struct device *dev, enum charger_battery_adc_sampling enable); + +/** + * @brief Enable or disable DPDM detection for the bq2562x charger. + * + * This function enables or disables the DPDM (Data Pair Positive and Data Pair + * Negative) detection feature on the bq2562x charger device. DPDM detection is + * used for USB charging port detection. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param enable Flag to enable or disable DPDM detection. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_set_dpdm_detection(const struct device *dev, enum charger_dpdm_detection enable); + +/** + * @brief Get the timer status of the bq2562x charger. + * + * This function retrieves the current state of a specific timer on the bq2562x + * charger device. Timers are used to manage various charging and protection + * operations. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param state Pointer to store the retrieved timer state. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_get_timer_status(const struct device *dev, enum charger_timer_state *state); + +/** + * @brief Get the TDIE ADC value for the bq2562x charger. + * + * This function retrieves the ADC (Analog-to-Digital Converter) value + * corresponding to the temperature of the bq2562x charger's die. This is used + * for temperature monitoring and protection. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param temperature Pointer to store the retrieved temperature value. + * + * @return 0 on success, negative error code on failure. + */ +int bq2562x_get_tdie_adc(const struct device *dev, int32_t *temperature); + +/** + * @brief Set the watchdog timer state for the bq2562x charger + * + * This function configures the watchdog timer functionality of the bq2562x + * charger device. The watchdog timer can be disabled or set to different timeout + * periods (50s, 100s, or 200s) to monitor system operation and trigger protective + * actions if the timer expires without being reset. + * + * @param dev Pointer to the device structure representing the bq2562x charger + * @param watchdog_state The desired watchdog timer state to set + * + * @retval 0 If successful + * @retval -ENODEV If the device is not available or not ready + * @retval -EIO If there was an I/O error while communicating with the device + * @retval -EINVAL If an invalid watchdog state is provided + */ +int bq2562x_config_watchdog(const struct device *dev, enum charger_watchdog_state watchdog_state); + +/** + * @brief Configure the NTC feedback state for the bq2562x charger. + * + * This function configures the NTC (Negative Temperature Coefficient) feedback + * state of the bq2562x charger device. When enabled, the NTC feedback is used + * for temperature monitoring and control during charging. When disabled, the + * NTC feedback state is ignored by the charger. + * + * @param dev Pointer to the device structure representing the bq2562x charger. + * @param state The desired NTC feedback state to configure. + * + * @retval 0 If successful + * @retval -ENODEV If the device is not available or not ready + * @retval -EIO If there was an I/O error while communicating with the device + * @retval -EINVAL If an invalid NTC state is provided + */ +int bq2562x_config_ntc_feedback(const struct device *dev, enum charger_ntc_state state); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_BQ2562X_H_ */