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

Commit 522c8036 authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

clk: qcom: gdsc-regulator: Add the qcom,poll-cfg-gdscr flag



The default behavior of the GDSC enable/disable sequence is
to poll the status bits of either the actual GDSCR or the
corresponding HW_CTRL registers.
On targets which have support for a CFG_GDSCR register, the
status bits might not show the correct state of the GDSC,
especially in the disable sequence, where the status bit
will be cleared even before the core is completely power
collapsed. On targets with this issue, poll the power on/off
bits in the CFG_GDSCR register instead to correctly determine
the GDSC state.

Change-Id: If41f3f1cea25c001938f28bbb94af3310860d60f
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 245de31b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ Optional properties:
 - reset-names: reset signal name strings sorted in the same order as the resets
			property. These can be supplied only if we support
			qcom,skip-logic-collapse.
 - qcom,poll-cfg-gdscr:	Poll the CFG register of the GDSC to determine if the
			GDSC is enabled/disabled. This flag should not be set
			in conjunction with "hw-ctrl-addr".

Example:
	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+66 −10
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@
#define HW_CONTROL_MASK		BIT(1)
#define SW_COLLAPSE_MASK	BIT(0)

/* CFG_GDSCR */
#define GDSC_POWER_UP_COMPLETE		BIT(16)
#define GDSC_POWER_DOWN_COMPLETE	BIT(15)

/* Domain Address */
#define GMEM_CLAMP_IO_MASK	BIT(0)
#define GMEM_RESET_MASK         BIT(4)
@@ -45,6 +49,7 @@

/* Register Offset */
#define REG_OFFSET		0x0
#define CFG_GDSCR_OFFSET	0x4

/* Timeout Delay */
#define TIMEOUT_US		100
@@ -69,6 +74,7 @@ struct gdsc {
	bool			is_gdsc_enabled;
	bool			allow_clear;
	bool			reset_aon;
	bool			poll_cfg_gdscr;
	int			clock_count;
	int			reset_count;
	int			root_clk_idx;
@@ -128,6 +134,31 @@ static int poll_gdsc_status(struct gdsc *sc, enum gdscr_status status)
	return -ETIMEDOUT;
}

static int poll_cfg_gdsc_status(struct gdsc *sc, enum gdscr_status status)
{
	struct regmap *regmap = sc->regmap;
	int count = sc->gds_timeout;
	u32 val;

	for (; count > 0; count--) {
		regmap_read(regmap, CFG_GDSCR_OFFSET, &val);

		switch (status) {
		case ENABLED:
			if (val & GDSC_POWER_UP_COMPLETE)
				return 0;
			break;
		case DISABLED:
			if (val & GDSC_POWER_DOWN_COMPLETE)
				return 0;
			break;
		}
		udelay(1);
	}

	return -ETIMEDOUT;
}

static int gdsc_is_enabled(struct regulator_dev *rdev)
{
	struct gdsc *sc = rdev_get_drvdata(rdev);
@@ -154,7 +185,7 @@ static int gdsc_is_enabled(struct regulator_dev *rdev)
static int gdsc_enable(struct regulator_dev *rdev)
{
	struct gdsc *sc = rdev_get_drvdata(rdev);
	uint32_t regval, hw_ctrl_regval = 0x0;
	uint32_t regval, cfg_regval, hw_ctrl_regval = 0x0;
	int i, ret = 0;

	mutex_lock(&gdsc_seq_lock);
@@ -230,6 +261,9 @@ static int gdsc_enable(struct regulator_dev *rdev)
		mb();
		udelay(1);

		if (sc->poll_cfg_gdscr)
			ret = poll_cfg_gdsc_status(sc, ENABLED);
		else
			ret = poll_gdsc_status(sc, ENABLED);
		if (ret) {
			regmap_read(sc->regmap, REG_OFFSET, &regval);
@@ -260,11 +294,21 @@ static int gdsc_enable(struct regulator_dev *rdev)
					regval);
				udelay(sc->gds_timeout);

				regmap_read(sc->regmap, REG_OFFSET, &regval);
				if (sc->poll_cfg_gdscr) {
					regmap_read(sc->regmap, REG_OFFSET,
							&regval);
					regmap_read(sc->regmap,
						CFG_GDSCR_OFFSET, &cfg_regval);
					dev_err(&rdev->dev, "%s final state: gdscr - 0x%x, cfg_gdscr - 0x%x (%d us after timeout)\n",
						sc->rdesc.name, regval,
						cfg_regval, sc->gds_timeout);
				} else {
					regmap_read(sc->regmap, REG_OFFSET,
							&regval);
					dev_err(&rdev->dev, "%s final state: 0x%x (%d us after timeout)\n",
						sc->rdesc.name, regval,
						sc->gds_timeout);

				}
				mutex_unlock(&gdsc_seq_lock);

				return ret;
@@ -346,6 +390,9 @@ static int gdsc_disable(struct regulator_dev *rdev)
			 */
			udelay(TIMEOUT_US);
		} else {
			if (sc->poll_cfg_gdscr)
				ret = poll_cfg_gdsc_status(sc, DISABLED);
			else
				ret = poll_gdsc_status(sc, DISABLED);
			if (ret)
				dev_err(&rdev->dev, "%s disable timed out: 0x%x\n",
@@ -434,6 +481,9 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode)
		mb();
		udelay(1);

		if (sc->poll_cfg_gdscr)
			ret = poll_cfg_gdsc_status(sc, ENABLED);
		else
			ret = poll_gdsc_status(sc, ENABLED);
		if (ret)
			dev_err(&rdev->dev, "%s set_mode timed out: 0x%x\n",
@@ -531,6 +581,9 @@ static int gdsc_probe(struct platform_device *pdev)
			return -ENODEV;
	}

	sc->poll_cfg_gdscr = of_property_read_bool(pdev->dev.of_node,
						"qcom,poll-cfg-gdscr");

	sc->gds_timeout = TIMEOUT_US;

	ret = of_property_read_u32(pdev->dev.of_node, "qcom,gds-timeout",
@@ -667,6 +720,9 @@ static int gdsc_probe(struct platform_device *pdev)
		regval &= ~SW_COLLAPSE_MASK;
		regmap_write(sc->regmap, REG_OFFSET, regval);

		if (sc->poll_cfg_gdscr)
			ret = poll_cfg_gdsc_status(sc, ENABLED);
		else
			ret = poll_gdsc_status(sc, ENABLED);
		if (ret) {
			dev_err(&pdev->dev, "%s enable timed out: 0x%x\n",