mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08: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/hwmon.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/gpio-fan.h>
|
#include <linux/gpio-fan.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
struct gpio_fan_data {
|
struct gpio_fan_data {
|
||||||
struct platform_device *pdev;
|
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);
|
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)
|
static int __devinit gpio_fan_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct gpio_fan_data *fan_data;
|
struct gpio_fan_data *fan_data;
|
||||||
struct gpio_fan_platform_data *pdata = pdev->dev.platform_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)
|
if (!pdata)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
#endif /* CONFIG_OF_GPIO */
|
||||||
|
|
||||||
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
|
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@ -511,6 +630,7 @@ static struct platform_driver gpio_fan_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "gpio-fan",
|
.name = "gpio-fan",
|
||||||
.pm = GPIO_FAN_PM,
|
.pm = GPIO_FAN_PM,
|
||||||
|
.of_match_table = of_match_ptr(of_gpio_fan_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user