1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * pwm-fan.c - Hwmon driver for fans connected to PWM lines. |
4 | * |
5 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. |
6 | * |
7 | * Author: Kamil Debski <k.debski@samsung.com> |
8 | */ |
9 | |
10 | #include <linux/hwmon.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mutex.h> |
14 | #include <linux/of.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/pwm.h> |
17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/sysfs.h> |
19 | #include <linux/thermal.h> |
20 | #include <linux/timer.h> |
21 | |
22 | #define MAX_PWM 255 |
23 | |
24 | struct pwm_fan_tach { |
25 | int irq; |
26 | atomic_t pulses; |
27 | unsigned int rpm; |
28 | u8 pulses_per_revolution; |
29 | }; |
30 | |
31 | enum pwm_fan_enable_mode { |
32 | pwm_off_reg_off, |
33 | pwm_disable_reg_enable, |
34 | pwm_enable_reg_enable, |
35 | pwm_disable_reg_disable, |
36 | }; |
37 | |
38 | struct pwm_fan_ctx { |
39 | struct device *dev; |
40 | |
41 | struct mutex lock; |
42 | struct pwm_device *pwm; |
43 | struct pwm_state pwm_state; |
44 | struct regulator *reg_en; |
45 | enum pwm_fan_enable_mode enable_mode; |
46 | bool regulator_enabled; |
47 | bool enabled; |
48 | |
49 | int tach_count; |
50 | struct pwm_fan_tach *tachs; |
51 | ktime_t sample_start; |
52 | struct timer_list rpm_timer; |
53 | |
54 | unsigned int pwm_value; |
55 | unsigned int pwm_fan_state; |
56 | unsigned int pwm_fan_max_state; |
57 | unsigned int *pwm_fan_cooling_levels; |
58 | struct thermal_cooling_device *cdev; |
59 | |
60 | struct hwmon_chip_info info; |
61 | struct hwmon_channel_info fan_channel; |
62 | }; |
63 | |
64 | /* This handler assumes self resetting edge triggered interrupt. */ |
65 | static irqreturn_t pulse_handler(int irq, void *dev_id) |
66 | { |
67 | struct pwm_fan_tach *tach = dev_id; |
68 | |
69 | atomic_inc(v: &tach->pulses); |
70 | |
71 | return IRQ_HANDLED; |
72 | } |
73 | |
74 | static void sample_timer(struct timer_list *t) |
75 | { |
76 | struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer); |
77 | unsigned int delta = ktime_ms_delta(later: ktime_get(), earlier: ctx->sample_start); |
78 | int i; |
79 | |
80 | if (delta) { |
81 | for (i = 0; i < ctx->tach_count; i++) { |
82 | struct pwm_fan_tach *tach = &ctx->tachs[i]; |
83 | int pulses; |
84 | |
85 | pulses = atomic_read(v: &tach->pulses); |
86 | atomic_sub(i: pulses, v: &tach->pulses); |
87 | tach->rpm = (unsigned int)(pulses * 1000 * 60) / |
88 | (tach->pulses_per_revolution * delta); |
89 | } |
90 | |
91 | ctx->sample_start = ktime_get(); |
92 | } |
93 | |
94 | mod_timer(timer: &ctx->rpm_timer, expires: jiffies + HZ); |
95 | } |
96 | |
97 | static void pwm_fan_enable_mode_2_state(int enable_mode, |
98 | struct pwm_state *state, |
99 | bool *enable_regulator) |
100 | { |
101 | switch (enable_mode) { |
102 | case pwm_disable_reg_enable: |
103 | /* disable pwm, keep regulator enabled */ |
104 | state->enabled = false; |
105 | *enable_regulator = true; |
106 | break; |
107 | case pwm_enable_reg_enable: |
108 | /* keep pwm and regulator enabled */ |
109 | state->enabled = true; |
110 | *enable_regulator = true; |
111 | break; |
112 | case pwm_off_reg_off: |
113 | case pwm_disable_reg_disable: |
114 | /* disable pwm and regulator */ |
115 | state->enabled = false; |
116 | *enable_regulator = false; |
117 | } |
118 | } |
119 | |
120 | static int pwm_fan_switch_power(struct pwm_fan_ctx *ctx, bool on) |
121 | { |
122 | int ret = 0; |
123 | |
124 | if (!ctx->reg_en) |
125 | return ret; |
126 | |
127 | if (!ctx->regulator_enabled && on) { |
128 | ret = regulator_enable(regulator: ctx->reg_en); |
129 | if (ret == 0) |
130 | ctx->regulator_enabled = true; |
131 | } else if (ctx->regulator_enabled && !on) { |
132 | ret = regulator_disable(regulator: ctx->reg_en); |
133 | if (ret == 0) |
134 | ctx->regulator_enabled = false; |
135 | } |
136 | return ret; |
137 | } |
138 | |
139 | static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) |
140 | { |
141 | struct pwm_state *state = &ctx->pwm_state; |
142 | int ret; |
143 | |
144 | if (ctx->enabled) |
145 | return 0; |
146 | |
147 | ret = pwm_fan_switch_power(ctx, on: true); |
148 | if (ret < 0) { |
149 | dev_err(ctx->dev, "failed to enable power supply\n" ); |
150 | return ret; |
151 | } |
152 | |
153 | state->enabled = true; |
154 | ret = pwm_apply_might_sleep(pwm: ctx->pwm, state); |
155 | if (ret) { |
156 | dev_err(ctx->dev, "failed to enable PWM\n" ); |
157 | goto disable_regulator; |
158 | } |
159 | |
160 | ctx->enabled = true; |
161 | |
162 | return 0; |
163 | |
164 | disable_regulator: |
165 | pwm_fan_switch_power(ctx, on: false); |
166 | return ret; |
167 | } |
168 | |
169 | static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) |
170 | { |
171 | struct pwm_state *state = &ctx->pwm_state; |
172 | bool enable_regulator = false; |
173 | int ret; |
174 | |
175 | if (!ctx->enabled) |
176 | return 0; |
177 | |
178 | pwm_fan_enable_mode_2_state(enable_mode: ctx->enable_mode, |
179 | state, |
180 | enable_regulator: &enable_regulator); |
181 | |
182 | state->enabled = false; |
183 | state->duty_cycle = 0; |
184 | ret = pwm_apply_might_sleep(pwm: ctx->pwm, state); |
185 | if (ret) { |
186 | dev_err(ctx->dev, "failed to disable PWM\n" ); |
187 | return ret; |
188 | } |
189 | |
190 | pwm_fan_switch_power(ctx, on: enable_regulator); |
191 | |
192 | ctx->enabled = false; |
193 | |
194 | return 0; |
195 | } |
196 | |
197 | static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) |
198 | { |
199 | struct pwm_state *state = &ctx->pwm_state; |
200 | unsigned long period; |
201 | int ret = 0; |
202 | |
203 | if (pwm > 0) { |
204 | if (ctx->enable_mode == pwm_off_reg_off) |
205 | /* pwm-fan hard disabled */ |
206 | return 0; |
207 | |
208 | period = state->period; |
209 | state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); |
210 | ret = pwm_apply_might_sleep(pwm: ctx->pwm, state); |
211 | if (ret) |
212 | return ret; |
213 | ret = pwm_fan_power_on(ctx); |
214 | } else { |
215 | ret = pwm_fan_power_off(ctx); |
216 | } |
217 | if (!ret) |
218 | ctx->pwm_value = pwm; |
219 | |
220 | return ret; |
221 | } |
222 | |
223 | static int set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) |
224 | { |
225 | int ret; |
226 | |
227 | mutex_lock(&ctx->lock); |
228 | ret = __set_pwm(ctx, pwm); |
229 | mutex_unlock(lock: &ctx->lock); |
230 | |
231 | return ret; |
232 | } |
233 | |
234 | static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm) |
235 | { |
236 | int i; |
237 | |
238 | for (i = 0; i < ctx->pwm_fan_max_state; ++i) |
239 | if (pwm < ctx->pwm_fan_cooling_levels[i + 1]) |
240 | break; |
241 | |
242 | ctx->pwm_fan_state = i; |
243 | } |
244 | |
245 | static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) |
246 | { |
247 | int ret = 0; |
248 | int old_val; |
249 | |
250 | mutex_lock(&ctx->lock); |
251 | |
252 | if (ctx->enable_mode == val) |
253 | goto out; |
254 | |
255 | old_val = ctx->enable_mode; |
256 | ctx->enable_mode = val; |
257 | |
258 | if (val == 0) { |
259 | /* Disable pwm-fan unconditionally */ |
260 | if (ctx->enabled) |
261 | ret = __set_pwm(ctx, pwm: 0); |
262 | else |
263 | ret = pwm_fan_switch_power(ctx, on: false); |
264 | if (ret) |
265 | ctx->enable_mode = old_val; |
266 | pwm_fan_update_state(ctx, pwm: 0); |
267 | } else { |
268 | /* |
269 | * Change PWM and/or regulator state if currently disabled |
270 | * Nothing to do if currently enabled |
271 | */ |
272 | if (!ctx->enabled) { |
273 | struct pwm_state *state = &ctx->pwm_state; |
274 | bool enable_regulator = false; |
275 | |
276 | state->duty_cycle = 0; |
277 | pwm_fan_enable_mode_2_state(enable_mode: val, |
278 | state, |
279 | enable_regulator: &enable_regulator); |
280 | |
281 | pwm_apply_might_sleep(pwm: ctx->pwm, state); |
282 | pwm_fan_switch_power(ctx, on: enable_regulator); |
283 | pwm_fan_update_state(ctx, pwm: 0); |
284 | } |
285 | } |
286 | out: |
287 | mutex_unlock(lock: &ctx->lock); |
288 | |
289 | return ret; |
290 | } |
291 | |
292 | static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type, |
293 | u32 attr, int channel, long val) |
294 | { |
295 | struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); |
296 | int ret; |
297 | |
298 | switch (attr) { |
299 | case hwmon_pwm_input: |
300 | if (val < 0 || val > MAX_PWM) |
301 | return -EINVAL; |
302 | ret = set_pwm(ctx, pwm: val); |
303 | if (ret) |
304 | return ret; |
305 | pwm_fan_update_state(ctx, pwm: val); |
306 | break; |
307 | case hwmon_pwm_enable: |
308 | if (val < 0 || val > 3) |
309 | ret = -EINVAL; |
310 | else |
311 | ret = pwm_fan_update_enable(ctx, val); |
312 | |
313 | return ret; |
314 | default: |
315 | return -EOPNOTSUPP; |
316 | } |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, |
322 | u32 attr, int channel, long *val) |
323 | { |
324 | struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); |
325 | |
326 | switch (type) { |
327 | case hwmon_pwm: |
328 | switch (attr) { |
329 | case hwmon_pwm_input: |
330 | *val = ctx->pwm_value; |
331 | return 0; |
332 | case hwmon_pwm_enable: |
333 | *val = ctx->enable_mode; |
334 | return 0; |
335 | } |
336 | return -EOPNOTSUPP; |
337 | case hwmon_fan: |
338 | *val = ctx->tachs[channel].rpm; |
339 | return 0; |
340 | |
341 | default: |
342 | return -ENOTSUPP; |
343 | } |
344 | } |
345 | |
346 | static umode_t pwm_fan_is_visible(const void *data, |
347 | enum hwmon_sensor_types type, |
348 | u32 attr, int channel) |
349 | { |
350 | switch (type) { |
351 | case hwmon_pwm: |
352 | return 0644; |
353 | |
354 | case hwmon_fan: |
355 | return 0444; |
356 | |
357 | default: |
358 | return 0; |
359 | } |
360 | } |
361 | |
362 | static const struct hwmon_ops pwm_fan_hwmon_ops = { |
363 | .is_visible = pwm_fan_is_visible, |
364 | .read = pwm_fan_read, |
365 | .write = pwm_fan_write, |
366 | }; |
367 | |
368 | /* thermal cooling device callbacks */ |
369 | static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev, |
370 | unsigned long *state) |
371 | { |
372 | struct pwm_fan_ctx *ctx = cdev->devdata; |
373 | |
374 | if (!ctx) |
375 | return -EINVAL; |
376 | |
377 | *state = ctx->pwm_fan_max_state; |
378 | |
379 | return 0; |
380 | } |
381 | |
382 | static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev, |
383 | unsigned long *state) |
384 | { |
385 | struct pwm_fan_ctx *ctx = cdev->devdata; |
386 | |
387 | if (!ctx) |
388 | return -EINVAL; |
389 | |
390 | *state = ctx->pwm_fan_state; |
391 | |
392 | return 0; |
393 | } |
394 | |
395 | static int |
396 | pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) |
397 | { |
398 | struct pwm_fan_ctx *ctx = cdev->devdata; |
399 | int ret; |
400 | |
401 | if (!ctx || (state > ctx->pwm_fan_max_state)) |
402 | return -EINVAL; |
403 | |
404 | if (state == ctx->pwm_fan_state) |
405 | return 0; |
406 | |
407 | ret = set_pwm(ctx, pwm: ctx->pwm_fan_cooling_levels[state]); |
408 | if (ret) { |
409 | dev_err(&cdev->device, "Cannot set pwm!\n" ); |
410 | return ret; |
411 | } |
412 | |
413 | ctx->pwm_fan_state = state; |
414 | |
415 | return ret; |
416 | } |
417 | |
418 | static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = { |
419 | .get_max_state = pwm_fan_get_max_state, |
420 | .get_cur_state = pwm_fan_get_cur_state, |
421 | .set_cur_state = pwm_fan_set_cur_state, |
422 | }; |
423 | |
424 | static int pwm_fan_of_get_cooling_data(struct device *dev, |
425 | struct pwm_fan_ctx *ctx) |
426 | { |
427 | struct device_node *np = dev->of_node; |
428 | int num, i, ret; |
429 | |
430 | if (!of_property_present(np, propname: "cooling-levels" )) |
431 | return 0; |
432 | |
433 | ret = of_property_count_u32_elems(np, propname: "cooling-levels" ); |
434 | if (ret <= 0) { |
435 | dev_err(dev, "Wrong data!\n" ); |
436 | return ret ? : -EINVAL; |
437 | } |
438 | |
439 | num = ret; |
440 | ctx->pwm_fan_cooling_levels = devm_kcalloc(dev, n: num, size: sizeof(u32), |
441 | GFP_KERNEL); |
442 | if (!ctx->pwm_fan_cooling_levels) |
443 | return -ENOMEM; |
444 | |
445 | ret = of_property_read_u32_array(np, propname: "cooling-levels" , |
446 | out_values: ctx->pwm_fan_cooling_levels, sz: num); |
447 | if (ret) { |
448 | dev_err(dev, "Property 'cooling-levels' cannot be read!\n" ); |
449 | return ret; |
450 | } |
451 | |
452 | for (i = 0; i < num; i++) { |
453 | if (ctx->pwm_fan_cooling_levels[i] > MAX_PWM) { |
454 | dev_err(dev, "PWM fan state[%d]:%d > %d\n" , i, |
455 | ctx->pwm_fan_cooling_levels[i], MAX_PWM); |
456 | return -EINVAL; |
457 | } |
458 | } |
459 | |
460 | ctx->pwm_fan_max_state = num - 1; |
461 | |
462 | return 0; |
463 | } |
464 | |
465 | static void pwm_fan_cleanup(void *__ctx) |
466 | { |
467 | struct pwm_fan_ctx *ctx = __ctx; |
468 | |
469 | del_timer_sync(timer: &ctx->rpm_timer); |
470 | /* Switch off everything */ |
471 | ctx->enable_mode = pwm_disable_reg_disable; |
472 | pwm_fan_power_off(ctx); |
473 | } |
474 | |
475 | static int pwm_fan_probe(struct platform_device *pdev) |
476 | { |
477 | struct thermal_cooling_device *cdev; |
478 | struct device *dev = &pdev->dev; |
479 | struct pwm_fan_ctx *ctx; |
480 | struct device *hwmon; |
481 | int ret; |
482 | const struct hwmon_channel_info **channels; |
483 | u32 *fan_channel_config; |
484 | int channel_count = 1; /* We always have a PWM channel. */ |
485 | int i; |
486 | |
487 | ctx = devm_kzalloc(dev, size: sizeof(*ctx), GFP_KERNEL); |
488 | if (!ctx) |
489 | return -ENOMEM; |
490 | |
491 | mutex_init(&ctx->lock); |
492 | |
493 | ctx->dev = &pdev->dev; |
494 | ctx->pwm = devm_pwm_get(dev, NULL); |
495 | if (IS_ERR(ptr: ctx->pwm)) |
496 | return dev_err_probe(dev, err: PTR_ERR(ptr: ctx->pwm), fmt: "Could not get PWM\n" ); |
497 | |
498 | platform_set_drvdata(pdev, data: ctx); |
499 | |
500 | ctx->reg_en = devm_regulator_get_optional(dev, id: "fan" ); |
501 | if (IS_ERR(ptr: ctx->reg_en)) { |
502 | if (PTR_ERR(ptr: ctx->reg_en) != -ENODEV) |
503 | return PTR_ERR(ptr: ctx->reg_en); |
504 | |
505 | ctx->reg_en = NULL; |
506 | } |
507 | |
508 | pwm_init_state(pwm: ctx->pwm, state: &ctx->pwm_state); |
509 | |
510 | /* |
511 | * PWM fans are controlled solely by the duty cycle of the PWM signal, |
512 | * they do not care about the exact timing. Thus set usage_power to true |
513 | * to allow less flexible hardware to work as a PWM source for fan |
514 | * control. |
515 | */ |
516 | ctx->pwm_state.usage_power = true; |
517 | |
518 | /* |
519 | * set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned |
520 | * long. Check this here to prevent the fan running at a too low |
521 | * frequency. |
522 | */ |
523 | if (ctx->pwm_state.period > ULONG_MAX / MAX_PWM + 1) { |
524 | dev_err(dev, "Configured period too big\n" ); |
525 | return -EINVAL; |
526 | } |
527 | |
528 | ctx->enable_mode = pwm_disable_reg_enable; |
529 | |
530 | /* |
531 | * Set duty cycle to maximum allowed and enable PWM output as well as |
532 | * the regulator. In case of error nothing is changed |
533 | */ |
534 | ret = set_pwm(ctx, MAX_PWM); |
535 | if (ret) { |
536 | dev_err(dev, "Failed to configure PWM: %d\n" , ret); |
537 | return ret; |
538 | } |
539 | timer_setup(&ctx->rpm_timer, sample_timer, 0); |
540 | ret = devm_add_action_or_reset(dev, pwm_fan_cleanup, ctx); |
541 | if (ret) |
542 | return ret; |
543 | |
544 | ctx->tach_count = platform_irq_count(pdev); |
545 | if (ctx->tach_count < 0) |
546 | return dev_err_probe(dev, err: ctx->tach_count, |
547 | fmt: "Could not get number of fan tachometer inputs\n" ); |
548 | dev_dbg(dev, "%d fan tachometer inputs\n" , ctx->tach_count); |
549 | |
550 | if (ctx->tach_count) { |
551 | channel_count++; /* We also have a FAN channel. */ |
552 | |
553 | ctx->tachs = devm_kcalloc(dev, n: ctx->tach_count, |
554 | size: sizeof(struct pwm_fan_tach), |
555 | GFP_KERNEL); |
556 | if (!ctx->tachs) |
557 | return -ENOMEM; |
558 | |
559 | ctx->fan_channel.type = hwmon_fan; |
560 | fan_channel_config = devm_kcalloc(dev, n: ctx->tach_count + 1, |
561 | size: sizeof(u32), GFP_KERNEL); |
562 | if (!fan_channel_config) |
563 | return -ENOMEM; |
564 | ctx->fan_channel.config = fan_channel_config; |
565 | } |
566 | |
567 | channels = devm_kcalloc(dev, n: channel_count + 1, |
568 | size: sizeof(struct hwmon_channel_info *), GFP_KERNEL); |
569 | if (!channels) |
570 | return -ENOMEM; |
571 | |
572 | channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); |
573 | |
574 | for (i = 0; i < ctx->tach_count; i++) { |
575 | struct pwm_fan_tach *tach = &ctx->tachs[i]; |
576 | u32 ppr = 2; |
577 | |
578 | tach->irq = platform_get_irq(pdev, i); |
579 | if (tach->irq == -EPROBE_DEFER) |
580 | return tach->irq; |
581 | if (tach->irq > 0) { |
582 | ret = devm_request_irq(dev, irq: tach->irq, handler: pulse_handler, irqflags: 0, |
583 | devname: pdev->name, dev_id: tach); |
584 | if (ret) { |
585 | dev_err(dev, |
586 | "Failed to request interrupt: %d\n" , |
587 | ret); |
588 | return ret; |
589 | } |
590 | } |
591 | |
592 | of_property_read_u32_index(np: dev->of_node, |
593 | propname: "pulses-per-revolution" , |
594 | index: i, |
595 | out_value: &ppr); |
596 | tach->pulses_per_revolution = ppr; |
597 | if (!tach->pulses_per_revolution) { |
598 | dev_err(dev, "pulses-per-revolution can't be zero.\n" ); |
599 | return -EINVAL; |
600 | } |
601 | |
602 | fan_channel_config[i] = HWMON_F_INPUT; |
603 | |
604 | dev_dbg(dev, "tach%d: irq=%d, pulses_per_revolution=%d\n" , |
605 | i, tach->irq, tach->pulses_per_revolution); |
606 | } |
607 | |
608 | if (ctx->tach_count > 0) { |
609 | ctx->sample_start = ktime_get(); |
610 | mod_timer(timer: &ctx->rpm_timer, expires: jiffies + HZ); |
611 | |
612 | channels[1] = &ctx->fan_channel; |
613 | } |
614 | |
615 | ctx->info.ops = &pwm_fan_hwmon_ops; |
616 | ctx->info.info = channels; |
617 | |
618 | hwmon = devm_hwmon_device_register_with_info(dev, name: "pwmfan" , |
619 | drvdata: ctx, info: &ctx->info, NULL); |
620 | if (IS_ERR(ptr: hwmon)) { |
621 | dev_err(dev, "Failed to register hwmon device\n" ); |
622 | return PTR_ERR(ptr: hwmon); |
623 | } |
624 | |
625 | ret = pwm_fan_of_get_cooling_data(dev, ctx); |
626 | if (ret) |
627 | return ret; |
628 | |
629 | ctx->pwm_fan_state = ctx->pwm_fan_max_state; |
630 | if (IS_ENABLED(CONFIG_THERMAL)) { |
631 | cdev = devm_thermal_of_cooling_device_register(dev, |
632 | np: dev->of_node, type: "pwm-fan" , devdata: ctx, ops: &pwm_fan_cooling_ops); |
633 | if (IS_ERR(ptr: cdev)) { |
634 | ret = PTR_ERR(ptr: cdev); |
635 | dev_err(dev, |
636 | "Failed to register pwm-fan as cooling device: %d\n" , |
637 | ret); |
638 | return ret; |
639 | } |
640 | ctx->cdev = cdev; |
641 | } |
642 | |
643 | return 0; |
644 | } |
645 | |
646 | static void pwm_fan_shutdown(struct platform_device *pdev) |
647 | { |
648 | struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); |
649 | |
650 | pwm_fan_cleanup(ctx: ctx); |
651 | } |
652 | |
653 | static int pwm_fan_suspend(struct device *dev) |
654 | { |
655 | struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); |
656 | |
657 | return pwm_fan_power_off(ctx); |
658 | } |
659 | |
660 | static int pwm_fan_resume(struct device *dev) |
661 | { |
662 | struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); |
663 | |
664 | return set_pwm(ctx, pwm: ctx->pwm_value); |
665 | } |
666 | |
667 | static DEFINE_SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); |
668 | |
669 | static const struct of_device_id of_pwm_fan_match[] = { |
670 | { .compatible = "pwm-fan" , }, |
671 | {}, |
672 | }; |
673 | MODULE_DEVICE_TABLE(of, of_pwm_fan_match); |
674 | |
675 | static struct platform_driver pwm_fan_driver = { |
676 | .probe = pwm_fan_probe, |
677 | .shutdown = pwm_fan_shutdown, |
678 | .driver = { |
679 | .name = "pwm-fan" , |
680 | .pm = pm_sleep_ptr(&pwm_fan_pm), |
681 | .of_match_table = of_pwm_fan_match, |
682 | }, |
683 | }; |
684 | |
685 | module_platform_driver(pwm_fan_driver); |
686 | |
687 | MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>" ); |
688 | MODULE_ALIAS("platform:pwm-fan" ); |
689 | MODULE_DESCRIPTION("PWM FAN driver" ); |
690 | MODULE_LICENSE("GPL" ); |
691 | |