From: Bjørn Mork Date: Wed, 12 Feb 2025 19:45:51 +0000 (+0100) Subject: realtek: thermal driver for rtl838x and rtl930x SoCs X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=864d6743ee3fe8ab649ee1e9455c7e0de212ea3c;p=openwrt%2Fstaging%2Fsvanheule.git realtek: thermal driver for rtl838x and rtl930x SoCs Add simple driver reading the internal temperature sensor. Signed-off-by: Bjørn Mork Link: https://github.com/openwrt/openwrt/pull/17967 Signed-off-by: Sander Vanheule --- diff --git a/target/linux/realtek/dts/rtl838x.dtsi b/target/linux/realtek/dts/rtl838x.dtsi index 18da4c9380..abce9500fe 100644 --- a/target/linux/realtek/dts/rtl838x.dtsi +++ b/target/linux/realtek/dts/rtl838x.dtsi @@ -264,6 +264,11 @@ pinctrl-names = "default"; pinctrl-0 = <&mdio_aux_mdx>, <&aux_mode_mdio>; }; + + soc_thermal: thermal { + compatible = "realtek,rtl8380-thermal"; + #thermal-sensor-cells = <0>; + }; }; pinmux@1b000144 { @@ -364,4 +369,20 @@ interrupt-parent = <&intc>; interrupts = <20 2>; }; + + thermal_zones: thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + coefficients = <1000 0>; + thermal-sensors = <&soc_thermal>; + trips { + cpu-crit { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; }; diff --git a/target/linux/realtek/dts/rtl930x.dtsi b/target/linux/realtek/dts/rtl930x.dtsi index 94b755aeee..34d1ede54c 100644 --- a/target/linux/realtek/dts/rtl930x.dtsi +++ b/target/linux/realtek/dts/rtl930x.dtsi @@ -156,6 +156,11 @@ status = "disabled"; }; + + soc_thermal: thermal { + compatible = "realtek,rtl9300-thermal"; + #thermal-sensor-cells = <0>; + }; }; pinmux@1b00c600 { @@ -209,4 +214,20 @@ interrupt-parent = <&intc>; interrupts = <23 2>; }; + + thermal_zones: thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + coefficients = <1000 0>; + thermal-sensors = <&soc_thermal>; + trips { + critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; }; diff --git a/target/linux/realtek/files-6.6/drivers/thermal/realtek-thermal.c b/target/linux/realtek/files-6.6/drivers/thermal/realtek-thermal.c new file mode 100644 index 0000000000..242f11bd89 --- /dev/null +++ b/target/linux/realtek/files-6.6/drivers/thermal/realtek-thermal.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Realtek thermal sensor driver + * + * Copyright (C) 2025 Bjørn Mork > + */ + +#include +#include +#include +#include +#include +#include "thermal_hwmon.h" + +#define RTL8380_THERMAL_METER_CTRL0 0x98 +#define RTL8380_THERMAL_METER_CTRL1 0x9c +#define RTL8380_THERMAL_METER_CTRL2 0xa0 +#define RTL8380_THERMAL_METER_RESULT 0xa4 +#define RTL8380_TM_ENABLE BIT(0) +#define RTL8380_TEMP_VALID BIT(8) +#define RTL8380_TEMP_OUT_MASK GENMASK(6, 0) + +#define RTL9300_THERMAL_METER_CTRL0 0x60 +#define RTL9300_THERMAL_METER_CTRL1 0x64 +#define RTL9300_THERMAL_METER_CTRL2 0x68 +#define RTL9300_THERMAL_METER_RESULT0 0x6c +#define RTL9300_THERMAL_METER_RESULT1 0x70 +#define RTL9300_TM_ENABLE BIT(16) +#define RTL9300_TEMP_VALID BIT(24) +#define RTL9300_TEMP_OUT_MASK GENMASK(23, 16) +#define RTL9300_SAMPLE_DLY_SHIFT (16) +#define RTL9300_SAMPLE_DLY_MASK GENMASK(RTL9300_SAMPLE_DLY_SHIFT + 15, RTL9300_SAMPLE_DLY_SHIFT) +#define RTL9300_COMPARE_DLY_SHIFT (0) +#define RTL9300_COMPARE_DLY_MASK GENMASK(RTL9300_COMPARE_DLY_SHIFT + 15, RTL9300_COMPARE_DLY_SHIFT) + +struct realtek_thermal_priv { + struct regmap *regmap; + bool enabled; +}; + +static void rtl8380_thermal_init(struct realtek_thermal_priv *priv) +{ + priv->enabled = !regmap_update_bits(priv->regmap, RTL8380_THERMAL_METER_CTRL0, RTL8380_TM_ENABLE, RTL8380_TM_ENABLE); +} + +static int rtl8380_get_temp(struct thermal_zone_device *tz, int *res) +{ + struct realtek_thermal_priv *priv = thermal_zone_device_priv(tz); + int offset = thermal_zone_get_offset(tz); + int slope = thermal_zone_get_slope(tz); + u32 val; + int ret; + + if (!priv->enabled) + rtl8380_thermal_init(priv); + + ret = regmap_read(priv->regmap, RTL8380_THERMAL_METER_RESULT, &val); + if (ret) + return ret; + + if (!(val & RTL8380_TEMP_VALID)) + return -EAGAIN; + + *res = FIELD_GET(RTL8380_TEMP_OUT_MASK, val) * slope + offset; + return 0; +} + +static const struct thermal_zone_device_ops rtl8380_ops = { + .get_temp = rtl8380_get_temp, +}; + +static void rtl9300_thermal_init(struct realtek_thermal_priv *priv) +{ + /* increasing sample delay makes get_temp() succeed more often */ + regmap_update_bits(priv->regmap, RTL9300_THERMAL_METER_CTRL1, RTL9300_SAMPLE_DLY_MASK, 0x0800 << RTL9300_SAMPLE_DLY_SHIFT); + priv->enabled = !regmap_update_bits(priv->regmap, RTL9300_THERMAL_METER_CTRL2, RTL9300_TM_ENABLE, RTL9300_TM_ENABLE); +} + +static int rtl9300_get_temp(struct thermal_zone_device *tz, int *res) +{ + struct realtek_thermal_priv *priv = thermal_zone_device_priv(tz); + int offset = thermal_zone_get_offset(tz); + int slope = thermal_zone_get_slope(tz); + u32 val; + int ret; + + if (!priv->enabled) + rtl9300_thermal_init(priv); + + ret = regmap_read(priv->regmap, RTL9300_THERMAL_METER_RESULT0, &val); + if (ret) + return ret; + if (!(val & RTL9300_TEMP_VALID)) + return -EAGAIN; + + *res = FIELD_GET(RTL9300_TEMP_OUT_MASK, val) * slope + offset; + return 0; +} + +static const struct thermal_zone_device_ops rtl9300_ops = { + .get_temp = rtl9300_get_temp, +}; + +static int realtek_thermal_probe(struct platform_device *pdev) +{ + struct realtek_thermal_priv *priv; + struct thermal_zone_device *tzdev; + struct device *dev = &pdev->dev; + struct regmap *regmap; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + regmap = syscon_node_to_regmap(dev->of_node->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + priv->regmap = regmap; + tzdev = devm_thermal_of_zone_register(dev, 0, priv, device_get_match_data(dev)); + if (IS_ERR(tzdev)) + return PTR_ERR(tzdev); + + return devm_thermal_add_hwmon_sysfs(dev, tzdev); +} + +static const struct of_device_id realtek_sensor_ids[] = { + { .compatible = "realtek,rtl8380-thermal", .data = &rtl8380_ops, }, + { .compatible = "realtek,rtl9300-thermal", .data = &rtl9300_ops, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, realtek_sensor_ids); + +static struct platform_driver realtek_thermal_driver = { + .probe = realtek_thermal_probe, + .driver = { + .name = "realtek-thermal", + .of_match_table = realtek_sensor_ids, + }, +}; + +module_platform_driver(realtek_thermal_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bjørn Mork "); +MODULE_DESCRIPTION("Realtek temperature sensor"); diff --git a/target/linux/realtek/patches-6.6/330-add-realtek-thernal-driver.patch b/target/linux/realtek/patches-6.6/330-add-realtek-thernal-driver.patch new file mode 100644 index 0000000000..0c8d4ab3ab --- /dev/null +++ b/target/linux/realtek/patches-6.6/330-add-realtek-thernal-driver.patch @@ -0,0 +1,21 @@ +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -522,4 +522,11 @@ config LOONGSON2_THERMAL + is higher than the high temperature threshold or lower than the low + temperature threshold, the interrupt will occur. + ++config REALTEK_THERMAL ++ tristate "Realtek RTL838x and RTL930x thermal sensor support" ++ depends on RTL838X || RTL930X || COMPILE_TEST ++ depends on THERMAL_OF ++ help ++ Support thermal sensor in Realtek RTL838x and RTL930x SoCs ++ + endif +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -64,3 +64,4 @@ obj-$(CONFIG_AMLOGIC_THERMAL) += aml + obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o + obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o + obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o ++obj-$(CONFIG_REALTEK_THERMAL) += realtek-thermal.o diff --git a/target/linux/realtek/rtl838x/config-6.6 b/target/linux/realtek/rtl838x/config-6.6 index 3020e58a68..b193377dda 100644 --- a/target/linux/realtek/rtl838x/config-6.6 +++ b/target/linux/realtek/rtl838x/config-6.6 @@ -210,6 +210,7 @@ CONFIG_REALTEK_OTTO_TIMER=y CONFIG_REALTEK_OTTO_WDT=y CONFIG_REALTEK_PHY=y CONFIG_REALTEK_SOC_PHY=y +CONFIG_REALTEK_THERMAL=y CONFIG_REGMAP=y CONFIG_REGMAP_I2C=y CONFIG_REGMAP_MDIO=y @@ -237,6 +238,14 @@ CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y CONFIG_SYS_SUPPORTS_HIGHMEM=y CONFIG_SYS_SUPPORTS_MIPS16=y CONFIG_TARGET_ISA_REV=2 +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y CONFIG_TICK_CPU_ACCOUNTING=y CONFIG_TIMER_OF=y CONFIG_TIMER_PROBE=y diff --git a/target/linux/realtek/rtl930x/config-6.6 b/target/linux/realtek/rtl930x/config-6.6 index a381e88824..a79ad61c24 100644 --- a/target/linux/realtek/rtl930x/config-6.6 +++ b/target/linux/realtek/rtl930x/config-6.6 @@ -188,6 +188,7 @@ CONFIG_REALTEK_OTTO_TIMER=y CONFIG_REALTEK_OTTO_WDT=y CONFIG_REALTEK_PHY=y CONFIG_REALTEK_SOC_PHY=y +CONFIG_REALTEK_THERMAL=y CONFIG_REGMAP=y CONFIG_REGMAP_I2C=y CONFIG_REGMAP_MDIO=y @@ -216,6 +217,14 @@ CONFIG_SYS_SUPPORTS_HIGHMEM=y CONFIG_SYS_SUPPORTS_MIPS16=y CONFIG_SYS_SUPPORTS_MULTITHREADING=y CONFIG_TARGET_ISA_REV=2 +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y CONFIG_TICK_CPU_ACCOUNTING=y CONFIG_TIMER_OF=y CONFIG_TIMER_PROBE=y