aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pwm-fan.c
diff options
context:
space:
mode:
authorStefan Wahren <stefan.wahren@i2se.com>2019-04-11 09:30:11 -0400
committerGuenter Roeck <linux@roeck-us.net>2019-04-15 20:19:53 -0400
commit6b1ec4789fb17890a7f95e72670a9393fd9f8c8f (patch)
treea1473c88414c9eb0be096b544fef678f7480f642 /drivers/hwmon/pwm-fan.c
parent285d7483aa3323c90891e26b73a0c9d9cc5f53e4 (diff)
hwmon: (pwm-fan) Add RPM support via external interrupt
This adds RPM support to the pwm-fan driver in order to use with fancontrol/pwmconfig. This feature is intended for fans with a tachometer output signal, which generate a defined number of pulses per revolution. Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com> Reviewed-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> [groeck: Drop unused 'devattr' variable] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/pwm-fan.c')
-rw-r--r--drivers/hwmon/pwm-fan.c105
1 files changed, 101 insertions, 4 deletions
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index e4c5197417a8..285ec3abb85e 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -18,6 +18,7 @@
18 18
19#include <linux/hwmon.h> 19#include <linux/hwmon.h>
20#include <linux/hwmon-sysfs.h> 20#include <linux/hwmon-sysfs.h>
21#include <linux/interrupt.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/mutex.h> 23#include <linux/mutex.h>
23#include <linux/of.h> 24#include <linux/of.h>
@@ -26,6 +27,7 @@
26#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
27#include <linux/sysfs.h> 28#include <linux/sysfs.h>
28#include <linux/thermal.h> 29#include <linux/thermal.h>
30#include <linux/timer.h>
29 31
30#define MAX_PWM 255 32#define MAX_PWM 255
31 33
@@ -33,6 +35,14 @@ struct pwm_fan_ctx {
33 struct mutex lock; 35 struct mutex lock;
34 struct pwm_device *pwm; 36 struct pwm_device *pwm;
35 struct regulator *reg_en; 37 struct regulator *reg_en;
38
39 int irq;
40 atomic_t pulses;
41 unsigned int rpm;
42 u8 pulses_per_revolution;
43 ktime_t sample_start;
44 struct timer_list rpm_timer;
45
36 unsigned int pwm_value; 46 unsigned int pwm_value;
37 unsigned int pwm_fan_state; 47 unsigned int pwm_fan_state;
38 unsigned int pwm_fan_max_state; 48 unsigned int pwm_fan_max_state;
@@ -40,6 +50,32 @@ struct pwm_fan_ctx {
40 struct thermal_cooling_device *cdev; 50 struct thermal_cooling_device *cdev;
41}; 51};
42 52
53/* This handler assumes self resetting edge triggered interrupt. */
54static irqreturn_t pulse_handler(int irq, void *dev_id)
55{
56 struct pwm_fan_ctx *ctx = dev_id;
57
58 atomic_inc(&ctx->pulses);
59
60 return IRQ_HANDLED;
61}
62
63static void sample_timer(struct timer_list *t)
64{
65 struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer);
66 int pulses;
67 u64 tmp;
68
69 pulses = atomic_read(&ctx->pulses);
70 atomic_sub(pulses, &ctx->pulses);
71 tmp = (u64)pulses * ktime_ms_delta(ktime_get(), ctx->sample_start) * 60;
72 do_div(tmp, ctx->pulses_per_revolution * 1000);
73 ctx->rpm = tmp;
74
75 ctx->sample_start = ktime_get();
76 mod_timer(&ctx->rpm_timer, jiffies + HZ);
77}
78
43static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) 79static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
44{ 80{
45 unsigned long period; 81 unsigned long period;
@@ -100,15 +136,45 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
100 return sprintf(buf, "%u\n", ctx->pwm_value); 136 return sprintf(buf, "%u\n", ctx->pwm_value);
101} 137}
102 138
139static ssize_t rpm_show(struct device *dev,
140 struct device_attribute *attr, char *buf)
141{
142 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
143
144 return sprintf(buf, "%u\n", ctx->rpm);
145}
103 146
104static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 147static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
148static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0);
105 149
106static struct attribute *pwm_fan_attrs[] = { 150static struct attribute *pwm_fan_attrs[] = {
107 &sensor_dev_attr_pwm1.dev_attr.attr, 151 &sensor_dev_attr_pwm1.dev_attr.attr,
152 &sensor_dev_attr_fan1_input.dev_attr.attr,
108 NULL, 153 NULL,
109}; 154};
110 155
111ATTRIBUTE_GROUPS(pwm_fan); 156static umode_t pwm_fan_attrs_visible(struct kobject *kobj, struct attribute *a,
157 int n)
158{
159 struct device *dev = container_of(kobj, struct device, kobj);
160 struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
161
162 /* Hide fan_input in case no interrupt is available */
163 if (n == 1 && ctx->irq <= 0)
164 return 0;
165
166 return a->mode;
167}
168
169static const struct attribute_group pwm_fan_group = {
170 .attrs = pwm_fan_attrs,
171 .is_visible = pwm_fan_attrs_visible,
172};
173
174static const struct attribute_group *pwm_fan_groups[] = {
175 &pwm_fan_group,
176 NULL,
177};
112 178
113/* thermal cooling device callbacks */ 179/* thermal cooling device callbacks */
114static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev, 180static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
@@ -214,6 +280,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
214 struct device *hwmon; 280 struct device *hwmon;
215 int ret; 281 int ret;
216 struct pwm_state state = { }; 282 struct pwm_state state = { };
283 u32 ppr = 2;
217 284
218 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 285 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
219 if (!ctx) 286 if (!ctx)
@@ -233,6 +300,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
233 300
234 platform_set_drvdata(pdev, ctx); 301 platform_set_drvdata(pdev, ctx);
235 302
303 ctx->irq = platform_get_irq(pdev, 0);
304 if (ctx->irq == -EPROBE_DEFER)
305 return ctx->irq;
306
236 ctx->reg_en = devm_regulator_get_optional(&pdev->dev, "fan"); 307 ctx->reg_en = devm_regulator_get_optional(&pdev->dev, "fan");
237 if (IS_ERR(ctx->reg_en)) { 308 if (IS_ERR(ctx->reg_en)) {
238 if (PTR_ERR(ctx->reg_en) != -ENODEV) 309 if (PTR_ERR(ctx->reg_en) != -ENODEV)
@@ -261,17 +332,38 @@ static int pwm_fan_probe(struct platform_device *pdev)
261 goto err_reg_disable; 332 goto err_reg_disable;
262 } 333 }
263 334
335 timer_setup(&ctx->rpm_timer, sample_timer, 0);
336
337 of_property_read_u32(pdev->dev.of_node, "pulses-per-revolution", &ppr);
338 ctx->pulses_per_revolution = ppr;
339 if (!ctx->pulses_per_revolution) {
340 dev_err(&pdev->dev, "pulses-per-revolution can't be zero.\n");
341 ret = -EINVAL;
342 goto err_pwm_disable;
343 }
344
345 if (ctx->irq > 0) {
346 ret = devm_request_irq(&pdev->dev, ctx->irq, pulse_handler, 0,
347 pdev->name, ctx);
348 if (ret) {
349 dev_err(&pdev->dev, "Can't get interrupt working.\n");
350 goto err_pwm_disable;
351 }
352 ctx->sample_start = ktime_get();
353 mod_timer(&ctx->rpm_timer, jiffies + HZ);
354 }
355
264 hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan", 356 hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan",
265 ctx, pwm_fan_groups); 357 ctx, pwm_fan_groups);
266 if (IS_ERR(hwmon)) { 358 if (IS_ERR(hwmon)) {
267 dev_err(&pdev->dev, "Failed to register hwmon device\n"); 359 dev_err(&pdev->dev, "Failed to register hwmon device\n");
268 ret = PTR_ERR(hwmon); 360 ret = PTR_ERR(hwmon);
269 goto err_pwm_disable; 361 goto err_del_timer;
270 } 362 }
271 363
272 ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); 364 ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
273 if (ret) 365 if (ret)
274 goto err_pwm_disable; 366 goto err_del_timer;
275 367
276 ctx->pwm_fan_state = ctx->pwm_fan_max_state; 368 ctx->pwm_fan_state = ctx->pwm_fan_max_state;
277 if (IS_ENABLED(CONFIG_THERMAL)) { 369 if (IS_ENABLED(CONFIG_THERMAL)) {
@@ -282,7 +374,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
282 dev_err(&pdev->dev, 374 dev_err(&pdev->dev,
283 "Failed to register pwm-fan as cooling device"); 375 "Failed to register pwm-fan as cooling device");
284 ret = PTR_ERR(cdev); 376 ret = PTR_ERR(cdev);
285 goto err_pwm_disable; 377 goto err_del_timer;
286 } 378 }
287 ctx->cdev = cdev; 379 ctx->cdev = cdev;
288 thermal_cdev_update(cdev); 380 thermal_cdev_update(cdev);
@@ -290,6 +382,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
290 382
291 return 0; 383 return 0;
292 384
385err_del_timer:
386 del_timer_sync(&ctx->rpm_timer);
387
293err_pwm_disable: 388err_pwm_disable:
294 state.enabled = false; 389 state.enabled = false;
295 pwm_apply_state(ctx->pwm, &state); 390 pwm_apply_state(ctx->pwm, &state);
@@ -306,6 +401,8 @@ static int pwm_fan_remove(struct platform_device *pdev)
306 struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); 401 struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
307 402
308 thermal_cooling_device_unregister(ctx->cdev); 403 thermal_cooling_device_unregister(ctx->cdev);
404 del_timer_sync(&ctx->rpm_timer);
405
309 if (ctx->pwm_value) 406 if (ctx->pwm_value)
310 pwm_disable(ctx->pwm); 407 pwm_disable(ctx->pwm);
311 408