summaryrefslogtreecommitdiff
path: root/drivers/leds/leds-bcm6328.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds/leds-bcm6328.c')
-rw-r--r--drivers/leds/leds-bcm6328.c63
1 files changed, 37 insertions, 26 deletions
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c
index c7ea5c626331..1548259297c1 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);