2020 February 29 Breaking Changes Update (#8064)
[jackhill/qmk/firmware.git] / keyboards / infinity60 / led_controller.c
CommitLineData
b73c935d 1/*
7a445d91 2Copyright 2016 flabbergast <s3+flabbergast@sdfeu.org>
dbd4ce19 3Copyright 2017 jpetermans <tibcmhhm@gmail.com>
b73c935d 4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/*
20 * LED controller code
2c5b5519 21 * IS31FL3731C matrix LED driver from ISSI
b73c935d 22 * datasheet: http://www.issi.com/WW/pdf/31FL3731C.pdf
23 */
24
25#include "ch.h"
26#include "hal.h"
da4c2d2e 27#include "print.h"
15635817 28#include "led.h"
b3945c10 29#include "host.h"
b73c935d 30
31#include "led_controller.h"
32
b73c935d 33#include "suspend.h"
34
35#include "usb_main.h"
36
da4c2d2e 37/* Infinity60 LED MAP
b73c935d 38 - digits mean "row" and "col", i.e. 45 means C4-5 in the IS31 datasheet, matrix A
39
da4c2d2e 40 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27*
41 28 31 32 33 34 35 36 37 38 41 42 43 44 45
42 46 47 48 51 52 53 54 55 56 57 58 61 62
43 63 64 65 66 67 68 71 72 73 74 75 76 77*
44 78 81 82 83 84 85 86 87
45
46*Unused in Alphabet Layout
b73c935d 47*/
48
49/*
50 each page has 0xB4 bytes
51 0 - 0x11: LED control (on/off):
52 order: CA1, CB1, CA2, CB2, .... (CA - matrix A, CB - matrix B)
53 CAn controls Cn-8 .. Cn-1 (LSbit)
54 0x12 - 0x23: blink control (like "LED control")
55 0x24 - 0xB3: PWM control: byte per LED, 0xFF max on
56 order same as above (CA 1st row (8bytes), CB 1st row (8bytes), ...)
57*/
58
2c5b5519 59// Which LED should be used for CAPS LOCK indicator
b73c935d 60#if !defined(CAPS_LOCK_LED_ADDRESS)
15635817 61#define CAPS_LOCK_LED_ADDRESS 46
dda858c4 62#endif
63
64#if !defined(NUM_LOCK_LED_ADDRESS)
15635817 65#define NUM_LOCK_LED_ADDRESS 85
b73c935d 66#endif
67
68/* Which LED should breathe during sleep */
69#if !defined(BREATHE_LED_ADDRESS)
70#define BREATHE_LED_ADDRESS CAPS_LOCK_LED_ADDRESS
71#endif
72
73/* =================
74 * ChibiOS I2C setup
75 * ================= */
76static const I2CConfig i2ccfg = {
77 400000 // clock speed (Hz); 400kHz max for IS31
78};
79
80/* ==============
81 * variables
82 * ============== */
83// internal communication buffers
84uint8_t tx[2] __attribute__((aligned(2)));
85uint8_t rx[1] __attribute__((aligned(2)));
86
87// buffer for sending the whole page at once (used also as a temp buffer)
88uint8_t full_page[0xB4+1] = {0};
89
90// LED mask (which LEDs are present, selected by bits)
da4c2d2e 91// IC60 pcb uses only CA matrix.
dda858c4 92// Each byte is a control pin for 8 leds ordered 8-1
1b1adf35 93const uint8_t all_on_leds_mask[0x12] = {
b73c935d 94 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
da4c2d2e 95 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x00
b73c935d 96};
97
dda858c4 98// array to hold brightness pwm steps
99const uint8_t pwm_levels[5] = {
100 0x00, 0x16, 0x4E, 0xA1, 0xFF
101};
102
103// array to write to pwm register
0881f2db 104uint8_t pwm_register_array[9] = {0};
dda858c4 105
106
b73c935d 107/* ============================
108 * communication functions
109 * ============================ */
110msg_t is31_select_page(uint8_t page) {
111 tx[0] = IS31_COMMANDREGISTER;
112 tx[1] = page;
26eef35f 113 return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, TIME_US2I(IS31_TIMEOUT));
b73c935d 114}
115
116msg_t is31_write_data(uint8_t page, uint8_t *buffer, uint8_t size) {
117 is31_select_page(page);
26eef35f 118 return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, buffer, size, NULL, 0, TIME_US2I(IS31_TIMEOUT));
b73c935d 119}
120
121msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data) {
122 is31_select_page(page);
123 tx[0] = reg;
124 tx[1] = data;
26eef35f 125 return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, TIME_US2I(IS31_TIMEOUT));
b73c935d 126}
127
a2ac8837 128msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result) {
129 is31_select_page(page);
b73c935d 130
131 tx[0] = reg;
26eef35f 132 return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 1, result, 1, TIME_US2I(IS31_TIMEOUT));
b73c935d 133}
134
135/* ========================
136 * initialise the IS31 chip
137 * ======================== */
138void is31_init(void) {
139 // just to be sure that it's all zeroes
140 __builtin_memset(full_page,0,0xB4+1);
141 // zero function page, all registers (assuming full_page is all zeroes)
142 is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1);
ac978708 143 // disable hardware shutdown
b73c935d 144 palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
145 palSetPad(GPIOB, 16);
146 chThdSleepMilliseconds(10);
ac978708 147 // software shutdown
b73c935d 148 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
149 chThdSleepMilliseconds(10);
ac978708 150 // zero function page, all registers
151 is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1);
152 chThdSleepMilliseconds(10);
153 // software shutdown disable (i.e. turn stuff on)
154 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
155 chThdSleepMilliseconds(10);
b73c935d 156 // zero all LED registers on all 8 pages
157 uint8_t i;
158 for(i=0; i<8; i++) {
159 is31_write_data(i, full_page, 0xB4 + 1);
164a6c99 160 chThdSleepMilliseconds(5);
b73c935d 161 }
162}
163
164/* ==================
165 * LED control thread
166 * ================== */
167#define LED_MAILBOX_NUM_MSGS 5
168static msg_t led_mailbox_queue[LED_MAILBOX_NUM_MSGS];
169mailbox_t led_mailbox;
170static THD_WORKING_AREA(waLEDthread, 256);
171static THD_FUNCTION(LEDthread, arg) {
172 (void)arg;
173 chRegSetThreadName("LEDthread");
174
b3945c10 175 uint8_t i;
046f1baf 176 uint8_t control_register_word[2] = {0};//2 bytes: register address, byte to write
1b1adf35 177 uint8_t led_control_reg[0x13] = {0};//led control register start address + 0x12 bytes
dda858c4 178
179 //persistent status variables
ac978708 180 uint8_t pwm_step_status, page_status, capslock_status, numlock_status;
dda858c4 181
182 //mailbox variables
164a6c99 183 uint8_t temp, msg_type;
184 uint8_t msg_args[3];
dda858c4 185 msg_t msg;
186
164a6c99 187 // initialize persistent variables
188 pwm_step_status = 4; //full brightness
189 page_status = 0; //start frame 0 (all off/on)
ac978708 190 numlock_status = (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? 1 : 0;
191 capslock_status = (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? 1 : 0;
b73c935d 192
193 while(true) {
194 // wait for a message (asynchronous)
195 // (messages are queued (up to LED_MAILBOX_NUM_MSGS) if they can't
821f72ea 196 // be processed right away
26eef35f 197 chMBFetchTimeout(&led_mailbox, &msg, TIME_INFINITE);
164a6c99 198 msg_type = msg & 0xFF; //first byte is action information
199 msg_args[0] = (msg >> 8) & 0xFF;
200 msg_args[1] = (msg >> 16) & 0XFF;
201 msg_args[2] = (msg >> 24) & 0xFF;
b73c935d 202
ac978708 203
c0ec1756 204 switch (msg_type){
52f671c2 205 case SET_FULL_ROW:
164a6c99 206 //write full byte to pin address, msg_args[1] = pin #, msg_args[0] = 8 bits to write
207 //writes only to currently displayed page
208 write_led_byte(page_status, msg_args[1], msg_args[0]);
209 break;
b3945c10 210
164a6c99 211 case OFF_LED:
f54b4771 212 //on/off/toggle single led, msg_args[0] = row/col of led, msg_args[1] = page
164a6c99 213 set_led_bit(msg_args[1], control_register_word, msg_args[0], 0);
c0ec1756 214 break;
164a6c99 215 case ON_LED:
216 set_led_bit(msg_args[1], control_register_word, msg_args[0], 1);
c0ec1756 217 break;
164a6c99 218 case TOGGLE_LED:
219 set_led_bit(msg_args[1], control_register_word, msg_args[0], 2);
c0ec1756 220 break;
dda858c4 221
164a6c99 222 case BLINK_OFF_LED:
223 //on/off/toggle single led, msg_args[0] = row/col of led
224 set_led_bit(msg_args[1], control_register_word, msg_args[0], 4);
b27fb216 225 break;
164a6c99 226 case BLINK_ON_LED:
227 set_led_bit(msg_args[1], control_register_word, msg_args[0], 5);
b27fb216 228 break;
164a6c99 229 case BLINK_TOGGLE_LED:
230 set_led_bit(msg_args[1], control_register_word, msg_args[0], 6);
52f671c2 231 break;
b27fb216 232
c0ec1756 233 case TOGGLE_ALL:
164a6c99 234 //turn on/off all leds, msg_args = unused
ac978708 235 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
236 chThdSleepMilliseconds(5);
2c5b5519 237 is31_read_register(0, 0x00, &temp);
ac978708 238 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
ac978708 239
c0ec1756 240 led_control_reg[0] = 0;
b27fb216 241
9af272e4 242 //toggle led mask based on current state (temp)
046f1baf 243 if (temp==0 || page_status > 0) {
c0ec1756 244 __builtin_memcpy(led_control_reg+1, all_on_leds_mask, 0x12);
245 } else {
c0ec1756 246 __builtin_memset(led_control_reg+1, 0, 0x12);
247 }
c0ec1756 248 is31_write_data(0, led_control_reg, 0x13);
b3945c10 249
046f1baf 250 if (page_status > 0) {
c0ec1756 251 is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0);
b3945c10 252
52f671c2 253 page_status=0;
046f1baf 254
9af272e4 255 //maintain lock leds, reset to off and force recheck to blink of all leds toggled on
256 numlock_status = 0;
257 capslock_status = 0;
52f671c2 258 led_set(host_keyboard_leds());
259 }
c0ec1756 260 break;
dda858c4 261
c0ec1756 262 case TOGGLE_BACKLIGHT:
164a6c99 263 //msg_args[0] = on/off
dda858c4 264
164a6c99 265 //populate 9 byte rows to be written to each pin, first byte is register (pin) address
266 if (msg_args[0] == 1) {
b3945c10 267 __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
268 } else {
269 __builtin_memset(pwm_register_array+1, 0, 8);
270 }
271
272 for(i=0; i<8; i++) {
164a6c99 273 //first byte is register address, every 0x10 9 bytes is A-matrix pwm pins
b3945c10 274 pwm_register_array[0] = 0x24 + (i * 0x10);
275 is31_write_data(0,pwm_register_array,9);
276 }
c0ec1756 277 break;
15635817 278
2c5b5519 279 case DISPLAY_PAGE:
164a6c99 280 //msg_args[0] = page to toggle on
281 if (page_status != msg_args[0]) {
282 is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, msg_args[0]);
283 page_status = msg_args[0];
52f671c2 284
9af272e4 285 //maintain lock leds, reset to off and force recheck for new page
286 numlock_status = 0;
287 capslock_status = 0;
52f671c2 288 led_set(host_keyboard_leds());
b3945c10 289 }
b3945c10 290 break;
291
292 case RESET_PAGE:
164a6c99 293 //led_args[0] = page to reset
b3945c10 294 led_control_reg[0] = 0;
295 __builtin_memset(led_control_reg+1, 0, 0x12);
164a6c99 296 is31_write_data(msg_args[0], led_control_reg, 0x13);
f54b4771 297
298 //repeat for blink register
299 led_control_reg[0] = 0x12;
300 is31_write_data(msg_args[0], led_control_reg, 0x13);
c0ec1756 301 break;
164a6c99 302
c0ec1756 303 case TOGGLE_NUM_LOCK:
164a6c99 304 //msg_args[0] = 0 or 1, off/on
ac978708 305 if (numlock_status != msg_args[0]) {
306 set_lock_leds(NUM_LOCK_LED_ADDRESS, msg_args[0], page_status);
307 numlock_status = msg_args[0];
308 }
c0ec1756 309 break;
c0ec1756 310 case TOGGLE_CAPS_LOCK:
164a6c99 311 //msg_args[0] = 0 or 1, off/on
ac978708 312 if (capslock_status != msg_args[0]) {
313 set_lock_leds(CAPS_LOCK_LED_ADDRESS, msg_args[0], page_status);
314 capslock_status = msg_args[0];
315 }
c0ec1756 316 break;
dda858c4 317
c0ec1756 318 case STEP_BRIGHTNESS:
164a6c99 319 //led_args[0] = step up (1) or down (0)
320 switch (msg_args[0]) {
52f671c2 321 case 0:
322 if (pwm_step_status == 0) {
323 pwm_step_status = 4;
324 } else {
325 pwm_step_status--;
326 }
327 break;
164a6c99 328
52f671c2 329 case 1:
330 if (pwm_step_status == 4) {
331 pwm_step_status = 0;
332 } else {
333 pwm_step_status++;
334 }
335 break;
336 }
dda858c4 337
821f72ea 338 //populate 8 byte arrays to write on each pin
164a6c99 339 //first byte is register address, every 0x10 9 bytes are A-matrix pwm pins
52f671c2 340 __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
c0ec1756 341
52f671c2 342 for(i=0; i<8; i++) {
343 pwm_register_array[0] = 0x24 + (i * 0x10);
344 is31_write_data(0,pwm_register_array,9);
345 }
346 break;
b27fb216 347 }
b73c935d 348 }
349}
dda858c4 350
1b1adf35 351/* ==============================
352 * led processing functions
353 * ============================== */
354
f54b4771 355void set_led_bit (uint8_t page, uint8_t *led_control_word, uint8_t led_addr, uint8_t action) {
2c5b5519 356 //returns 2 bytes: led control register address and byte to write
164a6c99 357 //action: 0 - off, 1 - on, 2 - toggle, 4 - blink on, 5 - blink off, 6 - toggle blink
b27fb216 358
164a6c99 359 uint8_t control_reg_addr, column_bit, column_byte, temp, blink_bit;
1b1adf35 360
b3945c10 361 //check for valid led address
b27fb216 362 if (led_addr < 0 || led_addr > 87 || led_addr % 10 > 8) {
b3945c10 363 return;
364 }
365
f54b4771 366 blink_bit = action>>2;//check for blink bit
b27fb216 367 action &= ~(1<<2); //strip blink bit
368
164a6c99 369 //led_addr tens column is pin#, ones column is bit position in 8-bit mask
370 control_reg_addr = ((led_addr / 10) % 10 - 1 ) * 0x02;// A-matrix is every other byte
371 control_reg_addr += blink_bit == 1 ? 0x12 : 0x00;//if blink_bit, shift 12 bytes to blink register
2c5b5519 372
ac978708 373 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
374 chThdSleepMilliseconds(5);
164a6c99 375 is31_read_register(page, control_reg_addr, &temp);//maintain status of leds on this byte
ac978708 376 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
ac978708 377
52f671c2 378 column_bit = 1<<(led_addr % 10 - 1);
164a6c99 379 column_byte = temp;
1b1adf35 380
381 switch(action) {
382 case 0:
ec1e936d 383 column_byte &= ~column_bit;
1b1adf35 384 break;
385 case 1:
ec1e936d 386 column_byte |= column_bit;
1b1adf35 387 break;
388 case 2:
ec1e936d 389 column_byte ^= column_bit;
1b1adf35 390 break;
dda858c4 391 }
1b1adf35 392
046f1baf 393 //return word to be written in register
f54b4771 394 led_control_word[0] = control_reg_addr;
395 led_control_word[1] = column_byte;
396 is31_write_data (page, led_control_word, 0x02);
dda858c4 397}
398
b27fb216 399void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte) {
52f671c2 400 uint8_t led_control_word[2] = {0};//register address and on/off byte
15635817 401
164a6c99 402 led_control_word[0] = (row - 1 ) * 0x02;// A-matrix is every other byte
52f671c2 403 led_control_word[1] = led_byte;
404 is31_write_data(page, led_control_word, 0x02);
dda858c4 405}
406
b3945c10 407void write_led_page (uint8_t page, uint8_t *user_led_array, uint8_t led_count) {
dda858c4 408 uint8_t i;
b27fb216 409 uint8_t pin, col;
2c5b5519 410 uint8_t led_control_register[0x13] = {0};
dda858c4 411
046f1baf 412 __builtin_memset(led_control_register,0,13);
413
dda858c4 414 for(i=0;i<led_count;i++){
164a6c99 415 //shift pin by 1 for led register 0x00 address
52f671c2 416 pin = ((user_led_array[i] / 10) % 10 - 1 ) * 2 + 1;
c0ec1756 417 col = user_led_array[i] % 10 - 1;
b27fb216 418 led_control_register[pin] |= 1<<(col);
dda858c4 419 }
420
1b1adf35 421 is31_write_data(page, led_control_register, 0x13);
dda858c4 422}
1b1adf35 423
52f671c2 424void set_lock_leds(uint8_t led_addr, uint8_t led_action, uint8_t page) {
164a6c99 425 uint8_t temp;
b27fb216 426 uint8_t led_control_word[2] = {0};
427
428 //blink if all leds are on
52f671c2 429 if (page == 0) {
ac978708 430 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
431 chThdSleepMilliseconds(5);
164a6c99 432 is31_read_register(0, 0x00, &temp);
ac978708 433 is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
f54b4771 434
164a6c99 435 if (temp == 0xFF) {
52f671c2 436 led_action |= (1<<2); //set blink bit
52f671c2 437 }
b27fb216 438 }
52f671c2 439
440 set_led_bit(page,led_control_word,led_addr,led_action);
b27fb216 441}
442
a2ac8837 443/* =====================
444 * hook into user keymap
445 * ===================== */
da4c2d2e 446void led_controller_init(void) {
b73c935d 447 uint8_t i;
448
449 /* initialise I2C */
450 /* I2C pins */
451 palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
452 palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA
453 /* start I2C */
454 i2cStart(&I2CD1, &i2ccfg);
455 // try high drive (from kiibohd)
456 I2CD1.i2c->C2 |= I2Cx_C2_HDRS;
457 // try glitch fixing (from kiibohd)
458 I2CD1.i2c->FLT = 4;
459
460 chThdSleepMilliseconds(10);
461
462 /* initialise IS31 chip */
463 is31_init();
464
52f671c2 465 //set Display Option Register so all pwm intensity is controlled from page 0
b27fb216 466 //enable blink and set blink period to 0.27s x rate
52f671c2 467 is31_write_register(IS31_FUNCTIONREG, IS31_REG_DISPLAYOPT, IS31_REG_DISPLAYOPT_INTENSITY_SAME + IS31_REG_DISPLAYOPT_BLINK_ENABLE + 4);
d8e9c183 468
52f671c2 469 /* set full pwm on page 1 */
c0ec1756 470 pwm_register_array[0] = 0;
471 __builtin_memset(pwm_register_array+1, 0xFF, 8);
b73c935d 472 for(i=0; i<8; i++) {
0881f2db 473 pwm_register_array[0] = 0x24 + (i * 0x10);//first byte of 9 bytes must be register address
474 is31_write_data(0, pwm_register_array, 9);
d8e9c183 475 chThdSleepMilliseconds(5);
b73c935d 476 }
477
478 /* enable breathing when the displayed page changes */
479 // Fade-in Fade-out, time = 26ms * 2^N, N=3
480 is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (3<<4)|3);
481 is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3);
482
b73c935d 483 /* more time consuming LED processing should be offloaded into
484 * a thread, with asynchronous messaging. */
485 chMBObjectInit(&led_mailbox, led_mailbox_queue, LED_MAILBOX_NUM_MSGS);
486 chThdCreateStatic(waLEDthread, sizeof(waLEDthread), LOWPRIO, LEDthread, NULL);
487}