summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-01-29 15:30:03 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-01-29 15:30:03 +0100
commit74dd4d1f4c7d2e49bbeb1374f1ebea95d963eac0 (patch)
tree5c72dd15804467a53d6e7cc4bbff53487b845f60
parenta1fe789a96fe47733c133134fd264cb7ca832395 (diff)
parent0061030929e2d09398ade9fae320528bdcba2bed (diff)
Merge tag 'thermal-v7.0' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux
Pull thermal control updates for 6.20/7.0 from Daniel Lezcano: "- Fix CFLAGS and LDFLAGS in the pkg-config template fir the libthermal (Romain Gantois) - Support multiple temp to raw conversion functions for the Mediatek LVTS thermal driver and add the MT8196 and MT6991 support (Laura Nao) - Add support for the Mediatek LVTS driver for MT7987 (Frank Wunderlich) - Use the existing HZ_PER_MHZ macro on STM32 (Andy Shevchenko) - Use the existing clamp() macro in BCM2835 (Thorsten Blum) - Make the reset line optional in order to support new Renesas Soc where it is not available. Add the RZ/T2H and RZ/N2H suppport (Cosmin Tanislav)" * tag 'thermal-v7.0' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux: thermal: renesas: rzg3e: add support for RZ/T2H and RZ/N2H dt-bindings: thermal: r9a09g047-tsu: document RZ/T2H and RZ/N2H thermal: renesas: rzg3e: make calibration value retrieval per-chip thermal: renesas: rzg3e: make min and max temperature per-chip thermal: renesas: rzg3e: make reset optional dt-bindings: thermal: r9a09g047-tsu: Document RZ/V2N TSU thermal/drivers/broadcom: Use clamp to simplify bcm2835_thermal_temp2adc thermal/drivers/stm32: Use predefined HZ_PER_MHZ instead of a custom one thermal/drivers/mediatek/lvts_thermal: Add mt7987 support dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT7987 dt-bindings: nvmem: mediatek: efuse: Add support for MT8196 thermal/drivers/mediatek/lvts_thermal: Add MT8196 support thermal/drivers/mediatek/lvts: Support MSR offset for 16-bit calibration data thermal/drivers/mediatek/lvts: Add support for ATP mode thermal/drivers/mediatek/lvts: Add lvts_temp_to_raw variant thermal/drivers/mediatek/lvts: Add platform ops to support alternative conversion logic thermal/drivers/mediatek/lvts: Make number of calibration offsets configurable dt-bindings: thermal: mediatek: Add LVTS thermal controller support for MT8196 tools: lib: thermal: Correct CFLAGS and LDFLAGS in pkg-config template
-rw-r--r--Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml1
-rw-r--r--Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml3
-rw-r--r--Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml34
-rw-r--r--drivers/thermal/broadcom/bcm2835_thermal.c8
-rw-r--r--drivers/thermal/mediatek/lvts_thermal.c362
-rw-r--r--drivers/thermal/renesas/rzg3e_thermal.c123
-rw-r--r--drivers/thermal/st/stm_thermal.c4
-rw-r--r--include/dt-bindings/thermal/mediatek,lvts-thermal.h29
-rw-r--r--tools/lib/thermal/libthermal.pc.template4
9 files changed, 483 insertions, 85 deletions
diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml
index c9bf34ee0efb..f9323b3ecfc8 100644
--- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml
+++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml
@@ -28,6 +28,7 @@ properties:
- enum:
- mediatek,mt8188-efuse
- mediatek,mt8189-efuse
+ - mediatek,mt8196-efuse
- const: mediatek,mt8186-efuse
- const: mediatek,mt8186-efuse
diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
index 0259cd3ce9c5..975235130670 100644
--- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
@@ -18,6 +18,7 @@ description: |
properties:
compatible:
enum:
+ - mediatek,mt7987-lvts-ap
- mediatek,mt7988-lvts-ap
- mediatek,mt8186-lvts
- mediatek,mt8188-lvts-ap
@@ -26,6 +27,8 @@ properties:
- mediatek,mt8192-lvts-mcu
- mediatek,mt8195-lvts-ap
- mediatek,mt8195-lvts-mcu
+ - mediatek,mt8196-lvts-ap
+ - mediatek,mt8196-lvts-mcu
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml
index befdc8b7a082..d560c58be4d6 100644
--- a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml
+++ b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml
@@ -17,10 +17,17 @@ description:
properties:
compatible:
oneOf:
- - const: renesas,r9a09g047-tsu # RZ/G3E
+ - enum:
+ - renesas,r9a09g047-tsu # RZ/G3E
+ - renesas,r9a09g077-tsu # RZ/T2H
- items:
- - const: renesas,r9a09g057-tsu # RZ/V2H
+ - enum:
+ - renesas,r9a09g056-tsu # RZ/V2N
+ - renesas,r9a09g057-tsu # RZ/V2H
- const: renesas,r9a09g047-tsu # RZ/G3E
+ - items:
+ - const: renesas,r9a09g087-tsu # RZ/N2H
+ - const: renesas,r9a09g077-tsu # RZ/T2H
reg:
maxItems: 1
@@ -63,12 +70,31 @@ required:
- compatible
- reg
- clocks
- - resets
- power-domains
- interrupts
- interrupt-names
- "#thermal-sensor-cells"
- - renesas,tsu-trim
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g047-tsu
+ then:
+ required:
+ - resets
+ - renesas,tsu-trim
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g077-tsu
+ then:
+ properties:
+ resets: false
+ renesas,tsu-trim: false
additionalProperties: false
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c
index 685a5aee5e0d..c5105dfc6ec9 100644
--- a/drivers/thermal/broadcom/bcm2835_thermal.c
+++ b/drivers/thermal/broadcom/bcm2835_thermal.c
@@ -11,6 +11,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -80,12 +81,7 @@ static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
temp -= offset;
temp /= slope;
- if (temp < 0)
- temp = 0;
- if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
- temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
-
- return temp;
+ return clamp(temp, 0, (int)BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1);
}
static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index ab55b20cda47..a9617d5e0077 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -44,6 +44,11 @@
#define LVTS_EDATA01(__base) (__base + 0x0058)
#define LVTS_EDATA02(__base) (__base + 0x005C)
#define LVTS_EDATA03(__base) (__base + 0x0060)
+#define LVTS_MSROFT(__base) (__base + 0x006C)
+#define LVTS_ATP0(__base) (__base + 0x0070)
+#define LVTS_ATP1(__base) (__base + 0x0074)
+#define LVTS_ATP2(__base) (__base + 0x0078)
+#define LVTS_ATP3(__base) (__base + 0x007C)
#define LVTS_MSR0(__base) (__base + 0x0090)
#define LVTS_MSR1(__base) (__base + 0x0094)
#define LVTS_MSR2(__base) (__base + 0x0098)
@@ -85,30 +90,43 @@
#define LVTS_GOLDEN_TEMP_DEFAULT 50
#define LVTS_COEFF_A_MT8195 -250460
#define LVTS_COEFF_B_MT8195 250460
+#define LVTS_COEFF_A_MT7987 -204650
+#define LVTS_COEFF_B_MT7987 204650
#define LVTS_COEFF_A_MT7988 -204650
#define LVTS_COEFF_B_MT7988 204650
+#define LVTS_COEFF_A_MT8196 391460
+#define LVTS_COEFF_B_MT8196 -391460
-#define LVTS_MSR_IMMEDIATE_MODE 0
-#define LVTS_MSR_FILTERED_MODE 1
+#define LVTS_MSR_OFFSET_MT8196 -984
#define LVTS_MSR_READ_TIMEOUT_US 400
#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
#define LVTS_MINIMUM_THRESHOLD 20000
+#define LVTS_MAX_CAL_OFFSETS 3
+#define LVTS_NUM_CAL_OFFSETS_MT7988 3
+#define LVTS_NUM_CAL_OFFSETS_MT8196 2
+
static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
static int golden_temp_offset;
+enum lvts_msr_mode {
+ LVTS_MSR_IMMEDIATE_MODE,
+ LVTS_MSR_FILTERED_MODE,
+ LVTS_MSR_ATP_MODE,
+};
+
struct lvts_sensor_data {
int dt_id;
- u8 cal_offsets[3];
+ u8 cal_offsets[LVTS_MAX_CAL_OFFSETS];
};
struct lvts_ctrl_data {
struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
u8 valid_sensor_mask;
int offset;
- int mode;
+ enum lvts_msr_mode mode;
};
#define VALID_SENSOR_MAP(s0, s1, s2, s3) \
@@ -123,10 +141,17 @@ struct lvts_ctrl_data {
continue; \
else
+struct lvts_platform_ops {
+ int (*lvts_raw_to_temp)(u32 raw_temp, int temp_factor);
+ u32 (*lvts_temp_to_raw)(int temperature, int temp_factor);
+};
+
struct lvts_data {
const struct lvts_ctrl_data *lvts_ctrl;
+ const struct lvts_platform_ops *ops;
const u32 *conn_cmd;
const u32 *init_cmd;
+ int num_cal_offsets;
int num_lvts_ctrl;
int num_conn_cmd;
int num_init_cmd;
@@ -134,6 +159,7 @@ struct lvts_data {
int temp_offset;
int gt_calib_bit_offset;
unsigned int def_calibration;
+ u16 msr_offset;
};
struct lvts_sensor {
@@ -202,6 +228,11 @@ static const struct debugfs_reg32 lvts_regs[] = {
LVTS_DEBUG_FS_REGS(LVTS_EDATA01),
LVTS_DEBUG_FS_REGS(LVTS_EDATA02),
LVTS_DEBUG_FS_REGS(LVTS_EDATA03),
+ LVTS_DEBUG_FS_REGS(LVTS_MSROFT),
+ LVTS_DEBUG_FS_REGS(LVTS_ATP0),
+ LVTS_DEBUG_FS_REGS(LVTS_ATP1),
+ LVTS_DEBUG_FS_REGS(LVTS_ATP2),
+ LVTS_DEBUG_FS_REGS(LVTS_ATP3),
LVTS_DEBUG_FS_REGS(LVTS_MSR0),
LVTS_DEBUG_FS_REGS(LVTS_MSR1),
LVTS_DEBUG_FS_REGS(LVTS_MSR2),
@@ -269,7 +300,17 @@ static inline int lvts_debugfs_init(struct device *dev,
#endif
-static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
+static int lvts_raw_to_temp(u32 raw_temp, const struct lvts_data *lvts_data)
+{
+ return lvts_data->ops->lvts_raw_to_temp(raw_temp & 0xFFFF, lvts_data->temp_factor);
+}
+
+static u32 lvts_temp_to_raw(int temperature, const struct lvts_data *lvts_data)
+{
+ return lvts_data->ops->lvts_temp_to_raw(temperature, lvts_data->temp_factor);
+}
+
+static int lvts_raw_to_temp_mt7988(u32 raw_temp, int temp_factor)
{
int temperature;
@@ -279,7 +320,7 @@ static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
return temperature;
}
-static u32 lvts_temp_to_raw(int temperature, int temp_factor)
+static u32 lvts_temp_to_raw_mt7988(int temperature, int temp_factor)
{
u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14;
@@ -288,6 +329,15 @@ static u32 lvts_temp_to_raw(int temperature, int temp_factor)
return raw_temp;
}
+static u32 lvts_temp_to_raw_mt8196(int temperature, int temp_factor)
+{
+ u32 raw_temp;
+
+ raw_temp = temperature - golden_temp_offset;
+
+ return div_s64((s64)temp_factor << 14, raw_temp);
+}
+
static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
@@ -326,7 +376,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
if (rc)
return -EAGAIN;
- *temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor);
+ *temp = lvts_raw_to_temp(value, lvts_data);
return 0;
}
@@ -396,8 +446,8 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
void __iomem *base = lvts_sensor->base;
u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD,
- lvts_data->temp_factor);
- u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor);
+ lvts_data);
+ u32 raw_high = lvts_temp_to_raw(high, lvts_data);
bool should_update_thresh;
lvts_sensor->low_thresh = low;
@@ -599,6 +649,13 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
LVTS_IMMD3(lvts_ctrl->base)
};
+ void __iomem *atp_regs[] = {
+ LVTS_ATP0(lvts_ctrl->base),
+ LVTS_ATP1(lvts_ctrl->base),
+ LVTS_ATP2(lvts_ctrl->base),
+ LVTS_ATP3(lvts_ctrl->base)
+ };
+
int i;
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
@@ -634,8 +691,20 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
/*
* Each sensor has its own register address to read from.
*/
- lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
- imm_regs[i] : msr_regs[i];
+ switch (lvts_ctrl_data->mode) {
+ case LVTS_MSR_IMMEDIATE_MODE:
+ lvts_sensor[i].msr = imm_regs[i];
+ break;
+ case LVTS_MSR_FILTERED_MODE:
+ lvts_sensor[i].msr = msr_regs[i];
+ break;
+ case LVTS_MSR_ATP_MODE:
+ lvts_sensor[i].msr = atp_regs[i];
+ break;
+ default:
+ lvts_sensor[i].msr = imm_regs[i];
+ break;
+ }
lvts_sensor[i].low_thresh = INT_MIN;
lvts_sensor[i].high_thresh = INT_MIN;
@@ -646,6 +715,26 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
return 0;
}
+static int lvts_decode_sensor_calibration(const struct lvts_sensor_data *sensor,
+ const u8 *efuse_calibration, u32 calib_len,
+ u8 num_offsets, u32 *calib)
+{
+ int i;
+ u32 calib_val = 0;
+
+ for (i = 0; i < num_offsets; i++) {
+ u8 offset = sensor->cal_offsets[i];
+
+ if (offset >= calib_len)
+ return -EINVAL;
+ // Pack each calibration byte into the correct position
+ calib_val |= efuse_calibration[offset] << (8 * i);
+ }
+
+ *calib = calib_val;
+ return 0;
+}
+
/*
* The efuse blob values follows the sensor enumeration per thermal
* controller. The decoding of the stream is as follow:
@@ -702,6 +791,39 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
* <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
* 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
*
+ * MT8196 :
+ * Stream index map for MCU Domain mt8196 :
+ *
+ * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
+ * 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B
+ *
+ * <-sensor#5--> <-sensor#4--> <-sensor#7--> <-sensor#6-->
+ * 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13
+ *
+ * <-sensor#9--> <-sensor#8--> <-sensor#11-> <-sensor#10->
+ * 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0X1B
+ *
+ * <-sensor#13-> <-sensor#12-> <-sensor#15-> <-sensor#14->
+ * 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23
+ *
+ * Stream index map for APU Domain mt8196 :
+ *
+ * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
+ * 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B
+ *
+ * Stream index map for GPU Domain mt8196 :
+ *
+ * <-sensor#1--> <-sensor#0-->
+ * 0x2C | 0x2D | 0x2E | 0x2F
+ *
+ * Stream index map for AP Domain mt8196 :
+ *
+ * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
+ * 0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37
+ *
+ * <-sensor#5--> <-sensor#4--> <-sensor#6--> <-sensor#7-->
+ * 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F
+ *
* Note: In some cases, values don't strictly follow a little endian ordering.
* The data description gives byte offsets constituting each calibration value
* for each sensor.
@@ -711,26 +833,29 @@ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl
u8 *efuse_calibration,
size_t calib_len)
{
- int i;
+ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
+ int i, ret;
u32 gt;
/* A zero value for gt means that device has invalid efuse data */
- gt = (((u32 *)efuse_calibration)[0] >> lvts_ctrl->lvts_data->gt_calib_bit_offset) & 0xff;
+ gt = (((u32 *)efuse_calibration)[0] >> lvts_data->gt_calib_bit_offset) & 0xff;
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
const struct lvts_sensor_data *sensor =
&lvts_ctrl_data->lvts_sensor[i];
+ u32 calib = 0;
- if (sensor->cal_offsets[0] >= calib_len ||
- sensor->cal_offsets[1] >= calib_len ||
- sensor->cal_offsets[2] >= calib_len)
- return -EINVAL;
+ ret = lvts_decode_sensor_calibration(sensor, efuse_calibration,
+ calib_len,
+ lvts_data->num_cal_offsets,
+ &calib);
+ if (ret)
+ return ret;
if (gt) {
- lvts_ctrl->calibration[i] =
- (efuse_calibration[sensor->cal_offsets[0]] << 0) +
- (efuse_calibration[sensor->cal_offsets[1]] << 8) +
- (efuse_calibration[sensor->cal_offsets[2]] << 16);
+ lvts_ctrl->calibration[i] = calib;
+ if (lvts_ctrl->lvts_data->msr_offset)
+ lvts_ctrl->calibration[i] += lvts_ctrl->lvts_data->msr_offset;
} else if (lvts_ctrl->lvts_data->def_calibration) {
lvts_ctrl->calibration[i] = lvts_ctrl->lvts_data->def_calibration;
} else {
@@ -884,7 +1009,7 @@ static void lvts_ctrl_monitor_enable(struct device *dev, struct lvts_ctrl *lvts_
u32 sensor_map = 0;
int i;
- if (lvts_ctrl->mode != LVTS_MSR_FILTERED_MODE)
+ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE)
return;
if (enable) {
@@ -1038,6 +1163,17 @@ static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
for (i = 0; i < LVTS_SENSOR_MAX; i++)
writel(lvts_ctrl->calibration[i], lvts_edata[i]);
+ /* LVTS_MSROFT : Constant offset applied to MSR values
+ * for post-processing
+ *
+ * Bits:
+ *
+ * 20-0 : Constant data added to MSR values
+ */
+ if (lvts_ctrl->lvts_data->msr_offset)
+ writel(lvts_ctrl->lvts_data->msr_offset,
+ LVTS_MSROFT(lvts_ctrl->base));
+
return 0;
}
@@ -1373,6 +1509,20 @@ static void lvts_remove(struct platform_device *pdev)
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
}
+static const struct lvts_ctrl_data mt7987_lvts_ap_data_ctrl[] = {
+ {
+ .lvts_sensor = {
+ { .dt_id = MT7987_CPU,
+ .cal_offsets = { 0x04, 0x05, 0x06 } },
+ { .dt_id = MT7987_ETH2P5G,
+ .cal_offsets = { 0x08, 0x09, 0x0a } },
+ },
+ VALID_SENSOR_MAP(1, 1, 0, 0),
+ .offset = 0x0,
+ .mode = LVTS_MSR_FILTERED_MODE,
+ },
+};
+
static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
{
.lvts_sensor = {
@@ -1455,6 +1605,12 @@ static const u32 default_init_cmds[] = {
0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
};
+static const u32 mt7987_init_cmds[] = {
+ 0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC10308C7,
+ 0xC103098D, 0xC1030C7C, 0xC1030AA8, 0xC10308CE, 0xC10308C7,
+ 0xC1030B04, 0xC1030E01, 0xC10306B8
+};
+
static const u32 mt7988_init_cmds[] = {
0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC,
0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01,
@@ -1753,6 +1909,125 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
}
};
+static const struct lvts_ctrl_data mt8196_lvts_mcu_data_ctrl[] = {
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_MCU_MEDIUM_CPU6_0,
+ .cal_offsets = { 0x06, 0x07 } },
+ { .dt_id = MT8196_MCU_MEDIUM_CPU6_1,
+ .cal_offsets = { 0x04, 0x05 } },
+ { .dt_id = MT8196_MCU_DSU2,
+ .cal_offsets = { 0x0A, 0x0B } },
+ { .dt_id = MT8196_MCU_DSU3,
+ .cal_offsets = { 0x08, 0x09 } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x0,
+ .mode = LVTS_MSR_ATP_MODE,
+ },
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_MCU_LITTLE_CPU3,
+ .cal_offsets = { 0x0E, 0x0F } },
+ { .dt_id = MT8196_MCU_LITTLE_CPU0,
+ .cal_offsets = { 0x0C, 0x0D } },
+ { .dt_id = MT8196_MCU_LITTLE_CPU1,
+ .cal_offsets = { 0x12, 0x13 } },
+ { .dt_id = MT8196_MCU_LITTLE_CPU2,
+ .cal_offsets = { 0x10, 0x11 } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x100,
+ .mode = LVTS_MSR_ATP_MODE,
+ },
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_MCU_MEDIUM_CPU4_0,
+ .cal_offsets = { 0x16, 0x17 } },
+ { .dt_id = MT8196_MCU_MEDIUM_CPU4_1,
+ .cal_offsets = { 0x14, 0x15 } },
+ { .dt_id = MT8196_MCU_MEDIUM_CPU5_0,
+ .cal_offsets = { 0x1A, 0x1B } },
+ { .dt_id = MT8196_MCU_MEDIUM_CPU5_1,
+ .cal_offsets = { 0x18, 0x19 } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x200,
+ .mode = LVTS_MSR_ATP_MODE,
+ },
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_MCU_DSU0,
+ .cal_offsets = { 0x1E, 0x1F } },
+ { .dt_id = MT8196_MCU_DSU1,
+ .cal_offsets = { 0x1C, 0x1D } },
+ { .dt_id = MT8196_MCU_BIG_CPU7_0,
+ .cal_offsets = { 0x22, 0x23 } },
+ { .dt_id = MT8196_MCU_BIG_CPU7_1,
+ .cal_offsets = { 0x20, 0x21 } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x300,
+ .mode = LVTS_MSR_ATP_MODE,
+ }
+};
+
+static const struct lvts_ctrl_data mt8196_lvts_ap_data_ctrl[] = {
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_AP_TOP0,
+ .cal_offsets = { 0x32, 0x33 } },
+ { .dt_id = MT8196_AP_TOP1,
+ .cal_offsets = { 0x30, 0x31 } },
+ { .dt_id = MT8196_AP_TOP2,
+ .cal_offsets = { 0x36, 0x37 } },
+ { .dt_id = MT8196_AP_TOP3,
+ .cal_offsets = { 0x34, 0x35 } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x0,
+ .mode = LVTS_MSR_ATP_MODE,
+ },
+ {
+ .lvts_sensor = {
+ { .dt_id = MT8196_AP_BOT0,
+ .cal_offsets = { 0x3A, 0x3B } },
+ { .dt_id = MT8196_AP_BOT1,
+ .cal_offsets = { 0x38, 0x39 } },
+ { .dt_id = MT8196_AP_BOT2,
+ .cal_offsets = { 0x3E, 0x3F } },
+ { .dt_id = MT8196_AP_BOT3,
+ .cal_offsets = { 0x3C, 0x3D } }
+ },
+ VALID_SENSOR_MAP(1, 1, 1, 1),
+ .offset = 0x100,
+ .mode = LVTS_MSR_ATP_MODE,
+ }
+};
+
+static const struct lvts_platform_ops lvts_platform_ops_mt7988 = {
+ .lvts_raw_to_temp = lvts_raw_to_temp_mt7988,
+ .lvts_temp_to_raw = lvts_temp_to_raw_mt7988,
+};
+
+static const struct lvts_platform_ops lvts_platform_ops_mt8196 = {
+ .lvts_raw_to_temp = lvts_raw_to_temp_mt7988,
+ .lvts_temp_to_raw = lvts_temp_to_raw_mt8196,
+};
+
+static const struct lvts_data mt7987_lvts_ap_data = {
+ .lvts_ctrl = mt7987_lvts_ap_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt7987_lvts_ap_data_ctrl),
+ .conn_cmd = mt7988_conn_cmds,
+ .init_cmd = mt7987_init_cmds,
+ .num_conn_cmd = ARRAY_SIZE(mt7988_conn_cmds),
+ .num_init_cmd = ARRAY_SIZE(mt7987_init_cmds),
+ .temp_factor = LVTS_COEFF_A_MT7987,
+ .temp_offset = LVTS_COEFF_B_MT7987,
+ .gt_calib_bit_offset = 32,
+ .def_calibration = 19380,
+};
+
static const struct lvts_data mt7988_lvts_ap_data = {
.lvts_ctrl = mt7988_lvts_ap_data_ctrl,
.conn_cmd = mt7988_conn_cmds,
@@ -1763,6 +2038,8 @@ static const struct lvts_data mt7988_lvts_ap_data = {
.temp_factor = LVTS_COEFF_A_MT7988,
.temp_offset = LVTS_COEFF_B_MT7988,
.gt_calib_bit_offset = 24,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8186_lvts_data = {
@@ -1776,6 +2053,8 @@ static const struct lvts_data mt8186_lvts_data = {
.temp_offset = LVTS_COEFF_B_MT7988,
.gt_calib_bit_offset = 24,
.def_calibration = 19000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8188_lvts_mcu_data = {
@@ -1789,6 +2068,8 @@ static const struct lvts_data mt8188_lvts_mcu_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 20,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8188_lvts_ap_data = {
@@ -1802,6 +2083,8 @@ static const struct lvts_data mt8188_lvts_ap_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 20,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8192_lvts_mcu_data = {
@@ -1815,6 +2098,8 @@ static const struct lvts_data mt8192_lvts_mcu_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 24,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8192_lvts_ap_data = {
@@ -1828,6 +2113,8 @@ static const struct lvts_data mt8192_lvts_ap_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 24,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8195_lvts_mcu_data = {
@@ -1841,6 +2128,8 @@ static const struct lvts_data mt8195_lvts_mcu_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 24,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
};
static const struct lvts_data mt8195_lvts_ap_data = {
@@ -1854,9 +2143,36 @@ static const struct lvts_data mt8195_lvts_ap_data = {
.temp_offset = LVTS_COEFF_B_MT8195,
.gt_calib_bit_offset = 24,
.def_calibration = 35000,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
+ .ops = &lvts_platform_ops_mt7988,
+};
+
+static const struct lvts_data mt8196_lvts_mcu_data = {
+ .lvts_ctrl = mt8196_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_mcu_data_ctrl),
+ .temp_factor = LVTS_COEFF_A_MT8196,
+ .temp_offset = LVTS_COEFF_B_MT8196,
+ .gt_calib_bit_offset = 0,
+ .def_calibration = 14437,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196,
+ .msr_offset = LVTS_MSR_OFFSET_MT8196,
+ .ops = &lvts_platform_ops_mt8196,
+};
+
+static const struct lvts_data mt8196_lvts_ap_data = {
+ .lvts_ctrl = mt8196_lvts_ap_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_ap_data_ctrl),
+ .temp_factor = LVTS_COEFF_A_MT8196,
+ .temp_offset = LVTS_COEFF_B_MT8196,
+ .gt_calib_bit_offset = 0,
+ .def_calibration = 14437,
+ .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196,
+ .msr_offset = LVTS_MSR_OFFSET_MT8196,
+ .ops = &lvts_platform_ops_mt8196,
};
static const struct of_device_id lvts_of_match[] = {
+ { .compatible = "mediatek,mt7987-lvts-ap", .data = &mt7987_lvts_ap_data },
{ .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
@@ -1865,6 +2181,8 @@ static const struct of_device_id lvts_of_match[] = {
{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
{ .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ { .compatible = "mediatek,mt8196-lvts-mcu", .data = &mt8196_lvts_mcu_data },
+ { .compatible = "mediatek,mt8196-lvts-ap", .data = &mt8196_lvts_ap_data },
{},
};
MODULE_DEVICE_TABLE(of, lvts_of_match);
diff --git a/drivers/thermal/renesas/rzg3e_thermal.c b/drivers/thermal/renesas/rzg3e_thermal.c
index e66d73ca6752..dde021e283b7 100644
--- a/drivers/thermal/renesas/rzg3e_thermal.c
+++ b/drivers/thermal/renesas/rzg3e_thermal.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2025 Renesas Electronics Corporation
*/
+#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
@@ -62,8 +63,6 @@
#define TSU_SICR_CMPCLR BIT(1)
/* Temperature calculation constants from datasheet */
-#define TSU_TEMP_D (-41)
-#define TSU_TEMP_E 126
#define TSU_CODE_MAX 0xFFF
/* Timing specifications from datasheet */
@@ -72,6 +71,18 @@
#define TSU_POLL_DELAY_US 10 /* Polling interval */
#define TSU_MIN_CLOCK_RATE 24000000 /* TSU_PCLK minimum 24MHz */
+#define RZ_SIP_SVC_GET_SYSTSU 0x82000022
+#define OTP_TSU_REG_ADR_TEMPHI 0x01DC
+#define OTP_TSU_REG_ADR_TEMPLO 0x01DD
+
+struct rzg3e_thermal_priv;
+
+struct rzg3e_thermal_info {
+ int (*get_trim)(struct rzg3e_thermal_priv *priv);
+ int temp_d_mc;
+ int temp_e_mc;
+};
+
/**
* struct rzg3e_thermal_priv - RZ/G3E TSU private data
* @base: TSU register base
@@ -79,6 +90,7 @@
* @syscon: regmap for calibration values
* @zone: thermal zone device
* @rstc: reset control
+ * @info: chip type specific information
* @trmval0: calibration value 0 (b)
* @trmval1: calibration value 1 (c)
* @trim_offset: offset for trim registers in syscon
@@ -87,12 +99,11 @@
struct rzg3e_thermal_priv {
void __iomem *base;
struct device *dev;
- struct regmap *syscon;
struct thermal_zone_device *zone;
struct reset_control *rstc;
+ const struct rzg3e_thermal_info *info;
u16 trmval0;
u16 trmval1;
- u32 trim_offset;
struct mutex lock;
};
@@ -161,17 +172,17 @@ static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv)
*/
static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code)
{
- int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE;
- int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE;
+ const struct rzg3e_thermal_info *info = priv->info;
s64 numerator, denominator;
int temp_mc;
- numerator = (temp_e_mc - temp_d_mc) * (s64)(code - priv->trmval0);
+ numerator = (info->temp_e_mc - info->temp_d_mc) *
+ (s64)(code - priv->trmval0);
denominator = priv->trmval1 - priv->trmval0;
- temp_mc = div64_s64(numerator, denominator) + temp_d_mc;
+ temp_mc = div64_s64(numerator, denominator) + info->temp_d_mc;
- return clamp(temp_mc, temp_d_mc, temp_e_mc);
+ return clamp(temp_mc, info->temp_d_mc, info->temp_e_mc);
}
/*
@@ -180,13 +191,12 @@ static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code)
*/
static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_mc)
{
- int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE;
- int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE;
+ const struct rzg3e_thermal_info *info = priv->info;
s64 numerator, denominator;
s64 code;
- numerator = (temp_mc - temp_d_mc) * (priv->trmval1 - priv->trmval0);
- denominator = temp_e_mc - temp_d_mc;
+ numerator = (temp_mc - info->temp_d_mc) * (priv->trmval1 - priv->trmval0);
+ denominator = info->temp_e_mc - info->temp_d_mc;
code = div64_s64(numerator, denominator) + priv->trmval0;
@@ -330,48 +340,45 @@ static const struct thermal_zone_device_ops rzg3e_tz_ops = {
.set_trips = rzg3e_thermal_set_trips,
};
-static int rzg3e_thermal_get_calibration(struct rzg3e_thermal_priv *priv)
+static int rzg3e_thermal_get_syscon_trim(struct rzg3e_thermal_priv *priv)
{
- u32 val;
+ struct device_node *np = priv->dev->of_node;
+ struct regmap *syscon;
+ u32 offset;
int ret;
+ u32 val;
+
+ syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset);
+ if (IS_ERR(syscon))
+ return dev_err_probe(priv->dev, PTR_ERR(syscon),
+ "Failed to parse renesas,tsu-trim\n");
/* Read calibration values from syscon */
- ret = regmap_read(priv->syscon, priv->trim_offset, &val);
+ ret = regmap_read(syscon, offset, &val);
if (ret)
return ret;
- priv->trmval0 = val & GENMASK(11, 0);
+ priv->trmval0 = val & TSU_CODE_MAX;
- ret = regmap_read(priv->syscon, priv->trim_offset + 4, &val);
+ ret = regmap_read(syscon, offset + 4, &val);
if (ret)
return ret;
- priv->trmval1 = val & GENMASK(11, 0);
-
- /* Validate calibration data */
- if (!priv->trmval0 || !priv->trmval1 ||
- priv->trmval0 == priv->trmval1 ||
- priv->trmval0 == 0xFFF || priv->trmval1 == 0xFFF) {
- dev_err(priv->dev, "Invalid calibration: b=0x%03x, c=0x%03x\n",
- priv->trmval0, priv->trmval1);
- return -EINVAL;
- }
-
- dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n",
- priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1);
+ priv->trmval1 = val & TSU_CODE_MAX;
return 0;
}
-static int rzg3e_thermal_parse_dt(struct rzg3e_thermal_priv *priv)
+static int rzg3e_thermal_get_smc_trim(struct rzg3e_thermal_priv *priv)
{
- struct device_node *np = priv->dev->of_node;
- u32 offset;
+ struct arm_smccc_res local_res;
- priv->syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset);
- if (IS_ERR(priv->syscon))
- return dev_err_probe(priv->dev, PTR_ERR(priv->syscon),
- "Failed to parse renesas,tsu-trim\n");
+ arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPLO,
+ 0, 0, 0, 0, 0, 0, &local_res);
+ priv->trmval0 = local_res.a0 & TSU_CODE_MAX;
+
+ arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPHI,
+ 0, 0, 0, 0, 0, 0, &local_res);
+ priv->trmval1 = local_res.a0 & TSU_CODE_MAX;
- priv->trim_offset = offset;
return 0;
}
@@ -392,15 +399,26 @@ static int rzg3e_thermal_probe(struct platform_device *pdev)
return ret;
platform_set_drvdata(pdev, priv);
+ priv->info = device_get_match_data(dev);
+
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- /* Parse device tree for trim register info */
- ret = rzg3e_thermal_parse_dt(priv);
+ ret = priv->info->get_trim(priv);
if (ret)
return ret;
+ if (!priv->trmval0 || !priv->trmval1 ||
+ priv->trmval0 == priv->trmval1 ||
+ priv->trmval0 == TSU_CODE_MAX || priv->trmval1 == TSU_CODE_MAX)
+ return dev_err_probe(priv->dev, -EINVAL,
+ "Invalid calibration: b=0x%03x, c=0x%03x\n",
+ priv->trmval0, priv->trmval1);
+
+ dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n",
+ priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1);
+
/* Get clock to verify frequency - clock is managed by power domain */
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk))
@@ -412,17 +430,11 @@ static int rzg3e_thermal_probe(struct platform_device *pdev)
"Clock rate %lu Hz too low (min %u Hz)\n",
clk_get_rate(clk), TSU_MIN_CLOCK_RATE);
- priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+ priv->rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
if (IS_ERR(priv->rstc))
return dev_err_probe(dev, PTR_ERR(priv->rstc),
"Failed to get/deassert reset control\n");
- /* Get calibration data */
- ret = rzg3e_thermal_get_calibration(priv);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to get valid calibration data\n");
-
/* Get comparison interrupt */
irq = platform_get_irq_byname(pdev, "adcmpi");
if (irq < 0)
@@ -526,8 +538,21 @@ static const struct dev_pm_ops rzg3e_thermal_pm_ops = {
SYSTEM_SLEEP_PM_OPS(rzg3e_thermal_suspend, rzg3e_thermal_resume)
};
+static const struct rzg3e_thermal_info rzg3e_thermal_info = {
+ .get_trim = rzg3e_thermal_get_syscon_trim,
+ .temp_d_mc = -41000,
+ .temp_e_mc = 126000,
+};
+
+static const struct rzg3e_thermal_info rzt2h_thermal_info = {
+ .get_trim = rzg3e_thermal_get_smc_trim,
+ .temp_d_mc = -40000,
+ .temp_e_mc = 125000,
+};
+
static const struct of_device_id rzg3e_thermal_dt_ids[] = {
- { .compatible = "renesas,r9a09g047-tsu" },
+ { .compatible = "renesas,r9a09g047-tsu", .data = &rzg3e_thermal_info },
+ { .compatible = "renesas,r9a09g077-tsu", .data = &rzt2h_thermal_info },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzg3e_thermal_dt_ids);
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 6e90eb9f414d..5d8170bfb382 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
+#include <linux/units.h>
#include "../thermal_hwmon.h"
@@ -76,7 +77,6 @@
/* Constants */
#define ADJUST 100
-#define ONE_MHZ 1000000
#define POLL_TIMEOUT 5000
#define STARTUP_TIME 40
#define TS1_T0_VAL0 30000 /* 30 celsius */
@@ -205,7 +205,7 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
return -EINVAL;
prescaler = 0;
- clk_freq /= ONE_MHZ;
+ clk_freq /= HZ_PER_MHZ;
if (clk_freq) {
while (prescaler <= clk_freq)
prescaler++;
diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
index ddc7302a510a..350f98178b26 100644
--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
@@ -7,6 +7,9 @@
#ifndef __MEDIATEK_LVTS_DT_H
#define __MEDIATEK_LVTS_DT_H
+#define MT7987_CPU 0
+#define MT7987_ETH2P5G 1
+
#define MT7988_CPU_0 0
#define MT7988_CPU_1 1
#define MT7988_ETH2P5G_0 2
@@ -80,4 +83,30 @@
#define MT8192_AP_MD1 15
#define MT8192_AP_MD2 16
+#define MT8196_MCU_MEDIUM_CPU6_0 0
+#define MT8196_MCU_MEDIUM_CPU6_1 1
+#define MT8196_MCU_DSU2 2
+#define MT8196_MCU_DSU3 3
+#define MT8196_MCU_LITTLE_CPU3 4
+#define MT8196_MCU_LITTLE_CPU0 5
+#define MT8196_MCU_LITTLE_CPU1 6
+#define MT8196_MCU_LITTLE_CPU2 7
+#define MT8196_MCU_MEDIUM_CPU4_0 8
+#define MT8196_MCU_MEDIUM_CPU4_1 9
+#define MT8196_MCU_MEDIUM_CPU5_0 10
+#define MT8196_MCU_MEDIUM_CPU5_1 11
+#define MT8196_MCU_DSU0 12
+#define MT8196_MCU_DSU1 13
+#define MT8196_MCU_BIG_CPU7_0 14
+#define MT8196_MCU_BIG_CPU7_1 15
+
+#define MT8196_AP_TOP0 0
+#define MT8196_AP_TOP1 1
+#define MT8196_AP_TOP2 2
+#define MT8196_AP_TOP3 3
+#define MT8196_AP_BOT0 4
+#define MT8196_AP_BOT1 5
+#define MT8196_AP_BOT2 6
+#define MT8196_AP_BOT3 7
+
#endif /* __MEDIATEK_LVTS_DT_H */
diff --git a/tools/lib/thermal/libthermal.pc.template b/tools/lib/thermal/libthermal.pc.template
index ac24d0ab17f5..3b8a24d0a8b8 100644
--- a/tools/lib/thermal/libthermal.pc.template
+++ b/tools/lib/thermal/libthermal.pc.template
@@ -8,5 +8,5 @@ Name: libthermal
Description: thermal library
Requires: libnl-3.0 libnl-genl-3.0
Version: @VERSION@
-Libs: -L${libdir} -lnl-genl-3 -lnl-3
-Cflags: -I${includedir} -I${include}/libnl3
+Libs: -L${libdir} -lnl-genl-3 -lnl-3 -lthermal
+Cflags: -I${includedir} -I${includedir}/libnl3