mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-18 02:58:57 +08:00
[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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user