【RK3399 Android10, 支持温控风扇】

【RK3399 Android10, 支持温控风扇】

需求描述

3399 Android10 的风扇,希望能做成温度控制的风扇,通过设置不同测温度阈值来实行不同的风速

patch

kernel

0020-feat-rochchip-system-monitor-add-temperature-notifye.patch

From 92116bdb9aa3efc280dd9c2699e8e82642860343 Mon Sep 17 00:00:00 2001
From: liangji <liangji@keenon.com>
Date: Tue, 26 Dec 2023 15:50:42 +0800
Subject: [PATCH 20/24] feat: rochchip system monitor add temperature notifyer

Change-Id: I8a561b9fdcaf4d15a8ee9e827eb3a350e342f55c
Signed-off-by: liangji <liangji@keenon.com>
---
 drivers/soc/rockchip/rockchip_system_monitor.c | 42 ++++++++++++++++++++++++--
 include/soc/rockchip/rockchip_system_monitor.h | 26 ++++++++++++++++
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/rockchip/rockchip_system_monitor.c b/drivers/soc/rockchip/rockchip_system_monitor.c
index 8a84d02..fcd980be 100644
--- a/drivers/soc/rockchip/rockchip_system_monitor.c
+++ b/drivers/soc/rockchip/rockchip_system_monitor.c
@@ -64,6 +64,7 @@ struct system_monitor {
 
 	struct thermal_zone_device *tz;
 	struct delayed_work thermal_work;
+	int last_temp;
 	int offline_cpus_temp;
 	int temp_hysteresis;
 	unsigned int delay;
@@ -84,6 +85,7 @@ static LIST_HEAD(monitor_dev_list);
 static struct system_monitor *system_monitor;
 static atomic_t monitor_in_suspend;
 
+static BLOCKING_NOTIFIER_HEAD(system_monitor_notifier_list);
 static BLOCKING_NOTIFIER_HEAD(system_status_notifier_list);
 
 int rockchip_register_system_status_notifier(struct notifier_block *nb)
@@ -1167,6 +1169,31 @@ void rockchip_system_monitor_unregister(struct monitor_dev_info *info)
 }
 EXPORT_SYMBOL(rockchip_system_monitor_unregister);
 
+int rockchip_system_monitor_register_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&system_monitor_notifier_list, nb);
+}
+EXPORT_SYMBOL(rockchip_system_monitor_register_notifier);
+
+void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&system_monitor_notifier_list, nb);
+}
+EXPORT_SYMBOL(rockchip_system_monitor_unregister_notifier);
+
+static int rockchip_system_monitor_temp_notify(int temp)
+{
+	struct system_monitor_event_data event_data;
+	int ret;
+
+	event_data.temp = temp;
+	ret = blocking_notifier_call_chain(&system_monitor_notifier_list,
+					   SYSTEM_MONITOR_CHANGE_TEMP,
+					   (void *)&event_data);
+
+	return notifier_to_errno(ret);
+}
+
 static int rockchip_system_monitor_parse_dt(struct system_monitor *monitor)
 {
 	struct device_node *np = monitor->dev->of_node;
@@ -1266,7 +1293,7 @@ static void rockchip_system_monitor_thermal_update(void)
 {
 	int temp, ret;
 	struct monitor_dev_info *info;
-	static int last_temp = INT_MAX;
+	//static int last_temp = INT_MAX;
 
 	ret = thermal_zone_get_temp(system_monitor->tz, &temp);
 	if (ret || temp == THERMAL_TEMP_INVALID)
@@ -1274,9 +1301,15 @@ static void rockchip_system_monitor_thermal_update(void)
 
 	dev_dbg(system_monitor->dev, "temperature=%d\n", temp);
 
-	if (temp < last_temp && last_temp - temp <= 2000)
+	//if (temp < last_temp && last_temp - temp <= 2000)
+	if (temp < system_monitor->last_temp &&
+	    system_monitor->last_temp - temp <= 2000)
 		goto out;
-	last_temp = temp;
+	//last_temp = temp;
+	system_monitor->last_temp = temp;
+
+	rockchip_system_monitor_temp_notify(temp);
+
 
 	down_read(&mdev_list_sem);
 	list_for_each_entry(info, &monitor_dev_list, node)
@@ -1379,6 +1412,8 @@ static int monitor_pm_notify(struct notifier_block *nb,
 		if (system_monitor->tz)
 			rockchip_system_monitor_thermal_update();
 		atomic_set(&monitor_in_suspend, 0);
+		system_monitor->last_temp = INT_MAX;
+
 		break;
 	default:
 		break;
@@ -1532,6 +1567,7 @@ static int rockchip_system_monitor_probe(struct platform_device *pdev)
 
 	rockchip_system_monitor_parse_dt(system_monitor);
 	if (system_monitor->tz) {
+		system_monitor->last_temp = INT_MAX;
 		INIT_DELAYED_WORK(&system_monitor->thermal_work,
 				  rockchip_system_monitor_thermal_check);
 		mod_delayed_work(system_freezable_wq,
diff --git a/include/soc/rockchip/rockchip_system_monitor.h b/include/soc/rockchip/rockchip_system_monitor.h
index 1f8bffc..bdc9a3f 100644
--- a/include/soc/rockchip/rockchip_system_monitor.h
+++ b/include/soc/rockchip/rockchip_system_monitor.h
@@ -6,11 +6,23 @@
 #ifndef __SOC_ROCKCHIP_SYSTEM_MONITOR_H
 #define __SOC_ROCKCHIP_SYSTEM_MONITOR_H
 
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+
 enum monitor_dev_type {
 	MONITOR_TPYE_CPU = 0,	/* CPU */
 	MONITOR_TPYE_DEV,	/* GPU, NPU, DMC, and so on */
 };
 
+enum system_monitor_event_type {
+	SYSTEM_MONITOR_CHANGE_TEMP = 0,
+};
+
+struct system_monitor_event_data {
+	int temp;
+};
+
 struct volt_adjust_table {
 	unsigned int min;	/* Minimum frequency in MHz */
 	unsigned int max;	/* Maximum frequency in MHz */
@@ -127,6 +139,8 @@ int rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info *info,
 int rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info,
 					  bool is_high);
 int rockchip_monitor_suspend_low_temp_adjust(int cpu);
+int rockchip_system_monitor_register_notifier(struct notifier_block *nb);
+void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb);
 int
 rockchip_system_monitor_adjust_cdev_state(struct thermal_cooling_device *cdev,
 					  int temp, unsigned long *state);
@@ -177,6 +191,18 @@ static inline int rockchip_monitor_suspend_low_temp_adjust(int cpu)
 };
 
 static inline int
+rockchip_system_monitor_register_notifier(struct notifier_block *nb)
+{
+	return 0;
+};
+
+static inline void
+rockchip_system_monitor_unregister_notifier(struct notifier_block *nb)
+{
+};
+
+
+static inline int
 rockchip_system_monitor_adjust_cdev_state(struct thermal_cooling_device *cdev,
 					  int temp, unsigned long *state)
 {
-- 
2.7.4


0021-feat-rockchip-system-status-use-IS_REACHABLE.patch

From a5b79acc99fe356dba8f3a51ee7918bfb885b679 Mon Sep 17 00:00:00 2001
From: liangji <liangji@keenon.com>
Date: Tue, 26 Dec 2023 16:00:13 +0800
Subject: [PATCH 21/24] feat: rockchip system status use IS_REACHABLE

Change-Id: I62e6deba1e511d14a3c11431fd04fcfcde65d5c3
Signed-off-by: liangji <liangji@keenon.com>
---
 include/soc/rockchip/rockchip-system-status.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/soc/rockchip/rockchip-system-status.h b/include/soc/rockchip/rockchip-system-status.h
index 200b1ee..de639b9 100644
--- a/include/soc/rockchip/rockchip-system-status.h
+++ b/include/soc/rockchip/rockchip-system-status.h
@@ -6,7 +6,8 @@
 #ifndef __SOC_ROCKCHIP_SYSTEM_STATUS_H
 #define __SOC_ROCKCHIP_SYSTEM_STATUS_H
 
-#if IS_ENABLED(CONFIG_ROCKCHIP_SYSTEM_MONITOR)
+//#if IS_ENABLED(CONFIG_ROCKCHIP_SYSTEM_MONITOR)
+#if IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR)
 int rockchip_register_system_status_notifier(struct notifier_block *nb);
 int rockchip_unregister_system_status_notifier(struct notifier_block *nb);
 void rockchip_set_system_status(unsigned long status);
-- 
2.7.4


0022-feat-hwmon-pwm-fan-add-system-monitor-notifyer.patch

From bf6df7f1173b10fadcd56ba8f9e3a357cf6613a0 Mon Sep 17 00:00:00 2001
From: liangji <liangji@keenon.com>
Date: Tue, 26 Dec 2023 16:10:13 +0800
Subject: [PATCH 22/24] feat: hwmon pwm fan add system monitor notifyer

Change-Id: Iaf0483d68ed46000d6eb43b3d41a34f7b4b55f4e
Signed-off-by: liangji <liangji@keenon.com>
---
 .../devicetree/bindings/hwmon/pwm-fan.txt          |   5 +
 drivers/hwmon/pwm-fan.c                            | 114 ++++++++++++++++++++-
 2 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
index c6d5332..282bca2 100644
--- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
+++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
@@ -5,6 +5,11 @@ Required properties:
 - pwms		: the PWM that is used to control the PWM fan
 - cooling-levels      : PWM duty cycle values in a range from 0 to 255
 			which correspond to thermal cooling states
+- rockchip,temp-trips	: The property is an array of 2-tuples items, and
+			  each item consists of temperature in millicelsius and
+			  pwm cooling state. This depends on CONFIG_ROCKCHIP_SYSTEM_MONITOR.
+			  If add the property the fan cooling state will be changed
+			  by system monitor. Otherwise, use the default thermal governor.
 
 Example:
 	fan0: pwm-fan {
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index db0d15c..5ba1820 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -25,9 +25,15 @@
 #include <linux/pwm.h>
 #include <linux/sysfs.h>
 #include <linux/thermal.h>
+#include <soc/rockchip/rockchip_system_monitor.h>
 
 #define MAX_PWM 255
 
+struct thermal_trips {
+	int temp;
+	int state;
+};
+
 struct pwm_fan_ctx {
 	struct mutex lock;
 	struct pwm_device *pwm;
@@ -36,6 +42,9 @@ struct pwm_fan_ctx {
 	unsigned int pwm_fan_max_state;
 	unsigned int *pwm_fan_cooling_levels;
 	struct thermal_cooling_device *cdev;
+	struct notifier_block thermal_nb;
+	struct thermal_trips *thermal_trips;
+	bool thermal_notifier_is_ok;
 };
 
 static int  __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
@@ -205,6 +214,95 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
 	return 0;
 }
 
+static int pwm_fan_get_thermal_trips(struct device *dev, char *porp_name,
+				     struct thermal_trips **trips)
+{
+	struct device_node *np = dev->of_node;
+	struct thermal_trips *thermal_trips;
+	const struct property *prop;
+	int count, i;
+
+	prop = of_find_property(np, porp_name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+	count = of_property_count_u32_elems(np, porp_name);
+	if (count < 0)
+		return -EINVAL;
+	if (count % 2)
+		return -EINVAL;
+	thermal_trips = devm_kzalloc(dev,
+				     sizeof(*thermal_trips) * (count / 2 + 1),
+				     GFP_KERNEL);
+	if (!thermal_trips)
+		return -ENOMEM;
+
+	for (i = 0; i < count / 2; i++) {
+		of_property_read_u32_index(np, porp_name, 2 * i,
+					   &thermal_trips[i].temp);
+		of_property_read_u32_index(np, porp_name, 2 * i + 1,
+					   &thermal_trips[i].state);
+	}
+	thermal_trips[i].temp = 0;
+	thermal_trips[i].state = INT_MAX;
+
+	*trips = thermal_trips;
+
+	return 0;
+}
+
+static int pwm_fan_temp_to_state(struct pwm_fan_ctx *ctx, int temp)
+{
+	struct thermal_trips *trips = ctx->thermal_trips;
+	int i, state = 0;
+
+	for (i = 0; trips[i].state != INT_MAX; i++) {
+		if (temp >= trips[i].temp)
+			state = trips[i].state;
+	}
+
+	return state;
+}
+
+static int pwm_fan_thermal_notifier_call(struct notifier_block *nb,
+					 unsigned long event, void *data)
+{
+	struct pwm_fan_ctx *ctx = container_of(nb, struct pwm_fan_ctx, thermal_nb);
+	struct system_monitor_event_data *event_data = data;
+	int state, ret;
+
+	if (event != SYSTEM_MONITOR_CHANGE_TEMP)
+		return NOTIFY_OK;
+
+	state = pwm_fan_temp_to_state(ctx, event_data->temp);
+	if (state > ctx->pwm_fan_max_state)
+		return NOTIFY_BAD;
+	if (state == ctx->pwm_fan_state)
+		return NOTIFY_OK;
+
+	ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
+	if (ret)
+		return NOTIFY_BAD;
+
+	ctx->pwm_fan_state = state;
+
+	return NOTIFY_OK;
+}
+
+static int pwm_fan_register_thermal_notifier(struct device *dev,
+					     struct pwm_fan_ctx *ctx)
+{
+	if (pwm_fan_get_thermal_trips(dev, "rockchip,temp-trips",
+				      &ctx->thermal_trips))
+		return -EINVAL;
+
+	ctx->thermal_nb.notifier_call = pwm_fan_thermal_notifier_call;
+
+	return rockchip_system_monitor_register_notifier(&ctx->thermal_nb);
+}
+
+
 static int pwm_fan_probe(struct platform_device *pdev)
 {
 	struct thermal_cooling_device *cdev;
@@ -257,6 +355,16 @@ static int pwm_fan_probe(struct platform_device *pdev)
 		goto err_pwm_disable;
 
 	ctx->pwm_fan_state = ctx->pwm_fan_max_state;
+	if (IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) &&
+	    of_find_property(dev->of_node, "rockchip,temp-trips", NULL)) {
+		ret = pwm_fan_register_thermal_notifier(dev, ctx);
+		if (ret)
+			dev_err(dev, "Failed to register thermal notifier: %d\n", ret);
+		else
+			ctx->thermal_notifier_is_ok = true;
+		return 0;
+	}
+
 	if (IS_ENABLED(CONFIG_THERMAL)) {
 		cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
 							  "pwm-fan", ctx,
@@ -299,7 +407,8 @@ static int pwm_fan_suspend(struct device *dev)
 
 	pwm_get_args(ctx->pwm, &args);
 
-	if (ctx->pwm_value) {
+	//if (ctx->pwm_value) {
+	if (ctx->pwm_value || ctx->thermal_notifier_is_ok) {
 		ret = pwm_config(ctx->pwm, 0, args.period);
 		if (ret < 0)
 			return ret;
@@ -317,7 +426,8 @@ static int pwm_fan_resume(struct device *dev)
 	unsigned long duty;
 	int ret;
 
-	if (ctx->pwm_value == 0)
+	//if (ctx->pwm_value == 0)
+	if (ctx->pwm_value == 0 && !ctx->thermal_notifier_is_ok)
 		return 0;
 
 	pwm_get_args(ctx->pwm, &pargs);
-- 
2.7.4


0023-feat-support-system-monitor-pwm-fan.patch

From 1cf46863c45c54007f1b4b9acf541781f138b215 Mon Sep 17 00:00:00 2001
From: liangji <liangji@keenon.com>
Date: Tue, 26 Dec 2023 16:59:57 +0800
Subject: [PATCH 23/24] feat: support system monitor pwm fan

Change-Id: Id40a42b3f2d185a9c6c5054125e4566b91c6c784
Signed-off-by: liangji <liangji@keenon.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-keenon-common.dtsi | 14 ++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-keenon-w3s.dts     |  4 ++++
 arch/arm64/configs/keenon_tablet_w3s_defconfig         |  1 +
 drivers/hwmon/pwm-fan.c                                |  6 +++---
 4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-keenon-common.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-keenon-common.dtsi
index fae2f81..33a10a4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-keenon-common.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-keenon-common.dtsi
@@ -254,6 +254,20 @@
 		compatible = "fake,battery";
 		status = "okay";
 	};
+
+    fan: pwm-fan {
+        compatible = "pwm-fan";
+        #cooling-cells = <2>;
+        pwms = <&pwm3 0 50000 0>;
+        cooling-levels = <0 50 100 150 200 255>;
+        rockchip,temp-trips = <
+                50000   1
+                60000   2
+                70000   3
+                80000   4
+                100000   5
+        >;
+    };
 };
 
 &backlight {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-keenon-w3s.dts b/arch/arm64/boot/dts/rockchip/rk3399-keenon-w3s.dts
index 7a47c04..b8a2637 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-keenon-w3s.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-keenon-w3s.dts
@@ -18,6 +18,10 @@
 	status = "okay";
 };
 
+&pwm3{
+	status = "okay";
+};
+
 &backlight {
 	enable-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
diff --git a/arch/arm64/configs/keenon_tablet_w3s_defconfig b/arch/arm64/configs/keenon_tablet_w3s_defconfig
index 89c6e3c..db151c1 100644
--- a/arch/arm64/configs/keenon_tablet_w3s_defconfig
+++ b/arch/arm64/configs/keenon_tablet_w3s_defconfig
@@ -27,6 +27,7 @@ CONFIG_NAMESPACES=y
 # CONFIG_PID_NS is not set
 CONFIG_SCHED_TUNE=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_SENSORS_PWM_FAN=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
 # CONFIG_RD_XZ is not set
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 5ba1820..0d3674d 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -356,10 +356,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
 
 	ctx->pwm_fan_state = ctx->pwm_fan_max_state;
 	if (IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) &&
-	    of_find_property(dev->of_node, "rockchip,temp-trips", NULL)) {
-		ret = pwm_fan_register_thermal_notifier(dev, ctx);
+	    of_find_property(pdev->dev.of_node, "rockchip,temp-trips", NULL)) {
+		ret = pwm_fan_register_thermal_notifier(&pdev->dev, ctx);
 		if (ret)
-			dev_err(dev, "Failed to register thermal notifier: %d\n", ret);
+			dev_err(&pdev->dev, "Failed to register thermal notifier: %d\n", ret);
 		else
 			ctx->thermal_notifier_is_ok = true;
 		return 0;
-- 
2.7.4


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值