|
@@ -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),
|
|
|
},
|
|
|
};
|
|
|
|