forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LED drivers: add support for IS31FL3236 (qmk#23264)
- Loading branch information
Showing
11 changed files
with
581 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
// Copyright 2024 QMK | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "is31fl3236-mono.h" | ||
#include "i2c_master.h" | ||
#include "gpio.h" | ||
|
||
#define IS31FL3236_PWM_REGISTER_COUNT 36 | ||
#define IS31FL3236_LED_CONTROL_REGISTER_COUNT 36 | ||
|
||
#ifndef IS31FL3236_I2C_TIMEOUT | ||
# define IS31FL3236_I2C_TIMEOUT 100 | ||
#endif | ||
|
||
#ifndef IS31FL3236_I2C_PERSISTENCE | ||
# define IS31FL3236_I2C_PERSISTENCE 0 | ||
#endif | ||
|
||
#ifndef IS31FL3236_PWM_FREQUENCY | ||
# define IS31FL3236_PWM_FREQUENCY IS31FL3236_PWM_FREQUENCY_3K_HZ // OFS - IS31FL3236A only | ||
#endif | ||
|
||
const uint8_t i2c_addresses[IS31FL3236_DRIVER_COUNT] = { | ||
IS31FL3236_I2C_ADDRESS_1, | ||
#ifdef IS31FL3236_I2C_ADDRESS_2 | ||
IS31FL3236_I2C_ADDRESS_2, | ||
# ifdef IS31FL3236_I2C_ADDRESS_3 | ||
IS31FL3236_I2C_ADDRESS_3, | ||
# ifdef IS31FL3236_I2C_ADDRESS_4 | ||
IS31FL3236_I2C_ADDRESS_4, | ||
# endif | ||
# endif | ||
#endif | ||
}; | ||
|
||
typedef struct is31fl3236_driver_t { | ||
uint8_t pwm_buffer[IS31FL3236_PWM_REGISTER_COUNT]; | ||
bool pwm_buffer_dirty; | ||
uint8_t led_control_buffer[IS31FL3236_LED_CONTROL_REGISTER_COUNT]; | ||
bool led_control_buffer_dirty; | ||
} PACKED is31fl3236_driver_t; | ||
|
||
is31fl3236_driver_t driver_buffers[IS31FL3236_DRIVER_COUNT] = {{ | ||
.pwm_buffer = {0}, | ||
.pwm_buffer_dirty = false, | ||
.led_control_buffer = {0}, | ||
.led_control_buffer_dirty = false, | ||
}}; | ||
|
||
void is31fl3236_write_register(uint8_t index, uint8_t reg, uint8_t data) { | ||
#if IS31FL3236_I2C_PERSISTENCE > 0 | ||
for (uint8_t i = 0; i < IS31FL3236_I2C_PERSISTENCE; i++) { | ||
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3236_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
} | ||
#else | ||
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3236_I2C_TIMEOUT); | ||
#endif | ||
} | ||
|
||
void is31fl3236_write_pwm_buffer(uint8_t index) { | ||
#if IS31FL3236_I2C_PERSISTENCE > 0 | ||
for (uint8_t i = 0; i < IS31FL3236_I2C_PERSISTENCE; i++) { | ||
if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3236_REG_PWM, driver_buffers[index].pwm_buffer, 36, IS31FL3236_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
} | ||
#else | ||
i2c_write_register(i2c_addresses[index] << 1, IS31FL3236_REG_PWM, driver_buffers[index].pwm_buffer, 36, IS31FL3236_I2C_TIMEOUT); | ||
#endif | ||
} | ||
|
||
void is31fl3236_init_drivers(void) { | ||
i2c_init(); | ||
|
||
#if defined(IS31FL3236_SDB_PIN) | ||
gpio_set_pin_output(IS31FL3236_SDB_PIN); | ||
gpio_write_pin_high(IS31FL3236_SDB_PIN); | ||
#endif | ||
|
||
for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { | ||
is31fl3236_init(i); | ||
} | ||
|
||
for (uint8_t i = 0; i < IS31FL3236_LED_COUNT; i++) { | ||
is31fl3236_set_led_control_register(i, true); | ||
} | ||
|
||
for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { | ||
is31fl3236_update_led_control_registers(i); | ||
} | ||
} | ||
|
||
void is31fl3236_init(uint8_t index) { | ||
// In case we ever want to reinitialize (?) | ||
is31fl3236_write_register(index, IS31FL3236_REG_RESET, 0x00); | ||
|
||
// Turn off software shutdown | ||
is31fl3236_write_register(index, IS31FL3236_REG_SHUTDOWN, 0x01); | ||
|
||
// Set all PWM values to zero | ||
for (uint8_t i = 0; i < IS31FL3236_PWM_REGISTER_COUNT; i++) { | ||
is31fl3236_write_register(index, IS31FL3236_REG_PWM + i, 0x00); | ||
} | ||
|
||
// turn off all LEDs in the LED control register | ||
for (uint8_t i = 0; i < IS31FL3236_LED_CONTROL_REGISTER_COUNT; i++) { | ||
is31fl3236_write_register(index, IS31FL3236_REG_LED_CONTROL + i, 0x00); | ||
} | ||
|
||
// Set PWM frequency (IS31FL3236A) | ||
is31fl3236_write_register(index, IS31FL3236_REG_PWM_FREQUENCY, IS31FL3236_PWM_FREQUENCY); | ||
|
||
// Load PWM registers and LED Control register data | ||
is31fl3236_write_register(index, IS31FL3236_REG_UPDATE, 0x01); | ||
} | ||
|
||
void is31fl3236_set_value(int index, uint8_t value) { | ||
is31fl3236_led_t led; | ||
|
||
if (index < IS31FL3236_LED_COUNT) { | ||
memcpy_P(&led, (&g_is31fl3236_leds[index]), sizeof(led)); | ||
|
||
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) { | ||
return; | ||
} | ||
|
||
driver_buffers[led.driver].pwm_buffer[led.v] = value; | ||
driver_buffers[led.driver].pwm_buffer_dirty = true; | ||
} | ||
} | ||
|
||
void is31fl3236_set_value_all(uint8_t value) { | ||
for (uint8_t i = 0; i < IS31FL3236_LED_COUNT; i++) { | ||
is31fl3236_set_value(i, value); | ||
} | ||
} | ||
|
||
void is31fl3236_set_led_control_register(uint8_t index, bool value) { | ||
is31fl3236_led_t led; | ||
memcpy_P(&led, (&g_is31fl3236_leds[index]), sizeof(led)); | ||
|
||
driver_buffers[led.driver].led_control_buffer[led.v] = value ? 0x01 : 0x00; | ||
driver_buffers[led.driver].led_control_buffer_dirty = true; | ||
} | ||
|
||
void is31fl3236_update_pwm_buffers(uint8_t index) { | ||
if (driver_buffers[index].pwm_buffer_dirty) { | ||
is31fl3236_write_pwm_buffer(index); | ||
// Load PWM registers and LED Control register data | ||
is31fl3236_write_register(index, IS31FL3236_REG_UPDATE, 0x01); | ||
|
||
driver_buffers[index].pwm_buffer_dirty = false; | ||
} | ||
} | ||
|
||
void is31fl3236_update_led_control_registers(uint8_t index) { | ||
if (driver_buffers[index].led_control_buffer_dirty) { | ||
for (uint8_t i = 0; i < IS31FL3236_LED_CONTROL_REGISTER_COUNT; i++) { | ||
is31fl3236_write_register(index, IS31FL3236_REG_LED_CONTROL + i, driver_buffers[index].led_control_buffer[i]); | ||
} | ||
|
||
driver_buffers[index].led_control_buffer_dirty = false; | ||
} | ||
} | ||
|
||
void is31fl3236_flush(void) { | ||
for (uint8_t i = 0; i < IS31FL3236_DRIVER_COUNT; i++) { | ||
is31fl3236_update_pwm_buffers(i); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2024 QMK | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include "progmem.h" | ||
#include "util.h" | ||
|
||
#define IS31FL3236_REG_SHUTDOWN 0x00 | ||
#define IS31FL3236_REG_PWM 0x01 | ||
#define IS31FL3236_REG_UPDATE 0x25 | ||
#define IS31FL3236_REG_LED_CONTROL 0x26 | ||
#define IS31FL3236_REG_GLOBAL_CONTROL 0x4A | ||
#define IS31FL3236_REG_PWM_FREQUENCY 0x4B | ||
#define IS31FL3236_REG_RESET 0x4F | ||
|
||
#define IS31FL3236_I2C_ADDRESS_GND 0x3C | ||
#define IS31FL3236_I2C_ADDRESS_SCL 0x3D | ||
#define IS31FL3236_I2C_ADDRESS_SDA 0x3E | ||
#define IS31FL3236_I2C_ADDRESS_VCC 0x3F | ||
|
||
#if defined(LED_MATRIX_IS31FL3236) | ||
# define IS31FL3236_LED_COUNT LED_MATRIX_LED_COUNT | ||
#endif | ||
|
||
#if defined(IS31FL3236_I2C_ADDRESS_4) | ||
# define IS31FL3236_DRIVER_COUNT 4 | ||
#elif defined(IS31FL3236_I2C_ADDRESS_3) | ||
# define IS31FL3236_DRIVER_COUNT 3 | ||
#elif defined(IS31FL3236_I2C_ADDRESS_2) | ||
# define IS31FL3236_DRIVER_COUNT 2 | ||
#elif defined(IS31FL3236_I2C_ADDRESS_1) | ||
# define IS31FL3236_DRIVER_COUNT 1 | ||
#endif | ||
|
||
typedef struct is31fl3236_led_t { | ||
uint8_t driver : 2; | ||
uint8_t v; | ||
} PACKED is31fl3236_led_t; | ||
|
||
extern const is31fl3236_led_t PROGMEM g_is31fl3236_leds[IS31FL3236_LED_COUNT]; | ||
|
||
void is31fl3236_init_drivers(void); | ||
|
||
void is31fl3236_init(uint8_t index); | ||
|
||
void is31fl3236_write_register(uint8_t index, uint8_t reg, uint8_t data); | ||
|
||
void is31fl3236_set_value(int index, uint8_t value); | ||
|
||
void is31fl3236_set_value_all(uint8_t value); | ||
|
||
void is31fl3236_set_led_control_register(uint8_t index, bool value); | ||
|
||
void is31fl3236_update_pwm_buffers(uint8_t index); | ||
|
||
void is31fl3236_update_led_control_registers(uint8_t index); | ||
|
||
void is31fl3236_flush(void); | ||
|
||
#define IS31FL3236_PWM_FREQUENCY_3K_HZ 0b0 | ||
#define IS31FL3236_PWM_FREQUENCY_22K_HZ 0b1 | ||
|
||
#define OUT1 0x00 | ||
#define OUT2 0x01 | ||
#define OUT3 0x02 | ||
#define OUT4 0x03 | ||
#define OUT5 0x04 | ||
#define OUT6 0x05 | ||
#define OUT7 0x06 | ||
#define OUT8 0x07 | ||
#define OUT9 0x08 | ||
#define OUT10 0x09 | ||
#define OUT11 0x0A | ||
#define OUT12 0x0B | ||
#define OUT13 0x0C | ||
#define OUT14 0x0D | ||
#define OUT15 0x0E | ||
#define OUT16 0x0F | ||
#define OUT17 0x10 | ||
#define OUT18 0x11 | ||
#define OUT19 0x12 | ||
#define OUT20 0x13 | ||
#define OUT21 0x14 | ||
#define OUT22 0x15 | ||
#define OUT23 0x16 | ||
#define OUT24 0x17 | ||
#define OUT25 0x18 | ||
#define OUT26 0x19 | ||
#define OUT27 0x1A | ||
#define OUT28 0x1B | ||
#define OUT29 0x1C | ||
#define OUT30 0x1D | ||
#define OUT31 0x1E | ||
#define OUT32 0x1F | ||
#define OUT33 0x20 | ||
#define OUT34 0x21 | ||
#define OUT35 0x22 | ||
#define OUT36 0x23 |
Oops, something went wrong.