is31fl3236.c (5897B)
1 // Copyright 2024 QMK 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include "is31fl3236.h" 5 #include "i2c_master.h" 6 #include "gpio.h" 7 8 #define IS31FL3236_PWM_REGISTER_COUNT 36 9 #define IS31FL3236_LED_CONTROL_REGISTER_COUNT 36 10 11 #ifndef IS31FL3236_I2C_TIMEOUT 12 # define IS31FL3236_I2C_TIMEOUT 100 13 #endif 14 15 #ifndef IS31FL3236_I2C_PERSISTENCE 16 # define IS31FL3236_I2C_PERSISTENCE 0 17 #endif 18 19 #ifndef IS31FL3236_PWM_FREQUENCY 20 # define IS31FL3236_PWM_FREQUENCY IS31FL3236_PWM_FREQUENCY_3K_HZ // OFS - IS31FL3236A only 21 #endif 22 23 const uint8_t i2c_addresses[IS31FL3236_DRIVER_COUNT] = { 24 IS31FL3236_I2C_ADDRESS_1, 25 #ifdef IS31FL3236_I2C_ADDRESS_2 26 IS31FL3236_I2C_ADDRESS_2, 27 # ifdef IS31FL3236_I2C_ADDRESS_3 28 IS31FL3236_I2C_ADDRESS_3, 29 # ifdef IS31FL3236_I2C_ADDRESS_4 30 IS31FL3236_I2C_ADDRESS_4, 31 # endif 32 # endif 33 #endif 34 }; 35 36 typedef struct is31fl3236_driver_t { 37 uint8_t pwm_buffer[IS31FL3236_PWM_REGISTER_COUNT]; 38 bool pwm_buffer_dirty; 39 uint8_t led_control_buffer[IS31FL3236_LED_CONTROL_REGISTER_COUNT]; 40 bool led_control_buffer_dirty; 41 } PACKED is31fl3236_driver_t; 42 43 is31fl3236_driver_t driver_buffers[IS31FL3236_DRIVER_COUNT] = {{ 44 .pwm_buffer = {0}, 45 .pwm_buffer_dirty = false, 46 .led_control_buffer = {0}, 47 .led_control_buffer_dirty = false, 48 }}; 49 50 void is31fl3236_write_register(uint8_t index, uint8_t reg, uint8_t data) { 51 #if IS31FL3236_I2C_PERSISTENCE > 0 52 for (uint8_t i = 0; i < IS31FL3236_I2C_PERSISTENCE; i++) { 53 if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3236_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; 54 } 55 #else 56 i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3236_I2C_TIMEOUT); 57 #endif 58 } 59 60 void is31fl3236_write_pwm_buffer(uint8_t index) { 61 #if IS31FL3236_I2C_PERSISTENCE > 0 62 for (uint8_t i = 0; i < IS31FL3236_I2C_PERSISTENCE; i++) { 63 if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3236_REG_PWM, driver_buffers[index].pwm_buffer, 36, IS31FL3236_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; 64 } 65 #else 66 i2c_write_register(i2c_addresses[index] << 1, IS31FL3236_REG_PWM, driver_buffers[index].pwm_buffer, 36, IS31FL3236_I2C_TIMEOUT); 67 #endif 68 } 69 70 void is31fl3236_init_drivers(void) { 71 i2c_init(); 72 73 #if defined(IS31FL3236_SDB_PIN) 74 gpio_set_pin_output(IS31FL3236_SDB_PIN); 75 gpio_write_pin_high(IS31FL3236_SDB_PIN); 76 #endif 77 78 for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { 79 is31fl3236_init(i); 80 } 81 82 for (uint8_t i = 0; i < IS31FL3236_LED_COUNT; i++) { 83 is31fl3236_set_led_control_register(i, true, true, true); 84 } 85 86 for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { 87 is31fl3236_update_led_control_registers(i); 88 } 89 } 90 91 void is31fl3236_init(uint8_t index) { 92 // In case we ever want to reinitialize (?) 93 is31fl3236_write_register(index, IS31FL3236_REG_RESET, 0x00); 94 95 // Turn off software shutdown 96 is31fl3236_write_register(index, IS31FL3236_REG_SHUTDOWN, 0x01); 97 98 // Set all PWM values to zero 99 for (uint8_t i = 0; i < IS31FL3236_PWM_REGISTER_COUNT; i++) { 100 is31fl3236_write_register(index, IS31FL3236_REG_PWM + i, 0x00); 101 } 102 103 // turn off all LEDs in the LED control register 104 for (uint8_t i = 0; i < IS31FL3236_LED_CONTROL_REGISTER_COUNT; i++) { 105 is31fl3236_write_register(index, IS31FL3236_REG_LED_CONTROL + i, 0x00); 106 } 107 108 // Set PWM frequency (IS31FL3236A) 109 is31fl3236_write_register(index, IS31FL3236_REG_PWM_FREQUENCY, IS31FL3236_PWM_FREQUENCY); 110 111 // Load PWM registers and LED Control register data 112 is31fl3236_write_register(index, IS31FL3236_REG_UPDATE, 0x01); 113 } 114 115 void is31fl3236_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { 116 is31fl3236_led_t led; 117 118 if (index < IS31FL3236_LED_COUNT) { 119 memcpy_P(&led, (&g_is31fl3236_leds[index]), sizeof(led)); 120 121 if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) { 122 return; 123 } 124 125 driver_buffers[led.driver].pwm_buffer[led.r] = red; 126 driver_buffers[led.driver].pwm_buffer[led.g] = green; 127 driver_buffers[led.driver].pwm_buffer[led.b] = blue; 128 driver_buffers[led.driver].pwm_buffer_dirty = true; 129 } 130 } 131 132 void is31fl3236_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { 133 for (uint8_t i = 0; i < IS31FL3236_LED_COUNT; i++) { 134 is31fl3236_set_color(i, red, green, blue); 135 } 136 } 137 138 void is31fl3236_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { 139 is31fl3236_led_t led; 140 memcpy_P(&led, (&g_is31fl3236_leds[index]), sizeof(led)); 141 142 driver_buffers[led.driver].led_control_buffer[led.r] = red ? 0x01 : 0x00; 143 driver_buffers[led.driver].led_control_buffer[led.g] = green ? 0x01 : 0x00; 144 driver_buffers[led.driver].led_control_buffer[led.b] = blue ? 0x01 : 0x00; 145 driver_buffers[led.driver].led_control_buffer_dirty = true; 146 } 147 148 void is31fl3236_update_pwm_buffers(uint8_t index) { 149 if (driver_buffers[index].pwm_buffer_dirty) { 150 is31fl3236_write_pwm_buffer(index); 151 // Load PWM registers and LED Control register data 152 is31fl3236_write_register(index, IS31FL3236_REG_UPDATE, 0x01); 153 154 driver_buffers[index].pwm_buffer_dirty = false; 155 } 156 } 157 158 void is31fl3236_update_led_control_registers(uint8_t index) { 159 if (driver_buffers[index].led_control_buffer_dirty) { 160 for (uint8_t i = 0; i < IS31FL3236_LED_CONTROL_REGISTER_COUNT; i++) { 161 is31fl3236_write_register(index, IS31FL3236_REG_LED_CONTROL + i, driver_buffers[index].led_control_buffer[i]); 162 } 163 164 driver_buffers[index].led_control_buffer_dirty = false; 165 } 166 } 167 168 void is31fl3236_flush(void) { 169 for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { 170 is31fl3236_update_pwm_buffers(i); 171 } 172 }