Skip to content

drivers: charger: bq2562x: Added some extended functionality. #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: dev/ti/bq2562x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 201 additions & 25 deletions drivers/charger/charger_bq2562x.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/charger/bq2562x.h>

LOG_MODULE_REGISTER(ti_bq25620, CONFIG_CHARGER_LOG_LEVEL);

Expand Down Expand Up @@ -44,6 +45,16 @@ 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 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;
};
Expand Down Expand Up @@ -123,17 +134,12 @@ static int bq2562x_set_ichrg_curr(const struct device *dev, int chrg_curr)
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;
}

Expand Down Expand Up @@ -277,18 +283,13 @@ 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;

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;
}

Expand Down Expand Up @@ -324,6 +325,103 @@ 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));
}

static int bq2562x_disbale_watchdog(const struct device *dev)
{
const struct bq2562x_config *const config = dev->config;

return i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_1, BQ2562X_WATCHDOG_MASK,
FIELD_PREP(BQ2562X_WATCHDOG_MASK, BQ2562X_WATCHDOG_DIS));
}

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_timer_state 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;
Expand Down Expand Up @@ -599,6 +697,49 @@ static int bq2562x_get_usb_type(const struct device *dev, enum charger_usb_type
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)
{
Expand Down Expand Up @@ -643,8 +784,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_disbale_watchdog(dev);
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);
Expand Down Expand Up @@ -715,44 +862,73 @@ static int bq2562x_set_heat_mgmt(const struct device *dev)
return ret;
}

ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_CHRG_CTRL_2, BQ2562X_CTRL2_VBUS_OVP, 1);
if (ret) {
return ret;
}

return bq2562x_set_min_sys_volt(dev, data->min_sys_voltage_uv);
}

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;

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);
value |= BQ2562X_CTRL2_REG_RST;
mask = BQ2562X_CTRL2_VBUS_OVP | BQ2562X_CTRL2_REG_RST;

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);
if (ret) {
value = FIELD_PREP(BQ2562X_TIMER_DCP_BIAS, data->enable_dcp_bias);
value |= FIELD_PREP(BQ2562X_TIMER_SAFETY_TMRS, data->enable_savety_tmrs);
mask = BQ2562X_TIMER_DCP_BIAS | BQ2562X_TIMER_SAFETY_TMRS;

ret = i2c_reg_update_byte_dt(&config->i2c, BQ2562X_TIMER_CTRL, mask, value);
if (ret != 0) {
return ret;
}

ret = bq2562x_set_prechrg_curr(dev, data->precharge_current_ua);
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;
}
Expand Down
27 changes: 24 additions & 3 deletions drivers/charger/charger_bq2562x.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,25 +129,43 @@
#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_SAFETY_TMRS BIT(2)

/* 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
Expand Down Expand Up @@ -213,6 +231,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)

Expand Down
Loading
Loading