diff options
Diffstat (limited to 'drivers/hwmon/pwm-fan.c')
-rw-r--r-- | drivers/hwmon/pwm-fan.c | 105 |
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. */ | ||
54 | static 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 | |||
63 | static 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 | |||
43 | static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) | 79 | static 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 | ||
139 | static 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 | ||
104 | static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); | 147 | static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); |
148 | static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0); | ||
105 | 149 | ||
106 | static struct attribute *pwm_fan_attrs[] = { | 150 | static 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 | ||
111 | ATTRIBUTE_GROUPS(pwm_fan); | 156 | static 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 | |||
169 | static const struct attribute_group pwm_fan_group = { | ||
170 | .attrs = pwm_fan_attrs, | ||
171 | .is_visible = pwm_fan_attrs_visible, | ||
172 | }; | ||
173 | |||
174 | static 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 */ |
114 | static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev, | 180 | static 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 | ||
385 | err_del_timer: | ||
386 | del_timer_sync(&ctx->rpm_timer); | ||
387 | |||
293 | err_pwm_disable: | 388 | err_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 | ||