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
pwm_fan_power_on(struct pwm_fan_cool * pf_cool)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
pwm_fan_power_off(struct pwm_fan_cool * pf_cool)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
pwm_fan_cool_get_max_level(struct rt_thermal_cooling_device * cdev,rt_ubase_t * out_level)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
pwm_fan_cool_get_cur_level(struct rt_thermal_cooling_device * cdev,rt_ubase_t * out_level)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
pwm_fan_cool_set_cur_level(struct rt_thermal_cooling_device * cdev,rt_ubase_t level)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
pwm_fan_cool_free(struct pwm_fan_cool * pf_cool)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
pwm_fan_cool_probe(struct rt_platform_device * pdev)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
pwm_fan_cool_remove(struct rt_platform_device * pdev)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
pwm_fan_cool_shutdown(struct rt_platform_device * pdev)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);
289