clock-output-names = "clkxtal";
};
+ fan: pwm-fan {
+ compatible = "pwm-fan";
+ /* cooling level (0, 1, 2) : (0% duty, 50% duty, 100% duty) */
+ cooling-levels = <0 128 255>;
+ #cooling-cells = <2>;
+ #thermal-sensor-cells = <1>;
+ status = "disabled";
+ };
+
pmu {
compatible = "arm,cortex-a73-pmu";
interrupt-parent = <&gic>;
status = "disabled";
};
- fan: pwm-fan {
- compatible = "pwm-fan";
- /* cooling level (0, 1, 2) : (0% duty, 50% duty, 100% duty) */
- cooling-levels = <0 128 255>;
- #cooling-cells = <2>;
- #thermal-sensor-cells = <1>;
- status = "disabled";
- };
-
lvts: lvts@1100a000 {
- compatible = "mediatek,mt7988-lvts";
+ compatible = "mediatek,mt7988-lvts-ap";
reg = <0 0x1100a000 0 0x1000>;
clocks = <&infracfg CLK_INFRA_26M_THERM_SYSTEM>;
clock-names = "lvts_clk";
+ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&infracfg MT7988_INFRA_RST1_THERM_CTRL_SWRST>;
nvmem-cells = <&lvts_calibration>;
- nvmem-cell-names = "e_data1";
+ nvmem-cell-names = "lvts-calib-data-1";
#thermal-sensor-cells = <1>;
};
CONFIG_MTK_SCPSYS_PM_DOMAINS=y
# CONFIG_MTK_SVS is not set
CONFIG_MTK_THERMAL=y
+CONFIG_MTK_SOC_THERMAL=y
+CONFIG_MTK_LVTS_THERMAL=y
+CONFIG_MTK_LVTS_THERMAL_DEBUGFS=y
CONFIG_MTK_TIMER=y
# CONFIG_MTK_UART_APDMA is not set
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_MTK_SCPSYS_PM_DOMAINS=y
# CONFIG_MTK_SVS is not set
CONFIG_MTK_THERMAL=y
+CONFIG_MTK_SOC_THERMAL=y
+# CONFIG_MTK_LVTS_THERMAL is not set
CONFIG_MTK_TIMER=y
# CONFIG_MTK_UART_APDMA is not set
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_MTK_SMI=y
# CONFIG_MTK_SVS is not set
CONFIG_MTK_THERMAL=y
+CONFIG_MTK_SOC_THERMAL=y
+# CONFIG_MTK_LVTS_THERMAL is not set
CONFIG_MTK_TIMER=y
# CONFIG_MTK_UART_APDMA is not set
# CONFIG_MUSB_PIO_ONLY is not set
+++ /dev/null
-From 69c17529e8418da3eec703dde31e1b01e5b0f7e8 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Wed, 18 Jan 2023 02:48:41 +0000
-Subject: [PATCH 1/2] thermal/drivers/mtk: use function pointer for
- raw_to_mcelsius
-
-Instead of having if-else logic selecting either raw_to_mcelsius_v1 or
-raw_to_mcelsius_v2 in mtk_thermal_bank_temperature introduce a function
-pointer raw_to_mcelsius to struct mtk_thermal which is initialized in the
-probe function.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/thermal/mtk_thermal.c | 17 ++++++++++-------
- 1 file changed, 10 insertions(+), 7 deletions(-)
-
---- a/drivers/thermal/mtk_thermal.c
-+++ b/drivers/thermal/mtk_thermal.c
-@@ -292,6 +292,8 @@ struct mtk_thermal {
-
- const struct mtk_thermal_data *conf;
- struct mtk_thermal_bank banks[MAX_NUM_ZONES];
-+
-+ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
- };
-
- /* MT8183 thermal sensor data */
-@@ -656,13 +658,9 @@ static int mtk_thermal_bank_temperature(
- for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
- raw = readl(mt->thermal_base + conf->msr[i]);
-
-- if (mt->conf->version == MTK_THERMAL_V1) {
-- temp = raw_to_mcelsius_v1(
-- mt, conf->bank_data[bank->id].sensors[i], raw);
-- } else {
-- temp = raw_to_mcelsius_v2(
-- mt, conf->bank_data[bank->id].sensors[i], raw);
-- }
-+ temp = mt->raw_to_mcelsius(
-+ mt, conf->bank_data[bank->id].sensors[i], raw);
-+
-
- /*
- * The first read of a sensor often contains very high bogus
-@@ -1075,6 +1073,11 @@ static int mtk_thermal_probe(struct plat
- mtk_thermal_release_periodic_ts(mt, auxadc_base);
- }
-
-+ if (mt->conf->version == MTK_THERMAL_V1)
-+ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
-+ else
-+ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
-+
- for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
- for (i = 0; i < mt->conf->num_banks; i++)
- mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+++ /dev/null
-From aa957c759b1182aee00cc35178667f849f941b42 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Wed, 30 Nov 2022 13:19:39 +0000
-Subject: [PATCH 2/2] thermal: mediatek: add support for MT7986 and MT7981
-
-Add support for V3 generation thermal found in MT7986 and MT7981 SoCs.
-Brings code to assign values from efuse as well as new function to
-convert raw temperature to millidegree celsius, as found in MediaTek's
-SDK sources (but cleaned up and de-duplicated)
-
-[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/baf36c7eef477aae1f8f2653b6c29e2caf48475b
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/thermal/mtk_thermal.c | 137 ++++++++++++++++++++++++++++++++--
- 1 file changed, 132 insertions(+), 5 deletions(-)
-
---- a/drivers/thermal/mtk_thermal.c
-+++ b/drivers/thermal/mtk_thermal.c
-@@ -150,6 +150,20 @@
- #define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
- #define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
-
-+/*
-+ * Layout of the fuses providing the calibration data
-+ * These macros can be used for MT7981 and MT7986.
-+ */
-+#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
-+#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
-+#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
-+#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
-+#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
-+#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
-+#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
-+#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
-+#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
-+
- enum {
- VTS1,
- VTS2,
-@@ -163,6 +177,7 @@ enum {
- enum mtk_thermal_version {
- MTK_THERMAL_V1 = 1,
- MTK_THERMAL_V2,
-+ MTK_THERMAL_V3,
- };
-
- /* MT2701 thermal sensors */
-@@ -245,6 +260,27 @@ enum mtk_thermal_version {
- /* The calibration coefficient of sensor */
- #define MT8183_CALIBRATION 153
-
-+/* AUXADC channel 11 is used for the temperature sensors */
-+#define MT7986_TEMP_AUXADC_CHANNEL 11
-+
-+/* The total number of temperature sensors in the MT7986 */
-+#define MT7986_NUM_SENSORS 1
-+
-+/* The number of banks in the MT7986 */
-+#define MT7986_NUM_ZONES 1
-+
-+/* The number of sensing points per bank */
-+#define MT7986_NUM_SENSORS_PER_ZONE 1
-+
-+/* MT7986 thermal sensors */
-+#define MT7986_TS1 0
-+
-+/* The number of controller in the MT7986 */
-+#define MT7986_NUM_CONTROLLER 1
-+
-+/* The calibration coefficient of sensor */
-+#define MT7986_CALIBRATION 165
-+
- struct mtk_thermal;
-
- struct thermal_bank_cfg {
-@@ -388,6 +424,14 @@ static const int mt7622_mux_values[MT762
- static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
- static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
-
-+/* MT7986 thermal sensor data */
-+static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
-+static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
-+static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
-+static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
-+static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
-+static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
-+
- /*
- * The MT8173 thermal controller has four banks. Each bank can read up to
- * four temperature sensors simultaneously. The MT8173 has a total of 5
-@@ -551,6 +595,30 @@ static const struct mtk_thermal_data mt8
- .version = MTK_THERMAL_V1,
- };
-
-+/*
-+ * MT7986 uses AUXADC Channel 11 for raw data access.
-+ */
-+static const struct mtk_thermal_data mt7986_thermal_data = {
-+ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
-+ .num_banks = MT7986_NUM_ZONES,
-+ .num_sensors = MT7986_NUM_SENSORS,
-+ .vts_index = mt7986_vts_index,
-+ .cali_val = MT7986_CALIBRATION,
-+ .num_controller = MT7986_NUM_CONTROLLER,
-+ .controller_offset = mt7986_tc_offset,
-+ .need_switch_bank = true,
-+ .bank_data = {
-+ {
-+ .num_sensors = 1,
-+ .sensors = mt7986_bank_data,
-+ },
-+ },
-+ .msr = mt7986_msr,
-+ .adcpnp = mt7986_adcpnp,
-+ .sensor_mux_values = mt7986_mux_values,
-+ .version = MTK_THERMAL_V3,
-+};
-+
- /**
- * raw_to_mcelsius - convert a raw ADC value to mcelsius
- * @mt: The thermal controller
-@@ -605,6 +673,22 @@ static int raw_to_mcelsius_v2(struct mtk
- return (format_2 - tmp) * 100;
- }
-
-+static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
-+{
-+ s32 tmp;
-+
-+ if (raw == 0)
-+ return 0;
-+
-+ raw &= 0xfff;
-+ tmp = 100000 * 15 / 16 * 10000;
-+ tmp /= 4096 - 512 + mt->adc_ge;
-+ tmp /= 1490;
-+ tmp *= raw - mt->vts[sensno] - 2900;
-+
-+ return mt->degc_cali * 500 - tmp;
-+}
-+
- /**
- * mtk_thermal_get_bank - get bank
- * @bank: The bank
-@@ -885,6 +969,25 @@ static int mtk_thermal_extract_efuse_v2(
- return 0;
- }
-
-+static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
-+{
-+ if (!CALIB_BUF1_VALID_V3(buf[1]))
-+ return -EINVAL;
-+
-+ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
-+ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
-+ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
-+ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
-+ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
-+ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
-+ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
-+
-+ if (CALIB_BUF1_ID_V3(buf[1]) == 0)
-+ mt->o_slope = 0;
-+
-+ return 0;
-+}
-+
- static int mtk_thermal_get_calibration_data(struct device *dev,
- struct mtk_thermal *mt)
- {
-@@ -895,6 +998,7 @@ static int mtk_thermal_get_calibration_d
-
- /* Start with default values */
- mt->adc_ge = 512;
-+ mt->adc_oe = 512;
- for (i = 0; i < mt->conf->num_sensors; i++)
- mt->vts[i] = 260;
- mt->degc_cali = 40;
-@@ -920,10 +1024,20 @@ static int mtk_thermal_get_calibration_d
- goto out;
- }
-
-- if (mt->conf->version == MTK_THERMAL_V1)
-+ switch (mt->conf->version) {
-+ case MTK_THERMAL_V1:
- ret = mtk_thermal_extract_efuse_v1(mt, buf);
-- else
-+ break;
-+ case MTK_THERMAL_V2:
- ret = mtk_thermal_extract_efuse_v2(mt, buf);
-+ break;
-+ case MTK_THERMAL_V3:
-+ ret = mtk_thermal_extract_efuse_v3(mt, buf);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-
- if (ret) {
- dev_info(dev, "Device not calibrated, using default calibration values\n");
-@@ -954,6 +1068,10 @@ static const struct of_device_id mtk_the
- .data = (void *)&mt7622_thermal_data,
- },
- {
-+ .compatible = "mediatek,mt7986-thermal",
-+ .data = (void *)&mt7986_thermal_data,
-+ },
-+ {
- .compatible = "mediatek,mt8183-thermal",
- .data = (void *)&mt8183_thermal_data,
- }, {
-@@ -1068,15 +1186,24 @@ static int mtk_thermal_probe(struct plat
- goto err_disable_clk_auxadc;
- }
-
-- if (mt->conf->version == MTK_THERMAL_V2) {
-+ if (mt->conf->version != MTK_THERMAL_V1) {
- mtk_thermal_turn_on_buffer(apmixed_base);
- mtk_thermal_release_periodic_ts(mt, auxadc_base);
- }
-
-- if (mt->conf->version == MTK_THERMAL_V1)
-+ switch (mt->conf->version) {
-+ case MTK_THERMAL_V1:
- mt->raw_to_mcelsius = raw_to_mcelsius_v1;
-- else
-+ break;
-+ case MTK_THERMAL_V2:
- mt->raw_to_mcelsius = raw_to_mcelsius_v2;
-+ break;
-+ case MTK_THERMAL_V3:
-+ mt->raw_to_mcelsius = raw_to_mcelsius_v3;
-+ break;
-+ default:
-+ break;
-+ }
-
- for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
- for (i = 0; i < mt->conf->num_banks; i++)
--- /dev/null
+From f167da186acf90847e1a6d3716e253825a6218ec Mon Sep 17 00:00:00 2001
+From: Randy Dunlap <rdunlap@infradead.org>
+Date: Thu, 12 Jan 2023 22:44:49 -0800
+Subject: [PATCH 01/42] thermal/drivers/mtk_thermal: Fix kernel-doc function
+ name
+
+Use the correct function name in a kernel-doc comment to prevent
+a warning:
+
+drivers/thermal/mtk_thermal.c:562: warning: expecting prototype for raw_to_mcelsius(). Prototype was for raw_to_mcelsius_v1() instead
+
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Cc: "Rafael J. Wysocki" <rafael@kernel.org>
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Amit Kucheria <amitk@kernel.org>
+Cc: Zhang Rui <rui.zhang@intel.com>
+Cc: Matthias Brugger <matthias.bgg@gmail.com>
+Cc: linux-pm@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-mediatek@lists.infradead.org
+Link: https://lore.kernel.org/r/20230113064449.15061-1-rdunlap@infradead.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -550,7 +550,7 @@ static const struct mtk_thermal_data mt8
+ };
+
+ /**
+- * raw_to_mcelsius - convert a raw ADC value to mcelsius
++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+ * @sensno: sensor number
+ * @raw: raw ADC value
--- /dev/null
+From 255509232417ee71fd606cb957d44cf6544f0c43 Mon Sep 17 00:00:00 2001
+From: ye xingchen <ye.xingchen@zte.com.cn>
+Date: Wed, 18 Jan 2023 16:37:47 +0800
+Subject: [PATCH 02/42] thermal/drivers/mtk_thermal: Use
+ devm_platform_get_and_ioremap_resource()
+
+Convert platform_get_resource(), devm_ioremap_resource() to a single
+call to devm_platform_get_and_ioremap_resource(), as this is exactly
+what this function does.
+
+Signed-off-by: ye xingchen <ye.xingchen@zte.com.cn>
+Link: https://lore.kernel.org/r/202301181637472073620@zte.com.cn
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -990,7 +990,6 @@ static int mtk_thermal_probe(struct plat
+ int ret, i, ctrl_id;
+ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
+ struct mtk_thermal *mt;
+- struct resource *res;
+ u64 auxadc_phys_base, apmixed_phys_base;
+ struct thermal_zone_device *tzdev;
+ void __iomem *apmixed_base, *auxadc_base;
+@@ -1009,8 +1008,7 @@ static int mtk_thermal_probe(struct plat
+ if (IS_ERR(mt->clk_auxadc))
+ return PTR_ERR(mt->clk_auxadc);
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- mt->thermal_base = devm_ioremap_resource(&pdev->dev, res);
++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(mt->thermal_base))
+ return PTR_ERR(mt->thermal_base);
+
--- /dev/null
+From ca86dbd309ba03bef38ae91f037e2030bb671ab7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 18 Jan 2023 15:40:39 +0000
+Subject: [PATCH 03/42] thermal/drivers/mtk: Use function pointer for
+ raw_to_mcelsius
+
+Instead of having if-else logic selecting either raw_to_mcelsius_v1 or
+raw_to_mcelsius_v2 in mtk_thermal_bank_temperature introduce a function
+pointer raw_to_mcelsius to struct mtk_thermal which is initialized in the
+probe function.
+
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Link: https://lore.kernel.org/r/69c17529e8418da3eec703dde31e1b01e5b0f7e8.1674055882.git.daniel@makrotopia.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -292,6 +292,8 @@ struct mtk_thermal {
+
+ const struct mtk_thermal_data *conf;
+ struct mtk_thermal_bank banks[MAX_NUM_ZONES];
++
++ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
+ };
+
+ /* MT8183 thermal sensor data */
+@@ -656,13 +658,9 @@ static int mtk_thermal_bank_temperature(
+ for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+ raw = readl(mt->thermal_base + conf->msr[i]);
+
+- if (mt->conf->version == MTK_THERMAL_V1) {
+- temp = raw_to_mcelsius_v1(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+- } else {
+- temp = raw_to_mcelsius_v2(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+- }
++ temp = mt->raw_to_mcelsius(
++ mt, conf->bank_data[bank->id].sensors[i], raw);
++
+
+ /*
+ * The first read of a sensor often contains very high bogus
+@@ -1073,6 +1071,11 @@ static int mtk_thermal_probe(struct plat
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+ }
+
++ if (mt->conf->version == MTK_THERMAL_V1)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++
+ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+ for (i = 0; i < mt->conf->num_banks; i++)
+ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
--- /dev/null
+From aec1d89dccc7cba04fdb3e52dfda328f3302ba17 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 18 Jan 2023 15:40:58 +0000
+Subject: [PATCH 04/42] thermal/drivers/mtk: Add support for MT7986 and MT7981
+
+Add support for V3 generation thermal found in MT7986 and MT7981 SoCs.
+Brings code to assign values from efuse as well as new function to
+convert raw temperature to millidegree celsius, as found in MediaTek's
+SDK sources (but cleaned up and de-duplicated)
+
+[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/baf36c7eef477aae1f8f2653b6c29e2caf48475b
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/2d341fc45266217249586eb4bd3be3ac4ca83a12.1674055882.git.daniel@makrotopia.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 128 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 124 insertions(+), 4 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -150,6 +150,20 @@
+ #define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
+ #define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
+
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros can be used for MT7981 and MT7986.
++ */
++#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
++#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
++#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
++
+ enum {
+ VTS1,
+ VTS2,
+@@ -163,6 +177,7 @@ enum {
+ enum mtk_thermal_version {
+ MTK_THERMAL_V1 = 1,
+ MTK_THERMAL_V2,
++ MTK_THERMAL_V3,
+ };
+
+ /* MT2701 thermal sensors */
+@@ -245,6 +260,27 @@ enum mtk_thermal_version {
+ /* The calibration coefficient of sensor */
+ #define MT8183_CALIBRATION 153
+
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT7986_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT7986 */
++#define MT7986_NUM_SENSORS 1
++
++/* The number of banks in the MT7986 */
++#define MT7986_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT7986_NUM_SENSORS_PER_ZONE 1
++
++/* MT7986 thermal sensors */
++#define MT7986_TS1 0
++
++/* The number of controller in the MT7986 */
++#define MT7986_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT7986_CALIBRATION 165
++
+ struct mtk_thermal;
+
+ struct thermal_bank_cfg {
+@@ -388,6 +424,14 @@ static const int mt7622_mux_values[MT762
+ static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
+ static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
+
++/* MT7986 thermal sensor data */
++static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
++static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
++static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
++static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
++
+ /*
+ * The MT8173 thermal controller has four banks. Each bank can read up to
+ * four temperature sensors simultaneously. The MT8173 has a total of 5
+@@ -551,6 +595,30 @@ static const struct mtk_thermal_data mt8
+ .version = MTK_THERMAL_V1,
+ };
+
++/*
++ * MT7986 uses AUXADC Channel 11 for raw data access.
++ */
++static const struct mtk_thermal_data mt7986_thermal_data = {
++ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7986_NUM_ZONES,
++ .num_sensors = MT7986_NUM_SENSORS,
++ .vts_index = mt7986_vts_index,
++ .cali_val = MT7986_CALIBRATION,
++ .num_controller = MT7986_NUM_CONTROLLER,
++ .controller_offset = mt7986_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7986_bank_data,
++ },
++ },
++ .msr = mt7986_msr,
++ .adcpnp = mt7986_adcpnp,
++ .sensor_mux_values = mt7986_mux_values,
++ .version = MTK_THERMAL_V3,
++};
++
+ /**
+ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+@@ -605,6 +673,22 @@ static int raw_to_mcelsius_v2(struct mtk
+ return (format_2 - tmp) * 100;
+ }
+
++static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ tmp = 100000 * 15 / 16 * 10000;
++ tmp /= 4096 - 512 + mt->adc_ge;
++ tmp /= 1490;
++ tmp *= raw - mt->vts[sensno] - 2900;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
+ /**
+ * mtk_thermal_get_bank - get bank
+ * @bank: The bank
+@@ -885,6 +969,25 @@ static int mtk_thermal_extract_efuse_v2(
+ return 0;
+ }
+
++static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V3(buf[1]))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
++
++ if (CALIB_BUF1_ID_V3(buf[1]) == 0)
++ mt->o_slope = 0;
++
++ return 0;
++}
++
+ static int mtk_thermal_get_calibration_data(struct device *dev,
+ struct mtk_thermal *mt)
+ {
+@@ -895,6 +998,7 @@ static int mtk_thermal_get_calibration_d
+
+ /* Start with default values */
+ mt->adc_ge = 512;
++ mt->adc_oe = 512;
+ for (i = 0; i < mt->conf->num_sensors; i++)
+ mt->vts[i] = 260;
+ mt->degc_cali = 40;
+@@ -920,10 +1024,20 @@ static int mtk_thermal_get_calibration_d
+ goto out;
+ }
+
+- if (mt->conf->version == MTK_THERMAL_V1)
++ switch (mt->conf->version) {
++ case MTK_THERMAL_V1:
+ ret = mtk_thermal_extract_efuse_v1(mt, buf);
+- else
++ break;
++ case MTK_THERMAL_V2:
+ ret = mtk_thermal_extract_efuse_v2(mt, buf);
++ break;
++ case MTK_THERMAL_V3:
++ ret = mtk_thermal_extract_efuse_v3(mt, buf);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
+
+ if (ret) {
+ dev_info(dev, "Device not calibrated, using default calibration values\n");
+@@ -954,6 +1068,10 @@ static const struct of_device_id mtk_the
+ .data = (void *)&mt7622_thermal_data,
+ },
+ {
++ .compatible = "mediatek,mt7986-thermal",
++ .data = (void *)&mt7986_thermal_data,
++ },
++ {
+ .compatible = "mediatek,mt8183-thermal",
+ .data = (void *)&mt8183_thermal_data,
+ }, {
+@@ -1066,15 +1184,17 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_auxadc;
+ }
+
+- if (mt->conf->version == MTK_THERMAL_V2) {
++ if (mt->conf->version != MTK_THERMAL_V1) {
+ mtk_thermal_turn_on_buffer(apmixed_base);
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+ }
+
+ if (mt->conf->version == MTK_THERMAL_V1)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
+- else
++ else if (mt->conf->version == MTK_THERMAL_V2)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v3;
+
+ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+ for (i = 0; i < mt->conf->num_banks; i++)
--- /dev/null
+From 5e3aac197a74914ccec2732a89c29d960730d28f Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:23 +0100
+Subject: [PATCH 05/42] thermal/drivers/mediatek: Relocate driver to mediatek
+ folder
+
+Add MediaTek proprietary folder to upstream more thermal zone and cooler
+drivers, relocate the original thermal controller driver to it, and rename it
+as "auxadc_thermal.c" to show its purpose more clearly.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230209105628.50294-2-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/Kconfig | 14 ++++---------
+ drivers/thermal/Makefile | 2 +-
+ drivers/thermal/mediatek/Kconfig | 21 +++++++++++++++++++
+ drivers/thermal/mediatek/Makefile | 1 +
+ .../auxadc_thermal.c} | 2 +-
+ 5 files changed, 28 insertions(+), 12 deletions(-)
+ create mode 100644 drivers/thermal/mediatek/Kconfig
+ create mode 100644 drivers/thermal/mediatek/Makefile
+ rename drivers/thermal/{mtk_thermal.c => mediatek/auxadc_thermal.c} (99%)
+
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -412,16 +412,10 @@ config DA9062_THERMAL
+ zone.
+ Compatible with the DA9062 and DA9061 PMICs.
+
+-config MTK_THERMAL
+- tristate "Temperature sensor driver for mediatek SoCs"
+- depends on ARCH_MEDIATEK || COMPILE_TEST
+- depends on HAS_IOMEM
+- depends on NVMEM || NVMEM=n
+- depends on RESET_CONTROLLER
+- default y
+- help
+- Enable this option if you want to have support for thermal management
+- controller present in Mediatek SoCs
++menu "Mediatek thermal drivers"
++depends on ARCH_MEDIATEK || COMPILE_TEST
++source "drivers/thermal/mediatek/Kconfig"
++endmenu
+
+ config AMLOGIC_THERMAL
+ tristate "Amlogic Thermal Support"
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -55,7 +55,7 @@ obj-y += st/
+ obj-y += qcom/
+ obj-y += tegra/
+ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
+-obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
++obj-y += mediatek/
+ obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+ obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
+ obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
+--- /dev/null
++++ b/drivers/thermal/mediatek/Kconfig
+@@ -0,0 +1,21 @@
++config MTK_THERMAL
++ tristate "MediaTek thermal drivers"
++ depends on THERMAL_OF
++ help
++ This is the option for MediaTek thermal software solutions.
++ Please enable corresponding options to get temperature
++ information from thermal sensors or turn on throttle
++ mechaisms for thermal mitigation.
++
++if MTK_THERMAL
++
++config MTK_SOC_THERMAL
++ tristate "AUXADC temperature sensor driver for MediaTek SoCs"
++ depends on HAS_IOMEM
++ help
++ Enable this option if you want to get SoC temperature
++ information for MediaTek platforms.
++ This driver configures thermal controllers to collect
++ temperature via AUXADC interface.
++
++endif
+--- /dev/null
++++ b/drivers/thermal/mediatek/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o
+--- a/drivers/thermal/mtk_thermal.c
++++ /dev/null
+@@ -1,1254 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2015 MediaTek Inc.
+- * Author: Hanyi Wu <hanyi.wu@mediatek.com>
+- * Sascha Hauer <s.hauer@pengutronix.de>
+- * Dawei Chien <dawei.chien@mediatek.com>
+- * Louis Yu <louis.yu@mediatek.com>
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+-#include <linux/thermal.h>
+-#include <linux/reset.h>
+-#include <linux/types.h>
+-
+-#include "thermal_hwmon.h"
+-
+-/* AUXADC Registers */
+-#define AUXADC_CON1_SET_V 0x008
+-#define AUXADC_CON1_CLR_V 0x00c
+-#define AUXADC_CON2_V 0x010
+-#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
+-
+-#define APMIXED_SYS_TS_CON1 0x604
+-
+-/* Thermal Controller Registers */
+-#define TEMP_MONCTL0 0x000
+-#define TEMP_MONCTL1 0x004
+-#define TEMP_MONCTL2 0x008
+-#define TEMP_MONIDET0 0x014
+-#define TEMP_MONIDET1 0x018
+-#define TEMP_MSRCTL0 0x038
+-#define TEMP_MSRCTL1 0x03c
+-#define TEMP_AHBPOLL 0x040
+-#define TEMP_AHBTO 0x044
+-#define TEMP_ADCPNP0 0x048
+-#define TEMP_ADCPNP1 0x04c
+-#define TEMP_ADCPNP2 0x050
+-#define TEMP_ADCPNP3 0x0b4
+-
+-#define TEMP_ADCMUX 0x054
+-#define TEMP_ADCEN 0x060
+-#define TEMP_PNPMUXADDR 0x064
+-#define TEMP_ADCMUXADDR 0x068
+-#define TEMP_ADCENADDR 0x074
+-#define TEMP_ADCVALIDADDR 0x078
+-#define TEMP_ADCVOLTADDR 0x07c
+-#define TEMP_RDCTRL 0x080
+-#define TEMP_ADCVALIDMASK 0x084
+-#define TEMP_ADCVOLTAGESHIFT 0x088
+-#define TEMP_ADCWRITECTRL 0x08c
+-#define TEMP_MSR0 0x090
+-#define TEMP_MSR1 0x094
+-#define TEMP_MSR2 0x098
+-#define TEMP_MSR3 0x0B8
+-
+-#define TEMP_SPARE0 0x0f0
+-
+-#define TEMP_ADCPNP0_1 0x148
+-#define TEMP_ADCPNP1_1 0x14c
+-#define TEMP_ADCPNP2_1 0x150
+-#define TEMP_MSR0_1 0x190
+-#define TEMP_MSR1_1 0x194
+-#define TEMP_MSR2_1 0x198
+-#define TEMP_ADCPNP3_1 0x1b4
+-#define TEMP_MSR3_1 0x1B8
+-
+-#define PTPCORESEL 0x400
+-
+-#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)
+-
+-#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)
+-#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)
+-
+-#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)
+-
+-#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)
+-#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)
+-
+-#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)
+-#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)
+-
+-/* MT8173 thermal sensors */
+-#define MT8173_TS1 0
+-#define MT8173_TS2 1
+-#define MT8173_TS3 2
+-#define MT8173_TS4 3
+-#define MT8173_TSABB 4
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT8173_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT8173 */
+-#define MT8173_NUM_SENSORS 5
+-
+-/* The number of banks in the MT8173 */
+-#define MT8173_NUM_ZONES 4
+-
+-/* The number of sensing points per bank */
+-#define MT8173_NUM_SENSORS_PER_ZONE 4
+-
+-/* The number of controller in the MT8173 */
+-#define MT8173_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT8173_CALIBRATION 165
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
+- * MT8183 has 6 sensors and needs 6 VTS calibration data.
+- * MT8173 has 5 sensors and needs 5 VTS calibration data.
+- * MT2701 has 3 sensors and needs 3 VTS calibration data.
+- * MT2712 has 4 sensors and needs 4 VTS calibration data.
+- */
+-#define CALIB_BUF0_VALID_V1 BIT(0)
+-#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff)
+-#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff)
+-#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff)
+-#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff)
+-#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff)
+-#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff)
+-#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1)
+-#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1)
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros could be used for MT7622.
+- */
+-#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff)
+-#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff)
+-#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f)
+-#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff)
+-#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff)
+-#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
+-#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros can be used for MT7981 and MT7986.
+- */
+-#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
+-#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
+-#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
+-#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
+-#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
+-#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
+-#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
+-
+-enum {
+- VTS1,
+- VTS2,
+- VTS3,
+- VTS4,
+- VTS5,
+- VTSABB,
+- MAX_NUM_VTS,
+-};
+-
+-enum mtk_thermal_version {
+- MTK_THERMAL_V1 = 1,
+- MTK_THERMAL_V2,
+- MTK_THERMAL_V3,
+-};
+-
+-/* MT2701 thermal sensors */
+-#define MT2701_TS1 0
+-#define MT2701_TS2 1
+-#define MT2701_TSABB 2
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT2701_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT2701 */
+-#define MT2701_NUM_SENSORS 3
+-
+-/* The number of sensing points per bank */
+-#define MT2701_NUM_SENSORS_PER_ZONE 3
+-
+-/* The number of controller in the MT2701 */
+-#define MT2701_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT2701_CALIBRATION 165
+-
+-/* MT2712 thermal sensors */
+-#define MT2712_TS1 0
+-#define MT2712_TS2 1
+-#define MT2712_TS3 2
+-#define MT2712_TS4 3
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT2712_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT2712 */
+-#define MT2712_NUM_SENSORS 4
+-
+-/* The number of sensing points per bank */
+-#define MT2712_NUM_SENSORS_PER_ZONE 4
+-
+-/* The number of controller in the MT2712 */
+-#define MT2712_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT2712_CALIBRATION 165
+-
+-#define MT7622_TEMP_AUXADC_CHANNEL 11
+-#define MT7622_NUM_SENSORS 1
+-#define MT7622_NUM_ZONES 1
+-#define MT7622_NUM_SENSORS_PER_ZONE 1
+-#define MT7622_TS1 0
+-#define MT7622_NUM_CONTROLLER 1
+-
+-/* The maximum number of banks */
+-#define MAX_NUM_ZONES 8
+-
+-/* The calibration coefficient of sensor */
+-#define MT7622_CALIBRATION 165
+-
+-/* MT8183 thermal sensors */
+-#define MT8183_TS1 0
+-#define MT8183_TS2 1
+-#define MT8183_TS3 2
+-#define MT8183_TS4 3
+-#define MT8183_TS5 4
+-#define MT8183_TSABB 5
+-
+-/* AUXADC channel is used for the temperature sensors */
+-#define MT8183_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT8183 */
+-#define MT8183_NUM_SENSORS 6
+-
+-/* The number of banks in the MT8183 */
+-#define MT8183_NUM_ZONES 1
+-
+-/* The number of sensing points per bank */
+-#define MT8183_NUM_SENSORS_PER_ZONE 6
+-
+-/* The number of controller in the MT8183 */
+-#define MT8183_NUM_CONTROLLER 2
+-
+-/* The calibration coefficient of sensor */
+-#define MT8183_CALIBRATION 153
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT7986_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT7986 */
+-#define MT7986_NUM_SENSORS 1
+-
+-/* The number of banks in the MT7986 */
+-#define MT7986_NUM_ZONES 1
+-
+-/* The number of sensing points per bank */
+-#define MT7986_NUM_SENSORS_PER_ZONE 1
+-
+-/* MT7986 thermal sensors */
+-#define MT7986_TS1 0
+-
+-/* The number of controller in the MT7986 */
+-#define MT7986_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT7986_CALIBRATION 165
+-
+-struct mtk_thermal;
+-
+-struct thermal_bank_cfg {
+- unsigned int num_sensors;
+- const int *sensors;
+-};
+-
+-struct mtk_thermal_bank {
+- struct mtk_thermal *mt;
+- int id;
+-};
+-
+-struct mtk_thermal_data {
+- s32 num_banks;
+- s32 num_sensors;
+- s32 auxadc_channel;
+- const int *vts_index;
+- const int *sensor_mux_values;
+- const int *msr;
+- const int *adcpnp;
+- const int cali_val;
+- const int num_controller;
+- const int *controller_offset;
+- bool need_switch_bank;
+- struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+- enum mtk_thermal_version version;
+-};
+-
+-struct mtk_thermal {
+- struct device *dev;
+- void __iomem *thermal_base;
+-
+- struct clk *clk_peri_therm;
+- struct clk *clk_auxadc;
+- /* lock: for getting and putting banks */
+- struct mutex lock;
+-
+- /* Calibration values */
+- s32 adc_ge;
+- s32 adc_oe;
+- s32 degc_cali;
+- s32 o_slope;
+- s32 o_slope_sign;
+- s32 vts[MAX_NUM_VTS];
+-
+- const struct mtk_thermal_data *conf;
+- struct mtk_thermal_bank banks[MAX_NUM_ZONES];
+-
+- int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
+-};
+-
+-/* MT8183 thermal sensor data */
+-static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
+- MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
+-};
+-
+-static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1
+-};
+-
+-static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1,
+- TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1
+-};
+-
+-static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 };
+-static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100};
+-
+-static const int mt8183_vts_index[MT8183_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB
+-};
+-
+-/* MT8173 thermal sensor data */
+-static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
+- { MT8173_TS2, MT8173_TS3 },
+- { MT8173_TS2, MT8173_TS4 },
+- { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
+- { MT8173_TS2 },
+-};
+-
+-static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+-};
+-
+-static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+-};
+-
+-static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
+-static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt8173_vts_index[MT8173_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4, VTSABB
+-};
+-
+-/* MT2701 thermal sensor data */
+-static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
+- MT2701_TS1, MT2701_TS2, MT2701_TSABB
+-};
+-
+-static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
+-};
+-
+-static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
+-};
+-
+-static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
+-static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt2701_vts_index[MT2701_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3
+-};
+-
+-/* MT2712 thermal sensor data */
+-static const int mt2712_bank_data[MT2712_NUM_SENSORS] = {
+- MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4
+-};
+-
+-static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+-};
+-
+-static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+-};
+-
+-static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
+-static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt2712_vts_index[MT2712_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4
+-};
+-
+-/* MT7622 thermal sensor data */
+-static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
+-static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+-static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
+-static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
+-static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
+-static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
+-
+-/* MT7986 thermal sensor data */
+-static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
+-static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+-static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
+-static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
+-static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
+-static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
+-
+-/*
+- * The MT8173 thermal controller has four banks. Each bank can read up to
+- * four temperature sensors simultaneously. The MT8173 has a total of 5
+- * temperature sensors. We use each bank to measure a certain area of the
+- * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
+- * areas, hence is used in different banks.
+- *
+- * The thermal core only gets the maximum temperature of all banks, so
+- * the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data, and this indeed needs the temperatures of the individual banks
+- * for making better decisions.
+- */
+-static const struct mtk_thermal_data mt8173_thermal_data = {
+- .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT8173_NUM_ZONES,
+- .num_sensors = MT8173_NUM_SENSORS,
+- .vts_index = mt8173_vts_index,
+- .cali_val = MT8173_CALIBRATION,
+- .num_controller = MT8173_NUM_CONTROLLER,
+- .controller_offset = mt8173_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 2,
+- .sensors = mt8173_bank_data[0],
+- }, {
+- .num_sensors = 2,
+- .sensors = mt8173_bank_data[1],
+- }, {
+- .num_sensors = 3,
+- .sensors = mt8173_bank_data[2],
+- }, {
+- .num_sensors = 1,
+- .sensors = mt8173_bank_data[3],
+- },
+- },
+- .msr = mt8173_msr,
+- .adcpnp = mt8173_adcpnp,
+- .sensor_mux_values = mt8173_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * The MT2701 thermal controller has one bank, which can read up to
+- * three temperature sensors simultaneously. The MT2701 has a total of 3
+- * temperature sensors.
+- *
+- * The thermal core only gets the maximum temperature of this one bank,
+- * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data.
+- */
+-static const struct mtk_thermal_data mt2701_thermal_data = {
+- .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
+- .num_banks = 1,
+- .num_sensors = MT2701_NUM_SENSORS,
+- .vts_index = mt2701_vts_index,
+- .cali_val = MT2701_CALIBRATION,
+- .num_controller = MT2701_NUM_CONTROLLER,
+- .controller_offset = mt2701_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 3,
+- .sensors = mt2701_bank_data,
+- },
+- },
+- .msr = mt2701_msr,
+- .adcpnp = mt2701_adcpnp,
+- .sensor_mux_values = mt2701_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * The MT2712 thermal controller has one bank, which can read up to
+- * four temperature sensors simultaneously. The MT2712 has a total of 4
+- * temperature sensors.
+- *
+- * The thermal core only gets the maximum temperature of this one bank,
+- * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data.
+- */
+-static const struct mtk_thermal_data mt2712_thermal_data = {
+- .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL,
+- .num_banks = 1,
+- .num_sensors = MT2712_NUM_SENSORS,
+- .vts_index = mt2712_vts_index,
+- .cali_val = MT2712_CALIBRATION,
+- .num_controller = MT2712_NUM_CONTROLLER,
+- .controller_offset = mt2712_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 4,
+- .sensors = mt2712_bank_data,
+- },
+- },
+- .msr = mt2712_msr,
+- .adcpnp = mt2712_adcpnp,
+- .sensor_mux_values = mt2712_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
+- * access.
+- */
+-static const struct mtk_thermal_data mt7622_thermal_data = {
+- .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT7622_NUM_ZONES,
+- .num_sensors = MT7622_NUM_SENSORS,
+- .vts_index = mt7622_vts_index,
+- .cali_val = MT7622_CALIBRATION,
+- .num_controller = MT7622_NUM_CONTROLLER,
+- .controller_offset = mt7622_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 1,
+- .sensors = mt7622_bank_data,
+- },
+- },
+- .msr = mt7622_msr,
+- .adcpnp = mt7622_adcpnp,
+- .sensor_mux_values = mt7622_mux_values,
+- .version = MTK_THERMAL_V2,
+-};
+-
+-/*
+- * The MT8183 thermal controller has one bank for the current SW framework.
+- * The MT8183 has a total of 6 temperature sensors.
+- * There are two thermal controller to control the six sensor.
+- * The first one bind 2 sensor, and the other bind 4 sensors.
+- * The thermal core only gets the maximum temperature of all sensor, so
+- * the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data, and this indeed needs the temperatures of the individual banks
+- * for making better decisions.
+- */
+-static const struct mtk_thermal_data mt8183_thermal_data = {
+- .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT8183_NUM_ZONES,
+- .num_sensors = MT8183_NUM_SENSORS,
+- .vts_index = mt8183_vts_index,
+- .cali_val = MT8183_CALIBRATION,
+- .num_controller = MT8183_NUM_CONTROLLER,
+- .controller_offset = mt8183_tc_offset,
+- .need_switch_bank = false,
+- .bank_data = {
+- {
+- .num_sensors = 6,
+- .sensors = mt8183_bank_data,
+- },
+- },
+-
+- .msr = mt8183_msr,
+- .adcpnp = mt8183_adcpnp,
+- .sensor_mux_values = mt8183_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * MT7986 uses AUXADC Channel 11 for raw data access.
+- */
+-static const struct mtk_thermal_data mt7986_thermal_data = {
+- .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT7986_NUM_ZONES,
+- .num_sensors = MT7986_NUM_SENSORS,
+- .vts_index = mt7986_vts_index,
+- .cali_val = MT7986_CALIBRATION,
+- .num_controller = MT7986_NUM_CONTROLLER,
+- .controller_offset = mt7986_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 1,
+- .sensors = mt7986_bank_data,
+- },
+- },
+- .msr = mt7986_msr,
+- .adcpnp = mt7986_adcpnp,
+- .sensor_mux_values = mt7986_mux_values,
+- .version = MTK_THERMAL_V3,
+-};
+-
+-/**
+- * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+- * @mt: The thermal controller
+- * @sensno: sensor number
+- * @raw: raw ADC value
+- *
+- * This converts the raw ADC value to mcelsius using the SoC specific
+- * calibration constants
+- */
+-static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 tmp;
+-
+- raw &= 0xfff;
+-
+- tmp = 203450520 << 3;
+- tmp /= mt->conf->cali_val + mt->o_slope;
+- tmp /= 10000 + mt->adc_ge;
+- tmp *= raw - mt->vts[sensno] - 3350;
+- tmp >>= 3;
+-
+- return mt->degc_cali * 500 - tmp;
+-}
+-
+-static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 format_1;
+- s32 format_2;
+- s32 g_oe;
+- s32 g_gain;
+- s32 g_x_roomt;
+- s32 tmp;
+-
+- if (raw == 0)
+- return 0;
+-
+- raw &= 0xfff;
+- g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
+- g_oe = mt->adc_oe - 512;
+- format_1 = mt->vts[VTS2] + 3105 - g_oe;
+- format_2 = (mt->degc_cali * 10) >> 1;
+- g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
+-
+- tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
+- tmp = tmp * 10 * 100 / 11;
+-
+- if (mt->o_slope_sign == 0)
+- tmp = tmp / (165 - mt->o_slope);
+- else
+- tmp = tmp / (165 + mt->o_slope);
+-
+- return (format_2 - tmp) * 100;
+-}
+-
+-static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 tmp;
+-
+- if (raw == 0)
+- return 0;
+-
+- raw &= 0xfff;
+- tmp = 100000 * 15 / 16 * 10000;
+- tmp /= 4096 - 512 + mt->adc_ge;
+- tmp /= 1490;
+- tmp *= raw - mt->vts[sensno] - 2900;
+-
+- return mt->degc_cali * 500 - tmp;
+-}
+-
+-/**
+- * mtk_thermal_get_bank - get bank
+- * @bank: The bank
+- *
+- * The bank registers are banked, we have to select a bank in the
+- * PTPCORESEL register to access it.
+- */
+-static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+- u32 val;
+-
+- if (mt->conf->need_switch_bank) {
+- mutex_lock(&mt->lock);
+-
+- val = readl(mt->thermal_base + PTPCORESEL);
+- val &= ~0xf;
+- val |= bank->id;
+- writel(val, mt->thermal_base + PTPCORESEL);
+- }
+-}
+-
+-/**
+- * mtk_thermal_put_bank - release bank
+- * @bank: The bank
+- *
+- * release a bank previously taken with mtk_thermal_get_bank,
+- */
+-static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+-
+- if (mt->conf->need_switch_bank)
+- mutex_unlock(&mt->lock);
+-}
+-
+-/**
+- * mtk_thermal_bank_temperature - get the temperature of a bank
+- * @bank: The bank
+- *
+- * The temperature of a bank is considered the maximum temperature of
+- * the sensors associated to the bank.
+- */
+-static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+- const struct mtk_thermal_data *conf = mt->conf;
+- int i, temp = INT_MIN, max = INT_MIN;
+- u32 raw;
+-
+- for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+- raw = readl(mt->thermal_base + conf->msr[i]);
+-
+- temp = mt->raw_to_mcelsius(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+-
+-
+- /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
+- */
+- if (temp > 200000)
+- temp = 0;
+-
+- if (temp > max)
+- max = temp;
+- }
+-
+- return max;
+-}
+-
+-static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
+-{
+- struct mtk_thermal *mt = tz->devdata;
+- int i;
+- int tempmax = INT_MIN;
+-
+- for (i = 0; i < mt->conf->num_banks; i++) {
+- struct mtk_thermal_bank *bank = &mt->banks[i];
+-
+- mtk_thermal_get_bank(bank);
+-
+- tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));
+-
+- mtk_thermal_put_bank(bank);
+- }
+-
+- *temperature = tempmax;
+-
+- return 0;
+-}
+-
+-static const struct thermal_zone_device_ops mtk_thermal_ops = {
+- .get_temp = mtk_read_temp,
+-};
+-
+-static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
+- u32 apmixed_phys_base, u32 auxadc_phys_base,
+- int ctrl_id)
+-{
+- struct mtk_thermal_bank *bank = &mt->banks[num];
+- const struct mtk_thermal_data *conf = mt->conf;
+- int i;
+-
+- int offset = mt->conf->controller_offset[ctrl_id];
+- void __iomem *controller_base = mt->thermal_base + offset;
+-
+- bank->id = num;
+- bank->mt = mt;
+-
+- mtk_thermal_get_bank(bank);
+-
+- /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
+- writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1);
+-
+- /*
+- * filt interval is 1 * 46.540us = 46.54us,
+- * sen interval is 429 * 46.540us = 19.96ms
+- */
+- writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |
+- TEMP_MONCTL2_SENSOR_INTERVAL(429),
+- controller_base + TEMP_MONCTL2);
+-
+- /* poll is set to 10u */
+- writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),
+- controller_base + TEMP_AHBPOLL);
+-
+- /* temperature sampling control, 1 sample */
+- writel(0x0, controller_base + TEMP_MSRCTL0);
+-
+- /* exceed this polling time, IRQ would be inserted */
+- writel(0xffffffff, controller_base + TEMP_AHBTO);
+-
+- /* number of interrupts per event, 1 is enough */
+- writel(0x0, controller_base + TEMP_MONIDET0);
+- writel(0x0, controller_base + TEMP_MONIDET1);
+-
+- /*
+- * The MT8173 thermal controller does not have its own ADC. Instead it
+- * uses AHB bus accesses to control the AUXADC. To do this the thermal
+- * controller has to be programmed with the physical addresses of the
+- * AUXADC registers and with the various bit positions in the AUXADC.
+- * Also the thermal controller controls a mux in the APMIXEDSYS register
+- * space.
+- */
+-
+- /*
+- * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
+- * automatically by hw
+- */
+- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX);
+-
+- /* AHB address for auxadc mux selection */
+- writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
+- controller_base + TEMP_ADCMUXADDR);
+-
+- if (mt->conf->version == MTK_THERMAL_V1) {
+- /* AHB address for pnp sensor mux selection */
+- writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
+- controller_base + TEMP_PNPMUXADDR);
+- }
+-
+- /* AHB value for auxadc enable */
+- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
+-
+- /* AHB address for auxadc enable (channel 0 immediate mode selected) */
+- writel(auxadc_phys_base + AUXADC_CON1_SET_V,
+- controller_base + TEMP_ADCENADDR);
+-
+- /* AHB address for auxadc valid bit */
+- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+- controller_base + TEMP_ADCVALIDADDR);
+-
+- /* AHB address for auxadc voltage output */
+- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+- controller_base + TEMP_ADCVOLTADDR);
+-
+- /* read valid & voltage are at the same register */
+- writel(0x0, controller_base + TEMP_RDCTRL);
+-
+- /* indicate where the valid bit is */
+- writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),
+- controller_base + TEMP_ADCVALIDMASK);
+-
+- /* no shift */
+- writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT);
+-
+- /* enable auxadc mux write transaction */
+- writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+- controller_base + TEMP_ADCWRITECTRL);
+-
+- for (i = 0; i < conf->bank_data[num].num_sensors; i++)
+- writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
+- mt->thermal_base + conf->adcpnp[i]);
+-
+- writel((1 << conf->bank_data[num].num_sensors) - 1,
+- controller_base + TEMP_MONCTL0);
+-
+- writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
+- TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+- controller_base + TEMP_ADCWRITECTRL);
+-
+- mtk_thermal_put_bank(bank);
+-}
+-
+-static u64 of_get_phys_base(struct device_node *np)
+-{
+- u64 size64;
+- const __be32 *regaddr_p;
+-
+- regaddr_p = of_get_address(np, 0, &size64, NULL);
+- if (!regaddr_p)
+- return OF_BAD_ADDR;
+-
+- return of_translate_address(np, regaddr_p);
+-}
+-
+-static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
+-{
+- int i;
+-
+- if (!(buf[0] & CALIB_BUF0_VALID_V1))
+- return -EINVAL;
+-
+- mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
+-
+- for (i = 0; i < mt->conf->num_sensors; i++) {
+- switch (mt->conf->vts_index[i]) {
+- case VTS1:
+- mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
+- break;
+- case VTS2:
+- mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
+- break;
+- case VTS3:
+- mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
+- break;
+- case VTS4:
+- mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
+- break;
+- case VTS5:
+- mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
+- break;
+- case VTSABB:
+- mt->vts[VTSABB] =
+- CALIB_BUF2_VTS_TSABB_V1(buf[2]);
+- break;
+- default:
+- break;
+- }
+- }
+-
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
+- if (CALIB_BUF1_ID_V1(buf[1]) &
+- CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
+- mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
+- else
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
+-{
+- if (!CALIB_BUF1_VALID_V2(buf[1]))
+- return -EINVAL;
+-
+- mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
+- mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
+- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
+- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
+- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
+- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
+-{
+- if (!CALIB_BUF1_VALID_V3(buf[1]))
+- return -EINVAL;
+-
+- mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
+- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
+- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
+- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
+- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
+-
+- if (CALIB_BUF1_ID_V3(buf[1]) == 0)
+- mt->o_slope = 0;
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_get_calibration_data(struct device *dev,
+- struct mtk_thermal *mt)
+-{
+- struct nvmem_cell *cell;
+- u32 *buf;
+- size_t len;
+- int i, ret = 0;
+-
+- /* Start with default values */
+- mt->adc_ge = 512;
+- mt->adc_oe = 512;
+- for (i = 0; i < mt->conf->num_sensors; i++)
+- mt->vts[i] = 260;
+- mt->degc_cali = 40;
+- mt->o_slope = 0;
+-
+- cell = nvmem_cell_get(dev, "calibration-data");
+- if (IS_ERR(cell)) {
+- if (PTR_ERR(cell) == -EPROBE_DEFER)
+- return PTR_ERR(cell);
+- return 0;
+- }
+-
+- buf = (u32 *)nvmem_cell_read(cell, &len);
+-
+- nvmem_cell_put(cell);
+-
+- if (IS_ERR(buf))
+- return PTR_ERR(buf);
+-
+- if (len < 3 * sizeof(u32)) {
+- dev_warn(dev, "invalid calibration data\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- switch (mt->conf->version) {
+- case MTK_THERMAL_V1:
+- ret = mtk_thermal_extract_efuse_v1(mt, buf);
+- break;
+- case MTK_THERMAL_V2:
+- ret = mtk_thermal_extract_efuse_v2(mt, buf);
+- break;
+- case MTK_THERMAL_V3:
+- ret = mtk_thermal_extract_efuse_v3(mt, buf);
+- break;
+- default:
+- ret = -EINVAL;
+- break;
+- }
+-
+- if (ret) {
+- dev_info(dev, "Device not calibrated, using default calibration values\n");
+- ret = 0;
+- }
+-
+-out:
+- kfree(buf);
+-
+- return ret;
+-}
+-
+-static const struct of_device_id mtk_thermal_of_match[] = {
+- {
+- .compatible = "mediatek,mt8173-thermal",
+- .data = (void *)&mt8173_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt2701-thermal",
+- .data = (void *)&mt2701_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt2712-thermal",
+- .data = (void *)&mt2712_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt7622-thermal",
+- .data = (void *)&mt7622_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt7986-thermal",
+- .data = (void *)&mt7986_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt8183-thermal",
+- .data = (void *)&mt8183_thermal_data,
+- }, {
+- },
+-};
+-MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+-
+-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
+-{
+- int tmp;
+-
+- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+- tmp &= ~(0x37);
+- tmp |= 0x1;
+- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
+- udelay(200);
+-}
+-
+-static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
+- void __iomem *auxadc_base)
+-{
+- int tmp;
+-
+- writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
+- writel(0x1, mt->thermal_base + TEMP_MONCTL0);
+- tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
+- writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
+-}
+-
+-static int mtk_thermal_probe(struct platform_device *pdev)
+-{
+- int ret, i, ctrl_id;
+- struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
+- struct mtk_thermal *mt;
+- u64 auxadc_phys_base, apmixed_phys_base;
+- struct thermal_zone_device *tzdev;
+- void __iomem *apmixed_base, *auxadc_base;
+-
+- mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
+- if (!mt)
+- return -ENOMEM;
+-
+- mt->conf = of_device_get_match_data(&pdev->dev);
+-
+- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
+- if (IS_ERR(mt->clk_peri_therm))
+- return PTR_ERR(mt->clk_peri_therm);
+-
+- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
+- if (IS_ERR(mt->clk_auxadc))
+- return PTR_ERR(mt->clk_auxadc);
+-
+- mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+- if (IS_ERR(mt->thermal_base))
+- return PTR_ERR(mt->thermal_base);
+-
+- ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);
+- if (ret)
+- return ret;
+-
+- mutex_init(&mt->lock);
+-
+- mt->dev = &pdev->dev;
+-
+- auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
+- if (!auxadc) {
+- dev_err(&pdev->dev, "missing auxadc node\n");
+- return -ENODEV;
+- }
+-
+- auxadc_base = of_iomap(auxadc, 0);
+- auxadc_phys_base = of_get_phys_base(auxadc);
+-
+- of_node_put(auxadc);
+-
+- if (auxadc_phys_base == OF_BAD_ADDR) {
+- dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+- return -EINVAL;
+- }
+-
+- apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);
+- if (!apmixedsys) {
+- dev_err(&pdev->dev, "missing apmixedsys node\n");
+- return -ENODEV;
+- }
+-
+- apmixed_base = of_iomap(apmixedsys, 0);
+- apmixed_phys_base = of_get_phys_base(apmixedsys);
+-
+- of_node_put(apmixedsys);
+-
+- if (apmixed_phys_base == OF_BAD_ADDR) {
+- dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+- return -EINVAL;
+- }
+-
+- ret = device_reset_optional(&pdev->dev);
+- if (ret)
+- return ret;
+-
+- ret = clk_prepare_enable(mt->clk_auxadc);
+- if (ret) {
+- dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
+- return ret;
+- }
+-
+- ret = clk_prepare_enable(mt->clk_peri_therm);
+- if (ret) {
+- dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
+- goto err_disable_clk_auxadc;
+- }
+-
+- if (mt->conf->version != MTK_THERMAL_V1) {
+- mtk_thermal_turn_on_buffer(apmixed_base);
+- mtk_thermal_release_periodic_ts(mt, auxadc_base);
+- }
+-
+- if (mt->conf->version == MTK_THERMAL_V1)
+- mt->raw_to_mcelsius = raw_to_mcelsius_v1;
+- else if (mt->conf->version == MTK_THERMAL_V2)
+- mt->raw_to_mcelsius = raw_to_mcelsius_v2;
+- else
+- mt->raw_to_mcelsius = raw_to_mcelsius_v3;
+-
+- for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+- for (i = 0; i < mt->conf->num_banks; i++)
+- mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+- auxadc_phys_base, ctrl_id);
+-
+- platform_set_drvdata(pdev, mt);
+-
+- tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+- &mtk_thermal_ops);
+- if (IS_ERR(tzdev)) {
+- ret = PTR_ERR(tzdev);
+- goto err_disable_clk_peri_therm;
+- }
+-
+- ret = devm_thermal_add_hwmon_sysfs(tzdev);
+- if (ret)
+- dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+-
+- return 0;
+-
+-err_disable_clk_peri_therm:
+- clk_disable_unprepare(mt->clk_peri_therm);
+-err_disable_clk_auxadc:
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return ret;
+-}
+-
+-static int mtk_thermal_remove(struct platform_device *pdev)
+-{
+- struct mtk_thermal *mt = platform_get_drvdata(pdev);
+-
+- clk_disable_unprepare(mt->clk_peri_therm);
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return 0;
+-}
+-
+-static struct platform_driver mtk_thermal_driver = {
+- .probe = mtk_thermal_probe,
+- .remove = mtk_thermal_remove,
+- .driver = {
+- .name = "mtk-thermal",
+- .of_match_table = mtk_thermal_of_match,
+- },
+-};
+-
+-module_platform_driver(mtk_thermal_driver);
+-
+-MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+-MODULE_AUTHOR("Louis Yu <louis.yu@mediatek.com>");
+-MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
+-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+-MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");
+-MODULE_DESCRIPTION("Mediatek thermal driver");
+-MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -0,0 +1,1254 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author: Hanyi Wu <hanyi.wu@mediatek.com>
++ * Sascha Hauer <s.hauer@pengutronix.de>
++ * Dawei Chien <dawei.chien@mediatek.com>
++ * Louis Yu <louis.yu@mediatek.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/thermal.h>
++#include <linux/reset.h>
++#include <linux/types.h>
++
++#include "../thermal_hwmon.h"
++
++/* AUXADC Registers */
++#define AUXADC_CON1_SET_V 0x008
++#define AUXADC_CON1_CLR_V 0x00c
++#define AUXADC_CON2_V 0x010
++#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
++
++#define APMIXED_SYS_TS_CON1 0x604
++
++/* Thermal Controller Registers */
++#define TEMP_MONCTL0 0x000
++#define TEMP_MONCTL1 0x004
++#define TEMP_MONCTL2 0x008
++#define TEMP_MONIDET0 0x014
++#define TEMP_MONIDET1 0x018
++#define TEMP_MSRCTL0 0x038
++#define TEMP_MSRCTL1 0x03c
++#define TEMP_AHBPOLL 0x040
++#define TEMP_AHBTO 0x044
++#define TEMP_ADCPNP0 0x048
++#define TEMP_ADCPNP1 0x04c
++#define TEMP_ADCPNP2 0x050
++#define TEMP_ADCPNP3 0x0b4
++
++#define TEMP_ADCMUX 0x054
++#define TEMP_ADCEN 0x060
++#define TEMP_PNPMUXADDR 0x064
++#define TEMP_ADCMUXADDR 0x068
++#define TEMP_ADCENADDR 0x074
++#define TEMP_ADCVALIDADDR 0x078
++#define TEMP_ADCVOLTADDR 0x07c
++#define TEMP_RDCTRL 0x080
++#define TEMP_ADCVALIDMASK 0x084
++#define TEMP_ADCVOLTAGESHIFT 0x088
++#define TEMP_ADCWRITECTRL 0x08c
++#define TEMP_MSR0 0x090
++#define TEMP_MSR1 0x094
++#define TEMP_MSR2 0x098
++#define TEMP_MSR3 0x0B8
++
++#define TEMP_SPARE0 0x0f0
++
++#define TEMP_ADCPNP0_1 0x148
++#define TEMP_ADCPNP1_1 0x14c
++#define TEMP_ADCPNP2_1 0x150
++#define TEMP_MSR0_1 0x190
++#define TEMP_MSR1_1 0x194
++#define TEMP_MSR2_1 0x198
++#define TEMP_ADCPNP3_1 0x1b4
++#define TEMP_MSR3_1 0x1B8
++
++#define PTPCORESEL 0x400
++
++#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)
++
++#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)
++#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)
++
++#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)
++
++#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)
++#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)
++
++#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)
++#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)
++
++/* MT8173 thermal sensors */
++#define MT8173_TS1 0
++#define MT8173_TS2 1
++#define MT8173_TS3 2
++#define MT8173_TS4 3
++#define MT8173_TSABB 4
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT8173_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT8173 */
++#define MT8173_NUM_SENSORS 5
++
++/* The number of banks in the MT8173 */
++#define MT8173_NUM_ZONES 4
++
++/* The number of sensing points per bank */
++#define MT8173_NUM_SENSORS_PER_ZONE 4
++
++/* The number of controller in the MT8173 */
++#define MT8173_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT8173_CALIBRATION 165
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
++ * MT8183 has 6 sensors and needs 6 VTS calibration data.
++ * MT8173 has 5 sensors and needs 5 VTS calibration data.
++ * MT2701 has 3 sensors and needs 3 VTS calibration data.
++ * MT2712 has 4 sensors and needs 4 VTS calibration data.
++ */
++#define CALIB_BUF0_VALID_V1 BIT(0)
++#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff)
++#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff)
++#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff)
++#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff)
++#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff)
++#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff)
++#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1)
++#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1)
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros could be used for MT7622.
++ */
++#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff)
++#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff)
++#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros can be used for MT7981 and MT7986.
++ */
++#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
++#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
++#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
++
++enum {
++ VTS1,
++ VTS2,
++ VTS3,
++ VTS4,
++ VTS5,
++ VTSABB,
++ MAX_NUM_VTS,
++};
++
++enum mtk_thermal_version {
++ MTK_THERMAL_V1 = 1,
++ MTK_THERMAL_V2,
++ MTK_THERMAL_V3,
++};
++
++/* MT2701 thermal sensors */
++#define MT2701_TS1 0
++#define MT2701_TS2 1
++#define MT2701_TSABB 2
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT2701_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT2701 */
++#define MT2701_NUM_SENSORS 3
++
++/* The number of sensing points per bank */
++#define MT2701_NUM_SENSORS_PER_ZONE 3
++
++/* The number of controller in the MT2701 */
++#define MT2701_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT2701_CALIBRATION 165
++
++/* MT2712 thermal sensors */
++#define MT2712_TS1 0
++#define MT2712_TS2 1
++#define MT2712_TS3 2
++#define MT2712_TS4 3
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT2712_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT2712 */
++#define MT2712_NUM_SENSORS 4
++
++/* The number of sensing points per bank */
++#define MT2712_NUM_SENSORS_PER_ZONE 4
++
++/* The number of controller in the MT2712 */
++#define MT2712_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT2712_CALIBRATION 165
++
++#define MT7622_TEMP_AUXADC_CHANNEL 11
++#define MT7622_NUM_SENSORS 1
++#define MT7622_NUM_ZONES 1
++#define MT7622_NUM_SENSORS_PER_ZONE 1
++#define MT7622_TS1 0
++#define MT7622_NUM_CONTROLLER 1
++
++/* The maximum number of banks */
++#define MAX_NUM_ZONES 8
++
++/* The calibration coefficient of sensor */
++#define MT7622_CALIBRATION 165
++
++/* MT8183 thermal sensors */
++#define MT8183_TS1 0
++#define MT8183_TS2 1
++#define MT8183_TS3 2
++#define MT8183_TS4 3
++#define MT8183_TS5 4
++#define MT8183_TSABB 5
++
++/* AUXADC channel is used for the temperature sensors */
++#define MT8183_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT8183 */
++#define MT8183_NUM_SENSORS 6
++
++/* The number of banks in the MT8183 */
++#define MT8183_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT8183_NUM_SENSORS_PER_ZONE 6
++
++/* The number of controller in the MT8183 */
++#define MT8183_NUM_CONTROLLER 2
++
++/* The calibration coefficient of sensor */
++#define MT8183_CALIBRATION 153
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT7986_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT7986 */
++#define MT7986_NUM_SENSORS 1
++
++/* The number of banks in the MT7986 */
++#define MT7986_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT7986_NUM_SENSORS_PER_ZONE 1
++
++/* MT7986 thermal sensors */
++#define MT7986_TS1 0
++
++/* The number of controller in the MT7986 */
++#define MT7986_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT7986_CALIBRATION 165
++
++struct mtk_thermal;
++
++struct thermal_bank_cfg {
++ unsigned int num_sensors;
++ const int *sensors;
++};
++
++struct mtk_thermal_bank {
++ struct mtk_thermal *mt;
++ int id;
++};
++
++struct mtk_thermal_data {
++ s32 num_banks;
++ s32 num_sensors;
++ s32 auxadc_channel;
++ const int *vts_index;
++ const int *sensor_mux_values;
++ const int *msr;
++ const int *adcpnp;
++ const int cali_val;
++ const int num_controller;
++ const int *controller_offset;
++ bool need_switch_bank;
++ struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
++ enum mtk_thermal_version version;
++};
++
++struct mtk_thermal {
++ struct device *dev;
++ void __iomem *thermal_base;
++
++ struct clk *clk_peri_therm;
++ struct clk *clk_auxadc;
++ /* lock: for getting and putting banks */
++ struct mutex lock;
++
++ /* Calibration values */
++ s32 adc_ge;
++ s32 adc_oe;
++ s32 degc_cali;
++ s32 o_slope;
++ s32 o_slope_sign;
++ s32 vts[MAX_NUM_VTS];
++
++ const struct mtk_thermal_data *conf;
++ struct mtk_thermal_bank banks[MAX_NUM_ZONES];
++
++ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
++};
++
++/* MT8183 thermal sensor data */
++static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
++ MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
++};
++
++static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1
++};
++
++static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1,
++ TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1
++};
++
++static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 };
++static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100};
++
++static const int mt8183_vts_index[MT8183_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB
++};
++
++/* MT8173 thermal sensor data */
++static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
++ { MT8173_TS2, MT8173_TS3 },
++ { MT8173_TS2, MT8173_TS4 },
++ { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
++ { MT8173_TS2 },
++};
++
++static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
++};
++
++static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
++};
++
++static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
++static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt8173_vts_index[MT8173_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4, VTSABB
++};
++
++/* MT2701 thermal sensor data */
++static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
++ MT2701_TS1, MT2701_TS2, MT2701_TSABB
++};
++
++static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
++};
++
++static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
++};
++
++static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
++static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt2701_vts_index[MT2701_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3
++};
++
++/* MT2712 thermal sensor data */
++static const int mt2712_bank_data[MT2712_NUM_SENSORS] = {
++ MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4
++};
++
++static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
++};
++
++static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
++};
++
++static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
++static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt2712_vts_index[MT2712_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4
++};
++
++/* MT7622 thermal sensor data */
++static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
++static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
++static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
++static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
++
++/* MT7986 thermal sensor data */
++static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
++static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
++static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
++static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
++
++/*
++ * The MT8173 thermal controller has four banks. Each bank can read up to
++ * four temperature sensors simultaneously. The MT8173 has a total of 5
++ * temperature sensors. We use each bank to measure a certain area of the
++ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
++ * areas, hence is used in different banks.
++ *
++ * The thermal core only gets the maximum temperature of all banks, so
++ * the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data, and this indeed needs the temperatures of the individual banks
++ * for making better decisions.
++ */
++static const struct mtk_thermal_data mt8173_thermal_data = {
++ .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8173_NUM_ZONES,
++ .num_sensors = MT8173_NUM_SENSORS,
++ .vts_index = mt8173_vts_index,
++ .cali_val = MT8173_CALIBRATION,
++ .num_controller = MT8173_NUM_CONTROLLER,
++ .controller_offset = mt8173_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 2,
++ .sensors = mt8173_bank_data[0],
++ }, {
++ .num_sensors = 2,
++ .sensors = mt8173_bank_data[1],
++ }, {
++ .num_sensors = 3,
++ .sensors = mt8173_bank_data[2],
++ }, {
++ .num_sensors = 1,
++ .sensors = mt8173_bank_data[3],
++ },
++ },
++ .msr = mt8173_msr,
++ .adcpnp = mt8173_adcpnp,
++ .sensor_mux_values = mt8173_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * The MT2701 thermal controller has one bank, which can read up to
++ * three temperature sensors simultaneously. The MT2701 has a total of 3
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt2701_thermal_data = {
++ .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
++ .num_banks = 1,
++ .num_sensors = MT2701_NUM_SENSORS,
++ .vts_index = mt2701_vts_index,
++ .cali_val = MT2701_CALIBRATION,
++ .num_controller = MT2701_NUM_CONTROLLER,
++ .controller_offset = mt2701_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 3,
++ .sensors = mt2701_bank_data,
++ },
++ },
++ .msr = mt2701_msr,
++ .adcpnp = mt2701_adcpnp,
++ .sensor_mux_values = mt2701_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * The MT2712 thermal controller has one bank, which can read up to
++ * four temperature sensors simultaneously. The MT2712 has a total of 4
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt2712_thermal_data = {
++ .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL,
++ .num_banks = 1,
++ .num_sensors = MT2712_NUM_SENSORS,
++ .vts_index = mt2712_vts_index,
++ .cali_val = MT2712_CALIBRATION,
++ .num_controller = MT2712_NUM_CONTROLLER,
++ .controller_offset = mt2712_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 4,
++ .sensors = mt2712_bank_data,
++ },
++ },
++ .msr = mt2712_msr,
++ .adcpnp = mt2712_adcpnp,
++ .sensor_mux_values = mt2712_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
++ * access.
++ */
++static const struct mtk_thermal_data mt7622_thermal_data = {
++ .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7622_NUM_ZONES,
++ .num_sensors = MT7622_NUM_SENSORS,
++ .vts_index = mt7622_vts_index,
++ .cali_val = MT7622_CALIBRATION,
++ .num_controller = MT7622_NUM_CONTROLLER,
++ .controller_offset = mt7622_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7622_bank_data,
++ },
++ },
++ .msr = mt7622_msr,
++ .adcpnp = mt7622_adcpnp,
++ .sensor_mux_values = mt7622_mux_values,
++ .version = MTK_THERMAL_V2,
++};
++
++/*
++ * The MT8183 thermal controller has one bank for the current SW framework.
++ * The MT8183 has a total of 6 temperature sensors.
++ * There are two thermal controller to control the six sensor.
++ * The first one bind 2 sensor, and the other bind 4 sensors.
++ * The thermal core only gets the maximum temperature of all sensor, so
++ * the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data, and this indeed needs the temperatures of the individual banks
++ * for making better decisions.
++ */
++static const struct mtk_thermal_data mt8183_thermal_data = {
++ .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8183_NUM_ZONES,
++ .num_sensors = MT8183_NUM_SENSORS,
++ .vts_index = mt8183_vts_index,
++ .cali_val = MT8183_CALIBRATION,
++ .num_controller = MT8183_NUM_CONTROLLER,
++ .controller_offset = mt8183_tc_offset,
++ .need_switch_bank = false,
++ .bank_data = {
++ {
++ .num_sensors = 6,
++ .sensors = mt8183_bank_data,
++ },
++ },
++
++ .msr = mt8183_msr,
++ .adcpnp = mt8183_adcpnp,
++ .sensor_mux_values = mt8183_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * MT7986 uses AUXADC Channel 11 for raw data access.
++ */
++static const struct mtk_thermal_data mt7986_thermal_data = {
++ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7986_NUM_ZONES,
++ .num_sensors = MT7986_NUM_SENSORS,
++ .vts_index = mt7986_vts_index,
++ .cali_val = MT7986_CALIBRATION,
++ .num_controller = MT7986_NUM_CONTROLLER,
++ .controller_offset = mt7986_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7986_bank_data,
++ },
++ },
++ .msr = mt7986_msr,
++ .adcpnp = mt7986_adcpnp,
++ .sensor_mux_values = mt7986_mux_values,
++ .version = MTK_THERMAL_V3,
++};
++
++/**
++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
++ * @mt: The thermal controller
++ * @sensno: sensor number
++ * @raw: raw ADC value
++ *
++ * This converts the raw ADC value to mcelsius using the SoC specific
++ * calibration constants
++ */
++static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ raw &= 0xfff;
++
++ tmp = 203450520 << 3;
++ tmp /= mt->conf->cali_val + mt->o_slope;
++ tmp /= 10000 + mt->adc_ge;
++ tmp *= raw - mt->vts[sensno] - 3350;
++ tmp >>= 3;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
++static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 format_1;
++ s32 format_2;
++ s32 g_oe;
++ s32 g_gain;
++ s32 g_x_roomt;
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
++ g_oe = mt->adc_oe - 512;
++ format_1 = mt->vts[VTS2] + 3105 - g_oe;
++ format_2 = (mt->degc_cali * 10) >> 1;
++ g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
++
++ tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
++ tmp = tmp * 10 * 100 / 11;
++
++ if (mt->o_slope_sign == 0)
++ tmp = tmp / (165 - mt->o_slope);
++ else
++ tmp = tmp / (165 + mt->o_slope);
++
++ return (format_2 - tmp) * 100;
++}
++
++static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ tmp = 100000 * 15 / 16 * 10000;
++ tmp /= 4096 - 512 + mt->adc_ge;
++ tmp /= 1490;
++ tmp *= raw - mt->vts[sensno] - 2900;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
++/**
++ * mtk_thermal_get_bank - get bank
++ * @bank: The bank
++ *
++ * The bank registers are banked, we have to select a bank in the
++ * PTPCORESEL register to access it.
++ */
++static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ u32 val;
++
++ if (mt->conf->need_switch_bank) {
++ mutex_lock(&mt->lock);
++
++ val = readl(mt->thermal_base + PTPCORESEL);
++ val &= ~0xf;
++ val |= bank->id;
++ writel(val, mt->thermal_base + PTPCORESEL);
++ }
++}
++
++/**
++ * mtk_thermal_put_bank - release bank
++ * @bank: The bank
++ *
++ * release a bank previously taken with mtk_thermal_get_bank,
++ */
++static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++
++ if (mt->conf->need_switch_bank)
++ mutex_unlock(&mt->lock);
++}
++
++/**
++ * mtk_thermal_bank_temperature - get the temperature of a bank
++ * @bank: The bank
++ *
++ * The temperature of a bank is considered the maximum temperature of
++ * the sensors associated to the bank.
++ */
++static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ const struct mtk_thermal_data *conf = mt->conf;
++ int i, temp = INT_MIN, max = INT_MIN;
++ u32 raw;
++
++ for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
++ raw = readl(mt->thermal_base + conf->msr[i]);
++
++ temp = mt->raw_to_mcelsius(
++ mt, conf->bank_data[bank->id].sensors[i], raw);
++
++
++ /*
++ * The first read of a sensor often contains very high bogus
++ * temperature value. Filter these out so that the system does
++ * not immediately shut down.
++ */
++ if (temp > 200000)
++ temp = 0;
++
++ if (temp > max)
++ max = temp;
++ }
++
++ return max;
++}
++
++static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
++{
++ struct mtk_thermal *mt = tz->devdata;
++ int i;
++ int tempmax = INT_MIN;
++
++ for (i = 0; i < mt->conf->num_banks; i++) {
++ struct mtk_thermal_bank *bank = &mt->banks[i];
++
++ mtk_thermal_get_bank(bank);
++
++ tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));
++
++ mtk_thermal_put_bank(bank);
++ }
++
++ *temperature = tempmax;
++
++ return 0;
++}
++
++static const struct thermal_zone_device_ops mtk_thermal_ops = {
++ .get_temp = mtk_read_temp,
++};
++
++static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
++ u32 apmixed_phys_base, u32 auxadc_phys_base,
++ int ctrl_id)
++{
++ struct mtk_thermal_bank *bank = &mt->banks[num];
++ const struct mtk_thermal_data *conf = mt->conf;
++ int i;
++
++ int offset = mt->conf->controller_offset[ctrl_id];
++ void __iomem *controller_base = mt->thermal_base + offset;
++
++ bank->id = num;
++ bank->mt = mt;
++
++ mtk_thermal_get_bank(bank);
++
++ /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
++ writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1);
++
++ /*
++ * filt interval is 1 * 46.540us = 46.54us,
++ * sen interval is 429 * 46.540us = 19.96ms
++ */
++ writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |
++ TEMP_MONCTL2_SENSOR_INTERVAL(429),
++ controller_base + TEMP_MONCTL2);
++
++ /* poll is set to 10u */
++ writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),
++ controller_base + TEMP_AHBPOLL);
++
++ /* temperature sampling control, 1 sample */
++ writel(0x0, controller_base + TEMP_MSRCTL0);
++
++ /* exceed this polling time, IRQ would be inserted */
++ writel(0xffffffff, controller_base + TEMP_AHBTO);
++
++ /* number of interrupts per event, 1 is enough */
++ writel(0x0, controller_base + TEMP_MONIDET0);
++ writel(0x0, controller_base + TEMP_MONIDET1);
++
++ /*
++ * The MT8173 thermal controller does not have its own ADC. Instead it
++ * uses AHB bus accesses to control the AUXADC. To do this the thermal
++ * controller has to be programmed with the physical addresses of the
++ * AUXADC registers and with the various bit positions in the AUXADC.
++ * Also the thermal controller controls a mux in the APMIXEDSYS register
++ * space.
++ */
++
++ /*
++ * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
++ * automatically by hw
++ */
++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX);
++
++ /* AHB address for auxadc mux selection */
++ writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
++ controller_base + TEMP_ADCMUXADDR);
++
++ if (mt->conf->version == MTK_THERMAL_V1) {
++ /* AHB address for pnp sensor mux selection */
++ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
++ controller_base + TEMP_PNPMUXADDR);
++ }
++
++ /* AHB value for auxadc enable */
++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
++
++ /* AHB address for auxadc enable (channel 0 immediate mode selected) */
++ writel(auxadc_phys_base + AUXADC_CON1_SET_V,
++ controller_base + TEMP_ADCENADDR);
++
++ /* AHB address for auxadc valid bit */
++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
++ controller_base + TEMP_ADCVALIDADDR);
++
++ /* AHB address for auxadc voltage output */
++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
++ controller_base + TEMP_ADCVOLTADDR);
++
++ /* read valid & voltage are at the same register */
++ writel(0x0, controller_base + TEMP_RDCTRL);
++
++ /* indicate where the valid bit is */
++ writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),
++ controller_base + TEMP_ADCVALIDMASK);
++
++ /* no shift */
++ writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT);
++
++ /* enable auxadc mux write transaction */
++ writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
++ controller_base + TEMP_ADCWRITECTRL);
++
++ for (i = 0; i < conf->bank_data[num].num_sensors; i++)
++ writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
++ mt->thermal_base + conf->adcpnp[i]);
++
++ writel((1 << conf->bank_data[num].num_sensors) - 1,
++ controller_base + TEMP_MONCTL0);
++
++ writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
++ TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
++ controller_base + TEMP_ADCWRITECTRL);
++
++ mtk_thermal_put_bank(bank);
++}
++
++static u64 of_get_phys_base(struct device_node *np)
++{
++ u64 size64;
++ const __be32 *regaddr_p;
++
++ regaddr_p = of_get_address(np, 0, &size64, NULL);
++ if (!regaddr_p)
++ return OF_BAD_ADDR;
++
++ return of_translate_address(np, regaddr_p);
++}
++
++static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
++{
++ int i;
++
++ if (!(buf[0] & CALIB_BUF0_VALID_V1))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
++
++ for (i = 0; i < mt->conf->num_sensors; i++) {
++ switch (mt->conf->vts_index[i]) {
++ case VTS1:
++ mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
++ break;
++ case VTS2:
++ mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
++ break;
++ case VTS3:
++ mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
++ break;
++ case VTS4:
++ mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
++ break;
++ case VTS5:
++ mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
++ break;
++ case VTSABB:
++ mt->vts[VTSABB] =
++ CALIB_BUF2_VTS_TSABB_V1(buf[2]);
++ break;
++ default:
++ break;
++ }
++ }
++
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
++ if (CALIB_BUF1_ID_V1(buf[1]) &
++ CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
++ mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
++ else
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
++
++ return 0;
++}
++
++static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V2(buf[1]))
++ return -EINVAL;
++
++ mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
++
++ return 0;
++}
++
++static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V3(buf[1]))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
++
++ if (CALIB_BUF1_ID_V3(buf[1]) == 0)
++ mt->o_slope = 0;
++
++ return 0;
++}
++
++static int mtk_thermal_get_calibration_data(struct device *dev,
++ struct mtk_thermal *mt)
++{
++ struct nvmem_cell *cell;
++ u32 *buf;
++ size_t len;
++ int i, ret = 0;
++
++ /* Start with default values */
++ mt->adc_ge = 512;
++ mt->adc_oe = 512;
++ for (i = 0; i < mt->conf->num_sensors; i++)
++ mt->vts[i] = 260;
++ mt->degc_cali = 40;
++ mt->o_slope = 0;
++
++ cell = nvmem_cell_get(dev, "calibration-data");
++ if (IS_ERR(cell)) {
++ if (PTR_ERR(cell) == -EPROBE_DEFER)
++ return PTR_ERR(cell);
++ return 0;
++ }
++
++ buf = (u32 *)nvmem_cell_read(cell, &len);
++
++ nvmem_cell_put(cell);
++
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++
++ if (len < 3 * sizeof(u32)) {
++ dev_warn(dev, "invalid calibration data\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ switch (mt->conf->version) {
++ case MTK_THERMAL_V1:
++ ret = mtk_thermal_extract_efuse_v1(mt, buf);
++ break;
++ case MTK_THERMAL_V2:
++ ret = mtk_thermal_extract_efuse_v2(mt, buf);
++ break;
++ case MTK_THERMAL_V3:
++ ret = mtk_thermal_extract_efuse_v3(mt, buf);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ if (ret) {
++ dev_info(dev, "Device not calibrated, using default calibration values\n");
++ ret = 0;
++ }
++
++out:
++ kfree(buf);
++
++ return ret;
++}
++
++static const struct of_device_id mtk_thermal_of_match[] = {
++ {
++ .compatible = "mediatek,mt8173-thermal",
++ .data = (void *)&mt8173_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt2701-thermal",
++ .data = (void *)&mt2701_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt2712-thermal",
++ .data = (void *)&mt2712_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt7622-thermal",
++ .data = (void *)&mt7622_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt7986-thermal",
++ .data = (void *)&mt7986_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt8183-thermal",
++ .data = (void *)&mt8183_thermal_data,
++ }, {
++ },
++};
++MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
++
++static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
++{
++ int tmp;
++
++ tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
++ tmp &= ~(0x37);
++ tmp |= 0x1;
++ writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
++ udelay(200);
++}
++
++static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
++ void __iomem *auxadc_base)
++{
++ int tmp;
++
++ writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
++ writel(0x1, mt->thermal_base + TEMP_MONCTL0);
++ tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
++ writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
++}
++
++static int mtk_thermal_probe(struct platform_device *pdev)
++{
++ int ret, i, ctrl_id;
++ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
++ struct mtk_thermal *mt;
++ u64 auxadc_phys_base, apmixed_phys_base;
++ struct thermal_zone_device *tzdev;
++ void __iomem *apmixed_base, *auxadc_base;
++
++ mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
++ if (!mt)
++ return -ENOMEM;
++
++ mt->conf = of_device_get_match_data(&pdev->dev);
++
++ mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
++ if (IS_ERR(mt->clk_peri_therm))
++ return PTR_ERR(mt->clk_peri_therm);
++
++ mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
++ if (IS_ERR(mt->clk_auxadc))
++ return PTR_ERR(mt->clk_auxadc);
++
++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
++ if (IS_ERR(mt->thermal_base))
++ return PTR_ERR(mt->thermal_base);
++
++ ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);
++ if (ret)
++ return ret;
++
++ mutex_init(&mt->lock);
++
++ mt->dev = &pdev->dev;
++
++ auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
++ if (!auxadc) {
++ dev_err(&pdev->dev, "missing auxadc node\n");
++ return -ENODEV;
++ }
++
++ auxadc_base = of_iomap(auxadc, 0);
++ auxadc_phys_base = of_get_phys_base(auxadc);
++
++ of_node_put(auxadc);
++
++ if (auxadc_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);
++ if (!apmixedsys) {
++ dev_err(&pdev->dev, "missing apmixedsys node\n");
++ return -ENODEV;
++ }
++
++ apmixed_base = of_iomap(apmixedsys, 0);
++ apmixed_phys_base = of_get_phys_base(apmixedsys);
++
++ of_node_put(apmixedsys);
++
++ if (apmixed_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ ret = device_reset_optional(&pdev->dev);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(mt->clk_auxadc);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(mt->clk_peri_therm);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
++ goto err_disable_clk_auxadc;
++ }
++
++ if (mt->conf->version != MTK_THERMAL_V1) {
++ mtk_thermal_turn_on_buffer(apmixed_base);
++ mtk_thermal_release_periodic_ts(mt, auxadc_base);
++ }
++
++ if (mt->conf->version == MTK_THERMAL_V1)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
++ else if (mt->conf->version == MTK_THERMAL_V2)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v3;
++
++ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
++ for (i = 0; i < mt->conf->num_banks; i++)
++ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
++ auxadc_phys_base, ctrl_id);
++
++ platform_set_drvdata(pdev, mt);
++
++ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
++ &mtk_thermal_ops);
++ if (IS_ERR(tzdev)) {
++ ret = PTR_ERR(tzdev);
++ goto err_disable_clk_peri_therm;
++ }
++
++ ret = devm_thermal_add_hwmon_sysfs(tzdev);
++ if (ret)
++ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
++
++ return 0;
++
++err_disable_clk_peri_therm:
++ clk_disable_unprepare(mt->clk_peri_therm);
++err_disable_clk_auxadc:
++ clk_disable_unprepare(mt->clk_auxadc);
++
++ return ret;
++}
++
++static int mtk_thermal_remove(struct platform_device *pdev)
++{
++ struct mtk_thermal *mt = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(mt->clk_peri_therm);
++ clk_disable_unprepare(mt->clk_auxadc);
++
++ return 0;
++}
++
++static struct platform_driver mtk_thermal_driver = {
++ .probe = mtk_thermal_probe,
++ .remove = mtk_thermal_remove,
++ .driver = {
++ .name = "mtk-thermal",
++ .of_match_table = mtk_thermal_of_match,
++ },
++};
++
++module_platform_driver(mtk_thermal_driver);
++
++MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
++MODULE_AUTHOR("Louis Yu <louis.yu@mediatek.com>");
++MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
++MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
++MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");
++MODULE_DESCRIPTION("Mediatek thermal driver");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 325fadf27b21f7d79843c3cc282b7f3e6620ad3d Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:26 +0100
+Subject: [PATCH 06/42] thermal/drivers/mediatek: Add the Low Voltage Thermal
+ Sensor driver
+
+The Low Voltage Thermal Sensor (LVTS) is a multiple sensors, multi
+controllers contained in a thermal domain.
+
+A thermal domains can be the MCU or the AP.
+
+Each thermal domains contain up to seven controllers, each thermal
+controller handle up to four thermal sensors.
+
+The LVTS has two Finite State Machines (FSM), one to handle the
+functionin temperatures range like hot or cold temperature and another
+one to handle monitoring trip point. The FSM notifies via interrupts
+when a trip point is crossed.
+
+The interrupt is managed at the thermal controller level, so when an
+interrupt occurs, the driver has to find out which sensor triggered
+such an interrupt.
+
+The sampling of the thermal can be filtered or immediate. For the
+former, the LVTS measures several points and applies a low pass
+filter.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+On MT8195 Tomato Chromebook:
+
+Tested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230209105628.50294-5-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/Kconfig | 16 +
+ drivers/thermal/mediatek/Makefile | 1 +
+ drivers/thermal/mediatek/lvts_thermal.c | 1224 +++++++++++++++++++++++
+ 3 files changed, 1241 insertions(+)
+ create mode 100644 drivers/thermal/mediatek/lvts_thermal.c
+
+--- a/drivers/thermal/mediatek/Kconfig
++++ b/drivers/thermal/mediatek/Kconfig
+@@ -18,4 +18,20 @@ config MTK_SOC_THERMAL
+ This driver configures thermal controllers to collect
+ temperature via AUXADC interface.
+
++config MTK_LVTS_THERMAL
++ tristate "LVTS Thermal Driver for MediaTek SoCs"
++ depends on HAS_IOMEM
++ help
++ Enable this option if you want to get SoC temperature
++ information for supported MediaTek platforms.
++ This driver configures LVTS (Low Voltage Thermal Sensor)
++ thermal controllers to collect temperatures via ASIF
++ (Analog Serial Interface).
++
++config MTK_LVTS_THERMAL_DEBUGFS
++ bool "LVTS thermal debugfs"
++ depends on MTK_LVTS_THERMAL && DEBUG_FS
++ help
++ Enable this option to debug the internals of the device driver.
++
+ endif
+--- a/drivers/thermal/mediatek/Makefile
++++ b/drivers/thermal/mediatek/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o
++obj-$(CONFIG_MTK_LVTS_THERMAL) += lvts_thermal.o
+--- /dev/null
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -0,0 +1,1224 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Balsam CHIHI <bchihi@baylibre.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/delay.h>
++#include <linux/debugfs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/thermal.h>
++#include <dt-bindings/thermal/mediatek,lvts-thermal.h>
++
++#define LVTS_MONCTL0(__base) (__base + 0x0000)
++#define LVTS_MONCTL1(__base) (__base + 0x0004)
++#define LVTS_MONCTL2(__base) (__base + 0x0008)
++#define LVTS_MONINT(__base) (__base + 0x000C)
++#define LVTS_MONINTSTS(__base) (__base + 0x0010)
++#define LVTS_MONIDET0(__base) (__base + 0x0014)
++#define LVTS_MONIDET1(__base) (__base + 0x0018)
++#define LVTS_MONIDET2(__base) (__base + 0x001C)
++#define LVTS_MONIDET3(__base) (__base + 0x0020)
++#define LVTS_H2NTHRE(__base) (__base + 0x0024)
++#define LVTS_HTHRE(__base) (__base + 0x0028)
++#define LVTS_OFFSETH(__base) (__base + 0x0030)
++#define LVTS_OFFSETL(__base) (__base + 0x0034)
++#define LVTS_MSRCTL0(__base) (__base + 0x0038)
++#define LVTS_MSRCTL1(__base) (__base + 0x003C)
++#define LVTS_TSSEL(__base) (__base + 0x0040)
++#define LVTS_CALSCALE(__base) (__base + 0x0048)
++#define LVTS_ID(__base) (__base + 0x004C)
++#define LVTS_CONFIG(__base) (__base + 0x0050)
++#define LVTS_EDATA00(__base) (__base + 0x0054)
++#define LVTS_EDATA01(__base) (__base + 0x0058)
++#define LVTS_EDATA02(__base) (__base + 0x005C)
++#define LVTS_EDATA03(__base) (__base + 0x0060)
++#define LVTS_MSR0(__base) (__base + 0x0090)
++#define LVTS_MSR1(__base) (__base + 0x0094)
++#define LVTS_MSR2(__base) (__base + 0x0098)
++#define LVTS_MSR3(__base) (__base + 0x009C)
++#define LVTS_IMMD0(__base) (__base + 0x00A0)
++#define LVTS_IMMD1(__base) (__base + 0x00A4)
++#define LVTS_IMMD2(__base) (__base + 0x00A8)
++#define LVTS_IMMD3(__base) (__base + 0x00AC)
++#define LVTS_PROTCTL(__base) (__base + 0x00C0)
++#define LVTS_PROTTA(__base) (__base + 0x00C4)
++#define LVTS_PROTTB(__base) (__base + 0x00C8)
++#define LVTS_PROTTC(__base) (__base + 0x00CC)
++#define LVTS_CLKEN(__base) (__base + 0x00E4)
++
++#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38))
++#define LVTS_GROUP_INTERVAL 1
++#define LVTS_FILTER_INTERVAL 1
++#define LVTS_SENSOR_INTERVAL 1
++#define LVTS_HW_FILTER 0x2
++#define LVTS_TSSEL_CONF 0x13121110
++#define LVTS_CALSCALE_CONF 0x300
++#define LVTS_MONINT_CONF 0x9FBF7BDE
++
++#define LVTS_INT_SENSOR0 0x0009001F
++#define LVTS_INT_SENSOR1 0X000881F0
++#define LVTS_INT_SENSOR2 0x00247C00
++#define LVTS_INT_SENSOR3 0x1FC00000
++
++#define LVTS_SENSOR_MAX 4
++#define LVTS_GOLDEN_TEMP_MAX 62
++#define LVTS_GOLDEN_TEMP_DEFAULT 50
++#define LVTS_COEFF_A -250460
++#define LVTS_COEFF_B 250460
++
++#define LVTS_MSR_IMMEDIATE_MODE 0
++#define LVTS_MSR_FILTERED_MODE 1
++
++#define LVTS_HW_SHUTDOWN_MT8195 105000
++
++static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
++static int coeff_b = LVTS_COEFF_B;
++
++struct lvts_sensor_data {
++ int dt_id;
++};
++
++struct lvts_ctrl_data {
++ struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
++ int cal_offset[LVTS_SENSOR_MAX];
++ int hw_tshut_temp;
++ int num_lvts_sensor;
++ int offset;
++ int mode;
++};
++
++struct lvts_data {
++ const struct lvts_ctrl_data *lvts_ctrl;
++ int num_lvts_ctrl;
++};
++
++struct lvts_sensor {
++ struct thermal_zone_device *tz;
++ void __iomem *msr;
++ void __iomem *base;
++ int id;
++ int dt_id;
++};
++
++struct lvts_ctrl {
++ struct lvts_sensor sensors[LVTS_SENSOR_MAX];
++ u32 calibration[LVTS_SENSOR_MAX];
++ u32 hw_tshut_raw_temp;
++ int num_lvts_sensor;
++ int mode;
++ void __iomem *base;
++};
++
++struct lvts_domain {
++ struct lvts_ctrl *lvts_ctrl;
++ struct reset_control *reset;
++ struct clk *clk;
++ int num_lvts_ctrl;
++ void __iomem *base;
++ size_t calib_len;
++ u8 *calib;
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *dom_dentry;
++#endif
++};
++
++#ifdef CONFIG_MTK_LVTS_THERMAL_DEBUGFS
++
++#define LVTS_DEBUG_FS_REGS(__reg) \
++{ \
++ .name = __stringify(__reg), \
++ .offset = __reg(0), \
++}
++
++static const struct debugfs_reg32 lvts_regs[] = {
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL0),
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL1),
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL2),
++ LVTS_DEBUG_FS_REGS(LVTS_MONINT),
++ LVTS_DEBUG_FS_REGS(LVTS_MONINTSTS),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET0),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET1),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET2),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET3),
++ LVTS_DEBUG_FS_REGS(LVTS_H2NTHRE),
++ LVTS_DEBUG_FS_REGS(LVTS_HTHRE),
++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETH),
++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETL),
++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL0),
++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL1),
++ LVTS_DEBUG_FS_REGS(LVTS_TSSEL),
++ LVTS_DEBUG_FS_REGS(LVTS_CALSCALE),
++ LVTS_DEBUG_FS_REGS(LVTS_ID),
++ LVTS_DEBUG_FS_REGS(LVTS_CONFIG),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA00),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA01),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA02),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA03),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR0),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR1),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR2),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR3),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD0),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD1),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD2),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD3),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTCTL),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTA),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTB),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTC),
++ LVTS_DEBUG_FS_REGS(LVTS_CLKEN),
++};
++
++static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
++{
++ struct debugfs_regset32 *regset;
++ struct lvts_ctrl *lvts_ctrl;
++ struct dentry *dentry;
++ char name[64];
++ int i;
++
++ lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
++ if (!lvts_td->dom_dentry)
++ return 0;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ lvts_ctrl = &lvts_td->lvts_ctrl[i];
++
++ sprintf(name, "controller%d", i);
++ dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
++ if (!dentry)
++ continue;
++
++ regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
++ if (!regset)
++ continue;
++
++ regset->base = lvts_ctrl->base;
++ regset->regs = lvts_regs;
++ regset->nregs = ARRAY_SIZE(lvts_regs);
++
++ debugfs_create_regset32("registers", 0400, dentry, regset);
++ }
++
++ return 0;
++}
++
++static void lvts_debugfs_exit(struct lvts_domain *lvts_td)
++{
++ debugfs_remove_recursive(lvts_td->dom_dentry);
++}
++
++#else
++
++static inline int lvts_debugfs_init(struct device *dev,
++ struct lvts_domain *lvts_td)
++{
++ return 0;
++}
++
++static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { }
++
++#endif
++
++static int lvts_raw_to_temp(u32 raw_temp)
++{
++ int temperature;
++
++ temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
++ temperature += coeff_b;
++
++ return temperature;
++}
++
++static u32 lvts_temp_to_raw(int temperature)
++{
++ u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
++
++ raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
++
++ return raw_temp;
++}
++
++static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
++{
++ struct lvts_sensor *lvts_sensor = tz->devdata;
++ void __iomem *msr = lvts_sensor->msr;
++ u32 value;
++
++ /*
++ * Measurement registers:
++ *
++ * LVTS_MSR[0-3] / LVTS_IMMD[0-3]
++ *
++ * Bits:
++ *
++ * 32-17: Unused
++ * 16 : Valid temperature
++ * 15-0 : Raw temperature
++ */
++ value = readl(msr);
++
++ /*
++ * As the thermal zone temperature will read before the
++ * hardware sensor is fully initialized, we have to check the
++ * validity of the temperature returned when reading the
++ * measurement register. The thermal controller will set the
++ * valid bit temperature only when it is totally initialized.
++ *
++ * Otherwise, we may end up with garbage values out of the
++ * functionning temperature and directly jump to a system
++ * shutdown.
++ */
++ if (!(value & BIT(16)))
++ return -EAGAIN;
++
++ *temp = lvts_raw_to_temp(value & 0xFFFF);
++
++ return 0;
++}
++
++static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
++{
++ struct lvts_sensor *lvts_sensor = tz->devdata;
++ void __iomem *base = lvts_sensor->base;
++ u32 raw_low = lvts_temp_to_raw(low);
++ u32 raw_high = lvts_temp_to_raw(high);
++
++ /*
++ * Hot to normal temperature threshold
++ *
++ * LVTS_H2NTHRE
++ *
++ * Bits:
++ *
++ * 14-0 : Raw temperature for threshold
++ */
++ if (low != -INT_MAX) {
++ dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low);
++ writel(raw_low, LVTS_H2NTHRE(base));
++ }
++
++ /*
++ * Hot temperature threshold
++ *
++ * LVTS_HTHRE
++ *
++ * Bits:
++ *
++ * 14-0 : Raw temperature for threshold
++ */
++ dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high);
++ writel(raw_high, LVTS_HTHRE(base));
++
++ return 0;
++}
++
++static irqreturn_t lvts_ctrl_irq_handler(struct lvts_ctrl *lvts_ctrl)
++{
++ irqreturn_t iret = IRQ_NONE;
++ u32 value;
++ u32 masks[] = {
++ LVTS_INT_SENSOR0,
++ LVTS_INT_SENSOR1,
++ LVTS_INT_SENSOR2,
++ LVTS_INT_SENSOR3
++ };
++ int i;
++
++ /*
++ * Interrupt monitoring status
++ *
++ * LVTS_MONINTST
++ *
++ * Bits:
++ *
++ * 31 : Interrupt for stage 3
++ * 30 : Interrupt for stage 2
++ * 29 : Interrupt for state 1
++ * 28 : Interrupt using filter on sensor 3
++ *
++ * 27 : Interrupt using immediate on sensor 3
++ * 26 : Interrupt normal to hot on sensor 3
++ * 25 : Interrupt high offset on sensor 3
++ * 24 : Interrupt low offset on sensor 3
++ *
++ * 23 : Interrupt hot threshold on sensor 3
++ * 22 : Interrupt cold threshold on sensor 3
++ * 21 : Interrupt using filter on sensor 2
++ * 20 : Interrupt using filter on sensor 1
++ *
++ * 19 : Interrupt using filter on sensor 0
++ * 18 : Interrupt using immediate on sensor 2
++ * 17 : Interrupt using immediate on sensor 1
++ * 16 : Interrupt using immediate on sensor 0
++ *
++ * 15 : Interrupt device access timeout interrupt
++ * 14 : Interrupt normal to hot on sensor 2
++ * 13 : Interrupt high offset interrupt on sensor 2
++ * 12 : Interrupt low offset interrupt on sensor 2
++ *
++ * 11 : Interrupt hot threshold on sensor 2
++ * 10 : Interrupt cold threshold on sensor 2
++ * 9 : Interrupt normal to hot on sensor 1
++ * 8 : Interrupt high offset interrupt on sensor 1
++ *
++ * 7 : Interrupt low offset interrupt on sensor 1
++ * 6 : Interrupt hot threshold on sensor 1
++ * 5 : Interrupt cold threshold on sensor 1
++ * 4 : Interrupt normal to hot on sensor 0
++ *
++ * 3 : Interrupt high offset interrupt on sensor 0
++ * 2 : Interrupt low offset interrupt on sensor 0
++ * 1 : Interrupt hot threshold on sensor 0
++ * 0 : Interrupt cold threshold on sensor 0
++ *
++ * We are interested in the sensor(s) responsible of the
++ * interrupt event. We update the thermal framework with the
++ * thermal zone associated with the sensor. The framework will
++ * take care of the rest whatever the kind of interrupt, we
++ * are only interested in which sensor raised the interrupt.
++ *
++ * sensor 3 interrupt: 0001 1111 1100 0000 0000 0000 0000 0000
++ * => 0x1FC00000
++ * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000
++ * => 0x00247C00
++ * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000
++ * => 0X000881F0
++ * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111
++ * => 0x0009001F
++ */
++ value = readl(LVTS_MONINTSTS(lvts_ctrl->base));
++
++ /*
++ * Let's figure out which sensors raised the interrupt
++ *
++ * NOTE: the masks array must be ordered with the index
++ * corresponding to the sensor id eg. index=0, mask for
++ * sensor0.
++ */
++ for (i = 0; i < ARRAY_SIZE(masks); i++) {
++
++ if (!(value & masks[i]))
++ continue;
++
++ thermal_zone_device_update(lvts_ctrl->sensors[i].tz,
++ THERMAL_TRIP_VIOLATED);
++ iret = IRQ_HANDLED;
++ }
++
++ /*
++ * Write back to clear the interrupt status (W1C)
++ */
++ writel(value, LVTS_MONINTSTS(lvts_ctrl->base));
++
++ return iret;
++}
++
++/*
++ * Temperature interrupt handler. Even if the driver supports more
++ * interrupt modes, we use the interrupt when the temperature crosses
++ * the hot threshold the way up and the way down (modulo the
++ * hysteresis).
++ *
++ * Each thermal domain has a couple of interrupts, one for hardware
++ * reset and another one for all the thermal events happening on the
++ * different sensors.
++ *
++ * The interrupt is configured for thermal events when crossing the
++ * hot temperature limit. At each interrupt, we check in every
++ * controller if there is an interrupt pending.
++ */
++static irqreturn_t lvts_irq_handler(int irq, void *data)
++{
++ struct lvts_domain *lvts_td = data;
++ irqreturn_t aux, iret = IRQ_NONE;
++ int i;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl);
++ if (aux != IRQ_HANDLED)
++ continue;
++
++ iret = IRQ_HANDLED;
++ }
++
++ return iret;
++}
++
++static struct thermal_zone_device_ops lvts_ops = {
++ .get_temp = lvts_get_temp,
++ .set_trips = lvts_set_trips,
++};
++
++static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
++ const struct lvts_ctrl_data *lvts_ctrl_data)
++{
++ struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors;
++ void __iomem *msr_regs[] = {
++ LVTS_MSR0(lvts_ctrl->base),
++ LVTS_MSR1(lvts_ctrl->base),
++ LVTS_MSR2(lvts_ctrl->base),
++ LVTS_MSR3(lvts_ctrl->base)
++ };
++
++ void __iomem *imm_regs[] = {
++ LVTS_IMMD0(lvts_ctrl->base),
++ LVTS_IMMD1(lvts_ctrl->base),
++ LVTS_IMMD2(lvts_ctrl->base),
++ LVTS_IMMD3(lvts_ctrl->base)
++ };
++
++ int i;
++
++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) {
++
++ int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id;
++
++ /*
++ * At this point, we don't know which id matches which
++ * sensor. Let's set arbitrally the id from the index.
++ */
++ lvts_sensor[i].id = i;
++
++ /*
++ * The thermal zone registration will set the trip
++ * point interrupt in the thermal controller
++ * register. But this one will be reset in the
++ * initialization after. So we need to post pone the
++ * thermal zone creation after the controller is
++ * setup. For this reason, we store the device tree
++ * node id from the data in the sensor structure
++ */
++ lvts_sensor[i].dt_id = dt_id;
++
++ /*
++ * We assign the base address of the thermal
++ * controller as a back pointer. So it will be
++ * accessible from the different thermal framework ops
++ * as we pass the lvts_sensor pointer as thermal zone
++ * private data.
++ */
++ lvts_sensor[i].base = lvts_ctrl->base;
++
++ /*
++ * 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];
++ };
++
++ lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
++
++ return 0;
++}
++
++/*
++ * The efuse blob values follows the sensor enumeration per thermal
++ * controller. The decoding of the stream is as follow:
++ *
++ * <--?-> <----big0 ???---> <-sensor0-> <-0->
++ * ------------------------------------------
++ * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 |
++ * ------------------------------------------
++ *
++ * <--sensor1--><-0-> <----big1 ???---> <-sen
++ * ------------------------------------------
++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
++ * ------------------------------------------
++ *
++ * sor0-> <-0-> <-sensor1-> <-0-> ..........
++ * ------------------------------------------
++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
++ * ------------------------------------------
++ *
++ * And so on ...
++ *
++ * The data description gives the offset of the calibration data in
++ * this bytes stream for each sensor.
++ *
++ * Each thermal controller can handle up to 4 sensors max, we don't
++ * care if there are less as the array of calibration is sized to 4
++ * anyway. The unused sensor slot will be zeroed.
++ */
++static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
++ const struct lvts_ctrl_data *lvts_ctrl_data,
++ u8 *efuse_calibration)
++{
++ int i;
++
++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++)
++ memcpy(&lvts_ctrl->calibration[i],
++ efuse_calibration + lvts_ctrl_data->cal_offset[i], 2);
++
++ return 0;
++}
++
++/*
++ * The efuse bytes stream can be split into different chunk of
++ * nvmems. This function reads and concatenate those into a single
++ * buffer so it can be read sequentially when initializing the
++ * calibration data.
++ */
++static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ struct device_node *np = dev_of_node(dev);
++ struct nvmem_cell *cell;
++ struct property *prop;
++ const char *cell_name;
++
++ of_property_for_each_string(np, "nvmem-cell-names", prop, cell_name) {
++ size_t len;
++ u8 *efuse;
++
++ cell = of_nvmem_cell_get(np, cell_name);
++ if (IS_ERR(cell)) {
++ dev_err(dev, "Failed to get cell '%s'\n", cell_name);
++ return PTR_ERR(cell);
++ }
++
++ efuse = nvmem_cell_read(cell, &len);
++
++ nvmem_cell_put(cell);
++
++ if (IS_ERR(efuse)) {
++ dev_err(dev, "Failed to read cell '%s'\n", cell_name);
++ return PTR_ERR(efuse);
++ }
++
++ lvts_td->calib = devm_krealloc(dev, lvts_td->calib,
++ lvts_td->calib_len + len, GFP_KERNEL);
++ if (!lvts_td->calib)
++ return -ENOMEM;
++
++ memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
++
++ lvts_td->calib_len += len;
++
++ kfree(efuse);
++ }
++
++ return 0;
++}
++
++static int lvts_golden_temp_init(struct device *dev, u32 *value)
++{
++ u32 gt;
++
++ gt = (*value) >> 24;
++
++ if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
++ golden_temp = gt;
++
++ coeff_b = golden_temp * 500 + LVTS_COEFF_B;
++
++ return 0;
++}
++
++static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ size_t size = sizeof(*lvts_td->lvts_ctrl) * lvts_data->num_lvts_ctrl;
++ struct lvts_ctrl *lvts_ctrl;
++ int i, ret;
++
++ /*
++ * Create the calibration bytes stream from efuse data
++ */
++ ret = lvts_calibration_read(dev, lvts_td, lvts_data);
++ if (ret)
++ return ret;
++
++ /*
++ * The golden temp information is contained in the first chunk
++ * of efuse data.
++ */
++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
++ if (ret)
++ return ret;
++
++ lvts_ctrl = devm_kzalloc(dev, size, GFP_KERNEL);
++ if (!lvts_ctrl)
++ return -ENOMEM;
++
++ for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
++
++ lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
++
++ ret = lvts_sensor_init(dev, &lvts_ctrl[i],
++ &lvts_data->lvts_ctrl[i]);
++ if (ret)
++ return ret;
++
++ ret = lvts_calibration_init(dev, &lvts_ctrl[i],
++ &lvts_data->lvts_ctrl[i],
++ lvts_td->calib);
++ if (ret)
++ return ret;
++
++ /*
++ * The mode the ctrl will use to read the temperature
++ * (filtered or immediate)
++ */
++ lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode;
++
++ /*
++ * The temperature to raw temperature must be done
++ * after initializing the calibration.
++ */
++ lvts_ctrl[i].hw_tshut_raw_temp =
++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++ }
++
++ /*
++ * We no longer need the efuse bytes stream, let's free it
++ */
++ devm_kfree(dev, lvts_td->calib);
++
++ lvts_td->lvts_ctrl = lvts_ctrl;
++ lvts_td->num_lvts_ctrl = lvts_data->num_lvts_ctrl;
++
++ return 0;
++}
++
++/*
++ * At this point the configuration register is the only place in the
++ * driver where we write multiple values. Per hardware constraint,
++ * each write in the configuration register must be separated by a
++ * delay of 2 us.
++ */
++static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, u32 *cmds, int nr_cmds)
++{
++ int i;
++
++ /*
++ * Configuration register
++ */
++ for (i = 0; i < nr_cmds; i++) {
++ writel(cmds[i], LVTS_CONFIG(lvts_ctrl->base));
++ usleep_range(2, 4);
++ }
++}
++
++static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
++{
++ /*
++ * LVTS_PROTCTL : Thermal Protection Sensor Selection
++ *
++ * Bits:
++ *
++ * 19-18 : Sensor to base the protection on
++ * 17-16 : Strategy:
++ * 00 : Average of 4 sensors
++ * 01 : Max of 4 sensors
++ * 10 : Selected sensor with bits 19-18
++ * 11 : Reserved
++ */
++ writel(BIT(16), LVTS_PROTCTL(lvts_ctrl->base));
++
++ /*
++ * LVTS_PROTTA : Stage 1 temperature threshold
++ * LVTS_PROTTB : Stage 2 temperature threshold
++ * LVTS_PROTTC : Stage 3 temperature threshold
++ *
++ * Bits:
++ *
++ * 14-0: Raw temperature threshold
++ *
++ * writel(0x0, LVTS_PROTTA(lvts_ctrl->base));
++ * writel(0x0, LVTS_PROTTB(lvts_ctrl->base));
++ */
++ writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base));
++
++ /*
++ * LVTS_MONINT : Interrupt configuration register
++ *
++ * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
++ * register, except we set the bits to enable the interrupt.
++ */
++ writel(LVTS_MONINT_CONF, LVTS_MONINT(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_domain_reset(struct device *dev, struct reset_control *reset)
++{
++ int ret;
++
++ ret = reset_control_assert(reset);
++ if (ret)
++ return ret;
++
++ return reset_control_deassert(reset);
++}
++
++/*
++ * Enable or disable the clocks of a specified thermal controller
++ */
++static int lvts_ctrl_set_enable(struct lvts_ctrl *lvts_ctrl, int enable)
++{
++ /*
++ * LVTS_CLKEN : Internal LVTS clock
++ *
++ * Bits:
++ *
++ * 0 : enable / disable clock
++ */
++ writel(enable, LVTS_CLKEN(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ u32 id, cmds[] = { 0xC103FFFF, 0xC502FF55 };
++
++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
++
++ /*
++ * LVTS_ID : Get ID and status of the thermal controller
++ *
++ * Bits:
++ *
++ * 0-5 : thermal controller id
++ * 7 : thermal controller connection is valid
++ */
++ id = readl(LVTS_ID(lvts_ctrl->base));
++ if (!(id & BIT(7)))
++ return -EIO;
++
++ return 0;
++}
++
++static int lvts_ctrl_initialize(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ /*
++ * Write device mask: 0xC1030000
++ */
++ u32 cmds[] = {
++ 0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1,
++ 0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300,
++ 0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC,
++ 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
++ };
++
++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
++
++ return 0;
++}
++
++static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ int i;
++ void __iomem *lvts_edata[] = {
++ LVTS_EDATA00(lvts_ctrl->base),
++ LVTS_EDATA01(lvts_ctrl->base),
++ LVTS_EDATA02(lvts_ctrl->base),
++ LVTS_EDATA03(lvts_ctrl->base)
++ };
++
++ /*
++ * LVTS_EDATA0X : Efuse calibration reference value for sensor X
++ *
++ * Bits:
++ *
++ * 20-0 : Efuse value for normalization data
++ */
++ for (i = 0; i < LVTS_SENSOR_MAX; i++)
++ writel(lvts_ctrl->calibration[i], lvts_edata[i]);
++
++ return 0;
++}
++
++static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ u32 value;
++
++ /*
++ * LVTS_TSSEL : Sensing point index numbering
++ *
++ * Bits:
++ *
++ * 31-24: ADC Sense 3
++ * 23-16: ADC Sense 2
++ * 15-8 : ADC Sense 1
++ * 7-0 : ADC Sense 0
++ */
++ value = LVTS_TSSEL_CONF;
++ writel(value, LVTS_TSSEL(lvts_ctrl->base));
++
++ /*
++ * LVTS_CALSCALE : ADC voltage round
++ */
++ value = 0x300;
++ value = LVTS_CALSCALE_CONF;
++
++ /*
++ * LVTS_MSRCTL0 : Sensor filtering strategy
++ *
++ * Filters:
++ *
++ * 000 : One sample
++ * 001 : Avg 2 samples
++ * 010 : 4 samples, drop min and max, avg 2 samples
++ * 011 : 6 samples, drop min and max, avg 4 samples
++ * 100 : 10 samples, drop min and max, avg 8 samples
++ * 101 : 18 samples, drop min and max, avg 16 samples
++ *
++ * Bits:
++ *
++ * 0-2 : Sensor0 filter
++ * 3-5 : Sensor1 filter
++ * 6-8 : Sensor2 filter
++ * 9-11 : Sensor3 filter
++ */
++ value = LVTS_HW_FILTER << 9 | LVTS_HW_FILTER << 6 |
++ LVTS_HW_FILTER << 3 | LVTS_HW_FILTER;
++ writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
++
++ /*
++ * LVTS_MSRCTL1 : Measurement control
++ *
++ * Bits:
++ *
++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
++ *
++ * That configuration will ignore the filtering and the delays
++ * introduced below in MONCTL1 and MONCTL2
++ */
++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
++ value = BIT(9) | BIT(6) | BIT(5) | BIT(4);
++ writel(value, LVTS_MSRCTL1(lvts_ctrl->base));
++ }
++
++ /*
++ * LVTS_MONCTL1 : Period unit and group interval configuration
++ *
++ * The clock source of LVTS thermal controller is 26MHz.
++ *
++ * The period unit is a time base for all the interval delays
++ * specified in the registers. By default we use 12. The time
++ * conversion is done by multiplying by 256 and 1/26.10^6
++ *
++ * An interval delay multiplied by the period unit gives the
++ * duration in seconds.
++ *
++ * - Filter interval delay is a delay between two samples of
++ * the same sensor.
++ *
++ * - Sensor interval delay is a delay between two samples of
++ * different sensors.
++ *
++ * - Group interval delay is a delay between different rounds.
++ *
++ * For example:
++ * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1,
++ * and two sensors, TS1 and TS2, are in a LVTS thermal controller
++ * and then
++ * Period unit time = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us
++ * Filter interval delay = 1 * Period unit = 118.149us
++ * Sensor interval delay = 2 * Period unit = 236.298us
++ * Group interval delay = 1 * Period unit = 118.149us
++ *
++ * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1...
++ * <--> Filter interval delay
++ * <--> Sensor interval delay
++ * <--> Group interval delay
++ * Bits:
++ * 29 - 20 : Group interval
++ * 16 - 13 : Send a single interrupt when crossing the hot threshold (1)
++ * or an interrupt everytime the hot threshold is crossed (0)
++ * 9 - 0 : Period unit
++ *
++ */
++ value = LVTS_GROUP_INTERVAL << 20 | LVTS_PERIOD_UNIT;
++ writel(value, LVTS_MONCTL1(lvts_ctrl->base));
++
++ /*
++ * LVTS_MONCTL2 : Filtering and sensor interval
++ *
++ * Bits:
++ *
++ * 25-16 : Interval unit in PERIOD_UNIT between sample on
++ * the same sensor, filter interval
++ * 9-0 : Interval unit in PERIOD_UNIT between each sensor
++ *
++ */
++ value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL;
++ writel(value, LVTS_MONCTL2(lvts_ctrl->base));
++
++ return lvts_irq_init(lvts_ctrl);
++}
++
++static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ struct lvts_sensor *lvts_sensors = lvts_ctrl->sensors;
++ struct thermal_zone_device *tz;
++ u32 sensor_map = 0;
++ int i;
++
++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
++
++ int dt_id = lvts_sensors[i].dt_id;
++
++ tz = devm_thermal_of_zone_register(dev, dt_id, &lvts_sensors[i],
++ &lvts_ops);
++ if (IS_ERR(tz)) {
++ /*
++ * This thermal zone is not described in the
++ * device tree. It is not an error from the
++ * thermal OF code POV, we just continue.
++ */
++ if (PTR_ERR(tz) == -ENODEV)
++ continue;
++
++ return PTR_ERR(tz);
++ }
++
++ /*
++ * The thermal zone pointer will be needed in the
++ * interrupt handler, we store it in the sensor
++ * structure. The thermal domain structure will be
++ * passed to the interrupt handler private data as the
++ * interrupt is shared for all the controller
++ * belonging to the thermal domain.
++ */
++ lvts_sensors[i].tz = tz;
++
++ /*
++ * This sensor was correctly associated with a thermal
++ * zone, let's set the corresponding bit in the sensor
++ * map, so we can enable the temperature monitoring in
++ * the hardware thermal controller.
++ */
++ sensor_map |= BIT(i);
++ }
++
++ /*
++ * Bits:
++ * 9: Single point access flow
++ * 0-3: Enable sensing point 0-3
++ *
++ * The initialization of the thermal zones give us
++ * which sensor point to enable. If any thermal zone
++ * was not described in the device tree, it won't be
++ * enabled here in the sensor map.
++ */
++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ struct lvts_ctrl *lvts_ctrl;
++ int i, ret;
++
++ ret = lvts_ctrl_init(dev, lvts_td, lvts_data);
++ if (ret)
++ return ret;
++
++ ret = lvts_domain_reset(dev, lvts_td->reset);
++ if (ret) {
++ dev_dbg(dev, "Failed to reset domain");
++ return ret;
++ }
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ lvts_ctrl = &lvts_td->lvts_ctrl[i];
++
++ /*
++ * Initialization steps:
++ *
++ * - Enable the clock
++ * - Connect to the LVTS
++ * - Initialize the LVTS
++ * - Prepare the calibration data
++ * - Select monitored sensors
++ * [ Configure sampling ]
++ * [ Configure the interrupt ]
++ * - Start measurement
++ */
++ ret = lvts_ctrl_set_enable(lvts_ctrl, true);
++ if (ret) {
++ dev_dbg(dev, "Failed to enable LVTS clock");
++ return ret;
++ }
++
++ ret = lvts_ctrl_connect(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to connect to LVTS controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_initialize(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to initialize controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_calibrate(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to calibrate controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_configure(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to configure controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_start(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to start controller");
++ return ret;
++ }
++ }
++
++ return lvts_debugfs_init(dev, lvts_td);
++}
++
++static int lvts_probe(struct platform_device *pdev)
++{
++ const struct lvts_data *lvts_data;
++ struct lvts_domain *lvts_td;
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ int irq, ret;
++
++ lvts_td = devm_kzalloc(dev, sizeof(*lvts_td), GFP_KERNEL);
++ if (!lvts_td)
++ return -ENOMEM;
++
++ lvts_data = of_device_get_match_data(dev);
++
++ lvts_td->clk = devm_clk_get_enabled(dev, NULL);
++ if (IS_ERR(lvts_td->clk))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n");
++
++ res = platform_get_mem_or_io(pdev, 0);
++ if (!res)
++ return dev_err_probe(dev, (-ENXIO), "No IO resource\n");
++
++ lvts_td->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
++ if (IS_ERR(lvts_td->base))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n");
++
++ lvts_td->reset = devm_reset_control_get_by_index(dev, 0);
++ if (IS_ERR(lvts_td->reset))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n");
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return dev_err_probe(dev, irq, "No irq resource\n");
++
++ ret = lvts_domain_init(dev, lvts_td, lvts_data);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
++
++ /*
++ * At this point the LVTS is initialized and enabled. We can
++ * safely enable the interrupt.
++ */
++ ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler,
++ IRQF_ONESHOT, dev_name(dev), lvts_td);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to request interrupt\n");
++
++ platform_set_drvdata(pdev, lvts_td);
++
++ return 0;
++}
++
++static int lvts_remove(struct platform_device *pdev)
++{
++ struct lvts_domain *lvts_td;
++ int i;
++
++ lvts_td = platform_get_drvdata(pdev);
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
++
++ lvts_debugfs_exit(lvts_td);
++
++ return 0;
++}
++
++static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = {
++ {
++ .cal_offset = { 0x04, 0x07 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_BIG_CPU0 },
++ { .dt_id = MT8195_MCU_BIG_CPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x0d, 0x10 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_BIG_CPU2 },
++ { .dt_id = MT8195_MCU_BIG_CPU3 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x16, 0x19, 0x1c, 0x1f },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_LITTLE_CPU0 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU1 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU2 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU3 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ }
++};
++
++static const struct lvts_data mt8195_lvts_mcu_data = {
++ .lvts_ctrl = mt8195_lvts_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl),
++};
++
++static const struct of_device_id lvts_of_match[] = {
++ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
++ {},
++};
++MODULE_DEVICE_TABLE(of, lvts_of_match);
++
++static struct platform_driver lvts_driver = {
++ .probe = lvts_probe,
++ .remove = lvts_remove,
++ .driver = {
++ .name = "mtk-lvts-thermal",
++ .of_match_table = lvts_of_match,
++ },
++};
++module_platform_driver(lvts_driver);
++
++MODULE_AUTHOR("Balsam CHIHI <bchihi@baylibre.com>");
++MODULE_DESCRIPTION("MediaTek LVTS Thermal Driver");
++MODULE_LICENSE("GPL");
--- /dev/null
+From 498e2f7a6e69dcbca24715de2b4b97569fdfeff4 Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:24 +0100
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controllers
+
+Add LVTS thermal controllers dt-binding definition for mt8192 and mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20230209105628.50294-3-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ .../thermal/mediatek,lvts-thermal.yaml | 142 ++++++++++++++++++
+ .../thermal/mediatek,lvts-thermal.h | 19 +++
+ 2 files changed, 161 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+ create mode 100644 include/dt-bindings/thermal/mediatek,lvts-thermal.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+@@ -0,0 +1,142 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/thermal/mediatek,lvts-thermal.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek SoC Low Voltage Thermal Sensor (LVTS)
++
++maintainers:
++ - Balsam CHIHI <bchihi@baylibre.com>
++
++description: |
++ LVTS is a thermal management architecture composed of three subsystems,
++ a Sensing device - Thermal Sensing Micro Circuit Unit (TSMCU),
++ a Converter - Low Voltage Thermal Sensor converter (LVTS), and
++ a Digital controller (LVTS_CTRL).
++
++properties:
++ compatible:
++ enum:
++ - mediatek,mt8192-lvts-ap
++ - mediatek,mt8192-lvts-mcu
++ - mediatek,mt8195-lvts-ap
++ - mediatek,mt8195-lvts-mcu
++
++ reg:
++ maxItems: 1
++
++ interrupts:
++ maxItems: 1
++
++ clocks:
++ maxItems: 1
++
++ resets:
++ maxItems: 1
++ description: LVTS reset for clearing temporary data on AP/MCU.
++
++ nvmem-cells:
++ minItems: 1
++ items:
++ - description: Calibration eFuse data 1 for LVTS
++ - description: Calibration eFuse data 2 for LVTS
++
++ nvmem-cell-names:
++ minItems: 1
++ items:
++ - const: lvts-calib-data-1
++ - const: lvts-calib-data-2
++
++ "#thermal-sensor-cells":
++ const: 1
++
++allOf:
++ - $ref: thermal-sensor.yaml#
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ enum:
++ - mediatek,mt8192-lvts-ap
++ - mediatek,mt8192-lvts-mcu
++ then:
++ properties:
++ nvmem-cells:
++ maxItems: 1
++
++ nvmem-cell-names:
++ maxItems: 1
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ enum:
++ - mediatek,mt8195-lvts-ap
++ - mediatek,mt8195-lvts-mcu
++ then:
++ properties:
++ nvmem-cells:
++ minItems: 2
++
++ nvmem-cell-names:
++ minItems: 2
++
++required:
++ - compatible
++ - reg
++ - interrupts
++ - clocks
++ - resets
++ - nvmem-cells
++ - nvmem-cell-names
++ - "#thermal-sensor-cells"
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/interrupt-controller/arm-gic.h>
++ #include <dt-bindings/clock/mt8195-clk.h>
++ #include <dt-bindings/reset/mt8195-resets.h>
++ #include <dt-bindings/thermal/mediatek,lvts-thermal.h>
++
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ lvts_mcu: thermal-sensor@11278000 {
++ compatible = "mediatek,mt8195-lvts-mcu";
++ reg = <0 0x11278000 0 0x1000>;
++ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
++ clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
++ resets = <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
++ nvmem-cells = <&lvts_efuse_data1 &lvts_efuse_data2>;
++ nvmem-cell-names = "lvts-calib-data-1", "lvts-calib-data-2";
++ #thermal-sensor-cells = <1>;
++ };
++ };
++
++ thermal_zones: thermal-zones {
++ cpu0-thermal {
++ polling-delay = <1000>;
++ polling-delay-passive = <250>;
++ thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>;
++
++ trips {
++ cpu0_alert: trip-alert {
++ temperature = <85000>;
++ hysteresis = <2000>;
++ type = "passive";
++ };
++
++ cpu0_crit: trip-crit {
++ temperature = <100000>;
++ hysteresis = <2000>;
++ type = "critical";
++ };
++ };
++ };
++ };
+--- /dev/null
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Balsam CHIHI <bchihi@baylibre.com>
++ */
++
++#ifndef __MEDIATEK_LVTS_DT_H
++#define __MEDIATEK_LVTS_DT_H
++
++#define MT8195_MCU_BIG_CPU0 0
++#define MT8195_MCU_BIG_CPU1 1
++#define MT8195_MCU_BIG_CPU2 2
++#define MT8195_MCU_BIG_CPU3 3
++#define MT8195_MCU_LITTLE_CPU0 4
++#define MT8195_MCU_LITTLE_CPU1 5
++#define MT8195_MCU_LITTLE_CPU2 6
++#define MT8195_MCU_LITTLE_CPU3 7
++
++#endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From 05aaa7fdb0736262e224369b9b9f1410320fc71b Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 7 Mar 2023 16:45:21 +0100
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add AP domain to LVTS thermal
+ controllers for mt8195
+
+Add AP Domain to LVTS thermal controllers dt-binding definition for mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230307154524.118541-2-bchihi@baylibre.com
+---
+ include/dt-bindings/thermal/mediatek,lvts-thermal.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -16,4 +16,14 @@
+ #define MT8195_MCU_LITTLE_CPU2 6
+ #define MT8195_MCU_LITTLE_CPU3 7
+
++#define MT8195_AP_VPU0 8
++#define MT8195_AP_VPU1 9
++#define MT8195_AP_GPU0 10
++#define MT8195_AP_GPU1 11
++#define MT8195_AP_VDEC 12
++#define MT8195_AP_IMG 13
++#define MT8195_AP_INFRA 14
++#define MT8195_AP_CAM0 15
++#define MT8195_AP_CAM1 16
++
+ #endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From a6ff3c0021468721b96e84892a8cae24bde8d65f Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:29 +0100
+Subject: [PATCH] thermal/core: Add a thermal zone 'devdata' accessor
+
+The thermal zone device structure is exposed to the different drivers
+and obviously they access the internals while that should be
+restricted to the core thermal code.
+
+In order to self-encapsulate the thermal core code, we need to prevent
+the drivers accessing directly the thermal zone structure and provide
+accessor functions to deal with.
+
+Provide an accessor to the 'devdata' structure and make use of it in
+the different drivers.
+
+No functional changes intended.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/thermal_core.c | 6 ++++++
+ include/linux/thermal.h | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1346,6 +1346,12 @@ struct thermal_zone_device *thermal_zone
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_device_register);
+
++void *thermal_zone_device_priv(struct thermal_zone_device *tzd)
++{
++ return tzd->devdata;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_device_priv);
++
+ /**
+ * thermal_zone_device_unregister - removes the registered thermal zone device
+ * @tz: the thermal zone device to remove
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -346,6 +346,8 @@ thermal_zone_device_register_with_trips(
+ void *, struct thermal_zone_device_ops *,
+ struct thermal_zone_params *, int, int);
+
++void *thermal_zone_device_priv(struct thermal_zone_device *tzd);
++
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+ struct thermal_cooling_device *,
+ unsigned long, unsigned long,
+@@ -417,6 +419,11 @@ static inline int thermal_zone_get_offse
+ struct thermal_zone_device *tz)
+ { return -ENODEV; }
+
++static inline void *thermal_zone_device_priv(struct thermal_zone_device *tz)
++{
++ return NULL;
++}
++
+ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+ { return -ENODEV; }
+
--- /dev/null
+From 072e35c98806100182c0a7263cf4cba09ce43463 Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:38 +0100
+Subject: [PATCH] thermal/core: Add thermal_zone_device structure 'type'
+ accessor
+
+The thermal zone device structure is exposed via the exported
+thermal.h header. This structure should stay private the thermal core
+code. In order to encapsulate the structure, let's add an accessor to
+get the 'type' of the thermal zone.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/thermal_core.c | 6 ++++++
+ include/linux/thermal.h | 6 ++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1352,6 +1352,12 @@ void *thermal_zone_device_priv(struct th
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_device_priv);
+
++const char *thermal_zone_device_type(struct thermal_zone_device *tzd)
++{
++ return tzd->type;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_device_type);
++
+ /**
+ * thermal_zone_device_unregister - removes the registered thermal zone device
+ * @tz: the thermal zone device to remove
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -347,6 +347,7 @@ thermal_zone_device_register_with_trips(
+ struct thermal_zone_params *, int, int);
+
+ void *thermal_zone_device_priv(struct thermal_zone_device *tzd);
++const char *thermal_zone_device_type(struct thermal_zone_device *tzd);
+
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+ struct thermal_cooling_device *,
+@@ -423,6 +424,11 @@ static inline void *thermal_zone_device_
+ {
+ return NULL;
+ }
++
++static inline const char *thermal_zone_device_type(struct thermal_zone_device *tzd)
++{
++ return NULL;
++}
+
+ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+ { return -ENODEV; }
--- /dev/null
+From 7d78bab533eb9aa0e5240e25a204e8f416723ed6 Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:30 +0100
+Subject: [PATCH 07/42] thermal/core: Use the thermal zone 'devdata' accessor
+ in thermal located drivers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The thermal zone device structure is exposed to the different drivers
+and obviously they access the internals while that should be
+restricted to the core thermal code.
+
+In order to self-encapsulate the thermal core code, we need to prevent
+the drivers accessing directly the thermal zone structure and provide
+accessor functions to deal with.
+
+Use the devdata accessor introduced in the previous patch.
+
+No functional changes intended.
+
+[skipped drivers not relevant for mediatek target]
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> #R-Car
+Acked-by: Mark Brown <broonie@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek auxadc and lvts
+Reviewed-by: Balsam CHIHI <bchihi@baylibre.com> #Mediatek lvts
+Reviewed-by: Adam Ward <DLG-Adam.Ward.opensource@dm.renesas.com> #da9062
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> #spread
+Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> #sun8i_thermal
+Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com> #Broadcom
+Reviewed-by: Dhruva Gole <d-gole@ti.com> # K3 bandgap
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Heiko Stuebner <heiko@sntech.de> #rockchip
+Reviewed-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> #uniphier
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ drivers/thermal/mediatek/lvts_thermal.c | 4 ++--
+ 43 files changed, 71 insertions(+), 73 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -763,7 +763,7 @@ static int mtk_thermal_bank_temperature(
+
+ static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
+ {
+- struct mtk_thermal *mt = tz->devdata;
++ struct mtk_thermal *mt = thermal_zone_device_priv(tz);
+ int i;
+ int tempmax = INT_MIN;
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -252,7 +252,7 @@ static u32 lvts_temp_to_raw(int temperat
+
+ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+- struct lvts_sensor *lvts_sensor = tz->devdata;
++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
+
+@@ -290,7 +290,7 @@ static int lvts_get_temp(struct thermal_
+
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+- struct lvts_sensor *lvts_sensor = tz->devdata;
++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *base = lvts_sensor->base;
+ u32 raw_low = lvts_temp_to_raw(low);
+ u32 raw_high = lvts_temp_to_raw(high);
--- /dev/null
+From cc9c60e9cfeeac45d63361fa8c085c43c4bdfe3a Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:36 +0100
+Subject: [PATCH 08/42] thermal/hwmon: Use the right device for
+ devm_thermal_add_hwmon_sysfs()
+
+The devres variant of thermal_add_hwmon_sysfs() only takes the thermal
+zone structure pointer as parameter.
+
+Actually, it uses the tz->device to add it in the devres list.
+
+It is preferable to use the device registering the thermal zone
+instead of the thermal zone device itself. That prevents the driver
+accessing the thermal zone structure internals and it is from my POV
+more correct regarding how devm_ is used.
+
+[skipped imx thermal which did not apply cleanly and irrelevant on
+mediatek target]
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Acked-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> #amlogic_thermal
+Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> #sun8i_thermal
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek auxadc
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/amlogic_thermal.c | 2 +-
+ drivers/thermal/imx_sc_thermal.c | 2 +-
+ drivers/thermal/k3_bandgap.c | 2 +-
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ drivers/thermal/qcom/qcom-spmi-adc-tm5.c | 2 +-
+ drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 2 +-
+ drivers/thermal/qcom/tsens.c | 2 +-
+ drivers/thermal/qoriq_thermal.c | 2 +-
+ drivers/thermal/sun8i_thermal.c | 2 +-
+ drivers/thermal/tegra/tegra30-tsensor.c | 2 +-
+ drivers/thermal/thermal_hwmon.c | 4 ++--
+ drivers/thermal/thermal_hwmon.h | 4 ++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 13 files changed, 15 insertions(+), 15 deletions(-)
+
+--- a/drivers/thermal/amlogic_thermal.c
++++ b/drivers/thermal/amlogic_thermal.c
+@@ -286,7 +286,7 @@ static int amlogic_thermal_probe(struct
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(pdata->tzd))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd))
+ dev_warn(&pdev->dev, "Failed to add hwmon sysfs attributes\n");
+
+ ret = amlogic_thermal_initialize(pdata);
+--- a/drivers/thermal/imx_sc_thermal.c
++++ b/drivers/thermal/imx_sc_thermal.c
+@@ -120,7 +120,7 @@ static int imx_sc_thermal_probe(struct p
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(sensor->tzd))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, sensor->tzd))
+ dev_warn(&pdev->dev, "failed to add hwmon sysfs attributes\n");
+ }
+
+--- a/drivers/thermal/k3_bandgap.c
++++ b/drivers/thermal/k3_bandgap.c
+@@ -222,7 +222,7 @@ static int k3_bandgap_probe(struct platf
+ goto err_alloc;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(data[id].tzd))
++ if (devm_thermal_add_hwmon_sysfs(dev, data[id].tzd))
+ dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
+ }
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1210,7 +1210,7 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_peri_therm;
+ }
+
+- ret = devm_thermal_add_hwmon_sysfs(tzdev);
++ ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev);
+ if (ret)
+ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+
+--- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
++++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
+@@ -688,7 +688,7 @@ static int adc_tm5_register_tzd(struct a
+ return PTR_ERR(tzd);
+ }
+ adc_tm->channels[i].tzd = tzd;
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(adc_tm->dev, tzd))
+ dev_warn(adc_tm->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
++++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
+@@ -460,7 +460,7 @@ static int qpnp_tm_probe(struct platform
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(chip->tz_dev))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, chip->tz_dev))
+ dev_warn(&pdev->dev,
+ "Failed to add hwmon sysfs attributes\n");
+
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -1056,7 +1056,7 @@ static int tsens_register(struct tsens_p
+ if (priv->ops->enable)
+ priv->ops->enable(priv, i);
+
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(priv->dev, tzd))
+ dev_warn(priv->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/qoriq_thermal.c
++++ b/drivers/thermal/qoriq_thermal.c
+@@ -158,7 +158,7 @@ static int qoriq_tmu_register_tmu_zone(s
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(dev, tzd))
+ dev_warn(dev,
+ "Failed to add hwmon sysfs attributes\n");
+
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -468,7 +468,7 @@ static int sun8i_ths_register(struct ths
+ if (IS_ERR(tmdev->sensor[i].tzd))
+ return PTR_ERR(tmdev->sensor[i].tzd);
+
+- if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd))
++ if (devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd))
+ dev_warn(tmdev->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/tegra/tegra30-tsensor.c
++++ b/drivers/thermal/tegra/tegra30-tsensor.c
+@@ -530,7 +530,7 @@ static int tegra_tsensor_register_channe
+ return 0;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(tsc->tzd))
++ if (devm_thermal_add_hwmon_sysfs(ts->dev, tsc->tzd))
+ dev_warn(ts->dev, "failed to add hwmon sysfs attributes\n");
+
+ return 0;
+--- a/drivers/thermal/thermal_hwmon.c
++++ b/drivers/thermal/thermal_hwmon.c
+@@ -255,7 +255,7 @@ static void devm_thermal_hwmon_release(s
+ thermal_remove_hwmon_sysfs(*(struct thermal_zone_device **)res);
+ }
+
+-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz)
+ {
+ struct thermal_zone_device **ptr;
+ int ret;
+@@ -272,7 +272,7 @@ int devm_thermal_add_hwmon_sysfs(struct
+ }
+
+ *ptr = tz;
+- devres_add(&tz->device, ptr);
++ devres_add(dev, ptr);
+
+ return ret;
+ }
+--- a/drivers/thermal/thermal_hwmon.h
++++ b/drivers/thermal/thermal_hwmon.h
+@@ -17,7 +17,7 @@
+
+ #ifdef CONFIG_THERMAL_HWMON
+ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
+-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz);
+ void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
+ #else
+ static inline int
+@@ -27,7 +27,7 @@ thermal_add_hwmon_sysfs(struct thermal_z
+ }
+
+ static inline int
+-devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
++devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz)
+ {
+ return 0;
+ }
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -182,7 +182,7 @@ int ti_thermal_expose_sensor(struct ti_b
+ ti_bandgap_set_sensor_data(bgp, id, data);
+ ti_bandgap_write_update_interval(bgp, data->sensor_id, interval);
+
+- if (devm_thermal_add_hwmon_sysfs(data->ti_thermal))
++ if (devm_thermal_add_hwmon_sysfs(bgp->dev, data->ti_thermal))
+ dev_warn(bgp->dev, "failed to add hwmon sysfs attributes\n");
+
+ return 0;
--- /dev/null
+From 5a72b8e4bac753e4dc74dc0a1335d120f63df97a Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:37 +0100
+Subject: [PATCH 09/42] thermal: Don't use 'device' internal thermal zone
+ structure field
+
+Some drivers are directly using the thermal zone's 'device' structure
+field.
+
+Use the driver device pointer instead of the thermal zone device when
+it is available.
+
+Remove the traces when they are duplicate with the traces in the core
+code.
+
+[again skipped imx_thermal.c]
+
+Cc: Jean Delvare <jdelvare@suse.com>
+Cc: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Balsam CHIHI <bchihi@baylibre.com> #Mediatek LVTS
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek LVTS
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 4 ++--
+ drivers/thermal/thermal_hwmon.c | 4 ++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -305,7 +305,7 @@ static int lvts_set_trips(struct thermal
+ * 14-0 : Raw temperature for threshold
+ */
+ if (low != -INT_MAX) {
+- dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low);
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low);
+ writel(raw_low, LVTS_H2NTHRE(base));
+ }
+
+@@ -318,7 +318,7 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high);
++ pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high);
+ writel(raw_high, LVTS_HTHRE(base));
+
+ return 0;
+--- a/drivers/thermal/thermal_hwmon.c
++++ b/drivers/thermal/thermal_hwmon.c
+@@ -220,14 +220,14 @@ void thermal_remove_hwmon_sysfs(struct t
+ hwmon = thermal_hwmon_lookup_by_type(tz);
+ if (unlikely(!hwmon)) {
+ /* Should never happen... */
+- dev_dbg(&tz->device, "hwmon device lookup failed!\n");
++ dev_dbg(hwmon->device, "hwmon device lookup failed!\n");
+ return;
+ }
+
+ temp = thermal_hwmon_lookup_temp(hwmon, tz);
+ if (unlikely(!temp)) {
+ /* Should never happen... */
+- dev_dbg(&tz->device, "temperature input lookup failed!\n");
++ dev_dbg(hwmon->device, "temperature input lookup failed!\n");
+ return;
+ }
+
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -43,7 +43,7 @@ static void ti_thermal_work(struct work_
+
+ thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
+
+- dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
++ dev_dbg(data->bgp->dev, "updated thermal zone %s\n",
+ data->ti_thermal->type);
+ }
+
--- /dev/null
+From 66b3a292d3fc749e8ec7ac5278a17e8a5757ecbc Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:41 +0100
+Subject: [PATCH 10/42] thermal: Use thermal_zone_device_type() accessor
+
+Replace the accesses to 'tz->type' by its accessor version in order to
+self-encapsulate the thermal_zone_device structure.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com> #mlxsw
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek LVTS
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 2 +-
+ drivers/thermal/mediatek/lvts_thermal.c | 6 ++++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 3 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+@@ -168,7 +168,7 @@ mlxsw_thermal_module_trips_update(struct
+
+ if (crit_temp > emerg_temp) {
+ dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
+- tz->tzdev->type, crit_temp, emerg_temp);
++ thermal_zone_device_type(tz->tzdev), crit_temp, emerg_temp);
+ return 0;
+ }
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -305,7 +305,8 @@ static int lvts_set_trips(struct thermal
+ * 14-0 : Raw temperature for threshold
+ */
+ if (low != -INT_MAX) {
+- pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low);
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), low);
+ writel(raw_low, LVTS_H2NTHRE(base));
+ }
+
+@@ -318,7 +319,8 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high);
++ pr_debug("%s: Setting high limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), high);
+ writel(raw_high, LVTS_HTHRE(base));
+
+ return 0;
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -44,7 +44,7 @@ static void ti_thermal_work(struct work_
+ thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
+
+ dev_dbg(data->bgp->dev, "updated thermal zone %s\n",
+- data->ti_thermal->type);
++ thermal_zone_device_type(data->ti_thermal));
+ }
+
+ /**
--- /dev/null
+From f6658c1c4ae98477d6be00495226c0617354fe76 Mon Sep 17 00:00:00 2001
+From: Markus Schneider-Pargmann <msp@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:43 +0100
+Subject: [PATCH 11/42] thermal/drivers/mediatek: Control buffer enablement
+ tweaks
+
+Add logic in order to be able to turn on the control buffer on MT8365.
+This change now allows to have control buffer support for MTK_THERMAL_V1,
+and it allows to define the register offset, and mask used to enable it.
+
+Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Signed-off-by: Fabien Parent <fparent@baylibre.com>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-2-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 28 +++++++++++++++--------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -307,6 +307,9 @@ struct mtk_thermal_data {
+ bool need_switch_bank;
+ struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+ enum mtk_thermal_version version;
++ u32 apmixed_buffer_ctl_reg;
++ u32 apmixed_buffer_ctl_mask;
++ u32 apmixed_buffer_ctl_set;
+ };
+
+ struct mtk_thermal {
+@@ -560,6 +563,9 @@ static const struct mtk_thermal_data mt7
+ .adcpnp = mt7622_adcpnp,
+ .sensor_mux_values = mt7622_mux_values,
+ .version = MTK_THERMAL_V2,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
++ .apmixed_buffer_ctl_set = BIT(0),
+ };
+
+ /*
+@@ -1079,14 +1085,18 @@ static const struct of_device_id mtk_the
+ };
+ MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+
+-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
++static void mtk_thermal_turn_on_buffer(struct mtk_thermal *mt,
++ void __iomem *apmixed_base)
+ {
+- int tmp;
++ u32 tmp;
++
++ if (!mt->conf->apmixed_buffer_ctl_reg)
++ return;
+
+- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+- tmp &= ~(0x37);
+- tmp |= 0x1;
+- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
++ tmp = readl(apmixed_base + mt->conf->apmixed_buffer_ctl_reg);
++ tmp &= mt->conf->apmixed_buffer_ctl_mask;
++ tmp |= mt->conf->apmixed_buffer_ctl_set;
++ writel(tmp, apmixed_base + mt->conf->apmixed_buffer_ctl_reg);
+ udelay(200);
+ }
+
+@@ -1184,10 +1194,10 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_auxadc;
+ }
+
+- if (mt->conf->version != MTK_THERMAL_V1) {
+- mtk_thermal_turn_on_buffer(apmixed_base);
++ mtk_thermal_turn_on_buffer(mt, apmixed_base);
++
++ if (mt->conf->version != MTK_THERMAL_V2)
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+- }
+
+ if (mt->conf->version == MTK_THERMAL_V1)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
--- /dev/null
+From c4eff784465f88218dc5eb51320320464db83d3f Mon Sep 17 00:00:00 2001
+From: Fabien Parent <fparent@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:44 +0100
+Subject: [PATCH 12/42] thermal/drivers/mediatek: Add support for MT8365 SoC
+
+MT8365 is similar to the other SoCs supported by the driver. It has only
+one bank and 3 actual sensors that can be multiplexed. There is another
+one sensor that does not have usable data.
+
+Signed-off-by: Fabien Parent <fparent@baylibre.com>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-3-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 68 +++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -31,6 +31,7 @@
+ #define AUXADC_CON2_V 0x010
+ #define AUXADC_DATA(channel) (0x14 + (channel) * 4)
+
++#define APMIXED_SYS_TS_CON0 0x600
+ #define APMIXED_SYS_TS_CON1 0x604
+
+ /* Thermal Controller Registers */
+@@ -281,6 +282,17 @@ enum mtk_thermal_version {
+ /* The calibration coefficient of sensor */
+ #define MT7986_CALIBRATION 165
+
++/* MT8365 */
++#define MT8365_TEMP_AUXADC_CHANNEL 11
++#define MT8365_CALIBRATION 164
++#define MT8365_NUM_CONTROLLER 1
++#define MT8365_NUM_BANKS 1
++#define MT8365_NUM_SENSORS 3
++#define MT8365_NUM_SENSORS_PER_ZONE 3
++#define MT8365_TS1 0
++#define MT8365_TS2 1
++#define MT8365_TS3 2
++
+ struct mtk_thermal;
+
+ struct thermal_bank_cfg {
+@@ -435,6 +447,24 @@ static const int mt7986_mux_values[MT798
+ static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
+ static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
+
++/* MT8365 thermal sensor data */
++static const int mt8365_bank_data[MT8365_NUM_SENSORS] = {
++ MT8365_TS1, MT8365_TS2, MT8365_TS3
++};
++
++static const int mt8365_msr[MT8365_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
++};
++
++static const int mt8365_adcpnp[MT8365_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
++};
++
++static const int mt8365_mux_values[MT8365_NUM_SENSORS] = { 0, 1, 2 };
++static const int mt8365_tc_offset[MT8365_NUM_CONTROLLER] = { 0 };
++
++static const int mt8365_vts_index[MT8365_NUM_SENSORS] = { VTS1, VTS2, VTS3 };
++
+ /*
+ * The MT8173 thermal controller has four banks. Each bank can read up to
+ * four temperature sensors simultaneously. The MT8173 has a total of 5
+@@ -510,6 +540,40 @@ static const struct mtk_thermal_data mt2
+ };
+
+ /*
++ * The MT8365 thermal controller has one bank, which can read up to
++ * four temperature sensors simultaneously. The MT8365 has a total of 3
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt8365_thermal_data = {
++ .auxadc_channel = MT8365_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8365_NUM_BANKS,
++ .num_sensors = MT8365_NUM_SENSORS,
++ .vts_index = mt8365_vts_index,
++ .cali_val = MT8365_CALIBRATION,
++ .num_controller = MT8365_NUM_CONTROLLER,
++ .controller_offset = mt8365_tc_offset,
++ .need_switch_bank = false,
++ .bank_data = {
++ {
++ .num_sensors = MT8365_NUM_SENSORS,
++ .sensors = mt8365_bank_data
++ },
++ },
++ .msr = mt8365_msr,
++ .adcpnp = mt8365_adcpnp,
++ .sensor_mux_values = mt8365_mux_values,
++ .version = MTK_THERMAL_V1,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON0,
++ .apmixed_buffer_ctl_mask = (u32) ~GENMASK(29, 28),
++ .apmixed_buffer_ctl_set = 0,
++};
++
++/*
+ * The MT2712 thermal controller has one bank, which can read up to
+ * four temperature sensors simultaneously. The MT2712 has a total of 4
+ * temperature sensors.
+@@ -1080,6 +1144,10 @@ static const struct of_device_id mtk_the
+ {
+ .compatible = "mediatek,mt8183-thermal",
+ .data = (void *)&mt8183_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt8365-thermal",
++ .data = (void *)&mt8365_thermal_data,
+ }, {
+ },
+ };
--- /dev/null
+From 4eead70db74922bc61e9d0b4591524369a335751 Mon Sep 17 00:00:00 2001
+From: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:46 +0100
+Subject: [PATCH 13/42] thermal/drivers/mediatek: Add delay after thermal banks
+ initialization
+
+Thermal sensor reads performed immediately after thermal bank
+initialization returns bogus values. This is currently tackled by returning
+0 if the temperature is bogus (exceeding 200000).
+
+Instead, add a delay between the bank init and the thermal zone device
+register to properly fix this.
+
+Signed-off-by: Michael Kao <michael.kao@mediatek.com>
+Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-5-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -816,14 +816,6 @@ static int mtk_thermal_bank_temperature(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+
+- /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
+- */
+- if (temp > 200000)
+- temp = 0;
+-
+ if (temp > max)
+ max = temp;
+ }
+@@ -1281,6 +1273,9 @@ static int mtk_thermal_probe(struct plat
+
+ platform_set_drvdata(pdev, mt);
+
++ /* Delay for thermal banks to be ready */
++ msleep(30);
++
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev)) {
--- /dev/null
+From ad9dc9e92367803a4f9576aea0dab110d03fc510 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wenst@chromium.org>
+Date: Tue, 28 Mar 2023 11:10:17 +0800
+Subject: [PATCH 14/42] thermal/drivers/mediatek/lvts_thermal: Fix sensor 1
+ interrupt status bitmask
+
+The binary representation for sensor 1 interrupt status was incorrectly
+assembled, when compared to the full table given in the same comment
+section. The conversion into hex was also incorrect, leading to
+incorrect interrupt status bitmask for sensor 1. This would cause the
+driver to incorrectly identify changes for sensor 1, when in fact it
+was sensor 0, or a sensor access time out.
+
+Fix the binary and hex representations in the comments, and the actual
+bitmask macro.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230328031017.1360976-1-wenst@chromium.org
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -66,7 +66,7 @@
+ #define LVTS_MONINT_CONF 0x9FBF7BDE
+
+ #define LVTS_INT_SENSOR0 0x0009001F
+-#define LVTS_INT_SENSOR1 0X000881F0
++#define LVTS_INT_SENSOR1 0x001203E0
+ #define LVTS_INT_SENSOR2 0x00247C00
+ #define LVTS_INT_SENSOR3 0x1FC00000
+
+@@ -395,8 +395,8 @@ static irqreturn_t lvts_ctrl_irq_handler
+ * => 0x1FC00000
+ * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000
+ * => 0x00247C00
+- * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000
+- * => 0X000881F0
++ * sensor 1 interrupt: 0000 0000 0001 0010 0000 0011 1110 0000
++ * => 0X001203E0
+ * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111
+ * => 0x0009001F
+ */
--- /dev/null
+From 9aad43ad3285fc21158fb416830a6156a9a31fa5 Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 7 Mar 2023 16:45:22 +0100
+Subject: [PATCH 15/42] thermal/drivers/mediatek/lvts_thermal: Add AP domain
+ for mt8195
+
+Add MT8195 AP Domain support to LVTS Driver.
+
+Take the opportunity to update the comments to show calibration data
+information related to the new domain.
+
+[dlezcano]: Massaged a bit the changelog
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230307154524.118541-3-bchihi@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 94 +++++++++++++++++++------
+ 1 file changed, 74 insertions(+), 20 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -530,29 +530,33 @@ static int lvts_sensor_init(struct devic
+ * The efuse blob values follows the sensor enumeration per thermal
+ * controller. The decoding of the stream is as follow:
+ *
+- * <--?-> <----big0 ???---> <-sensor0-> <-0->
+- * ------------------------------------------
+- * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 |
+- * ------------------------------------------
++ * stream index map for MCU Domain :
+ *
+- * <--sensor1--><-0-> <----big1 ???---> <-sen
+- * ------------------------------------------
+- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
+- * ------------------------------------------
++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
+ *
+- * sor0-> <-0-> <-sensor1-> <-0-> ..........
+- * ------------------------------------------
+- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
+- * ------------------------------------------
++ * <-----mcu-tc#1-----> <-----sensor#2-----> <-----sensor#3----->
++ * 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12
+ *
+- * And so on ...
++ * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
++ * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
++ *
++ * stream index map for AP Domain :
++ *
++ * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
++ *
++ * <-----ap--tc#1-----> <-----sensor#2-----> <-----sensor#3----->
++ * 0x2B | 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
++ *
++ * <-----ap--tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6----->
++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F
++ *
++ * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
++ * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
+ *
+ * The data description gives the offset of the calibration data in
+ * this bytes stream for each sensor.
+- *
+- * Each thermal controller can handle up to 4 sensors max, we don't
+- * care if there are less as the array of calibration is sized to 4
+- * anyway. The unused sensor slot will be zeroed.
+ */
+ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
+ const struct lvts_ctrl_data *lvts_ctrl_data,
+@@ -1165,7 +1169,7 @@ static int lvts_remove(struct platform_d
+ return 0;
+ }
+
+-static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = {
++static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+ .lvts_sensor = {
+@@ -1200,13 +1204,63 @@ static const struct lvts_ctrl_data mt819
+ }
+ };
+
++static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x25, 0x28 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_VPU0 },
++ { .dt_id = MT8195_AP_VPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x2e, 0x31 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_GPU0 },
++ { .dt_id = MT8195_AP_GPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x37, 0x3a, 0x3d },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_VDEC },
++ { .dt_id = MT8195_AP_IMG },
++ { .dt_id = MT8195_AP_INFRA },
++ },
++ .num_lvts_sensor = 3,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x43, 0x46 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_CAM0 },
++ { .dt_id = MT8195_AP_CAM1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x300,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ }
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+- .lvts_ctrl = mt8195_lvts_data_ctrl,
+- .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl),
++ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
++};
++
++static const struct lvts_data mt8195_lvts_ap_data = {
++ .lvts_ctrl = mt8195_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
+ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
++ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, lvts_of_match);
--- /dev/null
+From 7105a86760bd9e4d107075cefc75016b693a5542 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Wed, 19 Apr 2023 08:11:45 +0200
+Subject: [PATCH 16/42] Revert "thermal/drivers/mediatek: Add delay after
+ thermal banks initialization"
+
+Some more testing revealed that this commit introduces a regression on some
+MT8173 Chromebooks and at least on one MT6795 Sony Xperia M5 smartphone due
+to the delay being apparently variable and machine specific.
+
+Another solution would be to delay for a bit more (~70ms) but this is not
+feasible for two reasons: first of all, we're adding an even bigger delay
+in a probe function; second, some machines need less, some may need even
+more, making the msleep at probe solution highly suboptimal.
+
+This reverts commit 10debf8c2da8011c8009dd4b3f6d0ab85891c81b.
+
+Fixes: 10debf8c2da8 ("thermal/drivers/mediatek: Add delay after thermal banks initialization")
+Reported-by: "kernelci.org bot" <bot@kernelci.org>
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419061146.22246-2-angelogioacchino.delregno@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -816,6 +816,14 @@ static int mtk_thermal_bank_temperature(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+
++ /*
++ * The first read of a sensor often contains very high bogus
++ * temperature value. Filter these out so that the system does
++ * not immediately shut down.
++ */
++ if (temp > 200000)
++ temp = 0;
++
+ if (temp > max)
+ max = temp;
+ }
+@@ -1273,9 +1281,6 @@ static int mtk_thermal_probe(struct plat
+
+ platform_set_drvdata(pdev, mt);
+
+- /* Delay for thermal banks to be ready */
+- msleep(30);
+-
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev)) {
--- /dev/null
+From 681b652c9dfc4037d4a55b2733e091a4e1a5de18 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Wed, 19 Apr 2023 08:11:46 +0200
+Subject: [PATCH 17/42] thermal/drivers/mediatek: Add temperature constraints
+ to validate read
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The AUXADC thermal v1 allows reading temperature range between -20°C to
+150°C and any value out of this range is invalid.
+
+Add new definitions for MT8173_TEMP_{MIN_MAX} and a new small helper
+mtk_thermal_temp_is_valid() to check if new readings are in range: if
+not, we tell to the API that the reading is invalid by returning
+THERMAL_TEMP_INVALID.
+
+It was chosen to introduce the helper function because, even though this
+temperature range is realistically ok for all, it comes from a downstream
+kernel driver for version 1, but here we also support v2 and v3 which may
+may have wider constraints.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419061146.22246-3-angelogioacchino.delregno@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 24 +++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -116,6 +116,10 @@
+ /* The calibration coefficient of sensor */
+ #define MT8173_CALIBRATION 165
+
++/* Valid temperatures range */
++#define MT8173_TEMP_MIN -20000
++#define MT8173_TEMP_MAX 150000
++
+ /*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
+@@ -689,6 +693,11 @@ static const struct mtk_thermal_data mt7
+ .version = MTK_THERMAL_V3,
+ };
+
++static bool mtk_thermal_temp_is_valid(int temp)
++{
++ return (temp >= MT8173_TEMP_MIN) && (temp <= MT8173_TEMP_MAX);
++}
++
+ /**
+ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+@@ -815,14 +824,17 @@ static int mtk_thermal_bank_temperature(
+ temp = mt->raw_to_mcelsius(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+-
+ /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
++ * Depending on the filt/sen intervals and ADC polling time,
++ * we may need up to 60 milliseconds after initialization: this
++ * will result in the first reading containing an out of range
++ * temperature value.
++ * Validate the reading to both address the aforementioned issue
++ * and to eventually avoid bogus readings during runtime in the
++ * event that the AUXADC gets unstable due to high EMI, etc.
+ */
+- if (temp > 200000)
+- temp = 0;
++ if (!mtk_thermal_temp_is_valid(temp))
++ temp = THERMAL_TEMP_INVALID;
+
+ if (temp > max)
+ max = temp;
--- /dev/null
+From 458fa1d508de3f17e49d974a0158d9aeff273a58 Mon Sep 17 00:00:00 2001
+From: Kang Chen <void0red@hust.edu.cn>
+Date: Wed, 19 Apr 2023 10:07:48 +0800
+Subject: [PATCH 18/42] thermal/drivers/mediatek: Use devm_of_iomap to avoid
+ resource leak in mtk_thermal_probe
+
+Smatch reports:
+1. mtk_thermal_probe() warn: 'apmixed_base' from of_iomap() not released.
+2. mtk_thermal_probe() warn: 'auxadc_base' from of_iomap() not released.
+
+The original code forgets to release iomap resource when handling errors,
+fix it by switch to devm_of_iomap.
+
+Fixes: 89945047b166 ("thermal: mediatek: Add tsensor support for V2 thermal system")
+Signed-off-by: Kang Chen <void0red@hust.edu.cn>
+Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419020749.621257-1-void0red@hust.edu.cn
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1232,7 +1232,12 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- auxadc_base = of_iomap(auxadc, 0);
++ auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL);
++ if (IS_ERR(auxadc_base)) {
++ of_node_put(auxadc);
++ return PTR_ERR(auxadc_base);
++ }
++
+ auxadc_phys_base = of_get_phys_base(auxadc);
+
+ of_node_put(auxadc);
+@@ -1248,7 +1253,12 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- apmixed_base = of_iomap(apmixedsys, 0);
++ apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL);
++ if (IS_ERR(apmixed_base)) {
++ of_node_put(apmixedsys);
++ return PTR_ERR(apmixed_base);
++ }
++
+ apmixed_phys_base = of_get_phys_base(apmixedsys);
+
+ of_node_put(apmixedsys);
--- /dev/null
+From 227d1856924ec00a4f5bdf5afcf77bc7f3f04e86 Mon Sep 17 00:00:00 2001
+From: Kang Chen <void0red@hust.edu.cn>
+Date: Wed, 19 Apr 2023 10:07:49 +0800
+Subject: [PATCH 19/42] thermal/drivers/mediatek: Change clk_prepare_enable to
+ devm_clk_get_enabled in mtk_thermal_probe
+
+Use devm_clk_get_enabled to do automatic resource management.
+Meanwhile, remove error handling labels in the probe function and
+the whole remove function.
+
+Signed-off-by: Kang Chen <void0red@hust.edu.cn>
+Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419020749.621257-2-void0red@hust.edu.cn
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 44 +++++------------------
+ 1 file changed, 9 insertions(+), 35 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1206,14 +1206,6 @@ static int mtk_thermal_probe(struct plat
+
+ mt->conf = of_device_get_match_data(&pdev->dev);
+
+- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
+- if (IS_ERR(mt->clk_peri_therm))
+- return PTR_ERR(mt->clk_peri_therm);
+-
+- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
+- if (IS_ERR(mt->clk_auxadc))
+- return PTR_ERR(mt->clk_auxadc);
+-
+ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(mt->thermal_base))
+ return PTR_ERR(mt->thermal_base);
+@@ -1272,16 +1264,18 @@ static int mtk_thermal_probe(struct plat
+ if (ret)
+ return ret;
+
+- ret = clk_prepare_enable(mt->clk_auxadc);
+- if (ret) {
++ mt->clk_auxadc = devm_clk_get_enabled(&pdev->dev, "auxadc");
++ if (IS_ERR(mt->clk_auxadc)) {
++ ret = PTR_ERR(mt->clk_auxadc);
+ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
+ return ret;
+ }
+
+- ret = clk_prepare_enable(mt->clk_peri_therm);
+- if (ret) {
++ mt->clk_peri_therm = devm_clk_get_enabled(&pdev->dev, "therm");
++ if (IS_ERR(mt->clk_peri_therm)) {
++ ret = PTR_ERR(mt->clk_peri_therm);
+ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
+- goto err_disable_clk_auxadc;
++ return ret;
+ }
+
+ mtk_thermal_turn_on_buffer(mt, apmixed_base);
+@@ -1305,38 +1299,18 @@ static int mtk_thermal_probe(struct plat
+
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+- if (IS_ERR(tzdev)) {
+- ret = PTR_ERR(tzdev);
+- goto err_disable_clk_peri_therm;
+- }
++ if (IS_ERR(tzdev))
++ return PTR_ERR(tzdev);
+
+ ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev);
+ if (ret)
+ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+
+ return 0;
+-
+-err_disable_clk_peri_therm:
+- clk_disable_unprepare(mt->clk_peri_therm);
+-err_disable_clk_auxadc:
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return ret;
+-}
+-
+-static int mtk_thermal_remove(struct platform_device *pdev)
+-{
+- struct mtk_thermal *mt = platform_get_drvdata(pdev);
+-
+- clk_disable_unprepare(mt->clk_peri_therm);
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return 0;
+ }
+
+ static struct platform_driver mtk_thermal_driver = {
+ .probe = mtk_thermal_probe,
+- .remove = mtk_thermal_remove,
+ .driver = {
+ .name = "mtk-thermal",
+ .of_match_table = mtk_thermal_of_match,
--- /dev/null
+From 655fe2533ac05323a07c19ba079bf2064e7741af Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Sun, 19 Mar 2023 11:32:31 -0500
+Subject: [PATCH 20/42] thermal/drivers/mediatek: Use of_address_to_resource()
+
+Replace of_get_address() and of_translate_address() calls with single
+call to of_address_to_resource().
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230319163231.226738-1-robh@kernel.org
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -979,14 +979,12 @@ static void mtk_thermal_init_bank(struct
+
+ static u64 of_get_phys_base(struct device_node *np)
+ {
+- u64 size64;
+- const __be32 *regaddr_p;
++ struct resource res;
+
+- regaddr_p = of_get_address(np, 0, &size64, NULL);
+- if (!regaddr_p)
++ if (of_address_to_resource(np, 0, &res))
+ return OF_BAD_ADDR;
+
+- return of_translate_address(np, regaddr_p);
++ return res.start;
+ }
+
+ static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
--- /dev/null
+From 2c380d07215e6fce3ac66cc5af059bc2c2a69f7a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= <ricardo.canuelo@collabora.com>
+Date: Thu, 25 May 2023 14:18:11 +0200
+Subject: [PATCH 21/42] Revert "thermal/drivers/mediatek: Use devm_of_iomap to
+ avoid resource leak in mtk_thermal_probe"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit f05c7b7d9ea9477fcc388476c6f4ade8c66d2d26.
+
+That change was causing a regression in the generic-adc-thermal-probed
+bootrr test as reported in the kernelci-results list [1].
+A proper rework will take longer, so revert it for now.
+
+[1] https://groups.io/g/kernelci-results/message/42660
+
+Fixes: f05c7b7d9ea9 ("thermal/drivers/mediatek: Use devm_of_iomap to avoid resource leak in mtk_thermal_probe")
+Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com>
+Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230525121811.3360268-1-ricardo.canuelo@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 14 ++------------
+ 1 file changed, 2 insertions(+), 12 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1222,12 +1222,7 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL);
+- if (IS_ERR(auxadc_base)) {
+- of_node_put(auxadc);
+- return PTR_ERR(auxadc_base);
+- }
+-
++ auxadc_base = of_iomap(auxadc, 0);
+ auxadc_phys_base = of_get_phys_base(auxadc);
+
+ of_node_put(auxadc);
+@@ -1243,12 +1238,7 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL);
+- if (IS_ERR(apmixed_base)) {
+- of_node_put(apmixedsys);
+- return PTR_ERR(apmixed_base);
+- }
+-
++ apmixed_base = of_iomap(apmixedsys, 0);
+ apmixed_phys_base = of_get_phys_base(apmixedsys);
+
+ of_node_put(apmixedsys);
--- /dev/null
+From 496f4b08981d8a788ad5a2073fa1c65a2af1862b Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wenst@chromium.org>
+Date: Tue, 13 Jun 2023 17:13:16 +0800
+Subject: [PATCH 22/42] thermal/drivers/mediatek/lvts_thermal: Register thermal
+ zones as hwmon sensors
+
+Register thermal zones as hwmon sensors to let userspace read
+temperatures using standard hwmon interface.
+
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230613091317.1691247-1-wenst@chromium.org
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -19,6 +19,8 @@
+ #include <linux/thermal.h>
+ #include <dt-bindings/thermal/mediatek,lvts-thermal.h>
+
++#include "../thermal_hwmon.h"
++
+ #define LVTS_MONCTL0(__base) (__base + 0x0000)
+ #define LVTS_MONCTL1(__base) (__base + 0x0004)
+ #define LVTS_MONCTL2(__base) (__base + 0x0008)
+@@ -996,6 +998,9 @@ static int lvts_ctrl_start(struct device
+ return PTR_ERR(tz);
+ }
+
++ if (devm_thermal_add_hwmon_sysfs(dev, tz))
++ dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id);
++
+ /*
+ * The thermal zone pointer will be needed in the
+ * interrupt handler, we store it in the sensor
--- /dev/null
+From 885b9768ce2a66ed5d250822aed53d5114c895da Mon Sep 17 00:00:00 2001
+From: Yangtao Li <frank.li@vivo.com>
+Date: Tue, 20 Jun 2023 17:07:31 +0800
+Subject: [PATCH 23/42] thermal/drivers/mediatek/lvts_thermal: Remove redundant
+ msg in lvts_ctrl_start()
+
+The upper-layer devm_thermal_add_hwmon_sysfs() function can directly
+print error information.
+
+Signed-off-by: Yangtao Li <frank.li@vivo.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230620090732.50025-10-frank.li@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -998,8 +998,7 @@ static int lvts_ctrl_start(struct device
+ return PTR_ERR(tz);
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(dev, tz))
+- dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id);
++ devm_thermal_add_hwmon_sysfs(dev, tz);
+
+ /*
+ * The thermal zone pointer will be needed in the
--- /dev/null
+From 27b389d9f62c2174f95fe4002b11e77d4cb3ce80 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:32 -0400
+Subject: [PATCH 25/42] thermal/drivers/mediatek/lvts_thermal: Handle IRQ on
+ all controllers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is a single IRQ handler for each LVTS thermal domain, and it is
+supposed to check each of its underlying controllers for the origin of
+the interrupt and clear its status. However due to a typo, only the
+first controller was ever being handled, which resulted in the interrupt
+never being cleared when it happened on the other controllers. Add the
+missing index so interrupts are handled for all controllers.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-2-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -451,7 +451,7 @@ static irqreturn_t lvts_irq_handler(int
+
+ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
+
+- aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl);
++ aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]);
+ if (aux != IRQ_HANDLED)
+ continue;
+
--- /dev/null
+From 6d827142643ee10c13ff9a1d90f38fb399aa9fff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:33 -0400
+Subject: [PATCH 26/42] thermal/drivers/mediatek/lvts_thermal: Honor sensors in
+ immediate mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Each controller can be configured to operate on immediate or filtered
+mode. On filtered mode, the sensors are enabled by setting the
+corresponding bits in MONCTL0, while on immediate mode, by setting
+MSRCTL1.
+
+Previously, the code would set MSRCTL1 for all four sensors when
+configured to immediate mode, but given that the controller might not
+have all four sensors connected, this would cause interrupts to trigger
+for non-existent sensors. Fix this by handling the MSRCTL1 register
+analogously to the MONCTL0: only enable the sensors that were declared.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-3-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 57 ++++++++++++++-----------
+ 1 file changed, 33 insertions(+), 24 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -897,24 +897,6 @@ static int lvts_ctrl_configure(struct de
+ writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
+
+ /*
+- * LVTS_MSRCTL1 : Measurement control
+- *
+- * Bits:
+- *
+- * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
+- * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
+- * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
+- * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
+- *
+- * That configuration will ignore the filtering and the delays
+- * introduced below in MONCTL1 and MONCTL2
+- */
+- if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
+- value = BIT(9) | BIT(6) | BIT(5) | BIT(4);
+- writel(value, LVTS_MSRCTL1(lvts_ctrl->base));
+- }
+-
+- /*
+ * LVTS_MONCTL1 : Period unit and group interval configuration
+ *
+ * The clock source of LVTS thermal controller is 26MHz.
+@@ -979,6 +961,15 @@ static int lvts_ctrl_start(struct device
+ struct thermal_zone_device *tz;
+ u32 sensor_map = 0;
+ int i;
++ /*
++ * Bitmaps to enable each sensor on immediate and filtered modes, as
++ * described in MSRCTL1 and MONCTL0 registers below, respectively.
++ */
++ u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) };
++ u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) };
++
++ u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ?
++ sensor_imm_bitmap : sensor_filt_bitmap;
+
+ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
+
+@@ -1016,20 +1007,38 @@ static int lvts_ctrl_start(struct device
+ * map, so we can enable the temperature monitoring in
+ * the hardware thermal controller.
+ */
+- sensor_map |= BIT(i);
++ sensor_map |= sensor_bitmap[i];
+ }
+
+ /*
+- * Bits:
+- * 9: Single point access flow
+- * 0-3: Enable sensing point 0-3
+- *
+ * The initialization of the thermal zones give us
+ * which sensor point to enable. If any thermal zone
+ * was not described in the device tree, it won't be
+ * enabled here in the sensor map.
+ */
+- writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
++ /*
++ * LVTS_MSRCTL1 : Measurement control
++ *
++ * Bits:
++ *
++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
++ *
++ * That configuration will ignore the filtering and the delays
++ * introduced in MONCTL1 and MONCTL2
++ */
++ writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base));
++ } else {
++ /*
++ * Bits:
++ * 9: Single point access flow
++ * 0-3: Enable sensing point 0-3
++ */
++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++ }
+
+ return 0;
+ }
--- /dev/null
+From 93bb11dd19bdcc1fc97c7ceababd0db9fde128ad Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:34 -0400
+Subject: [PATCH 27/42] thermal/drivers/mediatek/lvts_thermal: Use offset
+ threshold for IRQ
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are two kinds of temperature monitoring interrupts available:
+* High Offset, Low Offset
+* Hot, Hot to normal, Cold
+
+The code currently uses the hot/h2n/cold interrupts, however in a way
+that doesn't work: the cold threshold is left uninitialized, which
+prevents the other thresholds from ever triggering, and the h2n
+interrupt is used as the lower threshold, which prevents the hot
+interrupt from triggering again after the thresholds are updated by the
+thermal framework, since a hot interrupt can only trigger again after
+the hot to normal interrupt has been triggered.
+
+But better yet than addressing those issues, is to use the high/low
+offset interrupts instead. This way only two thresholds need to be
+managed, which have a simpler state machine, making them a better match
+to the thermal framework's high and low thresholds.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-4-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -298,9 +298,9 @@ static int lvts_set_trips(struct thermal
+ u32 raw_high = lvts_temp_to_raw(high);
+
+ /*
+- * Hot to normal temperature threshold
++ * Low offset temperature threshold
+ *
+- * LVTS_H2NTHRE
++ * LVTS_OFFSETL
+ *
+ * Bits:
+ *
+@@ -309,13 +309,13 @@ static int lvts_set_trips(struct thermal
+ if (low != -INT_MAX) {
+ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
+ thermal_zone_device_type(tz), low);
+- writel(raw_low, LVTS_H2NTHRE(base));
++ writel(raw_low, LVTS_OFFSETL(base));
+ }
+
+ /*
+- * Hot temperature threshold
++ * High offset temperature threshold
+ *
+- * LVTS_HTHRE
++ * LVTS_OFFSETH
+ *
+ * Bits:
+ *
+@@ -323,7 +323,7 @@ static int lvts_set_trips(struct thermal
+ */
+ pr_debug("%s: Setting high limit temperature interrupt: %d\n",
+ thermal_zone_device_type(tz), high);
+- writel(raw_high, LVTS_HTHRE(base));
++ writel(raw_high, LVTS_OFFSETH(base));
+
+ return 0;
+ }
--- /dev/null
+From 8f8cab9d3e90acf1db278ef44ad05f10aefb973f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:35 -0400
+Subject: [PATCH 28/42] thermal/drivers/mediatek/lvts_thermal: Disable
+ undesired interrupts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Out of the many interrupts supported by the hardware, the only ones of
+interest to the driver currently are:
+* The temperature went over the high offset threshold, for any of the
+ sensors
+* The temperature went below the low offset threshold, for any of the
+ sensors
+* The temperature went over the stage3 threshold
+
+These are the only thresholds configured by the driver through the
+OFFSETH, OFFSETL, and PROTTC registers, respectively.
+
+The current interrupt mask in LVTS_MONINT_CONF, enables many more
+interrupts, including data ready on sensors for both filtered and
+immediate mode. These are not only not handled by the driver, but they
+are also triggered too often, causing unneeded overhead. Disable these
+unnecessary interrupts.
+
+The meaning of each bit can be seen in the comment describing
+LVTS_MONINTST in the IRQ handler.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-5-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -65,7 +65,7 @@
+ #define LVTS_HW_FILTER 0x2
+ #define LVTS_TSSEL_CONF 0x13121110
+ #define LVTS_CALSCALE_CONF 0x300
+-#define LVTS_MONINT_CONF 0x9FBF7BDE
++#define LVTS_MONINT_CONF 0x8300318C
+
+ #define LVTS_INT_SENSOR0 0x0009001F
+ #define LVTS_INT_SENSOR1 0x001203E0
--- /dev/null
+From bd1ccf9408e6155564530af5e09b53ae497fe332 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:36 -0400
+Subject: [PATCH 29/42] thermal/drivers/mediatek/lvts_thermal: Don't leave
+ threshold zeroed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The thermal framework might leave the low threshold unset if there
+aren't any lower trip points. This leaves the register zeroed, which
+translates to a very high temperature for the low threshold. The
+interrupt for this threshold is then immediately triggered, and the
+state machine gets stuck, preventing any other temperature monitoring
+interrupts to ever trigger.
+
+(The same happens by not setting the Cold or Hot to Normal thresholds
+when using those)
+
+Set the unused threshold to a valid low value. This value was chosen so
+that for any valid golden temperature read from the efuse, when the
+value is converted to raw and back again to milliCelsius, the result
+doesn't underflow.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-6-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -83,6 +83,8 @@
+
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
++#define LVTS_MINIMUM_THRESHOLD 20000
++
+ static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
+ static int coeff_b = LVTS_COEFF_B;
+
+@@ -294,7 +296,7 @@ static int lvts_set_trips(struct thermal
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *base = lvts_sensor->base;
+- u32 raw_low = lvts_temp_to_raw(low);
++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
+ u32 raw_high = lvts_temp_to_raw(high);
+
+ /*
+@@ -306,11 +308,9 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- if (low != -INT_MAX) {
+- pr_debug("%s: Setting low limit temperature interrupt: %d\n",
+- thermal_zone_device_type(tz), low);
+- writel(raw_low, LVTS_OFFSETL(base));
+- }
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), low);
++ writel(raw_low, LVTS_OFFSETL(base));
+
+ /*
+ * High offset temperature threshold
--- /dev/null
+From d4dd09968cab3249e6148e1c3fccb51824edb411 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:37 -0400
+Subject: [PATCH 30/42] thermal/drivers/mediatek/lvts_thermal: Manage threshold
+ between sensors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Each LVTS thermal controller can have up to four sensors, each capable
+of triggering its own interrupt when its measured temperature crosses
+the configured threshold. The threshold for each sensor is handled
+separately by the thermal framework, since each one is registered with
+its own thermal zone and trips. However, the temperature thresholds are
+configured on the controller, and therefore are shared between all
+sensors on that controller.
+
+When the temperature measured by the sensors is different enough to
+cause the thermal framework to configure different thresholds for each
+one, interrupts start triggering on sensors outside the last threshold
+configured.
+
+To address the issue, track the thresholds required by each sensor and
+only actually set the highest one in the hardware, and disable
+interrupts for all sensors outside the current configured range.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-7-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 69 +++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -67,6 +67,11 @@
+ #define LVTS_CALSCALE_CONF 0x300
+ #define LVTS_MONINT_CONF 0x8300318C
+
++#define LVTS_MONINT_OFFSET_SENSOR0 0xC
++#define LVTS_MONINT_OFFSET_SENSOR1 0x180
++#define LVTS_MONINT_OFFSET_SENSOR2 0x3000
++#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000
++
+ #define LVTS_INT_SENSOR0 0x0009001F
+ #define LVTS_INT_SENSOR1 0x001203E0
+ #define LVTS_INT_SENSOR2 0x00247C00
+@@ -112,6 +117,8 @@ struct lvts_sensor {
+ void __iomem *base;
+ int id;
+ int dt_id;
++ int low_thresh;
++ int high_thresh;
+ };
+
+ struct lvts_ctrl {
+@@ -121,6 +128,8 @@ struct lvts_ctrl {
+ int num_lvts_sensor;
+ int mode;
+ void __iomem *base;
++ int low_thresh;
++ int high_thresh;
+ };
+
+ struct lvts_domain {
+@@ -292,12 +301,66 @@ static int lvts_get_temp(struct thermal_
+ return 0;
+ }
+
++static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl)
++{
++ u32 masks[] = {
++ LVTS_MONINT_OFFSET_SENSOR0,
++ LVTS_MONINT_OFFSET_SENSOR1,
++ LVTS_MONINT_OFFSET_SENSOR2,
++ LVTS_MONINT_OFFSET_SENSOR3,
++ };
++ u32 value = 0;
++ int i;
++
++ value = readl(LVTS_MONINT(lvts_ctrl->base));
++
++ for (i = 0; i < ARRAY_SIZE(masks); i++) {
++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
++ value |= masks[i];
++ else
++ value &= ~masks[i];
++ }
++
++ writel(value, LVTS_MONINT(lvts_ctrl->base));
++}
++
++static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
++{
++ int i;
++
++ if (high > lvts_ctrl->high_thresh)
++ return true;
++
++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++)
++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
++ return false;
++
++ return true;
++}
++
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
+ void __iomem *base = lvts_sensor->base;
+ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
+ u32 raw_high = lvts_temp_to_raw(high);
++ bool should_update_thresh;
++
++ lvts_sensor->low_thresh = low;
++ lvts_sensor->high_thresh = high;
++
++ should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high);
++ if (should_update_thresh) {
++ lvts_ctrl->high_thresh = high;
++ lvts_ctrl->low_thresh = low;
++ }
++ lvts_update_irq_mask(lvts_ctrl);
++
++ if (!should_update_thresh)
++ return 0;
+
+ /*
+ * Low offset temperature threshold
+@@ -521,6 +584,9 @@ static int lvts_sensor_init(struct devic
+ */
+ lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
+ imm_regs[i] : msr_regs[i];
++
++ lvts_sensor[i].low_thresh = INT_MIN;
++ lvts_sensor[i].high_thresh = INT_MIN;
+ };
+
+ lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
+@@ -688,6 +754,9 @@ static int lvts_ctrl_init(struct device
+ */
+ lvts_ctrl[i].hw_tshut_raw_temp =
+ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++
++ lvts_ctrl[i].low_thresh = INT_MIN;
++ lvts_ctrl[i].high_thresh = INT_MIN;
+ }
+
+ /*
--- /dev/null
+From 5af4904adc8b840987000724977c13c706d3b7d8 Mon Sep 17 00:00:00 2001
+From: Minjie Du <duminjie@vivo.com>
+Date: Thu, 13 Jul 2023 12:24:12 +0800
+Subject: [PATCH 31/42] thermal/drivers/mediatek/lvts: Fix parameter check in
+ lvts_debugfs_init()
+
+The documentation says "If an error occurs, ERR_PTR(-ERROR) will be
+returned" but the current code checks against a NULL pointer returned.
+
+Fix this by checking if IS_ERR().
+
+Signed-off-by: Minjie Du <duminjie@vivo.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230713042413.2519-1-duminjie@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -201,7 +201,7 @@ static int lvts_debugfs_init(struct devi
+ int i;
+
+ lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
+- if (!lvts_td->dom_dentry)
++ if (IS_ERR(lvts_td->dom_dentry))
+ return 0;
+
+ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
--- /dev/null
+From 6186be80317d1dbda34d35c06c084a083938f2d3 Mon Sep 17 00:00:00 2001
+From: Chen Jiahao <chenjiahao16@huawei.com>
+Date: Wed, 2 Aug 2023 17:45:27 +0800
+Subject: [PATCH 32/42] thermal/drivers/mediatek: Clean up redundant
+ dev_err_probe()
+
+Referring to platform_get_irq()'s definition, the return value has
+already been checked if ret < 0, and printed via dev_err_probe().
+Calling dev_err_probe() one more time outside platform_get_irq()
+is obviously redundant.
+
+Removing dev_err_probe() outside platform_get_irq() to clean up
+above problem.
+
+Signed-off-by: Chen Jiahao <chenjiahao16@huawei.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230802094527.988842-1-chenjiahao16@huawei.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1216,7 +1216,7 @@ static int lvts_probe(struct platform_de
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+- return dev_err_probe(dev, irq, "No irq resource\n");
++ return irq;
+
+ ret = lvts_domain_init(dev, lvts_td, lvts_data);
+ if (ret)
--- /dev/null
+From c2ab54ab0425388e65901a7af2fbf69ead968708 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 13 Jul 2023 11:42:37 -0400
+Subject: [PATCH 33/42] thermal/drivers/mediatek/lvts_thermal: Make readings
+ valid in filtered mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently, when a controller is configured to use filtered mode, thermal
+readings are valid only about 30% of the time.
+
+Upon testing, it was noticed that lowering any of the interval settings
+resulted in an improved rate of valid data. The same was observed when
+decreasing the number of samples for each sensor (which also results in
+quicker measurements).
+
+Retrying the read with a timeout longer than the time it takes to
+resample (about 344us with these settings and 4 sensors) also improves
+the rate.
+
+Lower all timing settings to the minimum, configure the filtering to
+single sample, and poll the measurement register for at least one period
+to improve the data validity on filtered mode. With these changes in
+place, out of 100000 reads, a single one failed, ie 99.999% of the data
+was valid.
+
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230713154743.611870-1-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -58,11 +58,11 @@
+ #define LVTS_PROTTC(__base) (__base + 0x00CC)
+ #define LVTS_CLKEN(__base) (__base + 0x00E4)
+
+-#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38))
+-#define LVTS_GROUP_INTERVAL 1
+-#define LVTS_FILTER_INTERVAL 1
+-#define LVTS_SENSOR_INTERVAL 1
+-#define LVTS_HW_FILTER 0x2
++#define LVTS_PERIOD_UNIT 0
++#define LVTS_GROUP_INTERVAL 0
++#define LVTS_FILTER_INTERVAL 0
++#define LVTS_SENSOR_INTERVAL 0
++#define LVTS_HW_FILTER 0x0
+ #define LVTS_TSSEL_CONF 0x13121110
+ #define LVTS_CALSCALE_CONF 0x300
+ #define LVTS_MONINT_CONF 0x8300318C
+@@ -86,6 +86,9 @@
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+
++#define LVTS_MSR_READ_TIMEOUT_US 400
++#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
++
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -268,6 +271,7 @@ static int lvts_get_temp(struct thermal_
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
++ int rc;
+
+ /*
+ * Measurement registers:
+@@ -280,7 +284,8 @@ static int lvts_get_temp(struct thermal_
+ * 16 : Valid temperature
+ * 15-0 : Raw temperature
+ */
+- value = readl(msr);
++ rc = readl_poll_timeout(msr, value, value & BIT(16),
++ LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US);
+
+ /*
+ * As the thermal zone temperature will read before the
+@@ -293,7 +298,7 @@ static int lvts_get_temp(struct thermal_
+ * functionning temperature and directly jump to a system
+ * shutdown.
+ */
+- if (!(value & BIT(16)))
++ if (rc)
+ return -EAGAIN;
+
+ *temp = lvts_raw_to_temp(value & 0xFFFF);
--- /dev/null
+From c864ff9de3b225b43bb8e08dedb223632323e059 Mon Sep 17 00:00:00 2001
+From: Andrei Coardos <aboutphysycs@gmail.com>
+Date: Fri, 11 Aug 2023 22:28:47 +0300
+Subject: [PATCH 34/42] thermal/drivers/mediatek/auxadc_thermal: Removed call
+ to platform_set_drvdata()
+
+This function call was found to be unnecessary as there is no equivalent
+platform_get_drvdata() call to access the private data of the driver. Also,
+the private data is defined in this driver, so there is no risk of it being
+accessed outside of this driver file.
+
+Signed-off-by: Andrei Coardos <aboutphysycs@gmail.com>
+Reviewed-by: Alexandru Ardelean <alex@shruggie.ro>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230811192847.3838-1-aboutphysycs@gmail.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1283,8 +1283,6 @@ static int mtk_thermal_probe(struct plat
+ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+ auxadc_phys_base, ctrl_id);
+
+- platform_set_drvdata(pdev, mt);
+-
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev))
--- /dev/null
+From 6cf96078969ec00b873db99bae4e47001290685e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Wed, 27 Sep 2023 21:37:23 +0200
+Subject: [PATCH 35/42] thermal: lvts: Convert to platform remove callback
+ returning void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new(), which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1241,7 +1241,7 @@ static int lvts_probe(struct platform_de
+ return 0;
+ }
+
+-static int lvts_remove(struct platform_device *pdev)
++static void lvts_remove(struct platform_device *pdev)
+ {
+ struct lvts_domain *lvts_td;
+ int i;
+@@ -1252,8 +1252,6 @@ static int lvts_remove(struct platform_d
+ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
+
+ lvts_debugfs_exit(lvts_td);
+-
+- return 0;
+ }
+
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+@@ -1354,7 +1352,7 @@ MODULE_DEVICE_TABLE(of, lvts_of_match);
+
+ static struct platform_driver lvts_driver = {
+ .probe = lvts_probe,
+- .remove = lvts_remove,
++ .remove_new = lvts_remove,
+ .driver = {
+ .name = "mtk-lvts-thermal",
+ .of_match_table = lvts_of_match,
--- /dev/null
+From 26cc18a3d6d9eac21c4f4b4bb96147b2c6617c86 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:19 +0200
+Subject: [PATCH 36/42] thermal/drivers/mediatek/lvts_thermal: Make coeff
+ configurable
+
+The upcoming mt7988 has different temperature coefficients so we
+cannot use constants in the functions lvts_golden_temp_init,
+lvts_golden_temp_init and lvts_raw_to_temp anymore.
+
+Add a field in the lvts_ctrl pointing to the lvts_data which now
+contains the soc-specific temperature coefficents.
+
+To make the code better readable, rename static int coeff_b to
+golden_temp_offset, COEFF_A to temp_factor and COEFF_B to temp_offset.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-4-linux@fw-web.de
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 51 ++++++++++++++++---------
+ 1 file changed, 34 insertions(+), 17 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -80,8 +80,8 @@
+ #define LVTS_SENSOR_MAX 4
+ #define LVTS_GOLDEN_TEMP_MAX 62
+ #define LVTS_GOLDEN_TEMP_DEFAULT 50
+-#define LVTS_COEFF_A -250460
+-#define LVTS_COEFF_B 250460
++#define LVTS_COEFF_A_MT8195 -250460
++#define LVTS_COEFF_B_MT8195 250460
+
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+@@ -94,7 +94,7 @@
+ #define LVTS_MINIMUM_THRESHOLD 20000
+
+ static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
+-static int coeff_b = LVTS_COEFF_B;
++static int golden_temp_offset;
+
+ struct lvts_sensor_data {
+ int dt_id;
+@@ -112,6 +112,8 @@ struct lvts_ctrl_data {
+ struct lvts_data {
+ const struct lvts_ctrl_data *lvts_ctrl;
+ int num_lvts_ctrl;
++ int temp_factor;
++ int temp_offset;
+ };
+
+ struct lvts_sensor {
+@@ -126,6 +128,7 @@ struct lvts_sensor {
+
+ struct lvts_ctrl {
+ struct lvts_sensor sensors[LVTS_SENSOR_MAX];
++ const struct lvts_data *lvts_data;
+ u32 calibration[LVTS_SENSOR_MAX];
+ u32 hw_tshut_raw_temp;
+ int num_lvts_sensor;
+@@ -247,21 +250,21 @@ static void lvts_debugfs_exit(struct lvt
+
+ #endif
+
+-static int lvts_raw_to_temp(u32 raw_temp)
++static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
+ {
+ int temperature;
+
+- temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
+- temperature += coeff_b;
++ temperature = ((s64)(raw_temp & 0xFFFF) * temp_factor) >> 14;
++ temperature += golden_temp_offset;
+
+ return temperature;
+ }
+
+-static u32 lvts_temp_to_raw(int temperature)
++static u32 lvts_temp_to_raw(int temperature, int temp_factor)
+ {
+- u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
++ u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14;
+
+- raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
++ raw_temp = div_s64(raw_temp, -temp_factor);
+
+ return raw_temp;
+ }
+@@ -269,6 +272,9 @@ static u32 lvts_temp_to_raw(int temperat
+ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
++ sensors[lvts_sensor->id]);
++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
+ int rc;
+@@ -301,7 +307,7 @@ static int lvts_get_temp(struct thermal_
+ if (rc)
+ return -EAGAIN;
+
+- *temp = lvts_raw_to_temp(value & 0xFFFF);
++ *temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor);
+
+ return 0;
+ }
+@@ -348,10 +354,13 @@ static bool lvts_should_update_thresh(st
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+- struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
++ sensors[lvts_sensor->id]);
++ 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);
+- u32 raw_high = lvts_temp_to_raw(high);
++ 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);
+ bool should_update_thresh;
+
+ lvts_sensor->low_thresh = low;
+@@ -692,7 +701,7 @@ static int lvts_calibration_read(struct
+ return 0;
+ }
+
+-static int lvts_golden_temp_init(struct device *dev, u32 *value)
++static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset)
+ {
+ u32 gt;
+
+@@ -701,7 +710,7 @@ static int lvts_golden_temp_init(struct
+ if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
+ golden_temp = gt;
+
+- coeff_b = golden_temp * 500 + LVTS_COEFF_B;
++ golden_temp_offset = golden_temp * 500 + temp_offset;
+
+ return 0;
+ }
+@@ -724,7 +733,7 @@ static int lvts_ctrl_init(struct device
+ * The golden temp information is contained in the first chunk
+ * of efuse data.
+ */
+- ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset);
+ if (ret)
+ return ret;
+
+@@ -735,6 +744,7 @@ static int lvts_ctrl_init(struct device
+ for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
+
+ lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
++ lvts_ctrl[i].lvts_data = lvts_data;
+
+ ret = lvts_sensor_init(dev, &lvts_ctrl[i],
+ &lvts_data->lvts_ctrl[i]);
+@@ -758,7 +768,8 @@ static int lvts_ctrl_init(struct device
+ * after initializing the calibration.
+ */
+ lvts_ctrl[i].hw_tshut_raw_temp =
+- lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
++ lvts_data->temp_factor);
+
+ lvts_ctrl[i].low_thresh = INT_MIN;
+ lvts_ctrl[i].high_thresh = INT_MIN;
+@@ -1223,6 +1234,8 @@ static int lvts_probe(struct platform_de
+ if (irq < 0)
+ return irq;
+
++ golden_temp_offset = lvts_data->temp_offset;
++
+ ret = lvts_domain_init(dev, lvts_td, lvts_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
+@@ -1336,11 +1349,15 @@ static const struct lvts_ctrl_data mt819
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT8195,
++ .temp_offset = LVTS_COEFF_B_MT8195,
+ };
+
+ static const struct lvts_data mt8195_lvts_ap_data = {
+ .lvts_ctrl = mt8195_lvts_ap_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT8195,
++ .temp_offset = LVTS_COEFF_B_MT8195,
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
--- /dev/null
+From be2cc09bd5b46f13629d4fcdeac7ad1b18bb1a0b Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:18 +0200
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal sensors for
+ mt7988
+
+Add sensor constants for MT7988.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-3-linux@fw-web.de
+---
+ include/dt-bindings/thermal/mediatek,lvts-thermal.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -7,6 +7,15 @@
+ #ifndef __MEDIATEK_LVTS_DT_H
+ #define __MEDIATEK_LVTS_DT_H
+
++#define MT7988_CPU_0 0
++#define MT7988_CPU_1 1
++#define MT7988_ETH2P5G_0 2
++#define MT7988_ETH2P5G_1 3
++#define MT7988_TOPS_0 4
++#define MT7988_TOPS_1 5
++#define MT7988_ETHWARP_0 6
++#define MT7988_ETHWARP_1 7
++
+ #define MT8195_MCU_BIG_CPU0 0
+ #define MT8195_MCU_BIG_CPU1 1
+ #define MT8195_MCU_BIG_CPU2 2
--- /dev/null
+From 9924e9b91b43aaa1610a1d59c4caa43785948cf6 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:20 +0200
+Subject: [PATCH 37/42] thermal/drivers/mediatek/lvts_thermal: Add mt7988
+ support
+
+Add Support for Mediatek Filogic 880/MT7988 LVTS.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-5-linux@fw-web.de
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 38 +++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -82,6 +82,8 @@
+ #define LVTS_GOLDEN_TEMP_DEFAULT 50
+ #define LVTS_COEFF_A_MT8195 -250460
+ #define LVTS_COEFF_B_MT8195 250460
++#define LVTS_COEFF_A_MT7988 -204650
++#define LVTS_COEFF_B_MT7988 204650
+
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+@@ -89,6 +91,7 @@
+ #define LVTS_MSR_READ_TIMEOUT_US 400
+ #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
+
++#define LVTS_HW_SHUTDOWN_MT7988 105000
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -1267,6 +1270,33 @@ static void lvts_remove(struct platform_
+ lvts_debugfs_exit(lvts_td);
+ }
+
++static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x00, 0x04, 0x08, 0x0c },
++ .lvts_sensor = {
++ { .dt_id = MT7988_CPU_0 },
++ { .dt_id = MT7988_CPU_1 },
++ { .dt_id = MT7988_ETH2P5G_0 },
++ { .dt_id = MT7988_ETH2P5G_1 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
++ },
++ {
++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
++ .lvts_sensor = {
++ { .dt_id = MT7988_TOPS_0},
++ { .dt_id = MT7988_TOPS_1},
++ { .dt_id = MT7988_ETHWARP_0},
++ { .dt_id = MT7988_ETHWARP_1}
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
++ }
++};
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1346,6 +1376,13 @@ static const struct lvts_ctrl_data mt819
+ }
+ };
+
++static const struct lvts_data mt7988_lvts_ap_data = {
++ .lvts_ctrl = mt7988_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT7988,
++ .temp_offset = LVTS_COEFF_B_MT7988,
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
+@@ -1361,6 +1398,7 @@ static const struct lvts_data mt8195_lvt
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
++ { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
+ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
+ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ {},
--- /dev/null
+From fb1bbb5b63e4e3c788a978724749ced57d208054 Mon Sep 17 00:00:00 2001
+From: Minjie Du <duminjie@vivo.com>
+Date: Thu, 21 Sep 2023 17:10:50 +0800
+Subject: [PATCH 38/42] thermal/drivers/mediatek/lvts_thermal: Fix error check
+ in lvts_debugfs_init()
+
+debugfs_create_dir() function returns an error value embedded in
+the pointer (PTR_ERR). Evaluate the return value using IS_ERR
+rather than checking for NULL.
+
+Signed-off-by: Minjie Du <duminjie@vivo.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230921091057.3812-1-duminjie@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -219,7 +219,7 @@ static int lvts_debugfs_init(struct devi
+
+ sprintf(name, "controller%d", i);
+ dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
+- if (!dentry)
++ if (IS_ERR(dentry))
+ continue;
+
+ regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
--- /dev/null
+From e6f43063f2fe9f08b34797bc6d223f7d63b01910 Mon Sep 17 00:00:00 2001
+From: Markus Schneider-Pargmann <msp@baylibre.com>
+Date: Mon, 18 Sep 2023 12:07:06 +0200
+Subject: [PATCH 39/42] thermal/drivers/mediatek: Fix probe for THERMAL_V2
+
+Fix the probe function to call mtk_thermal_release_periodic_ts for
+everything != MTK_THERMAL_V1. This was accidentally changed from V1
+to V2 in the original patch.
+
+Reported-by: Frank Wunderlich <frank-w@public-files.de>
+Closes: https://lore.kernel.org/lkml/B0B3775B-B8D1-4284-814F-4F41EC22F532@public-files.de/
+Reported-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Closes: https://lore.kernel.org/lkml/07a569b9-e691-64ea-dd65-3b49842af33d@linaro.org/
+Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks")
+Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230918100706.1229239-1-msp@baylibre.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1268,7 +1268,7 @@ static int mtk_thermal_probe(struct plat
+
+ mtk_thermal_turn_on_buffer(mt, apmixed_base);
+
+- if (mt->conf->version != MTK_THERMAL_V2)
++ if (mt->conf->version != MTK_THERMAL_V1)
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+
+ if (mt->conf->version == MTK_THERMAL_V1)
--- /dev/null
+From a1d874ef3376295ee8ed89b3b5315f4c840ff00b Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:42 +0200
+Subject: [PATCH 40/42] thermal/drivers/mediatek/lvts_thermal: Add suspend and
+ resume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add suspend and resume support to LVTS driver.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+[bero@baylibre.com: suspend/resume in noirq phase]
+Co-developed-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-3-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 37 +++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1297,6 +1297,38 @@ static const struct lvts_ctrl_data mt798
+ }
+ };
+
++static int lvts_suspend(struct device *dev)
++{
++ struct lvts_domain *lvts_td;
++ int i;
++
++ lvts_td = dev_get_drvdata(dev);
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
++
++ clk_disable_unprepare(lvts_td->clk);
++
++ return 0;
++}
++
++static int lvts_resume(struct device *dev)
++{
++ struct lvts_domain *lvts_td;
++ int i, ret;
++
++ lvts_td = dev_get_drvdata(dev);
++
++ ret = clk_prepare_enable(lvts_td->clk);
++ if (ret)
++ return ret;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], true);
++
++ return 0;
++}
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1405,12 +1437,17 @@ static const struct of_device_id lvts_of
+ };
+ MODULE_DEVICE_TABLE(of, lvts_of_match);
+
++static const struct dev_pm_ops lvts_pm_ops = {
++ NOIRQ_SYSTEM_SLEEP_PM_OPS(lvts_suspend, lvts_resume)
++};
++
+ static struct platform_driver lvts_driver = {
+ .probe = lvts_probe,
+ .remove_new = lvts_remove,
+ .driver = {
+ .name = "mtk-lvts-thermal",
+ .of_match_table = lvts_of_match,
++ .pm = &lvts_pm_ops,
+ },
+ };
+ module_platform_driver(lvts_driver);
--- /dev/null
+From 0bb4937b58ab712f158588376dbac97f8e9df68e Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:41 +0200
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controller
+ definition for mt8192
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add LVTS thermal controller definition for MT8192.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-2-bero@baylibre.com
+---
+ .../thermal/mediatek,lvts-thermal.h | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -35,4 +35,23 @@
+ #define MT8195_AP_CAM0 15
+ #define MT8195_AP_CAM1 16
+
++#define MT8192_MCU_BIG_CPU0 0
++#define MT8192_MCU_BIG_CPU1 1
++#define MT8192_MCU_BIG_CPU2 2
++#define MT8192_MCU_BIG_CPU3 3
++#define MT8192_MCU_LITTLE_CPU0 4
++#define MT8192_MCU_LITTLE_CPU1 5
++#define MT8192_MCU_LITTLE_CPU2 6
++#define MT8192_MCU_LITTLE_CPU3 7
++
++#define MT8192_AP_VPU0 8
++#define MT8192_AP_VPU1 9
++#define MT8192_AP_GPU0 10
++#define MT8192_AP_GPU1 11
++#define MT8192_AP_INFRA 12
++#define MT8192_AP_CAM 13
++#define MT8192_AP_MD0 14
++#define MT8192_AP_MD1 15
++#define MT8192_AP_MD2 16
++
+ #endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From 7d8b3864b38d881cf105328ff8569f47446811ad Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:43 +0200
+Subject: [PATCH 41/42] thermal/drivers/mediatek/lvts_thermal: Add mt8192
+ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add LVTS Driver support for MT8192.
+
+Co-developed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+[bero@baylibre.com: cosmetic changes, rebase]
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-4-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 95 +++++++++++++++++++++++++
+ 1 file changed, 95 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -92,6 +92,7 @@
+ #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
+
+ #define LVTS_HW_SHUTDOWN_MT7988 105000
++#define LVTS_HW_SHUTDOWN_MT8192 105000
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -1329,6 +1330,88 @@ static int lvts_resume(struct device *de
+ return 0;
+ }
+
++static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
++ {
++ .cal_offset = { 0x04, 0x08 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_BIG_CPU0 },
++ { .dt_id = MT8192_MCU_BIG_CPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ },
++ {
++ .cal_offset = { 0x0c, 0x10 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_BIG_CPU2 },
++ { .dt_id = MT8192_MCU_BIG_CPU3 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ },
++ {
++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_LITTLE_CPU0 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU1 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU2 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU3 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ }
++};
++
++static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x24, 0x28 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_VPU0 },
++ { .dt_id = MT8192_AP_VPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x2c, 0x30 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_GPU0 },
++ { .dt_id = MT8192_AP_GPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x34, 0x38 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_INFRA },
++ { .dt_id = MT8192_AP_CAM },
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x3c, 0x40, 0x44 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_MD0 },
++ { .dt_id = MT8192_AP_MD1 },
++ { .dt_id = MT8192_AP_MD2 }
++ },
++ .num_lvts_sensor = 3,
++ .offset = 0x300,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ }
++};
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1415,6 +1498,16 @@ static const struct lvts_data mt7988_lvt
+ .temp_offset = LVTS_COEFF_B_MT7988,
+ };
+
++static const struct lvts_data mt8192_lvts_mcu_data = {
++ .lvts_ctrl = mt8192_lvts_mcu_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl),
++};
++
++static const struct lvts_data mt8192_lvts_ap_data = {
++ .lvts_ctrl = mt8192_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl),
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
+@@ -1431,6 +1524,8 @@ static const struct lvts_data mt8195_lvt
+
+ static const struct of_device_id lvts_of_match[] = {
+ { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
++ { .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
++ { .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 },
+ {},
--- /dev/null
+From 5d126a3c87cf7964b28bacf3826eea4266265bce Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:45 +0200
+Subject: [PATCH 42/42] thermal/drivers/mediatek/lvts_thermal: Update
+ calibration data documentation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Update LVTS calibration data documentation for mt8192 and mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+[bero@baylibre.com: Fix issues pointed out by Nícolas F. R. A. Prado <nfraprado@collabora.com>]
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-6-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 31 +++++++++++++++++++++++--
+ 1 file changed, 29 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -616,7 +616,34 @@ static int lvts_sensor_init(struct devic
+ * The efuse blob values follows the sensor enumeration per thermal
+ * controller. The decoding of the stream is as follow:
+ *
+- * stream index map for MCU Domain :
++ * MT8192 :
++ * Stream index map for MCU Domain mt8192 :
++ *
++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B
++ *
++ * <-----sensor#2-----> <-----sensor#3----->
++ * 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13
++ *
++ * <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
++ * 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23
++ *
++ * Stream index map for AP Domain mt8192 :
++ *
++ * <-----sensor#0-----> <-----sensor#1----->
++ * 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B
++ *
++ * <-----sensor#2-----> <-----sensor#3----->
++ * 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
++ *
++ * <-----sensor#4-----> <-----sensor#5----->
++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B
++ *
++ * <-----sensor#6-----> <-----sensor#7-----> <-----sensor#8----->
++ * 0x3C | 0x3D | 0x3E | 0x3F | 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47
++ *
++ * MT8195 :
++ * Stream index map for MCU Domain mt8195 :
+ *
+ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
+ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
+@@ -627,7 +654,7 @@ static int lvts_sensor_init(struct devic
+ * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
+ * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
+ *
+- * stream index map for AP Domain :
++ * Stream index map for AP Domain mt8195 :
+ *
+ * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
+ * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
--- /dev/null
+From patchwork Thu Sep 7 11:20:18 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Frank Wunderlich <linux@fw-web.de>
+X-Patchwork-Id: 13376356
+From: Frank Wunderlich <linux@fw-web.de>
+To: linux-mediatek@lists.infradead.org
+Subject: [PATCH] thermal/drivers/mediatek: Fix control buffer enablement on
+ MT7896
+Date: Thu, 7 Sep 2023 13:20:18 +0200
+Message-Id: <20230907112018.52811-1-linux@fw-web.de>
+X-Mailer: git-send-email 2.34.1
+MIME-Version: 1.0
+X-Mail-ID: e7eeb8e1-00de-41f6-a5df-ce2e9164136e
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.34
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>,
+ "Rafael J. Wysocki" <rafael@kernel.org>, linux-pm@vger.kernel.org,
+ Amit Kucheria <amitk@kernel.org>, Daniel Golle <daniel@makrotopia.org>,
+ stable@vger.kernel.org, linux-kernel@vger.kernel.org,
+ Matthias Brugger <matthias.bgg@gmail.com>, Zhang Rui <rui.zhang@intel.com>,
+ linux-arm-kernel@lists.infradead.org,
+ AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+
+From: Frank Wunderlich <frank-w@public-files.de>
+
+Reading thermal sensor on mt7986 devices returns invalid temperature:
+
+bpi-r3 ~ # cat /sys/class/thermal/thermal_zone0/temp
+ -274000
+
+Fix this by adding missing members in mtk_thermal_data struct which were
+used in mtk_thermal_turn_on_buffer after commit 33140e668b10.
+
+Cc: stable@vger.kernel.org
+Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks")
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Markus Schneider-Pargmann <msp@baylibre.com>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -691,6 +691,9 @@ static const struct mtk_thermal_data mt7
+ .adcpnp = mt7986_adcpnp,
+ .sensor_mux_values = mt7986_mux_values,
+ .version = MTK_THERMAL_V3,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
++ .apmixed_buffer_ctl_set = BIT(0),
+ };
+
+ static bool mtk_thermal_temp_is_valid(int temp)