thermal: qcom-spmi-temp-alarm: add support for new TEMP_ALARM subtypes
Subsystems (3)
v3 cover thermal: qcom-spmi-temp-alarm: add support for new TEMP_ALARM subtypes
Add support in the qcom-spmi-temp-alarm driver for the new PMIC TEMP_ALARM peripheral subtypes: GEN2 rev 2 and LITE. The GEN2 rev 2 subtype provides greater flexibility in temperature threshold specification by using an independent register value to configure each of the three thresholds. The LITE subtype utilizes a simplified set of control registers to configure two thresholds: warning and shutdown.
Also add support to avoid a potential issue on certain versions of the TEMP_ALARM GEN2 subtype when automatic stage 2 partial shutdown is disabled.
Changes since v2 [1]:
* Added missing header <linux/bitfield.h> in the third patch
Changes since v1 [2]:
* Updated the thermal API usage in the patches to work with the recent commit ca1b9a9eb3fd ("thermal/drivers/qcom: Switch to new of API")
[1]: https://lore.kernel.org/lkml/[email protected]/
[2]: https://lore.kernel.org/lkml/[email protected]/
David Collins (3):
thermal: qcom-spmi-temp-alarm: enable stage 2 shutdown when required
thermal: qcom-spmi-temp-alarm: add support for GEN2 rev 2 PMIC
peripherals
thermal: qcom-spmi-temp-alarm: add support for LITE PMIC peripherals
drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 407 +++++++++++++++++++- 1 file changed, 392 insertions(+), 15 deletions(-)
Signature · 1 line
2.25.1
PATCH v3 1/3 thermal: qcom-spmi-temp-alarm: enable stage 2 shutdown when required
Certain TEMP_ALARM GEN2 PMIC peripherals need over-temperature stage 2 automatic PMIC partial shutdown to be enabled in order to avoid repeated faults in the event of reaching over-temperature stage 3. Modify the stage 2 shutdown control logic to ensure that stage 2 shutdown is enabled on all affected PMICs. Read the digital major and minor revision registers to identify these PMICs.
--- drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 32 +++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
drivers/thermal/qcom/qcom-spmi-temp-alarm.c +30 -2
@@ -1,6 +1,7 @@// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2015, 2017, 2020, The Linux Foundation. All rights reserved. +* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/bitops.h>
@@ -18,6 +19,7 @@#include "../thermal_core.h" #include "../thermal_hwmon.h" +#define QPNP_TM_REG_DIG_MINOR 0x00#define QPNP_TM_REG_DIG_MAJOR 0x01#define QPNP_TM_REG_TYPE 0x04#define QPNP_TM_REG_SUBTYPE 0x05
@@ -73,6 +75,7 @@ struct qpnp_tm_chip {struct device *dev;struct thermal_zone_device *tz_dev;unsigned int subtype; +unsigned int dig_revision;long temp;unsigned int thresh;unsigned int stage;
@@ -224,6 +227,7 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN ][1 ];long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX ][1 ];bool disable_s2_shutdown = false; +bool require_s2_shutdown = false;u8 reg;WARN_ON (!mutex_is_locked (&chip->lock));
@@ -255,9 +259,25 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n"); } +if (chip->subtype ==QPNP_TM_SUBTYPE_GEN2 ) { +/* +* Check if stage 2 automatic partial shutdown must remain +* enabled to avoid potential repeated faults upon reaching +* over-temperature stage 3. +*/ +switch (chip->dig_revision) { +case 0x0001 : +case 0x0002 : +case 0x0100 : +case 0x0101 : + require_s2_shutdown = true; +break ; + } + } + skip: reg |= chip->thresh; -if (disable_s2_shutdown) +if (disable_s2_shutdown && !require_s2_shutdown) reg |=SHUTDOWN_CTRL1_OVERRIDE_S2 ;return qpnp_tm_write (chip,QPNP_TM_REG_SHUTDOWN_CTRL1 , reg);
@@ -372,7 +392,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) {struct qpnp_tm_chip *chip;struct device_node *node; -u8 type, subtype, dig_major; +u8 type, subtype, dig_major, dig_minor;u32 res;int ret, irq;
@@ -428,6 +448,14 @@ static int qpnp_tm_probe(struct platform_device *pdev)return ret; } + ret =qpnp_tm_read (chip,QPNP_TM_REG_DIG_MINOR , &dig_minor); +if (ret <0 ) { +dev_err (&pdev->dev,"could not read dig_minor\n" ); +return ret; + } + + chip->dig_revision = (dig_major <<8 ) | dig_minor; +if (type !=QPNP_TM_TYPE || (subtype !=QPNP_TM_SUBTYPE_GEN1 && subtype !=QPNP_TM_SUBTYPE_GEN2 )) { dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
Signature · 1 line
2.25.1
PATCH v3 2/3 thermal: qcom-spmi-temp-alarm: add support for GEN2 rev 2 PMIC peripherals
In reply to David CollinsAdd support for TEMP_ALARM GEN2 PMIC peripherals with digital major revision 2. This revision utilizes individual registers to set the threshold temperature for over-temperature stages 1, 2, and 3 instead of a single register to specify a set of thresholds.
--- drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 162 +++++++++++++++++++- 1 file changed, 156 insertions(+), 6 deletions(-)
drivers/thermal/qcom/qcom-spmi-temp-alarm.c +156 -6
@@ -26,6 +26,10 @@#define QPNP_TM_REG_STATUS 0x08#define QPNP_TM_REG_SHUTDOWN_CTRL1 0x40#define QPNP_TM_REG_ALARM_CTRL 0x46 +/* TEMP_DAC_* registers are only present for TEMP_GEN2 v2.0 */ +#define QPNP_TM_REG_TEMP_DAC_STG1 0x47 +#define QPNP_TM_REG_TEMP_DAC_STG2 0x48 +#define QPNP_TM_REG_TEMP_DAC_STG3 0x49#define QPNP_TM_TYPE 0x09#define QPNP_TM_SUBTYPE_GEN1 0x08
@@ -67,6 +71,25 @@ static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = {#define TEMP_STAGE_HYSTERESIS 2000 +/* +* For TEMP_GEN2 v2.0, TEMP_DAC_STG1/2/3 registers are used to set the threshold +* for each stage independently. +* TEMP_DAC_STG* = 0 --> 80 C +* Each 8 step increase in TEMP_DAC_STG* value corresponds to 5 C (5000 mC). +*/ +#define TEMP_DAC_MIN 80000 +#define TEMP_DAC_SCALE_NUM 8 +#define TEMP_DAC_SCALE_DEN 5000 + +#define TEMP_DAC_TEMP_TO_REG (temp) \ + (((temp) - TEMP_DAC_MIN) * TEMP_DAC_SCALE_NUM / TEMP_DAC_SCALE_DEN) +#define TEMP_DAC_REG_TO_TEMP (reg) \ + (TEMP_DAC_MIN + (reg) * TEMP_DAC_SCALE_DEN / TEMP_DAC_SCALE_NUM) + +static const long temp_dac_max[STAGE_COUNT ] = { +119375 ,159375 ,159375 +}; +/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ #define DEFAULT_TEMP 37000
@@ -87,6 +110,9 @@ struct qpnp_tm_chip {struct iio_channel *adc;const long (*temp_map)[THRESH_COUNT ][STAGE_COUNT ]; + +bool has_temp_dac; +long temp_dac_map[STAGE_COUNT ]; };/* This array maps from GEN2 alarm state to GEN1 alarm stage */
@@ -120,6 +146,13 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)*/ static long qpnp_tm_decode_temp (struct qpnp_tm_chip *chip,unsigned int stage) { +if (chip->has_temp_dac) { +if (stage ==0 || stage >STAGE_COUNT ) +return 0 ; + +return chip->temp_dac_map[stage -1 ]; + } +if (!chip->temp_map || chip->thresh >=THRESH_COUNT || stage ==0 || stage >STAGE_COUNT )return 0 ;
@@ -221,6 +254,34 @@ static int qpnp_tm_get_temp(struct thermal_zone_device *tz, int *temp)return 0 ; } +static int qpnp_tm_set_temp_dac_thresh (struct qpnp_tm_chip *chip,int trip, +int temp) +{ +int ret, temp_cfg; +u8 reg; + +if (trip <0 || trip >=STAGE_COUNT ) { +dev_err (chip->dev,"invalid TEMP_DAC trip = %d\n" , trip); +return -EINVAL ; + }else if (temp <TEMP_DAC_MIN || temp > temp_dac_max[trip]) { +dev_err (chip->dev,"invalid TEMP_DAC temp = %d\n" , temp); +return -EINVAL ; + } + + reg =TEMP_DAC_TEMP_TO_REG (temp); + temp_cfg =TEMP_DAC_REG_TO_TEMP (reg); + + ret =qpnp_tm_write (chip,QPNP_TM_REG_TEMP_DAC_STG1 + trip, reg); +if (ret <0 ) { +dev_err (chip->dev,"TEMP_DAC_STG write failed, ret=%d\n" , ret); +return ret; + } + + chip->temp_dac_map[trip] = temp_cfg; + +return 0 ; +} +static int qpnp_tm_update_critical_trip_temp (struct qpnp_tm_chip *chip,int temp) {
@@ -308,6 +369,24 @@ static const struct thermal_zone_device_ops qpnp_tm_sensor_ops = { .set_trip_temp = qpnp_tm_set_trip_temp, }; +static int qpnp_tm_set_temp_dac_trip_temp (struct thermal_zone_device *tz, +int trip,int temp) +{ +struct qpnp_tm_chip *chip = tz->devdata; +int ret; + +mutex_lock (&chip->lock); + ret =qpnp_tm_set_temp_dac_thresh (chip, trip, temp); +mutex_unlock (&chip->lock); + +return ret; +} + +static const struct thermal_zone_device_ops qpnp_tm_sensor_temp_dac_ops = { + .get_temp = qpnp_tm_get_temp, + .set_trip_temp = qpnp_tm_set_temp_dac_trip_temp, +}; +static irqreturn_t qpnp_tm_isr (int irq,void *data) {struct qpnp_tm_chip *chip = data;
@@ -340,6 +419,60 @@ static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip)return THERMAL_TEMP_INVALID ; } +/* Configure TEMP_DAC registers based on DT thermal_zone trips */ +static int qpnp_tm_temp_dac_update_trip_temps (struct qpnp_tm_chip *chip) +{ +const struct thermal_trip *trips; +int ret, ntrips, i; + + ntrips =of_thermal_get_ntrips (chip->tz_dev); +/* Keep hardware defaults if no DT trips are defined. */ +if (ntrips <=0 ) +return 0 ; + + trips =of_thermal_get_trip_points (chip->tz_dev); +if (!trips) +return -EINVAL ; + +for (i =0 ; i < ntrips; i++) { +if (of_thermal_is_trip_valid (chip->tz_dev, i)) { + ret =qpnp_tm_set_temp_dac_thresh (chip, i, + trips[i].temperature); +if (ret <0 ) +return ret; + } + } + +/* Verify that trips are strictly increasing. */ +for (i =1 ; i <STAGE_COUNT ; i++) { +if (chip->temp_dac_map[i] <= chip->temp_dac_map[i -1 ]) { +dev_err (chip->dev,"Threshold %d=%ld <= threshold %d=%ld\n" , + i, chip->temp_dac_map[i], i -1 , + chip->temp_dac_map[i -1 ]); +return -EINVAL ; + } + } + +return 0 ; +} + +/* Read the hardware default TEMP_DAC stage threshold temperatures */ +static int qpnp_tm_temp_dac_init (struct qpnp_tm_chip *chip) +{ +int ret, i; +u8 reg =0 ; + +for (i =0 ; i <STAGE_COUNT ; i++) { + ret =qpnp_tm_read (chip,QPNP_TM_REG_TEMP_DAC_STG1 + i, ®); +if (ret <0 ) +return ret; + + chip->temp_dac_map[i] =TEMP_DAC_REG_TO_TEMP (reg); + } + +return 0 ; +} +/* * This function initializes the internal temp value based on only the * current thermal stage and threshold. Setup threshold control and
@@ -372,10 +505,16 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)if (stage) chip->temp =qpnp_tm_decode_temp (chip, stage); - crit_temp =qpnp_tm_get_critical_trip_temp (chip); - ret =qpnp_tm_update_critical_trip_temp (chip, crit_temp); -if (ret <0 ) - goto out; +if (chip->has_temp_dac) { + ret =qpnp_tm_temp_dac_update_trip_temps (chip); +if (ret <0 ) + goto out; + }else { + crit_temp =qpnp_tm_get_critical_trip_temp (chip); + ret =qpnp_tm_update_critical_trip_temp (chip, crit_temp); +if (ret <0 ) + goto out; + }/* Enable the thermal alarm PMIC module in always-on mode. */ reg =ALARM_CTRL_FORCE_ENABLE ;
@@ -392,6 +531,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) {struct qpnp_tm_chip *chip;struct device_node *node; +const struct thermal_zone_device_ops *ops;u8 type, subtype, dig_major, dig_minor;u32 res;int ret, irq;
@@ -463,19 +603,29 @@ static int qpnp_tm_probe(struct platform_device *pdev)return -ENODEV ; } + ops = &qpnp_tm_sensor_ops; chip->subtype = subtype; -if (subtype ==QPNP_TM_SUBTYPE_GEN2 && dig_major >=1 ) +if (subtype ==QPNP_TM_SUBTYPE_GEN2 && dig_major >=2 ) + chip->has_temp_dac = true; +else if (subtype ==QPNP_TM_SUBTYPE_GEN2 && dig_major >=1 ) chip->temp_map = &temp_map_gen2_v1;else chip->temp_map = &temp_map_gen1; +if (chip->has_temp_dac) { + ops = &qpnp_tm_sensor_temp_dac_ops; + ret =qpnp_tm_temp_dac_init (chip); +if (ret <0 ) +return ret; + } +/* * Register the sensor before initializing the hardware to be able to * read the trip points. get_temp() returns the default temperature * before the hardware initialization is completed. */ chip->tz_dev =devm_thermal_of_zone_register ( - &pdev->dev,0 , chip, &qpnp_tm_sensor_ops); + &pdev->dev,0 , chip, ops);if (IS_ERR (chip->tz_dev)) {dev_err (&pdev->dev,"failed to register sensor\n" );return PTR_ERR (chip->tz_dev);
Signature · 1 line
2.25.1
PATCH v3 3/3 thermal: qcom-spmi-temp-alarm: add support for LITE PMIC peripherals
In reply to David CollinsAdd support for TEMP_ALARM LITE PMIC peripherals. This subtype utilizes a pair of registers to configure a warning interrupt threshold temperature and an automatic hardware shutdown threshold temperature.
--- drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 217 +++++++++++++++++++- 1 file changed, 208 insertions(+), 9 deletions(-)
drivers/thermal/qcom/qcom-spmi-temp-alarm.c +208 -9
@@ -4,6 +4,7 @@* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/err.h>
@@ -24,21 +25,28 @@#define QPNP_TM_REG_TYPE 0x04#define QPNP_TM_REG_SUBTYPE 0x05#define QPNP_TM_REG_STATUS 0x08 +#define QPNP_TM_REG_IRQ_STATUS 0x10#define QPNP_TM_REG_SHUTDOWN_CTRL1 0x40#define QPNP_TM_REG_ALARM_CTRL 0x46/* TEMP_DAC_* registers are only present for TEMP_GEN2 v2.0 */ #define QPNP_TM_REG_TEMP_DAC_STG1 0x47#define QPNP_TM_REG_TEMP_DAC_STG2 0x48#define QPNP_TM_REG_TEMP_DAC_STG3 0x49 +#define QPNP_TM_REG_LITE_TEMP_CFG1 0x50 +#define QPNP_TM_REG_LITE_TEMP_CFG2 0x51#define QPNP_TM_TYPE 0x09#define QPNP_TM_SUBTYPE_GEN1 0x08#define QPNP_TM_SUBTYPE_GEN2 0x09 +#define QPNP_TM_SUBTYPE_LITE 0xC0#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0)#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)#define STATUS_GEN2_STATE_SHIFT 4 +/* IRQ status only needed for TEMP_ALARM_LITE */ +#define IRQ_STATUS_MASK BIT(0) +#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6)#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
@@ -46,6 +54,8 @@#define ALARM_CTRL_FORCE_ENABLE BIT(7) +#define LITE_TEMP_CFG_THRESHOLD_MASK GENMASK(3, 2) +#define THRESH_COUNT 4#define STAGE_COUNT 3
@@ -90,6 +100,19 @@ static const long temp_dac_max[STAGE_COUNT] = { 119375, 159375, 159375 }; +/* +* TEMP_ALARM_LITE has two stages: warning and shutdown with independently +* configured threshold temperatures. +*/ + +static const long temp_map_lite_warning[THRESH_COUNT ] = { +115000 ,125000 ,135000 ,145000 +}; + +static const long temp_map_lite_shutdown[THRESH_COUNT ] = { +135000 ,145000 ,160000 ,175000 +}; +/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ #define DEFAULT_TEMP 37000
@@ -146,7 +169,7 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)*/ static long qpnp_tm_decode_temp (struct qpnp_tm_chip *chip,unsigned int stage) { -if (chip->has_temp_dac) { +if (chip->has_temp_dac || chip->subtype ==QPNP_TM_SUBTYPE_LITE ) {if (stage ==0 || stage >STAGE_COUNT )return 0 ;
@@ -164,19 +187,26 @@ static long qpnp_tm_decode_temp(struct qpnp_tm_chip *chip, unsigned int stage)* qpnp_tm_get_temp_stage() - return over-temperature stage * @chip: Pointer to the qpnp_tm chip * -* Return: stage (GEN1) or state (GEN2) on success, or errno on failure. +* Return: stage (GEN1), state (GEN2), or alarm interrupt state (LITE) on +* success; or errno on failure. */ static int qpnp_tm_get_temp_stage (struct qpnp_tm_chip *chip) {int ret; +u16 addr =QPNP_TM_REG_STATUS ;u8 reg =0 ; - ret =qpnp_tm_read (chip,QPNP_TM_REG_STATUS , ®); +if (chip->subtype ==QPNP_TM_SUBTYPE_LITE ) + addr =QPNP_TM_REG_IRQ_STATUS ; + + ret =qpnp_tm_read (chip, addr, ®);if (ret <0 )return ret;if (chip->subtype ==QPNP_TM_SUBTYPE_GEN1 ) ret = reg &STATUS_GEN1_STAGE_MASK ; +else if (chip->subtype ==QPNP_TM_SUBTYPE_LITE ) + ret = reg &IRQ_STATUS_MASK ;else ret = (reg &STATUS_GEN2_STATE_MASK ) >>STATUS_GEN2_STATE_SHIFT ;
@@ -199,7 +229,8 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)return ret; stage = ret; -if (chip->subtype ==QPNP_TM_SUBTYPE_GEN1 ) { +if (chip->subtype ==QPNP_TM_SUBTYPE_GEN1 + || chip->subtype ==QPNP_TM_SUBTYPE_LITE ) { stage_new = stage; stage_old = chip->stage; }else {
@@ -282,6 +313,78 @@ static int qpnp_tm_set_temp_dac_thresh(struct qpnp_tm_chip *chip, int trip,return 0 ; } +static int qpnp_tm_set_temp_lite_thresh (struct qpnp_tm_chip *chip,int trip, +int temp) +{ +int ret, temp_cfg, i; +const long *temp_map; +u16 addr; +u8 reg, thresh; + +if (trip <0 || trip >=STAGE_COUNT ) { +dev_err (chip->dev,"invalid TEMP_LITE trip = %d\n" , trip); +return -EINVAL ; + } + +switch (trip) { +case 0 : + temp_map = temp_map_lite_warning; + addr =QPNP_TM_REG_LITE_TEMP_CFG1 ; +break ; +case 1 : +/* +* The second trip point is purely in software to facilitate +* a controlled shutdown after the warning threshold is crossed +* but before the automatic hardware shutdown threshold is +* crossed. +*/ +return 0 ; +case 2 : + temp_map = temp_map_lite_shutdown; + addr =QPNP_TM_REG_LITE_TEMP_CFG2 ; +break ; +default : +return 0 ; + } + +if (temp < temp_map[THRESH_MIN ] || temp > temp_map[THRESH_MAX ]) { +dev_err (chip->dev,"invalid TEMP_LITE temp = %d\n" , temp); +return -EINVAL ; + } + + thresh =0 ; + temp_cfg = temp_map[thresh]; +for (i =THRESH_MAX ; i >=THRESH_MIN ; i--) { +if (temp >= temp_map[i]) { + thresh = i; + temp_cfg = temp_map[i]; +break ; + } + } + +if (temp_cfg == chip->temp_dac_map[trip]) +return 0 ; + + ret =qpnp_tm_read (chip, addr, ®); +if (ret <0 ) { +dev_err (chip->dev,"LITE_TEMP_CFG read failed, ret=%d\n" , ret); +return ret; + } + + reg &= ~LITE_TEMP_CFG_THRESHOLD_MASK ; + reg |=FIELD_PREP (LITE_TEMP_CFG_THRESHOLD_MASK , thresh); + + ret =qpnp_tm_write (chip, addr, reg); +if (ret <0 ) { +dev_err (chip->dev,"LITE_TEMP_CFG write failed, ret=%d\n" , ret); +return ret; + } + + chip->temp_dac_map[trip] = temp_cfg; + +return 0 ; +} +static int qpnp_tm_update_critical_trip_temp (struct qpnp_tm_chip *chip,int temp) {
@@ -387,6 +490,24 @@ static const struct thermal_zone_device_ops qpnp_tm_sensor_temp_dac_ops = { .set_trip_temp = qpnp_tm_set_temp_dac_trip_temp, }; +static int qpnp_tm_set_temp_lite_trip_temp (struct thermal_zone_device *tz, +int trip,int temp) +{ +struct qpnp_tm_chip *chip = tz->devdata; +int ret; + +mutex_lock (&chip->lock); + ret =qpnp_tm_set_temp_lite_thresh (chip, trip, temp); +mutex_unlock (&chip->lock); + +return ret; +} + +static const struct thermal_zone_device_ops qpnp_tm_sensor_temp_lite_ops = { + .get_temp = qpnp_tm_get_temp, + .set_trip_temp = qpnp_tm_set_temp_lite_trip_temp, +}; +static irqreturn_t qpnp_tm_isr (int irq,void *data) {struct qpnp_tm_chip *chip = data;
@@ -473,6 +594,71 @@ static int qpnp_tm_temp_dac_init(struct qpnp_tm_chip *chip)return 0 ; } +/* Configure TEMP_LITE registers based on DT thermal_zone trips */ +static int qpnp_tm_temp_lite_update_trip_temps (struct qpnp_tm_chip *chip) +{ +const struct thermal_trip *trips; +int ret, ntrips, i; + + ntrips =of_thermal_get_ntrips (chip->tz_dev); +/* Keep hardware defaults if no DT trips are defined. */ +if (ntrips <=0 ) +return 0 ; + + trips =of_thermal_get_trip_points (chip->tz_dev); +if (!trips) +return -EINVAL ; + +for (i =0 ; i < ntrips; i++) { +if (of_thermal_is_trip_valid (chip->tz_dev, i)) { + ret =qpnp_tm_set_temp_lite_thresh (chip, i, + trips[i].temperature); +if (ret <0 ) +return ret; + } + } + +/* Verify that trips are strictly increasing. */ +if (chip->temp_dac_map[2 ] <= chip->temp_dac_map[0 ]) { +dev_err (chip->dev,"Threshold 2=%ld <= threshold 0=%ld\n" , + chip->temp_dac_map[2 ], chip->temp_dac_map[0 ]); +return -EINVAL ; + } + +return 0 ; +} + +/* Read the hardware default TEMP_LITE stage threshold temperatures */ +static int qpnp_tm_temp_lite_init (struct qpnp_tm_chip *chip) +{ +int ret, thresh; +u8 reg =0 ; + +/* +* Store the warning trip temp in temp_dac_map[0] and the shutdown trip +* temp in temp_dac_map[2]. The second trip point is purely in software +* to facilitate a controlled shutdown after the warning threshold is +* crossed but before the automatic hardware shutdown threshold is +* crossed. Thus, there is no register to read for the second trip +* point. +*/ + ret =qpnp_tm_read (chip,QPNP_TM_REG_LITE_TEMP_CFG1 , ®); +if (ret <0 ) +return ret; + + thresh =FIELD_GET (LITE_TEMP_CFG_THRESHOLD_MASK , reg); + chip->temp_dac_map[0 ] = temp_map_lite_warning[thresh]; + + ret =qpnp_tm_read (chip,QPNP_TM_REG_LITE_TEMP_CFG2 , ®); +if (ret <0 ) +return ret; + + thresh =FIELD_GET (LITE_TEMP_CFG_THRESHOLD_MASK , reg); + chip->temp_dac_map[2 ] = temp_map_lite_shutdown[thresh]; + +return 0 ; +} +/* * This function initializes the internal temp value based on only the * current thermal stage and threshold. Setup threshold control and
@@ -499,13 +685,18 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) goto out; chip->stage = ret; - stage = chip->subtype ==QPNP_TM_SUBTYPE_GEN1 - ? chip->stage : alarm_state_map[chip->stage]; + stage = (chip->subtype ==QPNP_TM_SUBTYPE_GEN1 + || chip->subtype ==QPNP_TM_SUBTYPE_LITE ) + ? chip->stage : alarm_state_map[chip->stage];if (stage) chip->temp =qpnp_tm_decode_temp (chip, stage); -if (chip->has_temp_dac) { +if (chip->subtype ==QPNP_TM_SUBTYPE_LITE ) { + ret =qpnp_tm_temp_lite_update_trip_temps (chip); +if (ret <0 ) + goto out; + }else if (chip->has_temp_dac) { ret =qpnp_tm_temp_dac_update_trip_temps (chip);if (ret <0 ) goto out;
@@ -597,7 +788,8 @@ static int qpnp_tm_probe(struct platform_device *pdev) chip->dig_revision = (dig_major <<8 ) | dig_minor;if (type !=QPNP_TM_TYPE || (subtype !=QPNP_TM_SUBTYPE_GEN1 - && subtype !=QPNP_TM_SUBTYPE_GEN2 )) { + && subtype !=QPNP_TM_SUBTYPE_GEN2 + && subtype !=QPNP_TM_SUBTYPE_LITE )) {dev_err (&pdev->dev,"invalid type 0x%02x or subtype 0x%02x\n" , type, subtype);return -ENODEV ;
@@ -609,7 +801,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) chip->has_temp_dac = true; else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1) chip->temp_map = &temp_map_gen2_v1; - else + else if (subtype == QPNP_TM_SUBTYPE_GEN1) chip->temp_map = &temp_map_gen1;if (chip->has_temp_dac) {
@@ -619,6 +811,13 @@ static int qpnp_tm_probe(struct platform_device *pdev)return ret; } +if (chip->subtype ==QPNP_TM_SUBTYPE_LITE ) { + ops = &qpnp_tm_sensor_temp_lite_ops; + ret =qpnp_tm_temp_lite_init (chip); +if (ret <0 ) +return ret; + } +/* * Register the sensor before initializing the hardware to be able to * read the trip points. get_temp() returns the default temperature
Signature · 1 line
2.25.1