From bee8c43cfe4f625e301b0c183d84ad999231a877 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Wed, 26 Oct 2022 14:59:42 -0500 Subject: [PATCH 1/3] drivers: sensor: cp7420: Introduces CP7420 battery charger Adds support for the CP7420 battery charging IC in the sensor subsystem. Signed-off-by: Ricardo Rivera-Matos --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 2 + drivers/sensor/cp7420/CMakeLists.txt | 7 + drivers/sensor/cp7420/Kconfig | 10 + drivers/sensor/cp7420/cp7420.c | 1506 ++++++++++++++++++++++++++ drivers/sensor/cp7420/cp7420.h | 355 ++++++ 6 files changed, 1881 insertions(+) create mode 100644 drivers/sensor/cp7420/CMakeLists.txt create mode 100644 drivers/sensor/cp7420/Kconfig create mode 100644 drivers/sensor/cp7420/cp7420.c create mode 100644 drivers/sensor/cp7420/cp7420.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 406f64c55663e..373a3788c4d2b 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory_ifdef(CONFIG_BMM150 bmm150) add_subdirectory_ifdef(CONFIG_BMP388 bmp388) add_subdirectory_ifdef(CONFIG_BQ274XX bq274xx) add_subdirectory_ifdef(CONFIG_CCS811 ccs811) +add_subdirectory_ifdef(CONFIG_CP7420 cp7420) add_subdirectory_ifdef(CONFIG_DHT dht) add_subdirectory_ifdef(CONFIG_DPS310 dps310) add_subdirectory_ifdef(CONFIG_DS18B20 ds18b20) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 79e9c0131e718..c2f2e05abed9e 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -76,6 +76,8 @@ source "drivers/sensor/bq274xx/Kconfig" source "drivers/sensor/ccs811/Kconfig" +source "drivers/sensor/cp7420/Kconfig" + source "drivers/sensor/dht/Kconfig" source "drivers/sensor/dps310/Kconfig" diff --git a/drivers/sensor/cp7420/CMakeLists.txt b/drivers/sensor/cp7420/CMakeLists.txt new file mode 100644 index 0000000000000..353b832cf253f --- /dev/null +++ b/drivers/sensor/cp7420/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Cirrus Logic Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(cp7420.c) diff --git a/drivers/sensor/cp7420/Kconfig b/drivers/sensor/cp7420/Kconfig new file mode 100644 index 0000000000000..cdfdff7d0db71 --- /dev/null +++ b/drivers/sensor/cp7420/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2022 Cirrus Logic Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig CP7420 + bool "CP7420 Battery Charger" + default y + depends on I2C + help + Enable I2C-based driver for CP7420 Battery Charger. \ No newline at end of file diff --git a/drivers/sensor/cp7420/cp7420.c b/drivers/sensor/cp7420/cp7420.c new file mode 100644 index 0000000000000..2561fd439f757 --- /dev/null +++ b/drivers/sensor/cp7420/cp7420.c @@ -0,0 +1,1506 @@ + +/* + * Copyright 2022 Cirrus Logic, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +LOG_MODULE_REGISTER(cp7420, CONFIG_SENSOR_LOG_LEVEL); + +#include "cp7420.h" + +#define DT_DRV_COMPAT cirrus_cp7420 + +/** + * @brief Gets an ADC value and converts the raw data into a value in micro units + * + * @param dev CP7420 device to access + * @param chan the desired ADC channel + * @param val converted ADC value + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_get_adc(const struct device *dev, const enum cp7420_adc chan, int *val) +{ + const struct cp7420_config *const config = dev->config; + uint8_t read_buf[2] = { 0x0 }; + uint8_t start_addr; + uint16_t raw_data; + int ret; + + ret = i2c_reg_update_byte_dt(&config->i2c, + ADC_CTRL_1, + CP7420_PAUSE_UPDATES, + CP7420_PAUSE_UPDATES); + if (ret) { + LOG_ERR("Unable to pause ADC: %d\n", ret); + return ret; + } + + start_addr = (chan * 2) + ADC_NTC_STATUS; + + ret = i2c_burst_read_dt(&config->i2c, start_addr, read_buf, sizeof(read_buf)); + if (ret) { + LOG_ERR("Unable to read ADC channel %d: %d\n", chan, ret); + return ret; + } + + raw_data = (read_buf[1] << 8) | read_buf[0]; + + switch (chan) { + case CP7420_ADC_VIN: + *val = raw_data * CP7420_ADC_VIN_STEP_UV; + break; + case CP7420_ADC_IIN: + *val = raw_data * CP7420_ADC_IIN_STEP_UA; + break; + case CP7420_ADC_VSYS: + *val = raw_data * CP7420_ADC_VSYS_STEP_UV; + break; + case CP7420_ADC_VBAT: + *val = raw_data * CP7420_ADC_VBAT_STEP_UV; + break; + case CP7420_ADC_IBAT_CHG: + raw_data &= CP7420_ADC_IBAT_MASK; + + *val = raw_data * CP7420_ADC_IBAT_STEP_UA; + + if (raw_data & CP7420_ADC_IBAT_DISCHG) + *val *= -1; + + break; + case CP7420_ADC_NTC: + *val = raw_data * CP7420_ADC_NTC_STEP_UV; + break; + case CP7420_ADC_TDIE: + *val = raw_data * CP7420_ADC_TDIE_STEP_UC; + break; + default: + return -ENOTSUP; + } + + return ret; +} + +/** + * @brief Sets the LPM_EN bit + * + * @param dev CP7420 device to access + * @param en value to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_lpm_en(const struct device *dev, const bool en) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + if (en) + reg_code = CP7420_LPM_EN; + else + reg_code = 0; + + ret = i2c_reg_update_byte_dt(&config->i2c, OPERATION_CTRL_0, CP7420_LPM_EN, reg_code); + if (ret) { + LOG_ERR("Failed to set LPM_EN: %d\n", ret); + return ret; + } + + data->lpm_en = en; + + return ret; +} + +/** + * @brief Sets the IIN_REG_EN bit + * + * @param dev CP7420 device to access + * @param en value to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iin_reg_en(const struct device *dev, const bool en) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + if (en) + reg_code = CP7420_IIN_REG_EN; + else + reg_code = 0; + + ret = i2c_reg_update_byte_dt(&config->i2c, OPERATION_CTRL_0, CP7420_IIN_REG_EN, reg_code); + if (ret) { + LOG_ERR("Failed to set IIN_REG_EN: %d\n", ret); + return ret; + } + + data->iin_reg_en = en; + + return ret; +} + +/** + * @brief Sets the VIN_REG_EN bit + * + * @param dev CP7420 device to access + * @param en value to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_vin_reg_en(const struct device *dev, const bool en) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + if (en) + reg_code = CP7420_VIN_REG_EN; + else + reg_code = 0; + + ret = i2c_reg_update_byte_dt(&config->i2c, OPERATION_CTRL_0, CP7420_VIN_REG_EN, reg_code); + if (ret) { + LOG_ERR("Failed to set VIN_REG_EN: %d\n", ret); + return ret; + } + + data->vin_reg_en = en; + + return ret; +} + +/** + * @brief Sets the PSYS_EN bit + * + * @param dev CP7420 device to access + * @param en value to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_psys_en(const struct device *dev, const bool en) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + if (en) + reg_code = CP7420_PSYS_EN; + else + reg_code = 0; + + ret = i2c_reg_update_byte_dt(&config->i2c, POWER_MONITOR_CTRL, CP7420_PSYS_EN, reg_code); + if (ret) { + LOG_ERR("Failed to set PSYS_EN: %d\n", ret); + return ret; + } + + data->psys_en = en; + + return ret; +} + +/** + * @brief Sets the CHG_MODE + * + * @param dev CP7420 device to access + * @param val CHG_MODE value to set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_chg_mode(const struct device *dev, uint8_t val) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + int ret; + + ret = i2c_reg_update_byte_dt(&config->i2c, OPERATION_CTRL_0, CP7420_CHG_MODE_MASK, val); + if (ret) { + LOG_ERR("Failed to set CHG_MODE: %d\n", ret); + return ret; + } + + data->chg_mode = val; + + return ret; +} + +/** + * @brief Configures the SWITCH_CURRENT_CTRL_2 register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_switch_curr_ctrl_2(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint16_t ocp_pfm_cfg = config->ocp_pfm_cfg; + uint8_t reg_code; + + ocp_pfm_cfg = CLAMP(ocp_pfm_cfg, CP7420_OCP_PFM_MIN_MA, CP7420_OCP_PFM_MAX_MA); + + reg_code = (ocp_pfm_cfg - CP7420_OCP_PFM_OFFSET_MA) / CP7420_OCP_PFM_STEP_MA; + + return i2c_reg_write_byte_dt(&config->i2c, SWITCH_CURRENT_CTRL_2, reg_code); +} + +/** + * @brief Configures the SWITCH_CURRENT_CTRL_1 register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_switch_curr_ctrl_1(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint16_t ocp_pwm_cfg = config->ocp_pwm_cfg; + uint8_t reg_code; + + ocp_pwm_cfg = CLAMP(ocp_pwm_cfg, CP7420_OCP_PWM_MIN_MA, CP7420_OCP_PWM_MAX_MA); + + reg_code = (ocp_pwm_cfg - CP7420_OCP_PWM_OFFSET_MA) / CP7420_OCP_PWM_STEP_MA; + + return i2c_reg_write_byte_dt(&config->i2c, SWITCH_CURRENT_CTRL_1, reg_code); +} + +/** + * @brief Configures the POWER_MONITOR_CTRL register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_power_mon_ctrl(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code = 0; + int ret; + + if (config->psys_en) { + reg_code |= CP7420_PSYS_EN; + + if (config->rsi_cfg) + reg_code |= (config->rsi_cfg << CP7420_RSI_CFG_SHIFT) & CP7420_RSI_CFG_MASK; + + if (config->rso_cfg) + reg_code |= (config->rso_cfg << CP7420_RSO_CFG_SHIFT) & CP7420_RSO_CFG_MASK; + + if (config->psys_ratio) + reg_code |= (config->psys_ratio << CP7420_PSYS_RATIO_SHIFT) & CP7420_PSYS_RATIO_MASK; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, POWER_MONITOR_CTRL, reg_code); + if (ret) { + LOG_ERR("Failed to configure POWER_MONITOR_CTRL: %d", ret); + return ret; + } + + data->psys_en = config->psys_en; + + return ret; +} + +/** + * @brief Configures the DITHERING_CTRL register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_dither_ctrl(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->dither_en) { + reg_code |= CP7420_DITHER_EN; + + if (config->dither_rate) + reg_code |= (config->dither_rate << CP7420_DITHER_RATE_SHIFT) & CP7420_DITHER_RATE_MASK; + + if (config->dither_limit) + reg_code |= config->dither_limit & CP7420_DITHER_LIMIT_MASK; + } + + return i2c_reg_write_byte_dt(&config->i2c, DITHERING_CTRL, reg_code); +} + +/** + * @brief Sets the PROCHOT monitors + * + * @param dev CP7420 device to access + * @param prochot_mon code to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_prochot_mon(const struct device *dev, uint16_t prochot_mon) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t buf[3] = {PROCHOT_CTRL_1, prochot_mon >> 8, prochot_mon & 0xFF}; + int ret; + + ret = i2c_write_dt(&config->i2c, buf, sizeof(buf)); + if (ret) { + LOG_ERR("Failed to set PROCHOT monitors: %d", ret); + return ret; + } + + data->prochot_mon = prochot_mon; + + return ret; +} + +/** + * @brief Sets the PROCHOT debounce time + * + * @param dev CP7420 device to access + * @param prochot_dbounce code to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_prochot_debounce(const struct device *dev, uint8_t prochot_dbounce) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + reg_code = prochot_dbounce << CP7420_PROCHOT_DEBOUNCE_SHIFT; + + ret = i2c_reg_update_byte_dt(&config->i2c, + PROCHOT_CTRL_0, + CP7420_PROCHOT_DEBOUNCE_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set PROCHOT_DEBOUNCE: %d", ret); + return ret; + } + + data->prochot_debounce = prochot_dbounce; + + return ret; +} + +/** + * @brief Sets the PROCHOT minimum pulse width + * + * @param dev CP7420 device to access + * @param prochot_duration code to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_prochot_duration(const struct device *dev, uint8_t prochot_duration) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + reg_code = prochot_duration << CP7420_PROCHOT_DUR_SHIFT; + + ret = i2c_reg_update_byte_dt(&config->i2c, PROCHOT_CTRL_0, CP7420_PROCHOT_DUR_MASK, reg_code); + if (ret) { + LOG_ERR("Failed to set PROCHOT_DURATION: %d", ret); + return ret; + } + + data->prochot_duration = prochot_duration; + + return ret; +} + +/** + * @brief Configures T_IBAT_MAX1 and T_IBAT_MAX2 according to the datasheet + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_t_ibat(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->t_ibat_max1) + reg_code |= (config->t_ibat_max1 << CP7420_T_IBAT_MAX1_SHIFT) & CP7420_T_IBAT_MAX1_MASK; + + if (config->t_ibat_max2) + reg_code |= (config->t_ibat_max2 << CP7420_T_IBAT_MAX1_SHIFT) & CP7420_T_IBAT_MAX2_MASK; + + return i2c_reg_update_byte_dt(&config->i2c, + TWO_LEVEL_CURRENT_CTRL, + CP7420_T_IBAT_MASK, + reg_code); +} + +/** + * @brief Sets the upper PROCHOT input current limit's deglitch timer + * + * @param dev CP7420 device to access + * @param t_iin_max2 code to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_t_iin_max2(const struct device *dev, uint8_t t_iin_max2) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + int ret; + + ret = i2c_reg_update_byte_dt(&config->i2c, + TWO_LEVEL_CURRENT_CTRL, + CP7420_T_IIN_MAX2_MASK, + t_iin_max2); + if (ret) { + LOG_ERR("Failed to set T_IIN_MAX2: %d", ret); + return ret; + } + + data->t_iin_max_2 = t_iin_max2; + + return ret; +} + +/** + * @brief Sets the lower PROCHOT input current limit's deglitch timer + * + * @param dev CP7420 device to access + * @param t_iin_max1 code to be set + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_t_iin_max1(const struct device *dev, uint8_t t_iin_max1) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + reg_code = t_iin_max1 << CP7420_T_IIN_MAX1_SHIFT; + + ret = i2c_reg_update_byte_dt(&config->i2c, + TWO_LEVEL_CURRENT_CTRL, + CP7420_T_IIN_MAX1_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set T_IIN_MAX1: %d", ret); + return ret; + } + + data->t_iin_max_1 = t_iin_max1; + + return ret; +} + +/** + * @brief Sets the upper PROCHOT battery discharge current threshold + * + * @param dev CP7420 device to access + * @param ibat_dischg value to be set in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_ibat_dchg_lim_2(const struct device *dev, uint16_t ibat_dischg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code = 0; + int ret; + + ibat_dischg = CLAMP(ibat_dischg, + CP7420_IBAT_DISCHG_LIM_2_MIN_MA, + CP7420_IBAT_DISCHG_LIM_2_MAX_MA); + + reg_code = ibat_dischg / CP7420_IBAT_DISCHG_LIM_2_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, BATTERY_DISCHG_CTRL_1, reg_code); + if (ret) { + LOG_ERR("Failed to set IBAT_DISCHG_LIMIT_2: %d", ret); + return ret; + } + + data->ibat_dischg_limit_2_ma = ibat_dischg; + + return ret; +} + +/** + * @brief Sets the lower PROCHOT battery discharge current threshold + * + * @param dev CP7420 device to access + * @param ibat_dischg value to be set in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_ibat_dchg_lim_1(const struct device *dev, uint16_t ibat_dischg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code = 0; + int ret; + + ibat_dischg = CLAMP(ibat_dischg, + CP7420_IBAT_DISCHG_LIM_1_MIN_MA, + CP7420_IBAT_DISCHG_LIM_1_MAX_MA); + + reg_code = ibat_dischg / CP7420_IBAT_DISCHG_LIM_1_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, BATTERY_DISCHG_CTRL_0, reg_code); + if (ret) { + LOG_ERR("Failed to set IBAT_DISCHG_LIMIT_1: %d", ret); + return ret; + } + + data->ibat_dischg_limit_1_ma = ibat_dischg; + + return ret; +} + +/** + * @brief Configures the STARTUP_CTRL register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_startup_ctrl(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->ibat_softstart) + reg_code |= (config->ibat_softstart << CP7420_IBAT_SOFTSTART_SHIFT) & + CP7420_IBAT_SOFTSTART_MASK; + + if (config->rechg_ibat_softstart) + reg_code |= CP7420_RECHG_IBAT_SOFTSTART; + + if (config->vsys_softstart) + reg_code |= (config->vsys_softstart << CP7420_VSYS_SOFTSTART_SHIFT) & + CP7420_VSYS_SOFTSTART_MASK; + + return i2c_reg_write_byte_dt(&config->i2c, STARTUP_CTRL, reg_code); +} + +/** + * @brief Configures the DPM_CTRL register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_dpm_ctrl(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->vin_dpm_threshold) + reg_code |= (config->vin_dpm_threshold << CP7420_VIN_DPM_THRESH_SHIFT) & + CP7420_VIN_DPM_THRESH_MASK; + + if (config->fsw_cfg) + reg_code |= config->fsw_cfg & CP7420_FSW_CFG_MASK; + + return i2c_reg_write_byte_dt(&config->i2c, DPM_CTRL, reg_code); +} + +/** + * @brief Configures the TEMP_REGULATION register according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_temp_reg(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->ntc_en) + reg_code |= CP7420_NTC_EN; + + if (config->tsdie_en) + reg_code |= CP7420_TSDIE_EN; + + if (config->batgone_en) + reg_code |= CP7420_BATGONE_EN; + + if (config->watchdog_timer) { + reg_code |= (config->watchdog_timer & CP7420_WATCHDOG_TIMER_MASK); + } + + return i2c_reg_write_byte_dt(&config->i2c, TEMP_REGULATION_CTRL, reg_code); +} + +/** + * @brief Sets the falling PROCHOT system voltage threshold + * + * @param dev CP7420 device to access + * @param vsys_low Value to set in millivolts + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_vsys_low(const struct device *dev, uint16_t vsys_low) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + vsys_low = CLAMP(vsys_low, CP7420_VSYS_LOW_MIN_MV, CP7420_VSYS_LOW_MAX_MV); + + reg_code = (vsys_low - CP7420_VSYS_LOW_OFFSET_MV) / CP7420_VSYS_LOW_STEP_MV; + + ret = i2c_reg_write_byte_dt(&config->i2c, SYS_VOLTAGE_CTRL_2, reg_code); + if (ret) { + LOG_ERR("Failed to set VSYS_LOW: %d", ret); + return ret; + } + + data->vsys_low_mv = vsys_low; + + return ret; +} + +/** + * @brief Configures VSYS_MAX according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_vsys_max(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint16_t vsys_max_uv; + uint8_t reg_code; + int ret; + + vsys_max_uv = CLAMP(config->vsys_max_mv, CP7420_VSYS_MAX_MIN_MV, CP7420_VSYS_MAX_MAX_MV); + + reg_code = vsys_max_uv / CP7420_VSYS_MAX_STEP_MV; + + ret = i2c_reg_write_byte_dt(&config->i2c, SYS_VOLTAGE_CTRL_1, reg_code); + if (ret) + LOG_ERR("Failed to set VSYS_MAX: %d", ret); + + return ret; +} + +/** + * @brief Configures VSYS_MIN according to the devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_vsys_min(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint16_t vsys_min_uv; + uint8_t reg_code; + int ret; + + vsys_min_uv = CLAMP(config->vsys_min_mv, CP7420_VSYS_MIN_MIN_MV, CP7420_VSYS_MIN_MAX_MV); + + reg_code = vsys_min_uv / CP7420_VSYS_MIN_STEP_MV; + + ret = i2c_reg_write_byte_dt(&config->i2c, SYS_VOLTAGE_CTRL_0, reg_code); + if (ret) + LOG_ERR("Failed to set VSYS_MIN: %d", ret); + + return ret; +} + +/** + * @brief Sets the falling PROCHOT input voltage threshold + * + * @param dev CP7420 device to access + * @param vin_low VIN_LOW value in millivolts + * @return 0 if successful, + * @return negative error code from I2C API + */ +__unused static int cp7420_set_vin_low(const struct device *dev, uint16_t vin_low) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + vin_low = CLAMP(vin_low, CP7420_VIN_LOW_MIN_MV, CP7420_VIN_LOW_MAX_MV); + + reg_code = (vin_low - CP7420_VIN_LOW_OFFSET_MV) / CP7420_VIN_LOW_STEP_MV; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_5, reg_code); + if (ret) { + LOG_ERR("Failed to set VIN_LOW: %d", ret); + return ret; + } + + data->vin_low_mv = vin_low; + + return ret; +} + +/** + * @brief Sets the peak PROCHOT input current threshold + * + * @param dev CP7420 device to access + * @param iin_limit_peak IIN_LIMIT_PEAK value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iin_limit_peak(const struct device *dev, uint16_t iin_limit_peak) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + iin_limit_peak = CLAMP(iin_limit_peak, CP7420_IIN_LIMIT_PEAK_MIN_MA, CP7420_IIN_LIMIT_PEAK_MAX_MA); + + reg_code = iin_limit_peak / CP7420_IIN_LIMIT_PEAK_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_4, reg_code); + if (ret) { + LOG_ERR("Failed to set IIN_LIMIT_PEAK: %d", ret); + return ret; + } + + data->iin_limit_peak_ma = iin_limit_peak; + + return ret; +} + +/** + * @brief Sets the upper PROCHOT input current threshold + * + * @param dev CP7420 device to access + * @param iin_limit_2 IIN_LIMIT_2 value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iin_limit_2(const struct device *dev, uint16_t iin_limit_2) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + iin_limit_2 = CLAMP(iin_limit_2, CP7420_IIN_LIMIT_2_MIN_MA, CP7420_IIN_LIMIT_2_MAX_MA); + + reg_code = iin_limit_2 / CP7420_IIN_LIMIT_2_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_3, reg_code); + if (ret) { + LOG_ERR("Failed to set IIN_LIMIT_2: %d", ret); + return ret; + } + + data->iin_limit_2_ma = iin_limit_2; + + return ret; +} + +/** + * @brief Sets the lower PROCHOT input current threshold + * + * @param dev CP7420 device to access + * @param iin_limit_1 IIN_LIMIT_1 value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iin_limit_1(const struct device *dev, uint16_t iin_limit_1) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + iin_limit_1 = CLAMP(iin_limit_1, CP7420_IIN_LIMIT_1_MIN_MA, CP7420_IIN_LIMIT_1_MAX_MA); + + reg_code = iin_limit_1 / CP7420_IIN_LIMIT_1_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_2, reg_code); + if (ret) { + LOG_ERR("Failed to set IIN_LIMIT_1: %d", ret); + return ret; + } + + data->iin_limit_1_ma = iin_limit_1; + + return ret; +} + +/** + * @brief Sets the input current regulation target + * + * @param dev CP7420 device to access + * @param iin_reg IIN_REG value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iin_reg(const struct device *dev, uint16_t iin_reg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + iin_reg = CLAMP(iin_reg, CP7420_IIN_REG_MIN_MA, CP7420_IIN_REG_MAX_MA); + + reg_code = iin_reg / CP7420_IIN_REG_STEP_MA; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_1, reg_code); + if (ret) { + LOG_ERR("Failed to set IIN_REG: %d", ret); + return ret; + } + + data->iin_reg_ma = iin_reg; + + return ret; +} + +/** + * @brief Sets the input voltage regulation target + * + * @param dev CP7420 device to access + * @param vin_reg VIN_REG value in millivolts + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_vin_reg(const struct device *dev, uint16_t vin_reg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + vin_reg = CLAMP(vin_reg, CP7420_VIN_REG_MIN_MV, CP7420_VIN_REG_MAX_MV); + + reg_code = (vin_reg - CP7420_VIN_REG_OFFSET_MV) / CP7420_VIN_REG_STEP_MV; + + ret = i2c_reg_write_byte_dt(&config->i2c, INPUT_CTRL_0, reg_code); + if (ret) { + LOG_ERR("Failed to set VIN_REG: %d", ret); + return ret; + } + + data->vin_reg_mv = vin_reg; + + return ret; +} + +/** + * @brief Configures BATTERY_CHGING_CTRL_5 based on devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_batt_chg_ctrl_5(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code = 0; + + if (config->auto_chg_timer_en) + reg_code |= CP7420_AUTO_CHG_TIMER_EN; + + if (config->prechg_timer) + reg_code |= (config->prechg_timer << CP7420_PRECHG_TIMER_SHIFT) & CP7420_PRECHG_TIMER_MASK; + + if (config->fast_chg_timer) + reg_code |= config->fast_chg_timer & CP7420_FAST_CHG_TIMER_MASK; + + return i2c_reg_write_byte_dt(&config->i2c, BATTERY_CHGING_CTRL_5, reg_code);; +} + +/** + * @brief Configures BATTERY_CHGING_CTRL_4 based on devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_batt_chg_ctrl_4(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code; + uint16_t iterm; + + reg_code = config->vsys_ov_cfg << CP7420_VSYS_OV_CFG_SHIFT; + + if (config->iterm_en) { + iterm = CLAMP(config->iterm_ma, CP7420_ITERM_CFG_MIN_MA, CP7420_ITERM_CFG_MAX_MA); + reg_code |= ((iterm - CP7420_ITERM_CFG_OFFSET_MA) / + CP7420_ITERM_CFG_STEP_MA) | + CP7420_ITERM_EN; + } + + return i2c_reg_write_byte_dt(&config->i2c, BATTERY_CHGING_CTRL_4, reg_code); +} + +/** + * @brief Configures BATTERY_CHGING_CTRL_3 based on devicetree + * + * @param dev CP7420 device to access + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_cfg_batt_chg_ctrl_3(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code; + + reg_code = config->vbat_ov_cfg << CP7420_VBAT_OV_CFG_SHIFT; + + if (config->recharge_en) { + reg_code |= CP7420_RECHARGE_EN; + + reg_code |= (config->recharge_offset << CP7420_RECHARGE_OFFSET_SHIFT) & + CP7420_RECHARGE_OFFSET_MASK; + + reg_code |= config->recharge_deglitch & CP7420_RECAHRGE_DEGLITCH_MASK; + } + + return i2c_reg_write_byte_dt(&config->i2c, BATTERY_CHGING_CTRL_3, reg_code); +} + +/** + * @brief precharge current setter + * + * @param dev CP7420 device to access + * @param iprechg The prechagre current value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_iprechg_cfg(const struct device *dev, uint16_t iprechg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + iprechg = CLAMP(iprechg, CP7420_IPRECHG_MIN_MA, CP7420_IPRECHG_MAX_MA); + + reg_code = (iprechg - CP7420_IPRECHG_OFFSET_MA) / CP7420_IPRECHG_STEP_MA; + + ret = i2c_reg_update_byte_dt(&config->i2c, + BATTERY_CHGING_CTRL_3, + CP7420_IPRECHG_CFG_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set IPRECHG_CFG: %d", ret); + return ret; + } + + data->iprechg_ma = iprechg; + + return ret; +} + +/** + * @brief Configures VBAT_LOW based on devicetree + * + * @param dev CP7420 device to access + * @return int + */ +static int cp7420_cfg_vbat_low(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + uint8_t reg_code; + + reg_code = config->vbat_low << CP7420_VBAT_LOW_SHIFT; + + return i2c_reg_update_byte_dt(&config->i2c, + BATTERY_CHGING_CTRL_2, + CP7420_VBAT_LOW_MASK, + reg_code); +} + +/** + * @brief charge voltage setter + * + * @param dev CP7420 device to access + * @param vbat_reg charge voltage value in millivolts + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_vbat_reg(const struct device *dev, uint16_t vbat_reg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + uint16_t tmp; + int ret; + + vbat_reg = CLAMP(vbat_reg, CP7420_VBAT_REG_MIN_MV, CP7420_VBAT_REG_MAX_MV); + + tmp = (vbat_reg / CP7420_VBAT_REG_STEP_MV) << CP7420_VBAT_REG_SHIFT; + + reg_code = (tmp & 0xff00) >> 8; + + ret = i2c_reg_update_byte_dt(&config->i2c, + BATTERY_CHGING_CTRL_1, + CP7420_VBAT_REG_MSB_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set VBAT_REG MSB: %d", ret); + return ret; + } + + reg_code = tmp & 0xff; + + ret = i2c_reg_update_byte_dt(&config->i2c, + BATTERY_CHGING_CTRL_1, + CP7420_VBAT_REG_LSB_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set VBAT_REG LSB: %d", ret); + return ret; + } + + data->vbat_reg_mv = vbat_reg; + + return ret; +} + +/** + * @brief charge current setter + * + * @param dev CP7420 device to access + * @param ibat_chg_cfg charge current value in milliamps + * @return 0 if successful, + * @return negative error code from I2C API + */ +static int cp7420_set_ibat_chg_cfg(const struct device *dev, uint16_t ibat_chg_cfg) +{ + const struct cp7420_config *const config = dev->config; + struct cp7420_data *data = dev->data; + uint8_t reg_code; + int ret; + + ibat_chg_cfg = CLAMP(ibat_chg_cfg, CP7420_IBAT_CHG_MIN_MA, CP7420_IBAT_CHG_MAX_MA); + + reg_code = ibat_chg_cfg / CP7420_IBAT_CHG_STEP_MA; + + ret = i2c_reg_update_byte_dt(&config->i2c, + BATTERY_CHGING_CTRL_0, + CP7420_IBAT_CHG_CFG_MASK, + reg_code); + if (ret) { + LOG_ERR("Failed to set IBAT_CHG_CFG: %d", ret); + return ret; + } + + data->ibat_chg_ma = ibat_chg_cfg; + + return ret; +} + +/** + * @brief Gets values from the ADC for the supported channels + * + * @param dev CP7420 device to access + * @param chan Channel number to read + * @param valp Returns the sensor value read on success + * @return 0 if successful, + * @return -ENOTSUP for unsupported channels + */ +static int cp7420_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *valp) +{ + int ret, val; + + ret = cp7420_get_adc(dev, chan, &val); + if (ret) + return ret; + + valp->val1 = val / 1000; + valp->val2 = (val % 1000) * 1000U; + + return ret; +} + +/** + * @brief Sets attributes for a supported channel + * + * @param dev CP7420 device to access + * @param chan Channel number of interest + * @param attr Attribute of a channel to set + * @param val Value to be set + * @return -ENOTSUP for unsupported channels + */ +static int cp7420_attribute_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FEATURE_MASK: + switch (chan) { + case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: + return cp7420_set_chg_mode(dev, val->val1); + case SENSOR_CHAN_POWER: + return cp7420_set_psys_en(dev, val->val1); + case SENSOR_CHAN_VOLTAGE: + return cp7420_set_vin_reg_en(dev, val->val1); + case SENSOR_CHAN_CURRENT: + return cp7420_set_iin_reg_en(dev, val->val1); + case CP7420_CHAN_LOW_POWER_MODE: + return cp7420_set_lpm_en(dev, val->val1); + case CP7420_CHAN_PROCHOT_ALL: + return cp7420_set_prochot_mon(dev, val->val1); + default: + goto chan_err; + } + break; + case SENSOR_ATTR_CONFIGURATION: + switch (chan) { + case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: + return cp7420_set_ibat_chg_cfg(dev, val->val1); + case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE: + return cp7420_set_vbat_reg(dev, val->val1); + case SENSOR_CHAN_VOLTAGE: + return cp7420_set_vin_reg(dev, val->val1); + case SENSOR_CHAN_CURRENT: + return cp7420_set_iin_reg(dev, val->val1); + case CP7420_CHAN_IIN_LIMIT_1: + return cp7420_set_iin_limit_1(dev, val->val1); + case CP7420_CHAN_IIN_LIMIT_2: + return cp7420_set_iin_limit_2(dev, val->val1); + case CP7420_CHAN_IIN_LIMIT_PEAK: + return cp7420_set_iin_limit_peak(dev, val->val1); + case CP7420_CHAN_IBAT_DISCHARGE_LIMIT_1: + return cp7420_set_ibat_dchg_lim_1(dev, val->val1); + case CP7420_CHAN_IBAT_DISCHARGE_LIMIT_2: + return cp7420_set_ibat_dchg_lim_2(dev, val->val1); + case CP7420_CHAN_VIN_LOW: + return cp7420_set_vin_low(dev, val->val1); + case CP7420_CHAN_VSYSMIN: + return cp7420_set_vsys_low(dev, val->val1); + default: + goto chan_err; + } + break; + case CP7420_ATTR_PROCHOT_DEBOUNCE: + switch (chan) { + case CP7420_CHAN_PROCHOT_ALL: + return cp7420_set_prochot_debounce(dev, val->val1); + default: + goto chan_err; + } + break; + case CP7420_ATTR_PROCHOT_DURATION: + switch (chan) { + case CP7420_CHAN_IIN_LIMIT_1: + return cp7420_set_t_iin_max1(dev, val->val1); + case CP7420_CHAN_IIN_LIMIT_2: + return cp7420_set_t_iin_max2(dev, val->val1); + case CP7420_CHAN_PROCHOT_ALL: + return cp7420_set_prochot_duration(dev, val->val1); + default: + goto chan_err; + } + break; + default: + LOG_ERR("Attribute: %d is not supported", attr); + return -ENOTSUP; + } + + return 0; + +chan_err: + LOG_ERR("Channel: %d feature mask is not supported", chan); + return -ENOTSUP; +} + +/** + * @brief + * + * @param dev CP7420 device to access + * @param chan Channel number of interest + * @param attr Attribute of a channel to get + * @param val Value to be set + * @return -ENOTSUP for unsupported channels + */ +static int cp7420_attribute_get(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + struct sensor_value *val) +{ + struct cp7420_data *data = dev->data; + + switch (attr) { + case SENSOR_ATTR_FEATURE_MASK: + switch (chan) { + case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: + val->val1 = data->chg_mode; + break; + case SENSOR_CHAN_POWER: + val->val1 = data->psys_en; + break; + case SENSOR_CHAN_VOLTAGE: + val->val1 = data->vin_reg_en; + break; + case CP7420_CHAN_LOW_POWER_MODE: + val->val1 = data->lpm_en; + break; + case CP7420_CHAN_PROCHOT_ALL: + val->val1 = data->prochot_mon; + break; + default: + goto chan_err; + } + break; + case SENSOR_ATTR_CONFIGURATION: + switch (chan) { + case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: + val->val1 = data->ibat_chg_ma; + break; + case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE: + val->val1 = data->vbat_reg_mv; + break; + case SENSOR_CHAN_VOLTAGE: + val->val1 = data->vin_reg_mv; + break; + case SENSOR_CHAN_CURRENT: + val->val1 = data->iin_reg_ma; + break; + case CP7420_CHAN_IIN_LIMIT_1: + val->val1 = data->iin_limit_1_ma; + break; + case CP7420_CHAN_IIN_LIMIT_2: + val->val1 = data->iin_limit_2_ma; + break; + case CP7420_CHAN_IIN_LIMIT_PEAK: + val->val1 = data->iin_limit_peak_ma; + break; + case CP7420_CHAN_IBAT_DISCHARGE_LIMIT_1: + val->val1 = data->ibat_dischg_limit_1_ma; + break; + case CP7420_CHAN_IBAT_DISCHARGE_LIMIT_2: + val->val1 = data->ibat_dischg_limit_2_ma; + break; + case CP7420_CHAN_VIN_LOW: + val->val1 = data->vin_low_mv; + break; + case CP7420_CHAN_VSYSMIN: + val->val1 = data->vsys_low_mv; + break; + default: + goto chan_err; + } + break; + case CP7420_ATTR_PROCHOT_DEBOUNCE: + switch (chan) { + case CP7420_CHAN_PROCHOT_ALL: + val->val1 = data->prochot_debounce; + default: + goto chan_err; + } + break; + case CP7420_ATTR_PROCHOT_DURATION: + switch (chan) { + case CP7420_CHAN_IIN_LIMIT_1: + val->val1 = data->t_iin_max_1; + break; + case CP7420_CHAN_IIN_LIMIT_2: + val->val1 = data->t_iin_max_2; + break; + case CP7420_CHAN_PROCHOT_ALL: + val->val1 = data->prochot_duration; + break; + default: + goto chan_err; + } + break; + default: + LOG_ERR("Attribute: %d is not supported", attr); + return -ENOTSUP; + } + + return 0; + +chan_err: + LOG_ERR("Channel: %d feature mask is not supported", chan); + return -ENOTSUP; +} + +static int cp7420_apply_dt(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + int ret; + + ret = cp7420_set_ibat_chg_cfg(dev, config->ibat_chg_max_ma); + if (ret) + return ret; + + ret = cp7420_set_vbat_reg(dev, config->vbat_reg_max_mv); + if (ret) + return ret; + + ret = cp7420_cfg_vsys_max(dev); + if (ret) + return ret; + + ret = cp7420_cfg_vsys_min(dev); + if (ret) + return ret; + + ret = cp7420_cfg_vbat_low(dev); + if (ret) + return ret; + + ret = cp7420_set_iprechg_cfg(dev, config->iprechg_ma); + if (ret) + return ret; + + ret = cp7420_cfg_batt_chg_ctrl_3(dev); + if (ret) + return ret; + + ret = cp7420_cfg_batt_chg_ctrl_4(dev); + if (ret) + return ret; + + ret = cp7420_cfg_batt_chg_ctrl_5(dev); + if (ret) + return ret; + + ret = cp7420_cfg_temp_reg(dev); + if (ret) + return ret; + + ret = cp7420_cfg_dpm_ctrl(dev); + if (ret) + return ret; + + ret = cp7420_cfg_startup_ctrl(dev); + if (ret) + return ret; + + ret = cp7420_cfg_dither_ctrl(dev); + if (ret) + return ret; + + ret = cp7420_cfg_power_mon_ctrl(dev); + if (ret) + return ret; + + ret = cp7420_cfg_t_ibat(dev); + if (ret) + return ret; + + ret = cp7420_cfg_switch_curr_ctrl_1(dev); + if (ret) + return ret; + + return cp7420_cfg_switch_curr_ctrl_2(dev); +} + + +/** + * @brief Initialize the battery charger + * + * @param dev CP7420 device to access + * @return 0 for success + * @return -EINVAL if the I2C controller could not be found + */ +static int cp7420_charger_init(const struct device *dev) +{ + const struct cp7420_config *const config = dev->config; + int ret; + + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + ret = cp7420_apply_dt(dev); + if (ret) { + LOG_ERR("Failed to apply devicetree: %d", ret); + return -EIO; + } + + return 0; +} + +static const struct sensor_driver_api cp7420_charger_driver_api = { + .attr_get = cp7420_attribute_get, + .attr_set = cp7420_attribute_set, + .channel_get = cp7420_channel_get, +}; + +#define CP7420_INIT(n) \ + static struct cp7420_data cp7420_data_##n; \ + \ + static const struct cp7420_config cp7420_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .ibat_chg_max_ma = DT_INST_PROP(n, charge_current_milliamps), \ + .vbat_reg_max_mv = DT_INST_PROP(n, charge_voltage_millivolts), \ + .vsys_max_mv = DT_INST_PROP(n, maximum_system_millivolts), \ + .vsys_min_mv = DT_INST_PROP(n, minimum_system_millivolts), \ + .vin_ovp_en = DT_INST_PROP(n, enable_input_ovp), \ + .vsys_ovp_en = DT_INST_PROP(n, enable_system_ovp), \ + .vbat_ovp_en = DT_INST_PROP(n, enable_battery_ovp), \ + .sw_ocp_en = DT_INST_PROP(n, enable_switching_ocp), \ + .vin_ov_cfg = DT_INST_PROP(n, input_ovp_config), \ + .vbat_low = DT_INST_PROP(n, low_battery_threshold), \ + .iprechg_ma = DT_INST_PROP(n, precharge_current_milliamps), \ + .vbat_ov_cfg = DT_INST_PROP(n, battery_ovp_config), \ + .recharge_en = DT_INST_PROP(n, enable_recharge), \ + .recharge_offset = DT_INST_PROP(n, recharge_offset), \ + .recharge_deglitch = DT_INST_PROP(n, recharge_deglitch), \ + .vsys_ov_cfg = DT_INST_PROP(n, system_ovp_config), \ + .iterm_en = DT_INST_PROP(n, enable_charge_termination), \ + .iterm_ma = DT_INST_PROP(n, termination_current_milliamps), \ + .auto_chg_timer_en = DT_INST_PROP(n, enable_auto_charge_timer), \ + .prechg_timer = DT_INST_PROP(n, precharge_timer_config), \ + .fast_chg_timer = DT_INST_PROP(n, fast_charge_timer_config), \ + .ntc_en = DT_INST_PROP(n, enable_ntc_feedback), \ + .tsdie_en = DT_INST_PROP(n, enable_tsdie_protection), \ + .batgone_en = DT_INST_PROP(n, enable_batgone_detection), \ + .watchdog_timer = DT_INST_PROP(n, watchdog_timer_config), \ + .vin_dpm_threshold = DT_INST_PROP(n, input_voltage_dpm_config), \ + .fsw_cfg = DT_INST_PROP(n, switching_frequency_config), \ + .ibat_softstart = DT_INST_PROP(n, ibat_softstart_config), \ + .rechg_ibat_softstart = DT_INST_PROP(n, rechg_ibat_softstart), \ + .vsys_softstart = DT_INST_PROP(n, system_softstart), \ + .dither_en = DT_INST_PROP(n, enable_dithering), \ + .dither_rate = DT_INST_PROP(n, dither_rate_config), \ + .dither_limit = DT_INST_PROP(n, dither_limit_config), \ + .psys_en = DT_INST_PROP(n, psys_output_desired), \ + .rsi_cfg = DT_INST_PROP(n, input_sense_resistor_config), \ + .rso_cfg = DT_INST_PROP(n, output_sense_resistor_config), \ + .psys_ratio = DT_INST_PROP(n, psys_output_ratio_config), \ + .ocp_pwm_cfg = DT_INST_PROP(n, ocp_pwm_config), \ + .ocp_pfm_cfg = DT_INST_PROP(n, ocp_pfm_config), \ + .t_ibat_max1 = DT_INST_PROP(n, prochot_discharge_lower_limit), \ + .t_ibat_max2 = DT_INST_PROP(n, prochot_discharge_upper_limit), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &cp7420_charger_init, \ + NULL, \ + &cp7420_data_##n, \ + &cp7420_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &cp7420_charger_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CP7420_INIT) diff --git a/drivers/sensor/cp7420/cp7420.h b/drivers/sensor/cp7420/cp7420.h new file mode 100644 index 0000000000000..e2e8ef01d0615 --- /dev/null +++ b/drivers/sensor/cp7420/cp7420.h @@ -0,0 +1,355 @@ +/* + * Copyright(c) 2022 Cirrus Logic, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_CHARGER_CP7420_H_ +#define ZEPHYR_DRIVERS_SENSOR_CHARGER_CP7420_H_ + +#include + +#define CP7420_IPRECHG_CFG_MASK GENMASK(1, 0) +#define CP7420_IPRECHG_MIN_MA 128 +#define CP7420_IPRECHG_MAX_MA 512 +#define CP7420_IPRECHG_OFFSET_MA CP7420_IPRECHG_MIN_MA +#define CP7420_IPRECHG_STEP_MA 128 + +#define CP7420_IBAT_CHG_CFG_MASK GENMASK(6, 0) +#define CP7420_IBAT_CHG_MIN_MA 0 +#define CP7420_IBAT_CHG_MAX_MA 6000 +#define CP7420_IBAT_CHG_STEP_MA 50 + +#define CP7420_VBAT_REG_LSB_MASK GENMASK(7, 5) +#define CP7420_VBAT_REG_MSB_MASK GENMASK(6, 0) +#define CP7420_VBAT_REG_SHIFT 5 +#define CP7420_VBAT_REG_MIN_MV 0 +#define CP7420_VBAT_REG_MAX_MV 10230 +#define CP7420_VBAT_REG_STEP_MV 10 + +#define CP7420_VBAT_LOW_MASK GENMASK(4, 2) +#define CP7420_VBAT_LOW_SHIFT 2 + +#define CP7420_VBAT_OV_CFG_SHIFT 6 +#define CP7420_VBAT_OV_CFG_MASK GENMASK(7, CP7420_VBAT_OV_CFG_SHIFT) + +#define CP7420_RECHARGE_EN BIT(5) + +#define CP7420_RECHARGE_OFFSET_SHIFT 2 +#define CP7420_RECHARGE_OFFSET_MASK GENMASK(4, CP7420_RECHARGE_OFFSET_SHIFT) + +#define CP7420_RECAHRGE_DEGLITCH_MASK GENMASK(1, 0) + +#define CP7420_VSYS_OV_CFG_SHIFT 6 +#define CP7420_ITERM_EN BIT(4) +#define CP7420_ITERM_CFG_MIN_MA 100 +#define CP7420_ITERM_CFG_MAX_MA 1600 +#define CP7420_ITERM_CFG_STEP_MA 100 +#define CP7420_ITERM_CFG_OFFSET_MA CP7420_ITERM_CFG_MIN_MA + +#define CP7420_AUTO_CHG_TIMER_EN BIT(6) +#define CP7420_PRECHG_TIMER_SHIFT 3 +#define CP7420_PRECHG_TIMER_MASK GENMASK(5, CP7420_PRECHG_TIMER_SHIFT) +#define CP7420_FAST_CHG_TIMER_MASK GENMASK(2, 0) + +#define CP7420_VIN_REG_MIN_MV 3300 +#define CP7420_VIN_REG_MAX_MV 21000 +#define CP7420_VIN_REG_STEP_MV 100 +#define CP7420_VIN_REG_OFFSET_MV CP7420_VIN_REG_MIN_MV + +#define CP7420_IIN_REG_MIN_MA 0 +#define CP7420_IIN_REG_MAX_MA 10000 +#define CP7420_IIN_REG_STEP_MA 50 + +#define CP7420_IIN_LIMIT_1_MIN_MA 0 +#define CP7420_IIN_LIMIT_1_MAX_MA 6000 +#define CP7420_IIN_LIMIT_1_STEP_MA 50 + +#define CP7420_IIN_LIMIT_2_MIN_MA 0 +#define CP7420_IIN_LIMIT_2_MAX_MA 10000 +#define CP7420_IIN_LIMIT_2_STEP_MA 50 + +#define CP7420_IIN_LIMIT_PEAK_MIN_MA 0 +#define CP7420_IIN_LIMIT_PEAK_MAX_MA 10000 +#define CP7420_IIN_LIMIT_PEAK_STEP_MA 50 + +#define CP7420_VIN_LOW_MIN_MV 3800 +#define CP7420_VIN_LOW_MAX_MV 21000 +#define CP7420_VIN_LOW_STEP_MV 100 +#define CP7420_VIN_LOW_OFFSET_MV CP7420_VIN_LOW_MIN_MV + +#define CP7420_VSYS_MIN_MIN_MV 0 +#define CP7420_VSYS_MIN_MAX_MV 10000 +#define CP7420_VSYS_MIN_STEP_MV 50 + +#define CP7420_VSYS_MAX_MIN_MV 0 +#define CP7420_VSYS_MAX_MAX_MV 10000 +#define CP7420_VSYS_MAX_STEP_MV 50 + +#define CP7420_VSYS_LOW_MIN_MV 2500 +#define CP7420_VSYS_LOW_MAX_MV 9000 +#define CP7420_VSYS_LOW_STEP_MV 100 +#define CP7420_VSYS_LOW_OFFSET_MV CP7420_VSYS_LOW_MIN_MV + +#define CP7420_NTC_EN BIT(7) +#define CP7420_TSDIE_EN BIT(6) +#define CP7420_BATGONE_EN BIT(5) +#define CP7420_WATCHDOG_TIMER_MASK GENMASK(2, 0) + +#define CP7420_VIN_DPM_THRESH_MASK GENMASK(7, 4) +#define CP7420_VIN_DPM_THRESH_SHIFT 4 +#define CP7420_FSW_CFG_MASK GENMASK(3, 0) + +#define CP7420_IBAT_SOFTSTART_SHIFT 6 +#define CP7420_IBAT_SOFTSTART_MASK GENMASK(7, 6) +#define CP7420_RECHG_IBAT_SOFTSTART BIT(5) +#define CP7420_VSYS_SOFTSTART_SHIFT 3 +#define CP7420_VSYS_SOFTSTART_MASK GENMASK(4, 3) + +#define CP7420_IBAT_DISCHG_LIM_1_MIN_MA 0 +#define CP7420_IBAT_DISCHG_LIM_1_MAX_MA 20000 +#define CP7420_IBAT_DISCHG_LIM_1_STEP_MA 100 + +#define CP7420_IBAT_DISCHG_LIM_2_MIN_MA 0 +#define CP7420_IBAT_DISCHG_LIM_2_MAX_MA 40000 +#define CP7420_IBAT_DISCHG_LIM_2_STEP_MA 200 + +#define CP7420_T_IIN_MAX1_SHIFT 2 +#define CP7420_T_IIN_MAX1_MASK GENMASK(3, CP7420_T_IIN_MAX1_SHIFT) + +#define CP7420_T_IIN_MAX2_MASK GENMASK(1, 0) + +#define CP7420_T_IBAT_MAX1_SHIFT 6 +#define CP7420_T_IBAT_MAX1_MASK GENMASK(7, CP7420_T_IBAT_MAX1_SHIFT) + +#define CP7420_T_IBAT_MAX2_SHIFT 4 +#define CP7420_T_IBAT_MAX2_MASK GENMASK(5, CP7420_T_IBAT_MAX2_SHIFT) + +#define CP7420_T_IBAT_MASK (CP7420_T_IBAT_MAX1_MASK | \ + CP7420_T_IBAT_MAX2_MASK) + +#define CP7420_PROCHOT_DUR_SHIFT 4 +#define CP7420_PROCHOT_DUR_MASK GENMASK(7, CP7420_PROCHOT_DUR_SHIFT) + +#define CP7420_PROCHOT_DEBOUNCE_SHIFT 2 +#define CP7420_PROCHOT_DEBOUNCE_MASK GENMASK(3, CP7420_PROCHOT_DEBOUNCE_SHIFT) + +#define CP7420_PROCHOT_MON_SHIFT 5 + +#define CP7420_DITHER_EN BIT(7) +#define CP7420_DITHER_RATE_SHIFT 4 +#define CP7420_DITHER_RATE_MASK GENMASK(6, CP7420_DITHER_RATE_SHIFT) +#define CP7420_DITHER_LIMIT_MASK GENMASK(3, 0) + +#define CP7420_PSYS_EN BIT(7) +#define CP7420_RSI_CFG_SHIFT 5 +#define CP7420_RSI_CFG_MASK GENMASK(6, CP7420_RSI_CFG_SHIFT) +#define CP7420_RSO_CFG_SHIFT 3 +#define CP7420_RSO_CFG_MASK GENMASK(4, CP7420_RSO_CFG_SHIFT) +#define CP7420_PSYS_RATIO_SHIFT 1 +#define CP7420_PSYS_RATIO_MASK GENMASK(2, CP7420_PSYS_RATIO_SHIFT) + +#define CP7420_OCP_PWM_CFG_MASK GENMASK(4, 0) +#define CP7420_OCP_PWM_MIN_MA 3800 +#define CP7420_OCP_PWM_MAX_MA 6800 +#define CP7420_OCP_PWM_OFFSET_MA CP7420_OCP_PWM_MIN_MA +#define CP7420_OCP_PWM_STEP_MA 100 + +#define CP7420_OCP_PFM_CFG_MASK GENMASK(4, 0) +#define CP7420_OCP_PFM_MIN_MA 1300 +#define CP7420_OCP_PFM_MAX_MA 4000 +#define CP7420_OCP_PFM_OFFSET_MA CP7420_OCP_PFM_MIN_MA +#define CP7420_OCP_PFM_STEP_MA 100 + +#define CP7420_VIN_REG_EN BIT(7) +#define CP7420_IIN_REG_EN BIT(6) +#define CP7420_LPM_EN BIT(2) +#define CP7420_CHG_MODE_MASK GENMASK(2, 0) + +#define CP7420_ADC_EN BIT(7) +#define CP7420_PAUSE_ADC_UPDATES BIT(5) +#define CP7420_PAUSE_INT_UPDATES BIT(6) +#define CP7420_PAUSE_UPDATES (CP7420_PAUSE_ADC_UPDATES | \ + CP7420_PAUSE_INT_UPDATES) + +#define CP7420_ADC_NTC_STEP_UV 122 +#define CP7420_ADC_VBAT_STEP_UV 3000 +#define CP7420_ADC_TDIE_STEP_UC 45200 +#define CP7420_ADC_IIN_STEP_UA 2500 +#define CP7420_ADC_IBAT_STEP_UA 10000 +#define CP7420_ADC_IBAT_MASK GENMASK(11, 0) +#define CP7420_ADC_IBAT_DISCHG BIT(15) +#define CP7420_ADC_VSYS_STEP_UV 3000 +#define CP7420_ADC_VIN_STEP_UV 6000 + +/* Register addresses */ +enum { + POWER_STATUS = 0x6, + CHARGE_STATUS = 0x7, + REGULATION_STATUS = 0x8, + TEMP_TIMER_STATUS = 0x9, + PROTECTION_STATUS_0 = 0xa, + PROTECTION_STATUS_1 = 0xb, + ADC_NTC_STATUS = 0xc, + ADC_VBAT_STATUS = 0xe, + ADC_TDIE_STATUS = 0x10, + ADC_IIN_STATUS = 0x12, + ADC_IBAT_STATUS = 0x14, + ADC_VSYS_STATUS = 0x16, + ADC_VIN_STATUS = 0x18, + DEVICE_CONFIGURATION = 0x25, + OPERATION_CTRL_0 = 0x26, + PROTECTION_CTRL = 0x28, + BATTERY_CHGING_CTRL_0 = 0x29, + BATTERY_CHGING_CTRL_1, + BATTERY_CHGING_CTRL_2, + BATTERY_CHGING_CTRL_3, + BATTERY_CHGING_CTRL_4, + BATTERY_CHGING_CTRL_5, + INPUT_CTRL_0 = 0x2f, + INPUT_CTRL_1, + INPUT_CTRL_2, + INPUT_CTRL_3, + INPUT_CTRL_4, + INPUT_CTRL_5, + SYS_VOLTAGE_CTRL_0 = 0x35, + SYS_VOLTAGE_CTRL_1, + SYS_VOLTAGE_CTRL_2, + TEMP_REGULATION_CTRL = 0x38, + DPM_CTRL = 0x39, + STARTUP_CTRL = 0x3a, + BATTERY_DISCHG_CTRL_0 = 0x3b, + BATTERY_DISCHG_CTRL_1, + TWO_LEVEL_CURRENT_CTRL = 0x3d, + PROCHOT_CTRL_0 = 0x3e, + PROCHOT_CTRL_1, + PROCHOT_CTRL_2, + DITHERING_CTRL = 0x41, + ADC_CTRL_0 = 0x42, + ADC_CTRL_1 = 0x43, + POWER_MONITOR_CTRL = 0x44, + SWITCH_CURRENT_CTRL_1 = 0x45, + SWITCH_CURRENT_CTRL_2, +}; + +/* CP7420 specific attributes */ +enum cp7420_attributes { + CP7420_ATTR_PROCHOT_DURATION = SENSOR_ATTR_PRIV_START, + CP7420_ATTR_PROCHOT_DEBOUNCE, +}; + +/* CP7420 specific channels */ +enum cp7420_channels { + CP7420_CHAN_IIN_LIMIT_1 = SENSOR_CHAN_PRIV_START, + CP7420_CHAN_IIN_LIMIT_2, + CP7420_CHAN_IIN_LIMIT_PEAK, + CP7420_CHAN_VIN_LOW, + CP7420_CHAN_IBAT_DISCHARGE_LIMIT_1, + CP7420_CHAN_IBAT_DISCHARGE_LIMIT_2, + CP7420_CHAN_VSYSMIN, + CP7420_CHAN_LOW_POWER_MODE, + CP7420_CHAN_PROCHOT_ALL, +}; + +/* CP7420 ADC channels */ +enum cp7420_adc { + CP7420_ADC_NTC, + CP7420_ADC_VBAT, + CP7420_ADC_TDIE, + CP7420_ADC_IIN, + CP7420_ADC_IBAT_CHG, + CP7420_ADC_VSYS, + CP7420_ADC_VIN, + CP7420_ADC_PROG, + CP7420_ADC_ADDR, + CP7420_ADC_COUNT, +}; + +struct cp7420_data { + uint16_t vin_reg_mv; + uint16_t iin_reg_ma; + uint16_t vbat_reg_mv; + uint16_t iin_limit_1_ma; + uint16_t iin_limit_2_ma; + uint16_t iin_limit_peak_ma; + uint16_t vin_low_mv; + uint16_t vsys_low_mv; + uint16_t iprechg_ma; + uint16_t ibat_chg_ma; + uint16_t ibat_dischg_limit_1_ma; + uint16_t ibat_dischg_limit_2_ma; + uint16_t vsys_min_mv; + uint16_t prochot_mon; + uint8_t prochot_debounce; + uint8_t t_ibat_max_1; + uint8_t t_ibat_max_2; + uint8_t t_iin_max_1; + uint8_t t_iin_max_2; + uint8_t prochot_duration; + bool vin_reg_en; + bool iin_reg_en; + bool recharge_en; + bool lpm_en; + bool chg_mode; + bool psys_en; +}; + +struct cp7420_config { + struct i2c_dt_spec i2c; + uint16_t i2c_addr; + uint16_t ibat_chg_max_ma; + uint16_t vbat_reg_max_mv; + uint16_t vsys_max_mv; + uint16_t vsys_min_mv; + + bool vin_ovp_en; + bool vsys_ovp_en; + bool vbat_ovp_en; + bool sw_ocp_en; + uint8_t vin_ov_cfg; + + uint8_t vbat_low; + uint16_t iprechg_ma; + + uint8_t vbat_ov_cfg; + bool recharge_en; + uint8_t recharge_offset; + uint8_t recharge_deglitch; + + uint8_t vsys_ov_cfg; + bool iterm_en; + uint16_t iterm_ma; + + bool auto_chg_timer_en; + uint8_t prechg_timer; + uint8_t fast_chg_timer; + + bool ntc_en; + bool tsdie_en; + bool batgone_en; + uint8_t watchdog_timer; + + uint8_t vin_dpm_threshold; + uint8_t fsw_cfg; + + uint8_t ibat_softstart; + bool rechg_ibat_softstart; + uint8_t vsys_softstart; + + bool dither_en; + uint8_t dither_rate; + uint8_t dither_limit; + + bool psys_en; + uint8_t rsi_cfg; + uint8_t rso_cfg; + uint8_t psys_ratio; + + uint8_t ocp_pwm_cfg; + uint8_t ocp_pfm_cfg; + + uint8_t t_ibat_max1; + uint8_t t_ibat_max2; +}; + +#endif From a225a053da0078b62abe149019944cee86033b59 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Tue, 15 Nov 2022 13:28:49 -0600 Subject: [PATCH 2/3] dts: sensor: Adds CP7420 dt bindings Documents the CP7420 battery charger dt bindings Signed-off-by: Ricardo Rivera-Matos --- dts/bindings/sensor/cirrus,cp7420.yaml | 209 +++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 dts/bindings/sensor/cirrus,cp7420.yaml diff --git a/dts/bindings/sensor/cirrus,cp7420.yaml b/dts/bindings/sensor/cirrus,cp7420.yaml new file mode 100644 index 0000000000000..3a8858632afff --- /dev/null +++ b/dts/bindings/sensor/cirrus,cp7420.yaml @@ -0,0 +1,209 @@ +# +# Copyright (c) 2022 Cirrus Logic, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Cirrus Logic CP7420 Battery Charger + +compatible: "cirrus,cp7420" + +include: i2c-device.yaml + +properties: + charge-current-milliamps: + type: int + required: true + description: Battery charge current in mA + + charge-voltage-millivolts: + type: int + required: true + description: Battery charge voltage in mV + + maximum-system-millivolts: + type: int + required: true + description: Maximum system voltage in mV + + minimum-system-millivolts: + type: int + required: true + description: Minimum system voltage in mV + + enable-input-ovp: + type: boolean + description: Enable input overvoltage protection + + enable-system-ovp: + type: boolean + description: Enable system overvoltage protection + + enable-battery-ovp: + type: boolean + description: Enable battery overvoltage protection + + enable-switching-ocp: + type: boolean + description: Enable switching overcurrent protection + + input-ovp-config: + type: int + required: true + description: Configuration code for the input overvoltage protection + + low-battery-threshold: + type: int + required: true + description: Configuration code for precharge to fast charge transition + + precharge-current-milliamps: + type: int + required: true + description: Precharge current in mA + + battery-ovp-config: + type: int + required: true + description: Configuration code for the battery overvoltage protection + + enable-recharge: + type: boolean + description: Enable battery recharging + + recharge-offset: + type: int + required: true + description: Configuration code for the recharge offset + + recharge-deglitch: + type: int + required: true + description: Configuration code for the recharge deglitch + + system-ovp-config: + type: int + required: true + description: Configuration code for the system overvoltage protection + + enable-charge-termination: + type: boolean + description: Enable charging termination + + termination-current-milliamps: + type: int + required: true + description: Charge termination threshold in milliamps + + enable-auto-charge-timer: + type: boolean + description: Enable charging termination + + precharge-timer-config: + type: int + required: true + description: Configuration code for the precharge timer + + fast-charge-timer-config: + type: int + required: true + description: Configuration code for the fast charge timer + + enable-ntc-feedback: + type: boolean + description: Enable thermistor feedback + + enable-tsdie-protection: + type: boolean + description: Enable TSDIE protection + + enable-batgone-detection: + type: boolean + description: Enable BATGONE detection + + enable-ntc-feedback: + type: boolean + description: Enable thermistor feedback + + watchdog-timer-config: + type: int + required: true + description: Configuration code for the watchdog timer + + input-voltage-dpm-config: + type: int + required: true + description: Configuration code for the watchdog timer + + switching-frequency-config: + type: int + required: true + description: Configuration code for the switching frequency + + ibat-softstart-config: + type: int + required: true + description: Configuration code for IBAT softstart + + rechg-ibat-softstart: + type: int + required: true + description: Configuration code for recharge IBAT softstart + + system-softstart: + type: int + required: true + description: Configuration code for system softstart + + enable-dithering: + type: boolean + description: Enable converter dithering + + dither-rate-config: + type: int + required: true + description: Configuration code for dithering rate + + dither-limit-config: + type: int + required: true + description: Configuration code for dithering limit + + psys-output-desired: + type: boolean + description: PSYS analog output is desired + + input-sense-resistor-config: + type: int + required: true + description: Configuration code for the input sense resistor + + output-sense-resistor-config: + type: int + required: true + description: Configuration code for the output sense resistor + + psys-output-ratio-config: + type: int + required: true + description: Configuration code for the PSYS gain + + ocp-pwm-config: + type: int + required: true + description: Configuration code for the overcurrent protection in PWM mode + + ocp-pfm-config: + type: int + required: true + description: Configuration code for the overcurrent protection in PFM mode + + prochot-discharge-lower-limit: + type: int + required: true + description: Configuration code for the lower PROCHOT discharge limit + + prochot-discharge-upper-limit: + type: int + required: true + description: Configuration code for the upper PROCHOT discharge limit From 5c66c1299a80d6d8e7b9cb2915e38ed7695cf47d Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Tue, 15 Nov 2022 13:51:39 -0600 Subject: [PATCH 3/3] samples: sensor: cp7420: Adds a sample CP7420 app Adds sample application for the CP7420 battery charging IC. Signed-off-by: Ricardo Rivera-Matos --- samples/sensor/cp7420/CMakeLists.txt | 8 ++++ samples/sensor/cp7420/README.rst | 39 ++++++++++++++++ .../cp7420/boards/nucleo_f401re.overlay | 45 +++++++++++++++++++ samples/sensor/cp7420/prj.conf | 5 +++ samples/sensor/cp7420/sample.yaml | 11 +++++ samples/sensor/cp7420/src/main.c | 34 ++++++++++++++ 6 files changed, 142 insertions(+) create mode 100644 samples/sensor/cp7420/CMakeLists.txt create mode 100644 samples/sensor/cp7420/README.rst create mode 100644 samples/sensor/cp7420/boards/nucleo_f401re.overlay create mode 100644 samples/sensor/cp7420/prj.conf create mode 100644 samples/sensor/cp7420/sample.yaml create mode 100644 samples/sensor/cp7420/src/main.c diff --git a/samples/sensor/cp7420/CMakeLists.txt b/samples/sensor/cp7420/CMakeLists.txt new file mode 100644 index 0000000000000..1dca5916f96e5 --- /dev/null +++ b/samples/sensor/cp7420/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(cp7420) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) \ No newline at end of file diff --git a/samples/sensor/cp7420/README.rst b/samples/sensor/cp7420/README.rst new file mode 100644 index 0000000000000..77abc0ebd95a2 --- /dev/null +++ b/samples/sensor/cp7420/README.rst @@ -0,0 +1,39 @@ +.. cp7420: + + CP7420 Charger + ################################### + + Overview + ******** + + + + Requirements + ************ + + CP7420 + + This sample requires a board which provides a configuration for Arduino + connectors and defines node aliases for the I2C interface. + For more info about the node structure see + :zephyr_file:`samples/sensor/cp7420/boards/nucleo_f401re.overlay` + + Building and Running + ******************** + + This sample application uses an CP7420 sensor connected to a board via I2C. + Connect the sensor pins according to the connection diagram given in the + + .. zephyr-app-commands:: + :zephyr-app: samples/sensor/cp7420 + :board: nucleo_f401re + :goals: build flash + :compact: + + Sample Output + ============= + To check output of this sample , any serial console program can be used. + This example uses ``picocom`` on the serial port ``/dev/ttyUSB0``: + + References + *********** \ No newline at end of file diff --git a/samples/sensor/cp7420/boards/nucleo_f401re.overlay b/samples/sensor/cp7420/boards/nucleo_f401re.overlay new file mode 100644 index 0000000000000..cf9b8b6da691b --- /dev/null +++ b/samples/sensor/cp7420/boards/nucleo_f401re.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 Cirrus Logic Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&arduino_i2c { + status = "okay"; + + cp7420@58 { + compatible = "cirrus,cp7420"; + status = "okay"; + label = "CP7420"; + reg = <0x58>; + charge-current-milliamps = <3000>; + charge-voltage-millivolts = <8400>; + maximum-system-millivolts = <9000>; + minimum-system-millivolts = <8000>; + input-ovp-config = <0x1>; + low-battery-threshold = <0x1>; + precharge-current-milliamps = <256>; + battery-ovp-config = <0x1>; + recharge-offset = <0x1>; + recharge-deglitch = <0x1>; + system-ovp-config = <0x1>; + termination-current-milliamps = <0x1>; + precharge-timer-config = <0x1>; + fast-charge-timer-config = <0x1>; + watchdog-timer-config = <0x1>; + input-voltage-dpm-config = <0x1>; + switching-frequency-config = <0x1>; + ibat-softstart-config = <0x1>; + rechg-ibat-softstart = <0x1>; + system-softstart = <0x1>; + dither-rate-config = <0x1>; + dither-limit-config = <0x1>; + input-sense-resistor-config = <0x1>; + output-sense-resistor-config = <0x1>; + psys-output-ratio-config = <0x1>; + ocp-pwm-config = <0x1>; + ocp-pfm-config = <0x1>; + prochot-discharge-lower-limit = <0x1>; + prochot-discharge-upper-limit = <0x1>; + }; +}; \ No newline at end of file diff --git a/samples/sensor/cp7420/prj.conf b/samples/sensor/cp7420/prj.conf new file mode 100644 index 0000000000000..9f8b6e8fde885 --- /dev/null +++ b/samples/sensor/cp7420/prj.conf @@ -0,0 +1,5 @@ +CONFIG_I2C=y +CONFIG_LOG=y +CONFIG_SENSOR=y +CONFIG_CP7420=y +CONFIG_CBPRINTF_FP_SUPPORT=y \ No newline at end of file diff --git a/samples/sensor/cp7420/sample.yaml b/samples/sensor/cp7420/sample.yaml new file mode 100644 index 0000000000000..33aeda6d497cd --- /dev/null +++ b/samples/sensor/cp7420/sample.yaml @@ -0,0 +1,11 @@ +sample: + description: Demonstration of the CP7420 charging IC driver + name: CP7420 Sample +tests: + sample.sensor.cp7420: + harness: sensor + platform_allow: nucleo_f401re + integration_platforms: + - nucleo_f401re + tags: sensors + depends_on: i2c \ No newline at end of file diff --git a/samples/sensor/cp7420/src/main.c b/samples/sensor/cp7420/src/main.c new file mode 100644 index 0000000000000..722bece8a1970 --- /dev/null +++ b/samples/sensor/cp7420/src/main.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Cirrus Logic Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define CP7420 DT_INST(0, cirrus_cp7420) + +#if DT_NODE_HAS_STATUS(CP7420, okay) +#define CP7420_LABEL DT_LABEL(CP7420) +#else +#error Your devicetree has no enabled nodes with compatible "cirrus,cp7420" +#define CP7420_LABEL "" +#endif + +void main(void) +{ + const struct device *const dev = DEVICE_DT_GET_ANY(cirrus_cp7420); + + if (dev == NULL) { + printk("No device found...\n"); + return; + } + + while (1) { + printk("Found device %s\n", dev->name); + k_sleep(K_MSEC(1000)); + } +} \ No newline at end of file