Commit 55fb8b06813b190a9366fee396fac109638a9c9d
Committed by
Jason Cooper
1 parent
f37fbd36c5
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
hwmon: Add devicetree bindings to gpio-fan
Allow a gpio-fan to be defined in devicetree, see binding documentation for details. Signed-off-by: Jamie Lentin <jm@lentin.co.uk> Acked-by: Andrew Lunn <andrew@lunn.ch> Acked-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Showing 2 changed files with 145 additions and 0 deletions Side-by-side Diff
Documentation/devicetree/bindings/gpio/gpio-fan.txt
1 | +Bindings for fan connected to GPIO lines | |
2 | + | |
3 | +Required properties: | |
4 | +- compatible : "gpio-fan" | |
5 | +- gpios: Specifies the pins that map to bits in the control value, | |
6 | + ordered MSB-->LSB. | |
7 | +- gpio-fan,speed-map: A mapping of possible fan RPM speeds and the | |
8 | + control value that should be set to achieve them. This array | |
9 | + must have the RPM values in ascending order. | |
10 | + | |
11 | +Optional properties: | |
12 | +- alarm-gpios: This pin going active indicates something is wrong with | |
13 | + the fan, and a udev event will be fired. | |
14 | + | |
15 | +Examples: | |
16 | + | |
17 | + gpio_fan { | |
18 | + compatible = "gpio-fan"; | |
19 | + gpios = <&gpio1 14 1 | |
20 | + &gpio1 13 1>; | |
21 | + gpio-fan,speed-map = <0 0 | |
22 | + 3000 1 | |
23 | + 6000 2>; | |
24 | + alarm-gpios = <&gpio1 15 1>; | |
25 | + }; |
drivers/hwmon/gpio-fan.c
... | ... | @@ -31,6 +31,8 @@ |
31 | 31 | #include <linux/hwmon.h> |
32 | 32 | #include <linux/gpio.h> |
33 | 33 | #include <linux/gpio-fan.h> |
34 | +#include <linux/of_platform.h> | |
35 | +#include <linux/of_gpio.h> | |
34 | 36 | |
35 | 37 | struct gpio_fan_data { |
36 | 38 | struct platform_device *pdev; |
37 | 39 | |
38 | 40 | |
... | ... | @@ -400,14 +402,131 @@ |
400 | 402 | |
401 | 403 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
402 | 404 | |
405 | + | |
406 | +#ifdef CONFIG_OF_GPIO | |
407 | +/* | |
408 | + * Translate OpenFirmware node properties into platform_data | |
409 | + */ | |
410 | +static int gpio_fan_get_of_pdata(struct device *dev, | |
411 | + struct gpio_fan_platform_data *pdata) | |
412 | +{ | |
413 | + struct device_node *node; | |
414 | + struct gpio_fan_speed *speed; | |
415 | + unsigned *ctrl; | |
416 | + unsigned i; | |
417 | + u32 u; | |
418 | + struct property *prop; | |
419 | + const __be32 *p; | |
420 | + | |
421 | + node = dev->of_node; | |
422 | + | |
423 | + /* Fill GPIO pin array */ | |
424 | + pdata->num_ctrl = of_gpio_count(node); | |
425 | + if (!pdata->num_ctrl) { | |
426 | + dev_err(dev, "gpios DT property empty / missing"); | |
427 | + return -ENODEV; | |
428 | + } | |
429 | + ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned), | |
430 | + GFP_KERNEL); | |
431 | + if (!ctrl) | |
432 | + return -ENOMEM; | |
433 | + for (i = 0; i < pdata->num_ctrl; i++) { | |
434 | + int val; | |
435 | + | |
436 | + val = of_get_gpio(node, i); | |
437 | + if (val < 0) | |
438 | + return val; | |
439 | + ctrl[i] = val; | |
440 | + } | |
441 | + pdata->ctrl = ctrl; | |
442 | + | |
443 | + /* Get number of RPM/ctrl_val pairs in speed map */ | |
444 | + prop = of_find_property(node, "gpio-fan,speed-map", &i); | |
445 | + if (!prop) { | |
446 | + dev_err(dev, "gpio-fan,speed-map DT property missing"); | |
447 | + return -ENODEV; | |
448 | + } | |
449 | + i = i / sizeof(u32); | |
450 | + if (i == 0 || i & 1) { | |
451 | + dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries"); | |
452 | + return -ENODEV; | |
453 | + } | |
454 | + pdata->num_speed = i / 2; | |
455 | + | |
456 | + /* | |
457 | + * Populate speed map | |
458 | + * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...> | |
459 | + * this needs splitting into pairs to create gpio_fan_speed structs | |
460 | + */ | |
461 | + speed = devm_kzalloc(dev, | |
462 | + pdata->num_speed * sizeof(struct gpio_fan_speed), | |
463 | + GFP_KERNEL); | |
464 | + if (!speed) | |
465 | + return -ENOMEM; | |
466 | + p = NULL; | |
467 | + for (i = 0; i < pdata->num_speed; i++) { | |
468 | + p = of_prop_next_u32(prop, p, &u); | |
469 | + if (!p) | |
470 | + return -ENODEV; | |
471 | + speed[i].rpm = u; | |
472 | + p = of_prop_next_u32(prop, p, &u); | |
473 | + if (!p) | |
474 | + return -ENODEV; | |
475 | + speed[i].ctrl_val = u; | |
476 | + } | |
477 | + pdata->speed = speed; | |
478 | + | |
479 | + /* Alarm GPIO if one exists */ | |
480 | + if (of_gpio_named_count(node, "alarm-gpios")) { | |
481 | + struct gpio_fan_alarm *alarm; | |
482 | + int val; | |
483 | + enum of_gpio_flags flags; | |
484 | + | |
485 | + alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm), | |
486 | + GFP_KERNEL); | |
487 | + if (!alarm) | |
488 | + return -ENOMEM; | |
489 | + | |
490 | + val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags); | |
491 | + if (val < 0) | |
492 | + return val; | |
493 | + alarm->gpio = val; | |
494 | + alarm->active_low = flags & OF_GPIO_ACTIVE_LOW; | |
495 | + | |
496 | + pdata->alarm = alarm; | |
497 | + } | |
498 | + | |
499 | + return 0; | |
500 | +} | |
501 | + | |
502 | +static struct of_device_id of_gpio_fan_match[] __devinitdata = { | |
503 | + { .compatible = "gpio-fan", }, | |
504 | + {}, | |
505 | +}; | |
506 | +#endif /* CONFIG_OF_GPIO */ | |
507 | + | |
403 | 508 | static int __devinit gpio_fan_probe(struct platform_device *pdev) |
404 | 509 | { |
405 | 510 | int err; |
406 | 511 | struct gpio_fan_data *fan_data; |
407 | 512 | struct gpio_fan_platform_data *pdata = pdev->dev.platform_data; |
408 | 513 | |
514 | +#ifdef CONFIG_OF_GPIO | |
515 | + if (!pdata) { | |
516 | + pdata = devm_kzalloc(&pdev->dev, | |
517 | + sizeof(struct gpio_fan_platform_data), | |
518 | + GFP_KERNEL); | |
519 | + if (!pdata) | |
520 | + return -ENOMEM; | |
521 | + | |
522 | + err = gpio_fan_get_of_pdata(&pdev->dev, pdata); | |
523 | + if (err) | |
524 | + return err; | |
525 | + } | |
526 | +#else /* CONFIG_OF_GPIO */ | |
409 | 527 | if (!pdata) |
410 | 528 | return -EINVAL; |
529 | +#endif /* CONFIG_OF_GPIO */ | |
411 | 530 | |
412 | 531 | fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data), |
413 | 532 | GFP_KERNEL); |
... | ... | @@ -511,6 +630,7 @@ |
511 | 630 | .driver = { |
512 | 631 | .name = "gpio-fan", |
513 | 632 | .pm = GPIO_FAN_PM, |
633 | + .of_match_table = of_match_ptr(of_gpio_fan_match), | |
514 | 634 | }, |
515 | 635 | }; |
516 | 636 |