summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2024-01-01 21:44:18 +1100
committerGitHub <noreply@github.com>2024-01-01 21:44:18 +1100
commit0a6913b68274c03302b09466a79b99efffd35e59 (patch)
tree60c1075ded48a51727f2d2e13a1450f34d370951
parenta88dd675bf3e1dedac2ceb7df779e0fb6931948a (diff)
LED drivers: extract IS31FL3746A from IS31COMMON (#22637)
-rw-r--r--builddefs/common_features.mk6
-rw-r--r--drivers/led/issi/is31fl3746.h198
-rw-r--r--drivers/led/issi/is31fl3746a-simple.c208
-rw-r--r--drivers/led/issi/is31fl3746a-simple.h192
-rw-r--r--drivers/led/issi/is31fl3746a.c212
-rw-r--r--drivers/led/issi/is31fl3746a.h194
-rw-r--r--drivers/led/issi/is31flcommon.h5
-rw-r--r--quantum/led_matrix/led_matrix_drivers.c8
-rw-r--r--quantum/led_matrix/led_matrix_drivers.h2
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.c8
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.h2
11 files changed, 828 insertions, 207 deletions
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index d5446a54c8..cfdc63f1d4 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -414,10 +414,9 @@ ifeq ($(strip $(LED_MATRIX_ENABLE)), yes)
414 endif 414 endif
415 415
416 ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3746a) 416 ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3746a)
417 OPT_DEFS += -DIS31FLCOMMON
418 I2C_DRIVER_REQUIRED = yes 417 I2C_DRIVER_REQUIRED = yes
419 COMMON_VPATH += $(DRIVER_PATH)/led/issi 418 COMMON_VPATH += $(DRIVER_PATH)/led/issi
420 SRC += is31flcommon.c 419 SRC += is31fl3746a-simple.c
421 endif 420 endif
422 421
423 ifeq ($(strip $(LED_MATRIX_DRIVER)), snled27351) 422 ifeq ($(strip $(LED_MATRIX_DRIVER)), snled27351)
@@ -518,10 +517,9 @@ ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
518 endif 517 endif
519 518
520 ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3746a) 519 ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3746a)
521 OPT_DEFS += -DIS31FLCOMMON
522 I2C_DRIVER_REQUIRED = yes 520 I2C_DRIVER_REQUIRED = yes
523 COMMON_VPATH += $(DRIVER_PATH)/led/issi 521 COMMON_VPATH += $(DRIVER_PATH)/led/issi
524 SRC += is31flcommon.c 522 SRC += is31fl3746a.c
525 endif 523 endif
526 524
527 ifeq ($(strip $(RGB_MATRIX_DRIVER)), snled27351) 525 ifeq ($(strip $(RGB_MATRIX_DRIVER)), snled27351)
diff --git a/drivers/led/issi/is31fl3746.h b/drivers/led/issi/is31fl3746.h
deleted file mode 100644
index f89f281533..0000000000
--- a/drivers/led/issi/is31fl3746.h
+++ /dev/null
@@ -1,198 +0,0 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2020 MelGeek
5 * Copyright 2021 MasterSpoon
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#pragma once
22
23// This is a 7-bit address, that gets left-shifted and bit 0
24// set to 0 for write, 1 for read (as per I2C protocol)
25// The address will vary depending on your wiring:
26// 00 <-> GND
27// 01 <-> SCL
28// 10 <-> SDA
29// 11 <-> VCC
30// ADDR1 represents A1:A0 of the 7-bit address.
31// ADDR2 represents A3:A2 of the 7-bit address.
32// The result is: 0b110(ADDR2)(ADDR1)
33#ifndef DRIVER_ADDR_1
34# define DRIVER_ADDR_1 0b1100000
35#endif
36
37// Set defaults for Spread Spectrum Register
38#ifndef ISSI_SSR_1
39# define ISSI_SSR_1 0x00
40#endif
41#ifndef ISSI_SSR_2
42# define ISSI_SSR_2 0x00
43#endif
44#ifndef ISSI_SSR_3
45# define ISSI_SSR_3 0x00
46#endif
47#ifndef ISSI_SSR_4
48# define ISSI_SSR_4 0x00
49#endif
50
51// Command Registers
52#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
53#define ISSI_COMMANDREGISTER 0xFD
54#define ISSI_IDREGISTER 0xFC
55#define ISSI_REGISTER_UNLOCK 0xC5
56
57// Response Registers
58#define ISSI_PAGE_PWM 0x00
59#define ISSI_PAGE_SCALING 0x01
60#define ISSI_PAGE_FUNCTION 0x01
61
62// Registers under Function Register
63#define ISSI_REG_CONFIGURATION 0x50
64#define ISSI_REG_GLOBALCURRENT 0x51
65#define ISSI_REG_PULLDOWNUP 0x52
66#define ISSI_REG_TEMP 0x5F
67#define ISSI_REG_SSR 0x60
68#define ISSI_REG_RESET 0x8F
69#define ISSI_REG_PWM_ENABLE 0xE0
70#define ISSI_REG_PWM_SET 0xE2
71
72// Set defaults for Function Registers
73#ifndef ISSI_CONFIGURATION
74# define ISSI_CONFIGURATION 0x01
75#endif
76#ifndef ISSI_GLOBALCURRENT
77# define ISSI_GLOBALCURRENT 0xFF
78#endif
79#ifndef ISSI_PULLDOWNUP
80# define ISSI_PULLDOWNUP 0x33
81#endif
82#ifndef ISSI_TEMP
83# define ISSI_TEMP 0x00
84#endif
85#ifndef ISSI_PWM_ENABLE
86# define ISSI_PWM_ENABLE 0x00
87#endif
88#ifndef ISSI_PWM_SET
89# define ISSI_PWM_SET 0x00
90#endif
91
92// Set defaults for Scaling registers
93#ifndef ISSI_SCAL_RED
94# define ISSI_SCAL_RED 0xFF
95#endif
96#ifndef ISSI_SCAL_BLUE
97# define ISSI_SCAL_BLUE 0xFF
98#endif
99#ifndef ISSI_SCAL_GREEN
100# define ISSI_SCAL_GREEN 0xFF
101#endif
102#define ISSI_SCAL_RED_OFF 0x00
103#define ISSI_SCAL_GREEN_OFF 0x00
104#define ISSI_SCAL_BLUE_OFF 0x00
105
106#ifndef ISSI_SCAL_LED
107# define ISSI_SCAL_LED 0xFF
108#endif
109#define ISSI_SCAL_LED_OFF 0x00
110
111// Set buffer sizes
112#define ISSI_MAX_LEDS 72
113#define ISSI_SCALING_SIZE 72
114#define ISSI_PWM_TRF_SIZE 18
115#define ISSI_SCALING_TRF_SIZE 18
116
117// Location of 1st bit for PWM and Scaling registers
118#define ISSI_PWM_REG_1ST 0x01
119#define ISSI_SCL_REG_1ST 0x01
120
121// Map CS SW locations to order in PWM / Scaling buffers
122// This matches the ORDER in the Datasheet Register not the POSITION
123// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
124#define CS1_SW1 0x00
125#define CS2_SW1 0x01
126#define CS3_SW1 0x02
127#define CS4_SW1 0x03
128#define CS5_SW1 0x04
129#define CS6_SW1 0x05
130#define CS7_SW1 0x06
131#define CS8_SW1 0x07
132#define CS9_SW1 0x08
133#define CS10_SW1 0x09
134#define CS11_SW1 0x0A
135#define CS12_SW1 0x0B
136#define CS13_SW1 0x0C
137#define CS14_SW1 0x0D
138#define CS15_SW1 0x0E
139#define CS16_SW1 0x0F
140#define CS17_SW1 0x10
141#define CS18_SW1 0x11
142
143#define CS1_SW2 0x12
144#define CS2_SW2 0x13
145#define CS3_SW2 0x14
146#define CS4_SW2 0x15
147#define CS5_SW2 0x16
148#define CS6_SW2 0x17
149#define CS7_SW2 0x18
150#define CS8_SW2 0x19
151#define CS9_SW2 0x1A
152#define CS10_SW2 0x1B
153#define CS11_SW2 0x1C
154#define CS12_SW2 0x1D
155#define CS13_SW2 0x1E
156#define CS14_SW2 0x1F
157#define CS15_SW2 0x20
158#define CS16_SW2 0x21
159#define CS17_SW2 0x22
160#define CS18_SW2 0x23
161
162#define CS1_SW3 0x24
163#define CS2_SW3 0x25
164#define CS3_SW3 0x26
165#define CS4_SW3 0x27
166#define CS5_SW3 0x28
167#define CS6_SW3 0x29
168#define CS7_SW3 0x2A
169#define CS8_SW3 0x2B
170#define CS9_SW3 0x2C
171#define CS10_SW3 0x2D
172#define CS11_SW3 0x2E
173#define CS12_SW3 0x2F
174#define CS13_SW3 0x30
175#define CS14_SW3 0x31
176#define CS15_SW3 0x32
177#define CS16_SW3 0x33
178#define CS17_SW3 0x34
179#define CS18_SW3 0x35
180
181#define CS1_SW4 0x36
182#define CS2_SW4 0x37
183#define CS3_SW4 0x38
184#define CS4_SW4 0x39
185#define CS5_SW4 0x3A
186#define CS6_SW4 0x3B
187#define CS7_SW4 0x3C
188#define CS8_SW4 0x3D
189#define CS9_SW4 0x3E
190#define CS10_SW4 0x3F
191#define CS11_SW4 0x40
192#define CS12_SW4 0x41
193#define CS13_SW4 0x42
194#define CS14_SW4 0x43
195#define CS15_SW4 0x44
196#define CS16_SW4 0x45
197#define CS17_SW4 0x46
198#define CS18_SW4 0x47
diff --git a/drivers/led/issi/is31fl3746a-simple.c b/drivers/led/issi/is31fl3746a-simple.c
new file mode 100644
index 0000000000..3a29c511cb
--- /dev/null
+++ b/drivers/led/issi/is31fl3746a-simple.c
@@ -0,0 +1,208 @@
1#include "is31fl3746a-simple.h"
2#include <string.h>
3#include "i2c_master.h"
4#include "wait.h"
5
6#define IS31FL3746A_PWM_REGISTER_COUNT 72
7#define IS31FL3746A_SCALING_REGISTER_COUNT 72
8
9#ifndef IS31FL3746A_I2C_TIMEOUT
10# define IS31FL3746A_I2C_TIMEOUT 100
11#endif
12
13#ifndef IS31FL3746A_I2C_PERSISTENCE
14# define IS31FL3746A_I2C_PERSISTENCE 0
15#endif
16
17#ifndef IS31FL3746A_CONFIGURATION
18# define IS31FL3746A_CONFIGURATION 0x01
19#endif
20
21#ifndef IS31FL3746A_PWM_FREQUENCY
22# define IS31FL3746A_PWM_FREQUENCY IS31FL3746A_PWM_FREQUENCY_29K_HZ
23#endif
24
25#ifndef IS31FL3746A_SW_PULLDOWN
26# define IS31FL3746A_SW_PULLDOWN IS31FL3746A_PDR_2K_OHM_SW_OFF
27#endif
28
29#ifndef IS31FL3746A_CS_PULLUP
30# define IS31FL3746A_CS_PULLUP IS31FL3746A_PUR_2K_OHM_CS_OFF
31#endif
32
33#ifndef IS31FL3746A_GLOBAL_CURRENT
34# define IS31FL3746A_GLOBAL_CURRENT 0xFF
35#endif
36
37uint8_t i2c_transfer_buffer[20] = {0xFF};
38
39uint8_t g_pwm_buffer[IS31FL3746A_DRIVER_COUNT][IS31FL3746A_PWM_REGISTER_COUNT];
40bool g_pwm_buffer_update_required[IS31FL3746A_DRIVER_COUNT] = {false};
41bool g_scaling_registers_update_required[IS31FL3746A_DRIVER_COUNT] = {false};
42
43uint8_t g_scaling_registers[IS31FL3746A_DRIVER_COUNT][IS31FL3746A_SCALING_REGISTER_COUNT];
44
45void is31fl3746a_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
46 i2c_transfer_buffer[0] = reg;
47 i2c_transfer_buffer[1] = data;
48
49#if IS31FL3746A_I2C_PERSISTENCE > 0
50 for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
51 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3746A_I2C_TIMEOUT) == 0) break;
52 }
53#else
54 i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3746A_I2C_TIMEOUT);
55#endif
56}
57
58void is31fl3746a_select_page(uint8_t addr, uint8_t page) {
59 is31fl3746a_write_register(addr, IS31FL3746A_REG_COMMAND_WRITE_LOCK, IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC);
60 is31fl3746a_write_register(addr, IS31FL3746A_REG_COMMAND, page);
61}
62
63void is31fl3746a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
64 // Assumes page 0 is already selected.
65 // If any of the transactions fails function returns false.
66 // Transmit PWM registers in 12 transfers of 16 bytes.
67 // i2c_transfer_buffer[] is 20 bytes
68
69 // Iterate over the pwm_buffer contents at 16 byte intervals.
70 for (int i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i += 16) {
71 i2c_transfer_buffer[0] = i + 1;
72 // Copy the data from i to i+15.
73 // Device will auto-increment register for data after the first byte
74 // Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
75 memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
76
77#if IS31FL3746A_I2C_PERSISTENCE > 0
78 for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
79 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3746A_I2C_TIMEOUT) != 0) break;
80 }
81#else
82 i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3746A_I2C_TIMEOUT);
83#endif
84 }
85}
86
87void is31fl3746a_init_drivers(void) {
88 i2c_init();
89
90 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_1);
91#if defined(IS31FL3746A_I2C_ADDRESS_2)
92 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_2);
93# if defined(IS31FL3746A_I2C_ADDRESS_3)
94 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_3);
95# if defined(IS31FL3746A_I2C_ADDRESS_4)
96 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_4);
97# endif
98# endif
99#endif
100
101 for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
102 is31fl3746a_set_scaling_register(i, 0xFF);
103 }
104
105 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_1, 0);
106#if defined(IS31FL3746A_I2C_ADDRESS_2)
107 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_2, 1);
108# if defined(IS31FL3746A_I2C_ADDRESS_3)
109 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_3, 2);
110# if defined(IS31FL3746A_I2C_ADDRESS_4)
111 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_4, 3);
112# endif
113# endif
114#endif
115}
116
117void is31fl3746a_init(uint8_t addr) {
118 // In order to avoid the LEDs being driven with garbage data
119 // in the LED driver's PWM registers, shutdown is enabled last.
120 // Set up the mode and other settings, clear the PWM registers,
121 // then disable software shutdown.
122
123 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_SCALING);
124
125 // Turn off all LEDs.
126 for (int i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
127 is31fl3746a_write_register(addr, i + 1, 0x00);
128 }
129
130 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_PWM);
131
132 for (int i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i++) {
133 is31fl3746a_write_register(addr, i + 1, 0x00);
134 }
135
136 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_FUNCTION);
137
138 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PULLDOWNUP, (IS31FL3746A_SW_PULLDOWN << 4) | IS31FL3746A_CS_PULLUP);
139 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3746A_GLOBAL_CURRENT);
140 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PWM_ENABLE, 0x01);
141 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY, IS31FL3746A_PWM_FREQUENCY);
142 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_CONFIGURATION, IS31FL3746A_CONFIGURATION);
143
144 // Wait 10ms to ensure the device has woken up.
145 wait_ms(10);
146}
147
148void is31fl3746a_set_color(int index, uint8_t value) {
149 is31fl3746a_led_t led;
150 if (index >= 0 && index < IS31FL3746A_LED_COUNT) {
151 memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
152
153 if (g_pwm_buffer[led.driver][led.v] == value) {
154 return;
155 }
156 g_pwm_buffer_update_required[led.driver] = true;
157 g_pwm_buffer[led.driver][led.v] = value;
158 }
159}
160
161void is31fl3746a_set_value_all(uint8_t value) {
162 for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
163 is31fl3746a_set_value(i, value);
164 }
165}
166
167void is31fl3746a_set_scaling_register(uint8_t index, uint8_t value) {
168 is31fl3746a_led_t led;
169 memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
170
171 g_scaling_registers[led.driver][led.v] = value;
172
173 g_scaling_registers_update_required[led.driver] = true;
174}
175
176void is31fl3746a_update_pwm_buffers(uint8_t addr, uint8_t index) {
177 if (g_pwm_buffer_update_required[index]) {
178 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_PWM);
179
180 is31fl3746a_write_pwm_buffer(addr, g_pwm_buffer[index]);
181 }
182
183 g_pwm_buffer_update_required[index] = false;
184}
185
186void is31fl3746a_update_scaling_registers(uint8_t addr, uint8_t index) {
187 if (g_scaling_registers_update_required[index]) {
188 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_SCALING);
189
190 for (int i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
191 is31fl3746a_write_register(addr, i + 1, g_scaling_registers[index][i]);
192 }
193 g_scaling_registers_update_required[index] = false;
194 }
195}
196
197void is31fl3746a_flush(void) {
198 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_1, 0);
199#if defined(IS31FL3746A_I2C_ADDRESS_2)
200 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_2, 1);
201# if defined(IS31FL3746A_I2C_ADDRESS_3)
202 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_3, 2);
203# if defined(IS31FL3746A_I2C_ADDRESS_4)
204 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_4, 3);
205# endif
206# endif
207#endif
208}
diff --git a/drivers/led/issi/is31fl3746a-simple.h b/drivers/led/issi/is31fl3746a-simple.h
new file mode 100644
index 0000000000..eda644ad19
--- /dev/null
+++ b/drivers/led/issi/is31fl3746a-simple.h
@@ -0,0 +1,192 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2020 MelGeek
5 * Copyright 2021 MasterSpoon
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#pragma once
22
23#include <stdint.h>
24#include <stdbool.h>
25#include "progmem.h"
26#include "util.h"
27
28#define IS31FL3746A_REG_ID 0xFC
29
30#define IS31FL3746A_REG_COMMAND 0xFD
31
32#define IS31FL3746A_COMMAND_PWM 0x00
33#define IS31FL3746A_COMMAND_SCALING 0x01
34#define IS31FL3746A_COMMAND_FUNCTION 0x01
35
36#define IS31FL3746A_FUNCTION_REG_CONFIGURATION 0x50
37#define IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT 0x51
38#define IS31FL3746A_FUNCTION_REG_PULLDOWNUP 0x52
39#define IS31FL3746A_FUNCTION_REG_TEMPERATURE 0x5F
40#define IS31FL3746A_FUNCTION_REG_SPREAD_SPECTRUM 0x60
41#define IS31FL3746A_FUNCTION_REG_RESET 0x8F
42#define IS31FL3746A_FUNCTION_REG_PWM_ENABLE 0xE0
43#define IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY 0xE2
44
45#define IS31FL3746A_REG_COMMAND_WRITE_LOCK 0xFE
46#define IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC 0xC5
47
48#define IS31FL3746A_I2C_ADDRESS_GND_GND 0x60
49#define IS31FL3746A_I2C_ADDRESS_GND_SCL 0x61
50#define IS31FL3746A_I2C_ADDRESS_GND_SDA 0x62
51#define IS31FL3746A_I2C_ADDRESS_GND_VCC 0x63
52#define IS31FL3746A_I2C_ADDRESS_SCL_GND 0x64
53#define IS31FL3746A_I2C_ADDRESS_SCL_SCL 0x65
54#define IS31FL3746A_I2C_ADDRESS_SCL_SDA 0x66
55#define IS31FL3746A_I2C_ADDRESS_SCL_VCC 0x67
56#define IS31FL3746A_I2C_ADDRESS_SDA_GND 0x68
57#define IS31FL3746A_I2C_ADDRESS_SDA_SCL 0x69
58#define IS31FL3746A_I2C_ADDRESS_SDA_SDA 0x6A
59#define IS31FL3746A_I2C_ADDRESS_SDA_VCC 0x6B
60#define IS31FL3746A_I2C_ADDRESS_VCC_GND 0x6C
61#define IS31FL3746A_I2C_ADDRESS_VCC_SCL 0x6D
62#define IS31FL3746A_I2C_ADDRESS_VCC_SDA 0x6E
63#define IS31FL3746A_I2C_ADDRESS_VCC_VCC 0x6F
64
65#if defined(LED_MATRIX_IS31FL3746A)
66# define IS31FL3746A_LED_COUNT LED_MATRIX_LED_COUNT
67#endif
68
69typedef struct is31fl3746a_led_t {
70 uint8_t driver : 2;
71 uint8_t v;
72} PACKED is31fl3746a_led_t;
73
74extern const is31fl3746a_led_t PROGMEM g_is31fl3746a_leds[IS31FL3746A_LED_COUNT];
75
76void is31fl3746a_init_drivers(void);
77void is31fl3746a_init(uint8_t addr, uint8_t sync);
78void is31fl3746a_write_register(uint8_t addr, uint8_t reg, uint8_t data);
79void is31fl3746a_select_page(uint8_t addr, uint8_t page);
80void is31fl3746a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
81
82void is31fl3746a_set_value(int index, uint8_t value);
83void is31fl3746a_set_value_all(uint8_t value);
84
85void is31fl3746a_set_scaling_register(uint8_t index, uint8_t value);
86
87void is31fl3746a_update_pwm_buffers(uint8_t addr, uint8_t index);
88void is31fl3746a_update_scaling_registers(uint8_t addr, uint8_t index);
89
90void is31fl3746a_flush(void);
91
92#define IS31FL3746A_PDR_0_OHM 0b000 // No pull-down resistor
93#define IS31FL3746A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
94#define IS31FL3746A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
95#define IS31FL3746A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
96#define IS31FL3746A_PDR_1K_OHM 0b100 // 1 kOhm resistor
97#define IS31FL3746A_PDR_2K_OHM 0b101 // 2 kOhm resistor
98#define IS31FL3746A_PDR_4K_OHM 0b110 // 4 kOhm resistor
99#define IS31FL3746A_PDR_8K_OHM 0b111 // 8 kOhm resistor
100
101#define IS31FL3746A_PUR_0_OHM 0b000 // No pull-up resistor
102#define IS31FL3746A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
103#define IS31FL3746A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
104#define IS31FL3746A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
105#define IS31FL3746A_PUR_1K_OHM 0b100 // 1 kOhm resistor
106#define IS31FL3746A_PUR_2K_OHM 0b101 // 2 kOhm resistor
107#define IS31FL3746A_PUR_4K_OHM 0b110 // 4 kOhm resistor
108#define IS31FL3746A_PUR_8K_OHM 0b111 // 8 kOhm resistor
109
110#define IS31FL3746A_PWM_FREQUENCY_29K_HZ 0b000
111#define IS31FL3746A_PWM_FREQUENCY_14K5_HZ 0b001
112#define IS31FL3746A_PWM_FREQUENCY_7K25_HZ 0b010
113#define IS31FL3746A_PWM_FREQUENCY_3K63_HZ 0b011
114#define IS31FL3746A_PWM_FREQUENCY_1K81_HZ 0b100
115#define IS31FL3746A_PWM_FREQUENCY_906_HZ 0b101
116#define IS31FL3746A_PWM_FREQUENCY_453_HZ 0b110
117
118#define CS1_SW1 0x00
119#define CS2_SW1 0x01
120#define CS3_SW1 0x02
121#define CS4_SW1 0x03
122#define CS5_SW1 0x04
123#define CS6_SW1 0x05
124#define CS7_SW1 0x06
125#define CS8_SW1 0x07
126#define CS9_SW1 0x08
127#define CS10_SW1 0x09
128#define CS11_SW1 0x0A
129#define CS12_SW1 0x0B
130#define CS13_SW1 0x0C
131#define CS14_SW1 0x0D
132#define CS15_SW1 0x0E
133#define CS16_SW1 0x0F
134#define CS17_SW1 0x10
135#define CS18_SW1 0x11
136
137#define CS1_SW2 0x12
138#define CS2_SW2 0x13
139#define CS3_SW2 0x14
140#define CS4_SW2 0x15
141#define CS5_SW2 0x16
142#define CS6_SW2 0x17
143#define CS7_SW2 0x18
144#define CS8_SW2 0x19
145#define CS9_SW2 0x1A
146#define CS10_SW2 0x1B
147#define CS11_SW2 0x1C
148#define CS12_SW2 0x1D
149#define CS13_SW2 0x1E
150#define CS14_SW2 0x1F
151#define CS15_SW2 0x20
152#define CS16_SW2 0x21
153#define CS17_SW2 0x22
154#define CS18_SW2 0x23
155
156#define CS1_SW3 0x24
157#define CS2_SW3 0x25
158#define CS3_SW3 0x26
159#define CS4_SW3 0x27
160#define CS5_SW3 0x28
161#define CS6_SW3 0x29
162#define CS7_SW3 0x2A
163#define CS8_SW3 0x2B
164#define CS9_SW3 0x2C
165#define CS10_SW3 0x2D
166#define CS11_SW3 0x2E
167#define CS12_SW3 0x2F
168#define CS13_SW3 0x30
169#define CS14_SW3 0x31
170#define CS15_SW3 0x32
171#define CS16_SW3 0x33
172#define CS17_SW3 0x34
173#define CS18_SW3 0x35
174
175#define CS1_SW4 0x36
176#define CS2_SW4 0x37
177#define CS3_SW4 0x38
178#define CS4_SW4 0x39
179#define CS5_SW4 0x3A
180#define CS6_SW4 0x3B
181#define CS7_SW4 0x3C
182#define CS8_SW4 0x3D
183#define CS9_SW4 0x3E
184#define CS10_SW4 0x3F
185#define CS11_SW4 0x40
186#define CS12_SW4 0x41
187#define CS13_SW4 0x42
188#define CS14_SW4 0x43
189#define CS15_SW4 0x44
190#define CS16_SW4 0x45
191#define CS17_SW4 0x46
192#define CS18_SW4 0x47
diff --git a/drivers/led/issi/is31fl3746a.c b/drivers/led/issi/is31fl3746a.c
new file mode 100644
index 0000000000..5a3001f02f
--- /dev/null
+++ b/drivers/led/issi/is31fl3746a.c
@@ -0,0 +1,212 @@
1#include "is31fl3746a.h"
2#include <string.h>
3#include "i2c_master.h"
4#include "wait.h"
5
6#define IS31FL3746A_PWM_REGISTER_COUNT 72
7#define IS31FL3746A_SCALING_REGISTER_COUNT 72
8
9#ifndef IS31FL3746A_I2C_TIMEOUT
10# define IS31FL3746A_I2C_TIMEOUT 100
11#endif
12
13#ifndef IS31FL3746A_I2C_PERSISTENCE
14# define IS31FL3746A_I2C_PERSISTENCE 0
15#endif
16
17#ifndef IS31FL3746A_CONFIGURATION
18# define IS31FL3746A_CONFIGURATION 0x01
19#endif
20
21#ifndef IS31FL3746A_PWM_FREQUENCY
22# define IS31FL3746A_PWM_FREQUENCY IS31FL3746A_PWM_FREQUENCY_29K_HZ
23#endif
24
25#ifndef IS31FL3746A_SW_PULLDOWN
26# define IS31FL3746A_SW_PULLDOWN IS31FL3746A_PDR_2K_OHM_SW_OFF
27#endif
28
29#ifndef IS31FL3746A_CS_PULLUP
30# define IS31FL3746A_CS_PULLUP IS31FL3746A_PUR_2K_OHM_CS_OFF
31#endif
32
33#ifndef IS31FL3746A_GLOBAL_CURRENT
34# define IS31FL3746A_GLOBAL_CURRENT 0xFF
35#endif
36
37uint8_t i2c_transfer_buffer[20] = {0xFF};
38
39uint8_t g_pwm_buffer[IS31FL3746A_DRIVER_COUNT][IS31FL3746A_PWM_REGISTER_COUNT];
40bool g_pwm_buffer_update_required[IS31FL3746A_DRIVER_COUNT] = {false};
41bool g_scaling_registers_update_required[IS31FL3746A_DRIVER_COUNT] = {false};
42
43uint8_t g_scaling_registers[IS31FL3746A_DRIVER_COUNT][IS31FL3746A_SCALING_REGISTER_COUNT];
44
45void is31fl3746a_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
46 i2c_transfer_buffer[0] = reg;
47 i2c_transfer_buffer[1] = data;
48
49#if IS31FL3746A_I2C_PERSISTENCE > 0
50 for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
51 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3746A_I2C_TIMEOUT) == 0) break;
52 }
53#else
54 i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3746A_I2C_TIMEOUT);
55#endif
56}
57
58void is31fl3746a_select_page(uint8_t addr, uint8_t page) {
59 is31fl3746a_write_register(addr, IS31FL3746A_REG_COMMAND_WRITE_LOCK, IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC);
60 is31fl3746a_write_register(addr, IS31FL3746A_REG_COMMAND, page);
61}
62
63void is31fl3746a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
64 // Assumes page 0 is already selected.
65 // If any of the transactions fails function returns false.
66 // Transmit PWM registers in 12 transfers of 16 bytes.
67 // i2c_transfer_buffer[] is 20 bytes
68
69 // Iterate over the pwm_buffer contents at 16 byte intervals.
70 for (int i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i += 16) {
71 i2c_transfer_buffer[0] = i + 1;
72 // Copy the data from i to i+15.
73 // Device will auto-increment register for data after the first byte
74 // Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
75 memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
76
77#if IS31FL3746A_I2C_PERSISTENCE > 0
78 for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
79 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3746A_I2C_TIMEOUT) != 0) break;
80 }
81#else
82 i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3746A_I2C_TIMEOUT);
83#endif
84 }
85}
86
87void is31fl3746a_init_drivers(void) {
88 i2c_init();
89
90 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_1);
91#if defined(IS31FL3746A_I2C_ADDRESS_2)
92 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_2);
93# if defined(IS31FL3746A_I2C_ADDRESS_3)
94 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_3);
95# if defined(IS31FL3746A_I2C_ADDRESS_4)
96 is31fl3746a_init(IS31FL3746A_I2C_ADDRESS_4);
97# endif
98# endif
99#endif
100
101 for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
102 is31fl3746a_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
103 }
104
105 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_1, 0);
106#if defined(IS31FL3746A_I2C_ADDRESS_2)
107 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_2, 1);
108# if defined(IS31FL3746A_I2C_ADDRESS_3)
109 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_3, 2);
110# if defined(IS31FL3746A_I2C_ADDRESS_4)
111 is31fl3746a_update_scaling_registers(IS31FL3746A_I2C_ADDRESS_4, 3);
112# endif
113# endif
114#endif
115}
116
117void is31fl3746a_init(uint8_t addr) {
118 // In order to avoid the LEDs being driven with garbage data
119 // in the LED driver's PWM registers, shutdown is enabled last.
120 // Set up the mode and other settings, clear the PWM registers,
121 // then disable software shutdown.
122
123 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_SCALING);
124
125 // Turn off all LEDs.
126 for (int i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
127 is31fl3746a_write_register(addr, i + 1, 0x00);
128 }
129
130 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_PWM);
131
132 for (int i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i++) {
133 is31fl3746a_write_register(addr, i + 1, 0x00);
134 }
135
136 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_FUNCTION);
137
138 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PULLDOWNUP, (IS31FL3746A_SW_PULLDOWN << 4) | IS31FL3746A_CS_PULLUP);
139 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3746A_GLOBAL_CURRENT);
140 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PWM_ENABLE, 0x01);
141 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY, IS31FL3746A_PWM_FREQUENCY);
142 is31fl3746a_write_register(addr, IS31FL3746A_FUNCTION_REG_CONFIGURATION, IS31FL3746A_CONFIGURATION);
143
144 // Wait 10ms to ensure the device has woken up.
145 wait_ms(10);
146}
147
148void is31fl3746a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
149 is31fl3746a_led_t led;
150 if (index >= 0 && index < IS31FL3746A_LED_COUNT) {
151 memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
152
153 if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) {
154 return;
155 }
156 g_pwm_buffer_update_required[led.driver] = true;
157 g_pwm_buffer[led.driver][led.r] = red;
158 g_pwm_buffer[led.driver][led.g] = green;
159 g_pwm_buffer[led.driver][led.b] = blue;
160 }
161}
162
163void is31fl3746a_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
164 for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
165 is31fl3746a_set_color(i, red, green, blue);
166 }
167}
168
169void is31fl3746a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
170 is31fl3746a_led_t led;
171 memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
172
173 g_scaling_registers[led.driver][led.r] = red;
174 g_scaling_registers[led.driver][led.g] = green;
175 g_scaling_registers[led.driver][led.b] = blue;
176
177 g_scaling_registers_update_required[led.driver] = true;
178}
179
180void is31fl3746a_update_pwm_buffers(uint8_t addr, uint8_t index) {
181 if (g_pwm_buffer_update_required[index]) {
182 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_PWM);
183
184 is31fl3746a_write_pwm_buffer(addr, g_pwm_buffer[index]);
185 }
186
187 g_pwm_buffer_update_required[index] = false;
188}
189
190void is31fl3746a_update_scaling_registers(uint8_t addr, uint8_t index) {
191 if (g_scaling_registers_update_required[index]) {
192 is31fl3746a_select_page(addr, IS31FL3746A_COMMAND_SCALING);
193
194 for (int i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
195 is31fl3746a_write_register(addr, i + 1, g_scaling_registers[index][i]);
196 }
197 g_scaling_registers_update_required[index] = false;
198 }
199}
200
201void is31fl3746a_flush(void) {
202 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_1, 0);
203#if defined(IS31FL3746A_I2C_ADDRESS_2)
204 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_2, 1);
205# if defined(IS31FL3746A_I2C_ADDRESS_3)
206 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_3, 2);
207# if defined(IS31FL3746A_I2C_ADDRESS_4)
208 is31fl3746a_update_pwm_buffers(IS31FL3746A_I2C_ADDRESS_4, 3);
209# endif
210# endif
211#endif
212}
diff --git a/drivers/led/issi/is31fl3746a.h b/drivers/led/issi/is31fl3746a.h
new file mode 100644
index 0000000000..f335e98e82
--- /dev/null
+++ b/drivers/led/issi/is31fl3746a.h
@@ -0,0 +1,194 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2020 MelGeek
5 * Copyright 2021 MasterSpoon
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#pragma once
22
23#include <stdint.h>
24#include <stdbool.h>
25#include "progmem.h"
26#include "util.h"
27
28#define IS31FL3746A_REG_ID 0xFC
29
30#define IS31FL3746A_REG_COMMAND 0xFD
31
32#define IS31FL3746A_COMMAND_PWM 0x00
33#define IS31FL3746A_COMMAND_SCALING 0x01
34#define IS31FL3746A_COMMAND_FUNCTION 0x01
35
36#define IS31FL3746A_FUNCTION_REG_CONFIGURATION 0x50
37#define IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT 0x51
38#define IS31FL3746A_FUNCTION_REG_PULLDOWNUP 0x52
39#define IS31FL3746A_FUNCTION_REG_TEMPERATURE 0x5F
40#define IS31FL3746A_FUNCTION_REG_SPREAD_SPECTRUM 0x60
41#define IS31FL3746A_FUNCTION_REG_RESET 0x8F
42#define IS31FL3746A_FUNCTION_REG_PWM_ENABLE 0xE0
43#define IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY 0xE2
44
45#define IS31FL3746A_REG_COMMAND_WRITE_LOCK 0xFE
46#define IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC 0xC5
47
48#define IS31FL3746A_I2C_ADDRESS_GND_GND 0x60
49#define IS31FL3746A_I2C_ADDRESS_GND_SCL 0x61
50#define IS31FL3746A_I2C_ADDRESS_GND_SDA 0x62
51#define IS31FL3746A_I2C_ADDRESS_GND_VCC 0x63
52#define IS31FL3746A_I2C_ADDRESS_SCL_GND 0x64
53#define IS31FL3746A_I2C_ADDRESS_SCL_SCL 0x65
54#define IS31FL3746A_I2C_ADDRESS_SCL_SDA 0x66
55#define IS31FL3746A_I2C_ADDRESS_SCL_VCC 0x67
56#define IS31FL3746A_I2C_ADDRESS_SDA_GND 0x68
57#define IS31FL3746A_I2C_ADDRESS_SDA_SCL 0x69
58#define IS31FL3746A_I2C_ADDRESS_SDA_SDA 0x6A
59#define IS31FL3746A_I2C_ADDRESS_SDA_VCC 0x6B
60#define IS31FL3746A_I2C_ADDRESS_VCC_GND 0x6C
61#define IS31FL3746A_I2C_ADDRESS_VCC_SCL 0x6D
62#define IS31FL3746A_I2C_ADDRESS_VCC_SDA 0x6E
63#define IS31FL3746A_I2C_ADDRESS_VCC_VCC 0x6F
64
65#if defined(RGB_MATRIX_IS31FL3746A)
66# define IS31FL3746A_LED_COUNT RGB_MATRIX_LED_COUNT
67#endif
68
69typedef struct is31fl3746a_led_t {
70 uint8_t driver : 2;
71 uint8_t r;
72 uint8_t g;
73 uint8_t b;
74} PACKED is31fl3746a_led_t;
75
76extern const is31fl3746a_led_t PROGMEM g_is31fl3746a_leds[IS31FL3746A_LED_COUNT];
77
78void is31fl3746a_init_drivers(void);
79void is31fl3746a_init(uint8_t addr, uint8_t sync);
80void is31fl3746a_write_register(uint8_t addr, uint8_t reg, uint8_t data);
81void is31fl3746a_select_page(uint8_t addr, uint8_t page);
82void is31fl3746a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
83
84void is31fl3746a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
85void is31fl3746a_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
86
87void is31fl3746a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
88
89void is31fl3746a_update_pwm_buffers(uint8_t addr, uint8_t index);
90void is31fl3746a_update_scaling_registers(uint8_t addr, uint8_t index);
91
92void is31fl3746a_flush(void);
93
94#define IS31FL3746A_PDR_0_OHM 0b000 // No pull-down resistor
95#define IS31FL3746A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
96#define IS31FL3746A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
97#define IS31FL3746A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
98#define IS31FL3746A_PDR_1K_OHM 0b100 // 1 kOhm resistor
99#define IS31FL3746A_PDR_2K_OHM 0b101 // 2 kOhm resistor
100#define IS31FL3746A_PDR_4K_OHM 0b110 // 4 kOhm resistor
101#define IS31FL3746A_PDR_8K_OHM 0b111 // 8 kOhm resistor
102
103#define IS31FL3746A_PUR_0_OHM 0b000 // No pull-up resistor
104#define IS31FL3746A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
105#define IS31FL3746A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
106#define IS31FL3746A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
107#define IS31FL3746A_PUR_1K_OHM 0b100 // 1 kOhm resistor
108#define IS31FL3746A_PUR_2K_OHM 0b101 // 2 kOhm resistor
109#define IS31FL3746A_PUR_4K_OHM 0b110 // 4 kOhm resistor
110#define IS31FL3746A_PUR_8K_OHM 0b111 // 8 kOhm resistor
111
112#define IS31FL3746A_PWM_FREQUENCY_29K_HZ 0b000
113#define IS31FL3746A_PWM_FREQUENCY_14K5_HZ 0b001
114#define IS31FL3746A_PWM_FREQUENCY_7K25_HZ 0b010
115#define IS31FL3746A_PWM_FREQUENCY_3K63_HZ 0b011
116#define IS31FL3746A_PWM_FREQUENCY_1K81_HZ 0b100
117#define IS31FL3746A_PWM_FREQUENCY_906_HZ 0b101
118#define IS31FL3746A_PWM_FREQUENCY_453_HZ 0b110
119
120#define CS1_SW1 0x00
121#define CS2_SW1 0x01
122#define CS3_SW1 0x02
123#define CS4_SW1 0x03
124#define CS5_SW1 0x04
125#define CS6_SW1 0x05
126#define CS7_SW1 0x06
127#define CS8_SW1 0x07
128#define CS9_SW1 0x08
129#define CS10_SW1 0x09
130#define CS11_SW1 0x0A
131#define CS12_SW1 0x0B
132#define CS13_SW1 0x0C
133#define CS14_SW1 0x0D
134#define CS15_SW1 0x0E
135#define CS16_SW1 0x0F
136#define CS17_SW1 0x10
137#define CS18_SW1 0x11
138
139#define CS1_SW2 0x12
140#define CS2_SW2 0x13
141#define CS3_SW2 0x14
142#define CS4_SW2 0x15
143#define CS5_SW2 0x16
144#define CS6_SW2 0x17
145#define CS7_SW2 0x18
146#define CS8_SW2 0x19
147#define CS9_SW2 0x1A
148#define CS10_SW2 0x1B
149#define CS11_SW2 0x1C
150#define CS12_SW2 0x1D
151#define CS13_SW2 0x1E
152#define CS14_SW2 0x1F
153#define CS15_SW2 0x20
154#define CS16_SW2 0x21
155#define CS17_SW2 0x22
156#define CS18_SW2 0x23
157
158#define CS1_SW3 0x24
159#define CS2_SW3 0x25
160#define CS3_SW3 0x26
161#define CS4_SW3 0x27
162#define CS5_SW3 0x28
163#define CS6_SW3 0x29
164#define CS7_SW3 0x2A
165#define CS8_SW3 0x2B
166#define CS9_SW3 0x2C
167#define CS10_SW3 0x2D
168#define CS11_SW3 0x2E
169#define CS12_SW3 0x2F
170#define CS13_SW3 0x30
171#define CS14_SW3 0x31
172#define CS15_SW3 0x32
173#define CS16_SW3 0x33
174#define CS17_SW3 0x34
175#define CS18_SW3 0x35
176
177#define CS1_SW4 0x36
178#define CS2_SW4 0x37
179#define CS3_SW4 0x38
180#define CS4_SW4 0x39
181#define CS5_SW4 0x3A
182#define CS6_SW4 0x3B
183#define CS7_SW4 0x3C
184#define CS8_SW4 0x3D
185#define CS9_SW4 0x3E
186#define CS10_SW4 0x3F
187#define CS11_SW4 0x40
188#define CS12_SW4 0x41
189#define CS13_SW4 0x42
190#define CS14_SW4 0x43
191#define CS15_SW4 0x44
192#define CS16_SW4 0x45
193#define CS17_SW4 0x46
194#define CS18_SW4 0x47
diff --git a/drivers/led/issi/is31flcommon.h b/drivers/led/issi/is31flcommon.h
index e5c4c52125..db7cd24b48 100644
--- a/drivers/led/issi/is31flcommon.h
+++ b/drivers/led/issi/is31flcommon.h
@@ -25,11 +25,6 @@
25#include "progmem.h" 25#include "progmem.h"
26#include "util.h" 26#include "util.h"
27 27
28// Which variant header file to use
29#if defined(LED_MATRIX_IS31FL3746A) || defined(RGB_MATRIX_IS31FL3746A)
30# include "is31fl3746.h"
31#endif
32
33#if defined DRIVER_ADDR_4 28#if defined DRIVER_ADDR_4
34# define DRIVER_COUNT 4 29# define DRIVER_COUNT 4
35#elif defined DRIVER_ADDR_3 30#elif defined DRIVER_ADDR_3
diff --git a/quantum/led_matrix/led_matrix_drivers.c b/quantum/led_matrix/led_matrix_drivers.c
index f244ae30e9..73e2513a11 100644
--- a/quantum/led_matrix/led_matrix_drivers.c
+++ b/quantum/led_matrix/led_matrix_drivers.c
@@ -97,6 +97,14 @@ const led_matrix_driver_t led_matrix_driver = {
97 .set_value_all = is31fl3745_set_value_all, 97 .set_value_all = is31fl3745_set_value_all,
98}; 98};
99 99
100#elif defined(LED_MATRIX_IS31FL3746A)
101const led_matrix_driver_t led_matrix_driver = {
102 .init = is31fl3746a_init_drivers,
103 .flush = is31fl3746a_flush,
104 .set_value = is31fl3746a_set_value,
105 .set_value_all = is31fl3746a_set_value_all,
106};
107
100#elif defined(IS31FLCOMMON) 108#elif defined(IS31FLCOMMON)
101const led_matrix_driver_t led_matrix_driver = { 109const led_matrix_driver_t led_matrix_driver = {
102 .init = IS31FL_simple_init_drivers, 110 .init = IS31FL_simple_init_drivers,
diff --git a/quantum/led_matrix/led_matrix_drivers.h b/quantum/led_matrix/led_matrix_drivers.h
index 01821a83c4..4eab0ac748 100644
--- a/quantum/led_matrix/led_matrix_drivers.h
+++ b/quantum/led_matrix/led_matrix_drivers.h
@@ -23,6 +23,8 @@
23# include "is31fl3743a-simple.h" 23# include "is31fl3743a-simple.h"
24#elif defined(LED_MATRIX_IS31FL3745) 24#elif defined(LED_MATRIX_IS31FL3745)
25# include "is31fl3745-simple.h" 25# include "is31fl3745-simple.h"
26#elif defined(LED_MATRIX_IS31FL3746A)
27# include "is31fl3746a-simple.h"
26#elif defined(IS31FLCOMMON) 28#elif defined(IS31FLCOMMON)
27# include "is31flcommon.h" 29# include "is31flcommon.h"
28#elif defined(LED_MATRIX_SNLED27351) 30#elif defined(LED_MATRIX_SNLED27351)
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.c b/quantum/rgb_matrix/rgb_matrix_drivers.c
index 0a41991efb..e3dd9beff7 100644
--- a/quantum/rgb_matrix/rgb_matrix_drivers.c
+++ b/quantum/rgb_matrix/rgb_matrix_drivers.c
@@ -100,6 +100,14 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
100 .set_color_all = is31fl3745_set_color_all, 100 .set_color_all = is31fl3745_set_color_all,
101}; 101};
102 102
103#elif defined(RGB_MATRIX_IS31FL3746A)
104const rgb_matrix_driver_t rgb_matrix_driver = {
105 .init = is31fl3746a_init_drivers,
106 .flush = is31fl3746a_flush,
107 .set_color = is31fl3746a_set_color,
108 .set_color_all = is31fl3746a_set_color_all,
109};
110
103#elif defined(IS31FLCOMMON) 111#elif defined(IS31FLCOMMON)
104const rgb_matrix_driver_t rgb_matrix_driver = { 112const rgb_matrix_driver_t rgb_matrix_driver = {
105 .init = IS31FL_RGB_init_drivers, 113 .init = IS31FL_RGB_init_drivers,
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.h b/quantum/rgb_matrix/rgb_matrix_drivers.h
index 786f2fa37a..07d376dfd7 100644
--- a/quantum/rgb_matrix/rgb_matrix_drivers.h
+++ b/quantum/rgb_matrix/rgb_matrix_drivers.h
@@ -25,6 +25,8 @@
25# include "is31fl3743a.h" 25# include "is31fl3743a.h"
26#elif defined(RGB_MATRIX_IS31FL3745) 26#elif defined(RGB_MATRIX_IS31FL3745)
27# include "is31fl3745.h" 27# include "is31fl3745.h"
28#elif defined(RGB_MATRIX_IS31FL3746A)
29# include "is31fl3746a.h"
28#elif defined(IS31FLCOMMON) 30#elif defined(IS31FLCOMMON)
29# include "is31flcommon.h" 31# include "is31flcommon.h"
30#elif defined(RGB_MATRIX_SNLED27351) 32#elif defined(RGB_MATRIX_SNLED27351)