Skip to content

Commit 12721a8

Browse files
committed
[DM/THERMAL] Add PWM cool fan
PWM fan is the most populate cool device. Signed-off-by: GuEe-GUI <[email protected]>
1 parent b8a89c2 commit 12721a8

File tree

3 files changed

+299
-0
lines changed

3 files changed

+299
-0
lines changed

Diff for: components/drivers/thermal/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ if RT_USING_THERMAL
1515
comment "Thermal Cool Drivers"
1616
endif
1717

18+
config RT_THERMAL_COOL_PWM_FAN
19+
bool "PWM Fan"
20+
depends on RT_USING_THERMAL
21+
depends on RT_USING_PWM
22+
depends on RT_USING_REGULATOR
23+
depends on RT_USING_OFW
24+
default n
25+
1826
if RT_USING_THERMAL
1927
osource "$(SOC_DM_THERMAL_COOL_DIR)/Kconfig"
2028
endif

Diff for: components/drivers/thermal/SConscript

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include']
1010

1111
src = ['thermal.c', 'thermal_dm.c']
1212

13+
if GetDepend(['RT_THERMAL_COOL_PWM_FAN']):
14+
src += ['thermal-cool-pwm-fan.c']
15+
1316
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
1417

1518
Return('group')

Diff for: components/drivers/thermal/thermal-cool-pwm-fan.c

+288
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/*
2+
* Copyright (c) 2006-2022, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2022-3-08 GuEe-GUI the first version
9+
*/
10+
11+
#include <rthw.h>
12+
#include <rtthread.h>
13+
#include <rtdevice.h>
14+
15+
#define DBG_TAG "thermal.cool.pwm-fan"
16+
#define DBG_LVL DBG_INFO
17+
#include <rtdbg.h>
18+
19+
#define MAX_PWM 255
20+
21+
struct pwm_fan_cool
22+
{
23+
struct rt_thermal_cooling_device parent;
24+
25+
rt_uint32_t pwm_fan_level;
26+
rt_uint32_t pwm_fan_max_level;
27+
rt_uint32_t *pwm_fan_cooling_levels;
28+
29+
struct rt_device_pwm *pwm_dev;
30+
struct rt_pwm_configuration pwm_conf;
31+
32+
struct rt_regulator *supply;
33+
struct rt_spinlock lock;
34+
};
35+
36+
#define raw_to_pwm_fan_cool(raw) rt_container_of(raw, struct pwm_fan_cool, parent)
37+
38+
static rt_err_t pwm_fan_power_on(struct pwm_fan_cool *pf_cool)
39+
{
40+
rt_err_t err = RT_EOK;
41+
42+
if ((err = rt_pwm_enable(pf_cool->pwm_dev, pf_cool->pwm_conf.channel)))
43+
{
44+
return err;
45+
}
46+
47+
if (pf_cool->supply && (err = rt_regulator_enable(pf_cool->supply)))
48+
{
49+
rt_pwm_disable(pf_cool->pwm_dev, pf_cool->pwm_conf.channel);
50+
51+
return err;
52+
}
53+
54+
return err;
55+
}
56+
57+
static rt_err_t pwm_fan_power_off(struct pwm_fan_cool *pf_cool)
58+
{
59+
rt_err_t err = RT_EOK;
60+
61+
if (pf_cool->supply && (err = rt_regulator_disable(pf_cool->supply)))
62+
{
63+
return err;
64+
}
65+
66+
if ((err = rt_pwm_disable(pf_cool->pwm_dev, pf_cool->pwm_conf.channel)))
67+
{
68+
rt_regulator_enable(pf_cool->supply);
69+
70+
return err;
71+
}
72+
73+
return err;
74+
}
75+
76+
static rt_err_t pwm_fan_cool_get_max_level(struct rt_thermal_cooling_device *cdev,
77+
rt_ubase_t *out_level)
78+
{
79+
struct pwm_fan_cool *pf_cool = raw_to_pwm_fan_cool(cdev);
80+
81+
*out_level = pf_cool->pwm_fan_max_level;
82+
83+
return RT_EOK;
84+
}
85+
86+
static rt_err_t pwm_fan_cool_get_cur_level(struct rt_thermal_cooling_device *cdev,
87+
rt_ubase_t *out_level)
88+
{
89+
struct pwm_fan_cool *pf_cool = raw_to_pwm_fan_cool(cdev);
90+
91+
*out_level = pf_cool->pwm_fan_level;
92+
93+
return RT_EOK;
94+
}
95+
96+
static rt_err_t pwm_fan_cool_set_cur_level(struct rt_thermal_cooling_device *cdev,
97+
rt_ubase_t level)
98+
{
99+
rt_ubase_t pwm;
100+
rt_err_t err = RT_EOK;
101+
struct pwm_fan_cool *pf_cool = raw_to_pwm_fan_cool(cdev);
102+
103+
if (pf_cool->pwm_fan_level == level)
104+
{
105+
return RT_EOK;
106+
}
107+
108+
rt_spin_lock(&pf_cool->lock);
109+
110+
if ((pwm = pf_cool->pwm_fan_cooling_levels[level]))
111+
{
112+
rt_ubase_t period;
113+
struct rt_pwm_configuration *pwm_conf = &pf_cool->pwm_conf;
114+
115+
period = pwm_conf->period;
116+
pwm_conf->pulse = RT_DIV_ROUND_UP(pwm * (period - 1), MAX_PWM);
117+
118+
err = rt_pwm_set(pf_cool->pwm_dev,
119+
pwm_conf->channel, pwm_conf->period, pwm_conf->pulse);
120+
121+
if (!err && pf_cool->pwm_fan_level == 0)
122+
{
123+
err = pwm_fan_power_on(pf_cool);
124+
}
125+
}
126+
else if (pf_cool->pwm_fan_level > 0)
127+
{
128+
err = pwm_fan_power_off(pf_cool);
129+
}
130+
131+
rt_spin_unlock(&pf_cool->lock);
132+
133+
if (!err)
134+
{
135+
pf_cool->pwm_fan_level = level;
136+
}
137+
138+
return RT_EOK;
139+
}
140+
141+
const static struct rt_thermal_cooling_device_ops pwm_fan_cool_ops =
142+
{
143+
.get_max_level = pwm_fan_cool_get_max_level,
144+
.get_cur_level = pwm_fan_cool_get_cur_level,
145+
.set_cur_level = pwm_fan_cool_set_cur_level,
146+
};
147+
148+
static void pwm_fan_cool_free(struct pwm_fan_cool *pf_cool)
149+
{
150+
if (!rt_is_err_or_null(pf_cool->supply))
151+
{
152+
rt_regulator_put(pf_cool->supply);
153+
}
154+
155+
if (pf_cool->pwm_fan_cooling_levels)
156+
{
157+
rt_free(pf_cool->pwm_fan_cooling_levels);
158+
}
159+
160+
rt_free(pf_cool);
161+
}
162+
163+
static rt_err_t pwm_fan_cool_probe(struct rt_platform_device *pdev)
164+
{
165+
rt_err_t err;
166+
int levels_nr;
167+
struct rt_ofw_cell_args pwm_args;
168+
struct rt_device *dev = &pdev->parent;
169+
struct rt_ofw_node *np = dev->ofw_node, *pwm_np;
170+
struct pwm_fan_cool *pf_cool = rt_calloc(1, sizeof(*pf_cool));
171+
172+
if (!pf_cool)
173+
{
174+
return -RT_ENOMEM;
175+
}
176+
177+
if (rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", 0, &pwm_args))
178+
{
179+
err = -RT_EINVAL;
180+
goto _fail;
181+
}
182+
183+
pwm_np = pwm_args.data;
184+
185+
if (!rt_ofw_data(pwm_np))
186+
{
187+
rt_platform_ofw_request(pwm_np);
188+
}
189+
190+
pf_cool->pwm_dev = rt_ofw_data(pwm_np);
191+
rt_ofw_node_put(pwm_np);
192+
193+
if (!pf_cool->pwm_dev)
194+
{
195+
err = -RT_EINVAL;
196+
goto _fail;
197+
}
198+
199+
pf_cool->pwm_conf.channel = pwm_args.args[0];
200+
pf_cool->pwm_conf.period = pwm_args.args[1];
201+
202+
pf_cool->supply = rt_regulator_get(dev, "fan");
203+
204+
if (rt_is_err(pf_cool->supply))
205+
{
206+
err = rt_ptr_err(pf_cool->supply);
207+
goto _fail;
208+
}
209+
210+
if ((levels_nr = rt_dm_dev_prop_count_of_u32(dev, "cooling-levels")) <= 0)
211+
{
212+
err = -RT_EINVAL;
213+
goto _fail;
214+
}
215+
216+
pf_cool->pwm_fan_cooling_levels = rt_calloc(levels_nr, sizeof(rt_uint32_t));
217+
218+
if (!pf_cool->pwm_fan_cooling_levels)
219+
{
220+
err = -RT_ENOMEM;
221+
goto _fail;
222+
}
223+
224+
if (rt_dm_dev_prop_read_u32_array_index(dev, "cooling-levels",
225+
0, levels_nr, pf_cool->pwm_fan_cooling_levels) <= 0)
226+
{
227+
err = -RT_EINVAL;
228+
goto _fail;
229+
}
230+
231+
pf_cool->pwm_fan_level = MAX_PWM;
232+
pf_cool->pwm_fan_max_level = levels_nr - 1;
233+
234+
rt_spin_lock_init(&pf_cool->lock);
235+
pwm_fan_cool_set_cur_level(&pf_cool->parent, 0);
236+
237+
rt_dm_dev_set_name(&pf_cool->parent.parent, "%s", rt_dm_dev_get_name(&pdev->parent));
238+
pf_cool->parent.parent.ofw_node = dev->ofw_node;
239+
pf_cool->parent.ops = &pwm_fan_cool_ops;
240+
241+
if ((err = rt_thermal_cooling_device_register(&pf_cool->parent)))
242+
{
243+
goto _fail;
244+
}
245+
246+
dev->user_data = pf_cool;
247+
248+
return RT_EOK;
249+
250+
_fail:
251+
pwm_fan_cool_free(pf_cool);
252+
253+
return err;
254+
}
255+
256+
static rt_err_t pwm_fan_cool_remove(struct rt_platform_device *pdev)
257+
{
258+
struct pwm_fan_cool *pf_cool = pdev->parent.ofw_node;
259+
260+
rt_thermal_cooling_device_unregister(&pf_cool->parent);
261+
262+
pwm_fan_power_off(pf_cool);
263+
pwm_fan_cool_free(pf_cool);
264+
265+
return RT_EOK;
266+
}
267+
268+
static rt_err_t pwm_fan_cool_shutdown(struct rt_platform_device *pdev)
269+
{
270+
return pwm_fan_cool_remove(pdev);
271+
}
272+
273+
static const struct rt_ofw_node_id pwm_fan_cool_ofw_ids[] =
274+
{
275+
{ .compatible = "pwm-fan" },
276+
{ /* sentinel */ }
277+
};
278+
279+
static struct rt_platform_driver pwm_fan_cool_driver =
280+
{
281+
.name = "pwm-fan-cool",
282+
.ids = pwm_fan_cool_ofw_ids,
283+
284+
.probe = pwm_fan_cool_probe,
285+
.remove = pwm_fan_cool_remove,
286+
.shutdown = pwm_fan_cool_shutdown,
287+
};
288+
RT_PLATFORM_DRIVER_EXPORT(pwm_fan_cool_driver);

0 commit comments

Comments
 (0)