blob: ad7d8fdf4f81f04aff9b302b8757c3d88ffca3ff [file] [log] [blame]
Simon Guinotd6fe1362010-10-22 00:44:19 +02001/*
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>
Sachin Kamatc50588a2013-09-27 16:56:00 +053033#include <linux/of.h>
Jamie Lentin55fb8b062012-09-14 17:07:06 +010034#include <linux/of_platform.h>
35#include <linux/of_gpio.h>
Nishanth Menonb5cf88e2015-01-08 12:05:03 -060036#include <linux/thermal.h>
Simon Guinotd6fe1362010-10-22 00:44:19 +020037
Linus Walleijef7a6122017-09-26 01:09:05 +020038struct gpio_fan_alarm {
39 unsigned int gpio;
40 unsigned int active_low;
41};
42
43struct gpio_fan_speed {
44 int rpm;
45 int ctrl_val;
46};
47
48struct gpio_fan_platform_data {
49 int num_ctrl;
50 unsigned int *ctrl; /* fan control GPIOs. */
51 struct gpio_fan_alarm *alarm; /* fan alarm GPIO. */
52 /*
53 * Speed conversion array: rpm from/to GPIO bit field.
54 * This array _must_ be sorted in ascending rpm order.
55 */
56 int num_speed;
57 struct gpio_fan_speed *speed;
58};
59
Simon Guinotd6fe1362010-10-22 00:44:19 +020060struct gpio_fan_data {
Linus Walleij8c0eb9b2017-09-26 01:09:06 +020061 struct device *dev;
Simon Guinotd6fe1362010-10-22 00:44:19 +020062 struct device *hwmon_dev;
Nishanth Menonb5cf88e2015-01-08 12:05:03 -060063 /* Cooling device if any */
64 struct thermal_cooling_device *cdev;
Simon Guinotd6fe1362010-10-22 00:44:19 +020065 struct mutex lock; /* lock GPIOs operations. */
66 int num_ctrl;
67 unsigned *ctrl;
68 int num_speed;
69 struct gpio_fan_speed *speed;
70 int speed_index;
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +020071#ifdef CONFIG_PM_SLEEP
Simon Guinotd6fe1362010-10-22 00:44:19 +020072 int resume_speed;
73#endif
74 bool pwm_enable;
75 struct gpio_fan_alarm *alarm;
76 struct work_struct alarm_work;
77};
78
79/*
80 * Alarm GPIO.
81 */
82
83static void fan_alarm_notify(struct work_struct *ws)
84{
85 struct gpio_fan_data *fan_data =
86 container_of(ws, struct gpio_fan_data, alarm_work);
87
Linus Walleij8c0eb9b2017-09-26 01:09:06 +020088 sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
89 kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
Simon Guinotd6fe1362010-10-22 00:44:19 +020090}
91
92static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
93{
94 struct gpio_fan_data *fan_data = dev_id;
95
96 schedule_work(&fan_data->alarm_work);
97
98 return IRQ_NONE;
99}
100
Julia Lawallc490c632016-12-22 13:04:44 +0100101static ssize_t fan1_alarm_show(struct device *dev,
102 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200103{
104 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
105 struct gpio_fan_alarm *alarm = fan_data->alarm;
Nishanth Menon52a95c12014-12-04 10:58:47 -0600106 int value = gpio_get_value_cansleep(alarm->gpio);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200107
108 if (alarm->active_low)
109 value = !value;
110
111 return sprintf(buf, "%d\n", value);
112}
113
Julia Lawallc490c632016-12-22 13:04:44 +0100114static DEVICE_ATTR_RO(fan1_alarm);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200115
116static int fan_alarm_init(struct gpio_fan_data *fan_data,
117 struct gpio_fan_alarm *alarm)
118{
119 int err;
120 int alarm_irq;
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200121 struct device *dev = fan_data->dev;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200122
123 fan_data->alarm = alarm;
124
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200125 err = devm_gpio_request(dev, alarm->gpio, "GPIO fan alarm");
Simon Guinotd6fe1362010-10-22 00:44:19 +0200126 if (err)
127 return err;
128
129 err = gpio_direction_input(alarm->gpio);
130 if (err)
Guenter Roeckd00985f2012-06-02 09:58:07 -0700131 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200132
Simon Guinotd6fe1362010-10-22 00:44:19 +0200133 /*
134 * If the alarm GPIO don't support interrupts, just leave
135 * without initializing the fail notification support.
136 */
137 alarm_irq = gpio_to_irq(alarm->gpio);
138 if (alarm_irq < 0)
139 return 0;
140
141 INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200142 irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200143 err = devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
Guenter Roeckd00985f2012-06-02 09:58:07 -0700144 IRQF_SHARED, "GPIO fan alarm", fan_data);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200145 return err;
146}
147
Simon Guinotd6fe1362010-10-22 00:44:19 +0200148/*
149 * Control GPIOs.
150 */
151
152/* Must be called with fan_data->lock held, except during initialization. */
153static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
154{
155 int i;
156
157 for (i = 0; i < fan_data->num_ctrl; i++)
Nishanth Menon52a95c12014-12-04 10:58:47 -0600158 gpio_set_value_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200159}
160
161static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
162{
163 int i;
164 int ctrl_val = 0;
165
166 for (i = 0; i < fan_data->num_ctrl; i++) {
167 int value;
168
Nishanth Menon52a95c12014-12-04 10:58:47 -0600169 value = gpio_get_value_cansleep(fan_data->ctrl[i]);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200170 ctrl_val |= (value << i);
171 }
172 return ctrl_val;
173}
174
175/* Must be called with fan_data->lock held, except during initialization. */
176static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
177{
178 if (fan_data->speed_index == speed_index)
179 return;
180
181 __set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
182 fan_data->speed_index = speed_index;
183}
184
185static int get_fan_speed_index(struct gpio_fan_data *fan_data)
186{
187 int ctrl_val = __get_fan_ctrl(fan_data);
188 int i;
189
190 for (i = 0; i < fan_data->num_speed; i++)
191 if (fan_data->speed[i].ctrl_val == ctrl_val)
192 return i;
193
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200194 dev_warn(fan_data->dev,
Simon Guinotd6fe1362010-10-22 00:44:19 +0200195 "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
196
Guenter Roeckc52ae3d2013-09-13 10:42:39 -0700197 return -ENODEV;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200198}
199
Axel Lin2565fb02014-08-02 13:36:38 +0800200static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200201{
202 struct gpio_fan_speed *speed = fan_data->speed;
203 int i;
204
205 for (i = 0; i < fan_data->num_speed; i++)
206 if (speed[i].rpm >= rpm)
207 return i;
208
209 return fan_data->num_speed - 1;
210}
211
Julia Lawallc490c632016-12-22 13:04:44 +0100212static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr,
213 char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200214{
215 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
216 u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
217
218 return sprintf(buf, "%d\n", pwm);
219}
220
Julia Lawallc490c632016-12-22 13:04:44 +0100221static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr,
222 const char *buf, size_t count)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200223{
224 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
225 unsigned long pwm;
226 int speed_index;
227 int ret = count;
228
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100229 if (kstrtoul(buf, 10, &pwm) || pwm > 255)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200230 return -EINVAL;
231
232 mutex_lock(&fan_data->lock);
233
234 if (!fan_data->pwm_enable) {
235 ret = -EPERM;
236 goto exit_unlock;
237 }
238
239 speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
240 set_fan_speed(fan_data, speed_index);
241
242exit_unlock:
243 mutex_unlock(&fan_data->lock);
244
245 return ret;
246}
247
Julia Lawallc490c632016-12-22 13:04:44 +0100248static ssize_t pwm1_enable_show(struct device *dev,
249 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200250{
251 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
252
253 return sprintf(buf, "%d\n", fan_data->pwm_enable);
254}
255
Julia Lawallc490c632016-12-22 13:04:44 +0100256static ssize_t pwm1_enable_store(struct device *dev,
257 struct device_attribute *attr,
258 const char *buf, size_t count)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200259{
260 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
261 unsigned long val;
262
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100263 if (kstrtoul(buf, 10, &val) || val > 1)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200264 return -EINVAL;
265
266 if (fan_data->pwm_enable == val)
267 return count;
268
269 mutex_lock(&fan_data->lock);
270
271 fan_data->pwm_enable = val;
272
273 /* Disable manual control mode: set fan at full speed. */
274 if (val == 0)
275 set_fan_speed(fan_data, fan_data->num_speed - 1);
276
277 mutex_unlock(&fan_data->lock);
278
279 return count;
280}
281
Julia Lawallc490c632016-12-22 13:04:44 +0100282static ssize_t pwm1_mode_show(struct device *dev,
283 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200284{
285 return sprintf(buf, "0\n");
286}
287
Julia Lawallc490c632016-12-22 13:04:44 +0100288static ssize_t fan1_min_show(struct device *dev,
289 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200290{
291 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
292
293 return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
294}
295
Julia Lawallc490c632016-12-22 13:04:44 +0100296static ssize_t fan1_max_show(struct device *dev,
297 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200298{
299 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
300
301 return sprintf(buf, "%d\n",
302 fan_data->speed[fan_data->num_speed - 1].rpm);
303}
304
Julia Lawallc490c632016-12-22 13:04:44 +0100305static ssize_t fan1_input_show(struct device *dev,
306 struct device_attribute *attr, char *buf)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200307{
308 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
309
310 return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
311}
312
313static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
314 const char *buf, size_t count)
315{
316 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
317 unsigned long rpm;
318 int ret = count;
319
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100320 if (kstrtoul(buf, 10, &rpm))
Simon Guinotd6fe1362010-10-22 00:44:19 +0200321 return -EINVAL;
322
323 mutex_lock(&fan_data->lock);
324
325 if (!fan_data->pwm_enable) {
326 ret = -EPERM;
327 goto exit_unlock;
328 }
329
330 set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
331
332exit_unlock:
333 mutex_unlock(&fan_data->lock);
334
335 return ret;
336}
337
Julia Lawallc490c632016-12-22 13:04:44 +0100338static DEVICE_ATTR_RW(pwm1);
339static DEVICE_ATTR_RW(pwm1_enable);
340static DEVICE_ATTR_RO(pwm1_mode);
341static DEVICE_ATTR_RO(fan1_min);
342static DEVICE_ATTR_RO(fan1_max);
343static DEVICE_ATTR_RO(fan1_input);
344static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, fan1_input_show, set_rpm);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200345
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700346static umode_t gpio_fan_is_visible(struct kobject *kobj,
347 struct attribute *attr, int index)
348{
349 struct device *dev = container_of(kobj, struct device, kobj);
350 struct gpio_fan_data *data = dev_get_drvdata(dev);
351
Guenter Roeck7258a122013-07-06 09:46:14 -0700352 if (index == 0 && !data->alarm)
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700353 return 0;
Guenter Roeck7258a122013-07-06 09:46:14 -0700354 if (index > 0 && !data->ctrl)
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700355 return 0;
356
357 return attr->mode;
358}
359
360static struct attribute *gpio_fan_attributes[] = {
Guenter Roeck7258a122013-07-06 09:46:14 -0700361 &dev_attr_fan1_alarm.attr, /* 0 */
362 &dev_attr_pwm1.attr, /* 1 */
Simon Guinotd6fe1362010-10-22 00:44:19 +0200363 &dev_attr_pwm1_enable.attr,
364 &dev_attr_pwm1_mode.attr,
365 &dev_attr_fan1_input.attr,
366 &dev_attr_fan1_target.attr,
367 &dev_attr_fan1_min.attr,
368 &dev_attr_fan1_max.attr,
369 NULL
370};
371
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700372static const struct attribute_group gpio_fan_group = {
373 .attrs = gpio_fan_attributes,
374 .is_visible = gpio_fan_is_visible,
Simon Guinotd6fe1362010-10-22 00:44:19 +0200375};
376
Guenter Roeck7258a122013-07-06 09:46:14 -0700377static const struct attribute_group *gpio_fan_groups[] = {
378 &gpio_fan_group,
379 NULL
380};
381
Simon Guinotd6fe1362010-10-22 00:44:19 +0200382static int fan_ctrl_init(struct gpio_fan_data *fan_data,
383 struct gpio_fan_platform_data *pdata)
384{
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200385 struct device *dev = fan_data->dev;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200386 int num_ctrl = pdata->num_ctrl;
387 unsigned *ctrl = pdata->ctrl;
388 int i, err;
389
390 for (i = 0; i < num_ctrl; i++) {
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200391 err = devm_gpio_request(dev, ctrl[i],
Guenter Roeckd00985f2012-06-02 09:58:07 -0700392 "GPIO fan control");
Simon Guinotd6fe1362010-10-22 00:44:19 +0200393 if (err)
Guenter Roeckd00985f2012-06-02 09:58:07 -0700394 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200395
Nishanth Menon52a95c12014-12-04 10:58:47 -0600396 err = gpio_direction_output(ctrl[i],
397 gpio_get_value_cansleep(ctrl[i]));
Guenter Roeckd00985f2012-06-02 09:58:07 -0700398 if (err)
399 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200400 }
401
Simon Guinotd6fe1362010-10-22 00:44:19 +0200402 fan_data->num_ctrl = num_ctrl;
403 fan_data->ctrl = ctrl;
404 fan_data->num_speed = pdata->num_speed;
405 fan_data->speed = pdata->speed;
406 fan_data->pwm_enable = true; /* Enable manual fan speed control. */
407 fan_data->speed_index = get_fan_speed_index(fan_data);
Guenter Roeckd00985f2012-06-02 09:58:07 -0700408 if (fan_data->speed_index < 0)
Guenter Roeckc52ae3d2013-09-13 10:42:39 -0700409 return fan_data->speed_index;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200410
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700411 return 0;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200412}
413
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600414static int gpio_fan_get_max_state(struct thermal_cooling_device *cdev,
415 unsigned long *state)
416{
417 struct gpio_fan_data *fan_data = cdev->devdata;
418
419 if (!fan_data)
420 return -EINVAL;
421
422 *state = fan_data->num_speed - 1;
423 return 0;
424}
425
426static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev,
427 unsigned long *state)
428{
429 struct gpio_fan_data *fan_data = cdev->devdata;
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600430
431 if (!fan_data)
432 return -EINVAL;
433
Nishanth Menon000e09492016-02-19 18:09:51 -0600434 *state = fan_data->speed_index;
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600435 return 0;
436}
437
438static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev,
439 unsigned long state)
440{
441 struct gpio_fan_data *fan_data = cdev->devdata;
442
443 if (!fan_data)
444 return -EINVAL;
445
446 set_fan_speed(fan_data, state);
447 return 0;
448}
449
450static const struct thermal_cooling_device_ops gpio_fan_cool_ops = {
451 .get_max_state = gpio_fan_get_max_state,
452 .get_cur_state = gpio_fan_get_cur_state,
453 .set_cur_state = gpio_fan_set_cur_state,
454};
455
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100456#ifdef CONFIG_OF_GPIO
457/*
458 * Translate OpenFirmware node properties into platform_data
459 */
460static int gpio_fan_get_of_pdata(struct device *dev,
461 struct gpio_fan_platform_data *pdata)
462{
463 struct device_node *node;
464 struct gpio_fan_speed *speed;
465 unsigned *ctrl;
466 unsigned i;
467 u32 u;
468 struct property *prop;
469 const __be32 *p;
470
471 node = dev->of_node;
472
Simon Guinot73ef85f2015-02-25 18:58:19 +0100473 /* Alarm GPIO if one exists */
474 if (of_gpio_named_count(node, "alarm-gpios") > 0) {
475 struct gpio_fan_alarm *alarm;
476 int val;
477 enum of_gpio_flags flags;
478
479 alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
480 GFP_KERNEL);
481 if (!alarm)
482 return -ENOMEM;
483
484 val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
485 if (val < 0)
486 return val;
487 alarm->gpio = val;
488 alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
489
490 pdata->alarm = alarm;
491 }
492
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100493 /* Fill GPIO pin array */
494 pdata->num_ctrl = of_gpio_count(node);
Grant Likelye80beb22013-02-12 17:48:37 +0000495 if (pdata->num_ctrl <= 0) {
Simon Guinot73ef85f2015-02-25 18:58:19 +0100496 if (pdata->alarm)
497 return 0;
498 dev_err(dev, "DT properties empty / missing");
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100499 return -ENODEV;
500 }
501 ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
502 GFP_KERNEL);
503 if (!ctrl)
504 return -ENOMEM;
505 for (i = 0; i < pdata->num_ctrl; i++) {
506 int val;
507
508 val = of_get_gpio(node, i);
509 if (val < 0)
510 return val;
511 ctrl[i] = val;
512 }
513 pdata->ctrl = ctrl;
514
515 /* Get number of RPM/ctrl_val pairs in speed map */
516 prop = of_find_property(node, "gpio-fan,speed-map", &i);
517 if (!prop) {
518 dev_err(dev, "gpio-fan,speed-map DT property missing");
519 return -ENODEV;
520 }
521 i = i / sizeof(u32);
522 if (i == 0 || i & 1) {
523 dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries");
524 return -ENODEV;
525 }
526 pdata->num_speed = i / 2;
527
528 /*
529 * Populate speed map
530 * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...>
531 * this needs splitting into pairs to create gpio_fan_speed structs
532 */
533 speed = devm_kzalloc(dev,
534 pdata->num_speed * sizeof(struct gpio_fan_speed),
535 GFP_KERNEL);
536 if (!speed)
537 return -ENOMEM;
538 p = NULL;
539 for (i = 0; i < pdata->num_speed; i++) {
540 p = of_prop_next_u32(prop, p, &u);
541 if (!p)
542 return -ENODEV;
543 speed[i].rpm = u;
544 p = of_prop_next_u32(prop, p, &u);
545 if (!p)
546 return -ENODEV;
547 speed[i].ctrl_val = u;
548 }
549 pdata->speed = speed;
550
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100551 return 0;
552}
553
Jingoo Han6de709c2014-05-07 17:27:54 +0900554static const struct of_device_id of_gpio_fan_match[] = {
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100555 { .compatible = "gpio-fan", },
556 {},
557};
Luis de Bethencourtfe515282015-09-17 18:09:28 +0200558MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100559#endif /* CONFIG_OF_GPIO */
560
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500561static int gpio_fan_probe(struct platform_device *pdev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200562{
563 int err;
564 struct gpio_fan_data *fan_data;
Linus Walleijf9013c12017-09-26 01:09:04 +0200565 struct device *dev = &pdev->dev;
566 struct device_node *np = dev->of_node;
567 struct gpio_fan_platform_data *pdata = dev_get_platdata(dev);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200568
Linus Walleijf9013c12017-09-26 01:09:04 +0200569 fan_data = devm_kzalloc(dev, sizeof(struct gpio_fan_data),
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600570 GFP_KERNEL);
571 if (!fan_data)
572 return -ENOMEM;
573
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100574#ifdef CONFIG_OF_GPIO
575 if (!pdata) {
Linus Walleijf9013c12017-09-26 01:09:04 +0200576 pdata = devm_kzalloc(dev,
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100577 sizeof(struct gpio_fan_platform_data),
578 GFP_KERNEL);
579 if (!pdata)
580 return -ENOMEM;
581
Linus Walleijf9013c12017-09-26 01:09:04 +0200582 err = gpio_fan_get_of_pdata(dev, pdata);
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100583 if (err)
584 return err;
585 }
586#else /* CONFIG_OF_GPIO */
Simon Guinotd6fe1362010-10-22 00:44:19 +0200587 if (!pdata)
588 return -EINVAL;
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100589#endif /* CONFIG_OF_GPIO */
Simon Guinotd6fe1362010-10-22 00:44:19 +0200590
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200591 fan_data->dev = dev;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200592 platform_set_drvdata(pdev, fan_data);
593 mutex_init(&fan_data->lock);
594
595 /* Configure alarm GPIO if available. */
596 if (pdata->alarm) {
597 err = fan_alarm_init(fan_data, pdata->alarm);
598 if (err)
Guenter Roeckd00985f2012-06-02 09:58:07 -0700599 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200600 }
601
602 /* Configure control GPIOs if available. */
603 if (pdata->ctrl && pdata->num_ctrl > 0) {
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700604 if (!pdata->speed || pdata->num_speed <= 1)
605 return -EINVAL;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200606 err = fan_ctrl_init(fan_data, pdata);
607 if (err)
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700608 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200609 }
610
Simon Guinotd6fe1362010-10-22 00:44:19 +0200611 /* Make this driver part of hwmon class. */
Axel Lin49153b02014-06-14 14:50:50 +0800612 fan_data->hwmon_dev =
Linus Walleijf9013c12017-09-26 01:09:04 +0200613 devm_hwmon_device_register_with_groups(dev,
Axel Lin49153b02014-06-14 14:50:50 +0800614 "gpio_fan", fan_data,
615 gpio_fan_groups);
Guenter Roeck7258a122013-07-06 09:46:14 -0700616 if (IS_ERR(fan_data->hwmon_dev))
617 return PTR_ERR(fan_data->hwmon_dev);
Nishanth Menone76ea262015-04-08 18:23:52 -0500618#ifdef CONFIG_OF_GPIO
619 /* Optional cooling device register for Device tree platforms */
Linus Walleijf9013c12017-09-26 01:09:04 +0200620 fan_data->cdev = thermal_of_cooling_device_register(np,
Nishanth Menone76ea262015-04-08 18:23:52 -0500621 "gpio-fan",
622 fan_data,
623 &gpio_fan_cool_ops);
624#else /* CONFIG_OF_GPIO */
625 /* Optional cooling device register for non Device tree platforms */
626 fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data,
627 &gpio_fan_cool_ops);
628#endif /* CONFIG_OF_GPIO */
Simon Guinotd6fe1362010-10-22 00:44:19 +0200629
Linus Walleijf9013c12017-09-26 01:09:04 +0200630 dev_info(dev, "GPIO fan initialized\n");
Simon Guinotd6fe1362010-10-22 00:44:19 +0200631
632 return 0;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200633}
634
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600635static int gpio_fan_remove(struct platform_device *pdev)
Nishanth Menonb95579c2014-12-04 10:58:56 -0600636{
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600637 struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
638
639 if (!IS_ERR(fan_data->cdev))
640 thermal_cooling_device_unregister(fan_data->cdev);
Nishanth Menonb95579c2014-12-04 10:58:56 -0600641
642 if (fan_data->ctrl)
643 set_fan_speed(fan_data, 0);
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600644
645 return 0;
646}
647
648static void gpio_fan_shutdown(struct platform_device *pdev)
649{
650 gpio_fan_remove(pdev);
Nishanth Menonb95579c2014-12-04 10:58:56 -0600651}
652
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200653#ifdef CONFIG_PM_SLEEP
654static int gpio_fan_suspend(struct device *dev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200655{
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200656 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200657
658 if (fan_data->ctrl) {
659 fan_data->resume_speed = fan_data->speed_index;
660 set_fan_speed(fan_data, 0);
661 }
662
663 return 0;
664}
665
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200666static int gpio_fan_resume(struct device *dev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200667{
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200668 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200669
670 if (fan_data->ctrl)
671 set_fan_speed(fan_data, fan_data->resume_speed);
672
673 return 0;
674}
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200675
676static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
Guenter Roeck24f9c532013-01-10 05:54:40 -0800677#define GPIO_FAN_PM (&gpio_fan_pm)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200678#else
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200679#define GPIO_FAN_PM NULL
Simon Guinotd6fe1362010-10-22 00:44:19 +0200680#endif
681
682static struct platform_driver gpio_fan_driver = {
683 .probe = gpio_fan_probe,
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600684 .remove = gpio_fan_remove,
Nishanth Menonb95579c2014-12-04 10:58:56 -0600685 .shutdown = gpio_fan_shutdown,
Simon Guinotd6fe1362010-10-22 00:44:19 +0200686 .driver = {
687 .name = "gpio-fan",
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200688 .pm = GPIO_FAN_PM,
Jamie Lentineaa7cc62012-11-01 23:55:43 +0000689#ifdef CONFIG_OF_GPIO
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100690 .of_match_table = of_match_ptr(of_gpio_fan_match),
Jamie Lentineaa7cc62012-11-01 23:55:43 +0000691#endif
Simon Guinotd6fe1362010-10-22 00:44:19 +0200692 },
693};
694
Axel Lin25a236a2011-11-25 02:31:00 -0500695module_platform_driver(gpio_fan_driver);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200696
697MODULE_AUTHOR("Simon Guinot <[email protected]>");
698MODULE_DESCRIPTION("GPIO FAN driver");
699MODULE_LICENSE("GPL");
700MODULE_ALIAS("platform:gpio-fan");