Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b1408c2 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

power: bcl: Interface with the new BCL peripheral driver



Add support for battery current limit module to use
the BCL framework. This makes the battery current limit
module independent of the underlying hardware changes.

Change-Id: Ib0dab6c332846f71a2c8ce9fc5c6e88ae15d947c
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 87927b89
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -35,6 +35,13 @@ Optional parameters:
		are defined. Error in any of these properties will disable BTM
		mode of operation and will fall back to the available current
		monitor mode.
- qcom,bcl-framework-interface: If this property is defined, then the BCL uses
		the BCL framework for monitoring battery voltage and current.
		When this property is defined, the 'high-threshold-uamp',
		'low-threshold-uamp', 'mitigation-freq-khz',
		'vph-high-threshold-uv', 'vph-low-threshold-uv' and
		'thermal-handle' properties should be defined in the
		'qcom,ibat-monitor' node.

Optional nodes:
- qcom,ibat-monitor: This optional node defines all the parameters for the
@@ -96,6 +103,19 @@ Example:
			thermal-handle = <&msm_thermal_freq>;
		};
	};
For Using BCL peripheral interface:
	qcom,bcl {
		compatible = "qcom,bcl";
		qcom,bcl-framework-interface;
		qcom,ibat-monitor {
			high-threshold-uamp = <1500>;
			low-threshold-uamp = <500>;
			mitigation-freq-khz = <1958400>;
			vph-high-threshold-uv = <3700000>;
			vph-low-threshold-uv = <3500000>;
			thermal-handle = <&msm_thermal_freq>;
		};
	};

===============================================================================
BCL PMIC Peripheral driver:
+203 −22
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/cpufreq.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/cpu.h>
#include <linux/msm_bcl.h>

#define BCL_DEV_NAME "battery_current_limit"
#define BCL_NAME_LENGTH 20
@@ -39,6 +40,13 @@
#define BATTERY_VOLTAGE_MIN 3400
#define BTM_8084_FREQ_MITIG_LIMIT 1958400

#define BCL_FETCH_DT_U32(_dev, _key, _search_str, _ret, _out, _exit) do { \
		_key = _search_str; \
		_ret = of_property_read_u32(_dev, _key, &_out); \
		if (_ret) \
			goto _exit; \
	} while (0)

/*
 * Battery Current Limit Enable or Not
 */
@@ -67,6 +75,7 @@ enum bcl_iavail_threshold_type {
enum bcl_monitor_type {
	BCL_IAVAIL_MONITOR_TYPE,
	BCL_IBAT_MONITOR_TYPE,
	BCL_IBAT_PERIPH_MONITOR_TYPE,
	BCL_MONITOR_TYPE_MAX,
};

@@ -78,7 +87,8 @@ enum bcl_adc_monitor_mode {
	BCL_MONITOR_MODE_MAX,
};

static const char *bcl_type[BCL_MONITOR_TYPE_MAX] = {"bcl", "btm"};
static const char *bcl_type[BCL_MONITOR_TYPE_MAX] = {"bcl", "btm",
		"bcl_peripheral"};
int adc_timer_val_usec[] = {
	[ADC_MEAS1_INTERVAL_0MS] = 0,
	[ADC_MEAS1_INTERVAL_1P0MS] = 1000,
@@ -155,7 +165,14 @@ struct bcl_context {
	uint32_t btm_vph_low_thresh;
	struct qpnp_adc_tm_btm_param btm_vph_adc_param;
	/* Low temp min freq limit requested by thermal */
	uint32_t btm_freq_limit;
	uint32_t thermal_freq_limit;

	/* BCL Peripheral monitor parameters */
	struct bcl_threshold ibat_high_thresh;
	struct bcl_threshold ibat_low_thresh;
	struct bcl_threshold vbat_high_thresh;
	struct bcl_threshold vbat_low_thresh;
	uint32_t bcl_p_freq_max;
};

enum bcl_threshold_state {
@@ -173,15 +190,19 @@ static int bcl_cpufreq_callback(struct notifier_block *nfb,
		unsigned long event, void *data)
{
	struct cpufreq_policy *policy = data;
	uint32_t max_freq = UINT_MAX;

	switch (event) {
	case CPUFREQ_INCOMPATIBLE:
		if (bcl_vph_state == BCL_LOW_THRESHOLD
			&& bcl_ibat_state == BCL_HIGH_THRESHOLD) {
			max_freq = (gbcl->bcl_monitor_type
				== BCL_IBAT_MONITOR_TYPE) ? gbcl->btm_freq_max
				: gbcl->bcl_p_freq_max;
			pr_debug("Requesting Max freq:%d for CPU%d\n",
				gbcl->btm_freq_max, policy->cpu);
				max_freq, policy->cpu);
			cpufreq_verify_within_limits(policy, 0,
				gbcl->btm_freq_max);
				max_freq);
		}
		break;
	}
@@ -485,6 +506,79 @@ ibat_disable_exit:
	return ret;
}

static void bcl_periph_ibat_notify(enum bcl_trip_type type, int trip_temp,
	void *data)
{
	if (type == BCL_HIGH_TRIP)
		bcl_ibat_notify(BCL_HIGH_THRESHOLD);
	else
		bcl_ibat_notify(BCL_LOW_THRESHOLD);

	return;
}

static void bcl_periph_vbat_notify(enum bcl_trip_type type, int trip_temp,
		void *data)
{
	if (type == BCL_HIGH_TRIP)
		bcl_vph_notify(BCL_HIGH_THRESHOLD);
	else
		bcl_vph_notify(BCL_LOW_THRESHOLD);

	return;
}

static void bcl_periph_mode_set(enum bcl_device_mode mode)
{
	int ret = 0;

	if (mode == BCL_DEVICE_ENABLED) {
		ret = msm_bcl_set_threshold(BCL_PARAM_CURRENT, BCL_HIGH_TRIP,
			&gbcl->ibat_high_thresh);
		if (ret) {
			pr_err("Error setting Ibat high threshold. err:%d\n",
				ret);
			return;
		}
		ret = msm_bcl_set_threshold(BCL_PARAM_CURRENT, BCL_LOW_TRIP,
			&gbcl->ibat_low_thresh);
		if (ret) {
			pr_err("Error setting Ibat low threshold. err:%d\n",
				ret);
			return;
		}
		ret = msm_bcl_set_threshold(BCL_PARAM_VOLTAGE, BCL_LOW_TRIP,
			 &gbcl->vbat_low_thresh);
		if (ret) {
			pr_err("Error setting Vbat low threshold. err:%d\n",
				ret);
			return;
		}
		ret = msm_bcl_set_threshold(BCL_PARAM_VOLTAGE, BCL_HIGH_TRIP,
			 &gbcl->vbat_high_thresh);
		if (ret) {
			pr_err("Error setting Vbat high threshold. err:%d\n",
				ret);
			return;
		}
		ret = msm_bcl_enable();
		if (ret) {
			pr_err("Error enabling BCL\n");
			return;
		}
		gbcl->btm_mode = BCL_VPH_MONITOR_MODE;
	} else {
		ret = msm_bcl_disable();
		if (ret) {
			pr_err("Error disabling BCL\n");
			return;
		}
		gbcl->btm_mode = BCL_MONITOR_DISABLED;
		bcl_vph_notify(BCL_HIGH_THRESHOLD);
		bcl_ibat_notify(BCL_LOW_THRESHOLD);
	}
}

static void ibat_mode_set(enum bcl_device_mode mode)
{
	int ret = 0;
@@ -599,6 +693,9 @@ static void bcl_mode_set(enum bcl_device_mode mode)
	case BCL_IBAT_MONITOR_TYPE:
		ibat_mode_set(mode);
		break;
	case BCL_IBAT_PERIPH_MONITOR_TYPE:
		bcl_periph_mode_set(mode);
		break;
	default:
		pr_err("Invalid monitor type:%d\n", gbcl->bcl_monitor_type);
		break;
@@ -623,15 +720,21 @@ show_bcl(rbat, gbcl->bcl_rbat_mohm, "%d\n")
show_bcl(iavail, gbcl->bcl_iavail, "%d\n")
show_bcl(vbat_min, gbcl->bcl_vbat_min, "%d\n")
show_bcl(poll_interval, gbcl->bcl_poll_interval_msec, "%d\n")
show_bcl(high_ua, voltage_to_current(gbcl, gbcl->btm_high_threshold_uv),
		"%d\n")
show_bcl(low_ua, voltage_to_current(gbcl, gbcl->btm_low_threshold_uv), "%d\n")
show_bcl(adc_interval_us, adc_time_to_uSec(gbcl, gbcl->btm_adc_interval),
		"%d\n")
show_bcl(freq_max, gbcl->btm_freq_max, "%u\n")
show_bcl(vph_high, gbcl->btm_vph_high_thresh, "%d\n")
show_bcl(vph_low, gbcl->btm_vph_low_thresh, "%d\n")
show_bcl(freq_limit, gbcl->btm_freq_limit, "%u\n")
show_bcl(high_ua, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	voltage_to_current(gbcl, gbcl->btm_high_threshold_uv)
	: gbcl->ibat_high_thresh.trip_value, "%d\n")
show_bcl(low_ua, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	voltage_to_current(gbcl, gbcl->btm_low_threshold_uv)
	: gbcl->ibat_low_thresh.trip_value, "%d\n")
show_bcl(adc_interval_us, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	adc_time_to_uSec(gbcl, gbcl->btm_adc_interval) : 0, "%d\n")
show_bcl(freq_max, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	gbcl->btm_freq_max : gbcl->bcl_p_freq_max, "%u\n")
show_bcl(vph_high, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	gbcl->btm_vph_high_thresh : gbcl->vbat_high_thresh.trip_value, "%d\n")
show_bcl(vph_low, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
	gbcl->btm_vph_low_thresh : gbcl->vbat_low_thresh.trip_value, "%d\n")
show_bcl(freq_limit, gbcl->thermal_freq_limit, "%u\n")
show_bcl(vph_state, bcl_vph_state, "%d\n")
show_bcl(ibat_state, bcl_ibat_state, "%d\n")

@@ -858,7 +961,11 @@ static ssize_t high_ua_store(struct device *dev,
	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;

	if (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE)
		gbcl->btm_high_threshold_uv = current_to_voltage(gbcl, val);
	else
		gbcl->ibat_high_thresh.trip_value = val;

	return count;
}
@@ -873,7 +980,11 @@ static ssize_t low_ua_store(struct device *dev,
	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;

	if (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE)
		gbcl->btm_low_threshold_uv = current_to_voltage(gbcl, val);
	else
		gbcl->ibat_low_thresh.trip_value = val;

	return count;
}
@@ -884,11 +995,14 @@ static ssize_t freq_max_store(struct device *dev,
{
	int val = 0;
	int ret = 0;
	uint32_t *freq_lim = NULL;

	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;
	gbcl->btm_freq_max = max_t(uint32_t, val, gbcl->btm_freq_limit);
	freq_lim = (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
			&gbcl->btm_freq_max : &gbcl->bcl_p_freq_max;
	*freq_lim = max_t(uint32_t, val, gbcl->thermal_freq_limit);

	return count;
}
@@ -899,11 +1013,16 @@ static ssize_t vph_low_store(struct device *dev,
{
	int val = 0;
	int ret = 0;
	int *thresh = NULL;

	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;
	gbcl->btm_vph_low_thresh = val;

	thresh = (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE)
			? (int *)&gbcl->btm_vph_low_thresh
			: &gbcl->vbat_low_thresh.trip_value;
	*thresh = val;

	return count;
}
@@ -914,11 +1033,16 @@ static ssize_t vph_high_store(struct device *dev,
{
	int val = 0;
	int ret = 0;
	int *thresh = NULL;

	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;
	gbcl->btm_vph_high_thresh = val;

	thresh = (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE)
			? (int *)&gbcl->btm_vph_high_thresh
			: &gbcl->vbat_high_thresh.trip_value;
	*thresh = val;

	return count;
}
@@ -974,6 +1098,7 @@ static int create_bcl_sysfs(struct bcl_context *bcl)
		attr_ptr = bcl_dev_attr;
		break;
	case BCL_IBAT_MONITOR_TYPE:
	case BCL_IBAT_PERIPH_MONITOR_TYPE:
		num_attr = sizeof(btm_dev_attr)/sizeof(struct device_attribute);
		attr_ptr = btm_dev_attr;
		break;
@@ -1154,7 +1279,7 @@ static void get_vdd_rstr_freq(struct bcl_context *bcl,
	}
	key = "qcom,levels";
	ret = of_property_read_u32_index(phandle, key, 0,
					&bcl->btm_freq_limit);
					&bcl->thermal_freq_limit);
	if (ret) {
		pr_err("Error reading property %s. ret:%d\n", key, ret);
		goto vdd_rstr_exit;
@@ -1162,10 +1287,61 @@ static void get_vdd_rstr_freq(struct bcl_context *bcl,

vdd_rstr_exit:
	if (ret)
		bcl->btm_freq_limit = BTM_8084_FREQ_MITIG_LIMIT;
		bcl->thermal_freq_limit = BTM_8084_FREQ_MITIG_LIMIT;
	return;
}

static int probe_bcl_periph_prop(struct bcl_context *bcl)
{
	int ret = 0;
	struct device_node *ibat_node = NULL, *dev_node = bcl->dev->of_node;
	char *key = NULL;

	key = "qcom,ibat-monitor";
	ibat_node = of_find_node_by_name(dev_node, key);
	if (!ibat_node) {
		ret = -ENODEV;
		goto ibat_probe_exit;
	}

	BCL_FETCH_DT_U32(ibat_node, key, "low-threshold-uamp", ret,
		bcl->ibat_low_thresh.trip_value, ibat_probe_exit);
	BCL_FETCH_DT_U32(ibat_node, key, "high-threshold-uamp", ret,
		bcl->ibat_high_thresh.trip_value, ibat_probe_exit);
	BCL_FETCH_DT_U32(ibat_node, key, "mitigation-freq-khz", ret,
		bcl->bcl_p_freq_max, ibat_probe_exit);
	BCL_FETCH_DT_U32(ibat_node, key, "vph-high-threshold-uv", ret,
		bcl->vbat_high_thresh.trip_value, ibat_probe_exit);
	BCL_FETCH_DT_U32(ibat_node, key, "vph-low-threshold-uv", ret,
		bcl->vbat_low_thresh.trip_value, ibat_probe_exit);
	bcl->vbat_high_thresh.trip_notify
		= bcl->vbat_low_thresh.trip_notify = bcl_periph_vbat_notify;
	bcl->vbat_high_thresh.trip_data
		= bcl->vbat_low_thresh.trip_data = (void *) bcl;
	bcl->ibat_high_thresh.trip_notify
		= bcl->ibat_low_thresh.trip_notify = bcl_periph_ibat_notify;
	bcl->ibat_high_thresh.trip_data
		= bcl->ibat_low_thresh.trip_data = (void *) bcl;
	get_vdd_rstr_freq(bcl, ibat_node);
	bcl->bcl_p_freq_max = max(bcl->bcl_p_freq_max, bcl->thermal_freq_limit);

	bcl->btm_mode = BCL_MONITOR_DISABLED;
	bcl->bcl_monitor_type = BCL_IBAT_PERIPH_MONITOR_TYPE;
	snprintf(bcl->bcl_type, BCL_NAME_LENGTH, "%s",
			bcl_type[BCL_IBAT_PERIPH_MONITOR_TYPE]);
	ret = cpufreq_register_notifier(&bcl_cpufreq_notifier,
			CPUFREQ_POLICY_NOTIFIER);
	if (ret)
		pr_err("Error with cpufreq register. err:%d\n", ret);

ibat_probe_exit:
	if (ret && ret != -EPROBE_DEFER)
		dev_info(bcl->dev, "%s:%s Error reading key:%s. ret = %d\n",
				KBUILD_MODNAME, __func__, key, ret);

	return ret;
}

static int probe_btm_properties(struct bcl_context *bcl)
{
	int ret = 0, curr_ua = 0;
@@ -1249,7 +1425,7 @@ static int probe_btm_properties(struct bcl_context *bcl)
		goto btm_probe_exit;
	}
	get_vdd_rstr_freq(bcl, ibat_node);
	bcl->btm_freq_max = max(bcl->btm_freq_max, bcl->btm_freq_limit);
	bcl->btm_freq_max = max(bcl->btm_freq_max, bcl->thermal_freq_limit);

	bcl->btm_mode = BCL_MONITOR_DISABLED;
	bcl->bcl_monitor_type = BCL_IBAT_MONITOR_TYPE;
@@ -1300,7 +1476,12 @@ static int bcl_probe(struct platform_device *pdev)
			bcl_type[BCL_IAVAIL_MONITOR_TYPE]);
	bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;

	if (of_property_read_bool(pdev->dev.of_node,
		"qcom,bcl-framework-interface"))
		ret = probe_bcl_periph_prop(bcl);
	else
		ret = probe_btm_properties(bcl);

	if (ret == -EPROBE_DEFER)
		return ret;