blob: 55dbdb223e0233da813392ec170729d99604767b [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/*
457 * Translate OpenFirmware node properties into platform_data
458 */
459static int gpio_fan_get_of_pdata(struct device *dev,
460 struct gpio_fan_platform_data *pdata)
461{
462 struct device_node *node;
463 struct gpio_fan_speed *speed;
464 unsigned *ctrl;
465 unsigned i;
466 u32 u;
467 struct property *prop;
468 const __be32 *p;
469
470 node = dev->of_node;
471
Simon Guinot73ef85f2015-02-25 18:58:19 +0100472 /* Alarm GPIO if one exists */
473 if (of_gpio_named_count(node, "alarm-gpios") > 0) {
474 struct gpio_fan_alarm *alarm;
475 int val;
476 enum of_gpio_flags flags;
477
478 alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
479 GFP_KERNEL);
480 if (!alarm)
481 return -ENOMEM;
482
483 val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
484 if (val < 0)
485 return val;
486 alarm->gpio = val;
487 alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
488
489 pdata->alarm = alarm;
490 }
491
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100492 /* Fill GPIO pin array */
493 pdata->num_ctrl = of_gpio_count(node);
Grant Likelye80beb22013-02-12 17:48:37 +0000494 if (pdata->num_ctrl <= 0) {
Simon Guinot73ef85f2015-02-25 18:58:19 +0100495 if (pdata->alarm)
496 return 0;
497 dev_err(dev, "DT properties empty / missing");
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100498 return -ENODEV;
499 }
500 ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
501 GFP_KERNEL);
502 if (!ctrl)
503 return -ENOMEM;
504 for (i = 0; i < pdata->num_ctrl; i++) {
505 int val;
506
507 val = of_get_gpio(node, i);
508 if (val < 0)
509 return val;
510 ctrl[i] = val;
511 }
512 pdata->ctrl = ctrl;
513
514 /* Get number of RPM/ctrl_val pairs in speed map */
515 prop = of_find_property(node, "gpio-fan,speed-map", &i);
516 if (!prop) {
517 dev_err(dev, "gpio-fan,speed-map DT property missing");
518 return -ENODEV;
519 }
520 i = i / sizeof(u32);
521 if (i == 0 || i & 1) {
522 dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries");
523 return -ENODEV;
524 }
525 pdata->num_speed = i / 2;
526
527 /*
528 * Populate speed map
529 * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...>
530 * this needs splitting into pairs to create gpio_fan_speed structs
531 */
532 speed = devm_kzalloc(dev,
533 pdata->num_speed * sizeof(struct gpio_fan_speed),
534 GFP_KERNEL);
535 if (!speed)
536 return -ENOMEM;
537 p = NULL;
538 for (i = 0; i < pdata->num_speed; i++) {
539 p = of_prop_next_u32(prop, p, &u);
540 if (!p)
541 return -ENODEV;
542 speed[i].rpm = u;
543 p = of_prop_next_u32(prop, p, &u);
544 if (!p)
545 return -ENODEV;
546 speed[i].ctrl_val = u;
547 }
548 pdata->speed = speed;
549
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100550 return 0;
551}
552
Jingoo Han6de709c2014-05-07 17:27:54 +0900553static const struct of_device_id of_gpio_fan_match[] = {
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100554 { .compatible = "gpio-fan", },
555 {},
556};
Luis de Bethencourtfe515282015-09-17 18:09:28 +0200557MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100558
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500559static int gpio_fan_probe(struct platform_device *pdev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200560{
561 int err;
562 struct gpio_fan_data *fan_data;
Linus Walleijf9013c12017-09-26 01:09:04 +0200563 struct device *dev = &pdev->dev;
564 struct device_node *np = dev->of_node;
Linus Walleija9b4c8a2017-09-26 01:09:07 +0200565 struct gpio_fan_platform_data *pdata;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200566
Linus Walleijf9013c12017-09-26 01:09:04 +0200567 fan_data = devm_kzalloc(dev, sizeof(struct gpio_fan_data),
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600568 GFP_KERNEL);
569 if (!fan_data)
570 return -ENOMEM;
571
Linus Walleija9b4c8a2017-09-26 01:09:07 +0200572 pdata = devm_kzalloc(dev,
573 sizeof(struct gpio_fan_platform_data),
574 GFP_KERNEL);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200575 if (!pdata)
Linus Walleija9b4c8a2017-09-26 01:09:07 +0200576 return -ENOMEM;
577
578 err = gpio_fan_get_of_pdata(dev, pdata);
579 if (err)
580 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200581
Linus Walleij8c0eb9b2017-09-26 01:09:06 +0200582 fan_data->dev = dev;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200583 platform_set_drvdata(pdev, fan_data);
584 mutex_init(&fan_data->lock);
585
586 /* Configure alarm GPIO if available. */
587 if (pdata->alarm) {
588 err = fan_alarm_init(fan_data, pdata->alarm);
589 if (err)
Guenter Roeckd00985f2012-06-02 09:58:07 -0700590 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200591 }
592
593 /* Configure control GPIOs if available. */
594 if (pdata->ctrl && pdata->num_ctrl > 0) {
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700595 if (!pdata->speed || pdata->num_speed <= 1)
596 return -EINVAL;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200597 err = fan_ctrl_init(fan_data, pdata);
598 if (err)
Guenter Roeckc81cc5a2013-03-30 09:09:39 -0700599 return err;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200600 }
601
Simon Guinotd6fe1362010-10-22 00:44:19 +0200602 /* Make this driver part of hwmon class. */
Axel Lin49153b02014-06-14 14:50:50 +0800603 fan_data->hwmon_dev =
Linus Walleijf9013c12017-09-26 01:09:04 +0200604 devm_hwmon_device_register_with_groups(dev,
Axel Lin49153b02014-06-14 14:50:50 +0800605 "gpio_fan", fan_data,
606 gpio_fan_groups);
Guenter Roeck7258a122013-07-06 09:46:14 -0700607 if (IS_ERR(fan_data->hwmon_dev))
608 return PTR_ERR(fan_data->hwmon_dev);
Linus Walleija9b4c8a2017-09-26 01:09:07 +0200609
Nishanth Menone76ea262015-04-08 18:23:52 -0500610 /* Optional cooling device register for Device tree platforms */
Linus Walleijf9013c12017-09-26 01:09:04 +0200611 fan_data->cdev = thermal_of_cooling_device_register(np,
Nishanth Menone76ea262015-04-08 18:23:52 -0500612 "gpio-fan",
613 fan_data,
614 &gpio_fan_cool_ops);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200615
Linus Walleijf9013c12017-09-26 01:09:04 +0200616 dev_info(dev, "GPIO fan initialized\n");
Simon Guinotd6fe1362010-10-22 00:44:19 +0200617
618 return 0;
Simon Guinotd6fe1362010-10-22 00:44:19 +0200619}
620
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600621static int gpio_fan_remove(struct platform_device *pdev)
Nishanth Menonb95579c2014-12-04 10:58:56 -0600622{
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600623 struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
624
625 if (!IS_ERR(fan_data->cdev))
626 thermal_cooling_device_unregister(fan_data->cdev);
Nishanth Menonb95579c2014-12-04 10:58:56 -0600627
628 if (fan_data->ctrl)
629 set_fan_speed(fan_data, 0);
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600630
631 return 0;
632}
633
634static void gpio_fan_shutdown(struct platform_device *pdev)
635{
636 gpio_fan_remove(pdev);
Nishanth Menonb95579c2014-12-04 10:58:56 -0600637}
638
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200639#ifdef CONFIG_PM_SLEEP
640static int gpio_fan_suspend(struct device *dev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200641{
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200642 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200643
644 if (fan_data->ctrl) {
645 fan_data->resume_speed = fan_data->speed_index;
646 set_fan_speed(fan_data, 0);
647 }
648
649 return 0;
650}
651
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200652static int gpio_fan_resume(struct device *dev)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200653{
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200654 struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200655
656 if (fan_data->ctrl)
657 set_fan_speed(fan_data, fan_data->resume_speed);
658
659 return 0;
660}
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200661
662static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
Guenter Roeck24f9c532013-01-10 05:54:40 -0800663#define GPIO_FAN_PM (&gpio_fan_pm)
Simon Guinotd6fe1362010-10-22 00:44:19 +0200664#else
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200665#define GPIO_FAN_PM NULL
Simon Guinotd6fe1362010-10-22 00:44:19 +0200666#endif
667
668static struct platform_driver gpio_fan_driver = {
669 .probe = gpio_fan_probe,
Nishanth Menonb5cf88e2015-01-08 12:05:03 -0600670 .remove = gpio_fan_remove,
Nishanth Menonb95579c2014-12-04 10:58:56 -0600671 .shutdown = gpio_fan_shutdown,
Simon Guinotd6fe1362010-10-22 00:44:19 +0200672 .driver = {
673 .name = "gpio-fan",
Rafael J. Wysocki6d20a6c02012-07-08 00:01:03 +0200674 .pm = GPIO_FAN_PM,
Jamie Lentin55fb8b062012-09-14 17:07:06 +0100675 .of_match_table = of_match_ptr(of_gpio_fan_match),
Simon Guinotd6fe1362010-10-22 00:44:19 +0200676 },
677};
678
Axel Lin25a236a2011-11-25 02:31:00 -0500679module_platform_driver(gpio_fan_driver);
Simon Guinotd6fe1362010-10-22 00:44:19 +0200680
681MODULE_AUTHOR("Simon Guinot <[email protected]>");
682MODULE_DESCRIPTION("GPIO FAN driver");
683MODULE_LICENSE("GPL");
684MODULE_ALIAS("platform:gpio-fan");