diff --git a/components/drivers/thermal/Kconfig b/components/drivers/thermal/Kconfig index bdde92c728b..3cbb14b8bd5 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 015ff18d5a6..f3db0cf68f1 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 00000000000..6cce5dea1bd --- /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 +#include +#include + +#define DBG_TAG "thermal.cool.gpio-fan" +#define DBG_LVL DBG_INFO +#include + +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 69a08998969..fde9d9a32ac 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 dc87ec87d03..371ee4d9062 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); + 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; - } + level = rt_min_t(rt_ubase_t, level, max_level); - /* Check if cooling is required */ - if (level >= cell->level_range[0] && level <= cell->level_range[1]) + if (!cdev->ops->get_cur_level(cdev, &cur_level) && cur_level != level) { - /* Is cooling, not call */ - continue; + cdev->ops->set_cur_level(cdev, level); } - - cdev->gov->tuning(zdev, i, c, &level); - level = rt_min_t(rt_ubase_t, level, max_level); - - cdev->ops->set_cur_level(cdev, level); } } }