led.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * led.c
  3. *
  4. * Copyright (C) 2019 Sylvain Munaut
  5. * All rights reserved.
  6. *
  7. * LGPL v3+, see LICENSE.lgpl3
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program; if not, write to the Free Software Foundation,
  21. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. */
  23. #include <stdbool.h>
  24. #include <stdint.h>
  25. #include "config.h"
  26. #include "led.h"
  27. struct ledda_ip {
  28. uint32_t _rsvd0;
  29. uint32_t pwrr; /* 0001 LEDDPWRR - Pulse Width Register Red */
  30. uint32_t pwrg; /* 0010 LEDDPWRG - Pulse Width Register Green */
  31. uint32_t pwrb; /* 0011 LEDDPWRB - Pulse Width Register Blue */
  32. uint32_t _rsvd1;
  33. uint32_t bcrr; /* 0101 LEDDBCRR - Breathe Control Rise Register */
  34. uint32_t bcfr; /* 0101 LEDDBCFR - Breathe Control Fall Register */
  35. uint32_t _rsvd2;
  36. uint32_t cr0; /* 1000 LEDDCR0 - Control Register 0 */
  37. uint32_t br; /* 1001 LEDDBR - Pre-scale Register */
  38. uint32_t onr; /* 1010 LEDONR - ON Time Register */
  39. uint32_t ofr; /* 1011 LEDOFR - OFF Time Register */
  40. } __attribute__((packed,aligned(4)));
  41. #define LEDDA_IP_CR0_LEDDEN (1 << 7)
  42. #define LEDDA_IP_CR0_FR250 (1 << 6)
  43. #define LEDDA_IP_CR0_OUTPOL (1 << 5)
  44. #define LEDDA_IP_CR0_OUTSKEW (1 << 4)
  45. #define LEDDA_IP_CR0_QUICK_STOP (1 << 3)
  46. #define LEDDA_IP_CR0_PWM_LINEAR (0 << 2)
  47. #define LEDDA_IP_CR0_PWM_LFSR (1 << 2)
  48. #define LEDDA_IP_CR0_SCALE_MSB(x) (((x) >> 8) & 3)
  49. #define LEDDA_IP_BR_SCALE_LSB(x) ((x) & 0xff)
  50. #define LEDDA_IP_ONOFF_TIME_MS(x) (((x) >> 5) & 0xff) /* 32ms interval up to 8s */
  51. #define LEDDA_IP_BREATHE_ENABLE (1 << 7)
  52. #define LEDDA_IP_BREATHE_MODULATE (1 << 5)
  53. #define LEDDA_IP_BREATHE_TIME_MS(x) (((x) >> 7) & 0x0f) /* 128ms interval up to 2s */
  54. struct led {
  55. uint32_t csr;
  56. uint32_t _rsvd[15];
  57. struct ledda_ip ip;
  58. } __attribute__((packed,aligned(4)));
  59. #define LED_CSR_LEDDEXE (1 << 1)
  60. #define LED_CSR_RGBLEDEN (1 << 2)
  61. #define LED_CSR_CURREN (1 << 3)
  62. static volatile struct led * const led_regs = (void*)(LED_BASE);
  63. static const uint32_t led_cr0_base =
  64. LEDDA_IP_CR0_FR250 |
  65. LEDDA_IP_CR0_OUTSKEW |
  66. LEDDA_IP_CR0_QUICK_STOP |
  67. LEDDA_IP_CR0_PWM_LFSR |
  68. LEDDA_IP_CR0_SCALE_MSB(480);
  69. void
  70. led_init(void)
  71. {
  72. led_regs->ip.pwrr = 0;
  73. led_regs->ip.pwrg = 0;
  74. led_regs->ip.pwrb = 0;
  75. led_regs->ip.bcrr = 0;
  76. led_regs->ip.bcfr = 0;
  77. led_regs->ip.onr = 0;
  78. led_regs->ip.ofr = 0;
  79. led_regs->ip.br = LEDDA_IP_BR_SCALE_LSB(480);
  80. led_regs->ip.cr0 = led_cr0_base;
  81. led_regs->csr = LED_CSR_LEDDEXE | LED_CSR_RGBLEDEN | LED_CSR_CURREN;
  82. }
  83. void
  84. led_color(uint8_t r, uint8_t g, uint8_t b)
  85. {
  86. #if defined(BOARD_ICEBREAKER)
  87. /* // iCEBreaker v1.0b tnt
  88. led_regs->ip.pwrr = r;
  89. led_regs->ip.pwrg = b;
  90. led_regs->ip.pwrb = g;
  91. */
  92. // iCEBreaker v1.0c+
  93. led_regs->ip.pwrr = b;
  94. led_regs->ip.pwrg = g;
  95. led_regs->ip.pwrb = r;
  96. #elif defined(BOARD_BITSY_V0)
  97. // iCEBreaker bitsy v0 (RGB led 'hacked on')
  98. led_regs->ip.pwrr = g;
  99. led_regs->ip.pwrg = r;
  100. led_regs->ip.pwrb = b;
  101. #elif defined(BOARD_BITSY_V1)
  102. // iCEBreaker bitsy v1 (RGB led 'hacked on')
  103. led_regs->ip.pwrr = r;
  104. led_regs->ip.pwrg = g;
  105. led_regs->ip.pwrb = b;
  106. #elif defined(BOARD_ICE1USB)
  107. // icE1usb
  108. led_regs->ip.pwrr = b;
  109. led_regs->ip.pwrg = g;
  110. led_regs->ip.pwrb = r;
  111. #elif defined(BOARD_ICEPICK)
  112. // iCEpick with UHD-1110 LED
  113. led_regs->ip.pwrr = b;
  114. led_regs->ip.pwrg = g;
  115. led_regs->ip.pwrb = r;
  116. /* // iCEpick with alternate LED
  117. led_regs->ip.pwrr = g;
  118. led_regs->ip.pwrg = r;
  119. led_regs->ip.pwrb = b;
  120. */
  121. #elif defined(BOARD_E1TRACER)
  122. // E1 tracer
  123. led_regs->ip.pwrr = b;
  124. led_regs->ip.pwrg = g;
  125. led_regs->ip.pwrb = r;
  126. #else
  127. // Default / Unknown
  128. led_regs->ip.pwrr = r;
  129. led_regs->ip.pwrg = g;
  130. led_regs->ip.pwrb = b;
  131. #endif
  132. }
  133. void
  134. led_state(bool on)
  135. {
  136. if (on)
  137. led_regs->ip.cr0 = led_cr0_base | LEDDA_IP_CR0_LEDDEN;
  138. else
  139. led_regs->ip.cr0 = led_cr0_base;
  140. }
  141. void
  142. led_blink(bool enabled, int on_time_ms, int off_time_ms)
  143. {
  144. /* Disable EXE before doing any change */
  145. led_regs->csr = LED_CSR_RGBLEDEN | LED_CSR_CURREN;
  146. /* Load new config */
  147. if (enabled) {
  148. led_regs->ip.onr = LEDDA_IP_ONOFF_TIME_MS(on_time_ms);
  149. led_regs->ip.ofr = LEDDA_IP_ONOFF_TIME_MS(off_time_ms);
  150. } else {
  151. led_regs->ip.onr = 0;
  152. led_regs->ip.ofr = 0;
  153. }
  154. /* Re-enable execution */
  155. led_regs->csr = LED_CSR_LEDDEXE | LED_CSR_RGBLEDEN | LED_CSR_CURREN;
  156. }
  157. void
  158. led_breathe(bool enabled, int rise_time_ms, int fall_time_ms)
  159. {
  160. if (enabled) {
  161. led_regs->ip.bcrr = LEDDA_IP_BREATHE_ENABLE |
  162. LEDDA_IP_BREATHE_MODULATE |
  163. LEDDA_IP_BREATHE_TIME_MS(rise_time_ms);
  164. led_regs->ip.bcfr = LEDDA_IP_BREATHE_ENABLE |
  165. LEDDA_IP_BREATHE_MODULATE |
  166. LEDDA_IP_BREATHE_TIME_MS(fall_time_ms);
  167. } else {
  168. led_regs->ip.bcrr = 0;
  169. led_regs->ip.bcfr = 0;
  170. }
  171. }