summaryrefslogtreecommitdiff
path: root/components/drivers
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2026-07-22 23:15:05 +0800
committerRbb666 <[email protected]>2026-08-06 11:09:50 +0800
commit96cf830d89e823eed4259d24725905c979f2aebb (patch)
tree598d9cf32f9906974d15a550642fba816357316c /components/drivers
parent73614c8684f6cffa934db68582769dbea3f89820 (diff)
[dm][thermal] update the thermal cooling
1. Fixup the cooling control flow. 2. Replace the spinlock to mutex. 3. Fixup the PWM args for PWM-FAN. 4. Add GPIO-FAN Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers')
-rw-r--r--components/drivers/thermal/Kconfig7
-rw-r--r--components/drivers/thermal/SConscript3
-rw-r--r--components/drivers/thermal/thermal-cool-gpio-fan.c301
-rw-r--r--components/drivers/thermal/thermal-cool-pwm-fan.c29
-rw-r--r--components/drivers/thermal/thermal.c42
5 files changed, 356 insertions, 26 deletions
diff --git a/components/drivers/thermal/Kconfig b/components/drivers/thermal/Kconfig
index bdde92c728..3cbb14b8bd 100644
--- a/components/drivers/thermal/Kconfig
+++ b/components/drivers/thermal/Kconfig
@@ -27,6 +27,13 @@ config RT_THERMAL_COOL_DVFS
depends on RT_USING_DVFS
default n
+config RT_THERMAL_COOL_GPIO_FAN
+ bool "GPIO Fan"
+ depends on RT_USING_THERMAL
+ depends on RT_USING_PIN
+ depends on RT_USING_OFW
+ default n
+
config RT_THERMAL_COOL_PWM_FAN
bool "PWM Fan"
depends on RT_USING_THERMAL
diff --git a/components/drivers/thermal/SConscript b/components/drivers/thermal/SConscript
index 015ff18d5a..f3db0cf68f 100644
--- a/components/drivers/thermal/SConscript
+++ b/components/drivers/thermal/SConscript
@@ -16,6 +16,9 @@ if GetDepend(['RT_THERMAL_SCMI']):
if GetDepend(['RT_THERMAL_COOL_DVFS']):
src += ['thermal-cool-dvfs.c']
+if GetDepend(['RT_THERMAL_COOL_GPIO_FAN']):
+ src += ['thermal-cool-gpio-fan.c']
+
if GetDepend(['RT_THERMAL_COOL_PWM_FAN']):
src += ['thermal-cool-pwm-fan.c']
diff --git a/components/drivers/thermal/thermal-cool-gpio-fan.c b/components/drivers/thermal/thermal-cool-gpio-fan.c
new file mode 100644
index 0000000000..6cce5dea1b
--- /dev/null
+++ b/components/drivers/thermal/thermal-cool-gpio-fan.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-3-08 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "thermal.cool.gpio-fan"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct gpio_fan_desc
+{
+ rt_base_t pin;
+ rt_uint8_t active_val;
+};
+
+struct gpio_fan_speed
+{
+ rt_uint32_t rpm;
+ rt_uint32_t ctrl_val;
+};
+
+struct gpio_fan_cool
+{
+ struct rt_thermal_cooling_device parent;
+
+ rt_size_t pins_nr;
+ struct gpio_fan_desc *pins_desc;
+
+ rt_size_t speed_nr;
+ rt_size_t speed_cur;
+ struct gpio_fan_speed *speed;
+
+ struct rt_mutex lock;
+};
+
+#define raw_to_gpio_fan_cool(raw) rt_container_of(raw, struct gpio_fan_cool, parent)
+
+static rt_err_t gpio_fan_cool_set_speed(struct gpio_fan_cool *gf_cool, rt_size_t speed_idx)
+{
+ rt_uint32_t ctrl_val = gf_cool->speed[speed_idx].ctrl_val;
+
+ for (int i = 0; i < gf_cool->pins_nr; ++i)
+ {
+ rt_uint8_t value = (ctrl_val >> i) & 1;
+
+ if (gf_cool->pins_desc[i].active_val)
+ {
+ value = !value;
+ }
+
+ rt_pin_mode(gf_cool->pins_desc[i].pin, PIN_MODE_OUTPUT);
+ rt_pin_write(gf_cool->pins_desc[i].pin, value);
+ }
+
+ gf_cool->speed_cur = speed_idx;
+
+ return RT_EOK;
+}
+
+static rt_size_t gpio_fan_cool_get_speed(struct gpio_fan_cool *gf_cool)
+{
+ rt_uint32_t ctrl_val = 0;
+
+ for (int i = 0; i < gf_cool->pins_nr; ++i)
+ {
+ rt_uint32_t value;
+
+ rt_pin_mode(gf_cool->pins_desc[i].pin, PIN_MODE_INPUT);
+ value = rt_pin_read(gf_cool->pins_desc[i].pin);
+
+ if (gf_cool->pins_desc[i].active_val)
+ {
+ value = !value;
+ }
+
+ ctrl_val |= (value << i);
+ }
+
+ for (int i = 0; i < gf_cool->speed_nr; ++i)
+ {
+ if (gf_cool->speed[i].ctrl_val == ctrl_val)
+ {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static rt_err_t gpio_fan_cool_get_max_level(struct rt_thermal_cooling_device *cdev,
+ rt_ubase_t *out_level)
+{
+ struct gpio_fan_cool *gf_cool = raw_to_gpio_fan_cool(cdev);
+
+ *out_level = gf_cool->speed_nr - 1;
+
+ return RT_EOK;
+}
+
+static rt_err_t gpio_fan_cool_get_cur_level(struct rt_thermal_cooling_device *cdev,
+ rt_ubase_t *out_level)
+{
+ struct gpio_fan_cool *gf_cool = raw_to_gpio_fan_cool(cdev);
+
+ *out_level = gf_cool->speed_cur;
+
+ return RT_EOK;
+}
+
+static rt_err_t gpio_fan_cool_set_cur_level(struct rt_thermal_cooling_device *cdev,
+ rt_ubase_t level)
+{
+ rt_err_t err;
+ struct gpio_fan_cool *gf_cool = raw_to_gpio_fan_cool(cdev);
+
+ if (level >= gf_cool->speed_nr)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_mutex_take(&gf_cool->lock, RT_WAITING_FOREVER);
+
+ if (gf_cool->speed_cur == level)
+ {
+ rt_mutex_release(&gf_cool->lock);
+
+ return RT_EOK;
+ }
+
+ err = gpio_fan_cool_set_speed(gf_cool, level);
+
+ rt_mutex_release(&gf_cool->lock);
+
+ return err;
+}
+
+const static struct rt_thermal_cooling_device_ops gpio_fan_cool_ops =
+{
+ .get_max_level = gpio_fan_cool_get_max_level,
+ .get_cur_level = gpio_fan_cool_get_cur_level,
+ .set_cur_level = gpio_fan_cool_set_cur_level,
+};
+
+static void gpio_fan_cool_free(struct gpio_fan_cool *gf_cool)
+{
+ if (gf_cool->pins_desc)
+ {
+ rt_free(gf_cool->pins_desc);
+
+ if (gf_cool->speed)
+ {
+ rt_free(gf_cool->speed);
+ }
+ }
+
+ rt_mutex_detach(&gf_cool->lock);
+
+ rt_free(gf_cool);
+}
+
+static rt_err_t gpio_fan_cool_probe(struct rt_platform_device *pdev)
+{
+ rt_err_t err;
+ const fdt32_t *cell = RT_NULL;
+ rt_uint32_t value = 0;
+ struct rt_ofw_prop *prop;
+ struct rt_device *dev = &pdev->parent;
+ struct rt_ofw_node *np = dev->ofw_node;
+ struct gpio_fan_cool *gf_cool = rt_calloc(1, sizeof(*gf_cool));
+
+ if (!gf_cool)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_mutex_init(&gf_cool->lock, rt_dm_dev_get_name(dev), RT_IPC_FLAG_PRIO);
+
+ gf_cool->pins_nr = rt_ofw_get_named_pin_count(np, RT_NULL);
+
+ if (gf_cool->pins_nr <= 0)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ gf_cool->pins_desc = rt_malloc(sizeof(*gf_cool->pins_desc) * gf_cool->pins_nr);
+
+ if (!gf_cool->pins_desc)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ for (int i = 0; i < gf_cool->pins_nr; ++i)
+ {
+ gf_cool->pins_desc[i].pin = rt_ofw_get_named_pin(np, RT_NULL, i, RT_NULL,
+ &gf_cool->pins_desc[i].active_val);
+
+ if (gf_cool->pins_desc[i].pin < 0)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+ }
+
+ prop = rt_ofw_get_prop(np, "gpio-fan,speed-map", (rt_ssize_t *)&gf_cool->speed_nr);
+
+ if (!prop)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ gf_cool->speed_nr /= (sizeof(rt_uint32_t) * 2);
+
+ if (!gf_cool->speed_nr)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ gf_cool->speed = rt_malloc(sizeof(*gf_cool->speed) * gf_cool->speed_nr);
+
+ if (!gf_cool->speed)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ for (int i = 0; i < gf_cool->speed_nr; ++i)
+ {
+ cell = rt_ofw_prop_next_u32(prop, cell, &value);
+ gf_cool->speed[i].rpm = value;
+
+ cell = rt_ofw_prop_next_u32(prop, cell, &value);
+ gf_cool->speed[i].ctrl_val = value;
+ }
+
+ gf_cool->speed_cur = gpio_fan_cool_get_speed(gf_cool);
+
+ rt_dm_dev_set_name(&gf_cool->parent.parent, "%s", rt_dm_dev_get_name(&pdev->parent));
+ gf_cool->parent.parent.ofw_node = dev->ofw_node;
+ gf_cool->parent.ops = &gpio_fan_cool_ops;
+
+ if ((err = rt_thermal_cooling_device_register(&gf_cool->parent)))
+ {
+ goto _fail;
+ }
+
+ dev->user_data = gf_cool;
+
+ return RT_EOK;
+
+_fail:
+ gpio_fan_cool_free(gf_cool);
+
+ return err;
+}
+
+static rt_err_t gpio_fan_cool_remove(struct rt_platform_device *pdev)
+{
+ struct gpio_fan_cool *gf_cool = pdev->parent.user_data;
+
+ rt_thermal_cooling_device_unregister(&gf_cool->parent);
+
+ gpio_fan_cool_set_speed(gf_cool, 0);
+ gpio_fan_cool_free(gf_cool);
+
+ return RT_EOK;
+}
+
+static rt_err_t gpio_fan_cool_shutdown(struct rt_platform_device *pdev)
+{
+ return gpio_fan_cool_remove(pdev);
+}
+
+static const struct rt_ofw_node_id gpio_fan_cool_ofw_ids[] =
+{
+ { .compatible = "gpio-fan" },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver gpio_fan_cool_driver =
+{
+ .name = "gpio-fan-cool",
+ .ids = gpio_fan_cool_ofw_ids,
+
+ .probe = gpio_fan_cool_probe,
+ .remove = gpio_fan_cool_remove,
+ .shutdown = gpio_fan_cool_shutdown,
+};
+RT_PLATFORM_DRIVER_EXPORT(gpio_fan_cool_driver);
diff --git a/components/drivers/thermal/thermal-cool-pwm-fan.c b/components/drivers/thermal/thermal-cool-pwm-fan.c
index 69a0899896..fde9d9a32a 100644
--- a/components/drivers/thermal/thermal-cool-pwm-fan.c
+++ b/components/drivers/thermal/thermal-cool-pwm-fan.c
@@ -30,7 +30,7 @@ struct pwm_fan_cool
struct rt_pwm_configuration pwm_conf;
struct rt_regulator *supply;
- struct rt_spinlock lock;
+ struct rt_mutex lock;
};
#define raw_to_pwm_fan_cool(raw) rt_container_of(raw, struct pwm_fan_cool, parent)
@@ -100,13 +100,20 @@ static rt_err_t pwm_fan_cool_set_cur_level(struct rt_thermal_cooling_device *cde
rt_err_t err = RT_EOK;
struct pwm_fan_cool *pf_cool = raw_to_pwm_fan_cool(cdev);
+ if (level > pf_cool->pwm_fan_max_level)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_mutex_take(&pf_cool->lock, RT_WAITING_FOREVER);
+
if (pf_cool->pwm_fan_level == level)
{
+ rt_mutex_release(&pf_cool->lock);
+
return RT_EOK;
}
- rt_spin_lock(&pf_cool->lock);
-
if ((pwm = pf_cool->pwm_fan_cooling_levels[level]))
{
rt_ubase_t period;
@@ -128,14 +135,14 @@ static rt_err_t pwm_fan_cool_set_cur_level(struct rt_thermal_cooling_device *cde
err = pwm_fan_power_off(pf_cool);
}
- rt_spin_unlock(&pf_cool->lock);
-
if (!err)
{
pf_cool->pwm_fan_level = level;
}
- return RT_EOK;
+ rt_mutex_release(&pf_cool->lock);
+
+ return err;
}
const static struct rt_thermal_cooling_device_ops pwm_fan_cool_ops =
@@ -157,6 +164,8 @@ static void pwm_fan_cool_free(struct pwm_fan_cool *pf_cool)
rt_free(pf_cool->pwm_fan_cooling_levels);
}
+ rt_mutex_detach(&pf_cool->lock);
+
rt_free(pf_cool);
}
@@ -174,6 +183,8 @@ static rt_err_t pwm_fan_cool_probe(struct rt_platform_device *pdev)
return -RT_ENOMEM;
}
+ rt_mutex_init(&pf_cool->lock, rt_dm_dev_get_name(dev), RT_IPC_FLAG_PRIO);
+
if (rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", 0, &pwm_args))
{
err = -RT_EINVAL;
@@ -231,8 +242,10 @@ static rt_err_t pwm_fan_cool_probe(struct rt_platform_device *pdev)
pf_cool->pwm_fan_level = MAX_PWM;
pf_cool->pwm_fan_max_level = levels_nr - 1;
- rt_spin_lock_init(&pf_cool->lock);
- pwm_fan_cool_set_cur_level(&pf_cool->parent, 0);
+ if ((err = pwm_fan_cool_set_cur_level(&pf_cool->parent, 0)))
+ {
+ goto _fail;
+ }
rt_dm_dev_set_name(&pf_cool->parent.parent, "%s", rt_dm_dev_get_name(&pdev->parent));
pf_cool->parent.parent.ofw_node = dev->ofw_node;
diff --git a/components/drivers/thermal/thermal.c b/components/drivers/thermal/thermal.c
index dc87ec87d0..371ee4d906 100644
--- a/components/drivers/thermal/thermal.c
+++ b/components/drivers/thermal/thermal.c
@@ -773,6 +773,7 @@ void rt_thermal_cooling_device_kick(struct rt_thermal_zone_device *zdev)
{
rt_ubase_t level;
rt_ubase_t max_level;
+ rt_ubase_t cur_level;
struct rt_thermal_cooling_device *cdev;
struct rt_thermal_cooling_cell *cell;
struct rt_thermal_cooling_map *map = &zdev->cooling_maps[i];
@@ -795,32 +796,37 @@ void rt_thermal_cooling_device_kick(struct rt_thermal_zone_device *zdev)
cdev->max_level = max_level;
- if (!zdev->cooling)
+ level = 0;
+
+ if (zdev->cooling)
{
- /* Release cooling: restore full performance (highest OPP). */
- if (!cdev->ops->get_cur_level(cdev, &level) && level != max_level)
+ for (int m = 0; m < zdev->cooling_maps_nr; ++m)
{
- cdev->ops->set_cur_level(cdev, max_level);
- }
- continue;
- }
+ struct rt_thermal_cooling_map *scan_map = &zdev->cooling_maps[m];
- if (cdev->ops->get_cur_level(cdev, &level) || level > max_level)
- {
- continue;
- }
+ if (zdev->temperature <= scan_map->trips->temperature)
+ {
+ continue;
+ }
- /* Check if cooling is required */
- if (level >= cell->level_range[0] && level <= cell->level_range[1])
- {
- /* Is cooling, not call */
- continue;
+ for (int sc = 0; sc < scan_map->cells_nr; ++sc)
+ {
+ struct rt_thermal_cooling_cell *scan_cell = &scan_map->cells[sc];
+
+ if (scan_cell->cooling_devices == cdev)
+ {
+ level = rt_max_t(rt_ubase_t, level, scan_cell->level_range[1]);
+ }
+ }
+ }
}
- cdev->gov->tuning(zdev, i, c, &level);
level = rt_min_t(rt_ubase_t, level, max_level);
- cdev->ops->set_cur_level(cdev, level);
+ if (!cdev->ops->get_cur_level(cdev, &cur_level) && cur_level != level)
+ {
+ cdev->ops->set_cur_level(cdev, level);
+ }
}
}
}