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

Commit 2e7cb8c3 authored by Manaf Meethalavalappu Pallikunhi's avatar Manaf Meethalavalappu Pallikunhi
Browse files

driver: thermal: Update CX Ipeak driver to support CX Ipeak v1.1 hardware



CX Ipeak v1.1 hardware has separate register space for each client
unlike legacy version. Add CX Ipeak v1.1 hardware support to CX Ipeak
cooling device. It adds new devicetree property to get thermal client
and bypass clients register offsets for each target.

Change-Id: I765cdd7480d64b99f9ca62fba191c2b8aa4df3ea
Signed-off-by: default avatarManaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
parent 0482853e
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -18,6 +18,24 @@ Required Parameters:
		register address of the CX IPEAK LM hardware and 'b' is the
		size of the peripheral address space.

- qcom,thermal-client-offset:
	Usage: Optional
	Value type: <value in hex>
	Definition: This property is required for CX IP LM v1.1 and above
		hardware. Must contain offset from CX IPEAK LM reg
		base for thermal client voting. If this property is not defined,
		then CX IPEAK cooling device will use legacy CXIP LM hardware
		offset registers.

- qcom,bypass-client-list:
	Usage: Optional
	Value type: <value in hex>
	Definition: This property is required for CX IP LM v1.1 and above
		hardware. Must contain array of offsets from CX IPEAK LM reg
		base for clients those are not participating voting to CXIP LM
		hardware. This property makes sense only when thermal-client
		is defined.

- #cooling-cells:
	Usage: required
	Value type: <integer>
@@ -29,5 +47,7 @@ Example:
	cxip_cdev: cxip-cdev@1fed000 {
		compatible = "qcom,cxip-lm-cooling-device";
		reg = <0x1fed000 0x24>;
		qcom,thermal-client-offset = <0x8000>;
		qcom,bypass-client-list = <0x2004 0x3004>;
		#cooling-cells = <2>;
	};
+82 −14
Original line number Diff line number Diff line
@@ -35,27 +35,49 @@ struct cxip_lm_cooling_device {
	struct thermal_cooling_device	*cool_dev;
	char				cdev_name[THERMAL_NAME_LENGTH];
	void				*cx_ip_reg_base;
	unsigned int			therm_clnt;
	unsigned int			*bypass_clnts;
	unsigned int			bypass_clnt_cnt;
	bool				state;
};

static void cxip_lm_therm_vote_apply(void *reg_base, bool vote)
static void cxip_lm_therm_vote_apply(struct cxip_lm_cooling_device *cxip_dev,
					bool vote)
{
	writel_relaxed(CXIP_LM_THERM_VOTE_VAL,
		reg_base +
		(vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR));
	int vote_offset = 0, val = 0, sts_offset = 0;

	if (!cxip_dev->therm_clnt) {
		vote_offset = vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR;
		val = CXIP_LM_THERM_VOTE_VAL;
		sts_offset = CXIP_LM_VOTE_STATUS;
	} else {
		vote_offset = cxip_dev->therm_clnt;
		val = vote ? 0x1 : 0x0;
		sts_offset = vote_offset;
	}

	pr_debug("%s vote for cxip_lm. Agg.vote:0x%x\n",
	writel_relaxed(val, cxip_dev->cx_ip_reg_base + vote_offset);
	pr_debug("%s vote for cxip_lm. vote:0x%x\n",
		vote ? "Applied" : "Cleared",
		readl_relaxed(reg_base + CXIP_LM_VOTE_STATUS));
		readl_relaxed(cxip_dev->cx_ip_reg_base + sts_offset));
}

static void cxip_lm_initialize_cxip_hw(void *reg_base)
static void cxip_lm_initialize_cxip_hw(struct cxip_lm_cooling_device *cxip_dev)
{
	/* Enable CXIP LM HW */
	writel_relaxed(CXIP_LM_FEATURE_EN_VAL, reg_base + CXIP_LM_FEATURE_EN);
	int i = 0;

	/* Set CXIP LM proxy vote for clients who are not participating */
	writel_relaxed(CXIP_LM_BYPASS_VAL, reg_base + CXIP_LM_BYPASS);
	if (cxip_dev->bypass_clnt_cnt)
		for (i = 0; i < cxip_dev->bypass_clnt_cnt; i++)
			writel_relaxed(0x1, cxip_dev->cx_ip_reg_base +
					cxip_dev->bypass_clnts[i]);
	else if (!cxip_dev->therm_clnt)
		writel_relaxed(CXIP_LM_BYPASS_VAL,
			cxip_dev->cx_ip_reg_base + CXIP_LM_BYPASS);

	/* Enable CXIP LM HW */
	writel_relaxed(CXIP_LM_FEATURE_EN_VAL, cxip_dev->cx_ip_reg_base +
			CXIP_LM_FEATURE_EN);
}

static int cxip_lm_get_max_state(struct thermal_cooling_device *cdev,
@@ -78,7 +100,7 @@ static int cxip_lm_set_cur_state(struct thermal_cooling_device *cdev,
	if (cxip_dev->state == state)
		return 0;

	cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, state);
	cxip_lm_therm_vote_apply(cxip_dev, state);
	cxip_dev->state = state;

	return ret;
@@ -117,6 +139,49 @@ static int cxip_lm_cdev_remove(struct platform_device *pdev)
	return 0;
}

static int cxip_lm_get_devicetree_data(struct platform_device *pdev,
					struct cxip_lm_cooling_device *cxip_dev,
					struct device_node *np)
{
	int ret = 0;

	ret = of_property_read_u32(np, "qcom,thermal-client-offset",
			&cxip_dev->therm_clnt);
	if (ret) {
		dev_dbg(&pdev->dev,
			"error for qcom,thermal-client-offset. ret:%d\n",
			ret);
		cxip_dev->therm_clnt = 0;
		ret = 0;
		return ret;
	}

	ret = of_property_count_u32_elems(np, "qcom,bypass-client-list");
	if (ret <= 0) {
		dev_dbg(&pdev->dev, "Invalid number of clients err:%d\n", ret);
		ret = 0;
		return ret;
	}
	cxip_dev->bypass_clnt_cnt = ret;

	cxip_dev->bypass_clnts = devm_kcalloc(&pdev->dev,
				cxip_dev->bypass_clnt_cnt,
				sizeof(*cxip_dev->bypass_clnts), GFP_KERNEL);
	if (!cxip_dev->bypass_clnts)
		return -ENOMEM;

	ret = of_property_read_u32_array(np, "qcom,bypass-client-list",
		cxip_dev->bypass_clnts, cxip_dev->bypass_clnt_cnt);
	if (ret) {
		dev_dbg(&pdev->dev, "bypass client list err:%d, cnt:%d\n",
			ret, cxip_dev->bypass_clnt_cnt);
		cxip_dev->bypass_clnt_cnt = 0;
		ret = 0;
	}

	return ret;
}

static int cxip_lm_cdev_probe(struct platform_device *pdev)
{
	struct cxip_lm_cooling_device *cxip_dev = NULL;
@@ -135,6 +200,10 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev)
	if (!cxip_dev)
		return -ENOMEM;

	ret = cxip_lm_get_devicetree_data(pdev, cxip_dev, np);
	if (ret)
		return ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev,
@@ -149,12 +218,11 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	cxip_lm_initialize_cxip_hw(cxip_dev->cx_ip_reg_base);
	cxip_lm_initialize_cxip_hw(cxip_dev);

	/* Set thermal vote till we get first vote from TF */
	cxip_dev->state = true;
	cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base,
					cxip_dev->state);
	cxip_lm_therm_vote_apply(cxip_dev, cxip_dev->state);

	strlcpy(cxip_dev->cdev_name, np->name, THERMAL_NAME_LENGTH);
	cxip_dev->cool_dev = thermal_of_cooling_device_register(