]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/leds/leds-bcm6328.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / leds / leds-bcm6328.c
index 1793727bc9ae5f6c64467a68b4646b92e0963e1b..c7ea5c62633186294eff8046dba51c8865d06eab 100644 (file)
 #define BCM6328_SERIAL_LED_SHIFT_DIR   BIT(16)
 #define BCM6328_LED_SHIFT_TEST         BIT(30)
 #define BCM6328_LED_TEST               BIT(31)
+#define BCM6328_INIT_MASK              (BCM6328_SERIAL_LED_EN | \
+                                        BCM6328_SERIAL_LED_MUX  | \
+                                        BCM6328_SERIAL_LED_CLK_NPOL | \
+                                        BCM6328_SERIAL_LED_DATA_PPOL | \
+                                        BCM6328_SERIAL_LED_SHIFT_DIR)
 
 #define BCM6328_LED_MODE_MASK          3
 #define BCM6328_LED_MODE_OFF           0
@@ -281,11 +286,10 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                                                    "linux,default-trigger",
                                                    NULL);
 
+       spin_lock_irqsave(lock, flags);
        if (!of_property_read_string(nc, "default-state", &state)) {
-               spin_lock_irqsave(lock, flags);
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
-                       bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
                } else if (!strcmp(state, "keep")) {
                        void __iomem *mode;
                        unsigned long val, shift;
@@ -296,21 +300,28 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                        else
                                mode = mem + BCM6328_REG_MODE_LO;
 
-                       val = bcm6328_led_read(mode) >> (shift % 16);
+                       val = bcm6328_led_read(mode) >>
+                             BCM6328_LED_SHIFT(shift % 16);
                        val &= BCM6328_LED_MODE_MASK;
-                       if (val == BCM6328_LED_MODE_ON)
+                       if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
+                           (!led->active_low && val == BCM6328_LED_MODE_OFF))
                                led->cdev.brightness = LED_FULL;
-                       else {
+                       else
                                led->cdev.brightness = LED_OFF;
-                               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
-                       }
                } else {
                        led->cdev.brightness = LED_OFF;
-                       bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
                }
-               spin_unlock_irqrestore(lock, flags);
+       } else {
+               led->cdev.brightness = LED_OFF;
        }
 
+       if ((led->active_low && led->cdev.brightness == LED_FULL) ||
+           (!led->active_low && led->cdev.brightness == LED_OFF))
+               bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
+       else
+               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
+       spin_unlock_irqrestore(lock, flags);
+
        led->cdev.brightness_set = bcm6328_led_set;
        led->cdev.blink_set = bcm6328_blink_set;
 
@@ -360,9 +371,17 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
        bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
 
        val = bcm6328_led_read(mem + BCM6328_REG_INIT);
-       val &= ~BCM6328_SERIAL_LED_EN;
+       val &= ~(BCM6328_INIT_MASK);
        if (of_property_read_bool(np, "brcm,serial-leds"))
                val |= BCM6328_SERIAL_LED_EN;
+       if (of_property_read_bool(np, "brcm,serial-mux"))
+               val |= BCM6328_SERIAL_LED_MUX;
+       if (of_property_read_bool(np, "brcm,serial-clk-low"))
+               val |= BCM6328_SERIAL_LED_CLK_NPOL;
+       if (!of_property_read_bool(np, "brcm,serial-dat-low"))
+               val |= BCM6328_SERIAL_LED_DATA_PPOL;
+       if (!of_property_read_bool(np, "brcm,serial-shift-inv"))
+               val |= BCM6328_SERIAL_LED_SHIFT_DIR;
        bcm6328_led_write(mem + BCM6328_REG_INIT, val);
 
        for_each_available_child_of_node(np, child) {
@@ -373,7 +392,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
                        continue;
 
                if (reg >= BCM6328_LED_MAX_COUNT) {
-                       dev_err(dev, "invalid LED (>= %d)\n",
+                       dev_err(dev, "invalid LED (%u >= %d)\n", reg,
                                BCM6328_LED_MAX_COUNT);
                        continue;
                }
@@ -384,8 +403,10 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
                        rc = bcm6328_led(dev, child, reg, mem, lock,
                                         blink_leds, blink_delay);
 
-               if (rc < 0)
+               if (rc < 0) {
+                       of_node_put(child);
                        return rc;
+               }
        }
 
        return 0;