From b3c61e3c5196705b08cc3e750b06a5480c7b874a Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 11 Sep 2020 15:44:10 -0700 Subject: [PATCH] thermal: qcom-spmi-temp-alarm: align temp readings with over-temp stage Ensure that the PMIC temperature reported is at least the lowest value possible for the current over-temperature stage. This guarantees that we cannot hit the following corner case on PMICs that have a GEN2 TEMP_ALARM peripheral: 0. The PMIC's thermal zone device tree configuration defines a passive trip point equal to the stage 1 over-temperature threshold (e.g. 95 C) and hysteresis=0, along with polling-delay=0 and polling-delay-passive>0. 1. The PMIC heats up and reaches 95 C at which point the over- temperature stage transitions from 0 to 1. 2. The PMIC triggers the TEMP_ALARM IRQ (which only occurs for over-temperature stage 0 -> 1 and 1 -> 0 transitions on GEN2 peripherals). 3. The qcom-spmi-temp-alarm IRQ handler signals to the thermal framework that an event has occurred. 4. The thermal framework reads the PMIC temperature (via ADC). 5. If the temperature reported by the ADC is less than 95 C (e.g. 94.99 C), then no further action is taken. 6. The PMIC temperature can continue to increase without software awareness. 7. Eventually the PMIC temperature can hit the stage 3 over- temperature level (e.g. 145 C) at which point the PMIC abruptly shuts down the system. This situation is avoided if at step #5, the qcom-spmi-temp-alarm driver instead reports a temperature of 95 C (which is the minimum possible for over-temperature stage 1) instead of the slightly low ADC temperature reading. Doing so causes the thermal framework to switch to passive polling of the PMIC temperature. This ensures that further increase of the PMIC temperature is directly observed by software. That way, an orderly shutdown can be initiated by software if needed before hitting over-temperature stage 3. Change-Id: Ia4d12f092fb06970d686b830051788430afd32dc Signed-off-by: David Collins --- drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c index 185ffc930622..d054ac99fd1e 100644 --- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c @@ -190,7 +190,7 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) static int qpnp_tm_get_temp(void *data, int *temp) { struct qpnp_tm_chip *chip = data; - int ret, mili_celsius; + int ret, mili_celsius, stage, stage_temp_min; if (!temp) return -EINVAL; @@ -207,10 +207,27 @@ static int qpnp_tm_get_temp(void *data, int *temp) if (ret < 0) return ret; } else { + mutex_lock(&chip->lock); + stage = qpnp_tm_get_temp_stage(chip); + if (stage < 0) { + mutex_unlock(&chip->lock); + return stage; + } + if (chip->subtype != QPNP_TM_SUBTYPE_GEN1) + stage = alarm_state_map[stage]; + stage_temp_min = qpnp_tm_decode_temp(chip, stage); + mutex_unlock(&chip->lock); + ret = iio_read_channel_processed(chip->adc, &mili_celsius); if (ret < 0) return ret; + if (stage_temp_min > mili_celsius && stage_temp_min > 0) { + dev_dbg(chip->dev, "replacing ADC temp=%d with min stage[%d] temp=%d\n", + mili_celsius, stage, stage_temp_min); + mili_celsius = stage_temp_min; + } + chip->temp = mili_celsius; }