1 /* This file is part of the coreboot project. */
2 /* SPDX-License-Identifier: GPL-2.0-only */
5 * This is a driver for the Whirlwind LED ring, which is equipped with two LED
6 * microcontrollers TI LP55231 (http://www.ti.com/product/lp55231), each of
7 * them driving three multicolor LEDs.
9 * The only connection between the ring and the main board is an i2c bus.
11 * This driver imitates a depthcharge display device. On initialization the
12 * driver sets up the controllers to prepare them to accept programs to run.
14 * When a certain vboot state needs to be indicated, the program for that
15 * state is loaded into the controllers, resulting in the state appropriate
19 #include "drivers/i2c/ww_ring/ww_ring_programs.h"
21 /****************************************************************
22 * LED ring program definitions for different patterns.
24 * Comments below are real lp55231 source code, they are compiled using
25 * lasm.exe, the TI tool available from their Web site (search for lp55231)
26 * and running only on Windows :P.
28 * Different hex dumps are results of tweaking the source code parameters to
29 * achieve desirable LED ring behavior. It is possible to use just one code
30 * dump and replace certain values in the body to achieve different behaviour
31 * with the same basic dump, but keeping track of location to tweak with every
32 * code change would be quite tedious.
36 * Solid LED display, the arguments of the set_pwm commands set intensity and
37 * color of the display:
39 row_red: dw 0000000000000001b
40 row_green: dw 0000000000000010b
41 row_blue: dw 0000000000000100b
49 mux_map_addr row_green
59 /* RGB set to 000000, resulting in all LEDs off. */
60 static const uint8_t solid_000000_text
[] = {
61 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x9F, 0x80,
62 0x40, 0, 0xC0, 0x00, 0x9F, 0x81, 0x40, 0,
63 0xC0, 0x00, 0x9F, 0x82, 0x40, 0, 0xC0, 0x00
66 /* Rgb set to 128, resulting in a brightish white color. */
67 static const uint8_t solid_808080_text
[] = {
68 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x9F, 0x80,
69 0x40, 128, 0xC0, 0x00, 0x9F, 0x81, 0x40, 128,
70 0xC0, 0x00, 0x9F, 0x82, 0x40, 128, 0xC0, 0x00
73 static const TiLp55231Program solid_808080_program
= {
75 sizeof(solid_808080_text
),
80 static const TiLp55231Program solid_000000_program
= {
82 sizeof(solid_000000_text
),
88 * Blinking patterns are trickier then solid ones.
90 * The three internal engines seem to be competing for resources and get out
91 * of sync in seconds if left running asynchronously.
93 * When solid patterns are deployed with instanteneous color intensity
94 * changes, all three LEDs can be controlled by one engine in sequential
95 * accesses. But the controllers still neeed to be synchronized.
97 * The maximum timer duration of lp55231 is .48 seconds. To achieve longer
98 * blinking intervals the loops delays are deployed. Only the first controller
99 * intervals need to be changed, as the second one is in lockstep with the
102 * The time granularity is set at .1 second (see commands 'wait 0.1' in the
103 * code), and then the loop counters can be set up to 63 (registers rb and rc),
104 * which allows to generate intervals up to 6.3 seconds in .1 second
109 row_red: dw 0000000000000001b
110 row_green: dw 0000000000000010b
111 row_blue: dw 0000000000000100b
114 ld ra, 2 # LED on duration
115 ld rb, 2 # LED off duration
118 ld rc, 1 ; red intensity
120 mux_map_addr row_green
121 ld rc, 50 ; green intensity
123 mux_map_addr row_blue
124 ld rc, 155 ; blue intensity
130 mux_map_addr row_green
143 static const uint8_t blink_wipeout1_text
[] = {
144 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x90, 0x02,
145 0x94, 0x02, 0x9f, 0x80, 0x98, 1, 0x84, 0x62,
146 0x9f, 0x81, 0x98, 50, 0x84, 0x62, 0x9f, 0x82,
147 0x98, 155, 0x84, 0x62, 0x4c, 0x00, 0x86, 0x2c,
148 0x40, 0x00, 0x9f, 0x81, 0x40, 0x00, 0x9f, 0x80,
149 0x40, 0x00, 0x4c, 0x00, 0x86, 0x49, 0xa0, 0x03,
150 0xc0, 0x00, 0xc0, 0x00, 0x00,
153 static const TiLp55231Program blink_wipeout1_program
= {
155 sizeof(blink_wipeout1_text
),
160 static const uint8_t blink_recovery1_text
[] = {
161 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x90, 0x02,
162 0x94, 0x02, 0x9f, 0x80, 0x98, 255, 0x84, 0x62,
163 0x9f, 0x81, 0x98, 100, 0x84, 0x62, 0x9f, 0x82,
164 0x98, 10, 0x84, 0x62, 0x4c, 0x00, 0x86, 0x2c,
165 0x40, 0x00, 0x9f, 0x81, 0x40, 0x00, 0x9f, 0x80,
166 0x40, 0x00, 0x4c, 0x00, 0x86, 0x49, 0xa0, 0x03,
167 0xc0, 0x00, 0xc0, 0x00, 0x00,
169 static const TiLp55231Program blink_recovery1_program
= {
170 blink_recovery1_text
,
171 sizeof(blink_recovery1_text
),
179 row_red: dw 0000000000000001b
180 row_green: dw 0000000000000010b
181 row_blue: dw 0000000000000100b
189 mux_map_addr row_green
195 mux_map_addr row_blue
202 static const uint8_t fade_in1_text
[] = {
203 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x9f, 0x80,
204 0x40, 0x01, 0xe0, 0x0c, 0xc0, 0x00, 0x9f, 0x81,
205 0x40, 0x00, 0xe0, 0x80, 0x46, 0x32, 0xc0, 0x00,
206 0x9f, 0x82, 0x40, 0x00, 0xe0, 0x80, 0x34, 0x9B,
209 static const TiLp55231Program fade_in1_program
= {
211 sizeof(fade_in1_text
),
216 const WwRingStateProg wwr_state_programs
[] = {
218 * for test purposes the blank screen program is set to blinking, will
221 {WWR_ALL_OFF
, {&solid_000000_program
} },
222 {WWR_RECOVERY_PUSHED
, {&solid_808080_program
} },
223 {WWR_WIPEOUT_REQUEST
, {&blink_wipeout1_program
} },
224 {WWR_RECOVERY_REQUEST
, {&blink_recovery1_program
} },
225 {WWR_NORMAL_BOOT
, {&fade_in1_program
} },
226 {}, /* Empty record to mark the end of the table. */