diff options
Diffstat (limited to 'drivers/led/issi/is31flcommon.c')
| -rw-r--r-- | drivers/led/issi/is31flcommon.c | 230 | 
1 files changed, 230 insertions, 0 deletions
| diff --git a/drivers/led/issi/is31flcommon.c b/drivers/led/issi/is31flcommon.c new file mode 100644 index 0000000000..9f4b2123ff --- /dev/null +++ b/drivers/led/issi/is31flcommon.c @@ -0,0 +1,230 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * Copyright 2020 MelGeek + * Copyright 2021 MasterSpoon + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "is31flcommon.h" +#include "i2c_master.h" +#include "wait.h" +#include <string.h> + +// Set defaults for Timeout and Persistence +#ifndef ISSI_TIMEOUT +#    define ISSI_TIMEOUT 100 +#endif +#ifndef ISSI_PERSISTENCE +#    define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the PWM & scaling registers. +// Storing them like this is optimal for I2C transfers to the registers. +uint8_t g_pwm_buffer[DRIVER_COUNT][ISSI_MAX_LEDS]; +bool    g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_scaling_buffer[DRIVER_COUNT][ISSI_SCALING_SIZE]; +bool    g_scaling_buffer_update_required[DRIVER_COUNT] = {false}; + +// For writing of single register entry +void IS31FL_write_single_register(uint8_t addr, uint8_t reg, uint8_t data) { +    // Set register address and register data ready to write +    g_twi_transfer_buffer[0] = reg; +    g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 +    for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { +        if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break; +    } +#else +    i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +// For writing of mulitple register entries to make use of address auto increment +// Once the controller has been called and we have written the first bit of data +// the controller will move to the next register meaning we can write sequential blocks. +bool IS31FL_write_multi_registers(uint8_t addr, uint8_t *source_buffer, uint8_t buffer_size, uint8_t transfer_size, uint8_t start_reg_addr) { +    // Split the buffer into chunks to transfer +    for (int i = 0; i < buffer_size; i += transfer_size) { +        // Set the first entry of transfer buffer to the first register we want to write +        g_twi_transfer_buffer[0] = i + start_reg_addr; +        // Copy the section of our source buffer into the transfer buffer after first register address +        memcpy(g_twi_transfer_buffer + 1, source_buffer + i, transfer_size); + +#if ISSI_PERSISTENCE > 0 +        for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { +            if (i2c_transmit(addr << 1, g_twi_transfer_buffer, transfer_size + 1, ISSI_TIMEOUT) != 0) { +                return false; +            } +        } +#else +        if (i2c_transmit(addr << 1, g_twi_transfer_buffer, transfer_size + 1, ISSI_TIMEOUT) != 0) { +            return false; +        } +#endif +    } +    return true; +} + +void IS31FL_unlock_register(uint8_t addr, uint8_t page) { +    // unlock the command register and select Page to write +    IS31FL_write_single_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, ISSI_REGISTER_UNLOCK); +    IS31FL_write_single_register(addr, ISSI_COMMANDREGISTER, page); +} + +void IS31FL_common_init(uint8_t addr, uint8_t ssr) { +    // Setup phase, need to take out of software shutdown and configure +    // ISSI_SSR_x is passed to allow Master / Slave setting where applicable + +    // Unlock the command register & select Function Register +    IS31FL_unlock_register(addr, ISSI_PAGE_FUNCTION); +    // Set Configuration Register to remove Software shutdown +    IS31FL_write_single_register(addr, ISSI_REG_CONFIGURATION, ISSI_CONFIGURATION); +    // Set Golbal Current Control Register +    IS31FL_write_single_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); +    // Set Pull up & Down for SWx CSy +    IS31FL_write_single_register(addr, ISSI_REG_PULLDOWNUP, ISSI_PULLDOWNUP); +// Set Tempature Status +#ifdef ISSI_REG_TEMP +    IS31FL_write_single_register(addr, ISSI_REG_TEMP, ISSI_TEMP); +#endif +    // Set Spread Spectrum Register, passed through as sets SYNC function +    IS31FL_write_single_register(addr, ISSI_REG_SSR, ssr); +// Set PWM Frequency Enable Register if applicable +#ifdef ISSI_REG_PWM_ENABLE +    IS31FL_write_single_register(addr, ISSI_REG_PWM_ENABLE, ISSI_PWM_ENABLE); +#endif +// Set PWM Frequency Register if applicable +#ifdef ISSI_REG_PWM_SET +    IS31FL_write_single_register(addr, ISSI_REG_PWM_SET, ISSI_PWM_SET); +#endif + +    // Wait 10ms to ensure the device has woken up. +    wait_ms(10); +} + +void IS31FL_common_update_pwm_register(uint8_t addr, uint8_t index) { +    if (g_pwm_buffer_update_required[index]) { +        // Queue up the correct page +        IS31FL_unlock_register(addr, ISSI_PAGE_PWM); +        // Hand off the update to IS31FL_write_multi_registers +        IS31FL_write_multi_registers(addr, g_pwm_buffer[index], ISSI_MAX_LEDS, ISSI_PWM_TRF_SIZE, ISSI_PWM_REG_1ST); +        // Update flags that pwm_buffer has been updated +        g_pwm_buffer_update_required[index] = false; +    } +} + +#ifdef ISSI_MANUAL_SCALING +void IS31FL_set_manual_scaling_buffer(void) { +    for (int i = 0; i < ISSI_MANUAL_SCALING; i++) { +        is31_led scale = g_is31_scaling[i]; +        if (scale.driver >= 0 && scale.driver < DRIVER_LED_TOTAL) { +            is31_led led = g_is31_leds[scale.driver]; + +#    ifdef RGB_MATRIX_ENABLE +            g_scaling_buffer[led.driver][led.r] = scale.r; +            g_scaling_buffer[led.driver][led.g] = scale.g; +            g_scaling_buffer[led.driver][led.b] = scale.b; +#    elif defined(LED_MATRIX_ENABLE) +            g_scaling_buffer[led.driver][led.v] = scale.v; +#    endif +            g_scaling_buffer_update_required[led.driver] = true; +        } +    } +} +#endif + +void IS31FL_common_update_scaling_register(uint8_t addr, uint8_t index) { +    if (g_scaling_buffer_update_required[index]) { +        // Queue up the correct page +        IS31FL_unlock_register(addr, ISSI_PAGE_SCALING); +        // Hand off the update to IS31FL_write_multi_registers +        IS31FL_write_multi_registers(addr, g_scaling_buffer[index], ISSI_SCALING_SIZE, ISSI_SCALING_TRF_SIZE, ISSI_SCL_REG_1ST); +        // Update flags that scaling_buffer has been updated +        g_scaling_buffer_update_required[index] = false; +    } +} + +#ifdef RGB_MATRIX_ENABLE +// Colour is set by adjusting PWM register +void IS31FL_RGB_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +    if (index >= 0 && index < DRIVER_LED_TOTAL) { +        is31_led led = g_is31_leds[index]; + +        g_pwm_buffer[led.driver][led.r]          = red; +        g_pwm_buffer[led.driver][led.g]          = green; +        g_pwm_buffer[led.driver][led.b]          = blue; +        g_pwm_buffer_update_required[led.driver] = true; +    } +} + +void IS31FL_RGB_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +        IS31FL_RGB_set_color(i, red, green, blue); +    } +} + +// Setup Scaling register that decides the peak current of each LED +void IS31FL_RGB_set_scaling_buffer(uint8_t index, bool red, bool green, bool blue) { +    is31_led led = g_is31_leds[index]; +    if (red) { +        g_scaling_buffer[led.driver][led.r] = ISSI_SCAL_RED; +    } else { +        g_scaling_buffer[led.driver][led.r] = ISSI_SCAL_RED_OFF; +    } +    if (green) { +        g_scaling_buffer[led.driver][led.g] = ISSI_SCAL_GREEN; +    } else { +        g_scaling_buffer[led.driver][led.g] = ISSI_SCAL_GREEN_OFF; +    } +    if (blue) { +        g_scaling_buffer[led.driver][led.b] = ISSI_SCAL_BLUE; +    } else { +        g_scaling_buffer[led.driver][led.b] = ISSI_SCAL_BLUE_OFF; +    } +    g_scaling_buffer_update_required[led.driver] = true; +} + +#elif defined(LED_MATRIX_ENABLE) +// LED Matrix Specific scripts +void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value) { +    is31_led led = g_is31_leds[index]; +    if (value) { +        g_scaling_buffer[led.driver][led.v] = ISSI_SCAL_LED; +    } else { +        g_scaling_buffer[led.driver][led.v] = ISSI_SCAL_LED_OFF; +    } +    g_scaling_buffer_update_required[led.driver] = true; +} + +void IS31FL_simple_set_brightness(int index, uint8_t value) { +    if (index >= 0 && index < DRIVER_LED_TOTAL) { +        is31_led led = g_is31_leds[index]; +        g_pwm_buffer[led.driver][led.v] = value; +        g_pwm_buffer_update_required[led.driver] = true; +    } +} + +void IS31FL_simple_set_brigntness_all(uint8_t value) { +    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +        IS31FL_simple_set_brightness(i, value); +    } +} +#endif | 
