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

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

clk: qcom: gdsc-regulator: Add MMCX specific logic



When clients call the regulator_is_enabled() API for GDSCs that
are sourced off of the MMCX rail, any register accesses that will
be made as part of the callback rely on the presumption that the
MMCX rail is enabled. When the rail is disabled, the corresponding
ahb clocks that are needed for these registers to be accessible
will also be turned off, thus leading to an unclocked access. Check
to make sure that the MMCX rail is enabled prior to reading or
writing to the MM registers.

Along similar lines, add logic to enable the parent rail for the
GDSC prior to reading and writing to the GDSC registers during the
set_mode and get_mode callbacks.

Change-Id: I8265bc147efd2acd1d6638638eb78935762feee8
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent c7d3dc88
Loading
Loading
Loading
Loading
+70 −3
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ static int poll_gdsc_status(struct gdsc *sc, enum gdscr_status status)
		 * bit in the GDSCR to be set or reset after the GDSC state
		 * changes. Hence, keep on checking for a reasonable number
		 * of times until the bit is set with the least possible delay
		 * between succeessive tries.
		 * between successive tries.
		 */
		udelay(1);
	}
@@ -139,6 +139,30 @@ static int gdsc_is_enabled(struct regulator_dev *rdev)
	if (!sc->toggle_logic)
		return !sc->resets_asserted;

	if (sc->parent_regulator) {
		/*
		 * The parent regulator for the GDSC is required to be on to
		 * make any register accesses to the GDSC base. Return false
		 * if the parent supply is disabled.
		 */
		if (regulator_is_enabled(sc->parent_regulator) <= 0)
			return false;

		/*
		 * Place an explicit vote on the parent rail to cover cases when
		 * it might be disabled between this point and reading the GDSC
		 * registers.
		 */
		if (regulator_set_voltage(sc->parent_regulator,
					RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX))
			return false;

		if (regulator_enable(sc->parent_regulator)) {
			regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
			return false;
		}
	}

	regmap_read(sc->regmap, REG_OFFSET, &regval);

	if (regval & PWR_ON_MASK) {
@@ -147,10 +171,20 @@ static int gdsc_is_enabled(struct regulator_dev *rdev)
		 * votable GDS registers. Check the SW_COLLAPSE_MASK to
		 * determine if HLOS has voted for it.
		 */
		if (!(regval & SW_COLLAPSE_MASK))
		if (!(regval & SW_COLLAPSE_MASK)) {
			if (sc->parent_regulator) {
				regulator_disable(sc->parent_regulator);
				regulator_set_voltage(sc->parent_regulator, 0,
							INT_MAX);
			}
			return true;
		}
	}

	if (sc->parent_regulator) {
		regulator_disable(sc->parent_regulator);
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
	}
	return false;
}

@@ -404,9 +438,33 @@ static unsigned int gdsc_get_mode(struct regulator_dev *rdev)
{
	struct gdsc *sc = rdev_get_drvdata(rdev);
	uint32_t regval;
	int ret;

	mutex_lock(&gdsc_seq_lock);

	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);
			return ret;
		}

		ret = regulator_enable(sc->parent_regulator);
		if (ret) {
			regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
			mutex_unlock(&gdsc_seq_lock);
			return ret;
		}
	}

	regmap_read(sc->regmap, REG_OFFSET, &regval);

	if (sc->parent_regulator) {
		regulator_disable(sc->parent_regulator);
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
	}

	mutex_unlock(&gdsc_seq_lock);

	if (regval & HW_CONTROL_MASK)
@@ -430,6 +488,13 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode)
			mutex_unlock(&gdsc_seq_lock);
			return ret;
		}

		ret = regulator_enable(sc->parent_regulator);
		if (ret) {
			regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
			mutex_unlock(&gdsc_seq_lock);
			return ret;
		}
	}

	regmap_read(sc->regmap, REG_OFFSET, &regval);
@@ -475,8 +540,10 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode)
		break;
	}

	if (sc->parent_regulator)
	if (sc->parent_regulator) {
		regulator_disable(sc->parent_regulator);
		regulator_set_voltage(sc->parent_regulator, 0, INT_MAX);
	}

	mutex_unlock(&gdsc_seq_lock);