Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/hwmon/gpio-fan.c
15109 views
1
/*
2
* gpio-fan.c - Hwmon driver for fans connected to GPIO lines.
3
*
4
* Copyright (C) 2010 LaCie
5
*
6
* Author: Simon Guinot <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*/
22
23
#include <linux/module.h>
24
#include <linux/init.h>
25
#include <linux/slab.h>
26
#include <linux/interrupt.h>
27
#include <linux/irq.h>
28
#include <linux/platform_device.h>
29
#include <linux/err.h>
30
#include <linux/mutex.h>
31
#include <linux/hwmon.h>
32
#include <linux/gpio.h>
33
#include <linux/gpio-fan.h>
34
35
struct gpio_fan_data {
36
struct platform_device *pdev;
37
struct device *hwmon_dev;
38
struct mutex lock; /* lock GPIOs operations. */
39
int num_ctrl;
40
unsigned *ctrl;
41
int num_speed;
42
struct gpio_fan_speed *speed;
43
int speed_index;
44
#ifdef CONFIG_PM
45
int resume_speed;
46
#endif
47
bool pwm_enable;
48
struct gpio_fan_alarm *alarm;
49
struct work_struct alarm_work;
50
};
51
52
/*
53
* Alarm GPIO.
54
*/
55
56
static void fan_alarm_notify(struct work_struct *ws)
57
{
58
struct gpio_fan_data *fan_data =
59
container_of(ws, struct gpio_fan_data, alarm_work);
60
61
sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
62
kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
63
}
64
65
static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
66
{
67
struct gpio_fan_data *fan_data = dev_id;
68
69
schedule_work(&fan_data->alarm_work);
70
71
return IRQ_NONE;
72
}
73
74
static ssize_t show_fan_alarm(struct device *dev,
75
struct device_attribute *attr, char *buf)
76
{
77
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
78
struct gpio_fan_alarm *alarm = fan_data->alarm;
79
int value = gpio_get_value(alarm->gpio);
80
81
if (alarm->active_low)
82
value = !value;
83
84
return sprintf(buf, "%d\n", value);
85
}
86
87
static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
88
89
static int fan_alarm_init(struct gpio_fan_data *fan_data,
90
struct gpio_fan_alarm *alarm)
91
{
92
int err;
93
int alarm_irq;
94
struct platform_device *pdev = fan_data->pdev;
95
96
fan_data->alarm = alarm;
97
98
err = gpio_request(alarm->gpio, "GPIO fan alarm");
99
if (err)
100
return err;
101
102
err = gpio_direction_input(alarm->gpio);
103
if (err)
104
goto err_free_gpio;
105
106
err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
107
if (err)
108
goto err_free_gpio;
109
110
/*
111
* If the alarm GPIO don't support interrupts, just leave
112
* without initializing the fail notification support.
113
*/
114
alarm_irq = gpio_to_irq(alarm->gpio);
115
if (alarm_irq < 0)
116
return 0;
117
118
INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
119
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
120
err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED,
121
"GPIO fan alarm", fan_data);
122
if (err)
123
goto err_free_sysfs;
124
125
return 0;
126
127
err_free_sysfs:
128
device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
129
err_free_gpio:
130
gpio_free(alarm->gpio);
131
132
return err;
133
}
134
135
static void fan_alarm_free(struct gpio_fan_data *fan_data)
136
{
137
struct platform_device *pdev = fan_data->pdev;
138
int alarm_irq = gpio_to_irq(fan_data->alarm->gpio);
139
140
if (alarm_irq >= 0)
141
free_irq(alarm_irq, fan_data);
142
device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
143
gpio_free(fan_data->alarm->gpio);
144
}
145
146
/*
147
* Control GPIOs.
148
*/
149
150
/* Must be called with fan_data->lock held, except during initialization. */
151
static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
152
{
153
int i;
154
155
for (i = 0; i < fan_data->num_ctrl; i++)
156
gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
157
}
158
159
static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
160
{
161
int i;
162
int ctrl_val = 0;
163
164
for (i = 0; i < fan_data->num_ctrl; i++) {
165
int value;
166
167
value = gpio_get_value(fan_data->ctrl[i]);
168
ctrl_val |= (value << i);
169
}
170
return ctrl_val;
171
}
172
173
/* Must be called with fan_data->lock held, except during initialization. */
174
static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
175
{
176
if (fan_data->speed_index == speed_index)
177
return;
178
179
__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
180
fan_data->speed_index = speed_index;
181
}
182
183
static int get_fan_speed_index(struct gpio_fan_data *fan_data)
184
{
185
int ctrl_val = __get_fan_ctrl(fan_data);
186
int i;
187
188
for (i = 0; i < fan_data->num_speed; i++)
189
if (fan_data->speed[i].ctrl_val == ctrl_val)
190
return i;
191
192
dev_warn(&fan_data->pdev->dev,
193
"missing speed array entry for GPIO value 0x%x\n", ctrl_val);
194
195
return -EINVAL;
196
}
197
198
static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm)
199
{
200
struct gpio_fan_speed *speed = fan_data->speed;
201
int i;
202
203
for (i = 0; i < fan_data->num_speed; i++)
204
if (speed[i].rpm >= rpm)
205
return i;
206
207
return fan_data->num_speed - 1;
208
}
209
210
static ssize_t show_pwm(struct device *dev,
211
struct device_attribute *attr, char *buf)
212
{
213
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
214
u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
215
216
return sprintf(buf, "%d\n", pwm);
217
}
218
219
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
220
const char *buf, size_t count)
221
{
222
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
223
unsigned long pwm;
224
int speed_index;
225
int ret = count;
226
227
if (strict_strtoul(buf, 10, &pwm) || pwm > 255)
228
return -EINVAL;
229
230
mutex_lock(&fan_data->lock);
231
232
if (!fan_data->pwm_enable) {
233
ret = -EPERM;
234
goto exit_unlock;
235
}
236
237
speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
238
set_fan_speed(fan_data, speed_index);
239
240
exit_unlock:
241
mutex_unlock(&fan_data->lock);
242
243
return ret;
244
}
245
246
static ssize_t show_pwm_enable(struct device *dev,
247
struct device_attribute *attr, char *buf)
248
{
249
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
250
251
return sprintf(buf, "%d\n", fan_data->pwm_enable);
252
}
253
254
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
255
const char *buf, size_t count)
256
{
257
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
258
unsigned long val;
259
260
if (strict_strtoul(buf, 10, &val) || val > 1)
261
return -EINVAL;
262
263
if (fan_data->pwm_enable == val)
264
return count;
265
266
mutex_lock(&fan_data->lock);
267
268
fan_data->pwm_enable = val;
269
270
/* Disable manual control mode: set fan at full speed. */
271
if (val == 0)
272
set_fan_speed(fan_data, fan_data->num_speed - 1);
273
274
mutex_unlock(&fan_data->lock);
275
276
return count;
277
}
278
279
static ssize_t show_pwm_mode(struct device *dev,
280
struct device_attribute *attr, char *buf)
281
{
282
return sprintf(buf, "0\n");
283
}
284
285
static ssize_t show_rpm_min(struct device *dev,
286
struct device_attribute *attr, char *buf)
287
{
288
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
289
290
return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
291
}
292
293
static ssize_t show_rpm_max(struct device *dev,
294
struct device_attribute *attr, char *buf)
295
{
296
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
297
298
return sprintf(buf, "%d\n",
299
fan_data->speed[fan_data->num_speed - 1].rpm);
300
}
301
302
static ssize_t show_rpm(struct device *dev,
303
struct device_attribute *attr, char *buf)
304
{
305
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
306
307
return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
308
}
309
310
static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
311
const char *buf, size_t count)
312
{
313
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
314
unsigned long rpm;
315
int ret = count;
316
317
if (strict_strtoul(buf, 10, &rpm))
318
return -EINVAL;
319
320
mutex_lock(&fan_data->lock);
321
322
if (!fan_data->pwm_enable) {
323
ret = -EPERM;
324
goto exit_unlock;
325
}
326
327
set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
328
329
exit_unlock:
330
mutex_unlock(&fan_data->lock);
331
332
return ret;
333
}
334
335
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
336
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
337
show_pwm_enable, set_pwm_enable);
338
static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL);
339
static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL);
340
static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
341
static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
342
static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
343
344
static struct attribute *gpio_fan_ctrl_attributes[] = {
345
&dev_attr_pwm1.attr,
346
&dev_attr_pwm1_enable.attr,
347
&dev_attr_pwm1_mode.attr,
348
&dev_attr_fan1_input.attr,
349
&dev_attr_fan1_target.attr,
350
&dev_attr_fan1_min.attr,
351
&dev_attr_fan1_max.attr,
352
NULL
353
};
354
355
static const struct attribute_group gpio_fan_ctrl_group = {
356
.attrs = gpio_fan_ctrl_attributes,
357
};
358
359
static int fan_ctrl_init(struct gpio_fan_data *fan_data,
360
struct gpio_fan_platform_data *pdata)
361
{
362
struct platform_device *pdev = fan_data->pdev;
363
int num_ctrl = pdata->num_ctrl;
364
unsigned *ctrl = pdata->ctrl;
365
int i, err;
366
367
for (i = 0; i < num_ctrl; i++) {
368
err = gpio_request(ctrl[i], "GPIO fan control");
369
if (err)
370
goto err_free_gpio;
371
372
err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
373
if (err) {
374
gpio_free(ctrl[i]);
375
goto err_free_gpio;
376
}
377
}
378
379
fan_data->num_ctrl = num_ctrl;
380
fan_data->ctrl = ctrl;
381
fan_data->num_speed = pdata->num_speed;
382
fan_data->speed = pdata->speed;
383
fan_data->pwm_enable = true; /* Enable manual fan speed control. */
384
fan_data->speed_index = get_fan_speed_index(fan_data);
385
if (fan_data->speed_index < 0) {
386
err = -ENODEV;
387
goto err_free_gpio;
388
}
389
390
err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
391
if (err)
392
goto err_free_gpio;
393
394
return 0;
395
396
err_free_gpio:
397
for (i = i - 1; i >= 0; i--)
398
gpio_free(ctrl[i]);
399
400
return err;
401
}
402
403
static void fan_ctrl_free(struct gpio_fan_data *fan_data)
404
{
405
struct platform_device *pdev = fan_data->pdev;
406
int i;
407
408
sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
409
for (i = 0; i < fan_data->num_ctrl; i++)
410
gpio_free(fan_data->ctrl[i]);
411
}
412
413
/*
414
* Platform driver.
415
*/
416
417
static ssize_t show_name(struct device *dev,
418
struct device_attribute *attr, char *buf)
419
{
420
return sprintf(buf, "gpio-fan\n");
421
}
422
423
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
424
425
static int __devinit gpio_fan_probe(struct platform_device *pdev)
426
{
427
int err;
428
struct gpio_fan_data *fan_data;
429
struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
430
431
if (!pdata)
432
return -EINVAL;
433
434
fan_data = kzalloc(sizeof(struct gpio_fan_data), GFP_KERNEL);
435
if (!fan_data)
436
return -ENOMEM;
437
438
fan_data->pdev = pdev;
439
platform_set_drvdata(pdev, fan_data);
440
mutex_init(&fan_data->lock);
441
442
/* Configure alarm GPIO if available. */
443
if (pdata->alarm) {
444
err = fan_alarm_init(fan_data, pdata->alarm);
445
if (err)
446
goto err_free_data;
447
}
448
449
/* Configure control GPIOs if available. */
450
if (pdata->ctrl && pdata->num_ctrl > 0) {
451
if (!pdata->speed || pdata->num_speed <= 1) {
452
err = -EINVAL;
453
goto err_free_alarm;
454
}
455
err = fan_ctrl_init(fan_data, pdata);
456
if (err)
457
goto err_free_alarm;
458
}
459
460
err = device_create_file(&pdev->dev, &dev_attr_name);
461
if (err)
462
goto err_free_ctrl;
463
464
/* Make this driver part of hwmon class. */
465
fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
466
if (IS_ERR(fan_data->hwmon_dev)) {
467
err = PTR_ERR(fan_data->hwmon_dev);
468
goto err_remove_name;
469
}
470
471
dev_info(&pdev->dev, "GPIO fan initialized\n");
472
473
return 0;
474
475
err_remove_name:
476
device_remove_file(&pdev->dev, &dev_attr_name);
477
err_free_ctrl:
478
if (fan_data->ctrl)
479
fan_ctrl_free(fan_data);
480
err_free_alarm:
481
if (fan_data->alarm)
482
fan_alarm_free(fan_data);
483
err_free_data:
484
platform_set_drvdata(pdev, NULL);
485
kfree(fan_data);
486
487
return err;
488
}
489
490
static int __devexit gpio_fan_remove(struct platform_device *pdev)
491
{
492
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
493
494
hwmon_device_unregister(fan_data->hwmon_dev);
495
device_remove_file(&pdev->dev, &dev_attr_name);
496
if (fan_data->alarm)
497
fan_alarm_free(fan_data);
498
if (fan_data->ctrl)
499
fan_ctrl_free(fan_data);
500
kfree(fan_data);
501
502
return 0;
503
}
504
505
#ifdef CONFIG_PM
506
static int gpio_fan_suspend(struct platform_device *pdev, pm_message_t state)
507
{
508
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
509
510
if (fan_data->ctrl) {
511
fan_data->resume_speed = fan_data->speed_index;
512
set_fan_speed(fan_data, 0);
513
}
514
515
return 0;
516
}
517
518
static int gpio_fan_resume(struct platform_device *pdev)
519
{
520
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
521
522
if (fan_data->ctrl)
523
set_fan_speed(fan_data, fan_data->resume_speed);
524
525
return 0;
526
}
527
#else
528
#define gpio_fan_suspend NULL
529
#define gpio_fan_resume NULL
530
#endif
531
532
static struct platform_driver gpio_fan_driver = {
533
.probe = gpio_fan_probe,
534
.remove = __devexit_p(gpio_fan_remove),
535
.suspend = gpio_fan_suspend,
536
.resume = gpio_fan_resume,
537
.driver = {
538
.name = "gpio-fan",
539
},
540
};
541
542
static int __init gpio_fan_init(void)
543
{
544
return platform_driver_register(&gpio_fan_driver);
545
}
546
547
static void __exit gpio_fan_exit(void)
548
{
549
platform_driver_unregister(&gpio_fan_driver);
550
}
551
552
module_init(gpio_fan_init);
553
module_exit(gpio_fan_exit);
554
555
MODULE_AUTHOR("Simon Guinot <[email protected]>");
556
MODULE_DESCRIPTION("GPIO FAN driver");
557
MODULE_LICENSE("GPL");
558
MODULE_ALIAS("platform:gpio-fan");
559
560