power: qcom: qbg: add jeita/step-chg parameters for QBG algorithm

Parse JEITA and step charging settings from battery
profile and send them to userspace algorithm for
TTF calculation.

Change-Id: I6250b34ecdca0d94d672f5859843cc4c54923412
Signed-off-by: Hui Liu <huliu@codeaurora.org>
This commit is contained in:
Hui Liu 2021-05-17 18:35:03 +08:00
commit c4e2bcf66f
4 changed files with 264 additions and 0 deletions

View file

@ -12,6 +12,12 @@
|| ((left) <= (right) && (left) <= (value) \
&& (value) <= (right)))
enum ttf_calc_mode {
TTF_MODE_VBAT_STEP_CHG = 0,
TTF_MODE_OCV_STEP_CHG,
TTF_MODE_SOC_STEP_CHG,
};
struct battery_data_table0 {
int soc_length;
int ocv_length;

View file

@ -84,6 +84,7 @@ enum QBG_ACCUM_INTERVAL_TYPE {
* @kdata: QBG Kernel space data structure
* @udata: QBG user space data structure
* @battery: Pointer to QBG battery data structure
* @step_chg_jeita_params: Jeita step charge parameters structure
* @fifo_lock: Lock for reading FIFO data
* @data_lock: Lock for reading kdata from QBG char device
* @batt_id_chan: IIO channel to read battery ID
@ -154,6 +155,7 @@ struct qti_qbg {
struct qbg_kernel_data kdata;
struct qbg_user_data udata;
struct qbg_battery_data *battery;
struct qbg_step_chg_jeita_params *step_chg_jeita_params;
struct mutex fifo_lock;
struct mutex data_lock;
struct iio_channel *batt_id_chan;

View file

@ -99,6 +99,12 @@
#define OCV_BOOST_MAX_UV 5600000
#define OCV_BOOST_STEP_UV 100000
#define BATT_HOT_DECIDEGREE_MAX 600
#define MILLI_TO_10NANO 100000
#define MICRO_TO_10NANO 100
#define MILLI_TO_MICRO 1000
static int qbg_debug_mask;
static const unsigned int qbg_accum_interval[8] = {
@ -706,6 +712,211 @@ static int qbg_notifier_cb(struct notifier_block *nb,
return NOTIFY_OK;
}
static int qbg_read_range_data_from_node(struct device_node *node,
const char *prop_str, struct ranges *ranges,
int max_threshold, u32 max_value)
{
int rc = 0, i, length, per_tuple_length, tuples;
if (!node || !prop_str || !ranges) {
pr_err("Invalid parameters passed\n");
return -EINVAL;
}
rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32));
if (rc < 0) {
pr_err("Count %s failed, rc=%d\n", prop_str, rc);
return rc;
}
length = rc;
per_tuple_length = sizeof(struct range_data) / sizeof(u32);
if (length % per_tuple_length) {
pr_err("%s length (%d) should be multiple of %d\n",
prop_str, length, per_tuple_length);
return -EINVAL;
}
tuples = length / per_tuple_length;
if (tuples > QBG_MAX_STEP_CHG_ENTRIES) {
pr_err("too many entries(%d), only %d allowed\n",
tuples, QBG_MAX_STEP_CHG_ENTRIES);
return -EINVAL;
}
rc = of_property_read_u32_array(node, prop_str, (u32 *)ranges->data, length);
if (rc < 0) {
pr_err("Read %s failed, rc=%d\n", prop_str, rc);
return rc;
}
for (i = 0; i < tuples; i++) {
if (ranges->data[i].low_threshold >
ranges->data[i].high_threshold) {
pr_err("%s thresholds should be in ascendant ranges data\n",
prop_str);
rc = -EINVAL;
goto clean;
}
if (i != 0) {
if (ranges->data[i - 1].high_threshold >
ranges->data[i].low_threshold) {
pr_err("%s thresholds should be in ascendant ranges data\n",
prop_str);
rc = -EINVAL;
goto clean;
}
}
if (ranges->data[i].low_threshold > max_threshold)
ranges->data[i].low_threshold = max_threshold;
if (ranges->data[i].high_threshold > max_threshold)
ranges->data[i].high_threshold = max_threshold;
if (ranges->data[i].value > max_value)
ranges->data[i].value = max_value;
}
ranges->range_count = tuples;
ranges->valid = true;
return rc;
clean:
memset(ranges, 0, tuples * sizeof(struct range_data));
return rc;
}
#define QBG_DEFAULT_JEITA_FULL_FV_10NV 420000000
#define QBG_DEFAULT_BATTERY_BETA 4250
#define QBG_DEFAULT_BATTERY_THERM_KOHM 100
#define QBG_DEFAULT_JEITA_WARM_ADC_DATA 0x25e3 /* WARM = 40 DegC */
#define QBG_DEFAULT_JEITA_COOL_ADC_DATA 0x5314 /* COOL = 5 DegC */
static int parse_step_chg_jeita_params(struct qti_qbg *chip, struct device_node *profile_node)
{
struct qbg_step_chg_jeita_params *step_chg_jeita;
bool soc_based_step_chg = false;
bool ocv_based_step_chg = false;
int rc;
int i = 0;
u32 temp[2];
bool jeita_thresh_valid = true;
step_chg_jeita = devm_kzalloc(chip->dev, sizeof(*step_chg_jeita),
GFP_KERNEL);
if (!step_chg_jeita)
return -ENOMEM;
/* choose the lower of the two soft threaholds as the jeita-full-fv */
step_chg_jeita->jeita_full_fv_10nv = QBG_DEFAULT_JEITA_FULL_FV_10NV;
rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-fv-uv",
temp, 2);
if (!rc)
step_chg_jeita->jeita_full_fv_10nv = min(temp[0], temp[1]) * MICRO_TO_10NANO;
else
pr_debug("Failed to read jeita full fv from battery profile, rc=%d\n", rc);
step_chg_jeita->jeita_full_iterm_10na = chip->iterm_ma * MILLI_TO_10NANO;
soc_based_step_chg = of_property_read_bool(profile_node, "qcom,soc-based-step-chg");
ocv_based_step_chg = of_property_read_bool(profile_node, "qcom,ocv-based-step-chg");
if (soc_based_step_chg)
step_chg_jeita->ttf_calc_mode = TTF_MODE_SOC_STEP_CHG;
else if (ocv_based_step_chg)
step_chg_jeita->ttf_calc_mode = TTF_MODE_OCV_STEP_CHG;
step_chg_jeita->battery_beta = QBG_DEFAULT_BATTERY_BETA;
rc = of_property_read_u32(profile_node, "qcom,battery-beta",
&step_chg_jeita->battery_beta);
if (rc < 0)
pr_debug("Failed to read battery beta form battery profile, rc=%d\n", rc);
step_chg_jeita->battery_therm_kohm = QBG_DEFAULT_BATTERY_THERM_KOHM;
rc = of_property_read_u32(profile_node, "qcom,battery-therm-kohm",
&step_chg_jeita->battery_therm_kohm);
if (rc < 0)
pr_debug("Failed to read battery therm from battery profile, rc=%d\n", rc);
step_chg_jeita->jeita_cool_adc_value = QBG_DEFAULT_JEITA_COOL_ADC_DATA;
step_chg_jeita->jeita_warm_adc_value = QBG_DEFAULT_JEITA_WARM_ADC_DATA;
rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-thresholds",
temp, 2);
if (!rc) {
step_chg_jeita->jeita_cool_adc_value = temp[0];
step_chg_jeita->jeita_warm_adc_value = temp[1];
} else {
jeita_thresh_valid = false;
pr_debug("Failed to read jeita cool and warm value from battery profile, rc=%d\n",
rc);
}
rc = qbg_read_range_data_from_node(profile_node,
"qcom,jeita-fcc-ranges",
&step_chg_jeita->jeita_fcc_cfg,
BATT_HOT_DECIDEGREE_MAX,
chip->fastchg_curr_ma * MILLI_TO_MICRO);
if (rc < 0)
pr_debug("Failed to read qcom,jeita-fcc-ranges from battery profile, rc=%d\n",
rc);
rc = qbg_read_range_data_from_node(profile_node,
"qcom,jeita-fv-ranges",
&step_chg_jeita->jeita_fv_cfg,
BATT_HOT_DECIDEGREE_MAX, chip->float_volt_uv);
if (rc < 0)
pr_debug("Failed to read qcom,jeita-fv-ranges from battery profile, rc=%d\n",
rc);
if ((step_chg_jeita->jeita_fcc_cfg.valid != step_chg_jeita->jeita_fv_cfg.valid)
|| (jeita_thresh_valid != step_chg_jeita->jeita_fcc_cfg.valid)) {
pr_err("battery JEITA configuration is not valid\n");
return -EINVAL;
}
rc = qbg_read_range_data_from_node(profile_node,
"qcom,step-chg-ranges",
&step_chg_jeita->step_fcc_cfg,
soc_based_step_chg ? 100 : chip->float_volt_uv,
chip->fastchg_curr_ma * MILLI_TO_MICRO);
if (rc < 0)
pr_debug("Failed to read qcom,step-chg-ranges from battery profile, rc=%d\n",
rc);
qbg_dbg(chip, QBG_DEBUG_PROFILE, "jeita_full_fv = %dnv, jeita_full_iterm = %dna, jeita_warm_adc = 0x%x, jeita_cool_adc = 0x%x, battery_beta = %d, battery_therm = %dkohm\n",
step_chg_jeita->jeita_full_fv_10nv,
step_chg_jeita->jeita_full_iterm_10na,
step_chg_jeita->jeita_warm_adc_value,
step_chg_jeita->jeita_cool_adc_value,
step_chg_jeita->battery_beta,
step_chg_jeita->battery_therm_kohm);
pr_debug("step-chg-ranges:\n");
for (i = 0; i < step_chg_jeita->step_fcc_cfg.range_count; i++) {
pr_debug("%d %d %d\n",
step_chg_jeita->step_fcc_cfg.data[i].low_threshold,
step_chg_jeita->step_fcc_cfg.data[i].high_threshold,
step_chg_jeita->step_fcc_cfg.data[i].value);
}
pr_debug("jeita-fcc-ranges:\n");
for (i = 0; i < step_chg_jeita->jeita_fcc_cfg.range_count; i++) {
pr_debug("%d %d %d\n",
step_chg_jeita->jeita_fcc_cfg.data[i].low_threshold,
step_chg_jeita->jeita_fcc_cfg.data[i].high_threshold,
step_chg_jeita->jeita_fcc_cfg.data[i].value);
}
pr_debug("jeita-fv-ranges:\n");
for (i = 0; i < step_chg_jeita->jeita_fv_cfg.range_count; i++) {
pr_debug("%d %d %d\n",
step_chg_jeita->jeita_fv_cfg.data[i].low_threshold,
step_chg_jeita->jeita_fv_cfg.data[i].high_threshold,
step_chg_jeita->jeita_fv_cfg.data[i].value);
}
chip->step_chg_jeita_params = step_chg_jeita;
return 0;
}
static int qbg_load_battery_profile(struct qti_qbg *chip)
{
struct device_node *node = chip->dev->of_node;
@ -771,6 +982,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip)
}
chip->nominal_capacity = temp[0];
rc = parse_step_chg_jeita_params(chip, profile_node);
out:
of_node_put(chip->batt_node);
return rc;
@ -1448,6 +1660,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
struct qbg_config __user *config_user;
struct qbg_config config;
struct qbg_essential_params __user *params_user;
struct qbg_step_chg_jeita_params __user *step_chg_params_user;
unsigned long rtc_sec;
int rc = 0, i;
@ -1499,6 +1712,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
config.pon_tbat = chip->pon_tbat;
config.pon_soc = chip->pon_soc;
config.float_volt_uv = chip->float_volt_uv;
config.fastchg_curr_ma = chip->fastchg_curr_ma;
config.vbat_cutoff_mv = chip->vbat_cutoff_mv;
config.ibat_cutoff_ma = chip->ibat_cutoff_ma;
config.vph_min_mv = chip->vph_min_mv;
@ -1559,6 +1773,21 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
qbg_dbg(chip, QBG_DEBUG_SDAM, "Essential params written, time:%lu secs\n",
rtc_sec);
break;
case QBGIOCXSTEPCHGCFG:
step_chg_params_user = (struct qbg_step_chg_jeita_params __user *)arg;
if (copy_to_user(step_chg_params_user, (void *)chip->step_chg_jeita_params,
sizeof(struct qbg_step_chg_jeita_params))) {
pr_err("Failed to copy QBG step and jeita charge params to user\n");
return -EFAULT;
}
qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXSTEPCHGCFG: jeita_full_fv_10nv:%d jeita_warm_adc_value:0x%x jeita_cool_adc_value:0x%x ttf_calc_mode:%u\n",
chip->step_chg_jeita_params->jeita_full_fv_10nv,
chip->step_chg_jeita_params->jeita_warm_adc_value,
chip->step_chg_jeita_params->jeita_cool_adc_value,
chip->step_chg_jeita_params->ttf_calc_mode);
break;
default:
pr_err("IOCTL %d not supported\n", cmd);

View file

@ -7,6 +7,7 @@
#define __QBG_H__
#define MAX_FIFO_COUNT 36
#define QBG_MAX_STEP_CHG_ENTRIES 6
enum QBG_STATE {
QBG_LPM,
@ -143,9 +144,35 @@ struct qbg_user_data {
struct qbg_param param[QBG_PARAM_MAX];
} __attribute__ ((__packed__));
struct range_data {
int low_threshold;
int high_threshold;
unsigned int value;
} __attribute__ ((__packed__));
struct ranges {
struct range_data data[QBG_MAX_STEP_CHG_ENTRIES];
unsigned char range_count;
_Bool valid;
} __attribute__((__packed__));
struct qbg_step_chg_jeita_params {
int jeita_full_fv_10nv;
int jeita_full_iterm_10na;
int jeita_warm_adc_value;
int jeita_cool_adc_value;
int battery_beta;
int battery_therm_kohm;
struct ranges step_fcc_cfg;
struct ranges jeita_fcc_cfg;
struct ranges jeita_fv_cfg;
unsigned char ttf_calc_mode;
} __attribute__ ((__packed__));
/* IOCTLs to read & write QBG config and essential params */
#define QBGIOCXCFG _IOR('B', 0x01, struct qbg_config)
#define QBGIOCXEPR _IOR('B', 0x02, struct qbg_essential_params)
#define QBGIOCXEPW _IOWR('B', 0x03, struct qbg_essential_params)
#define QBGIOCXSTEPCHGCFG _IOWR('B', 0x04, struct qbg_step_chg_jeita_params)
#endif