mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 22:40:54 -04:00
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: Deepak Katragadda <dkatraga@codeaurora.org>
This commit is contained in:
parent
167c01a0af
commit
584cd27f0b
1 changed files with 70 additions and 3 deletions
|
|
@ -111,7 +111,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);
|
||||
}
|
||||
|
|
@ -127,6 +127,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, ®val);
|
||||
|
||||
if (regval & PWR_ON_MASK) {
|
||||
|
|
@ -135,10 +159,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;
|
||||
}
|
||||
|
||||
|
|
@ -374,9 +408,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, ®val);
|
||||
|
||||
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)
|
||||
|
|
@ -400,6 +458,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, ®val);
|
||||
|
|
@ -445,8 +510,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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue