linux/arch/arm/mach-omap1/leds-osk.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-omap1/leds-osk.c
   3 *
   4 * LED driver for OSK, and optionally Mistral QVGA, boards
   5 */
   6#include <linux/init.h>
   7#include <linux/workqueue.h>
   8
   9#include <asm/hardware.h>
  10#include <asm/leds.h>
  11#include <asm/system.h>
  12
  13#include <asm/arch/gpio.h>
  14#include <asm/arch/tps65010.h>
  15
  16#include "leds.h"
  17
  18
  19#define LED_STATE_ENABLED       (1 << 0)
  20#define LED_STATE_CLAIMED       (1 << 1)
  21static u8 led_state;
  22
  23#define GREEN_LED               (1 << 0)        /* TPS65010 LED1 */
  24#define AMBER_LED               (1 << 1)        /* TPS65010 LED2 */
  25#define RED_LED                 (1 << 2)        /* TPS65010 GPIO2 */
  26#define TIMER_LED               (1 << 3)        /* Mistral board */
  27#define IDLE_LED                (1 << 4)        /* Mistral board */
  28static u8 hw_led_state;
  29
  30
  31/* TPS65010 leds are changed using i2c -- from a task context.
  32 * Using one of these for the "idle" LED would be impractical...
  33 */
  34#define TPS_LEDS        (GREEN_LED | RED_LED | AMBER_LED)
  35
  36static u8 tps_leds_change;
  37
  38static void tps_work(struct work_struct *unused)
  39{
  40        for (;;) {
  41                u8      leds;
  42
  43                local_irq_disable();
  44                leds = tps_leds_change;
  45                tps_leds_change = 0;
  46                local_irq_enable();
  47
  48                if (!leds)
  49                        break;
  50
  51                /* careful:  the set_led() value is on/off/blink */
  52                if (leds & GREEN_LED)
  53                        tps65010_set_led(LED1, !!(hw_led_state & GREEN_LED));
  54                if (leds & AMBER_LED)
  55                        tps65010_set_led(LED2, !!(hw_led_state & AMBER_LED));
  56
  57                /* the gpio led doesn't have that issue */
  58                if (leds & RED_LED)
  59                        tps65010_set_gpio_out_value(GPIO2,
  60                                        !(hw_led_state & RED_LED));
  61        }
  62}
  63
  64static DECLARE_WORK(work, tps_work);
  65
  66#ifdef  CONFIG_OMAP_OSK_MISTRAL
  67
  68/* For now, all system indicators require the Mistral board, since that
  69 * LED can be manipulated without a task context.  This LED is either red,
  70 * or green, but not both; it can't give the full "disco led" effect.
  71 */
  72
  73#define GPIO_LED_RED            3
  74#define GPIO_LED_GREEN          OMAP_MPUIO(4)
  75
  76static void mistral_setled(void)
  77{
  78        int     red = 0;
  79        int     green = 0;
  80
  81        if (hw_led_state & TIMER_LED)
  82                red = 1;
  83        else if (hw_led_state & IDLE_LED)
  84                green = 1;
  85        // else both sides are disabled
  86
  87        omap_set_gpio_dataout(GPIO_LED_GREEN, green);
  88        omap_set_gpio_dataout(GPIO_LED_RED, red);
  89}
  90
  91#endif
  92
  93void osk_leds_event(led_event_t evt)
  94{
  95        unsigned long   flags;
  96        u16             leds;
  97
  98        local_irq_save(flags);
  99
 100        if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
 101                goto done;
 102
 103        leds = hw_led_state;
 104        switch (evt) {
 105        case led_start:
 106                led_state |= LED_STATE_ENABLED;
 107                hw_led_state = 0;
 108                leds = ~0;
 109                break;
 110
 111        case led_halted:
 112        case led_stop:
 113                led_state &= ~LED_STATE_ENABLED;
 114                hw_led_state = 0;
 115                // NOTE:  work may still be pending!!
 116                break;
 117
 118        case led_claim:
 119                led_state |= LED_STATE_CLAIMED;
 120                hw_led_state = 0;
 121                leds = ~0;
 122                break;
 123
 124        case led_release:
 125                led_state &= ~LED_STATE_CLAIMED;
 126                hw_led_state = 0;
 127                break;
 128
 129#ifdef  CONFIG_OMAP_OSK_MISTRAL
 130
 131        case led_timer:
 132                hw_led_state ^= TIMER_LED;
 133                mistral_setled();
 134                break;
 135
 136        case led_idle_start:    /* idle == off */
 137                hw_led_state &= ~IDLE_LED;
 138                mistral_setled();
 139                break;
 140
 141        case led_idle_end:
 142                hw_led_state |= IDLE_LED;
 143                mistral_setled();
 144                break;
 145
 146#endif  /* CONFIG_OMAP_OSK_MISTRAL */
 147
 148        /* "green" == tps LED1 (leftmost, normally power-good)
 149         * works only with DC adapter, not on battery power!
 150         */
 151        case led_green_on:
 152                if (led_state & LED_STATE_CLAIMED)
 153                        hw_led_state |= GREEN_LED;
 154                break;
 155        case led_green_off:
 156                if (led_state & LED_STATE_CLAIMED)
 157                        hw_led_state &= ~GREEN_LED;
 158                break;
 159
 160        /* "amber" == tps LED2 (middle) */
 161        case led_amber_on:
 162                if (led_state & LED_STATE_CLAIMED)
 163                        hw_led_state |= AMBER_LED;
 164                break;
 165        case led_amber_off:
 166                if (led_state & LED_STATE_CLAIMED)
 167                        hw_led_state &= ~AMBER_LED;
 168                break;
 169
 170        /* "red" == LED on tps gpio3 (rightmost) */
 171        case led_red_on:
 172                if (led_state & LED_STATE_CLAIMED)
 173                        hw_led_state |= RED_LED;
 174                break;
 175        case led_red_off:
 176                if (led_state & LED_STATE_CLAIMED)
 177                        hw_led_state &= ~RED_LED;
 178                break;
 179
 180        default:
 181                break;
 182        }
 183
 184        leds ^= hw_led_state;
 185        leds &= TPS_LEDS;
 186        if (leds && (led_state & LED_STATE_CLAIMED)) {
 187                tps_leds_change |= leds;
 188                schedule_work(&work);
 189        }
 190
 191done:
 192        local_irq_restore(flags);
 193}
 194