[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 <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2026-08-06 11:09:50 +08:00
committed by Rbb666
parent 73614c8684
commit 96cf830d89
5 changed files with 358 additions and 28 deletions
+7
View File
@@ -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
+3
View File
@@ -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']
@@ -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);
@@ -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,12 +100,19 @@ 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 (pf_cool->pwm_fan_level == level)
if (level > pf_cool->pwm_fan_max_level)
{
return RT_EOK;
return -RT_EINVAL;
}
rt_spin_lock(&pf_cool->lock);
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;
}
if ((pwm = pf_cool->pwm_fan_cooling_levels[level]))
{
@@ -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;
+25 -19
View File
@@ -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);
struct rt_thermal_cooling_map *scan_map = &zdev->cooling_maps[m];
if (zdev->temperature <= scan_map->trips->temperature)
{
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]);
}
}
}
continue;
}
if (cdev->ops->get_cur_level(cdev, &level) || level > max_level)
{
continue;
}
/* Check if cooling is required */
if (level >= cell->level_range[0] && level <= cell->level_range[1])
{
/* Is cooling, not call */
continue;
}
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);
}
}
}
}