From 88a9b4ea32652c246cb0b03b7c89b624c466b9bd Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Fri, 27 Aug 2021 02:35:52 +0530 Subject: [PATCH] drivers: thermal: Add support to scale ibat current using range factor Add support to read ibat range factor from nvmem and use it to scale ibat current for greater than default max supported ibat range. Change-Id: Iee83be8d6663920d4df0b792417820d222e3ff46 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/qcom/bcl_pmic5.c | 97 +++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c index b4730211eec7..04352b2ec974 100644 --- a/drivers/thermal/qcom/bcl_pmic5.c +++ b/drivers/thermal/qcom/bcl_pmic5.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include "../thermal_core.h" @@ -91,6 +93,19 @@ static char bcl_int_names[BCL_TYPE_MAX][25] = { "bcl-lvl2", }; +enum bcl_ibat_ext_range_type { + BCL_IBAT_RANGE_LVL0, + BCL_IBAT_RANGE_LVL1, + BCL_IBAT_RANGE_LVL2, + BCL_IBAT_RANGE_MAX, +}; + +static uint32_t bcl_ibat_ext_ranges[BCL_IBAT_RANGE_MAX] = { + 10, /* default range factor */ + 20, + 25 +}; + struct bcl_device; struct bcl_peripheral_data { @@ -112,6 +127,7 @@ struct bcl_device { uint16_t fg_bcl_addr; void *ipc_log; bool ibat_ccm_enabled; + uint32_t ibat_ext_range_factor; struct bcl_peripheral_data param[BCL_TYPE_MAX]; }; @@ -192,9 +208,11 @@ static void convert_ibat_to_adc_val(int *val, int scaling_factor) if (ibat_use_qg_adc) *val = (int)div_s64(*val * 2000 * 2, scaling_factor); else if (no_bit_shift) - *val = (int)div_s64(*val * 1000, scaling_factor); + *val = (int)div_s64(*val * 1000 * bcl_ibat_ext_ranges[BCL_IBAT_RANGE_LVL0], + scaling_factor); else - *val = (int)div_s64(*val * 2000, scaling_factor); + *val = (int)div_s64(*val * 2000 * bcl_ibat_ext_ranges[BCL_IBAT_RANGE_LVL0], + scaling_factor); } @@ -204,7 +222,8 @@ static void convert_adc_to_ibat_val(int *val, int scaling_factor) if (ibat_use_qg_adc) *val = (int)div_s64(*val * scaling_factor, 2 * 1000); else - *val = (int)div_s64(*val * scaling_factor, 1000); + *val = (int)div_s64(*val * scaling_factor, + 1000 * bcl_ibat_ext_ranges[BCL_IBAT_RANGE_LVL0]); } static int8_t convert_ibat_to_ccm_val(int ibat) @@ -247,9 +266,11 @@ static int bcl_set_ibat(void *data, int low, int high) ibat_ua = thresh_value; if (bat_data->dev->ibat_ccm_enabled) - convert_ibat_to_adc_val(&thresh_value, BCL_IBAT_CCM_SCALING_UA); + convert_ibat_to_adc_val(&thresh_value, + BCL_IBAT_CCM_SCALING_UA * bat_data->dev->ibat_ext_range_factor); else - convert_ibat_to_adc_val(&thresh_value, BCL_IBAT_SCALING_UA); + convert_ibat_to_adc_val(&thresh_value, + BCL_IBAT_SCALING_UA * bat_data->dev->ibat_ext_range_factor); val = (int8_t)thresh_value; switch (bat_data->type) { case BCL_IBAT_LVL0: @@ -304,9 +325,11 @@ static int bcl_read_ibat(void *data, int *adc_value) *adc_value = bat_data->last_val; } else { if (bat_data->dev->ibat_ccm_enabled) - convert_adc_to_ibat_val(adc_value, BCL_IBAT_CCM_SCALING_UA); + convert_adc_to_ibat_val(adc_value, + BCL_IBAT_CCM_SCALING_UA * bat_data->dev->ibat_ext_range_factor); else - convert_adc_to_ibat_val(adc_value, BCL_IBAT_SCALING_UA); + convert_adc_to_ibat_val(adc_value, + BCL_IBAT_SCALING_UA * bat_data->dev->ibat_ext_range_factor); bat_data->last_val = *adc_value; } pr_debug("ibat:%d mA ADC:0x%02x\n", bat_data->last_val, val); @@ -518,6 +541,56 @@ static irqreturn_t bcl_handle_irq(int irq, void *data) return IRQ_HANDLED; } +static int bcl_get_ibat_ext_range_factor(struct platform_device *pdev, + uint32_t *ibat_range_factor) +{ + int ret = 0; + const char *name; + struct nvmem_cell *cell; + size_t len; + char *buf; + uint32_t ext_range_index = 0; + + ret = of_property_read_string(pdev->dev.of_node, "nvmem-cell-names", &name); + if (ret) { + *ibat_range_factor = bcl_ibat_ext_ranges[BCL_IBAT_RANGE_LVL0]; + pr_debug("Default ibat range factor enabled %u\n", *ibat_range_factor); + return 0; + } + + cell = nvmem_cell_get(&pdev->dev, name); + if (IS_ERR(cell)) { + dev_err(&pdev->dev, "failed to get nvmem cell %s\n", name); + return PTR_ERR(cell); + } + + buf = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + if (IS_ERR_OR_NULL(buf)) { + dev_err(&pdev->dev, "failed to read nvmem cell %s\n", name); + return PTR_ERR(buf); + } + + if (len <= 0 || len > sizeof(uint32_t)) { + dev_err(&pdev->dev, "nvmem cell length out of range %d\n", len); + kfree(buf); + return -EINVAL; + } + memcpy(&ext_range_index, buf, min(len, sizeof(ext_range_index))); + kfree(buf); + + if (ext_range_index >= BCL_IBAT_RANGE_MAX) { + dev_err(&pdev->dev, "invalid BCL ibat scaling factor %d\n", ext_range_index); + return -EINVAL; + } + + *ibat_range_factor = bcl_ibat_ext_ranges[ext_range_index]; + pr_debug("ext_range_index %u, ibat range factor %u\n", + ext_range_index, *ibat_range_factor); + + return 0; +} + static int bcl_get_devicetree_data(struct platform_device *pdev, struct bcl_device *bcl_perph) { @@ -541,6 +614,9 @@ static int bcl_get_devicetree_data(struct platform_device *pdev, bcl_perph->ibat_ccm_enabled = of_property_read_bool(dev_node, "qcom,ibat-ccm-hw-support"); + ret = bcl_get_ibat_ext_range_factor(pdev, + &bcl_perph->ibat_ext_range_factor); + return ret; } @@ -701,6 +777,7 @@ static int bcl_probe(struct platform_device *pdev) { struct bcl_device *bcl_perph = NULL; char bcl_name[40]; + int err = 0; if (bcl_device_ct >= MAX_PERPH_COUNT) { dev_err(&pdev->dev, "Max bcl peripheral supported already.\n"); @@ -720,7 +797,11 @@ static int bcl_probe(struct platform_device *pdev) } bcl_device_ct++; - bcl_get_devicetree_data(pdev, bcl_perph); + err = bcl_get_devicetree_data(pdev, bcl_perph); + if (err) { + bcl_device_ct--; + return err; + } bcl_probe_vbat(pdev, bcl_perph); bcl_probe_ibat(pdev, bcl_perph); bcl_probe_lvls(pdev, bcl_perph);