summaryrefslogtreecommitdiff
path: root/drivers/led
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2024-01-01 12:40:35 +1100
committerGitHub <noreply@github.com>2024-01-01 12:40:35 +1100
commite1c0bd8a7c8d86ca573b430d5a914cf649c8d9b2 (patch)
treeb433888c667a12fab56be926a620e902ec22343a /drivers/led
parent709d07aebc38e6edd4e0f41d80792a7230c5180f (diff)
LED drivers: extract IS31FL3742A from IS31COMMON (#22620)
Diffstat (limited to 'drivers/led')
-rw-r--r--drivers/led/issi/is31fl3742a-simple.c206
-rw-r--r--drivers/led/issi/is31fl3742a-simple.h (renamed from drivers/led/issi/is31fl3742.h)158
-rw-r--r--drivers/led/issi/is31fl3742a.c210
-rw-r--r--drivers/led/issi/is31fl3742a.h299
-rw-r--r--drivers/led/issi/is31flcommon.h4
5 files changed, 794 insertions, 83 deletions
diff --git a/drivers/led/issi/is31fl3742a-simple.c b/drivers/led/issi/is31fl3742a-simple.c
new file mode 100644
index 0000000000..ee6e8741b9
--- /dev/null
+++ b/drivers/led/issi/is31fl3742a-simple.c
@@ -0,0 +1,206 @@
1#include "is31fl3742a-simple.h"
2#include <string.h>
3#include "i2c_master.h"
4#include "wait.h"
5
6#define IS31FL3742A_PWM_REGISTER_COUNT 180
7#define IS31FL3742A_SCALING_REGISTER_COUNT 180
8
9#ifndef IS31FL3742A_I2C_TIMEOUT
10# define IS31FL3742A_I2C_TIMEOUT 100
11#endif
12
13#ifndef IS31FL3742A_I2C_PERSISTENCE
14# define IS31FL3742A_I2C_PERSISTENCE 0
15#endif
16
17#ifndef IS31FL3742A_CONFIGURATION
18# define IS31FL3742A_CONFIGURATION 0x31
19#endif
20
21#ifndef IS31FL3742A_PWM_FREQUENCY
22# define IS31FL3742A_PWM_FREQUENCY IS31FL3742A_PWM_FREQUENCY_29K_HZ
23#endif
24
25#ifndef IS31FL3742A_SW_PULLDOWN
26# define IS31FL3742A_SW_PULLDOWN IS31FL3742A_PDR_8K_OHM
27#endif
28
29#ifndef IS31FL3742A_CS_PULLUP
30# define IS31FL3742A_CS_PULLUP IS31FL3742A_PUR_8K_OHM
31#endif
32
33#ifndef IS31FL3742A_GLOBAL_CURRENT
34# define IS31FL3742A_GLOBAL_CURRENT 0xFF
35#endif
36
37uint8_t i2c_transfer_buffer[20] = {0xFF};
38
39uint8_t g_pwm_buffer[IS31FL3742A_DRIVER_COUNT][IS31FL3742A_PWM_REGISTER_COUNT];
40bool g_pwm_buffer_update_required[IS31FL3742A_DRIVER_COUNT] = {false};
41bool g_scaling_registers_update_required[IS31FL3742A_DRIVER_COUNT] = {false};
42
43uint8_t g_scaling_registers[IS31FL3742A_DRIVER_COUNT][IS31FL3742A_SCALING_REGISTER_COUNT];
44
45void is31fl3742a_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 IS31FL3742A_I2C_PERSISTENCE > 0
50 for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
51 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3742A_I2C_TIMEOUT) == 0) break;
52 }
53#else
54 i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3742A_I2C_TIMEOUT);
55#endif
56}
57
58void is31fl3742a_select_page(uint8_t addr, uint8_t page) {
59 is31fl3742a_write_register(addr, IS31FL3742A_REG_COMMAND_WRITE_LOCK, IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC);
60 is31fl3742a_write_register(addr, IS31FL3742A_REG_COMMAND, page);
61}
62
63void is31fl3742a_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 < IS31FL3742A_PWM_REGISTER_COUNT; i += 16) {
71 i2c_transfer_buffer[0] = i;
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 IS31FL3742A_I2C_PERSISTENCE > 0
78 for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
79 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3742A_I2C_TIMEOUT) != 0) break;
80 }
81#else
82 i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3742A_I2C_TIMEOUT);
83#endif
84 }
85}
86
87void is31fl3742a_init_drivers(void) {
88 i2c_init();
89
90 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_1);
91#if defined(IS31FL3742A_I2C_ADDRESS_2)
92 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_2);
93# if defined(IS31FL3742A_I2C_ADDRESS_3)
94 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_3);
95# if defined(IS31FL3742A_I2C_ADDRESS_4)
96 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_4);
97# endif
98# endif
99#endif
100
101 for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
102 is31fl3742a_set_scaling_register(i, 0xFF);
103 }
104
105 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_1, 0);
106#if defined(IS31FL3742A_I2C_ADDRESS_2)
107 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_2, 1);
108# if defined(IS31FL3742A_I2C_ADDRESS_3)
109 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_3, 2);
110# if defined(IS31FL3742A_I2C_ADDRESS_4)
111 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_4, 3);
112# endif
113# endif
114#endif
115}
116
117void is31fl3742a_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 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_SCALING);
124
125 // Turn off all LEDs.
126 for (int i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
127 is31fl3742a_write_register(addr, i, 0x00);
128 }
129
130 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_PWM);
131
132 for (int i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i++) {
133 is31fl3742a_write_register(addr, i, 0x00);
134 }
135
136 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_FUNCTION);
137
138 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_PULLDOWNUP, (IS31FL3742A_SW_PULLDOWN << 4) | IS31FL3742A_CS_PULLUP);
139 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3742A_GLOBAL_CURRENT);
140 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3742A_PWM_FREQUENCY & 0b0111));
141 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_CONFIGURATION, IS31FL3742A_CONFIGURATION);
142
143 // Wait 10ms to ensure the device has woken up.
144 wait_ms(10);
145}
146
147void is31fl3742a_set_value(int index, uint8_t value) {
148 is31fl3742a_led_t led;
149 if (index >= 0 && index < IS31FL3742A_LED_COUNT) {
150 memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
151
152 if (g_pwm_buffer[led.driver][led.v] == value) {
153 return;
154 }
155 g_pwm_buffer[led.driver][led.v] = value;
156 g_pwm_buffer_update_required[led.driver] = true;
157 }
158}
159
160void is31fl3742a_set_value_all(uint8_t value) {
161 for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
162 is31fl3742a_set_value(i, value);
163 }
164}
165
166void is31fl3742a_set_scaling_register(uint8_t index, uint8_t value) {
167 is31fl3742a_led_t led;
168 memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
169
170 g_scaling_registers[led.driver][led.v] = value;
171
172 g_scaling_registers_update_required[led.driver] = true;
173}
174
175void is31fl3742a_update_pwm_buffers(uint8_t addr, uint8_t index) {
176 if (g_pwm_buffer_update_required[index]) {
177 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_PWM);
178
179 is31fl3742a_write_pwm_buffer(addr, g_pwm_buffer[index]);
180 g_pwm_buffer_update_required[index] = false;
181 }
182}
183
184void is31fl3742a_update_scaling_registers(uint8_t addr, uint8_t index) {
185 if (g_scaling_registers_update_required[index]) {
186 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_SCALING);
187
188 for (int i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
189 is31fl3742a_write_register(addr, i, g_scaling_registers[index][i]);
190 }
191 g_scaling_registers_update_required[index] = false;
192 }
193}
194
195void is31fl3742a_flush(void) {
196 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_1, 0);
197#if defined(IS31FL3742A_I2C_ADDRESS_2)
198 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_2, 1);
199# if defined(IS31FL3742A_I2C_ADDRESS_3)
200 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_3, 2);
201# if defined(IS31FL3742A_I2C_ADDRESS_4)
202 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_4, 3);
203# endif
204# endif
205#endif
206}
diff --git a/drivers/led/issi/is31fl3742.h b/drivers/led/issi/is31fl3742a-simple.h
index c96f12d0f1..04614e4f6e 100644
--- a/drivers/led/issi/is31fl3742.h
+++ b/drivers/led/issi/is31fl3742a-simple.h
@@ -20,98 +20,96 @@
20 20
21#pragma once 21#pragma once
22 22
23// This is a 7-bit address, that gets left-shifted and bit 0 23#include <stdint.h>
24// set to 0 for write, 1 for read (as per I2C protocol) 24#include <stdbool.h>
25// The address will vary depending on your wiring: 25#include "progmem.h"
26// 00 <-> GND 26#include "util.h"
27// 01 <-> SCL
28// 10 <-> SDA
29// 11 <-> VCC
30// ADDR represents A1:A0 of the 7-bit address.
31// The result is: 0b01100(ADDR)
32#ifndef DRIVER_ADDR_1
33# define DRIVER_ADDR_1 0b0110000
34#endif
35 27
36// Command Registers 28#define IS31FL3742A_REG_INTERRUPT_MASK 0xF0
37#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE 29#define IS31FL3742A_REG_INTERRUPT_STATUS 0xF1
38#define ISSI_COMMANDREGISTER 0xFD 30#define IS31FL3742A_REG_ID 0xFC
39#define ISSI_IDREGISTER 0xFC
40#define ISSI_REGISTER_UNLOCK 0xC5
41 31
42// Response Registers 32#define IS31FL3742A_REG_COMMAND 0xFD
43#define ISSI_PAGE_PWM 0x00
44#define ISSI_PAGE_SCALING 0x02
45#define ISSI_PAGE_FUNCTION 0x04
46 33
47// Registers under Function Register 34#define IS31FL3742A_COMMAND_PWM 0x00
48#define ISSI_REG_CONFIGURATION 0x00 35#define IS31FL3742A_COMMAND_SCALING 0x02
49#define ISSI_REG_GLOBALCURRENT 0x01 36#define IS31FL3742A_COMMAND_FUNCTION 0x04
50#define ISSI_REG_PULLDOWNUP 0x02
51#define ISSI_REG_SSR 0x41
52#define ISSI_REG_RESET 0x3F
53#define ISSI_REG_PWM_SET 0x36
54 37
55// Set defaults for Function Registers 38#define IS31FL3742A_FUNCTION_REG_CONFIGURATION 0x00
56#ifndef ISSI_CONFIGURATION 39#define IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT 0x01
57# define ISSI_CONFIGURATION 0x31 40#define IS31FL3742A_FUNCTION_REG_PULLDOWNUP 0x02
58#endif 41#define IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY 0x36
59#ifndef ISSI_GLOBALCURRENT 42#define IS31FL3742A_FUNCTION_REG_RESET 0x3F
60# define ISSI_GLOBALCURRENT 0xFF 43#define IS31FL3742A_FUNCTION_REG_SPREAD_SPECTRUM 0x41
61#endif
62#ifndef ISSI_PULLDOWNUP
63# define ISSI_PULLDOWNUP 0x55
64#endif
65#ifndef ISSI_PWM_SET
66# define ISSI_PWM_SET 0x00
67#endif
68 44
69// Set defaults for Spread Spectrum Register 45#define IS31FL3742A_REG_COMMAND_WRITE_LOCK 0xFE
70#ifndef ISSI_SSR_1 46#define IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC 0xC5
71# define ISSI_SSR_1 0x00
72#endif
73#ifndef ISSI_SSR_2
74# define ISSI_SSR_2 0x00
75#endif
76#ifndef ISSI_SSR_3
77# define ISSI_SSR_3 0x00
78#endif
79#ifndef ISSI_SSR_4
80# define ISSI_SSR_4 0x00
81#endif
82 47
83// Set defaults for Scaling registers 48#define IS31FL3742A_I2C_ADDRESS_GND 0x30
84#ifndef ISSI_SCAL_RED 49#define IS31FL3742A_I2C_ADDRESS_SCL 0x31
85# define ISSI_SCAL_RED 0xFF 50#define IS31FL3742A_I2C_ADDRESS_SDA 0x32
86#endif 51#define IS31FL3742A_I2C_ADDRESS_VCC 0x33
87#ifndef ISSI_SCAL_BLUE 52
88# define ISSI_SCAL_BLUE 0xFF 53#if defined(LED_MATRIX_IS31FL3742A)
89#endif 54# define IS31FL3742A_LED_COUNT LED_MATRIX_LED_COUNT
90#ifndef ISSI_SCAL_GREEN
91# define ISSI_SCAL_GREEN 0xFF
92#endif 55#endif
93#define ISSI_SCAL_RED_OFF 0x00
94#define ISSI_SCAL_GREEN_OFF 0x00
95#define ISSI_SCAL_BLUE_OFF 0x00
96 56
97#ifndef ISSI_SCAL_LED 57#if defined(IS31FL3742A_I2C_ADDRESS_4)
98# define ISSI_SCAL_LED 0xFF 58# define IS31FL3742A_DRIVER_COUNT 4
59#elif defined(IS31FL3742A_I2C_ADDRESS_3)
60# define IS31FL3742A_DRIVER_COUNT 3
61#elif defined(IS31FL3742A_I2C_ADDRESS_2)
62# define IS31FL3742A_DRIVER_COUNT 2
63#elif defined(IS31FL3742A_I2C_ADDRESS_1)
64# define IS31FL3742A_DRIVER_COUNT 1
99#endif 65#endif
100#define ISSI_SCAL_LED_OFF 0x00
101 66
102// Set buffer sizes 67typedef struct is31fl3742a_led_t {
103#define ISSI_MAX_LEDS 180 68 uint8_t driver : 2;
104#define ISSI_SCALING_SIZE 180 69 uint8_t v;
105#define ISSI_PWM_TRF_SIZE 18 70} PACKED is31fl3742a_led_t;
106#define ISSI_SCALING_TRF_SIZE 18 71
72extern const is31fl3742a_led_t PROGMEM g_is31fl3742a_leds[IS31FL3742A_LED_COUNT];
73
74void is31fl3742a_init_drivers(void);
75void is31fl3742a_init(uint8_t addr);
76void is31fl3742a_write_register(uint8_t addr, uint8_t reg, uint8_t data);
77void is31fl3742a_select_page(uint8_t addr, uint8_t page);
78void is31fl3742a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
79
80void is31fl3742a_set_value(int index, uint8_t value);
81void is31fl3742a_set_value_all(uint8_t value);
82
83void is31fl3742a_set_scaling_register(uint8_t index, uint8_t value);
84
85void is31fl3742a_update_pwm_buffers(uint8_t addr, uint8_t index);
86void is31fl3742a_update_scaling_registers(uint8_t addr, uint8_t index);
87
88void is31fl3742a_flush(void);
89
90#define IS31FL3742A_PDR_0_OHM 0b000 // No pull-down resistor
91#define IS31FL3742A_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
92#define IS31FL3742A_PDR_1K_OHM 0b010 // 1 kOhm resistor
93#define IS31FL3742A_PDR_2K_OHM 0b011 // 2 kOhm resistor
94#define IS31FL3742A_PDR_4K_OHM 0b100 // 4 kOhm resistor
95#define IS31FL3742A_PDR_8K_OHM 0b101 // 8 kOhm resistor
96#define IS31FL3742A_PDR_16K_OHM 0b110 // 16 kOhm resistor
97#define IS31FL3742A_PDR_32K_OHM 0b111 // 32 kOhm resistor
98
99#define IS31FL3742A_PUR_0_OHM 0b000 // No pull-up resistor
100#define IS31FL3742A_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
101#define IS31FL3742A_PUR_1K_OHM 0b010 // 1 kOhm resistor
102#define IS31FL3742A_PUR_2K_OHM 0b011 // 2 kOhm resistor
103#define IS31FL3742A_PUR_4K_OHM 0b100 // 4 kOhm resistor
104#define IS31FL3742A_PUR_8K_OHM 0b101 // 8 kOhm resistor
105#define IS31FL3742A_PUR_16K_OHM 0b110 // 16 kOhm resistor
106#define IS31FL3742A_PUR_32K_OHM 0b111 // 32 kOhm resistor
107 107
108// Location of 1st bit for PWM and Scaling registers 108#define IS31FL3742A_PWM_FREQUENCY_29K_HZ 0b0000
109#define ISSI_PWM_REG_1ST 0x00 109#define IS31FL3742A_PWM_FREQUENCY_3K6_HZ 0b0011
110#define ISSI_SCL_REG_1ST 0x00 110#define IS31FL3742A_PWM_FREQUENCY_1K8_HZ 0b0111
111#define IS31FL3742A_PWM_FREQUENCY_900_HZ 0b1011
111 112
112// Map CS SW locations to order in PWM / Scaling buffers
113// This matches the ORDER in the Datasheet Register not the POSITION
114// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
115#define CS1_SW1 0x00 113#define CS1_SW1 0x00
116#define CS2_SW1 0x01 114#define CS2_SW1 0x01
117#define CS3_SW1 0x02 115#define CS3_SW1 0x02
diff --git a/drivers/led/issi/is31fl3742a.c b/drivers/led/issi/is31fl3742a.c
new file mode 100644
index 0000000000..766ba0ba34
--- /dev/null
+++ b/drivers/led/issi/is31fl3742a.c
@@ -0,0 +1,210 @@
1#include "is31fl3742a.h"
2#include <string.h>
3#include "i2c_master.h"
4#include "wait.h"
5
6#define IS31FL3742A_PWM_REGISTER_COUNT 180
7#define IS31FL3742A_SCALING_REGISTER_COUNT 180
8
9#ifndef IS31FL3742A_I2C_TIMEOUT
10# define IS31FL3742A_I2C_TIMEOUT 100
11#endif
12
13#ifndef IS31FL3742A_I2C_PERSISTENCE
14# define IS31FL3742A_I2C_PERSISTENCE 0
15#endif
16
17#ifndef IS31FL3742A_CONFIGURATION
18# define IS31FL3742A_CONFIGURATION 0x31
19#endif
20
21#ifndef IS31FL3742A_PWM_FREQUENCY
22# define IS31FL3742A_PWM_FREQUENCY IS31FL3742A_PWM_FREQUENCY_29K_HZ
23#endif
24
25#ifndef IS31FL3742A_SW_PULLDOWN
26# define IS31FL3742A_SW_PULLDOWN IS31FL3742A_PDR_8K_OHM
27#endif
28
29#ifndef IS31FL3742A_CS_PULLUP
30# define IS31FL3742A_CS_PULLUP IS31FL3742A_PUR_8K_OHM
31#endif
32
33#ifndef IS31FL3742A_GLOBAL_CURRENT
34# define IS31FL3742A_GLOBAL_CURRENT 0xFF
35#endif
36
37uint8_t i2c_transfer_buffer[20] = {0xFF};
38
39uint8_t g_pwm_buffer[IS31FL3742A_DRIVER_COUNT][IS31FL3742A_PWM_REGISTER_COUNT];
40bool g_pwm_buffer_update_required[IS31FL3742A_DRIVER_COUNT] = {false};
41bool g_scaling_registers_update_required[IS31FL3742A_DRIVER_COUNT] = {false};
42
43uint8_t g_scaling_registers[IS31FL3742A_DRIVER_COUNT][IS31FL3742A_SCALING_REGISTER_COUNT];
44
45void is31fl3742a_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 IS31FL3742A_I2C_PERSISTENCE > 0
50 for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
51 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3742A_I2C_TIMEOUT) == 0) break;
52 }
53#else
54 i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3742A_I2C_TIMEOUT);
55#endif
56}
57
58void is31fl3742a_select_page(uint8_t addr, uint8_t page) {
59 is31fl3742a_write_register(addr, IS31FL3742A_REG_COMMAND_WRITE_LOCK, IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC);
60 is31fl3742a_write_register(addr, IS31FL3742A_REG_COMMAND, page);
61}
62
63void is31fl3742a_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 < IS31FL3742A_PWM_REGISTER_COUNT; i += 16) {
71 i2c_transfer_buffer[0] = i;
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 IS31FL3742A_I2C_PERSISTENCE > 0
78 for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
79 if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3742A_I2C_TIMEOUT) != 0) break;
80 }
81#else
82 i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3742A_I2C_TIMEOUT);
83#endif
84 }
85}
86
87void is31fl3742a_init_drivers(void) {
88 i2c_init();
89
90 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_1);
91#if defined(IS31FL3742A_I2C_ADDRESS_2)
92 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_2);
93# if defined(IS31FL3742A_I2C_ADDRESS_3)
94 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_3);
95# if defined(IS31FL3742A_I2C_ADDRESS_4)
96 is31fl3742a_init(IS31FL3742A_I2C_ADDRESS_4);
97# endif
98# endif
99#endif
100
101 for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
102 is31fl3742a_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
103 }
104
105 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_1, 0);
106#if defined(IS31FL3742A_I2C_ADDRESS_2)
107 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_2, 1);
108# if defined(IS31FL3742A_I2C_ADDRESS_3)
109 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_3, 2);
110# if defined(IS31FL3742A_I2C_ADDRESS_4)
111 is31fl3742a_update_scaling_registers(IS31FL3742A_I2C_ADDRESS_4, 3);
112# endif
113# endif
114#endif
115}
116
117void is31fl3742a_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 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_SCALING);
124
125 // Turn off all LEDs.
126 for (int i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
127 is31fl3742a_write_register(addr, i, 0x00);
128 }
129
130 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_PWM);
131
132 for (int i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i++) {
133 is31fl3742a_write_register(addr, i, 0x00);
134 }
135
136 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_FUNCTION);
137
138 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_PULLDOWNUP, (IS31FL3742A_SW_PULLDOWN << 4) | IS31FL3742A_CS_PULLUP);
139 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3742A_GLOBAL_CURRENT);
140 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3742A_PWM_FREQUENCY & 0b0111));
141 is31fl3742a_write_register(addr, IS31FL3742A_FUNCTION_REG_CONFIGURATION, IS31FL3742A_CONFIGURATION);
142
143 // Wait 10ms to ensure the device has woken up.
144 wait_ms(10);
145}
146
147void is31fl3742a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
148 is31fl3742a_led_t led;
149 if (index >= 0 && index < IS31FL3742A_LED_COUNT) {
150 memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
151
152 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) {
153 return;
154 }
155 g_pwm_buffer[led.driver][led.r] = red;
156 g_pwm_buffer[led.driver][led.g] = green;
157 g_pwm_buffer[led.driver][led.b] = blue;
158 g_pwm_buffer_update_required[led.driver] = true;
159 }
160}
161
162void is31fl3742a_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
163 for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
164 is31fl3742a_set_color(i, red, green, blue);
165 }
166}
167
168void is31fl3742a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
169 is31fl3742a_led_t led;
170 memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
171
172 g_scaling_registers[led.driver][led.r] = red;
173 g_scaling_registers[led.driver][led.g] = green;
174 g_scaling_registers[led.driver][led.b] = blue;
175
176 g_scaling_registers_update_required[led.driver] = true;
177}
178
179void is31fl3742a_update_pwm_buffers(uint8_t addr, uint8_t index) {
180 if (g_pwm_buffer_update_required[index]) {
181 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_PWM);
182
183 is31fl3742a_write_pwm_buffer(addr, g_pwm_buffer[index]);
184 g_pwm_buffer_update_required[index] = false;
185 }
186}
187
188void is31fl3742a_update_scaling_registers(uint8_t addr, uint8_t index) {
189 if (g_scaling_registers_update_required[index]) {
190 is31fl3742a_select_page(addr, IS31FL3742A_COMMAND_SCALING);
191
192 for (int i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
193 is31fl3742a_write_register(addr, i, g_scaling_registers[index][i]);
194 }
195 g_scaling_registers_update_required[index] = false;
196 }
197}
198
199void is31fl3742a_flush(void) {
200 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_1, 0);
201#if defined(IS31FL3742A_I2C_ADDRESS_2)
202 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_2, 1);
203# if defined(IS31FL3742A_I2C_ADDRESS_3)
204 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_3, 2);
205# if defined(IS31FL3742A_I2C_ADDRESS_4)
206 is31fl3742a_update_pwm_buffers(IS31FL3742A_I2C_ADDRESS_4, 3);
207# endif
208# endif
209#endif
210}
diff --git a/drivers/led/issi/is31fl3742a.h b/drivers/led/issi/is31fl3742a.h
new file mode 100644
index 0000000000..304dd5925b
--- /dev/null
+++ b/drivers/led/issi/is31fl3742a.h
@@ -0,0 +1,299 @@
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 IS31FL3742A_REG_INTERRUPT_MASK 0xF0
29#define IS31FL3742A_REG_INTERRUPT_STATUS 0xF1
30#define IS31FL3742A_REG_ID 0xFC
31
32#define IS31FL3742A_REG_COMMAND 0xFD
33
34#define IS31FL3742A_COMMAND_PWM 0x00
35#define IS31FL3742A_COMMAND_SCALING 0x02
36#define IS31FL3742A_COMMAND_FUNCTION 0x04
37
38#define IS31FL3742A_FUNCTION_REG_CONFIGURATION 0x00
39#define IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT 0x01
40#define IS31FL3742A_FUNCTION_REG_PULLDOWNUP 0x02
41#define IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY 0x36
42#define IS31FL3742A_FUNCTION_REG_RESET 0x3F
43#define IS31FL3742A_FUNCTION_REG_SPREAD_SPECTRUM 0x41
44
45#define IS31FL3742A_REG_COMMAND_WRITE_LOCK 0xFE
46#define IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC 0xC5
47
48#define IS31FL3742A_I2C_ADDRESS_GND 0x30
49#define IS31FL3742A_I2C_ADDRESS_SCL 0x31
50#define IS31FL3742A_I2C_ADDRESS_SDA 0x32
51#define IS31FL3742A_I2C_ADDRESS_VCC 0x33
52
53#if defined(RGB_MATRIX_IS31FL3742A)
54# define IS31FL3742A_LED_COUNT RGB_MATRIX_LED_COUNT
55#endif
56
57#if defined(IS31FL3742A_I2C_ADDRESS_4)
58# define IS31FL3742A_DRIVER_COUNT 4
59#elif defined(IS31FL3742A_I2C_ADDRESS_3)
60# define IS31FL3742A_DRIVER_COUNT 3
61#elif defined(IS31FL3742A_I2C_ADDRESS_2)
62# define IS31FL3742A_DRIVER_COUNT 2
63#elif defined(IS31FL3742A_I2C_ADDRESS_1)
64# define IS31FL3742A_DRIVER_COUNT 1
65#endif
66
67typedef struct is31fl3742a_led_t {
68 uint8_t driver : 2;
69 uint8_t r;
70 uint8_t g;
71 uint8_t b;
72} PACKED is31fl3742a_led_t;
73
74extern const is31fl3742a_led_t PROGMEM g_is31fl3742a_leds[IS31FL3742A_LED_COUNT];
75
76void is31fl3742a_init_drivers(void);
77void is31fl3742a_init(uint8_t addr);
78void is31fl3742a_write_register(uint8_t addr, uint8_t reg, uint8_t data);
79void is31fl3742a_select_page(uint8_t addr, uint8_t page);
80void is31fl3742a_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
81
82void is31fl3742a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
83void is31fl3742a_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
84
85void is31fl3742a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
86
87void is31fl3742a_update_pwm_buffers(uint8_t addr, uint8_t index);
88void is31fl3742a_update_scaling_registers(uint8_t addr, uint8_t index);
89
90void is31fl3742a_flush(void);
91
92#define IS31FL3742A_PDR_0_OHM 0b000 // No pull-down resistor
93#define IS31FL3742A_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
94#define IS31FL3742A_PDR_1K_OHM 0b010 // 1 kOhm resistor
95#define IS31FL3742A_PDR_2K_OHM 0b011 // 2 kOhm resistor
96#define IS31FL3742A_PDR_4K_OHM 0b100 // 4 kOhm resistor
97#define IS31FL3742A_PDR_8K_OHM 0b101 // 8 kOhm resistor
98#define IS31FL3742A_PDR_16K_OHM 0b110 // 16 kOhm resistor
99#define IS31FL3742A_PDR_32K_OHM 0b111 // 32 kOhm resistor
100
101#define IS31FL3742A_PUR_0_OHM 0b000 // No pull-up resistor
102#define IS31FL3742A_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
103#define IS31FL3742A_PUR_1K_OHM 0b010 // 1 kOhm resistor
104#define IS31FL3742A_PUR_2K_OHM 0b011 // 2 kOhm resistor
105#define IS31FL3742A_PUR_4K_OHM 0b100 // 4 kOhm resistor
106#define IS31FL3742A_PUR_8K_OHM 0b101 // 8 kOhm resistor
107#define IS31FL3742A_PUR_16K_OHM 0b110 // 16 kOhm resistor
108#define IS31FL3742A_PUR_32K_OHM 0b111 // 32 kOhm resistor
109
110#define IS31FL3742A_PWM_FREQUENCY_29K_HZ 0b0000
111#define IS31FL3742A_PWM_FREQUENCY_3K6_HZ 0b0011
112#define IS31FL3742A_PWM_FREQUENCY_1K8_HZ 0b0111
113#define IS31FL3742A_PWM_FREQUENCY_900_HZ 0b1011
114
115#define CS1_SW1 0x00
116#define CS2_SW1 0x01
117#define CS3_SW1 0x02
118#define CS4_SW1 0x03
119#define CS5_SW1 0x04
120#define CS6_SW1 0x05
121#define CS7_SW1 0x06
122#define CS8_SW1 0x07
123#define CS9_SW1 0x08
124#define CS10_SW1 0x09
125#define CS11_SW1 0x0A
126#define CS12_SW1 0x0B
127#define CS13_SW1 0x0C
128#define CS14_SW1 0x0D
129#define CS15_SW1 0x0E
130#define CS16_SW1 0x0F
131#define CS17_SW1 0x10
132#define CS18_SW1 0x11
133#define CS19_SW1 0x12
134#define CS20_SW1 0x13
135#define CS21_SW1 0x14
136#define CS22_SW1 0x15
137#define CS23_SW1 0x16
138#define CS24_SW1 0x17
139#define CS25_SW1 0x18
140#define CS26_SW1 0x19
141#define CS27_SW1 0x1A
142#define CS28_SW1 0x1B
143#define CS29_SW1 0x1C
144#define CS30_SW1 0x1D
145
146#define CS1_SW2 0x1E
147#define CS2_SW2 0x1F
148#define CS3_SW2 0x20
149#define CS4_SW2 0x21
150#define CS5_SW2 0x22
151#define CS6_SW2 0x23
152#define CS7_SW2 0x24
153#define CS8_SW2 0x25
154#define CS9_SW2 0x26
155#define CS10_SW2 0x27
156#define CS11_SW2 0x28
157#define CS12_SW2 0x29
158#define CS13_SW2 0x2A
159#define CS14_SW2 0x2B
160#define CS15_SW2 0x2C
161#define CS16_SW2 0x2D
162#define CS17_SW2 0x2E
163#define CS18_SW2 0x2F
164#define CS19_SW2 0x30
165#define CS20_SW2 0x31
166#define CS21_SW2 0x32
167#define CS22_SW2 0x33
168#define CS23_SW2 0x34
169#define CS24_SW2 0x35
170#define CS25_SW2 0x36
171#define CS26_SW2 0x37
172#define CS27_SW2 0x38
173#define CS28_SW2 0x39
174#define CS29_SW2 0x3A
175#define CS30_SW2 0x3B
176
177#define CS1_SW3 0x3C
178#define CS2_SW3 0x3D
179#define CS3_SW3 0x3E
180#define CS4_SW3 0x3F
181#define CS5_SW3 0x40
182#define CS6_SW3 0x41
183#define CS7_SW3 0x42
184#define CS8_SW3 0x43
185#define CS9_SW3 0x44
186#define CS10_SW3 0x45
187#define CS11_SW3 0x46
188#define CS12_SW3 0x47
189#define CS13_SW3 0x48
190#define CS14_SW3 0x49
191#define CS15_SW3 0x4A
192#define CS16_SW3 0x4B
193#define CS17_SW3 0x4C
194#define CS18_SW3 0x4D
195#define CS19_SW3 0x4E
196#define CS20_SW3 0x4F
197#define CS21_SW3 0x50
198#define CS22_SW3 0x51
199#define CS23_SW3 0x52
200#define CS24_SW3 0x53
201#define CS25_SW3 0x54
202#define CS26_SW3 0x55
203#define CS27_SW3 0x56
204#define CS28_SW3 0x57
205#define CS29_SW3 0x58
206#define CS30_SW3 0x59
207
208#define CS1_SW4 0x5A
209#define CS2_SW4 0x5B
210#define CS3_SW4 0x5C
211#define CS4_SW4 0x5D
212#define CS5_SW4 0x5E
213#define CS6_SW4 0x5F
214#define CS7_SW4 0x60
215#define CS8_SW4 0x61
216#define CS9_SW4 0x62
217#define CS10_SW4 0x63
218#define CS11_SW4 0x64
219#define CS12_SW4 0x65
220#define CS13_SW4 0x66
221#define CS14_SW4 0x67
222#define CS15_SW4 0x68
223#define CS16_SW4 0x69
224#define CS17_SW4 0x6A
225#define CS18_SW4 0x6B
226#define CS19_SW4 0x6C
227#define CS20_SW4 0x6D
228#define CS21_SW4 0x6E
229#define CS22_SW4 0x6F
230#define CS23_SW4 0x70
231#define CS24_SW4 0x71
232#define CS25_SW4 0x72
233#define CS26_SW4 0x73
234#define CS27_SW4 0x74
235#define CS28_SW4 0x75
236#define CS29_SW4 0x76
237#define CS30_SW4 0x77
238
239#define CS1_SW5 0x78
240#define CS2_SW5 0x79
241#define CS3_SW5 0x7A
242#define CS4_SW5 0x7B
243#define CS5_SW5 0x7C
244#define CS6_SW5 0x7D
245#define CS7_SW5 0x7E
246#define CS8_SW5 0x7F
247#define CS9_SW5 0x80
248#define CS10_SW5 0x81
249#define CS11_SW5 0x82
250#define CS12_SW5 0x83
251#define CS13_SW5 0x84
252#define CS14_SW5 0x85
253#define CS15_SW5 0x86
254#define CS16_SW5 0x87
255#define CS17_SW5 0x88
256#define CS18_SW5 0x89
257#define CS19_SW5 0x8A
258#define CS20_SW5 0x8B
259#define CS21_SW5 0x8C
260#define CS22_SW5 0x8D
261#define CS23_SW5 0x8E
262#define CS24_SW5 0x8F
263#define CS25_SW5 0x90
264#define CS26_SW5 0x91
265#define CS27_SW5 0x92
266#define CS28_SW5 0x93
267#define CS29_SW5 0x94
268#define CS30_SW5 0x95
269
270#define CS1_SW6 0x96
271#define CS2_SW6 0x97
272#define CS3_SW6 0x98
273#define CS4_SW6 0x99
274#define CS5_SW6 0x9A
275#define CS6_SW6 0x9B
276#define CS7_SW6 0x9C
277#define CS8_SW6 0x9D
278#define CS9_SW6 0x9E
279#define CS10_SW6 0x9F
280#define CS11_SW6 0xA0
281#define CS12_SW6 0xA1
282#define CS13_SW6 0xA2
283#define CS14_SW6 0xA3
284#define CS15_SW6 0xA4
285#define CS16_SW6 0xA5
286#define CS17_SW6 0xA6
287#define CS18_SW6 0xA7
288#define CS19_SW6 0xA8
289#define CS20_SW6 0xA9
290#define CS21_SW6 0xAA
291#define CS22_SW6 0xAB
292#define CS23_SW6 0xAC
293#define CS24_SW6 0xAD
294#define CS25_SW6 0xAE
295#define CS26_SW6 0xAF
296#define CS27_SW6 0xB0
297#define CS28_SW6 0xB1
298#define CS29_SW6 0xB2
299#define CS30_SW6 0xB3
diff --git a/drivers/led/issi/is31flcommon.h b/drivers/led/issi/is31flcommon.h
index 10613a6eed..1ba57c6cf7 100644
--- a/drivers/led/issi/is31flcommon.h
+++ b/drivers/led/issi/is31flcommon.h
@@ -26,9 +26,7 @@
26#include "util.h" 26#include "util.h"
27 27
28// Which variant header file to use 28// Which variant header file to use
29#if defined(LED_MATRIX_IS31FL3742A) || defined(RGB_MATRIX_IS31FL3742A) 29#if defined(LED_MATRIX_IS31FL3743A) || defined(RGB_MATRIX_IS31FL3743A)
30# include "is31fl3742.h"
31#elif defined(LED_MATRIX_IS31FL3743A) || defined(RGB_MATRIX_IS31FL3743A)
32# include "is31fl3743.h" 30# include "is31fl3743.h"
33#elif defined(LED_MATRIX_IS31FL3745) || defined(RGB_MATRIX_IS31FL3745) 31#elif defined(LED_MATRIX_IS31FL3745) || defined(RGB_MATRIX_IS31FL3745)
34# include "is31fl3745.h" 32# include "is31fl3745.h"