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

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

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

parents c7e0736d e4d3e480
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;
}