mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-08 14:23:19 +00:00
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>
This commit is contained in:
parent
f37fbd36c5
commit
55fb8b0681
25
Documentation/devicetree/bindings/gpio/gpio-fan.txt
Normal file
25
Documentation/devicetree/bindings/gpio/gpio-fan.txt
Normal file
@ -0,0 +1,25 @@
|
||||
Bindings for fan connected to GPIO lines
|
||||
|
||||
Required properties:
|
||||
- compatible : "gpio-fan"
|
||||
- gpios: Specifies the pins that map to bits in the control value,
|
||||
ordered MSB-->LSB.
|
||||
- gpio-fan,speed-map: A mapping of possible fan RPM speeds and the
|
||||
control value that should be set to achieve them. This array
|
||||
must have the RPM values in ascending order.
|
||||
|
||||
Optional properties:
|
||||
- alarm-gpios: This pin going active indicates something is wrong with
|
||||
the fan, and a udev event will be fired.
|
||||
|
||||
Examples:
|
||||
|
||||
gpio_fan {
|
||||
compatible = "gpio-fan";
|
||||
gpios = <&gpio1 14 1
|
||||
&gpio1 13 1>;
|
||||
gpio-fan,speed-map = <0 0
|
||||
3000 1
|
||||
6000 2>;
|
||||
alarm-gpios = <&gpio1 15 1>;
|
||||
};
|
@ -31,6 +31,8 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio-fan.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
struct gpio_fan_data {
|
||||
struct platform_device *pdev;
|
||||
@ -400,14 +402,131 @@ static ssize_t show_name(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
* Translate OpenFirmware node properties into platform_data
|
||||
*/
|
||||
static int gpio_fan_get_of_pdata(struct device *dev,
|
||||
struct gpio_fan_platform_data *pdata)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct gpio_fan_speed *speed;
|
||||
unsigned *ctrl;
|
||||
unsigned i;
|
||||
u32 u;
|
||||
struct property *prop;
|
||||
const __be32 *p;
|
||||
|
||||
node = dev->of_node;
|
||||
|
||||
/* Fill GPIO pin array */
|
||||
pdata->num_ctrl = of_gpio_count(node);
|
||||
if (!pdata->num_ctrl) {
|
||||
dev_err(dev, "gpios DT property empty / missing");
|
||||
return -ENODEV;
|
||||
}
|
||||
ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
|
||||
GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < pdata->num_ctrl; i++) {
|
||||
int val;
|
||||
|
||||
val = of_get_gpio(node, i);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ctrl[i] = val;
|
||||
}
|
||||
pdata->ctrl = ctrl;
|
||||
|
||||
/* Get number of RPM/ctrl_val pairs in speed map */
|
||||
prop = of_find_property(node, "gpio-fan,speed-map", &i);
|
||||
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;
|
||||
}
|
||||
pdata->num_speed = i / 2;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
speed = devm_kzalloc(dev,
|
||||
pdata->num_speed * sizeof(struct gpio_fan_speed),
|
||||
GFP_KERNEL);
|
||||
if (!speed)
|
||||
return -ENOMEM;
|
||||
p = NULL;
|
||||
for (i = 0; i < pdata->num_speed; i++) {
|
||||
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;
|
||||
}
|
||||
pdata->speed = speed;
|
||||
|
||||
/* Alarm GPIO if one exists */
|
||||
if (of_gpio_named_count(node, "alarm-gpios")) {
|
||||
struct gpio_fan_alarm *alarm;
|
||||
int val;
|
||||
enum of_gpio_flags flags;
|
||||
|
||||
alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
|
||||
GFP_KERNEL);
|
||||
if (!alarm)
|
||||
return -ENOMEM;
|
||||
|
||||
val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
|
||||
if (val < 0)
|
||||
return val;
|
||||
alarm->gpio = val;
|
||||
alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
|
||||
pdata->alarm = alarm;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id of_gpio_fan_match[] __devinitdata = {
|
||||
{ .compatible = "gpio-fan", },
|
||||
{},
|
||||
};
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
static int __devinit gpio_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct gpio_fan_data *fan_data;
|
||||
struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
if (!pdata) {
|
||||
pdata = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct gpio_fan_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
err = gpio_fan_get_of_pdata(&pdev->dev, pdata);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
#else /* CONFIG_OF_GPIO */
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
|
||||
GFP_KERNEL);
|
||||
@ -511,6 +630,7 @@ static struct platform_driver gpio_fan_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-fan",
|
||||
.pm = GPIO_FAN_PM,
|
||||
.of_match_table = of_match_ptr(of_gpio_fan_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user