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

Commit 6695a73d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: bcl: Interface with the new BCL peripheral driver"

parents 3d17071d 5b1408c2
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;