From f29dfe25baaa5c03f2b52f49dfdc12ed99abe8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Valentin?= Date: Tue, 25 Aug 2026 19:51:12 +0200 Subject: [PATCH] qualcommax: ipq807x: nbg7815: add fan and second temp sensor support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NBG7815 cools itself with a GPIO driven fan on TLMM 21. A second tmp103 sits on the second I2C bus (BLSP QUP4), which the stock firmware reads as the board temperature, and the stock firmware keeps GPIO 22 high to enable the second fan. The switching points come from the stock firmware, which controls the fan from a shell daemon /usr/sbin/fanctld, configured in /etc/config/fanctld: config fanctld config option Enabled '1' option Delay '20' option Hits '3' option TempTrig '108' option TempClr '85' fanctld polls every 20 s and starts the fan once any of thermal_zone0 (nss-top), wifi0 or wifi1 has been at or above TempTrig for three consecutive polls. It stops the fan again only after all three have been at or below TempClr for three polls: if [ $temp1 -ge $temp_trig -o $temp2 -ge $temp_trig -o $temp3 -ge $temp_trig ]; then echo 2 elif [ $temp1 -le $temp_clr -a $temp2 -le $temp_clr -a $temp3 -le $temp_clr ]; then echo 1 The trip is placed at 85 degC with 5 degC hysteresis, so the fan runs from 85 degC and stops again at 80 degC, rather than at the stock 108/85: the SoC hardly reaches 108, so the case gets uncomfortably hot under load before the fan would ever start, as reported for this device in https://github.com/openwrt/openwrt/pull/14210 It sits on the CPU cluster rather than on the sensors the stock daemon polls: the wifi sensors are only reachable through the vendor thermaltool there, and one zone is enough to drive the fan. Add the gpio-fan as a cooling device with that trip, enable the second I2C bus with its tmp103, add the gpio-hog for the second fan enable and describe the USB VBUS switch on GPIO 32 as a regulator rather than hogging it. That regulator carries enable-active-high. For regulator-fixed, gpiolib ignores the flag in the GPIO specifier and takes the line as active low without that property, so the regulator would drive GPIO 32 low at probe - logged as "enforce active low on GPIO handle" - while the stock firmware holds the line high. The AQR PHY is deliberately left out of the cooling maps: its driver rejects the low trip the thermal core installs by default, so a thermal zone bound to it fails to set its trips. Co-developed-by: Semih Baskan Signed-off-by: Semih Baskan Signed-off-by: André Valentin --- .../linux/qualcommax/dts/ipq8074-nbg7815.dts | 93 ++++++++++++++++++- target/linux/qualcommax/image/ipq807x.mk | 2 +- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/target/linux/qualcommax/dts/ipq8074-nbg7815.dts b/target/linux/qualcommax/dts/ipq8074-nbg7815.dts index f4eed1345a8..8967f7a1a0c 100644 --- a/target/linux/qualcommax/dts/ipq8074-nbg7815.dts +++ b/target/linux/qualcommax/dts/ipq8074-nbg7815.dts @@ -43,6 +43,25 @@ gpios = <&tlmm 54 GPIO_ACTIVE_LOW>; }; }; + + fan: fan { + compatible = "gpio-fan"; + gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + /* nominal rpm of the stock fan */ + gpio-fan,speed-map = <0 0>, + <3000 1>; + #cooling-cells = <2>; + }; + + usb_vbus: regulator-usb-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; }; &tlmm { @@ -62,7 +81,27 @@ }; }; - /* the stock firmware keeps gpio60 high to enable the LED board */ + i2c_1_pins: i2c1-pins { + mux { + pins = "gpio50", "gpio51"; + function = "blsp3_i2c"; + drive-strength = <8>; + bias-disable; + }; + }; + + /* + * The stock firmware keeps these outputs high: + * gpio22: second fan enable + * gpio60: LED board enable + */ + fan2-en { + gpio-hog; + gpios = <22 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "fan2-enable"; + }; + led-en { gpio-hog; gpios = <60 GPIO_ACTIVE_HIGH>; @@ -728,6 +767,33 @@ }; +/* use the second I2C bus for the second temperature sensor */ +/delete-node/ &blsp1_spi4; + +&soc { + i2c@78b8000 { + compatible = "qcom,i2c-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x078b8000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + clock-frequency = <400000>; + dmas = <&blsp_dma 18>, <&blsp_dma 19>; + dma-names = "tx", "rx"; + pinctrl-0 = <&i2c_1_pins>; + pinctrl-names = "default"; + status = "okay"; + + tmp103@70 { + compatible = "ti,tmp103"; + reg = <0x70>; + }; + }; +}; + &sdhc_1 { status = "okay"; /* unstable, problem with the hs400 > h200 speed switch */ @@ -750,6 +816,7 @@ }; &qusb_phy_1 { + vdd-supply = <&usb_vbus>; status = "okay"; }; @@ -770,3 +837,27 @@ qcom,ath11k-calibration-variant = "Zyxel-NBG7815"; }; + +&cluster_thermal { + trips { + cluster_fan: cluster-fan { + /* + * The stock firmware only switches the fan at 108/85 + * degC, which the SoC hardly ever reaches, so the case + * gets uncomfortably hot under load first. Start it at + * 85 degC instead, as discussed for this device in + * https://github.com/openwrt/openwrt/pull/14210 + */ + temperature = <85000>; + hysteresis = <5000>; + type = "active"; + }; + }; + + cooling-maps { + map2 { + trip = <&cluster_fan>; + cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; +}; diff --git a/target/linux/qualcommax/image/ipq807x.mk b/target/linux/qualcommax/image/ipq807x.mk index f61c9cafeeb..de7225767f4 100644 --- a/target/linux/qualcommax/image/ipq807x.mk +++ b/target/linux/qualcommax/image/ipq807x.mk @@ -630,7 +630,7 @@ define Device/zyxel_nbg7815 DEVICE_DTS_CONFIG := config@nbg7815 SOC := ipq8074 DEVICE_PACKAGES := kmod-fs-f2fs f2fs-tools ipq-wifi-zyxel_nbg7815 kmod-ath11k-pci \ - kmod-hci-uart kmod-hwmon-tmp103 \ + kmod-hci-uart kmod-hwmon-tmp103 kmod-hwmon-gpiofan \ kmod-leds-lp5569 endef TARGET_DEVICES += zyxel_nbg7815