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

Commit c7d3dc88 authored by Deepak Katragadda's avatar Deepak Katragadda Committed by David Collins
Browse files

clk: qcom: gdsc: Fix issue with dereferencing NULL pointer in gdsc APIs



Fix the issue with deferencing the rdev structure for
the GDSC prior to it being populated. Replace the
qcom,vote-parent-supply-voltage property with
vdd_parent-supply and use the regulator handle that's
returned from calling regulator_get for the parent
regulator directly.

Change-Id: I9a80cbeb4fd88b718e6e7509d8868d965253ae5e
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 9e7d8b0b
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -50,10 +50,11 @@ Optional properties:
			to enable.
 - qcom,reset-aon-logic: If present, the GPU DEMET cells need to be reset while
			 enabling the GX GDSC.
 - qcom,vote-parent-supply-voltage: If present, need to vote for a minimum
			operational voltage (LOW_SVS) on the GDSC parent
			regulator prior to configuring it. The vote is removed
			once the GDSC FSM has latched on to the new state.
 - vdd_parent-supply:	phandle to the regulator that this GDSC gates. If
			present, need to vote for a minimum operational voltage
			(LOW_SVS) on the GDSC parent regulator prior to
			configuring it. The vote is removed once the GDSC FSM
			has latched on to the new state.
 - resets: reset specifier pair consisting of phandle for the reset controller
			and reset lines used by this controller. These can be
			supplied only if we support qcom,skip-logic-collapse.
+26 −19
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 */

#include <linux/kernel.h>
@@ -52,6 +52,7 @@ struct gdsc {
	struct regmap           *hw_ctrl;
	struct regmap           *sw_reset;
	struct clk		**clocks;
	struct regulator	*parent_regulator;
	struct reset_control	**reset_clocks;
	bool			toggle_mem;
	bool			toggle_periph;
@@ -63,7 +64,6 @@ struct gdsc {
	bool			is_gdsc_enabled;
	bool			allow_clear;
	bool			reset_aon;
	bool			vote_supply_voltage;
	int			clock_count;
	int			reset_count;
	int			root_clk_idx;
@@ -162,8 +162,8 @@ static int gdsc_enable(struct regulator_dev *rdev)

	mutex_lock(&gdsc_seq_lock);

	if (sc->vote_supply_voltage) {
		ret = regulator_set_voltage(sc->rdev->supply,
	if (sc->parent_regulator) {
		ret = regulator_set_voltage(sc->parent_regulator,
				RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX);
		if (ret) {
			mutex_unlock(&gdsc_seq_lock);
@@ -308,8 +308,8 @@ static int gdsc_enable(struct regulator_dev *rdev)

	sc->is_gdsc_enabled = true;
end:
	if (sc->vote_supply_voltage)
		regulator_set_voltage(sc->rdev->supply, 0, INT_MAX);
	if (sc->parent_regulator)
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);

	mutex_unlock(&gdsc_seq_lock);

@@ -324,8 +324,8 @@ static int gdsc_disable(struct regulator_dev *rdev)

	mutex_lock(&gdsc_seq_lock);

	if (sc->vote_supply_voltage) {
		ret = regulator_set_voltage(sc->rdev->supply,
	if (sc->parent_regulator) {
		ret = regulator_set_voltage(sc->parent_regulator,
				RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX);
		if (ret) {
			mutex_unlock(&gdsc_seq_lock);
@@ -390,8 +390,8 @@ static int gdsc_disable(struct regulator_dev *rdev)
	if ((sc->is_gdsc_enabled && sc->root_en) || sc->force_root_en)
		clk_disable_unprepare(sc->clocks[sc->root_clk_idx]);

	if (sc->vote_supply_voltage)
		regulator_set_voltage(sc->rdev->supply, 0, INT_MAX);
	if (sc->parent_regulator)
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);

	sc->is_gdsc_enabled = false;

@@ -423,8 +423,8 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode)

	mutex_lock(&gdsc_seq_lock);

	if (sc->vote_supply_voltage) {
		ret = regulator_set_voltage(sc->rdev->supply,
	if (sc->parent_regulator) {
		ret = regulator_set_voltage(sc->parent_regulator,
				RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX);
		if (ret) {
			mutex_unlock(&gdsc_seq_lock);
@@ -475,8 +475,8 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode)
		break;
	}

	if (sc->vote_supply_voltage)
		regulator_set_voltage(sc->rdev->supply, 0, INT_MAX);
	if (sc->parent_regulator)
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);

	mutex_unlock(&gdsc_seq_lock);

@@ -594,8 +594,18 @@ static int gdsc_probe(struct platform_device *pdev)
	sc->force_root_en = of_property_read_bool(pdev->dev.of_node,
						"qcom,force-enable-root-clk");

	sc->vote_supply_voltage = of_property_read_bool(pdev->dev.of_node,
					"qcom,vote-parent-supply-voltage");
	if (of_find_property(pdev->dev.of_node, "vdd_parent-supply", NULL)) {
		sc->parent_regulator = devm_regulator_get(&pdev->dev,
							"vdd_parent");
		if (IS_ERR(sc->parent_regulator)) {
			ret = PTR_ERR(sc->parent_regulator);
			if (ret != -EPROBE_DEFER)
				dev_err(&pdev->dev,
				"Unable to get vdd_parent regulator, err: %d\n",
					ret);
			return ret;
		}
	}

	for (i = 0; i < sc->clock_count; i++) {
		const char *clock_name;
@@ -741,9 +751,6 @@ static int gdsc_probe(struct platform_device *pdev)
		return PTR_ERR(sc->rdev);
	}

	if (!sc->rdev->supply)
		sc->vote_supply_voltage = false;

	return 0;
}