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