Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions components/drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions components/drivers/thermal/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -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']

Expand Down
301 changes: 301 additions & 0 deletions components/drivers/thermal/thermal-cool-gpio-fan.c
Original file line number Diff line number Diff line change
@@ -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);
Loading
Loading