|
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;
|
@@ -400,14 +402,131 @@ static ssize_t show_name(struct device *dev,
|
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 @@ static struct platform_driver gpio_fan_driver = {
|
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 |
|
|
0 commit comments