* Copyright (c) 2008-2009 PIKA Technologies
  *   Sean MacLennan <smaclennan@pikatech.com>
  */
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/kthread.h>
+#include <linux/leds.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/export.h>
 
 
 static LIST_HEAD(dtm_shutdown_list);
 static void __iomem *dtm_fpga;
-static unsigned green_led, red_led;
-
 
 struct dtm_shutdown {
        struct list_head list;
        void *arg;
 };
 
-
 int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg)
 {
        struct dtm_shutdown *shutdown;
        return -EINVAL;
 }
 
+#define WARP_GREEN_LED 0
+#define WARP_RED_LED   1
+
+static struct gpio_led warp_gpio_led_pins[] = {
+       [WARP_GREEN_LED] = {
+               .name           = "green",
+               .default_state  = LEDS_DEFSTATE_KEEP,
+               .gpiod          = NULL, /* to be filled by pika_setup_leds() */
+       },
+       [WARP_RED_LED] = {
+               .name           = "red",
+               .default_state  = LEDS_DEFSTATE_KEEP,
+               .gpiod          = NULL, /* to be filled by pika_setup_leds() */
+       },
+};
+
+static struct gpio_led_platform_data warp_gpio_led_data = {
+       .leds           = warp_gpio_led_pins,
+       .num_leds       = ARRAY_SIZE(warp_gpio_led_pins),
+};
+
+static struct platform_device warp_gpio_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &warp_gpio_led_data,
+       },
+};
+
 static irqreturn_t temp_isr(int irq, void *context)
 {
        struct dtm_shutdown *shutdown;
 
        local_irq_disable();
 
-       gpio_set_value(green_led, 0);
+       gpiod_set_value(warp_gpio_led_pins[WARP_GREEN_LED].gpiod, 0);
 
        /* Run through the shutdown list. */
        list_for_each_entry(shutdown, &dtm_shutdown_list, list)
                        out_be32(dtm_fpga + 0x14, reset);
                }
 
-               gpio_set_value(red_led, value);
+               gpiod_set_value(warp_gpio_led_pins[WARP_RED_LED].gpiod, value);
                value ^= 1;
                mdelay(500);
        }
        return IRQ_HANDLED;
 }
 
+/*
+ * Because green and red power LEDs are normally driven by leds-gpio driver,
+ * but in case of critical temperature shutdown we want to drive them
+ * ourselves, we acquire both and then create leds-gpio platform device
+ * ourselves, instead of doing it through device tree. This way we can still
+ * keep access to the gpios and use them when needed.
+ */
 static int pika_setup_leds(void)
 {
        struct device_node *np, *child;
+       struct gpio_desc *gpio;
+       struct gpio_led *led;
+       int led_count = 0;
+       int error;
+       int i;
 
-       np = of_find_compatible_node(NULL, NULL, "gpio-leds");
+       np = of_find_compatible_node(NULL, NULL, "warp-power-leds");
        if (!np) {
                printk(KERN_ERR __FILE__ ": Unable to find leds\n");
                return -ENOENT;
        }
 
-       for_each_child_of_node(np, child)
-               if (of_node_name_eq(child, "green"))
-                       green_led = of_get_gpio(child, 0);
-               else if (of_node_name_eq(child, "red"))
-                       red_led = of_get_gpio(child, 0);
+       for_each_child_of_node(np, child) {
+               for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) {
+                       led = &warp_gpio_led_pins[i];
+
+                       if (!of_node_name_eq(child, led->name))
+                               continue;
+
+                       if (led->gpiod) {
+                               printk(KERN_ERR __FILE__ ": %s led has already been defined\n",
+                                      led->name);
+                               continue;
+                       }
+
+                       gpio = fwnode_gpiod_get_index(of_fwnode_handle(child),
+                                                     NULL, 0, GPIOD_ASIS,
+                                                     led->name);
+                       error = PTR_ERR_OR_ZERO(gpio);
+                       if (error) {
+                               printk(KERN_ERR __FILE__ ": Failed to get %s led gpio: %d\n",
+                                      led->name, error);
+                               of_node_put(child);
+                               goto err_cleanup_pins;
+                       }
+
+                       led->gpiod = gpio;
+                       led_count++;
+               }
+       }
 
        of_node_put(np);
 
+       /* Skip device registration if no leds have been defined */
+       if (led_count) {
+               error = platform_device_register(&warp_gpio_leds);
+               if (error) {
+                       printk(KERN_ERR __FILE__ ": Unable to add leds-gpio: %d\n",
+                              error);
+                       goto err_cleanup_pins;
+               }
+       }
+
        return 0;
+
+err_cleanup_pins:
+       for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) {
+               led = &warp_gpio_led_pins[i];
+               gpiod_put(led->gpiod);
+               led->gpiod = NULL;
+       }
+       return error;
 }
 
 static void pika_setup_critical_temp(struct device_node *np,