blob: 111a91dc6b798e31ae6ff9998e4eea0428943bc5 [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Kamil Debskid82d5772014-07-16 17:46:42 +02002/*
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>
Kamil Debskid82d5772014-07-16 17:46:42 +02008 */
9
10#include <linux/hwmon.h>
Stefan Wahren6b1ec472019-04-11 15:30:11 +020011#include <linux/interrupt.h>
Kamil Debskid82d5772014-07-16 17:46:42 +020012#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>
Stefan Wahrenb57e1d42019-02-22 14:45:24 +010017#include <linux/regulator/consumer.h>
Kamil Debskid82d5772014-07-16 17:46:42 +020018#include <linux/sysfs.h>
Lukasz Majewskib6bddec02015-02-26 14:59:37 +010019#include <linux/thermal.h>
Stefan Wahren6b1ec472019-04-11 15:30:11 +020020#include <linux/timer.h>
Kamil Debskid82d5772014-07-16 17:46:42 +020021
22#define MAX_PWM 255
23
24struct pwm_fan_ctx {
25 struct mutex lock;
26 struct pwm_device *pwm;
Stefan Wahrenb57e1d42019-02-22 14:45:24 +010027 struct regulator *reg_en;
Stefan Wahren6b1ec472019-04-11 15:30:11 +020028
29 int irq;
30 atomic_t pulses;
31 unsigned int rpm;
32 u8 pulses_per_revolution;
33 ktime_t sample_start;
34 struct timer_list rpm_timer;
35
Lukasz Majewski2e5219c2015-02-26 14:59:36 +010036 unsigned int pwm_value;
37 unsigned int pwm_fan_state;
38 unsigned int pwm_fan_max_state;
39 unsigned int *pwm_fan_cooling_levels;
Lukasz Majewskib6bddec02015-02-26 14:59:37 +010040 struct thermal_cooling_device *cdev;
Paul Barker1aa036552020-11-28 17:49:09 +000041
42 struct hwmon_chip_info info;
43};
44
45static const u32 pwm_fan_channel_config_pwm[] = {
46 HWMON_PWM_INPUT,
47 0
48};
49
50static const struct hwmon_channel_info pwm_fan_channel_pwm = {
51 .type = hwmon_pwm,
52 .config = pwm_fan_channel_config_pwm,
53};
54
55static const u32 pwm_fan_channel_config_fan[] = {
56 HWMON_F_INPUT,
57 0
58};
59
60static const struct hwmon_channel_info pwm_fan_channel_fan = {
61 .type = hwmon_fan,
62 .config = pwm_fan_channel_config_fan,
Kamil Debskid82d5772014-07-16 17:46:42 +020063};
64
Stefan Wahren6b1ec472019-04-11 15:30:11 +020065/* This handler assumes self resetting edge triggered interrupt. */
66static irqreturn_t pulse_handler(int irq, void *dev_id)
67{
68 struct pwm_fan_ctx *ctx = dev_id;
69
70 atomic_inc(&ctx->pulses);
71
72 return IRQ_HANDLED;
73}
74
75static void sample_timer(struct timer_list *t)
76{
77 struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer);
Paul Barkerfd8feec2020-11-11 16:46:43 +000078 unsigned int delta = ktime_ms_delta(ktime_get(), ctx->sample_start);
Stefan Wahren6b1ec472019-04-11 15:30:11 +020079 int pulses;
Stefan Wahren6b1ec472019-04-11 15:30:11 +020080
Paul Barkerfd8feec2020-11-11 16:46:43 +000081 if (delta) {
82 pulses = atomic_read(&ctx->pulses);
83 atomic_sub(pulses, &ctx->pulses);
84 ctx->rpm = (unsigned int)(pulses * 1000 * 60) /
85 (ctx->pulses_per_revolution * delta);
Stefan Wahren6b1ec472019-04-11 15:30:11 +020086
Paul Barkerfd8feec2020-11-11 16:46:43 +000087 ctx->sample_start = ktime_get();
88 }
89
Stefan Wahren6b1ec472019-04-11 15:30:11 +020090 mod_timer(&ctx->rpm_timer, jiffies + HZ);
91}
92
Lukasz Majewskicb85ca32015-02-26 14:59:35 +010093static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
Kamil Debskid82d5772014-07-16 17:46:42 +020094{
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +020095 unsigned long period;
Lukasz Majewskicb85ca32015-02-26 14:59:35 +010096 int ret = 0;
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +020097 struct pwm_state state = { };
Boris Brezillon22897112016-04-14 21:17:24 +020098
Kamil Debskid82d5772014-07-16 17:46:42 +020099 mutex_lock(&ctx->lock);
Kamil Debskid82d5772014-07-16 17:46:42 +0200100 if (ctx->pwm_value == pwm)
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100101 goto exit_set_pwm_err;
Kamil Debskid82d5772014-07-16 17:46:42 +0200102
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200103 pwm_init_state(ctx->pwm, &state);
104 period = ctx->pwm->args.period;
105 state.duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM);
106 state.enabled = pwm ? true : false;
Kamil Debskid82d5772014-07-16 17:46:42 +0200107
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200108 ret = pwm_apply_state(ctx->pwm, &state);
109 if (!ret)
110 ctx->pwm_value = pwm;
Kamil Debskid82d5772014-07-16 17:46:42 +0200111exit_set_pwm_err:
112 mutex_unlock(&ctx->lock);
113 return ret;
114}
115
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100116static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm)
117{
118 int i;
119
120 for (i = 0; i < ctx->pwm_fan_max_state; ++i)
121 if (pwm < ctx->pwm_fan_cooling_levels[i + 1])
122 break;
123
124 ctx->pwm_fan_state = i;
125}
126
Paul Barker1aa036552020-11-28 17:49:09 +0000127static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type,
128 u32 attr, int channel, long val)
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100129{
130 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100131 int ret;
132
Paul Barker1aa036552020-11-28 17:49:09 +0000133 if (val < 0 || val > MAX_PWM)
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100134 return -EINVAL;
135
Paul Barker1aa036552020-11-28 17:49:09 +0000136 ret = __set_pwm(ctx, val);
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100137 if (ret)
138 return ret;
139
Paul Barker1aa036552020-11-28 17:49:09 +0000140 pwm_fan_update_state(ctx, val);
141 return 0;
Lukasz Majewskicb85ca32015-02-26 14:59:35 +0100142}
143
Paul Barker1aa036552020-11-28 17:49:09 +0000144static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type,
145 u32 attr, int channel, long *val)
Kamil Debskid82d5772014-07-16 17:46:42 +0200146{
147 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
148
Paul Barker1aa036552020-11-28 17:49:09 +0000149 switch (type) {
150 case hwmon_pwm:
151 *val = ctx->pwm_value;
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200152 return 0;
153
Paul Barker1aa036552020-11-28 17:49:09 +0000154 case hwmon_fan:
155 *val = ctx->rpm;
156 return 0;
157
158 default:
159 return -ENOTSUPP;
160 }
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200161}
162
Paul Barker1aa036552020-11-28 17:49:09 +0000163static umode_t pwm_fan_is_visible(const void *data,
164 enum hwmon_sensor_types type,
165 u32 attr, int channel)
166{
167 switch (type) {
168 case hwmon_pwm:
169 return 0644;
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200170
Paul Barker1aa036552020-11-28 17:49:09 +0000171 case hwmon_fan:
172 return 0444;
173
174 default:
175 return 0;
176 }
177}
178
179static const struct hwmon_ops pwm_fan_hwmon_ops = {
180 .is_visible = pwm_fan_is_visible,
181 .read = pwm_fan_read,
182 .write = pwm_fan_write,
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200183};
Kamil Debskid82d5772014-07-16 17:46:42 +0200184
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100185/* thermal cooling device callbacks */
186static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
187 unsigned long *state)
188{
189 struct pwm_fan_ctx *ctx = cdev->devdata;
190
191 if (!ctx)
192 return -EINVAL;
193
194 *state = ctx->pwm_fan_max_state;
195
196 return 0;
197}
198
199static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev,
200 unsigned long *state)
201{
202 struct pwm_fan_ctx *ctx = cdev->devdata;
203
204 if (!ctx)
205 return -EINVAL;
206
207 *state = ctx->pwm_fan_state;
208
209 return 0;
210}
211
212static int
213pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
214{
215 struct pwm_fan_ctx *ctx = cdev->devdata;
216 int ret;
217
218 if (!ctx || (state > ctx->pwm_fan_max_state))
219 return -EINVAL;
220
221 if (state == ctx->pwm_fan_state)
222 return 0;
223
224 ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
225 if (ret) {
226 dev_err(&cdev->device, "Cannot set pwm!\n");
227 return ret;
228 }
229
230 ctx->pwm_fan_state = state;
231
232 return ret;
233}
234
235static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {
236 .get_max_state = pwm_fan_get_max_state,
237 .get_cur_state = pwm_fan_get_cur_state,
238 .set_cur_state = pwm_fan_set_cur_state,
239};
240
Guenter Roeckde52b042015-03-04 09:51:05 -0800241static int pwm_fan_of_get_cooling_data(struct device *dev,
242 struct pwm_fan_ctx *ctx)
Lukasz Majewski2e5219c2015-02-26 14:59:36 +0100243{
244 struct device_node *np = dev->of_node;
245 int num, i, ret;
246
247 if (!of_find_property(np, "cooling-levels", NULL))
248 return 0;
249
250 ret = of_property_count_u32_elems(np, "cooling-levels");
251 if (ret <= 0) {
252 dev_err(dev, "Wrong data!\n");
253 return ret ? : -EINVAL;
254 }
255
256 num = ret;
Kees Cooka86854d2018-06-12 14:07:58 -0700257 ctx->pwm_fan_cooling_levels = devm_kcalloc(dev, num, sizeof(u32),
Lukasz Majewski2e5219c2015-02-26 14:59:36 +0100258 GFP_KERNEL);
259 if (!ctx->pwm_fan_cooling_levels)
260 return -ENOMEM;
261
262 ret = of_property_read_u32_array(np, "cooling-levels",
263 ctx->pwm_fan_cooling_levels, num);
264 if (ret) {
265 dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
266 return ret;
267 }
268
269 for (i = 0; i < num; i++) {
270 if (ctx->pwm_fan_cooling_levels[i] > MAX_PWM) {
271 dev_err(dev, "PWM fan state[%d]:%d > %d\n", i,
272 ctx->pwm_fan_cooling_levels[i], MAX_PWM);
273 return -EINVAL;
274 }
275 }
276
277 ctx->pwm_fan_max_state = num - 1;
278
279 return 0;
280}
281
Guenter Roeck37bcec52019-04-18 12:58:20 -0700282static void pwm_fan_regulator_disable(void *data)
283{
284 regulator_disable(data);
285}
286
Linus Torvaldsa455eda2019-05-16 07:56:57 -0700287static void pwm_fan_pwm_disable(void *__ctx)
Guenter Roeck37bcec52019-04-18 12:58:20 -0700288{
Linus Torvaldsa455eda2019-05-16 07:56:57 -0700289 struct pwm_fan_ctx *ctx = __ctx;
290 pwm_disable(ctx->pwm);
291 del_timer_sync(&ctx->rpm_timer);
Guenter Roeck37bcec52019-04-18 12:58:20 -0700292}
293
Kamil Debskid82d5772014-07-16 17:46:42 +0200294static int pwm_fan_probe(struct platform_device *pdev)
295{
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100296 struct thermal_cooling_device *cdev;
Guenter Roeck37bcec52019-04-18 12:58:20 -0700297 struct device *dev = &pdev->dev;
Kamil Debskid82d5772014-07-16 17:46:42 +0200298 struct pwm_fan_ctx *ctx;
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100299 struct device *hwmon;
Kamil Debskid82d5772014-07-16 17:46:42 +0200300 int ret;
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200301 struct pwm_state state = { };
Paul Barkerb5fcb8a2020-11-26 17:44:07 +0000302 int tach_count;
Paul Barker1aa036552020-11-28 17:49:09 +0000303 const struct hwmon_channel_info **channels;
Kamil Debskid82d5772014-07-16 17:46:42 +0200304
Guenter Roeck37bcec52019-04-18 12:58:20 -0700305 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
Kamil Debskid82d5772014-07-16 17:46:42 +0200306 if (!ctx)
307 return -ENOMEM;
308
309 mutex_init(&ctx->lock);
310
Guenter Roeck37bcec52019-04-18 12:58:20 -0700311 ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL);
Anson Huang65b2aad2020-08-17 15:34:33 +0800312 if (IS_ERR(ctx->pwm))
313 return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n");
Kamil Debskid82d5772014-07-16 17:46:42 +0200314
Kamil Debskid82d5772014-07-16 17:46:42 +0200315 platform_set_drvdata(pdev, ctx);
316
Guenter Roeck37bcec52019-04-18 12:58:20 -0700317 ctx->reg_en = devm_regulator_get_optional(dev, "fan");
Stefan Wahrenb57e1d42019-02-22 14:45:24 +0100318 if (IS_ERR(ctx->reg_en)) {
319 if (PTR_ERR(ctx->reg_en) != -ENODEV)
320 return PTR_ERR(ctx->reg_en);
321
322 ctx->reg_en = NULL;
323 } else {
324 ret = regulator_enable(ctx->reg_en);
325 if (ret) {
Guenter Roeck37bcec52019-04-18 12:58:20 -0700326 dev_err(dev, "Failed to enable fan supply: %d\n", ret);
Stefan Wahrenb57e1d42019-02-22 14:45:24 +0100327 return ret;
328 }
Guenter Roeck5696e4a2019-06-07 13:27:06 -0700329 ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
330 ctx->reg_en);
331 if (ret)
332 return ret;
Stefan Wahrenb57e1d42019-02-22 14:45:24 +0100333 }
334
Kamil Debskid82d5772014-07-16 17:46:42 +0200335 ctx->pwm_value = MAX_PWM;
336
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200337 pwm_init_state(ctx->pwm, &state);
Uwe Kleine-König1eda5232020-12-15 10:20:30 +0100338 /*
339 * __set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned
340 * long. Check this here to prevent the fan running at a too low
341 * frequency.
342 */
343 if (state.period > ULONG_MAX / MAX_PWM + 1) {
344 dev_err(dev, "Configured period too big\n");
345 return -EINVAL;
346 }
347
348 /* Set duty cycle to maximum allowed and enable PWM output */
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200349 state.duty_cycle = ctx->pwm->args.period - 1;
350 state.enabled = true;
351
352 ret = pwm_apply_state(ctx->pwm, &state);
Kamil Debskid82d5772014-07-16 17:46:42 +0200353 if (ret) {
Linus Torvaldsa455eda2019-05-16 07:56:57 -0700354 dev_err(dev, "Failed to configure PWM: %d\n", ret);
Guenter Roeck37bcec52019-04-18 12:58:20 -0700355 return ret;
Kamil Debskid82d5772014-07-16 17:46:42 +0200356 }
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200357 timer_setup(&ctx->rpm_timer, sample_timer, 0);
Guenter Roeck5696e4a2019-06-07 13:27:06 -0700358 ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
359 if (ret)
360 return ret;
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200361
Paul Barkerb5fcb8a2020-11-26 17:44:07 +0000362 tach_count = platform_irq_count(pdev);
363 if (tach_count < 0)
364 return dev_err_probe(dev, tach_count,
365 "Could not get number of fan tachometer inputs\n");
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200366
Paul Barker1aa036552020-11-28 17:49:09 +0000367 channels = devm_kcalloc(dev, tach_count + 2,
368 sizeof(struct hwmon_channel_info *), GFP_KERNEL);
369 if (!channels)
370 return -ENOMEM;
371
372 channels[0] = &pwm_fan_channel_pwm;
373
Paul Barkerb5fcb8a2020-11-26 17:44:07 +0000374 if (tach_count > 0) {
375 u32 ppr = 2;
376
377 ctx->irq = platform_get_irq(pdev, 0);
378 if (ctx->irq == -EPROBE_DEFER)
379 return ctx->irq;
380 if (ctx->irq > 0) {
381 ret = devm_request_irq(dev, ctx->irq, pulse_handler, 0,
382 pdev->name, ctx);
383 if (ret) {
384 dev_err(dev,
385 "Failed to request interrupt: %d\n",
386 ret);
387 return ret;
388 }
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200389 }
Paul Barkerb5fcb8a2020-11-26 17:44:07 +0000390
391 of_property_read_u32(dev->of_node,
392 "pulses-per-revolution",
393 &ppr);
394 ctx->pulses_per_revolution = ppr;
395 if (!ctx->pulses_per_revolution) {
396 dev_err(dev, "pulses-per-revolution can't be zero.\n");
397 return -EINVAL;
398 }
399
400 dev_dbg(dev, "tach: irq=%d, pulses_per_revolution=%d\n",
401 ctx->irq, ctx->pulses_per_revolution);
402
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200403 ctx->sample_start = ktime_get();
404 mod_timer(&ctx->rpm_timer, jiffies + HZ);
Paul Barker1aa036552020-11-28 17:49:09 +0000405
406 channels[1] = &pwm_fan_channel_fan;
Stefan Wahren6b1ec472019-04-11 15:30:11 +0200407 }
408
Paul Barker1aa036552020-11-28 17:49:09 +0000409 ctx->info.ops = &pwm_fan_hwmon_ops;
410 ctx->info.info = channels;
411
412 hwmon = devm_hwmon_device_register_with_info(dev, "pwmfan",
413 ctx, &ctx->info, NULL);
Kamil Debskid82d5772014-07-16 17:46:42 +0200414 if (IS_ERR(hwmon)) {
Guenter Roeck37bcec52019-04-18 12:58:20 -0700415 dev_err(dev, "Failed to register hwmon device\n");
416 return PTR_ERR(hwmon);
Kamil Debskid82d5772014-07-16 17:46:42 +0200417 }
Lukasz Majewski2e5219c2015-02-26 14:59:36 +0100418
Guenter Roeck37bcec52019-04-18 12:58:20 -0700419 ret = pwm_fan_of_get_cooling_data(dev, ctx);
Lukasz Majewski2e5219c2015-02-26 14:59:36 +0100420 if (ret)
421 return ret;
422
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100423 ctx->pwm_fan_state = ctx->pwm_fan_max_state;
424 if (IS_ENABLED(CONFIG_THERMAL)) {
Guenter Roeck37bcec52019-04-18 12:58:20 -0700425 cdev = devm_thermal_of_cooling_device_register(dev,
426 dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100427 if (IS_ERR(cdev)) {
Bartlomiej Zolnierkiewicz677252a2017-04-24 15:13:17 +0200428 ret = PTR_ERR(cdev);
Guenter Roeck37bcec52019-04-18 12:58:20 -0700429 dev_err(dev,
Robin Murphy841cf672019-04-12 15:05:23 +0100430 "Failed to register pwm-fan as cooling device: %d\n",
431 ret);
Linus Torvaldsa455eda2019-05-16 07:56:57 -0700432 return ret;
Lukasz Majewskib6bddec02015-02-26 14:59:37 +0100433 }
434 ctx->cdev = cdev;
435 thermal_cdev_update(cdev);
436 }
437
Kamil Debskid82d5772014-07-16 17:46:42 +0200438 return 0;
Kamil Debskid82d5772014-07-16 17:46:42 +0200439}
440
Akinobu Mita7992db72020-01-21 00:32:24 +0900441static int pwm_fan_disable(struct device *dev)
Kamil Debskid82d5772014-07-16 17:46:42 +0200442{
443 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
Thierry Reding95dcd642018-09-21 12:10:48 +0200444 struct pwm_args args;
445 int ret;
Kamil Debskid82d5772014-07-16 17:46:42 +0200446
Thierry Reding95dcd642018-09-21 12:10:48 +0200447 pwm_get_args(ctx->pwm, &args);
448
449 if (ctx->pwm_value) {
450 ret = pwm_config(ctx->pwm, 0, args.period);
451 if (ret < 0)
452 return ret;
453
Kamil Debskid82d5772014-07-16 17:46:42 +0200454 pwm_disable(ctx->pwm);
Thierry Reding95dcd642018-09-21 12:10:48 +0200455 }
456
Stefan Wahrenb57e1d42019-02-22 14:45:24 +0100457 if (ctx->reg_en) {
458 ret = regulator_disable(ctx->reg_en);
459 if (ret) {
460 dev_err(dev, "Failed to disable fan supply: %d\n", ret);
461 return ret;
462 }
463 }
464
Kamil Debskid82d5772014-07-16 17:46:42 +0200465 return 0;
466}
467
Akinobu Mita7992db72020-01-21 00:32:24 +0900468static void pwm_fan_shutdown(struct platform_device *pdev)
469{
470 pwm_fan_disable(&pdev->dev);
471}
472
473#ifdef CONFIG_PM_SLEEP
474static int pwm_fan_suspend(struct device *dev)
475{
476 return pwm_fan_disable(dev);
477}
478
Kamil Debskid82d5772014-07-16 17:46:42 +0200479static int pwm_fan_resume(struct device *dev)
480{
481 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
Boris Brezillon22897112016-04-14 21:17:24 +0200482 struct pwm_args pargs;
Kamil Debski48b9d5b2014-11-03 15:42:55 +0100483 unsigned long duty;
484 int ret;
Kamil Debskid82d5772014-07-16 17:46:42 +0200485
Stefan Wahrenb57e1d42019-02-22 14:45:24 +0100486 if (ctx->reg_en) {
487 ret = regulator_enable(ctx->reg_en);
488 if (ret) {
489 dev_err(dev, "Failed to enable fan supply: %d\n", ret);
490 return ret;
491 }
492 }
493
Kamil Debski48b9d5b2014-11-03 15:42:55 +0100494 if (ctx->pwm_value == 0)
495 return 0;
496
Boris Brezillon22897112016-04-14 21:17:24 +0200497 pwm_get_args(ctx->pwm, &pargs);
Guru Das Srinageshf3e4b142020-06-02 15:31:06 -0700498 duty = DIV_ROUND_UP_ULL(ctx->pwm_value * (pargs.period - 1), MAX_PWM);
Boris Brezillon22897112016-04-14 21:17:24 +0200499 ret = pwm_config(ctx->pwm, duty, pargs.period);
Kamil Debski48b9d5b2014-11-03 15:42:55 +0100500 if (ret)
501 return ret;
502 return pwm_enable(ctx->pwm);
Kamil Debskid82d5772014-07-16 17:46:42 +0200503}
504#endif
505
506static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume);
507
Fabian Frederickd720aca2015-03-16 20:54:36 +0100508static const struct of_device_id of_pwm_fan_match[] = {
Kamil Debskid82d5772014-07-16 17:46:42 +0200509 { .compatible = "pwm-fan", },
510 {},
511};
Luis de Bethencourtf491e702015-09-17 18:09:55 +0200512MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
Kamil Debskid82d5772014-07-16 17:46:42 +0200513
514static struct platform_driver pwm_fan_driver = {
515 .probe = pwm_fan_probe,
Akinobu Mita7992db72020-01-21 00:32:24 +0900516 .shutdown = pwm_fan_shutdown,
Kamil Debskid82d5772014-07-16 17:46:42 +0200517 .driver = {
518 .name = "pwm-fan",
519 .pm = &pwm_fan_pm,
520 .of_match_table = of_pwm_fan_match,
521 },
522};
523
524module_platform_driver(pwm_fan_driver);
525
526MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
527MODULE_ALIAS("platform:pwm-fan");
528MODULE_DESCRIPTION("PWM FAN driver");
529MODULE_LICENSE("GPL");