Blame view
drivers/hwmon/gpio-fan.c
13.9 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
d6fe1360f hwmon: add generi... |
2 3 4 5 6 7 |
/* * gpio-fan.c - Hwmon driver for fans connected to GPIO lines. * * Copyright (C) 2010 LaCie * * Author: Simon Guinot <sguinot@lacie.com> |
d6fe1360f hwmon: add generi... |
8 9 10 11 12 13 14 15 16 17 18 |
*/ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/hwmon.h> |
9de382fdd hwmon: (gpio-fan)... |
19 |
#include <linux/gpio/consumer.h> |
c50588aba hwmon: (gpio-fan)... |
20 |
#include <linux/of.h> |
55fb8b068 hwmon: Add device... |
21 |
#include <linux/of_platform.h> |
b5cf88e46 (gpio-fan): Add t... |
22 |
#include <linux/thermal.h> |
d6fe1360f hwmon: add generi... |
23 |
|
ef7a61241 hwmon: (gpio-fan)... |
24 25 26 27 |
struct gpio_fan_speed { int rpm; int ctrl_val; }; |
d6fe1360f hwmon: add generi... |
28 |
struct gpio_fan_data { |
8c0eb9bc5 hwmon: (gpio-fan)... |
29 |
struct device *dev; |
d6fe1360f hwmon: add generi... |
30 |
struct device *hwmon_dev; |
b5cf88e46 (gpio-fan): Add t... |
31 32 |
/* Cooling device if any */ struct thermal_cooling_device *cdev; |
d6fe1360f hwmon: add generi... |
33 |
struct mutex lock; /* lock GPIOs operations. */ |
e99c2e5d6 hwmon: (gpio-fan)... |
34 |
int num_gpios; |
9de382fdd hwmon: (gpio-fan)... |
35 |
struct gpio_desc **gpios; |
d6fe1360f hwmon: add generi... |
36 37 38 |
int num_speed; struct gpio_fan_speed *speed; int speed_index; |
6d20a6c06 hwmon: (gpio-fan)... |
39 |
#ifdef CONFIG_PM_SLEEP |
d6fe1360f hwmon: add generi... |
40 41 42 |
int resume_speed; #endif bool pwm_enable; |
9de382fdd hwmon: (gpio-fan)... |
43 |
struct gpio_desc *alarm_gpio; |
d6fe1360f hwmon: add generi... |
44 45 46 47 48 49 50 51 52 53 54 |
struct work_struct alarm_work; }; /* * Alarm GPIO. */ static void fan_alarm_notify(struct work_struct *ws) { struct gpio_fan_data *fan_data = container_of(ws, struct gpio_fan_data, alarm_work); |
277c628fa hwmon: (gpio-fan)... |
55 56 |
sysfs_notify(&fan_data->hwmon_dev->kobj, NULL, "fan1_alarm"); kobject_uevent(&fan_data->hwmon_dev->kobj, KOBJ_CHANGE); |
d6fe1360f hwmon: add generi... |
57 58 59 60 61 62 63 64 65 66 |
} static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id) { struct gpio_fan_data *fan_data = dev_id; schedule_work(&fan_data->alarm_work); return IRQ_NONE; } |
c490c63e9 hwmon: (gpio-fan)... |
67 68 |
static ssize_t fan1_alarm_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
69 70 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); |
d6fe1360f hwmon: add generi... |
71 |
|
9de382fdd hwmon: (gpio-fan)... |
72 73 74 |
return sprintf(buf, "%d ", gpiod_get_value_cansleep(fan_data->alarm_gpio)); |
d6fe1360f hwmon: add generi... |
75 |
} |
c490c63e9 hwmon: (gpio-fan)... |
76 |
static DEVICE_ATTR_RO(fan1_alarm); |
d6fe1360f hwmon: add generi... |
77 |
|
b5482f7e6 hwmon: (gpio-fan)... |
78 |
static int fan_alarm_init(struct gpio_fan_data *fan_data) |
d6fe1360f hwmon: add generi... |
79 |
{ |
d6fe1360f hwmon: add generi... |
80 |
int alarm_irq; |
8c0eb9bc5 hwmon: (gpio-fan)... |
81 |
struct device *dev = fan_data->dev; |
d6fe1360f hwmon: add generi... |
82 |
|
d6fe1360f hwmon: add generi... |
83 84 85 86 |
/* * If the alarm GPIO don't support interrupts, just leave * without initializing the fail notification support. */ |
9de382fdd hwmon: (gpio-fan)... |
87 88 |
alarm_irq = gpiod_to_irq(fan_data->alarm_gpio); if (alarm_irq <= 0) |
d6fe1360f hwmon: add generi... |
89 90 91 |
return 0; INIT_WORK(&fan_data->alarm_work, fan_alarm_notify); |
dced35aeb drivers: Final ir... |
92 |
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); |
9de382fdd hwmon: (gpio-fan)... |
93 94 |
return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler, IRQF_SHARED, "GPIO fan alarm", fan_data); |
d6fe1360f hwmon: add generi... |
95 |
} |
d6fe1360f hwmon: add generi... |
96 97 98 99 100 101 102 103 |
/* * Control GPIOs. */ /* Must be called with fan_data->lock held, except during initialization. */ static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val) { int i; |
e99c2e5d6 hwmon: (gpio-fan)... |
104 |
for (i = 0; i < fan_data->num_gpios; i++) |
9de382fdd hwmon: (gpio-fan)... |
105 106 |
gpiod_set_value_cansleep(fan_data->gpios[i], (ctrl_val >> i) & 1); |
d6fe1360f hwmon: add generi... |
107 108 109 110 111 112 |
} static int __get_fan_ctrl(struct gpio_fan_data *fan_data) { int i; int ctrl_val = 0; |
e99c2e5d6 hwmon: (gpio-fan)... |
113 |
for (i = 0; i < fan_data->num_gpios; i++) { |
d6fe1360f hwmon: add generi... |
114 |
int value; |
9de382fdd hwmon: (gpio-fan)... |
115 |
value = gpiod_get_value_cansleep(fan_data->gpios[i]); |
d6fe1360f hwmon: add generi... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
ctrl_val |= (value << i); } return ctrl_val; } /* Must be called with fan_data->lock held, except during initialization. */ static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index) { if (fan_data->speed_index == speed_index) return; __set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val); fan_data->speed_index = speed_index; } static int get_fan_speed_index(struct gpio_fan_data *fan_data) { int ctrl_val = __get_fan_ctrl(fan_data); int i; for (i = 0; i < fan_data->num_speed; i++) if (fan_data->speed[i].ctrl_val == ctrl_val) return i; |
8c0eb9bc5 hwmon: (gpio-fan)... |
139 |
dev_warn(fan_data->dev, |
d6fe1360f hwmon: add generi... |
140 141 |
"missing speed array entry for GPIO value 0x%x ", ctrl_val); |
c52ae3d27 hwmon: (gpio_fan)... |
142 |
return -ENODEV; |
d6fe1360f hwmon: add generi... |
143 |
} |
2565fb05d hwmon: (gpio-fan)... |
144 |
static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm) |
d6fe1360f hwmon: add generi... |
145 146 147 148 149 150 151 152 153 154 |
{ struct gpio_fan_speed *speed = fan_data->speed; int i; for (i = 0; i < fan_data->num_speed; i++) if (speed[i].rpm >= rpm) return i; return fan_data->num_speed - 1; } |
c490c63e9 hwmon: (gpio-fan)... |
155 156 |
static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
157 158 159 160 161 162 163 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1); return sprintf(buf, "%d ", pwm); } |
c490c63e9 hwmon: (gpio-fan)... |
164 165 |
static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
d6fe1360f hwmon: add generi... |
166 167 168 169 170 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); unsigned long pwm; int speed_index; int ret = count; |
179c4fdb5 hwmon: replaced s... |
171 |
if (kstrtoul(buf, 10, &pwm) || pwm > 255) |
d6fe1360f hwmon: add generi... |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
return -EINVAL; mutex_lock(&fan_data->lock); if (!fan_data->pwm_enable) { ret = -EPERM; goto exit_unlock; } speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255); set_fan_speed(fan_data, speed_index); exit_unlock: mutex_unlock(&fan_data->lock); return ret; } |
c490c63e9 hwmon: (gpio-fan)... |
189 190 |
static ssize_t pwm1_enable_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
191 192 193 194 195 196 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d ", fan_data->pwm_enable); } |
c490c63e9 hwmon: (gpio-fan)... |
197 198 199 |
static ssize_t pwm1_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
d6fe1360f hwmon: add generi... |
200 201 202 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); unsigned long val; |
179c4fdb5 hwmon: replaced s... |
203 |
if (kstrtoul(buf, 10, &val) || val > 1) |
d6fe1360f hwmon: add generi... |
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
return -EINVAL; if (fan_data->pwm_enable == val) return count; mutex_lock(&fan_data->lock); fan_data->pwm_enable = val; /* Disable manual control mode: set fan at full speed. */ if (val == 0) set_fan_speed(fan_data, fan_data->num_speed - 1); mutex_unlock(&fan_data->lock); return count; } |
c490c63e9 hwmon: (gpio-fan)... |
221 222 |
static ssize_t pwm1_mode_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
223 224 225 226 |
{ return sprintf(buf, "0 "); } |
c490c63e9 hwmon: (gpio-fan)... |
227 228 |
static ssize_t fan1_min_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
229 230 231 232 233 234 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d ", fan_data->speed[0].rpm); } |
c490c63e9 hwmon: (gpio-fan)... |
235 236 |
static ssize_t fan1_max_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
237 238 239 240 241 242 243 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d ", fan_data->speed[fan_data->num_speed - 1].rpm); } |
c490c63e9 hwmon: (gpio-fan)... |
244 245 |
static ssize_t fan1_input_show(struct device *dev, struct device_attribute *attr, char *buf) |
d6fe1360f hwmon: add generi... |
246 247 248 249 250 251 252 253 254 255 256 257 258 |
{ struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d ", fan_data->speed[fan_data->speed_index].rpm); } static ssize_t set_rpm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); unsigned long rpm; int ret = count; |
179c4fdb5 hwmon: replaced s... |
259 |
if (kstrtoul(buf, 10, &rpm)) |
d6fe1360f hwmon: add generi... |
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
return -EINVAL; mutex_lock(&fan_data->lock); if (!fan_data->pwm_enable) { ret = -EPERM; goto exit_unlock; } set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm)); exit_unlock: mutex_unlock(&fan_data->lock); return ret; } |
c490c63e9 hwmon: (gpio-fan)... |
276 277 278 279 280 281 |
static DEVICE_ATTR_RW(pwm1); static DEVICE_ATTR_RW(pwm1_enable); static DEVICE_ATTR_RO(pwm1_mode); static DEVICE_ATTR_RO(fan1_min); static DEVICE_ATTR_RO(fan1_max); static DEVICE_ATTR_RO(fan1_input); |
905bc0d46 hwmon: (gpio-fan)... |
282 |
static DEVICE_ATTR(fan1_target, 0644, fan1_input_show, set_rpm); |
d6fe1360f hwmon: add generi... |
283 |
|
c81cc5a4c hwmon: (gpio-fan)... |
284 285 286 287 288 |
static umode_t gpio_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); struct gpio_fan_data *data = dev_get_drvdata(dev); |
c9933cb16 hwmon: (gpio-fan)... |
289 |
if (index == 0 && !data->alarm_gpio) |
c81cc5a4c hwmon: (gpio-fan)... |
290 |
return 0; |
e99c2e5d6 hwmon: (gpio-fan)... |
291 |
if (index > 0 && !data->gpios) |
c81cc5a4c hwmon: (gpio-fan)... |
292 293 294 295 296 297 |
return 0; return attr->mode; } static struct attribute *gpio_fan_attributes[] = { |
7258a1253 hwmon: (gpio-fan)... |
298 299 |
&dev_attr_fan1_alarm.attr, /* 0 */ &dev_attr_pwm1.attr, /* 1 */ |
d6fe1360f hwmon: add generi... |
300 301 302 303 304 305 306 307 |
&dev_attr_pwm1_enable.attr, &dev_attr_pwm1_mode.attr, &dev_attr_fan1_input.attr, &dev_attr_fan1_target.attr, &dev_attr_fan1_min.attr, &dev_attr_fan1_max.attr, NULL }; |
c81cc5a4c hwmon: (gpio-fan)... |
308 309 310 |
static const struct attribute_group gpio_fan_group = { .attrs = gpio_fan_attributes, .is_visible = gpio_fan_is_visible, |
d6fe1360f hwmon: add generi... |
311 |
}; |
7258a1253 hwmon: (gpio-fan)... |
312 313 314 315 |
static const struct attribute_group *gpio_fan_groups[] = { &gpio_fan_group, NULL }; |
b5482f7e6 hwmon: (gpio-fan)... |
316 |
static int fan_ctrl_init(struct gpio_fan_data *fan_data) |
d6fe1360f hwmon: add generi... |
317 |
{ |
e99c2e5d6 hwmon: (gpio-fan)... |
318 |
int num_gpios = fan_data->num_gpios; |
9de382fdd hwmon: (gpio-fan)... |
319 |
struct gpio_desc **gpios = fan_data->gpios; |
d6fe1360f hwmon: add generi... |
320 |
int i, err; |
e99c2e5d6 hwmon: (gpio-fan)... |
321 |
for (i = 0; i < num_gpios; i++) { |
9de382fdd hwmon: (gpio-fan)... |
322 323 324 325 326 327 328 329 |
/* * The GPIO descriptors were retrieved with GPIOD_ASIS so here * we set the GPIO into output mode, carefully preserving the * current value by setting it to whatever it is already set * (no surprise changes in default fan speed). */ err = gpiod_direction_output(gpios[i], gpiod_get_value_cansleep(gpios[i])); |
d00985f3d hwmon: (gpio-fan)... |
330 331 |
if (err) return err; |
d6fe1360f hwmon: add generi... |
332 |
} |
d6fe1360f hwmon: add generi... |
333 334 |
fan_data->pwm_enable = true; /* Enable manual fan speed control. */ fan_data->speed_index = get_fan_speed_index(fan_data); |
d00985f3d hwmon: (gpio-fan)... |
335 |
if (fan_data->speed_index < 0) |
c52ae3d27 hwmon: (gpio_fan)... |
336 |
return fan_data->speed_index; |
d6fe1360f hwmon: add generi... |
337 |
|
c81cc5a4c hwmon: (gpio-fan)... |
338 |
return 0; |
d6fe1360f hwmon: add generi... |
339 |
} |
b5cf88e46 (gpio-fan): Add t... |
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
static int gpio_fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct gpio_fan_data *fan_data = cdev->devdata; if (!fan_data) return -EINVAL; *state = fan_data->num_speed - 1; return 0; } static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct gpio_fan_data *fan_data = cdev->devdata; |
b5cf88e46 (gpio-fan): Add t... |
356 357 358 |
if (!fan_data) return -EINVAL; |
000e09491 hwmon: (gpio-fan)... |
359 |
*state = fan_data->speed_index; |
b5cf88e46 (gpio-fan): Add t... |
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
return 0; } static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct gpio_fan_data *fan_data = cdev->devdata; if (!fan_data) return -EINVAL; set_fan_speed(fan_data, state); return 0; } static const struct thermal_cooling_device_ops gpio_fan_cool_ops = { .get_max_state = gpio_fan_get_max_state, .get_cur_state = gpio_fan_get_cur_state, .set_cur_state = gpio_fan_set_cur_state, }; |
55fb8b068 hwmon: Add device... |
380 381 382 |
/* * Translate OpenFirmware node properties into platform_data */ |
b5482f7e6 hwmon: (gpio-fan)... |
383 |
static int gpio_fan_get_of_data(struct gpio_fan_data *fan_data) |
55fb8b068 hwmon: Add device... |
384 |
{ |
55fb8b068 hwmon: Add device... |
385 |
struct gpio_fan_speed *speed; |
b5482f7e6 hwmon: (gpio-fan)... |
386 387 |
struct device *dev = fan_data->dev; struct device_node *np = dev->of_node; |
9de382fdd hwmon: (gpio-fan)... |
388 |
struct gpio_desc **gpios; |
55fb8b068 hwmon: Add device... |
389 390 391 392 |
unsigned i; u32 u; struct property *prop; const __be32 *p; |
73ef85f42 hwmon: (gpio-fan)... |
393 |
/* Alarm GPIO if one exists */ |
9de382fdd hwmon: (gpio-fan)... |
394 395 396 |
fan_data->alarm_gpio = devm_gpiod_get_optional(dev, "alarm", GPIOD_IN); if (IS_ERR(fan_data->alarm_gpio)) return PTR_ERR(fan_data->alarm_gpio); |
73ef85f42 hwmon: (gpio-fan)... |
397 |
|
55fb8b068 hwmon: Add device... |
398 |
/* Fill GPIO pin array */ |
9de382fdd hwmon: (gpio-fan)... |
399 |
fan_data->num_gpios = gpiod_count(dev, NULL); |
e99c2e5d6 hwmon: (gpio-fan)... |
400 |
if (fan_data->num_gpios <= 0) { |
c9933cb16 hwmon: (gpio-fan)... |
401 |
if (fan_data->alarm_gpio) |
73ef85f42 hwmon: (gpio-fan)... |
402 403 |
return 0; dev_err(dev, "DT properties empty / missing"); |
55fb8b068 hwmon: Add device... |
404 405 |
return -ENODEV; } |
a86854d0c treewide: devm_kz... |
406 407 |
gpios = devm_kcalloc(dev, fan_data->num_gpios, sizeof(struct gpio_desc *), |
9de382fdd hwmon: (gpio-fan)... |
408 |
GFP_KERNEL); |
e99c2e5d6 hwmon: (gpio-fan)... |
409 |
if (!gpios) |
55fb8b068 hwmon: Add device... |
410 |
return -ENOMEM; |
e99c2e5d6 hwmon: (gpio-fan)... |
411 |
for (i = 0; i < fan_data->num_gpios; i++) { |
9de382fdd hwmon: (gpio-fan)... |
412 413 414 |
gpios[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); if (IS_ERR(gpios[i])) return PTR_ERR(gpios[i]); |
55fb8b068 hwmon: Add device... |
415 |
} |
e99c2e5d6 hwmon: (gpio-fan)... |
416 |
fan_data->gpios = gpios; |
55fb8b068 hwmon: Add device... |
417 418 |
/* Get number of RPM/ctrl_val pairs in speed map */ |
b5482f7e6 hwmon: (gpio-fan)... |
419 |
prop = of_find_property(np, "gpio-fan,speed-map", &i); |
55fb8b068 hwmon: Add device... |
420 421 422 423 424 425 426 427 428 |
if (!prop) { dev_err(dev, "gpio-fan,speed-map DT property missing"); return -ENODEV; } i = i / sizeof(u32); if (i == 0 || i & 1) { dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries"); return -ENODEV; } |
b5482f7e6 hwmon: (gpio-fan)... |
429 |
fan_data->num_speed = i / 2; |
55fb8b068 hwmon: Add device... |
430 431 432 433 434 435 |
/* * Populate speed map * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...> * this needs splitting into pairs to create gpio_fan_speed structs */ |
a86854d0c treewide: devm_kz... |
436 437 |
speed = devm_kcalloc(dev, fan_data->num_speed, sizeof(struct gpio_fan_speed), |
55fb8b068 hwmon: Add device... |
438 439 440 441 |
GFP_KERNEL); if (!speed) return -ENOMEM; p = NULL; |
b5482f7e6 hwmon: (gpio-fan)... |
442 |
for (i = 0; i < fan_data->num_speed; i++) { |
55fb8b068 hwmon: Add device... |
443 444 445 446 447 448 449 450 451 |
p = of_prop_next_u32(prop, p, &u); if (!p) return -ENODEV; speed[i].rpm = u; p = of_prop_next_u32(prop, p, &u); if (!p) return -ENODEV; speed[i].ctrl_val = u; } |
b5482f7e6 hwmon: (gpio-fan)... |
452 |
fan_data->speed = speed; |
55fb8b068 hwmon: Add device... |
453 |
|
55fb8b068 hwmon: Add device... |
454 455 |
return 0; } |
6de709c5e hwmon: (gpio-fan)... |
456 |
static const struct of_device_id of_gpio_fan_match[] = { |
55fb8b068 hwmon: Add device... |
457 458 459 |
{ .compatible = "gpio-fan", }, {}, }; |
fe5152882 hwmon: (gpio-fan)... |
460 |
MODULE_DEVICE_TABLE(of, of_gpio_fan_match); |
55fb8b068 hwmon: Add device... |
461 |
|
953478455 hwmon: (gpio-fan)... |
462 463 464 465 |
static void gpio_fan_stop(void *data) { set_fan_speed(data, 0); } |
6c931ae1c hwmon: remove use... |
466 |
static int gpio_fan_probe(struct platform_device *pdev) |
d6fe1360f hwmon: add generi... |
467 468 469 |
{ int err; struct gpio_fan_data *fan_data; |
f9013c167 hwmon: (gpio-fan)... |
470 471 |
struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; |
d6fe1360f hwmon: add generi... |
472 |
|
f9013c167 hwmon: (gpio-fan)... |
473 |
fan_data = devm_kzalloc(dev, sizeof(struct gpio_fan_data), |
b5cf88e46 (gpio-fan): Add t... |
474 475 476 |
GFP_KERNEL); if (!fan_data) return -ENOMEM; |
534e28d87 hwmon: (gpio-fan)... |
477 |
fan_data->dev = dev; |
b5482f7e6 hwmon: (gpio-fan)... |
478 |
err = gpio_fan_get_of_data(fan_data); |
a9b4c8afc hwmon: (gpio-fan)... |
479 480 |
if (err) return err; |
d6fe1360f hwmon: add generi... |
481 |
|
d6fe1360f hwmon: add generi... |
482 483 |
platform_set_drvdata(pdev, fan_data); mutex_init(&fan_data->lock); |
d6fe1360f hwmon: add generi... |
484 |
/* Configure control GPIOs if available. */ |
e99c2e5d6 hwmon: (gpio-fan)... |
485 |
if (fan_data->gpios && fan_data->num_gpios > 0) { |
b5482f7e6 hwmon: (gpio-fan)... |
486 |
if (!fan_data->speed || fan_data->num_speed <= 1) |
c81cc5a4c hwmon: (gpio-fan)... |
487 |
return -EINVAL; |
b5482f7e6 hwmon: (gpio-fan)... |
488 |
err = fan_ctrl_init(fan_data); |
d6fe1360f hwmon: add generi... |
489 |
if (err) |
c81cc5a4c hwmon: (gpio-fan)... |
490 |
return err; |
b9bb92e1d hwmon: (gpio-fan)... |
491 492 493 |
err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data); if (err) return err; |
d6fe1360f hwmon: add generi... |
494 |
} |
d6fe1360f hwmon: add generi... |
495 |
/* Make this driver part of hwmon class. */ |
49153b092 hwmon: (gpio-fan)... |
496 |
fan_data->hwmon_dev = |
f9013c167 hwmon: (gpio-fan)... |
497 |
devm_hwmon_device_register_with_groups(dev, |
49153b092 hwmon: (gpio-fan)... |
498 499 |
"gpio_fan", fan_data, gpio_fan_groups); |
7258a1253 hwmon: (gpio-fan)... |
500 501 |
if (IS_ERR(fan_data->hwmon_dev)) return PTR_ERR(fan_data->hwmon_dev); |
a9b4c8afc hwmon: (gpio-fan)... |
502 |
|
f2173fa22 hwmon: (gpio-fan)... |
503 504 505 506 507 508 |
/* Configure alarm GPIO if available. */ if (fan_data->alarm_gpio) { err = fan_alarm_init(fan_data); if (err) return err; } |
e76ea2614 hwmon: (gpio-fan)... |
509 |
/* Optional cooling device register for Device tree platforms */ |
953478455 hwmon: (gpio-fan)... |
510 511 |
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np, "gpio-fan", fan_data, &gpio_fan_cool_ops); |
d6fe1360f hwmon: add generi... |
512 |
|
f9013c167 hwmon: (gpio-fan)... |
513 514 |
dev_info(dev, "GPIO fan initialized "); |
d6fe1360f hwmon: add generi... |
515 516 |
return 0; |
d6fe1360f hwmon: add generi... |
517 |
} |
953478455 hwmon: (gpio-fan)... |
518 |
static void gpio_fan_shutdown(struct platform_device *pdev) |
b95579cd8 hwmon: (gpio-fan)... |
519 |
{ |
b5cf88e46 (gpio-fan): Add t... |
520 |
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); |
e99c2e5d6 hwmon: (gpio-fan)... |
521 |
if (fan_data->gpios) |
b95579cd8 hwmon: (gpio-fan)... |
522 523 |
set_fan_speed(fan_data, 0); } |
6d20a6c06 hwmon: (gpio-fan)... |
524 525 |
#ifdef CONFIG_PM_SLEEP static int gpio_fan_suspend(struct device *dev) |
d6fe1360f hwmon: add generi... |
526 |
{ |
6d20a6c06 hwmon: (gpio-fan)... |
527 |
struct gpio_fan_data *fan_data = dev_get_drvdata(dev); |
d6fe1360f hwmon: add generi... |
528 |
|
e99c2e5d6 hwmon: (gpio-fan)... |
529 |
if (fan_data->gpios) { |
d6fe1360f hwmon: add generi... |
530 531 532 533 534 535 |
fan_data->resume_speed = fan_data->speed_index; set_fan_speed(fan_data, 0); } return 0; } |
6d20a6c06 hwmon: (gpio-fan)... |
536 |
static int gpio_fan_resume(struct device *dev) |
d6fe1360f hwmon: add generi... |
537 |
{ |
6d20a6c06 hwmon: (gpio-fan)... |
538 |
struct gpio_fan_data *fan_data = dev_get_drvdata(dev); |
d6fe1360f hwmon: add generi... |
539 |
|
e99c2e5d6 hwmon: (gpio-fan)... |
540 |
if (fan_data->gpios) |
d6fe1360f hwmon: add generi... |
541 542 543 544 |
set_fan_speed(fan_data, fan_data->resume_speed); return 0; } |
6d20a6c06 hwmon: (gpio-fan)... |
545 546 |
static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); |
24f9c539b hwmon: Fix 'Macro... |
547 |
#define GPIO_FAN_PM (&gpio_fan_pm) |
d6fe1360f hwmon: add generi... |
548 |
#else |
6d20a6c06 hwmon: (gpio-fan)... |
549 |
#define GPIO_FAN_PM NULL |
d6fe1360f hwmon: add generi... |
550 551 552 553 |
#endif static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, |
b95579cd8 hwmon: (gpio-fan)... |
554 |
.shutdown = gpio_fan_shutdown, |
d6fe1360f hwmon: add generi... |
555 556 |
.driver = { .name = "gpio-fan", |
6d20a6c06 hwmon: (gpio-fan)... |
557 |
.pm = GPIO_FAN_PM, |
55fb8b068 hwmon: Add device... |
558 |
.of_match_table = of_match_ptr(of_gpio_fan_match), |
d6fe1360f hwmon: add generi... |
559 560 |
}, }; |
25a236a5d hwmon: convert dr... |
561 |
module_platform_driver(gpio_fan_driver); |
d6fe1360f hwmon: add generi... |
562 563 564 565 566 |
MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>"); MODULE_DESCRIPTION("GPIO FAN driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:gpio-fan"); |