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

Commit e4d3e480 authored by Jeff Bernard's avatar Jeff Bernard
Browse files

msm: thermal: Add support to update DPM voltage scale register



Register for a voltage change callback function
and adjust the DPM voltage scale register. DPM is
currently not aware of the voltage scaling change and
the voltage level that is changed to. This lets the
HLOS driver to notify the DPM about the voltage
scaling.

When voltage goes from low to high, program the register
after the change is applied. When voltage goes from high
to low, program the register before the change.

Change-Id: Icc46e4b1b461882d9fdd7833575316c62ee985ee
Signed-off-by: default avatarJeff Bernard <jbernard@codeaurora.org>
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent d0e3b687
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@ Device/Asic specific properties:
- qcom,lmh-trim-err-offset : This property defines the bit in the LMH
		interrupt status register, which shows whether there is a
		trim error in LMH hardware.
- vdd-apss-supply : This property should hold the phandle of APSS regulator.
		When defined, the M4M DPM will be notified for the APSS
		voltage change.

Required parameters:
- compatible: Must be either "qcom,lmh" or "qcom,lmh_v1".
@@ -26,9 +29,11 @@ qcom,lmh {
	interrupts = <0 332 4>;
	reg = <0xF9117000 0x4>;
	qcom,lmh-trim-err-offset = <18>;
	vdd-apss-supply = <&pm8994_s11>;
};

Or for asics that don't have trim err:
Or for asics that don't have trim err and don't require the voltage change
update for DPM.

qcom,lmh {
	compatible = "qcom,lmh_v1";
+106 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <asm/cacheflush.h>
#include <soc/qcom/scm.h>
#include <linux/dma-mapping.h>
#include <linux/regulator/consumer.h>

#define CREATE_TRACE_POINTS
#define TRACE_MSM_LMH
@@ -51,6 +52,8 @@
#define LMH_DEBUG_READ_BUF_SIZE		0x09
#define LMH_DEBUG_READ			0x0A
#define LMH_DEBUG_GET_TYPE		0x0B
#define MAX_TRACE_EVENT_MSG_LEN		50
#define APCS_DPM_VOLTAGE_SCALE		0x09950804

#define LMH_CHECK_SCM_CMD(_cmd) \
	do { \
@@ -152,6 +155,9 @@ struct lmh_driver_data {
	int				max_sensor_count;
	struct lmh_profile		dev_info;
	struct lmh_debug		debug_info;
	struct regulator		*regulator;
	struct notifier_block		dpm_notifier_blk;
	void __iomem			*dpm_voltage_scale_reg;
};

struct lmh_sensor_data {
@@ -518,6 +524,13 @@ static int lmh_get_sensor_devicetree(struct platform_device *pdev)
		}
	}

	lmh_data->regulator = devm_regulator_get(lmh_data->dev, "vdd-apss");
	if (IS_ERR(lmh_data->regulator)) {
		pr_err("unable to get vdd-apss regulator. err:%ld\n",
			PTR_ERR(lmh_data->regulator));
		lmh_data->regulator = NULL;
	}

	lmh_data->irq_num = platform_get_irq(pdev, 0);
	if (lmh_data->irq_num < 0) {
		ret = lmh_data->irq_num;
@@ -1080,6 +1093,94 @@ static int lmh_debug_lmh_config(struct lmh_debug_ops *ops, uint32_t *buf,
	return lmh_debug_config_write(LMH_DEBUG_SET, buf, size);
}

static void lmh_voltage_scale_set(uint32_t voltage)
{
	char trace_buf[MAX_TRACE_EVENT_MSG_LEN] = "";

	writel_relaxed(voltage, lmh_data->dpm_voltage_scale_reg);
	snprintf(trace_buf, MAX_TRACE_EVENT_MSG_LEN,
		"DPM voltage scale %d mV", voltage);
	pr_debug("%s\n", trace_buf);
	trace_lmh_event_call(trace_buf);
}

static int lmh_voltage_change_notifier(struct notifier_block *nb_data,
	unsigned long event, void *data)
{
	uint32_t voltage = 0;
	static uint32_t last_voltage;
	static bool change_needed;

	if (event == REGULATOR_EVENT_VOLTAGE_CHANGE) {
		/* Convert from uV to mV */
		voltage = ((unsigned long)data) / 1000;
		if (change_needed == 1 &&
			(last_voltage == voltage)) {
			lmh_voltage_scale_set(voltage);
			change_needed = 0;
		}
	} else if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
		struct pre_voltage_change_data *change_data =
			(struct pre_voltage_change_data *)data;
		last_voltage = change_data->min_uV / 1000;
		if (change_data->min_uV > change_data->old_uV)
			/* Going from low to high apply change first */
			lmh_voltage_scale_set(last_voltage);
		else
			/* Going from high to low apply change after */
			change_needed = 1;
		pr_debug("Received event PRE_VOLTAGE_CHANGE\n");
		pr_debug("max = %lu mV min = %lu mV previous = %lu mV\n",
			change_data->max_uV / 1000, change_data->min_uV / 1000,
			change_data->old_uV / 1000);
	}

	return NOTIFY_OK;
}

static void lmh_dpm_remove(void)
{
	if (!IS_ERR_OR_NULL(lmh_data->regulator) &&
		lmh_data->dpm_notifier_blk.notifier_call != NULL) {
		regulator_unregister_notifier(lmh_data->regulator,
			&(lmh_data->dpm_notifier_blk));
		lmh_data->regulator = NULL;
	}
}

static void lmh_dpm_init(void)
{
	int ret = 0;

	lmh_data->dpm_voltage_scale_reg = devm_ioremap(lmh_data->dev,
			(phys_addr_t)APCS_DPM_VOLTAGE_SCALE, 4);
	if (!lmh_data->dpm_voltage_scale_reg) {
		ret = -ENODEV;
		pr_err("Error mapping LMH DPM voltage scale register\n");
		goto dpm_init_exit;
	}

	lmh_data->dpm_notifier_blk.notifier_call = lmh_voltage_change_notifier;
	ret = regulator_register_notifier(lmh_data->regulator,
		&(lmh_data->dpm_notifier_blk));
	if (ret) {
		pr_err("DPM regulator notification registration failed. err:%d\n",
			ret);
		goto dpm_init_exit;
	}

dpm_init_exit:
	if (ret) {
		if (lmh_data->dpm_notifier_blk.notifier_call)
			regulator_unregister_notifier(lmh_data->regulator,
				&(lmh_data->dpm_notifier_blk));
		devm_regulator_put(lmh_data->regulator);
		lmh_data->dpm_notifier_blk.notifier_call = NULL;
		lmh_data->regulator = NULL;
	}
}


static int lmh_debug_init(void)
{
	int ret = 0;
@@ -1169,6 +1270,10 @@ static int lmh_probe(struct platform_device *pdev)
			ret);
		ret = 0;
	}

	if (lmh_data->regulator)
		lmh_dpm_init();

	ret = lmh_debug_init();
	if (ret) {
		pr_err("LMH debug init failed. err:%d\n", ret);
@@ -1194,6 +1299,7 @@ static int lmh_remove(struct platform_device *pdev)
	free_irq(lmh_dat->irq_num, lmh_dat);
	lmh_remove_sensors();
	lmh_device_deregister(&lmh_dat->dev_info.dev_ops);
	lmh_dpm_remove();

	return 0;
}