diff --git a/drivers/charger/Kconfig.bq2562x b/drivers/charger/Kconfig.bq2562x index a91e149b97d12..3c231b5850e6f 100644 --- a/drivers/charger/Kconfig.bq2562x +++ b/drivers/charger/Kconfig.bq2562x @@ -4,7 +4,8 @@ config CHARGER_BQ2562X bool "BQ2562X Battery Charger" default y + depends on DT_HAS_TI_BQ2562X_CHARGER_ENABLED depends on DT_HAS_TI_BQ2562X_ENABLED - select I2C + select MFD help - Enable I2C-based driver for the TI BQ2562X Battery Charger. + Enable MFD-based driver for the TI BQ2562X Battery Charger. diff --git a/drivers/charger/charger_bq2562x.c b/drivers/charger/charger_bq2562x.c index 3d26b94084cec..c94207a8f5b77 100644 --- a/drivers/charger/charger_bq2562x.c +++ b/drivers/charger/charger_bq2562x.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT ti_bq2562x +#define DT_DRV_COMPAT ti_bq2562x_charger #include "charger_bq2562x.h" @@ -13,25 +13,24 @@ #include #include #include -#include #include #include #include -LOG_MODULE_REGISTER(ti_bq25620, CONFIG_CHARGER_LOG_LEVEL); +#include + +LOG_MODULE_REGISTER(ti_bq25620_charger, CONFIG_CHARGER_LOG_LEVEL); struct bq2562x_config { - struct i2c_dt_spec i2c; + const struct device *mfd; struct gpio_dt_spec ce_gpio; - struct gpio_dt_spec int_gpio; }; struct bq2562x_data { const struct device *dev; - struct gpio_callback gpio_cb; + struct bq2562x_mfd_callback bq2562x_cb; charger_status_notifier_t charger_status_notifier; charger_online_notifier_t charger_online_notifier; - struct k_work int_routine_work; uint32_t constant_charge_current_max_ua; uint32_t constant_charge_voltage_max_uv; uint32_t precharge_current_ua; @@ -48,11 +47,6 @@ struct bq2562x_data { enum charger_online online; }; -enum bq2562x_id { - BQ25620, - BQ25622, -}; - static bool bq2562x_get_charge_enable(const struct device *dev) { const struct bq2562x_config *const config = dev->config; @@ -65,7 +59,7 @@ static bool bq2562x_get_charge_enable(const struct device *dev) ce_pin = gpio_pin_get_dt(&config->ce_gpio); } - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, &chrg_ctrl_0); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, &chrg_ctrl_0); if (ret) { return ret; } @@ -92,8 +86,8 @@ static int bq2562x_set_charge_enable(const struct device *dev, const bool enable } } - return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, BQ2562X_CHRG_EN, - enable ? BQ2562X_CHRG_EN : 0); + return mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, BQ2562X_CHRG_EN, + (enable ? BQ2562X_CHRG_EN : 0)); } /* Charge Current Limit */ @@ -103,7 +97,7 @@ static int bq2562x_get_ichrg_curr(const struct device *dev, uint32_t *current_ua uint8_t ichg[2]; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_CHRG_I_LIM_LSB, ichg, ARRAY_SIZE(ichg)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_CHRG_I_LIM_LSB, ichg, ARRAY_SIZE(ichg)); if (ret) { return ret; } @@ -130,7 +124,7 @@ static int bq2562x_set_ichrg_curr(const struct device *dev, uint32_t chrg_curr) 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)); + ret = mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_CHRG_I_LIM_LSB, ichg, ARRAY_SIZE(ichg)); (void)bq2562x_set_charge_enable(dev, 1); @@ -144,7 +138,7 @@ static int bq2562x_get_chrg_volt(const struct device *dev, uint32_t *voltage_uv) uint8_t chrg_volt[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_CHRG_V_LIM_LSB, chrg_volt, + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_CHRG_V_LIM_LSB, chrg_volt, ARRAY_SIZE(chrg_volt)); if (ret) { return ret; @@ -169,7 +163,7 @@ static int bq2562x_set_chrg_volt(const struct device *dev, uint32_t chrg_volt) volt[1] = (chrg_volt >> 8) & BQ2562X_VREG_MSB_MSK; volt[0] = chrg_volt & BQ2562X_VREG_LSB_MSK; - return i2c_burst_write_dt(&config->i2c, BQ2562X_CHRG_V_LIM_LSB, volt, ARRAY_SIZE(volt)); + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_CHRG_V_LIM_LSB, volt, ARRAY_SIZE(volt)); } /* Input Current Limit */ @@ -179,7 +173,7 @@ static int bq2562x_get_input_curr_lim(const struct device *dev, uint32_t *curren uint8_t ilim[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_INPUT_I_LIM_LSB, ilim, ARRAY_SIZE(ilim)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_INPUT_I_LIM_LSB, ilim, ARRAY_SIZE(ilim)); if (ret) { return ret; } @@ -201,7 +195,7 @@ static int bq2562x_set_input_curr_lim(const struct device *dev, int iindpm) ilim[0] = iindpm & BQ2562X_IINDPM_LSB_MSK; ilim[1] = (iindpm >> 8) & BQ2562X_IINDPM_MSB_MSK; - return i2c_burst_write_dt(&config->i2c, BQ2562X_INPUT_I_LIM_LSB, ilim, ARRAY_SIZE(ilim)); + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_INPUT_I_LIM_LSB, ilim, ARRAY_SIZE(ilim)); } /* Input Voltage Limit */ @@ -211,7 +205,7 @@ static int bq2562x_get_input_volt_lim(const struct device *dev, uint32_t *voltag uint8_t vlim[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_INPUT_V_LIM_LSB, vlim, ARRAY_SIZE(vlim)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_INPUT_V_LIM_LSB, vlim, ARRAY_SIZE(vlim)); if (ret) { return ret; } @@ -233,7 +227,7 @@ static int bq2562x_set_input_volt_lim(const struct device *dev, int vindpm) vlim[1] = (vindpm >> 8) & BQ2562X_VINDPM_MSB_MSK; vlim[0] = vindpm & BQ2562X_VINDPM_LSB_MSK; - return i2c_burst_write_dt(&config->i2c, BQ2562X_INPUT_V_LIM_LSB, vlim, ARRAY_SIZE(vlim)); + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_INPUT_V_LIM_LSB, vlim, ARRAY_SIZE(vlim)); } /* Minimal System Voltage */ @@ -248,7 +242,7 @@ static int bq2562x_set_min_sys_volt(const struct device *dev, int vsysmin) vlim[1] = (vsysmin >> 8) & BQ2562X_VSYSMIN_V_MSB_MSK; vlim[0] = vsysmin & BQ2562X_VSYSMIN_V_LSB_MSK; - return i2c_burst_write_dt(&config->i2c, BQ2562X_MIN_SYS_V_LSB, vlim, ARRAY_SIZE(vlim)); + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_MIN_SYS_V_LSB, vlim, ARRAY_SIZE(vlim)); } /* Pre-charge Control */ @@ -258,7 +252,7 @@ static int bq2562x_get_prechrg_curr(const struct device *dev, uint32_t *current_ uint8_t prechrg_curr[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_PRECHRG_CTRL_LSB, prechrg_curr, + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_PRECHRG_CTRL_LSB, prechrg_curr, ARRAY_SIZE(prechrg_curr)); if (ret) { return ret; @@ -284,7 +278,7 @@ static int bq2562x_set_prechrg_curr(const struct device *dev, int pre_current) prechrg_curr[1] = (pre_current >> 8) & BQ2562X_PRECHRG_I_MSB_MSK; prechrg_curr[0] = pre_current & BQ2562X_PRECHRG_I_LSB_MSK; - ret = i2c_burst_write_dt(&config->i2c, BQ2562X_PRECHRG_CTRL_LSB, prechrg_curr, + ret = mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_PRECHRG_CTRL_LSB, prechrg_curr, ARRAY_SIZE(prechrg_curr)); (void)bq2562x_set_charge_enable(dev, 1); @@ -299,7 +293,7 @@ static int bq2562x_get_term_curr(const struct device *dev, uint32_t *current_ua) uint8_t iterm[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_TERM_CTRL_LSB, iterm, ARRAY_SIZE(iterm)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_TERM_CTRL_LSB, iterm, ARRAY_SIZE(iterm)); if (ret) { return ret; } @@ -321,7 +315,7 @@ static int bq2562x_set_term_curr(const struct device *dev, int term_current) iterm[1] = (term_current >> 8) & BQ2562X_TERMCHRG_I_MSB_MSK; iterm[0] = term_current & BQ2562X_TERMCHRG_I_LSB_MSK; - return i2c_burst_write_dt(&config->i2c, BQ2562X_TERM_CTRL_LSB, iterm, ARRAY_SIZE(iterm)); + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_TERM_CTRL_LSB, iterm, ARRAY_SIZE(iterm)); } static int bq2562x_get_vbat_adc(const struct device *dev, uint32_t *vbat) @@ -330,7 +324,7 @@ static int bq2562x_get_vbat_adc(const struct device *dev, uint32_t *vbat) uint8_t vbat_adc[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_ADC_VBAT_LSB, vbat_adc, ARRAY_SIZE(vbat_adc)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_VBAT_LSB, vbat_adc, ARRAY_SIZE(vbat_adc)); if (ret) { return ret; } @@ -347,7 +341,7 @@ static int bq2562x_get_vbus_adc(const struct device *dev, uint32_t *volt) uint8_t vbus_adc[2] = {0}; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_ADC_VBUS_LSB, vbus_adc, ARRAY_SIZE(vbus_adc)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_VBUS_LSB, vbus_adc, ARRAY_SIZE(vbus_adc)); if (ret) { return ret; } @@ -365,7 +359,7 @@ static int bq2562x_get_ibat_adc(const struct device *dev, int32_t *ibat) uint16_t temp; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_ADC_IBAT_LSB, ibat_adc, ARRAY_SIZE(ibat_adc)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_IBAT_LSB, ibat_adc, ARRAY_SIZE(ibat_adc)); if (ret) { return ret; } @@ -388,7 +382,7 @@ static int bq2562x_get_ibus_adc(const struct device *dev, int32_t *ibus) uint16_t temp; int ret; - ret = i2c_burst_read_dt(&config->i2c, BQ2562X_ADC_IBUS_LSB, ibus_adc, ARRAY_SIZE(ibus_adc)); + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_IBUS_LSB, ibus_adc, ARRAY_SIZE(ibus_adc)); if (ret) { return ret; } @@ -411,7 +405,7 @@ static int bq2562x_get_online_status(const struct device *dev, enum charger_onli int online_status; int ret; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_STAT_1, &chrg_stat_1); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_STAT_1, &chrg_stat_1); if (ret) { return ret; } @@ -432,7 +426,7 @@ static int bq2562x_get_health(const struct device *dev, enum charger_health *hea uint8_t fault; int ret; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_FAULT_STAT_0, &fault); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_FAULT_STAT_0, &fault); if (ret) { return ret; } @@ -480,7 +474,7 @@ static int bq2562x_get_charger_type(const struct device *dev, enum charger_charg int32_t ibat, itrickle_max; int ret; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_STAT_1, &chrg_stat_1); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_STAT_1, &chrg_stat_1); if (ret) { return ret; } @@ -503,7 +497,7 @@ static int bq2562x_get_charger_type(const struct device *dev, enum charger_charg break; } - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_0, &chrg_ctl); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_0, &chrg_ctl); if (ret) { break; } @@ -537,7 +531,7 @@ static int bq2562x_get_charger_status(const struct device *dev, enum charger_sta uint8_t type, status; int ret; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_CHRG_STAT_1, &chrg_stat_1); + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_STAT_1, &chrg_stat_1); if (ret) { return ret; } @@ -657,19 +651,19 @@ static int bq2562x_set_heat_mgmt(const struct device *dev) struct bq2562x_data *data = dev->data; int ret; - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_SET_CONV_STRN, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_SET_CONV_STRN, data->switching_converter_strength << 2); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_SET_CONV_FREQ, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_SET_CONV_FREQ, data->switching_converter_freq << 4); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_TREG, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_TREG, data->thermal_regulation_threshold << 6); if (ret) { return ret; @@ -684,19 +678,19 @@ static int bq2562x_hw_init(const struct device *dev) struct bq2562x_data *data = dev->data; int ret; - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_REG_RST, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_REG_RST, BQ2562X_CTRL2_REG_RST); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_NTC_CTRL_0, BQ2562X_NTC_MASK, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_NTC_CTRL_0, BQ2562X_NTC_MASK, BQ2562X_NTC_MASK); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, BQ2562X_WATCHDOG_MASK, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, BQ2562X_WATCHDOG_MASK, BQ2562X_WATCHDOG_DIS); if (ret) { return ret; @@ -738,12 +732,12 @@ static int bq2562x_hw_init(const struct device *dev) } /* ADC 12 bit resolution */ - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_ADC_CTRL, BQ2562X_ADC_SAMPLE, 0); + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_ADC_CTRL, BQ2562X_ADC_SAMPLE, 0); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_ADC_CTRL, BQ2562X_ADC_EN, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_ADC_CTRL, BQ2562X_ADC_EN, BQ2562X_ADC_EN); if (ret) { return ret; @@ -752,26 +746,9 @@ static int bq2562x_hw_init(const struct device *dev) return 0; } -static int bq2562x_enable_interrupt_pin(const struct device *dev, bool enabled) +static void bq2562x_int_work_handler(const struct device *dev) { - const struct bq2562x_config *const config = dev->config; - gpio_flags_t flags; - int ret; - - flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; - - ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, flags); - if (ret < 0) { - LOG_ERR("Could not %s interrupt GPIO callback: %d", enabled ? "enable" : "disable", - ret); - } - - return ret; -} - -static void bq2562x_int_routine_work_handler(struct k_work *work) -{ - struct bq2562x_data *data = CONTAINER_OF(work, struct bq2562x_data, int_routine_work); + struct bq2562x_data *data = dev->data; union charger_propval val; int ret; @@ -788,20 +765,6 @@ static void bq2562x_int_routine_work_handler(struct k_work *work) data->charger_online_notifier(val.online); } } - (void)bq2562x_enable_interrupt_pin(data->dev, true); -} - -static void bq2562x_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) -{ - struct bq2562x_data *data = CONTAINER_OF(cb, struct bq2562x_data, gpio_cb); - int ret; - - (void)bq2562x_enable_interrupt_pin(data->dev, false); - - ret = k_work_submit(&data->int_routine_work); - if (ret < 0) { - LOG_WRN("Could not submit int work: %d", ret); - } } static int bq2562x_configure_interrupt(const struct device *dev) @@ -810,48 +773,32 @@ static int bq2562x_configure_interrupt(const struct device *dev) struct bq2562x_data *data = dev->data; int ret; - k_work_init(&data->int_routine_work, bq2562x_int_routine_work_handler); - if (!gpio_is_ready_dt(&config->int_gpio)) { - LOG_ERR("Interrupt GPIO device not ready"); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); - if (ret < 0) { - LOG_ERR("Could not configure interrupt GPIO"); - return ret; - } - - gpio_init_callback(&data->gpio_cb, bq2562x_gpio_callback, BIT(config->int_gpio.pin)); - ret = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb); - if (ret < 0) { - LOG_ERR("Could not add interrupt GPIO callback"); - return ret; - } - /* enable status and online interrupt */ - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_MSK_0, BQ2562X_CHG_MSK_0_CLR, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_MSK_0, BQ2562X_CHG_MSK_0_CLR, BQ2562X_CHG_MSK_0_CLR); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_FAULT_MSK_0, BQ2562X_FAULT_MSK_0_CLR, + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_FAULT_MSK_0, BQ2562X_FAULT_MSK_0_CLR, BQ2562X_FAULT_MSK_0_CLR); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_MSK_1, BQ2562X_CHG_MSK, 0); + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_MSK_1, BQ2562X_CHG_MSK, 0); if (ret) { return ret; } - ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_MSK_1, BQ2562X_VBUS_MSK, 0); + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_MSK_1, BQ2562X_VBUS_MSK, 0); if (ret) { return ret; } - (void)bq2562x_enable_interrupt_pin(data->dev, true); + + data->bq2562x_cb.cb = bq2562x_int_work_handler; + data->bq2562x_cb.dev = dev; + mfd_bq2562x_register_interrupt_callback(config->mfd, &data->bq2562x_cb); return 0; } @@ -860,20 +807,9 @@ static int bq2562x_init(const struct device *dev) { const struct bq2562x_config *const config = dev->config; struct bq2562x_data *data = dev->data; - uint8_t val; int ret; data->dev = dev; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_PART_INFO, &val); - if (ret) { - return ret; - } - - val = FIELD_GET(BQ2562X_PART_NO_MASK, val); - if (val == BQ25622) { - return -ENOTSUP; - } - /* charge enable */ if (config->ce_gpio.port != NULL) { if (!gpio_is_ready_dt(&config->ce_gpio)) { @@ -899,11 +835,9 @@ static int bq2562x_init(const struct device *dev) return ret; } - if (config->int_gpio.port != NULL) { - ret = bq2562x_configure_interrupt(dev); - if (ret) { - return ret; - } + ret = bq2562x_configure_interrupt(dev); + if (ret) { + return ret; } return ret; @@ -915,33 +849,32 @@ static DEVICE_API(charger, bq2562x_driver_api) = { .charge_enable = bq2562x_set_charge_enable, }; -#define BQ2562X_INIT(inst) \ - \ - static const struct bq2562x_config bq2562x_config_##inst = { \ - .i2c = I2C_DT_SPEC_INST_GET(inst), \ - .ce_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, ce_gpios, {}), \ - .int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {}), \ - }; \ - \ - static struct bq2562x_data bq2562x_data_##inst = { \ - .constant_charge_current_max_ua = \ - DT_INST_PROP(inst, constant_charge_current_max_microamp), \ - .constant_charge_voltage_max_uv = \ - DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ - .precharge_current_ua = DT_INST_PROP(inst, precharge_current_microamp), \ - .charge_term_current_ua = DT_INST_PROP(inst, charge_term_current_microamp), \ - .min_sys_voltage_uv = DT_INST_PROP(inst, ti_min_sys_voltage_microvolt), \ - .input_voltage_min_uv = DT_INST_PROP(inst, ti_input_voltage_limit_microvolt), \ - .input_current_max_ua = DT_INST_PROP(inst, ti_input_current_limit_microamp), \ - .thermal_regulation_threshold = \ - DT_INST_PROP(inst, ti_thermal_regulation_threshold), \ - .switching_converter_freq = DT_INST_PROP(inst, ti_switching_converter_freq), \ - .switching_converter_strength = \ - DT_INST_PROP(inst, ti_switching_converter_strength), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(inst, bq2562x_init, NULL, &bq2562x_data_##inst, \ - &bq2562x_config_##inst, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \ +#define BQ2562X_INIT(n) \ + \ + static const struct bq2562x_config bq2562x_config_##n = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .ce_gpio = GPIO_DT_SPEC_INST_GET_OR(n, ce_gpios, {}), \ + }; \ + \ + static struct bq2562x_data bq2562x_data_##n = { \ + .constant_charge_current_max_ua = \ + DT_INST_PROP(n, constant_charge_current_max_microamp), \ + .constant_charge_voltage_max_uv = \ + DT_INST_PROP(n, constant_charge_voltage_max_microvolt), \ + .precharge_current_ua = DT_INST_PROP(n, precharge_current_microamp), \ + .charge_term_current_ua = DT_INST_PROP(n, charge_term_current_microamp), \ + .min_sys_voltage_uv = DT_INST_PROP(n, ti_min_sys_voltage_microvolt), \ + .input_voltage_min_uv = DT_INST_PROP(n, ti_input_voltage_limit_microvolt), \ + .input_current_max_ua = DT_INST_PROP(n, ti_input_current_limit_microamp), \ + .thermal_regulation_threshold = \ + DT_INST_PROP(n, ti_thermal_regulation_threshold), \ + .switching_converter_freq = DT_INST_PROP(n, ti_switching_converter_freq), \ + .switching_converter_strength = \ + DT_INST_PROP(n, ti_switching_converter_strength), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, bq2562x_init, NULL, &bq2562x_data_##n, \ + &bq2562x_config_##n, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \ &bq2562x_driver_api); DT_INST_FOREACH_STATUS_OKAY(BQ2562X_INIT) diff --git a/drivers/charger/charger_bq2562x.h b/drivers/charger/charger_bq2562x.h index 9f57918975845..20235dc5a668f 100644 --- a/drivers/charger/charger_bq2562x.h +++ b/drivers/charger/charger_bq2562x.h @@ -1,5 +1,5 @@ /* - * Copyright 2025 Linumiz + * Copyright 2025 Linumiz GmbH * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +7,6 @@ #ifndef ZEPHYR_DRIVERS_CHARGER_BQ2562X_H_ #define ZEPHYR_DRIVERS_CHARGER_BQ2562X_H_ -#define BQ2562X_RESERVED_LSB 0x00 -#define BQ2562X_RESERVED_MSB 0x01 #define BQ2562X_CHRG_I_LIM_LSB 0x02 #define BQ2562X_CHRG_I_LIM_MSB 0x03 #define BQ2562X_CHRG_V_LIM_LSB 0x04 @@ -17,10 +15,6 @@ #define BQ2562X_INPUT_I_LIM_MSB 0x07 #define BQ2562X_INPUT_V_LIM_LSB 0x08 #define BQ2562X_INPUT_V_LIM_MSB 0x09 -#define BQ2562X_IOTG_LSB 0x0a -#define BQ2562X_IOTG_MSB 0x0b -#define BQ2562X_VOTG_LSB 0x0c -#define BQ2562X_VOTG_MSB 0x0d #define BQ2562X_MIN_SYS_V_LSB 0x0e #define BQ2562X_MIN_SYS_V_MSB 0x0f #define BQ2562X_PRECHRG_CTRL_LSB 0x10 @@ -28,31 +22,18 @@ #define BQ2562X_TERM_CTRL_LSB 0x12 #define BQ2562X_TERM_CTRL_MSB 0x13 #define BQ2562X_CHRG_CTRL_0 0x14 -#define BQ2562X_TIMER_CTRL 0x15 -#define BQ2562X_CHRG_CTRL_1 0x16 #define BQ2562X_CHRG_CTRL_2 0x17 -#define BQ2562X_CHRG_CTRL_3 0x18 -#define BQ2562X_CHRG_CTRL_4 0x19 #define BQ2562X_NTC_CTRL_0 0x1a #define BQ2562X_NTC_CTRL_1 0x1b #define BQ2562X_NTC_CTRL_2 0x1c #define BQ2562X_CHRG_STAT_0 0x1d #define BQ2562X_CHRG_STAT_1 0x1e -#define BQ2562X_FAULT_STAT_0 0x1f -#define BQ2562X_CHRG_FLAG_0 0x20 -#define BQ2562X_CHRG_FLAG_1 0x21 -#define BQ2562X_FAULT_FLAG_0 0x22 #define BQ2562X_CHRG_MSK_0 0x23 #define BQ2562X_CHRG_MSK_1 0x24 #define BQ2562X_FAULT_MSK_0 0x25 #define BQ2562X_ADC_CTRL 0x26 -#define BQ2562X_FN_DISABE_0 0x27 -#define BQ2562X_ADC_IBUS_LSB 0x28 -#define BQ2562X_ADC_IBUS_MSB 0x29 #define BQ2562X_ADC_IBAT_LSB 0x2a #define BQ2562X_ADC_IBAT_MSB 0x2b -#define BQ2562X_ADC_VBUS_LSB 0x2c -#define BQ2562X_ADC_VBUS_MSB 0x2d #define BQ2562X_ADC_VPMID_LSB 0x2e #define BQ2562X_ADC_VPMID_MSB 0x2f #define BQ2562X_ADC_VBAT_LSB 0x30 @@ -63,7 +44,6 @@ #define BQ2562X_ADC_TS_MSB 0x35 #define BQ2562X_ADC_TDIE_LSB 0x36 #define BQ2562X_ADC_TDIE_MSB 0x37 -#define BQ2562X_PART_INFO 0x38 /* REG0x02_Charge_Current_Limit */ #define BQ2562X_ICHG_I_MIN_UA 80000 @@ -133,11 +113,6 @@ #define BQ2562X_CHG_CTL_ITRICKLE_DEF_UA 20000 #define BQ2562X_CHG_CTL_ITRICKLE_MAX_UA 80000 -/* REG0x16_Charger_Control_1 */ -#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) @@ -148,38 +123,6 @@ #define BQ2562X_NTC_MASK BIT(7) #define BQ2562X_NTC_DIS 1 -/* REG0x1E_Charger_Status_1 */ -#define BQ2562X_CHG_STAT_MSK GENMASK(4, 3) -#define BQ2562X_NOT_CHRGING 0 -#define BQ2562X_TRICKLE_CHRG 1 -#define BQ2562X_TAPER_CHRG 2 -#define BQ2562X_TOP_OFF_CHRG 3 -#define BQ2562X_PRECHG_MAX_UA 620000 - -#define BQ2562X_VBUS_STAT_MSK GENMASK(2, 0) -#define BQ2562X_USB_SDP BIT(0) -#define BQ2562X_USB_CDP BIT(1) -#define BQ2562X_USB_DCP (BIT(1) | BIT(0)) -#define BQ2562X_UNKNOWN_500MA BIT(2) -#define BQ2562X_NON_STANDARD (BIT(2) | BIT(0)) -#define BQ2562X_HVDCP (BIT(2) | BIT(1)) -#define BQ2562X_OTG_MODE (BIT(2) | BIT(1) | BIT(0)) - -/* REG0x1F_FAULT_Status_0 */ -#define BQ2562X_TEMP_TS_NORMAL 0x00 -#define BQ2562X_TEMP_COLD BIT(0) -#define BQ2562X_TEMP_HOT BIT(1) -#define BQ2562X_TEMP_COOL (BIT(1) | BIT(0)) -#define BQ2562X_TEMP_WARM BIT(2) -#define BQ2562X_TEMP_PRECOOL (BIT(2) | BIT(0)) -#define BQ2562X_TEMP_PREWARM (BIT(2) | BIT(1)) -#define BQ2562X_TEMP_PIN_BIAS_REF_FAULT (BIT(2) | BIT(1) | BIT(0)) -#define BQ2562X_TEMP_MASK GENMASK(2, 0) -#define BQ2562X_TSHUT_STAT BIT(3) -#define BQ2562X_OTG_FAULT_STAT BIT(4) -#define BQ2562X_SYS_FAULT_STAT BIT(5) -#define BQ2562X_BAT_FAULT_STAT BIT(6) -#define BQ2562X_VBUS_FAULT_STAT BIT(7) /* REG0x23_Charger_Mask_0 */ #define BQ2562X_CHG_MSK_0_CLR GENMASK(6, 0) @@ -195,25 +138,14 @@ #define BQ2562X_ADC_EN BIT(7) #define BQ2562X_ADC_SAMPLE GENMASK(5, 4) -/* REG0x28_IBUS_ADC */ -#define BQ2562X_ADC_IBUS_SHIFT 1 -#define BQ2562X_ADC_CURR_STEP_UA 2000 - /* REG0x2A_IBAT_ADC */ #define BQ2562X_ADC_IBAT_STEP_UV 4000 #define BQ2562X_ADC_IBAT_SHIFT 2 #define BQ2562X_ADC_IBAT_MASK GENMASK(15, 2) -/* REG0x2C_VBUS_ADC */ -#define BQ2562X_ADC_VBUS_STEP_UV 3970 -#define BQ2562X_ADC_VBUS_SHIFT 2 - /* REG0x30_VBAT_ADC */ #define BQ2562X_ADC_VBAT_STEP_UV 1990 #define BQ2562X_ADC_VBAT_MASK GENMASK(12, 1) #define BQ2562X_ADC_VBAT_SHIFT 1 -/* REG0x38_Part_Information */ -#define BQ2562X_PART_NO_MASK GENMASK(5, 3) - #endif /* ZEPHYR_DRIVERS_CHARGER_BQ2562X_H_ */ diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 3c477fc7da861..14f621572038a 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_MFD_MAX31790 mfd_max31790.c) zephyr_library_sources_ifdef(CONFIG_MFD_MAXQ10XX mfd_maxq10xx.c) zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c) +zephyr_library_sources_ifdef(CONFIG_MFD_BQ2562X mfd_bq2562x.c) zephyr_library_sources_ifdef(CONFIG_MFD_TLE9104 mfd_tle9104.c) zephyr_library_sources_ifdef(CONFIG_MFD_ITE_IT8801 mfd_ite_it8801.c) zephyr_library_sources_ifdef(CONFIG_MFD_ITE_IT8801_ALTCTRL mfd_it8801_altctrl.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 86a11a72b410b..4e6b79c7f95b1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -23,6 +23,7 @@ source "drivers/mfd/Kconfig.adp5585" source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.aw9523b" source "drivers/mfd/Kconfig.bd8lb600fs" +source "drivers/mfd/Kconfig.bq2562x" source "drivers/mfd/Kconfig.ds3231" source "drivers/mfd/Kconfig.max20335" source "drivers/mfd/Kconfig.max22017" diff --git a/drivers/mfd/Kconfig.bq2562x b/drivers/mfd/Kconfig.bq2562x new file mode 100644 index 0000000000000..ec259e5e3407a --- /dev/null +++ b/drivers/mfd/Kconfig.bq2562x @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +config MFD_BQ2562X + bool "BQ2562x switch multi-function device driver" + default y + depends on DT_HAS_TI_BQ2562X_ENABLED + select I2C diff --git a/drivers/mfd/mfd_bq2562x.c b/drivers/mfd/mfd_bq2562x.c new file mode 100644 index 0000000000000..96f75bb82a4ad --- /dev/null +++ b/drivers/mfd/mfd_bq2562x.c @@ -0,0 +1,202 @@ +/* + * Copyright 2025 Linumiz GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_bq2562x + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mfd_bq2562x, CONFIG_MFD_LOG_LEVEL); + +#define BQ2562X_PART_INFO 0x38 + +/* REG0x38_Part_Information */ +#define BQ2562X_PART_NO_MASK GENMASK(5, 3) + +struct mfd_bq2562x_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec int_gpio; +}; + +struct mfd_bq2562x_data { + const struct device *dev; + struct gpio_callback gpio_cb; + struct k_work int_routine_work; + sys_slist_t callback_list; +}; + +enum mfd_bq2562x_id { + BQ25620, + BQ25622, +}; + +int mfd_bq2562x_reg_update_byte_dt(const struct device *dev, uint8_t reg_addr, uint8_t mask, + uint8_t value) +{ + const struct mfd_bq2562x_config *config = dev->config; + + return i2c_reg_update_byte_dt(&config->i2c, reg_addr, mask, value); + +} + +int mfd_bq2562x_reg_read_byte_dt(const struct device *dev, uint8_t reg_addr, uint8_t *value) +{ + const struct mfd_bq2562x_config *config = dev->config; + + return i2c_reg_read_byte_dt(&config->i2c, reg_addr, value); +} + +int mfd_bq2562x_burst_read_dt(const struct device *dev, uint8_t start_addr, + uint8_t *buf, uint32_t num_bytes) +{ + const struct mfd_bq2562x_config *config = dev->config; + + return i2c_burst_read_dt(&config->i2c, start_addr, buf, num_bytes); + +} + +int mfd_bq2562x_burst_write_dt(const struct device *dev, uint8_t start_addr, + uint8_t *buf, uint32_t num_bytes) +{ + const struct mfd_bq2562x_config *config = dev->config; + + return i2c_burst_write_dt(&config->i2c, start_addr, buf, num_bytes); +} + +int mfd_bq2562x_enable_interrupt_pin(const struct device *dev, bool enabled) +{ + const struct mfd_bq2562x_config *const config = dev->config; + gpio_flags_t flags; + int ret; + + flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, flags); + if (ret < 0) { + LOG_ERR("Could not %s interrupt GPIO callback: %d", enabled ? "enable" : "disable", + ret); + } + + return ret; +} + +void mfd_bq2562x_register_interrupt_callback(const struct device *mfd, + struct bq2562x_mfd_callback *callback) +{ + struct mfd_bq2562x_data *data = mfd->data; + + sys_slist_append(&data->callback_list, &callback->node); +} + +static void mfd_bq2562x_int_work_handler(struct k_work *work) +{ + struct mfd_bq2562x_data *data = CONTAINER_OF(work, struct mfd_bq2562x_data, + int_routine_work); + struct bq2562x_mfd_callback *cb_entry; + + SYS_SLIST_FOR_EACH_CONTAINER(&data->callback_list, cb_entry, node) { + cb_entry->cb(cb_entry->dev); + } + + (void)mfd_bq2562x_enable_interrupt_pin(data->dev, true); +} + +static void mfd_bq2562x_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct mfd_bq2562x_data *data = CONTAINER_OF(cb, struct mfd_bq2562x_data, gpio_cb); + int ret; + + (void)mfd_bq2562x_enable_interrupt_pin(data->dev, false); + + ret = k_work_submit(&data->int_routine_work); + if (ret < 0) { + LOG_ERR("Could not submit int work: %d", ret); + } +} + +static int mfd_bq2562x_configure_interrupt(const struct device *dev) +{ + const struct mfd_bq2562x_config *const config = dev->config; + struct mfd_bq2562x_data *data = dev->data; + int ret; + + k_work_init(&data->int_routine_work, mfd_bq2562x_int_work_handler); + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("Interrupt GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure interrupt GPIO"); + return ret; + } + + gpio_init_callback(&data->gpio_cb, mfd_bq2562x_gpio_callback, BIT(config->int_gpio.pin)); + ret = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not add interrupt GPIO callback"); + return ret; + } + + (void)mfd_bq2562x_enable_interrupt_pin(dev, true); + + return 0; +} + +static int mfd_bq2562x_init(const struct device *dev) +{ + const struct mfd_bq2562x_config *const config = dev->config; + struct mfd_bq2562x_data *data = dev->data; + uint8_t val; + int ret; + + data->dev = dev; + + if (!i2c_is_ready_dt(&config->i2c)) { + return -ENODEV; + } + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ2562X_PART_INFO, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(BQ2562X_PART_NO_MASK, val); + if (val == BQ25622) { + return -ENOTSUP; + } + + if (config->int_gpio.port != NULL) { + ret = mfd_bq2562x_configure_interrupt(dev); + if (ret) { + return ret; + } + } + + return ret; +} + +#define BQ2562X_INIT(n) \ + \ + static const struct mfd_bq2562x_config mfd_bq2562x_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {}), \ + }; \ + \ + static struct mfd_bq2562x_data mfd_bq2562x_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, mfd_bq2562x_init, NULL, &mfd_bq2562x_data_##n, \ + &mfd_bq2562x_config_##n, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(BQ2562X_INIT) + diff --git a/drivers/usb/bc12/CMakeLists.txt b/drivers/usb/bc12/CMakeLists.txt index 31b9c3212a296..593552b57738b 100644 --- a/drivers/usb/bc12/CMakeLists.txt +++ b/drivers/usb/bc12/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/usb/usb_bc12.h) zephyr_library() +zephyr_library_sources_ifdef(CONFIG_USB_BC12_BQ25620 bc12_bq25620.c) zephyr_library_sources_ifdef(CONFIG_USB_BC12_PI3USB9201 bc12_pi3usb9201.c) zephyr_library_sources_ifdef(CONFIG_EMUL_BC12_PI3USB9201 emul_bc12_pi3usb9201.c) zephyr_include_directories_ifdef(CONFIG_EMUL_BC12_PI3USB9201 .) diff --git a/drivers/usb/bc12/Kconfig b/drivers/usb/bc12/Kconfig index 65f75966aced6..d03eacc2137cc 100644 --- a/drivers/usb/bc12/Kconfig +++ b/drivers/usb/bc12/Kconfig @@ -12,6 +12,7 @@ module = USB_BC12 module-str = usb_bc12 source "subsys/logging/Kconfig.template.log_config" +source "drivers/usb/bc12/Kconfig.bq25620" source "drivers/usb/bc12/Kconfig.pi3usb9201" endif # USB_BC12 diff --git a/drivers/usb/bc12/Kconfig.bq25620 b/drivers/usb/bc12/Kconfig.bq25620 new file mode 100644 index 0000000000000..9bd14d775256e --- /dev/null +++ b/drivers/usb/bc12/Kconfig.bq25620 @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +config USB_BC12_BQ25620 + bool "TI BQ25620" + default y + depends on DT_HAS_TI_BQ25620_BC_ENABLED + depends on DT_HAS_TI_BQ2562X_ENABLED + select MFD + help + Enable MFD-based driver for the TI BQ25620 Battery Charger. + +config BC12_BQ25620_INIT_PRIORITY + int "TI BQ25620 driver initialization priority" + default 90 + depends on USB_BC12_BQ25620 diff --git a/drivers/usb/bc12/bc12_bq25620.c b/drivers/usb/bc12/bc12_bq25620.c new file mode 100644 index 0000000000000..2192395fe1396 --- /dev/null +++ b/drivers/usb/bc12/bc12_bq25620.c @@ -0,0 +1,499 @@ +/* + * Copyright 2025 Linumiz GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_bq25620_bc + +#include "bc12_bq25620.h" + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(BQ25620_BC, CONFIG_USB_BC12_LOG_LEVEL); + +struct bc12_bq25620_config { + const struct device *mfd; + enum bc12_type charging_mode; +}; + +struct bc12_bq25620_data { + struct bc12_partner_state partner_state; + struct bq2562x_mfd_callback bq25620_cb; + bc12_callback_t result_cb; + void *result_cb_data; +}; + +static const enum bq25620_mode charging_mode_to_host_mode[] = { + [BC12_TYPE_NONE] = BQ2562X_POWER_DOWN, + [BC12_TYPE_SDP] = BQ2562X_SDP_HOST_MODE, + [BC12_TYPE_CDP] = BQ2562X_CDP_HOST_MODE, + [BC12_TYPE_DCP] = BQ2562X_DCP_HOST_MODE, +}; + +static void bq25620_notify_callback(const struct device *dev, + struct bc12_partner_state *const state) +{ + struct bc12_bq25620_data *data = dev->data; + + if (data->result_cb != NULL) { + data->result_cb(dev, state, data->result_cb_data); + } +} + +static void bq25620_update_charging_partner(const struct device *dev, + struct bc12_partner_state *const state) +{ + struct bc12_bq25620_data *data = dev->data; + + if (state) { + /* Now update callback with the new partner type */ + data->partner_state = *state; + bq25620_notify_callback(dev, state); + } else { + data->partner_state.bc12_role = BC12_DISCONNECTED; + bq25620_notify_callback(dev, NULL); + } +} + +static int bq25620_get_vbus_adc(const struct device *dev, uint32_t *volt) +{ + const struct bc12_bq25620_config *config = dev->config; + uint8_t vbus_adc[2] = {0}; + int ret; + + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_VBUS_LSB, vbus_adc, + ARRAY_SIZE(vbus_adc)); + if (ret) { + LOG_ERR("Failed to read the VBUS reg ,ret :%d", ret); + return ret; + } + + *volt = ((vbus_adc[1] << 8) | vbus_adc[0]) >> BQ2562X_ADC_VBUS_SHIFT; + *volt = *volt * BQ2562X_ADC_VBUS_STEP_UV; + + return 0; + +} + +static int bq25620_get_ibus_adc(const struct device *dev, int32_t *ibus) +{ + const struct bc12_bq25620_config *config = dev->config; + uint8_t ibus_adc[2] = {0}; + uint16_t temp; + int ret; + + ret = mfd_bq2562x_burst_read_dt(config->mfd, BQ2562X_ADC_IBUS_LSB, ibus_adc, + ARRAY_SIZE(ibus_adc)); + if (ret) { + LOG_ERR("Failed to read the IBUS reg, ret : %d", ret); + return ret; + } + + temp = sys_get_le16(ibus_adc); + if (temp & BIT(15)) { + temp = ~temp + 1; + *ibus = (temp >> BQ2562X_ADC_IBUS_SHIFT) * BQ2562X_ADC_CURR_STEP_UA * -1; + } else { + *ibus = (temp >> BQ2562X_ADC_IBUS_SHIFT) * BQ2562X_ADC_CURR_STEP_UA; + } + + return 0; +} + +static int bq25620_set_iotg(const struct device *dev, uint32_t iotg_ua) +{ + const struct bc12_bq25620_config *config = dev->config; + uint8_t curr[2] = {0}; + + iotg_ua = CLAMP(iotg_ua, BQ2562X_IOTG_MIN, BQ2562X_IOTG_MAX); + + iotg_ua = (iotg_ua / BQ2562X_IOTG_STEP_UA) << BQ2562X_IOTG_SHIFT; + curr[1] = (iotg_ua >> 8) & BQ2562X_IOTG_MSB_MSK; + curr[0] = iotg_ua & BQ2562X_IOTG_LSB_MSK; + + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_IOTG_LSB, curr, ARRAY_SIZE(curr)); +} + +static int bq25620_set_votg(const struct device *dev, uint32_t votg_uv) +{ + const struct bc12_bq25620_config *config = dev->config; + uint8_t volt[2] = {0}; + + votg_uv = CLAMP(votg_uv, BQ2562X_VOTG_MIN, BQ2562X_VOTG_MAX); + + votg_uv = (votg_uv / BQ2562X_VOTG_STEP_UV) << BQ2562X_VOTG_SHIFT; + volt[1] = (votg_uv >> 8) & BQ2562X_VOTG_MSB_MSK; + volt[0] = votg_uv & BQ2562X_VOTG_LSB_MSK; + + return mfd_bq2562x_burst_write_dt(config->mfd, BQ2562X_VOTG_LSB, volt, ARRAY_SIZE(volt)); +} + +static int bq25620_get_pd_type(const struct device *dev, struct bc12_partner_state *partner_state) +{ + const struct bc12_bq25620_config *config = dev->config; + uint8_t val; + int ret; + + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_STAT_1, &val); + if (ret) { + LOG_ERR("Failed to Read CHRG_STAT_1 Reg: %d", ret); + return ret; + } + + val = FIELD_GET(BQ2562X_VBUS_STAT_MSK, val); + + switch (val) { + case BQ2562X_USB_SDP: + partner_state->type = BC12_TYPE_SDP; + break; + case BQ2562X_USB_CDP: + partner_state->type = BC12_TYPE_CDP; + break; + case BQ2562X_HVDCP: + __fallthrough; + case BQ2562X_USB_DCP: + partner_state->type = BC12_TYPE_DCP; + break; + case BQ2562X_UNKNOWN_500MA: + partner_state->type = BC12_TYPE_UNKNOWN; + break; + case BQ2562X_NON_STANDARD: + partner_state->type = BC12_TYPE_PROPRIETARY; + break; + case BQ2562X_OTG_MODE: + partner_state->pd_partner_connected = true; + partner_state->bc12_role = BC12_CHARGING_PORT; + break; + default: + partner_state->bc12_role = BC12_DISCONNECTED; + break; + } + return ret; +} + +static void bq25620_int_work_handler(const struct device *dev) +{ + const struct bc12_bq25620_config *config = dev->config; + struct bc12_partner_state partner_state = {0}; + uint32_t vbus_uv; + int32_t ibus_ua; + uint8_t val; + int ret; + + ret = mfd_bq2562x_reg_read_byte_dt(config->mfd, BQ2562X_CHRG_FLAG_1, &val); + if (ret) { + LOG_ERR("Failed to Read CHRG_FLAG_1 Reg: %d", ret); + return; + } + + if (val & BQ2562X_VBUS_FLAG_MSK) { + partner_state.pd_partner_connected = false; + partner_state.bc12_role = BC12_PORTABLE_DEVICE; + + ret = bq25620_get_pd_type(dev, &partner_state); + if (ret) { + LOG_ERR("Failed to get pd type ret: %d", ret); + return; + } + + if (partner_state.bc12_role == BC12_DISCONNECTED) { + bq25620_update_charging_partner(dev, NULL); + return; + } else if (partner_state.bc12_role == BC12_PORTABLE_DEVICE){ + + ret = bq25620_get_ibus_adc(dev, &ibus_ua); + if (ret) { + LOG_ERR("Failed to read the IBUS ADC ret: %d", ret); + return; + } + + ret = bq25620_get_vbus_adc(dev, &vbus_uv); + if (ret) { + LOG_ERR("Failed to read the VBUS ADC ret: %d", ret); + return; + } + + partner_state.current_ua = ibus_ua; + partner_state.voltage_uv = (int)vbus_uv; + } + bq25620_update_charging_partner(dev, &partner_state); + } +} + +static int bq25620_disconnect(const struct device *dev) +{ + const struct bc12_bq25620_config *config = dev->config; + int ret; + + /* Disable interrupts during mode change */ + mfd_bq2562x_enable_interrupt_pin(config->mfd, false); + + /* Disable auto indent to stop detection in dpdm pins */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_TIMER_CTRL, + BQ2562X_TIMER_AUTO_INDET, 0); + if (ret) { + goto cleanup; + } + + /* Enable HIZ mode to put VBUS in high impedance */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, + BQ2562X_CHRG_HIZ, BQ2562X_CHRG_HIZ); + if (ret) { + goto cleanup; + } + + bq25620_update_charging_partner(dev, NULL); + +cleanup: + mfd_bq2562x_enable_interrupt_pin(config->mfd, true); + return ret; +} + +static int bq25620_set_portable_device(const struct device *dev) +{ + const struct bc12_bq25620_config *config = dev->config; + struct bc12_bq25620_data *data = dev->data; + struct bc12_partner_state partner_state; + uint32_t vbus_uv; + int32_t ibus_ua; + int ret; + + if (data->partner_state.bc12_role == BC12_PORTABLE_DEVICE) { + /* Device is already in the same mode */ + return 0; + } + + /* Disable interrupts during mode change */ + mfd_bq2562x_enable_interrupt_pin(config->mfd, false); + + /* Enable auto indet to start dpdm detection */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_TIMER_CTRL, + BQ2562X_TIMER_AUTO_INDET, BQ2562X_TIMER_AUTO_INDET); + if (ret) { + goto cleanup; + } + + /* Disable HIZ mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, + BQ2562X_CHRG_HIZ, 0); + if (ret) { + goto cleanup; + } + + /* Disable OTG mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_3, + BQ2562X_CTRL3_EN_OTG, 0); + if (ret) { + goto cleanup; + } + + /* Enable charging mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, + BQ2562X_CHRG_EN, BQ2562X_CHRG_EN); + if (ret) { + goto cleanup; + } + + /* To determine the voltage and current value of the pd partner */ + ret = bq25620_get_ibus_adc(dev, &ibus_ua); + if (ret) { + LOG_ERR("Failed to read the IBUS ADC ret : %d", ret); + return ret; + } + + ret = bq25620_get_vbus_adc(dev, &vbus_uv); + if (ret) { + LOG_ERR("Failed to read the VBUS ADC ret : %d", ret); + return ret; + } + + partner_state.bc12_role = BC12_PORTABLE_DEVICE; + ret = bq25620_get_pd_type(dev, &partner_state); + if (ret) { + return ret; + } + partner_state.current_ua = ibus_ua; + partner_state.voltage_uv = vbus_uv; + + bq25620_update_charging_partner(dev, &partner_state); + +cleanup: + mfd_bq2562x_enable_interrupt_pin(config->mfd, true); + return ret; +} + +static int bq25620_set_mode(const struct device *dev, enum bq25620_mode mode) +{ + int ret; + + ret = bq25620_set_votg(dev, BQ2562X_VOLT_UV); + if (ret) { + return ret; + } + switch(mode){ + case BQ2562X_POWER_DOWN: + ret = bq25620_set_iotg(dev, BQ2562X_POWER_NONE); + if (ret) { + return ret; + } + ret = bq25620_set_votg(dev, BQ2562X_POWER_NONE); + if (ret) { + return ret; + } + break; + case BQ2562X_SDP_HOST_MODE: + ret = bq25620_set_iotg(dev, BQ2562X_SDP_CURR_UA); + if (ret) { + return ret; + } + break; + case BQ2562X_DCP_HOST_MODE: + __fallthrough; + case BQ2562X_CDP_HOST_MODE: + ret = bq25620_set_iotg(dev, BQ2562X_CDP_CURR_UA); + if (ret) { + return ret; + } + break; + default: + LOG_ERR("Not supporting mode !!"); + return -EINVAL; + }; + return ret; +} + +static int bq25620_set_charging_mode(const struct device *dev) +{ + const struct bc12_bq25620_config *config = dev->config; + struct bc12_bq25620_data *data = dev->data; + struct bc12_partner_state partner_state; + int32_t ibus_ua; + int ret; + + if (data->partner_state.bc12_role == BC12_CHARGING_PORT) { + /* Device is already in the same mode */ + return 0; + } + + ret = bq25620_set_mode(dev, charging_mode_to_host_mode[config->charging_mode]); + if (ret) { + return ret; + } + + /* Disable interrupts during mode change */ + mfd_bq2562x_enable_interrupt_pin(config->mfd, false); + + /* Enable auto indet to start dpdm detection */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_TIMER_CTRL, + BQ2562X_TIMER_AUTO_INDET, BQ2562X_TIMER_AUTO_INDET); + if (ret) { + goto cleanup; + } + + /* Disable HIZ mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, BQ2562X_CHRG_HIZ, 0); + if (ret) { + goto cleanup; + } + + /* Disable charging mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_1, BQ2562X_CHRG_EN, 0); + if (ret) { + goto cleanup; + } + + /* Enable OTG mode */ + ret = mfd_bq2562x_reg_update_byte_dt(config->mfd, BQ2562X_CHRG_CTRL_3, + BQ2562X_CTRL3_EN_OTG, BQ2562X_CTRL3_EN_OTG); + if (ret) { + goto cleanup; + } + + /* To determine pd is connected or not */ + ret = bq25620_get_ibus_adc(dev, &ibus_ua); + if (ret) { + LOG_ERR(" Failed to read the IBUS ADC ret : %d", ret); + return ret; + } + + if (ibus_ua < 0) { + partner_state.pd_partner_connected = true; + } else { + partner_state.pd_partner_connected = false; + } + + partner_state.bc12_role = BC12_CHARGING_PORT; + bq25620_update_charging_partner(dev, &partner_state); + +cleanup: + mfd_bq2562x_enable_interrupt_pin(config->mfd, true); + return ret; +} + +static int bq25620_set_role(const struct device *dev, const enum bc12_role role) +{ + switch (role) { + case BC12_DISCONNECTED: + return bq25620_disconnect(dev); + case BC12_PORTABLE_DEVICE: + return bq25620_set_portable_device(dev); + case BC12_CHARGING_PORT: + return bq25620_set_charging_mode(dev); + default: + LOG_ERR("Unsupported BC12 role : %d", role); + return -EINVAL; + }; + + return 0; +} + +static int bq25620_set_result_cb(const struct device *dev, bc12_callback_t cb, + void *const user_data) +{ + struct bc12_bq25620_data *data = dev->data; + + data->result_cb = cb; + data->result_cb_data = user_data; + + return 0; +} + +static int bc12_bq25620_init(const struct device *dev) +{ + const struct bc12_bq25620_config *config = dev->config; + struct bc12_bq25620_data *data = dev->data; + + /* interrupt handler register for bc12 */ + data->bq25620_cb.cb = bq25620_int_work_handler; + data->bq25620_cb.dev = dev; + mfd_bq2562x_register_interrupt_callback(config->mfd, &data->bq25620_cb); + + return 0; +} + +static DEVICE_API(bc12, bc12_bq25620_driver_api) = { + .set_role = bq25620_set_role, + .set_result_cb = bq25620_set_result_cb, +}; + +#define BQ25620_INIT(n) \ + \ + static const struct bc12_bq25620_config bq25620_config_##n = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .charging_mode = DT_INST_STRING_UPPER_TOKEN(n, charging_mode), \ + }; \ + \ + static struct bc12_bq25620_data bq25620_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, bc12_bq25620_init, NULL, &bq25620_data_##n, \ + &bq25620_config_##n, POST_KERNEL, \ + CONFIG_BC12_BQ25620_INIT_PRIORITY, &bc12_bq25620_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BQ25620_INIT) diff --git a/drivers/usb/bc12/bc12_bq25620.h b/drivers/usb/bc12/bc12_bq25620.h new file mode 100644 index 0000000000000..d11ee4255d95a --- /dev/null +++ b/drivers/usb/bc12/bc12_bq25620.h @@ -0,0 +1,66 @@ +/* + * Copyright 2025 Linumiz GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_BC12_BQ25620_H_ +#define ZEPHYR_DRIVERS_BC12_BQ25620_H_ + +#define BQ2562X_IOTG_LSB 0x0a +#define BQ2562X_IOTG_MSB 0x0b +#define BQ2562X_VOTG_LSB 0x0c +#define BQ2562X_VOTG_MSB 0x0d +#define BQ2562X_TIMER_CTRL 0x15 +#define BQ2562X_CHRG_CTRL_3 0x18 +#define BQ2562X_CHRG_FLAG_1 0x21 + +/* REG0x0A_IOTG */ +#define BQ2562X_IOTG_MIN 100000 +#define BQ2562X_IOTG_MAX 2400000 +#define BQ2562X_IOTG_STEP_UA 20000 +#define BQ2562X_IOTG_SHIFT 4 +#define BQ2562X_IOTG_MSB_MSK GENMASK(3, 0) +#define BQ2562X_IOTG_LSB_MSK GENMASK(7, 4) + +/* REG0X0C_VOTG*/ +#define BQ2562X_VOTG_MIN 3840000 +#define BQ2562X_VOTG_MAX 9600000 +#define BQ2562X_VOTG_STEP_UV 80000 +#define BQ2562X_VOTG_SHIFT 6 +#define BQ2562X_VOTG_MSB_MSK GENMASK(4, 0) +#define BQ2562X_VOTG_LSB_MSK GENMASK(7, 6) + +/* REG0x15_Charger_Timer_Control */ +#define BQ2562X_TIMER_CTRL_MSK GENMASK(7, 0) +#define BQ2562X_TIMER_DIS_STAT BIT(7) +#define BQ2562X_TIMER_AUTO_INDET BIT(6) +#define BQ2562X_TIMER_FRCE_INDET BIT(5) +#define BQ2562X_TIMER_EN_DCP BIT(4) +#define BQ2562X_TIMER_TMR2X_EN BIT(3) +#define BQ2562X_TIMER_SAFE_TMRS BIT(2) +#define BQ2562X_TIMER_PRECHR_TMR BIT(1) +#define BQ2562X_TIMER_CHG_TMR BIT(0) + + +/* REG0x18_Charger_Control_3 */ +#define BQ2562X_CTRL3_EN_OTG BIT(6) + +/* REG0x21_Charger_Flag_1 */ +#define BQ2562X_VBUS_FLAG_MSK BIT(0) +#define BQ2562X_CHG_FLAG_MSK BIT(3) + +#define BQ2562X_POWER_NONE 0 +#define BQ2562X_SDP_CURR_UA 500000 +#define BQ2562X_CDP_CURR_UA 1500000 +#define BQ2562X_DCP_CURR_UA 1500000 +#define BQ2562X_VOLT_UV 5040000 + +enum bq25620_mode { + BQ2562X_POWER_DOWN, + BQ2562X_SDP_HOST_MODE, + BQ2562X_CDP_HOST_MODE, + BQ2562X_DCP_HOST_MODE, +}; + +#endif /* ZEPHYR_DRIVERS_BC12_BQ25620_H_ */ diff --git a/dts/bindings/charger/ti,bq2562x.yaml b/dts/bindings/charger/ti,bq2562x-charger.yaml similarity index 92% rename from dts/bindings/charger/ti,bq2562x.yaml rename to dts/bindings/charger/ti,bq2562x-charger.yaml index 501ca9cd98899..192c652a8e838 100644 --- a/dts/bindings/charger/ti,bq2562x.yaml +++ b/dts/bindings/charger/ti,bq2562x-charger.yaml @@ -7,8 +7,7 @@ description: | The device has a single child node for the charger. For example: bq25620@6b { - compatible = "ti,bq2562x"; - reg = <0x6b>; + compatible = "ti,bq2562x-charger"; ce-gpios = <&gpioa 3 GPIO_ACTIVE_LOW>; constant-charge-current-max-microamp = <1040000>; @@ -19,9 +18,9 @@ description: | ti,input-voltage-limit-microvolt = <4600000>; }; -compatible: "ti,bq2562x" +compatible: "ti,bq2562x-charger" -include: [battery.yaml, i2c-device.yaml] +include: [battery.yaml] properties: constant-charge-current-max-microamp: @@ -44,10 +43,6 @@ properties: type: phandle-array description: Active low, charge enable pin - int-gpios: - type: phandle-array - description: Interrupt pin - ti,min-sys-voltage-microvolt: type: int default: 3600000 diff --git a/dts/bindings/mfd/ti,bq2652x.yaml b/dts/bindings/mfd/ti,bq2652x.yaml new file mode 100644 index 0000000000000..b5c4a6aeb39d3 --- /dev/null +++ b/dts/bindings/mfd/ti,bq2652x.yaml @@ -0,0 +1,22 @@ +# Copyright 2025 Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + BQ25620/BQ25622 is a single cell buck battery charger with OTG support. + + The device has a single child node for the charger. For example: + + bq25620@6b { + compatible = "ti,bq2562x"; + reg = <0x6b>; + int-gpio = <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + +compatible: "ti,bq2562x" + +include: [i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + description: Interrupt pin diff --git a/dts/bindings/usb/ti,bq25620-bc.yaml b/dts/bindings/usb/ti,bq25620-bc.yaml new file mode 100644 index 0000000000000..1ad73b3047e7e --- /dev/null +++ b/dts/bindings/usb/ti,bq25620-bc.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments BQ2562X + +compatible: "ti,bq25620-bc" + +include: [usb-bc12.yaml] diff --git a/include/zephyr/drivers/mfd/mfd_bq2562x.h b/include/zephyr/drivers/mfd/mfd_bq2562x.h new file mode 100644 index 0000000000000..0dde08415c2d8 --- /dev/null +++ b/include/zephyr/drivers/mfd/mfd_bq2562x.h @@ -0,0 +1,98 @@ +/* + * Copyright 2025 Linumiz GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MFD_BQ2562X_H_ +#define ZEPHYR_DRIVERS_MFD_BQ2562X_H_ + +#include + +#define BQ2562X_RESERVED_LSB 0x00 +#define BQ2562X_RESERVED_MSB 0x01 +#define BQ2562X_CHRG_CTRL_1 0x16 +#define BQ2562X_CHRG_STAT_1 0x1e +#define BQ2562X_FAULT_STAT_0 0x1f +#define BQ2562X_CHRG_FLAG_0 0x20 +#define BQ2562X_FAULT_FLAG_0 0x22 +#define BQ2562X_FN_DISABE_0 0x27 +#define BQ2562X_ADC_IBUS_LSB 0x28 +#define BQ2562X_ADC_IBUS_MSB 0x29 +#define BQ2562X_ADC_VBUS_LSB 0x2c +#define BQ2562X_ADC_VBUS_MSB 0x2d + +/* REG0x16_Charger_Control_1 */ +#define BQ2562X_CHRG_EN BIT(5) +#define BQ2562X_CHRG_HIZ BIT(4) +#define BQ2562X_WATCHDOG_MASK GENMASK(1, 0) +#define BQ2562X_WATCHDOG_DIS 0 + +/* REG0x1E_Charger_Status_1 */ +#define BQ2562X_CHG_STAT_MSK GENMASK(4, 3) +#define BQ2562X_NOT_CHRGING 0 +#define BQ2562X_TRICKLE_CHRG 1 +#define BQ2562X_TAPER_CHRG 2 +#define BQ2562X_TOP_OFF_CHRG 3 +#define BQ2562X_PRECHG_MAX_UA 620000 + +#define BQ2562X_VBUS_STAT_MSK GENMASK(2, 0) +#define BQ2562X_USB_SDP BIT(0) +#define BQ2562X_USB_CDP BIT(1) +#define BQ2562X_USB_DCP (BIT(1) | BIT(0)) +#define BQ2562X_UNKNOWN_500MA BIT(2) +#define BQ2562X_NON_STANDARD (BIT(2) | BIT(0)) +#define BQ2562X_HVDCP (BIT(2) | BIT(1)) +#define BQ2562X_OTG_MODE (BIT(2) | BIT(1) | BIT(0)) + +/* REG0x1F_FAULT_Status_0 */ +#define BQ2562X_TEMP_TS_NORMAL 0x00 +#define BQ2562X_TEMP_COLD BIT(0) +#define BQ2562X_TEMP_HOT BIT(1) +#define BQ2562X_TEMP_COOL (BIT(1) | BIT(0)) +#define BQ2562X_TEMP_WARM BIT(2) +#define BQ2562X_TEMP_PRECOOL (BIT(2) | BIT(0)) +#define BQ2562X_TEMP_PREWARM (BIT(2) | BIT(1)) +#define BQ2562X_TEMP_PIN_BIAS_REF_FAULT (BIT(2) | BIT(1) | BIT(0)) +#define BQ2562X_TEMP_MASK GENMASK(2, 0) +#define BQ2562X_TSHUT_STAT BIT(3) +#define BQ2562X_OTG_FAULT_STAT BIT(4) +#define BQ2562X_SYS_FAULT_STAT BIT(5) +#define BQ2562X_BAT_FAULT_STAT BIT(6) +#define BQ2562X_VBUS_FAULT_STAT BIT(7) + +/* REG0x28_IBUS_ADC */ +#define BQ2562X_ADC_IBUS_SHIFT 1 +#define BQ2562X_ADC_CURR_STEP_UA 2000 + +/* REG0x2C_VBUS_ADC */ +#define BQ2562X_ADC_VBUS_STEP_UV 3970 +#define BQ2562X_ADC_VBUS_SHIFT 2 + +/* Define the BQ2562X MFD interrupt callback function handler */ +typedef void (*bq2562x_callback_handler_t)(const struct device *dev); + +struct bq2562x_mfd_callback { + sys_snode_t node; + bq2562x_callback_handler_t cb; + const struct device *dev; +}; + +/* Register the interrupt of BQ2562X MFD callback function */ +void mfd_bq2562x_register_interrupt_callback(const struct device *dev, + struct bq2562x_mfd_callback *callback); + +int mfd_bq2562x_reg_update_byte_dt(const struct device *dev, uint8_t reg_addr, uint8_t mask, + uint8_t value); + +int mfd_bq2562x_reg_read_byte_dt(const struct device *dev, uint8_t reg_addr, uint8_t *value); + +int mfd_bq2562x_burst_read_dt(const struct device *dev, uint8_t start_addr, uint8_t *buf, + uint32_t num_bytes); + +int mfd_bq2562x_burst_write_dt(const struct device *dev, uint8_t start_addr, uint8_t *buf, + uint32_t num_bytes); + +int mfd_bq2562x_enable_interrupt_pin(const struct device *dev, bool enabled); + +#endif /* ZEPHYR_DRIVERS_MFD_BQ2562X_H_ */