diff options
| author | Olof Johansson <olof@lixom.net> | 2012-09-22 16:24:09 -0400 |
|---|---|---|
| committer | Olof Johansson <olof@lixom.net> | 2012-09-22 16:24:09 -0400 |
| commit | d6a93ceb3f523be3a00b5ee8c6380653c764927b (patch) | |
| tree | 9699d60dc3b21e9fc7782af93aefdd334cfc46b7 /drivers/hwmon | |
| parent | fb6f3d69af95006c0518be7fbcd73bff555c837d (diff) | |
| parent | 1b90e06b14291ce3c252bd10e4ce981a08152e2e (diff) | |
Merge branch 'kirkwood/dt' of git://git.infradead.org/users/jcooper/linux into late/kirkwood
From Jason Cooper:
New bindings:
- iconnect nand and keys
- mv_cesa
- gpio-fan
* 'kirkwood/dt' of git://git.infradead.org/users/jcooper/linux:
ARM: kirkwood: Use devicetree to define DNS-32[05] fan
hwmon: Add devicetree bindings to gpio-fan
Crypto: CESA: Add support for DT based instantiation.
ARM: Kirkwood: Describe iconnect nand in DT.
ARM: Kirkwood: Describe iconnect keys in DT.
Diffstat (limited to 'drivers/hwmon')
| -rw-r--r-- | drivers/hwmon/gpio-fan.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 2f4b01bda87c..36509ae32083 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | #include <linux/hwmon.h> | 31 | #include <linux/hwmon.h> |
| 32 | #include <linux/gpio.h> | 32 | #include <linux/gpio.h> |
| 33 | #include <linux/gpio-fan.h> | 33 | #include <linux/gpio-fan.h> |
| 34 | #include <linux/of_platform.h> | ||
| 35 | #include <linux/of_gpio.h> | ||
| 34 | 36 | ||
| 35 | struct gpio_fan_data { | 37 | struct gpio_fan_data { |
| 36 | struct platform_device *pdev; | 38 | struct platform_device *pdev; |
| @@ -400,14 +402,131 @@ static ssize_t show_name(struct device *dev, | |||
| 400 | 402 | ||
| 401 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 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 | static int __devinit gpio_fan_probe(struct platform_device *pdev) | 508 | static int __devinit gpio_fan_probe(struct platform_device *pdev) |
| 404 | { | 509 | { |
| 405 | int err; | 510 | int err; |
| 406 | struct gpio_fan_data *fan_data; | 511 | struct gpio_fan_data *fan_data; |
| 407 | struct gpio_fan_platform_data *pdata = pdev->dev.platform_data; | 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 | if (!pdata) | 527 | if (!pdata) |
| 410 | return -EINVAL; | 528 | return -EINVAL; |
| 529 | #endif /* CONFIG_OF_GPIO */ | ||
| 411 | 530 | ||
| 412 | fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data), | 531 | fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data), |
| 413 | GFP_KERNEL); | 532 | GFP_KERNEL); |
| @@ -511,6 +630,7 @@ static struct platform_driver gpio_fan_driver = { | |||
| 511 | .driver = { | 630 | .driver = { |
| 512 | .name = "gpio-fan", | 631 | .name = "gpio-fan", |
| 513 | .pm = GPIO_FAN_PM, | 632 | .pm = GPIO_FAN_PM, |
| 633 | .of_match_table = of_match_ptr(of_gpio_fan_match), | ||
| 514 | }, | 634 | }, |
| 515 | }; | 635 | }; |
| 516 | 636 | ||
