Merge branch 'for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[linux-2.6-block.git] / drivers / leds / leds-bcm6328.c
index c7ea5c62633186294eff8046dba51c8865d06eab..1548259297c185e8cfefb4f6df7127b97755da2b 100644 (file)
 #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_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
+#define BCM6328_LED_MODE_O           0
 #define BCM6328_LED_MODE_FAST          1
 #define BCM6328_LED_MODE_BLINK         2
-#define BCM6328_LED_MODE_O           3
+#define BCM6328_LED_MODE_OFF           3
 #define BCM6328_LED_SHIFT(X)           ((X) << 1)
 
 /**
@@ -76,12 +76,20 @@ struct bcm6328_led {
 
 static void bcm6328_led_write(void __iomem *reg, unsigned long data)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        iowrite32be(data, reg);
+#else
+       writel(data, reg);
+#endif
 }
 
 static unsigned long bcm6328_led_read(void __iomem *reg)
 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
        return ioread32be(reg);
+#else
+       return readl(reg);
+#endif
 }
 
 /**
@@ -126,34 +134,45 @@ static void bcm6328_led_set(struct led_classdev *led_cdev,
        *(led->blink_leds) &= ~BIT(led->pin);
        if ((led->active_low && value == LED_OFF) ||
            (!led->active_low && value != LED_OFF))
-               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
-       else
                bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
+       else
+               bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
        spin_unlock_irqrestore(led->lock, flags);
 }
 
+static unsigned long bcm6328_blink_delay(unsigned long delay)
+{
+       unsigned long bcm6328_delay;
+
+       bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2;
+       bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS;
+       if (bcm6328_delay == 0)
+               bcm6328_delay = 1;
+
+       return bcm6328_delay;
+}
+
 static int bcm6328_blink_set(struct led_classdev *led_cdev,
                             unsigned long *delay_on, unsigned long *delay_off)
 {
        struct bcm6328_led *led =
                container_of(led_cdev, struct bcm6328_led, cdev);
        unsigned long delay, flags;
+       int rc;
 
        if (!*delay_on)
                *delay_on = BCM6328_LED_DEF_DELAY;
        if (!*delay_off)
                *delay_off = BCM6328_LED_DEF_DELAY;
 
-       if (*delay_on != *delay_off) {
+       delay = bcm6328_blink_delay(*delay_on);
+       if (delay != bcm6328_blink_delay(*delay_off)) {
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay_on != delay_off)\n");
                return -EINVAL;
        }
 
-       delay = *delay_on / BCM6328_LED_INTERVAL_MS;
-       if (delay == 0)
-               delay = 1;
-       else if (delay > BCM6328_LED_INTV_MASK) {
+       if (delay > BCM6328_LED_INTV_MASK) {
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay > %ums)\n",
                        BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
@@ -175,16 +194,15 @@ static int bcm6328_blink_set(struct led_classdev *led_cdev,
                bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
 
                bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
-
-               spin_unlock_irqrestore(led->lock, flags);
+               rc = 0;
        } else {
-               spin_unlock_irqrestore(led->lock, flags);
                dev_dbg(led_cdev->dev,
                        "fallback to soft blinking (delay already set)\n");
-               return -EINVAL;
+               rc = -EINVAL;
        }
+       spin_unlock_irqrestore(led->lock, flags);
 
-       return 0;
+       return rc;
 }
 
 static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
@@ -264,7 +282,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                       unsigned long *blink_leds, unsigned long *blink_delay)
 {
        struct bcm6328_led *led;
-       unsigned long flags;
        const char *state;
        int rc;
 
@@ -286,7 +303,6 @@ 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)) {
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
@@ -303,8 +319,8 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                        val = bcm6328_led_read(mode) >>
                              BCM6328_LED_SHIFT(shift % 16);
                        val &= BCM6328_LED_MODE_MASK;
-                       if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
-                           (!led->active_low && val == BCM6328_LED_MODE_OFF))
+                       if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
+                           (!led->active_low && val == BCM6328_LED_MODE_ON))
                                led->cdev.brightness = LED_FULL;
                        else
                                led->cdev.brightness = LED_OFF;
@@ -315,12 +331,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                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);
+       bcm6328_led_set(&led->cdev, led->cdev.brightness);
 
        led->cdev.brightness_set = bcm6328_led_set;
        led->cdev.blink_set = bcm6328_blink_set;
@@ -341,7 +352,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
        struct device_node *child;
        struct resource *mem_r;
        void __iomem *mem;
-       spinlock_t *lock;
+       spinlock_t *lock; /* memory lock */
        unsigned long val, *blink_leds, *blink_delay;
 
        mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);