leds-osk.c 3.9 KB

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