diff options
Diffstat (limited to 'drivers/leds/leds-bcm6328.c')
-rw-r--r-- | drivers/leds/leds-bcm6328.c | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index c7ea5c626..154825929 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -42,16 +42,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_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_ON 0 #define BCM6328_LED_MODE_FAST 1 #define BCM6328_LED_MODE_BLINK 2 -#define BCM6328_LED_MODE_ON 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); |