summaryrefslogtreecommitdiff
path: root/drivers/led
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2023-10-03 01:09:20 +1100
committerGitHub <noreply@github.com>2023-10-03 01:09:20 +1100
commitbd5860de4ed50ee306cee2ef54c7ff4f751a6168 (patch)
treeb64ac52a33a54fe8e1e60541d4d2fe4255d2ec84 /drivers/led
parent6e3f770d0d26230381a57b43843c074508a850e8 (diff)
is31fl3737/3741: add LED Matrix support (#22163)
Diffstat (limited to 'drivers/led')
-rw-r--r--drivers/led/issi/is31fl3737-simple.c219
-rw-r--r--drivers/led/issi/is31fl3737-simple.h256
-rw-r--r--drivers/led/issi/is31fl3741-simple.c253
-rw-r--r--drivers/led/issi/is31fl3741-simple.h471
4 files changed, 1199 insertions, 0 deletions
diff --git a/drivers/led/issi/is31fl3737-simple.c b/drivers/led/issi/is31fl3737-simple.c
new file mode 100644
index 0000000000..b25fbb5a56
--- /dev/null
+++ b/drivers/led/issi/is31fl3737-simple.c
@@ -0,0 +1,219 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "is31fl3737-simple.h"
21#include <string.h>
22#include "i2c_master.h"
23#include "wait.h"
24
25#define IS31FL3737_COMMANDREGISTER 0xFD
26#define IS31FL3737_COMMANDREGISTER_WRITELOCK 0xFE
27#define IS31FL3737_INTERRUPTMASKREGISTER 0xF0
28#define IS31FL3737_INTERRUPTSTATUSREGISTER 0xF1
29
30#define IS31FL3737_PAGE_LEDCONTROL 0x00 // PG0
31#define IS31FL3737_PAGE_PWM 0x01 // PG1
32#define IS31FL3737_PAGE_AUTOBREATH 0x02 // PG2
33#define IS31FL3737_PAGE_FUNCTION 0x03 // PG3
34
35#define IS31FL3737_REG_CONFIGURATION 0x00 // PG3
36#define IS31FL3737_REG_GLOBALCURRENT 0x01 // PG3
37#define IS31FL3737_REG_RESET 0x11 // PG3
38#define IS31FL3737_REG_SWPULLUP 0x0F // PG3
39#define IS31FL3737_REG_CSPULLUP 0x10 // PG3
40
41#ifndef IS31FL3737_I2C_TIMEOUT
42# define IS31FL3737_I2C_TIMEOUT 100
43#endif
44
45#ifndef IS31FL3737_I2C_PERSISTENCE
46# define IS31FL3737_I2C_PERSISTENCE 0
47#endif
48
49#ifndef IS31FL3737_PWM_FREQUENCY
50# define IS31FL3737_PWM_FREQUENCY IS31FL3737_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3737B only
51#endif
52
53#ifndef IS31FL3737_SWPULLUP
54# define IS31FL3737_SWPULLUP IS31FL3737_PUR_0R
55#endif
56
57#ifndef IS31FL3737_CSPULLUP
58# define IS31FL3737_CSPULLUP IS31FL3737_PUR_0R
59#endif
60
61#ifndef IS31FL3737_GLOBALCURRENT
62# define IS31FL3737_GLOBALCURRENT 0xFF
63#endif
64
65// Transfer buffer for TWITransmitData()
66uint8_t g_twi_transfer_buffer[20];
67
68// These buffers match the IS31FL3737 PWM registers.
69// The control buffers match the PG0 LED On/Off registers.
70// Storing them like this is optimal for I2C transfers to the registers.
71// We could optimize this and take out the unused registers from these
72// buffers and the transfers in is31fl3737_write_pwm_buffer() but it's
73// probably not worth the extra complexity.
74
75uint8_t g_pwm_buffer[IS31FL3737_DRIVER_COUNT][192];
76bool g_pwm_buffer_update_required[IS31FL3737_DRIVER_COUNT] = {false};
77
78uint8_t g_led_control_registers[IS31FL3737_DRIVER_COUNT][24] = {0};
79bool g_led_control_registers_update_required[IS31FL3737_DRIVER_COUNT] = {false};
80
81void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
82 g_twi_transfer_buffer[0] = reg;
83 g_twi_transfer_buffer[1] = data;
84
85#if IS31FL3737_I2C_PERSISTENCE > 0
86 for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
87 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT) == 0) break;
88 }
89#else
90 i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT);
91#endif
92}
93
94void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
95 // assumes PG1 is already selected
96
97 // transmit PWM registers in 12 transfers of 16 bytes
98 // g_twi_transfer_buffer[] is 20 bytes
99
100 // iterate over the pwm_buffer contents at 16 byte intervals
101 for (int i = 0; i < 192; i += 16) {
102 g_twi_transfer_buffer[0] = i;
103 // copy the data from i to i+15
104 // device will auto-increment register for data after the first byte
105 // thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
106 memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 16);
107
108#if IS31FL3737_I2C_PERSISTENCE > 0
109 for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
110 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT) == 0) break;
111 }
112#else
113 i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT);
114#endif
115 }
116}
117
118void is31fl3737_init(uint8_t addr) {
119 // In order to avoid the LEDs being driven with garbage data
120 // in the LED driver's PWM registers, shutdown is enabled last.
121 // Set up the mode and other settings, clear the PWM registers,
122 // then disable software shutdown.
123
124 // Unlock the command register.
125 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER_WRITELOCK, 0xC5);
126
127 // Select PG0
128 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER, IS31FL3737_PAGE_LEDCONTROL);
129 // Turn off all LEDs.
130 for (int i = 0x00; i <= 0x17; i++) {
131 is31fl3737_write_register(addr, i, 0x00);
132 }
133
134 // Unlock the command register.
135 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER_WRITELOCK, 0xC5);
136
137 // Select PG1
138 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER, IS31FL3737_PAGE_PWM);
139 // Set PWM on all LEDs to 0
140 // No need to setup Breath registers to PWM as that is the default.
141 for (int i = 0x00; i <= 0xBF; i++) {
142 is31fl3737_write_register(addr, i, 0x00);
143 }
144
145 // Unlock the command register.
146 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER_WRITELOCK, 0xC5);
147
148 // Select PG3
149 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER, IS31FL3737_PAGE_FUNCTION);
150 // Set de-ghost pull-up resistors (SWx)
151 is31fl3737_write_register(addr, IS31FL3737_REG_SWPULLUP, IS31FL3737_SWPULLUP);
152 // Set de-ghost pull-down resistors (CSx)
153 is31fl3737_write_register(addr, IS31FL3737_REG_CSPULLUP, IS31FL3737_CSPULLUP);
154 // Set global current to maximum.
155 is31fl3737_write_register(addr, IS31FL3737_REG_GLOBALCURRENT, IS31FL3737_GLOBALCURRENT);
156 // Disable software shutdown.
157 is31fl3737_write_register(addr, IS31FL3737_REG_CONFIGURATION, ((IS31FL3737_PWM_FREQUENCY & 0b111) << 3) | 0x01);
158
159 // Wait 10ms to ensure the device has woken up.
160 wait_ms(10);
161}
162
163void is31fl3737_set_value(int index, uint8_t value) {
164 is31_led led;
165 if (index >= 0 && index < LED_MATRIX_LED_COUNT) {
166 memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));
167
168 if (g_pwm_buffer[led.driver][led.v] == value) {
169 return;
170 }
171 g_pwm_buffer[led.driver][led.v] = value;
172 g_pwm_buffer_update_required[led.driver] = true;
173 }
174}
175
176void is31fl3737_set_value_all(uint8_t value) {
177 for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {
178 is31fl3737_set_value(i, value);
179 }
180}
181
182void is31fl3737_set_led_control_register(uint8_t index, bool value) {
183 is31_led led;
184 memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));
185
186 uint8_t control_register = led.v / 8;
187 uint8_t bit_value = led.v % 8;
188
189 if (value) {
190 g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
191 } else {
192 g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
193 }
194
195 g_led_control_registers_update_required[led.driver] = true;
196}
197
198void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index) {
199 if (g_pwm_buffer_update_required[index]) {
200 // Firstly we need to unlock the command register and select PG1
201 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER_WRITELOCK, 0xC5);
202 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER, IS31FL3737_PAGE_PWM);
203
204 is31fl3737_write_pwm_buffer(addr, g_pwm_buffer[index]);
205 g_pwm_buffer_update_required[index] = false;
206 }
207}
208
209void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index) {
210 if (g_led_control_registers_update_required[index]) {
211 // Firstly we need to unlock the command register and select PG0
212 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER_WRITELOCK, 0xC5);
213 is31fl3737_write_register(addr, IS31FL3737_COMMANDREGISTER, IS31FL3737_PAGE_LEDCONTROL);
214 for (int i = 0; i < 24; i++) {
215 is31fl3737_write_register(addr, i, g_led_control_registers[index][i]);
216 }
217 g_led_control_registers_update_required[index] = false;
218 }
219}
diff --git a/drivers/led/issi/is31fl3737-simple.h b/drivers/led/issi/is31fl3737-simple.h
new file mode 100644
index 0000000000..d242daa1d0
--- /dev/null
+++ b/drivers/led/issi/is31fl3737-simple.h
@@ -0,0 +1,256 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <stdint.h>
23#include <stdbool.h>
24#include "progmem.h"
25
26// ======== DEPRECATED DEFINES - DO NOT USE ========
27#ifdef DRIVER_COUNT
28# define IS31FL3737_DRIVER_COUNT DRIVER_COUNT
29#endif
30#ifdef ISSI_TIMEOUT
31# define IS31FL3737_I2C_TIMEOUT ISSI_TIMEOUT
32#endif
33#ifdef ISSI_PERSISTENCE
34# define IS31FL3737_I2C_PERSISTENCE ISSI_PERSISTENCE
35#endif
36#ifdef ISSI_PWM_FREQUENCY
37# define IS31FL3737_PWM_FREQUENCY ISSI_PWM_FREQUENCY
38#endif
39#ifdef ISSI_SWPULLUP
40# define IS31FL3737_SWPULLUP ISSI_SWPULLUP
41#endif
42#ifdef ISSI_CSPULLUP
43# define IS31FL3737_CSPULLUP ISSI_CSPULLUP
44#endif
45#ifdef ISSI_GLOBALCURRENT
46# define IS31FL3737_GLOBALCURRENT ISSI_GLOBALCURRENT
47#endif
48
49#define PUR_0R IS31FL3737_PUR_0R
50#define PUR_05KR IS31FL3737_PUR_05KR
51#define PUR_1KR IS31FL3737_PUR_1KR
52#define PUR_2KR IS31FL3737_PUR_2KR
53#define PUR_4KR IS31FL3737_PUR_4KR
54#define PUR_8KR IS31FL3737_PUR_8KR
55#define PUR_16KR IS31FL3737_PUR_16KR
56#define PUR_32KR IS31FL3737_PUR_32KR
57// ========
58
59#define IS31FL3737_I2C_ADDRESS_GND 0x50
60#define IS31FL3737_I2C_ADDRESS_SCL 0x55
61#define IS31FL3737_I2C_ADDRESS_SDA 0x5A
62#define IS31FL3737_I2C_ADDRESS_VCC 0x5F
63
64typedef struct is31_led {
65 uint8_t driver : 2;
66 uint8_t v;
67} __attribute__((packed)) is31_led;
68
69extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT];
70
71void is31fl3737_init(uint8_t addr);
72void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data);
73void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
74
75void is31fl3737_set_value(int index, uint8_t value);
76void is31fl3737_set_value_all(uint8_t value);
77
78void is31fl3737_set_led_control_register(uint8_t index, bool value);
79
80// This should not be called from an interrupt
81// (eg. from a timer interrupt).
82// Call this while idle (in between matrix scans).
83// If the buffer is dirty, it will update the driver with the buffer.
84void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index);
85void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index);
86
87#define IS31FL3737_PUR_0R 0x00 // No PUR resistor
88#define IS31FL3737_PUR_05KR 0x01 // 0.5k Ohm resistor in t_NOL
89#define IS31FL3737_PUR_1KR 0x02 // 1.0k Ohm resistor in t_NOL
90#define IS31FL3737_PUR_2KR 0x03 // 2.0k Ohm resistor in t_NOL
91#define IS31FL3737_PUR_4KR 0x04 // 4.0k Ohm resistor in t_NOL
92#define IS31FL3737_PUR_8KR 0x05 // 8.0k Ohm resistor in t_NOL
93#define IS31FL3737_PUR_16KR 0x06 // 16k Ohm resistor in t_NOL
94#define IS31FL3737_PUR_32KR 0x07 // 32k Ohm resistor in t_NOL
95
96#define IS31FL3737_PWM_FREQUENCY_8K4_HZ 0b000
97#define IS31FL3737_PWM_FREQUENCY_4K2_HZ 0b001
98#define IS31FL3737_PWM_FREQUENCY_26K7_HZ 0b010
99#define IS31FL3737_PWM_FREQUENCY_2K1_HZ 0b011
100#define IS31FL3737_PWM_FREQUENCY_1K05_HZ 0b100
101
102#define A_1 0x00
103#define A_2 0x01
104#define A_3 0x02
105#define A_4 0x03
106#define A_5 0x04
107#define A_6 0x05
108#define A_7 0x08
109#define A_8 0x09
110#define A_9 0x0A
111#define A_10 0x0B
112#define A_11 0x0C
113#define A_12 0x0D
114
115#define B_1 0x10
116#define B_2 0x11
117#define B_3 0x12
118#define B_4 0x13
119#define B_5 0x14
120#define B_6 0x15
121#define B_7 0x18
122#define B_8 0x19
123#define B_9 0x1A
124#define B_10 0x1B
125#define B_11 0x1C
126#define B_12 0x1D
127
128#define C_1 0x20
129#define C_2 0x21
130#define C_3 0x22
131#define C_4 0x23
132#define C_5 0x24
133#define C_6 0x25
134#define C_7 0x28
135#define C_8 0x29
136#define C_9 0x2A
137#define C_10 0x2B
138#define C_11 0x2C
139#define C_12 0x2D
140
141#define D_1 0x30
142#define D_2 0x31
143#define D_3 0x32
144#define D_4 0x33
145#define D_5 0x34
146#define D_6 0x35
147#define D_7 0x38
148#define D_8 0x39
149#define D_9 0x3A
150#define D_10 0x3B
151#define D_11 0x3C
152#define D_12 0x3D
153
154#define E_1 0x40
155#define E_2 0x41
156#define E_3 0x42
157#define E_4 0x43
158#define E_5 0x44
159#define E_6 0x45
160#define E_7 0x48
161#define E_8 0x49
162#define E_9 0x4A
163#define E_10 0x4B
164#define E_11 0x4C
165#define E_12 0x4D
166
167#define F_1 0x50
168#define F_2 0x51
169#define F_3 0x52
170#define F_4 0x53
171#define F_5 0x54
172#define F_6 0x55
173#define F_7 0x58
174#define F_8 0x59
175#define F_9 0x5A
176#define F_10 0x5B
177#define F_11 0x5C
178#define F_12 0x5D
179
180#define G_1 0x60
181#define G_2 0x61
182#define G_3 0x62
183#define G_4 0x63
184#define G_5 0x64
185#define G_6 0x65
186#define G_7 0x68
187#define G_8 0x69
188#define G_9 0x6A
189#define G_10 0x6B
190#define G_11 0x6C
191#define G_12 0x6D
192
193#define H_1 0x70
194#define H_2 0x71
195#define H_3 0x72
196#define H_4 0x73
197#define H_5 0x74
198#define H_6 0x75
199#define H_7 0x78
200#define H_8 0x79
201#define H_9 0x7A
202#define H_10 0x7B
203#define H_11 0x7C
204#define H_12 0x7D
205
206#define I_1 0x80
207#define I_2 0x81
208#define I_3 0x82
209#define I_4 0x83
210#define I_5 0x84
211#define I_6 0x85
212#define I_7 0x88
213#define I_8 0x89
214#define I_9 0x8A
215#define I_10 0x8B
216#define I_11 0x8C
217#define I_12 0x8D
218
219#define J_1 0x90
220#define J_2 0x91
221#define J_3 0x92
222#define J_4 0x93
223#define J_5 0x94
224#define J_6 0x95
225#define J_7 0x98
226#define J_8 0x99
227#define J_9 0x9A
228#define J_10 0x9B
229#define J_11 0x9C
230#define J_12 0x9D
231
232#define K_1 0xA0
233#define K_2 0xA1
234#define K_3 0xA2
235#define K_4 0xA3
236#define K_5 0xA4
237#define K_6 0xA5
238#define K_7 0xA8
239#define K_8 0xA9
240#define K_9 0xAA
241#define K_10 0xAB
242#define K_11 0xAC
243#define K_12 0xAD
244
245#define L_1 0xB0
246#define L_2 0xB1
247#define L_3 0xB2
248#define L_4 0xB3
249#define L_5 0xB4
250#define L_6 0xB5
251#define L_7 0xB8
252#define L_8 0xB9
253#define L_9 0xBA
254#define L_10 0xBB
255#define L_11 0xBC
256#define L_12 0xBD
diff --git a/drivers/led/issi/is31fl3741-simple.c b/drivers/led/issi/is31fl3741-simple.c
new file mode 100644
index 0000000000..7df3030131
--- /dev/null
+++ b/drivers/led/issi/is31fl3741-simple.c
@@ -0,0 +1,253 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2020 MelGeek
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "is31fl3741-simple.h"
21#include <string.h>
22#include "i2c_master.h"
23#include "wait.h"
24
25#define IS31FL3741_COMMANDREGISTER 0xFD
26#define IS31FL3741_COMMANDREGISTER_WRITELOCK 0xFE
27#define IS31FL3741_INTERRUPTMASKREGISTER 0xF0
28#define IS31FL3741_INTERRUPTSTATUSREGISTER 0xF1
29#define IS31FL3741_IDREGISTER 0xFC
30
31#define IS31FL3741_PAGE_PWM0 0x00 // PG0
32#define IS31FL3741_PAGE_PWM1 0x01 // PG1
33#define IS31FL3741_PAGE_SCALING_0 0x02 // PG2
34#define IS31FL3741_PAGE_SCALING_1 0x03 // PG3
35#define IS31FL3741_PAGE_FUNCTION 0x04 // PG4
36
37#define IS31FL3741_REG_CONFIGURATION 0x00 // PG4
38#define IS31FL3741_REG_GLOBALCURRENT 0x01 // PG4
39#define IS31FL3741_REG_PULLDOWNUP 0x02 // PG4
40#define IS31FL3741_REG_PWM_FREQUENCY 0x36 // PG4
41#define IS31FL3741_REG_RESET 0x3F // PG4
42
43#ifndef IS31FL3741_I2C_TIMEOUT
44# define IS31FL3741_I2C_TIMEOUT 100
45#endif
46
47#ifndef IS31FL3741_I2C_PERSISTENCE
48# define IS31FL3741_I2C_PERSISTENCE 0
49#endif
50
51#ifndef IS31FL3741_CONFIGURATION
52# define IS31FL3741_CONFIGURATION 0x01
53#endif
54
55#ifndef IS31FL3741_PWM_FREQUENCY
56# define IS31FL3741_PWM_FREQUENCY IS31FL3741_PWM_FREQUENCY_29K_HZ
57#endif
58
59#ifndef IS31FL3741_SWPULLUP
60# define IS31FL3741_SWPULLUP IS31FL3741_PUR_32KR
61#endif
62
63#ifndef IS31FL3741_CSPULLUP
64# define IS31FL3741_CSPULLUP IS31FL3741_PUR_32KR
65#endif
66
67#ifndef IS31FL3741_GLOBALCURRENT
68# define IS31FL3741_GLOBALCURRENT 0xFF
69#endif
70
71#define IS31FL3741_MAX_LEDS 351
72
73// Transfer buffer for TWITransmitData()
74uint8_t g_twi_transfer_buffer[20] = {0xFF};
75
76// These buffers match the IS31FL3741 and IS31FL3741A PWM registers.
77// The scaling buffers match the PG2 and PG3 LED On/Off registers.
78// Storing them like this is optimal for I2C transfers to the registers.
79// We could optimize this and take out the unused registers from these
80// buffers and the transfers in is31fl3741_write_pwm_buffer() but it's
81// probably not worth the extra complexity.
82uint8_t g_pwm_buffer[IS31FL3741_DRIVER_COUNT][IS31FL3741_MAX_LEDS];
83bool g_pwm_buffer_update_required[IS31FL3741_DRIVER_COUNT] = {false};
84bool g_scaling_registers_update_required[IS31FL3741_DRIVER_COUNT] = {false};
85
86uint8_t g_scaling_registers[IS31FL3741_DRIVER_COUNT][IS31FL3741_MAX_LEDS];
87
88void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
89 g_twi_transfer_buffer[0] = reg;
90 g_twi_transfer_buffer[1] = data;
91
92#if IS31FL3741_I2C_PERSISTENCE > 0
93 for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
94 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT) == 0) break;
95 }
96#else
97 i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT);
98#endif
99}
100
101bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
102 // Assume PG0 is already selected
103
104 for (int i = 0; i < 342; i += 18) {
105 if (i == 180) {
106 // unlock the command register and select PG1
107 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER_WRITELOCK, 0xC5);
108 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER, IS31FL3741_PAGE_PWM1);
109 }
110
111 g_twi_transfer_buffer[0] = i % 180;
112 memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 18);
113
114#if IS31FL3741_I2C_PERSISTENCE > 0
115 for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
116 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
117 return false;
118 }
119 }
120#else
121 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
122 return false;
123 }
124#endif
125 }
126
127 // transfer the left cause the total number is 351
128 g_twi_transfer_buffer[0] = 162;
129 memcpy(g_twi_transfer_buffer + 1, pwm_buffer + 342, 9);
130
131#if IS31FL3741_I2C_PERSISTENCE > 0
132 for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
133 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
134 return false;
135 }
136 }
137#else
138 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
139 return false;
140 }
141#endif
142
143 return true;
144}
145
146void is31fl3741_init(uint8_t addr) {
147 // In order to avoid the LEDs being driven with garbage data
148 // in the LED driver's PWM registers, shutdown is enabled last.
149 // Set up the mode and other settings, clear the PWM registers,
150 // then disable software shutdown.
151 // Unlock the command register.
152
153 // Unlock the command register.
154 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER_WRITELOCK, 0xC5);
155
156 // Select PG4
157 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER, IS31FL3741_PAGE_FUNCTION);
158
159 // Set to Normal operation
160 is31fl3741_write_register(addr, IS31FL3741_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
161
162 // Set Golbal Current Control Register
163 is31fl3741_write_register(addr, IS31FL3741_REG_GLOBALCURRENT, IS31FL3741_GLOBALCURRENT);
164 // Set Pull up & Down for SWx CSy
165 is31fl3741_write_register(addr, IS31FL3741_REG_PULLDOWNUP, ((IS31FL3741_CSPULLUP << 4) | IS31FL3741_SWPULLUP));
166 // Set PWM frequency
167 is31fl3741_write_register(addr, IS31FL3741_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
168
169 // is31fl3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF);
170
171 // Wait 10ms to ensure the device has woken up.
172 wait_ms(10);
173}
174
175void is31fl3741_set_value(int index, uint8_t value) {
176 is31_led led;
177 if (index >= 0 && index < LED_MATRIX_LED_COUNT) {
178 memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));
179
180 if (g_pwm_buffer[led.driver][led.v] == value) {
181 return;
182 }
183 g_pwm_buffer_update_required[led.driver] = true;
184 g_pwm_buffer[led.driver][led.v] = value;
185 }
186}
187
188void is31fl3741_set_value_all(uint8_t value) {
189 for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {
190 is31fl3741_set_value(i, value);
191 }
192}
193
194void is31fl3741_set_led_control_register(uint8_t index, bool value) {
195 is31_led led;
196 memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));
197
198 if (value) {
199 g_scaling_registers[led.driver][led.v] = 0xFF;
200 } else {
201 g_scaling_registers[led.driver][led.v] = 0x00;
202 }
203
204 g_scaling_registers_update_required[led.driver] = true;
205}
206
207void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index) {
208 if (g_pwm_buffer_update_required[index]) {
209 // unlock the command register and select PG2
210 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER_WRITELOCK, 0xC5);
211 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER, IS31FL3741_PAGE_PWM0);
212
213 is31fl3741_write_pwm_buffer(addr, g_pwm_buffer[index]);
214 }
215
216 g_pwm_buffer_update_required[index] = false;
217}
218
219void is31fl3741_set_pwm_buffer(const is31_led *pled, uint8_t value) {
220 g_pwm_buffer[pled->driver][pled->v] = value;
221
222 g_pwm_buffer_update_required[pled->driver] = true;
223}
224
225void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index) {
226 if (g_scaling_registers_update_required[index]) {
227 // unlock the command register and select PG2
228 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER_WRITELOCK, 0xC5);
229 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER, IS31FL3741_PAGE_SCALING_0);
230
231 // CS1_SW1 to CS30_SW6 are on PG2
232 for (int i = CS1_SW1; i <= CS30_SW6; ++i) {
233 is31fl3741_write_register(addr, i, g_scaling_registers[index][i]);
234 }
235
236 // unlock the command register and select PG3
237 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER_WRITELOCK, 0xC5);
238 is31fl3741_write_register(addr, IS31FL3741_COMMANDREGISTER, IS31FL3741_PAGE_SCALING_1);
239
240 // CS1_SW7 to CS39_SW9 are on PG3
241 for (int i = CS1_SW7; i <= CS39_SW9; ++i) {
242 is31fl3741_write_register(addr, i - CS1_SW7, g_scaling_registers[index][i]);
243 }
244
245 g_scaling_registers_update_required[index] = false;
246 }
247}
248
249void is31fl3741_set_scaling_registers(const is31_led *pled, uint8_t value) {
250 g_scaling_registers[pled->driver][pled->v] = value;
251
252 g_scaling_registers_update_required[pled->driver] = true;
253}
diff --git a/drivers/led/issi/is31fl3741-simple.h b/drivers/led/issi/is31fl3741-simple.h
new file mode 100644
index 0000000000..8bca066ad3
--- /dev/null
+++ b/drivers/led/issi/is31fl3741-simple.h
@@ -0,0 +1,471 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar
4 * Copyright 2020 MelGeek
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <stdint.h>
23#include <stdbool.h>
24#include "progmem.h"
25
26// ======== DEPRECATED DEFINES - DO NOT USE ========
27#ifdef DRIVER_COUNT
28# define IS31FL3741_DRIVER_COUNT DRIVER_COUNT
29#endif
30#ifdef ISSI_TIMEOUT
31# define IS31FL3741_I2C_TIMEOUT ISSI_TIMEOUT
32#endif
33#ifdef ISSI_PERSISTENCE
34# define IS31FL3741_I2C_PERSISTENCE ISSI_PERSISTENCE
35#endif
36#ifdef ISSI_CONFIGURATION
37# define IS31FL3741_CONFIGURATION ISSI_CONFIGURATION
38#endif
39#ifdef ISSI_SWPULLUP
40# define IS31FL3741_SWPULLUP ISSI_SWPULLUP
41#endif
42#ifdef ISSI_CSPULLUP
43# define IS31FL3741_CSPULLUP ISSI_CSPULLUP
44#endif
45#ifdef ISSI_GLOBALCURRENT
46# define IS31FL3741_GLOBALCURRENT ISSI_GLOBALCURRENT
47#endif
48
49#define PUR_0R IS31FL3741_PUR_0R
50#define PUR_05KR IS31FL3741_PUR_05KR
51#define PUR_1KR IS31FL3741_PUR_1KR
52#define PUR_2KR IS31FL3741_PUR_2KR
53#define PUR_4KR IS31FL3741_PUR_4KR
54#define PUR_8KR IS31FL3741_PUR_8KR
55#define PUR_16KR IS31FL3741_PUR_16KR
56#define PUR_32KR IS31FL3741_PUR_32KR
57// ========
58
59#define IS31FL3741_I2C_ADDRESS_GND 0x30
60#define IS31FL3741_I2C_ADDRESS_SCL 0x31
61#define IS31FL3741_I2C_ADDRESS_SDA 0x32
62#define IS31FL3741_I2C_ADDRESS_VCC 0x33
63
64typedef struct is31_led {
65 uint32_t driver : 2;
66 uint32_t v : 10;
67} __attribute__((packed)) is31_led;
68
69extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];
70
71void is31fl3741_init(uint8_t addr);
72void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data);
73bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
74
75void is31fl3741_set_value(int index, uint8_t value);
76void is31fl3741_set_value_all(uint8_t value);
77
78void is31fl3741_set_led_control_register(uint8_t index, bool value);
79
80// This should not be called from an interrupt
81// (eg. from a timer interrupt).
82// Call this while idle (in between matrix scans).
83// If the buffer is dirty, it will update the driver with the buffer.
84void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index);
85void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index);
86void is31fl3741_set_scaling_registers(const is31_led *pled, uint8_t value);
87
88void is31fl3741_set_pwm_buffer(const is31_led *pled, uint8_t value);
89
90#define IS31FL3741_PUR_0R 0x00 // No PUR resistor
91#define IS31FL3741_PUR_05KR 0x01 // 0.5k Ohm resistor
92#define IS31FL3741_PUR_1KR 0x02 // 1.0k Ohm resistor
93#define IS31FL3741_PUR_2KR 0x03 // 2.0k Ohm resistor
94#define IS31FL3741_PUR_4KR 0x04 // 4.0k Ohm resistor
95#define IS31FL3741_PUR_8KR 0x05 // 8.0k Ohm resistor
96#define IS31FL3741_PUR_16KR 0x06 // 16k Ohm resistor
97#define IS31FL3741_PUR_32KR 0x07 // 32k Ohm resistor
98
99#define IS31FL3741_PWM_FREQUENCY_29K_HZ 0b0000
100#define IS31FL3741_PWM_FREQUENCY_3K6_HZ 0b0011
101#define IS31FL3741_PWM_FREQUENCY_1K8_HZ 0b0111
102#define IS31FL3741_PWM_FREQUENCY_900_HZ 0b1011
103
104#define CS1_SW1 0x00
105#define CS2_SW1 0x01
106#define CS3_SW1 0x02
107#define CS4_SW1 0x03
108#define CS5_SW1 0x04
109#define CS6_SW1 0x05
110#define CS7_SW1 0x06
111#define CS8_SW1 0x07
112#define CS9_SW1 0x08
113#define CS10_SW1 0x09
114#define CS11_SW1 0x0A
115#define CS12_SW1 0x0B
116#define CS13_SW1 0x0C
117#define CS14_SW1 0x0D
118#define CS15_SW1 0x0E
119#define CS16_SW1 0x0F
120#define CS17_SW1 0x10
121#define CS18_SW1 0x11
122#define CS19_SW1 0x12
123#define CS20_SW1 0x13
124#define CS21_SW1 0x14
125#define CS22_SW1 0x15
126#define CS23_SW1 0x16
127#define CS24_SW1 0x17
128#define CS25_SW1 0x18
129#define CS26_SW1 0x19
130#define CS27_SW1 0x1A
131#define CS28_SW1 0x1B
132#define CS29_SW1 0x1C
133#define CS30_SW1 0x1D
134
135#define CS1_SW2 0x1E
136#define CS2_SW2 0x1F
137#define CS3_SW2 0x20
138#define CS4_SW2 0x21
139#define CS5_SW2 0x22
140#define CS6_SW2 0x23
141#define CS7_SW2 0x24
142#define CS8_SW2 0x25
143#define CS9_SW2 0x26
144#define CS10_SW2 0x27
145#define CS11_SW2 0x28
146#define CS12_SW2 0x29
147#define CS13_SW2 0x2A
148#define CS14_SW2 0x2B
149#define CS15_SW2 0x2C
150#define CS16_SW2 0x2D
151#define CS17_SW2 0x2E
152#define CS18_SW2 0x2F
153#define CS19_SW2 0x30
154#define CS20_SW2 0x31
155#define CS21_SW2 0x32
156#define CS22_SW2 0x33
157#define CS23_SW2 0x34
158#define CS24_SW2 0x35
159#define CS25_SW2 0x36
160#define CS26_SW2 0x37
161#define CS27_SW2 0x38
162#define CS28_SW2 0x39
163#define CS29_SW2 0x3A
164#define CS30_SW2 0x3B
165
166#define CS1_SW3 0x3C
167#define CS2_SW3 0x3D
168#define CS3_SW3 0x3E
169#define CS4_SW3 0x3F
170#define CS5_SW3 0x40
171#define CS6_SW3 0x41
172#define CS7_SW3 0x42
173#define CS8_SW3 0x43
174#define CS9_SW3 0x44
175#define CS10_SW3 0x45
176#define CS11_SW3 0x46
177#define CS12_SW3 0x47
178#define CS13_SW3 0x48
179#define CS14_SW3 0x49
180#define CS15_SW3 0x4A
181#define CS16_SW3 0x4B
182#define CS17_SW3 0x4C
183#define CS18_SW3 0x4D
184#define CS19_SW3 0x4E
185#define CS20_SW3 0x4F
186#define CS21_SW3 0x50
187#define CS22_SW3 0x51
188#define CS23_SW3 0x52
189#define CS24_SW3 0x53
190#define CS25_SW3 0x54
191#define CS26_SW3 0x55
192#define CS27_SW3 0x56
193#define CS28_SW3 0x57
194#define CS29_SW3 0x58
195#define CS30_SW3 0x59
196
197#define CS1_SW4 0x5A
198#define CS2_SW4 0x5B
199#define CS3_SW4 0x5C
200#define CS4_SW4 0x5D
201#define CS5_SW4 0x5E
202#define CS6_SW4 0x5F
203#define CS7_SW4 0x60
204#define CS8_SW4 0x61
205#define CS9_SW4 0x62
206#define CS10_SW4 0x63
207#define CS11_SW4 0x64
208#define CS12_SW4 0x65
209#define CS13_SW4 0x66
210#define CS14_SW4 0x67
211#define CS15_SW4 0x68
212#define CS16_SW4 0x69
213#define CS17_SW4 0x6A
214#define CS18_SW4 0x6B
215#define CS19_SW4 0x6C
216#define CS20_SW4 0x6D
217#define CS21_SW4 0x6E
218#define CS22_SW4 0x6F
219#define CS23_SW4 0x70
220#define CS24_SW4 0x71
221#define CS25_SW4 0x72
222#define CS26_SW4 0x73
223#define CS27_SW4 0x74
224#define CS28_SW4 0x75
225#define CS29_SW4 0x76
226#define CS30_SW4 0x77
227
228#define CS1_SW5 0x78
229#define CS2_SW5 0x79
230#define CS3_SW5 0x7A
231#define CS4_SW5 0x7B
232#define CS5_SW5 0x7C
233#define CS6_SW5 0x7D
234#define CS7_SW5 0x7E
235#define CS8_SW5 0x7F
236#define CS9_SW5 0x80
237#define CS10_SW5 0x81
238#define CS11_SW5 0x82
239#define CS12_SW5 0x83
240#define CS13_SW5 0x84
241#define CS14_SW5 0x85
242#define CS15_SW5 0x86
243#define CS16_SW5 0x87
244#define CS17_SW5 0x88
245#define CS18_SW5 0x89
246#define CS19_SW5 0x8A
247#define CS20_SW5 0x8B
248#define CS21_SW5 0x8C
249#define CS22_SW5 0x8D
250#define CS23_SW5 0x8E
251#define CS24_SW5 0x8F
252#define CS25_SW5 0x90
253#define CS26_SW5 0x91
254#define CS27_SW5 0x92
255#define CS28_SW5 0x93
256#define CS29_SW5 0x94
257#define CS30_SW5 0x95
258
259#define CS1_SW6 0x96
260#define CS2_SW6 0x97
261#define CS3_SW6 0x98
262#define CS4_SW6 0x99
263#define CS5_SW6 0x9A
264#define CS6_SW6 0x9B
265#define CS7_SW6 0x9C
266#define CS8_SW6 0x9D
267#define CS9_SW6 0x9E
268#define CS10_SW6 0x9F
269#define CS11_SW6 0xA0
270#define CS12_SW6 0xA1
271#define CS13_SW6 0xA2
272#define CS14_SW6 0xA3
273#define CS15_SW6 0xA4
274#define CS16_SW6 0xA5
275#define CS17_SW6 0xA6
276#define CS18_SW6 0xA7
277#define CS19_SW6 0xA8
278#define CS20_SW6 0xA9
279#define CS21_SW6 0xAA
280#define CS22_SW6 0xAB
281#define CS23_SW6 0xAC
282#define CS24_SW6 0xAD
283#define CS25_SW6 0xAE
284#define CS26_SW6 0xAF
285#define CS27_SW6 0xB0
286#define CS28_SW6 0xB1
287#define CS29_SW6 0xB2
288#define CS30_SW6 0xB3
289
290#define CS1_SW7 0xB4
291#define CS2_SW7 0xB5
292#define CS3_SW7 0xB6
293#define CS4_SW7 0xB7
294#define CS5_SW7 0xB8
295#define CS6_SW7 0xB9
296#define CS7_SW7 0xBA
297#define CS8_SW7 0xBB
298#define CS9_SW7 0xBC
299#define CS10_SW7 0xBD
300#define CS11_SW7 0xBE
301#define CS12_SW7 0xBF
302#define CS13_SW7 0xC0
303#define CS14_SW7 0xC1
304#define CS15_SW7 0xC2
305#define CS16_SW7 0xC3
306#define CS17_SW7 0xC4
307#define CS18_SW7 0xC5
308#define CS19_SW7 0xC6
309#define CS20_SW7 0xC7
310#define CS21_SW7 0xC8
311#define CS22_SW7 0xC9
312#define CS23_SW7 0xCA
313#define CS24_SW7 0xCB
314#define CS25_SW7 0xCC
315#define CS26_SW7 0xCD
316#define CS27_SW7 0xCE
317#define CS28_SW7 0xCF
318#define CS29_SW7 0xD0
319#define CS30_SW7 0xD1
320
321#define CS1_SW8 0xD2
322#define CS2_SW8 0xD3
323#define CS3_SW8 0xD4
324#define CS4_SW8 0xD5
325#define CS5_SW8 0xD6
326#define CS6_SW8 0xD7
327#define CS7_SW8 0xD8
328#define CS8_SW8 0xD9
329#define CS9_SW8 0xDA
330#define CS10_SW8 0xDB
331#define CS11_SW8 0xDC
332#define CS12_SW8 0xDD
333#define CS13_SW8 0xDE
334#define CS14_SW8 0xDF
335#define CS15_SW8 0xE0
336#define CS16_SW8 0xE1
337#define CS17_SW8 0xE2
338#define CS18_SW8 0xE3
339#define CS19_SW8 0xE4
340#define CS20_SW8 0xE5
341#define CS21_SW8 0xE6
342#define CS22_SW8 0xE7
343#define CS23_SW8 0xE8
344#define CS24_SW8 0xE9
345#define CS25_SW8 0xEA
346#define CS26_SW8 0xEB
347#define CS27_SW8 0xEC
348#define CS28_SW8 0xED
349#define CS29_SW8 0xEE
350#define CS30_SW8 0xEF
351
352#define CS1_SW9 0xF0
353#define CS2_SW9 0xF1
354#define CS3_SW9 0xF2
355#define CS4_SW9 0xF3
356#define CS5_SW9 0xF4
357#define CS6_SW9 0xF5
358#define CS7_SW9 0xF6
359#define CS8_SW9 0xF7
360#define CS9_SW9 0xF8
361#define CS10_SW9 0xF9
362#define CS11_SW9 0xFA
363#define CS12_SW9 0xFB
364#define CS13_SW9 0xFC
365#define CS14_SW9 0xFD
366#define CS15_SW9 0xFE
367#define CS16_SW9 0xFF
368#define CS17_SW9 0x100
369#define CS18_SW9 0x101
370#define CS19_SW9 0x102
371#define CS20_SW9 0x103
372#define CS21_SW9 0x104
373#define CS22_SW9 0x105
374#define CS23_SW9 0x106
375#define CS24_SW9 0x107
376#define CS25_SW9 0x108
377#define CS26_SW9 0x109
378#define CS27_SW9 0x10A
379#define CS28_SW9 0x10B
380#define CS29_SW9 0x10C
381#define CS30_SW9 0x10D
382
383#define CS31_SW1 0x10E
384#define CS32_SW1 0x10F
385#define CS33_SW1 0x110
386#define CS34_SW1 0x111
387#define CS35_SW1 0x112
388#define CS36_SW1 0x113
389#define CS37_SW1 0x114
390#define CS38_SW1 0x115
391#define CS39_SW1 0x116
392
393#define CS31_SW2 0x117
394#define CS32_SW2 0x118
395#define CS33_SW2 0x119
396#define CS34_SW2 0x11A
397#define CS35_SW2 0x11B
398#define CS36_SW2 0x11C
399#define CS37_SW2 0x11D
400#define CS38_SW2 0x11E
401#define CS39_SW2 0x11F
402
403#define CS31_SW3 0x120
404#define CS32_SW3 0x121
405#define CS33_SW3 0x122
406#define CS34_SW3 0x123
407#define CS35_SW3 0x124
408#define CS36_SW3 0x125
409#define CS37_SW3 0x126
410#define CS38_SW3 0x127
411#define CS39_SW3 0x128
412
413#define CS31_SW4 0x129
414#define CS32_SW4 0x12A
415#define CS33_SW4 0x12B
416#define CS34_SW4 0x12C
417#define CS35_SW4 0x12D
418#define CS36_SW4 0x12E
419#define CS37_SW4 0x12F
420#define CS38_SW4 0x130
421#define CS39_SW4 0x131
422
423#define CS31_SW5 0x132
424#define CS32_SW5 0x133
425#define CS33_SW5 0x134
426#define CS34_SW5 0x135
427#define CS35_SW5 0x136
428#define CS36_SW5 0x137
429#define CS37_SW5 0x138
430#define CS38_SW5 0x139
431#define CS39_SW5 0x13A
432
433#define CS31_SW6 0x13B
434#define CS32_SW6 0x13C
435#define CS33_SW6 0x13D
436#define CS34_SW6 0x13E
437#define CS35_SW6 0x13F
438#define CS36_SW6 0x140
439#define CS37_SW6 0x141
440#define CS38_SW6 0x142
441#define CS39_SW6 0x143
442
443#define CS31_SW7 0x144
444#define CS32_SW7 0x145
445#define CS33_SW7 0x146
446#define CS34_SW7 0x147
447#define CS35_SW7 0x148
448#define CS36_SW7 0x149
449#define CS37_SW7 0x14A
450#define CS38_SW7 0x14B
451#define CS39_SW7 0x14C
452
453#define CS31_SW8 0x14D
454#define CS32_SW8 0x14E
455#define CS33_SW8 0x14F
456#define CS34_SW8 0x150
457#define CS35_SW8 0x151
458#define CS36_SW8 0x152
459#define CS37_SW8 0x153
460#define CS38_SW8 0x154
461#define CS39_SW8 0x155
462
463#define CS31_SW9 0x156
464#define CS32_SW9 0x157
465#define CS33_SW9 0x158
466#define CS34_SW9 0x159
467#define CS35_SW9 0x15A
468#define CS36_SW9 0x15B
469#define CS37_SW9 0x15C
470#define CS38_SW9 0x15D
471#define CS39_SW9 0x15E