]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/leds/leds-ns2.c
Merge tag 'md-3.8' of git://neil.brown.name/md
[karo-tx-linux.git] / drivers / leds / leds-ns2.c
index d176ec83f5d9bd84b72aaf7e7797b36d5441353c..d978171c25b4da1b8bcfb6804e508b374549acdc 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/platform_data/leds-kirkwood-ns2.h>
+#include <linux/of_gpio.h>
 
 /*
  * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in
@@ -149,7 +150,7 @@ static ssize_t ns2_led_sata_store(struct device *dev,
        unsigned long enable;
        enum ns2_led_modes mode;
 
-       ret = strict_strtoul(buff, 10, &enable);
+       ret = kstrtoul(buff, 10, &enable);
        if (ret < 0)
                return ret;
 
@@ -184,36 +185,29 @@ static ssize_t ns2_led_sata_show(struct device *dev,
 
 static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
 
-static int __devinit
+static int
 create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
               const struct ns2_led *template)
 {
        int ret;
        enum ns2_led_modes mode;
 
-       ret = gpio_request(template->cmd, template->name);
-       if (ret == 0) {
-               ret = gpio_direction_output(template->cmd,
-                                           gpio_get_value(template->cmd));
-               if (ret)
-                       gpio_free(template->cmd);
-       }
+       ret = devm_gpio_request_one(&pdev->dev, template->cmd,
+                       GPIOF_DIR_OUT | gpio_get_value(template->cmd),
+                       template->name);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to setup command GPIO\n",
                        template->name);
+               return ret;
        }
 
-       ret = gpio_request(template->slow, template->name);
-       if (ret == 0) {
-               ret = gpio_direction_output(template->slow,
-                                           gpio_get_value(template->slow));
-               if (ret)
-                       gpio_free(template->slow);
-       }
+       ret = devm_gpio_request_one(&pdev->dev, template->slow,
+                       GPIOF_DIR_OUT | gpio_get_value(template->slow),
+                       template->name);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n",
                        template->name);
-               goto err_free_cmd;
+               return ret;
        }
 
        rwlock_init(&led_dat->rw_lock);
@@ -228,7 +222,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
 
        ret = ns2_led_get_mode(led_dat, &mode);
        if (ret < 0)
-               goto err_free_slow;
+               return ret;
 
        /* Set LED initial state. */
        led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
@@ -237,7 +231,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
 
        ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
        if (ret < 0)
-               goto err_free_slow;
+               return ret;
 
        ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
        if (ret < 0)
@@ -247,11 +241,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
 
 err_free_cdev:
        led_classdev_unregister(&led_dat->cdev);
-err_free_slow:
-       gpio_free(led_dat->slow);
-err_free_cmd:
-       gpio_free(led_dat->cmd);
-
        return ret;
 }
 
@@ -259,22 +248,90 @@ static void delete_ns2_led(struct ns2_led_data *led_dat)
 {
        device_remove_file(led_dat->cdev.dev, &dev_attr_sata);
        led_classdev_unregister(&led_dat->cdev);
-       gpio_free(led_dat->cmd);
-       gpio_free(led_dat->slow);
 }
 
-static int __devinit ns2_led_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF_GPIO
+/*
+ * Translate OpenFirmware node properties into platform_data.
+ */
+static int
+ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
+{
+       struct device_node *np = dev->of_node;
+       struct device_node *child;
+       struct ns2_led *leds;
+       int num_leds = 0;
+       int i = 0;
+
+       num_leds = of_get_child_count(np);
+       if (!num_leds)
+               return -ENODEV;
+
+       leds = devm_kzalloc(dev, num_leds * sizeof(struct ns2_led),
+                           GFP_KERNEL);
+       if (!leds)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               const char *string;
+               int ret;
+
+               ret = of_get_named_gpio(child, "cmd-gpio", 0);
+               if (ret < 0)
+                       return ret;
+               leds[i].cmd = ret;
+               ret = of_get_named_gpio(child, "slow-gpio", 0);
+               if (ret < 0)
+                       return ret;
+               leds[i].slow = ret;
+               ret = of_property_read_string(child, "label", &string);
+               leds[i].name = (ret == 0) ? string : child->name;
+               ret = of_property_read_string(child, "linux,default-trigger",
+                                             &string);
+               if (ret == 0)
+                       leds[i].default_trigger = string;
+
+               i++;
+       }
+
+       pdata->leds = leds;
+       pdata->num_leds = num_leds;
+
+       return 0;
+}
+
+static const struct of_device_id of_ns2_leds_match[] = {
+       { .compatible = "lacie,ns2-leds", },
+       {},
+};
+#endif /* CONFIG_OF_GPIO */
+
+static int ns2_led_probe(struct platform_device *pdev)
 {
        struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
        struct ns2_led_data *leds_data;
        int i;
        int ret;
 
+#ifdef CONFIG_OF_GPIO
+       if (!pdata) {
+               pdata = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct ns2_led_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               ret = ns2_leds_get_of_pdata(&pdev->dev, pdata);
+               if (ret)
+                       return ret;
+       }
+#else
        if (!pdata)
                return -EINVAL;
+#endif /* CONFIG_OF_GPIO */
 
        leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) *
-                           pdata->num_leds, GFP_KERNEL);
+                                pdata->num_leds, GFP_KERNEL);
        if (!leds_data)
                return -ENOMEM;
 
@@ -292,7 +349,7 @@ static int __devinit ns2_led_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit ns2_led_remove(struct platform_device *pdev)
+static int ns2_led_remove(struct platform_device *pdev)
 {
        int i;
        struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
@@ -310,10 +367,11 @@ static int __devexit ns2_led_remove(struct platform_device *pdev)
 
 static struct platform_driver ns2_led_driver = {
        .probe          = ns2_led_probe,
-       .remove         = __devexit_p(ns2_led_remove),
+       .remove         = ns2_led_remove,
        .driver         = {
-               .name   = "leds-ns2",
-               .owner  = THIS_MODULE,
+               .name           = "leds-ns2",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(of_ns2_leds_match),
        },
 };