]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
thermal/drivers/qcom-spmi-temp-alarm: Add temp alarm data struct based on HW subtype
authorAnjelique Melendez <anjelique.melendez@oss.qualcomm.com>
Thu, 10 Jul 2025 22:45:52 +0000 (15:45 -0700)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Sun, 13 Jul 2025 16:01:03 +0000 (18:01 +0200)
Currently multiple if/else statements are used in functions to decipher
between SPMI temp alarm Gen 1, Gen 2 and Gen 2 Rev 1 functionality. Instead
refactor the driver so that SPMI temp alarm chips will have reference to a
spmi_temp_alarm_data struct which defines data and function callbacks
based on the HW subtype.

Signed-off-by: Anjelique Melendez <anjelique.melendez@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20250710224555.3047790-3-anjelique.melendez@oss.qualcomm.com
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
drivers/thermal/qcom/qcom-spmi-temp-alarm.c

index 4b91cc13ce3472e8b735e14d052d42a5f04ff661..607838162c7d0499e25734fb81001b50c566ee55 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -31,7 +32,6 @@
 
 #define STATUS_GEN1_STAGE_MASK         GENMASK(1, 0)
 #define STATUS_GEN2_STATE_MASK         GENMASK(6, 4)
-#define STATUS_GEN2_STATE_SHIFT                4
 
 #define SHUTDOWN_CTRL1_OVERRIDE_STAGE2 BIT(6)
 #define SHUTDOWN_CTRL1_THRESHOLD_MASK  GENMASK(1, 0)
 #define THRESH_COUNT                   4
 #define STAGE_COUNT                    3
 
+enum overtemp_stage {
+       STAGE1 = 0,
+       STAGE2,
+       STAGE3,
+};
+
 /* Over-temperature trip point values in mC */
 static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = {
        { 105000, 125000, 145000 },
@@ -68,22 +74,29 @@ static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = {
 /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
 #define DEFAULT_TEMP                   37000
 
+struct qpnp_tm_chip;
+
+struct spmi_temp_alarm_data {
+       const long (*temp_map)[THRESH_COUNT][STAGE_COUNT];
+       int (*get_temp_stage)(struct qpnp_tm_chip *chip);
+};
+
 struct qpnp_tm_chip {
        struct regmap                   *map;
        struct device                   *dev;
        struct thermal_zone_device      *tz_dev;
+       const struct spmi_temp_alarm_data *data;
        unsigned int                    subtype;
        long                            temp;
-       unsigned int                    thresh;
        unsigned int                    stage;
        unsigned int                    base;
        /* protects .thresh, .stage and chip registers */
        struct mutex                    lock;
        bool                            initialized;
        bool                            require_stage2_shutdown;
+       long                            temp_thresh_map[STAGE_COUNT];
 
        struct iio_channel              *adc;
-       const long                      (*temp_map)[THRESH_COUNT][STAGE_COUNT];
 };
 
 /* This array maps from GEN2 alarm state to GEN1 alarm stage */
@@ -117,34 +130,48 @@ 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->temp_map || chip->thresh >= THRESH_COUNT || stage == 0 ||
-           stage > STAGE_COUNT)
+       if (stage == 0 || stage > STAGE_COUNT)
                return 0;
 
-       return (*chip->temp_map)[chip->thresh][stage - 1];
+       return chip->temp_thresh_map[stage - 1];
 }
 
 /**
- * qpnp_tm_get_temp_stage() - return over-temperature stage
+ * qpnp_tm_gen1_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 on success, or errno on failure.
  */
-static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
+static int qpnp_tm_gen1_get_temp_stage(struct qpnp_tm_chip *chip)
 {
        int ret;
-       u8 reg = 0;
+       u8 reg;
 
        ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
        if (ret < 0)
                return ret;
 
-       if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
-               ret = reg & STATUS_GEN1_STAGE_MASK;
-       else
-               ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT;
+       return FIELD_GET(STATUS_GEN1_STAGE_MASK, reg);
+}
 
-       return ret;
+/**
+ * qpnp_tm_gen2_get_temp_stage() - return over-temperature stage
+ * @chip:              Pointer to the qpnp_tm chip
+ *
+ * Return: stage on success, or errno on failure.
+ */
+static int qpnp_tm_gen2_get_temp_stage(struct qpnp_tm_chip *chip)
+{
+       int ret;
+       u8 reg;
+
+       ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
+       if (ret < 0)
+               return ret;
+
+       ret = FIELD_GET(STATUS_GEN2_STATE_MASK, reg);
+
+       return alarm_state_map[ret];
 }
 
 /*
@@ -153,23 +180,16 @@ static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
  */
 static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
 {
-       unsigned int stage, stage_new, stage_old;
+       unsigned int stage_new, stage_old;
        int ret;
 
        WARN_ON(!mutex_is_locked(&chip->lock));
 
-       ret = qpnp_tm_get_temp_stage(chip);
+       ret = chip->data->get_temp_stage(chip);
        if (ret < 0)
                return ret;
-       stage = ret;
-
-       if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
-               stage_new = stage;
-               stage_old = chip->stage;
-       } else {
-               stage_new = alarm_state_map[stage];
-               stage_old = alarm_state_map[chip->stage];
-       }
+       stage_new = ret;
+       stage_old = chip->stage;
 
        if (stage_new > stage_old) {
                /* increasing stage, use lower bound */
@@ -181,7 +201,7 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
                                - TEMP_STAGE_HYSTERESIS;
        }
 
-       chip->stage = stage;
+       chip->stage = stage_new;
 
        return 0;
 }
@@ -221,10 +241,10 @@ static int qpnp_tm_get_temp(struct thermal_zone_device *tz, int *temp)
 static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
                                             int temp)
 {
-       long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN][1];
-       long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX][1];
+       long stage2_threshold_min = (*chip->data->temp_map)[THRESH_MIN][STAGE2];
+       long stage2_threshold_max = (*chip->data->temp_map)[THRESH_MAX][STAGE2];
        bool disable_stage2_shutdown = false;
-       u8 reg;
+       u8 reg, threshold;
 
        WARN_ON(!mutex_is_locked(&chip->lock));
 
@@ -236,17 +256,17 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
 
        if (temp == THERMAL_TEMP_INVALID ||
            temp < stage2_threshold_min) {
-               chip->thresh = THRESH_MIN;
+               threshold = THRESH_MIN;
                goto skip;
        }
 
        if (temp <= stage2_threshold_max) {
-               chip->thresh = THRESH_MAX -
+               threshold = THRESH_MAX -
                        ((stage2_threshold_max - temp) /
                         TEMP_THRESH_STEP);
                disable_stage2_shutdown = true;
        } else {
-               chip->thresh = THRESH_MAX;
+               threshold = THRESH_MAX;
 
                if (chip->adc)
                        disable_stage2_shutdown = true;
@@ -257,7 +277,9 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
        }
 
 skip:
-       reg |= chip->thresh;
+       memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
+               sizeof(chip->temp_thresh_map));
+       reg |= threshold;
        if (disable_stage2_shutdown && !chip->require_stage2_shutdown)
                reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2;
 
@@ -294,6 +316,21 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static const struct spmi_temp_alarm_data spmi_temp_alarm_data = {
+       .temp_map = &temp_map_gen1,
+       .get_temp_stage = qpnp_tm_gen1_get_temp_stage,
+};
+
+static const struct spmi_temp_alarm_data spmi_temp_alarm_gen2_data = {
+       .temp_map = &temp_map_gen1,
+       .get_temp_stage = qpnp_tm_gen2_get_temp_stage,
+};
+
+static const struct spmi_temp_alarm_data spmi_temp_alarm_gen2_rev1_data = {
+       .temp_map = &temp_map_gen2_v1,
+       .get_temp_stage = qpnp_tm_gen2_get_temp_stage,
+};
+
 /*
  * This function initializes the internal temp value based on only the
  * current thermal stage and threshold. Setup threshold control and
@@ -301,10 +338,10 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
  */
 static int qpnp_tm_init(struct qpnp_tm_chip *chip)
 {
-       unsigned int stage;
-       int ret;
-       u8 reg = 0;
        int crit_temp;
+       u8 threshold;
+       int ret;
+       u8 reg;
 
        mutex_lock(&chip->lock);
 
@@ -312,19 +349,19 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
        if (ret < 0)
                goto out;
 
-       chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
+       threshold = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
+       memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
+               sizeof(chip->temp_thresh_map));
+
        chip->temp = DEFAULT_TEMP;
 
-       ret = qpnp_tm_get_temp_stage(chip);
+       ret = chip->data->get_temp_stage(chip);
        if (ret < 0)
                goto out;
        chip->stage = ret;
 
-       stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
-               ? chip->stage : alarm_state_map[chip->stage];
-
-       if (stage)
-               chip->temp = qpnp_tm_decode_temp(chip, stage);
+       if (chip->stage)
+               chip->temp = qpnp_tm_decode_temp(chip, chip->stage);
 
        mutex_unlock(&chip->lock);
 
@@ -418,10 +455,14 @@ static int qpnp_tm_probe(struct platform_device *pdev)
        }
 
        chip->subtype = subtype;
-       if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1)
-               chip->temp_map = &temp_map_gen2_v1;
+       if (subtype == QPNP_TM_SUBTYPE_GEN1)
+               chip->data = &spmi_temp_alarm_data;
+       else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major == 0)
+               chip->data = &spmi_temp_alarm_gen2_data;
+       else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1)
+               chip->data = &spmi_temp_alarm_gen2_rev1_data;
        else
-               chip->temp_map = &temp_map_gen1;
+               return -ENODEV;
 
        if (chip->subtype == QPNP_TM_SUBTYPE_GEN2) {
                dig_revision = (dig_major << 8) | dig_minor;