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