diff options
Diffstat (limited to 'drivers')
30 files changed, 550 insertions, 139 deletions
| diff --git a/drivers/eeprom/eeprom_i2c.h b/drivers/eeprom/eeprom_i2c.h index 77eea66d63..85317c9ea5 100644 --- a/drivers/eeprom/eeprom_i2c.h +++ b/drivers/eeprom/eeprom_i2c.h @@ -54,6 +54,11 @@  #    define EXTERNAL_EEPROM_PAGE_SIZE 32  #    define EXTERNAL_EEPROM_ADDRESS_SIZE 2  #    define EXTERNAL_EEPROM_WRITE_TIME 5 +#elif defined(EEPROM_I2C_24LC32A) +#    define EXTERNAL_EEPROM_BYTE_COUNT 4096 +#    define EXTERNAL_EEPROM_PAGE_SIZE 32 +#    define EXTERNAL_EEPROM_ADDRESS_SIZE 2 +#    define EXTERNAL_EEPROM_WRITE_TIME 5  #elif defined(EEPROM_I2C_MB85RC256V)  #    define EXTERNAL_EEPROM_BYTE_COUNT 32768  #    define EXTERNAL_EEPROM_PAGE_SIZE 128 diff --git a/drivers/eeprom/eeprom_wear_leveling.c b/drivers/eeprom/eeprom_wear_leveling.c new file mode 100644 index 0000000000..bd77eef35c --- /dev/null +++ b/drivers/eeprom/eeprom_wear_leveling.c @@ -0,0 +1,23 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include <stdint.h> +#include <string.h> + +#include "eeprom_driver.h" +#include "wear_leveling.h" + +void eeprom_driver_init(void) { +    wear_leveling_init(); +} + +void eeprom_driver_erase(void) { +    wear_leveling_erase(); +} + +void eeprom_read_block(void *buf, const void *addr, size_t len) { +    wear_leveling_read((uint32_t)addr, buf, len); +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { +    wear_leveling_write((uint32_t)addr, buf, len); +} diff --git a/drivers/led/aw20216.c b/drivers/led/aw20216.c index 448accdcd3..55083936ef 100644 --- a/drivers/led/aw20216.c +++ b/drivers/led/aw20216.c @@ -53,6 +53,10 @@  #    define AW_GLOBAL_CURRENT_MAX 150  #endif +#ifndef AW_SPI_MODE +#    define AW_SPI_MODE 0 +#endif +  #ifndef AW_SPI_DIVISOR  #    define AW_SPI_DIVISOR 4  #endif @@ -63,7 +67,7 @@ bool    g_pwm_buffer_update_required[DRIVER_COUNT] = {false};  bool AW20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8_t len) {      static uint8_t s_spi_transfer_buffer[2] = {0}; -    if (!spi_start(cs_pin, false, 3, AW_SPI_DIVISOR)) { +    if (!spi_start(cs_pin, false, AW_SPI_MODE, AW_SPI_DIVISOR)) {          spi_stop();          return false;      } diff --git a/drivers/led/issi/is31fl3733-simple.c b/drivers/led/issi/is31fl3733-simple.c index af006f756d..2f41a7b1a9 100644 --- a/drivers/led/issi/is31fl3733-simple.c +++ b/drivers/led/issi/is31fl3733-simple.c @@ -70,6 +70,10 @@  #    define ISSI_CSPULLUP PUR_0R  #endif +#ifndef ISSI_GLOBALCURRENT +#    define ISSI_GLOBALCURRENT 0xFF +#endif +  // Transfer buffer for TWITransmitData()  uint8_t g_twi_transfer_buffer[20]; @@ -182,7 +186,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {      // Set de-ghost pull-down resistors (CSx)      IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);      // Set global current to maximum. -    IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); +    IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);      // Disable software shutdown.      IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); diff --git a/drivers/led/issi/is31fl3733.c b/drivers/led/issi/is31fl3733.c index a2fdaa90fa..add998f256 100644 --- a/drivers/led/issi/is31fl3733.c +++ b/drivers/led/issi/is31fl3733.c @@ -69,6 +69,10 @@  #    define ISSI_CSPULLUP PUR_0R  #endif +#ifndef ISSI_GLOBALCURRENT +#    define ISSI_GLOBALCURRENT 0xFF +#endif +  // Transfer buffer for TWITransmitData()  uint8_t g_twi_transfer_buffer[20]; @@ -172,7 +176,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {      // Set de-ghost pull-down resistors (CSx)      IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);      // Set global current to maximum. -    IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); +    IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);      // Disable software shutdown.      IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); diff --git a/drivers/led/issi/is31fl3736.c b/drivers/led/issi/is31fl3736.c index 7752a3f6cb..e9943614d2 100644 --- a/drivers/led/issi/is31fl3736.c +++ b/drivers/led/issi/is31fl3736.c @@ -63,6 +63,10 @@  #    define ISSI_CSPULLUP PUR_0R  #endif +#ifndef ISSI_GLOBALCURRENT +#    define ISSI_GLOBALCURRENT 0xFF +#endif +  // Transfer buffer for TWITransmitData()  uint8_t g_twi_transfer_buffer[20]; @@ -154,7 +158,7 @@ void IS31FL3736_init(uint8_t addr) {      // Set de-ghost pull-down resistors (CSx)      IS31FL3736_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);      // Set global current to maximum. -    IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); +    IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);      // Disable software shutdown.      IS31FL3736_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c index bce0c34b2c..932530ac0a 100644 --- a/drivers/led/issi/is31fl3737.c +++ b/drivers/led/issi/is31fl3737.c @@ -69,6 +69,10 @@  #    define ISSI_CSPULLUP PUR_0R  #endif +#ifndef ISSI_GLOBALCURRENT +#    define ISSI_GLOBALCURRENT 0xFF +#endif +  // Transfer buffer for TWITransmitData()  uint8_t g_twi_transfer_buffer[20]; @@ -161,7 +165,7 @@ void IS31FL3737_init(uint8_t addr) {      // Set de-ghost pull-down resistors (CSx)      IS31FL3737_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);      // Set global current to maximum. -    IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); +    IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);      // Disable software shutdown.      IS31FL3737_write_register(addr, ISSI_REG_CONFIGURATION, ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); diff --git a/drivers/led/issi/is31fl3741.c b/drivers/led/issi/is31fl3741.c index 393b0179b5..ba6b6761a3 100644 --- a/drivers/led/issi/is31fl3741.c +++ b/drivers/led/issi/is31fl3741.c @@ -69,6 +69,10 @@  #    define ISSI_CSPULLUP PUR_32KR  #endif +#ifndef ISSI_GLOBALCURRENT +#    define ISSI_GLOBALCURRENT 0xFF +#endif +  #define ISSI_MAX_LEDS 351  // Transfer buffer for TWITransmitData() @@ -163,7 +167,7 @@ void IS31FL3741_init(uint8_t addr) {      IS31FL3741_write_register(addr, ISSI_REG_CONFIGURATION, 0x01);      // Set Golbal Current Control Register -    IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); +    IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);      // Set Pull up & Down for SWx CSy      IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, ((ISSI_CSPULLUP << 4) | ISSI_SWPULLUP)); diff --git a/drivers/painter/gc9a01/qp_gc9a01.c b/drivers/painter/gc9a01/qp_gc9a01.c index ad76d58b07..37700a28a4 100644 --- a/drivers/painter/gc9a01/qp_gc9a01.c +++ b/drivers/painter/gc9a01/qp_gc9a01.c @@ -102,12 +102,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t gc9a01_driver_vtable = {              .flush           = qp_tft_panel_flush,              .pixdata         = qp_tft_panel_pixdata,              .viewport        = qp_tft_panel_viewport, -            .palette_convert = qp_tft_panel_palette_convert, -            .append_pixels   = qp_tft_panel_append_pixels, +            .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, +            .append_pixels   = qp_tft_panel_append_pixels_rgb565,          }, -    .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, -    .num_window_bytes      = 2, -    .swap_window_coords    = false, +    .num_window_bytes   = 2, +    .swap_window_coords = false,      .opcodes =          {              .display_on         = GC9A01_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9163.c b/drivers/painter/ili9xxx/qp_ili9163.c index beaac0fbb5..14363c7d04 100644 --- a/drivers/painter/ili9xxx/qp_ili9163.c +++ b/drivers/painter/ili9xxx/qp_ili9163.c @@ -67,12 +67,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9163_driver_vtable =              .flush           = qp_tft_panel_flush,              .pixdata         = qp_tft_panel_pixdata,              .viewport        = qp_tft_panel_viewport, -            .palette_convert = qp_tft_panel_palette_convert, -            .append_pixels   = qp_tft_panel_append_pixels, +            .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, +            .append_pixels   = qp_tft_panel_append_pixels_rgb565,          }, -    .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, -    .num_window_bytes      = 2, -    .swap_window_coords    = false, +    .num_window_bytes   = 2, +    .swap_window_coords = false,      .opcodes =          {              .display_on         = ILI9XXX_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9341.c b/drivers/painter/ili9xxx/qp_ili9341.c index 1f41dcfc0b..9608f109bd 100644 --- a/drivers/painter/ili9xxx/qp_ili9341.c +++ b/drivers/painter/ili9xxx/qp_ili9341.c @@ -74,12 +74,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9341_driver_vtable =              .flush           = qp_tft_panel_flush,              .pixdata         = qp_tft_panel_pixdata,              .viewport        = qp_tft_panel_viewport, -            .palette_convert = qp_tft_panel_palette_convert, -            .append_pixels   = qp_tft_panel_append_pixels, +            .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, +            .append_pixels   = qp_tft_panel_append_pixels_rgb565,          }, -    .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, -    .num_window_bytes      = 2, -    .swap_window_coords    = false, +    .num_window_bytes   = 2, +    .swap_window_coords = false,      .opcodes =          {              .display_on         = ILI9XXX_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9488.c b/drivers/painter/ili9xxx/qp_ili9488.c new file mode 100644 index 0000000000..55cf9f896f --- /dev/null +++ b/drivers/painter/ili9xxx/qp_ili9488.c @@ -0,0 +1,120 @@ +// Copyright 2021 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qp_internal.h" +#include "qp_comms.h" +#include "qp_ili9488.h" +#include "qp_ili9xxx_opcodes.h" +#include "qp_tft_panel.h" + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE +#    include <qp_comms_spi.h> +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common + +// Driver storage +tft_panel_dc_reset_painter_device_t ili9488_drivers[ILI9488_NUM_DEVICES] = {0}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Initialization + +bool qp_ili9488_init(painter_device_t device, painter_rotation_t rotation) { +    // clang-format off +    const uint8_t ili9488_init_sequence[] = { +        // Command,                 Delay,  N, Data[N] +        ILI9XXX_CMD_RESET,            120,  0, +        ILI9XXX_SET_PGAMMA,             0, 15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F, +        ILI9XXX_SET_NGAMMA,             0, 15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F, +        ILI9XXX_SET_POWER_CTL_1,        0,  2, 0x17, 0x15, +        ILI9XXX_SET_POWER_CTL_2,        0,  1, 0x41, +        ILI9XXX_SET_VCOM_CTL_1,         0,  3, 0x00, 0x12, 0x80, +        ILI9XXX_SET_PIX_FMT,            0,  1, 0x66, +        ILI9XXX_SET_RGB_IF_SIG_CTL,     0,  1, 0x80, +        ILI9XXX_SET_FRAME_CTL_NORMAL,   0,  1, 0xA0, +        ILI9XXX_SET_INVERSION_CTL,      0,  1, 0x02, +        ILI9XXX_SET_FUNCTION_CTL,       0,  2, 0x02, 0x02, +        ILI9XXX_SET_IMAGE_FUNCTION,     0,  1, 0x00, +        ILI9XXX_SET_PUMP_RATIO_CTL,     0,  4, 0xA9, 0x51, 0x2C, 0x82, +        ILI9XXX_CMD_SLEEP_OFF,          5,  0, +        ILI9XXX_CMD_DISPLAY_ON,        20,  0 +    }; +    // clang-format on +    qp_comms_bulk_command_sequence(device, ili9488_init_sequence, sizeof(ili9488_init_sequence)); + +    // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) +    const uint8_t madctl[] = { +        [QP_ROTATION_0]   = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MY, +        [QP_ROTATION_90]  = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX | ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MY, +        [QP_ROTATION_180] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX, +        [QP_ROTATION_270] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MV, +    }; +    qp_comms_command_databyte(device, ILI9XXX_SET_MEM_ACS_CTL, madctl[rotation]); + +    return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver vtable + +const struct tft_panel_dc_reset_painter_driver_vtable_t ili9488_driver_vtable = { +    .base = +        { +            .init            = qp_ili9488_init, +            .power           = qp_tft_panel_power, +            .clear           = qp_tft_panel_clear, +            .flush           = qp_tft_panel_flush, +            .pixdata         = qp_tft_panel_pixdata, +            .viewport        = qp_tft_panel_viewport, +            .palette_convert = qp_tft_panel_palette_convert_rgb888, +            .append_pixels   = qp_tft_panel_append_pixels_rgb888, +        }, +    .num_window_bytes   = 2, +    .swap_window_coords = false, +    .opcodes = +        { +            .display_on         = ILI9XXX_CMD_DISPLAY_ON, +            .display_off        = ILI9XXX_CMD_DISPLAY_OFF, +            .set_column_address = ILI9XXX_SET_COL_ADDR, +            .set_row_address    = ILI9XXX_SET_PAGE_ADDR, +            .enable_writes      = ILI9XXX_SET_MEM, +        }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SPI + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +// Factory function for creating a handle to the ILI9488 device +painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) { +    for (uint32_t i = 0; i < ILI9488_NUM_DEVICES; ++i) { +        tft_panel_dc_reset_painter_device_t *driver = &ili9488_drivers[i]; +        if (!driver->base.driver_vtable) { +            driver->base.driver_vtable         = (const struct painter_driver_vtable_t *)&ili9488_driver_vtable; +            driver->base.comms_vtable          = (const struct painter_comms_vtable_t *)&spi_comms_with_dc_vtable; +            driver->base.native_bits_per_pixel = 24; // RGB888 +            driver->base.panel_width           = panel_width; +            driver->base.panel_height          = panel_height; +            driver->base.rotation              = QP_ROTATION_0; +            driver->base.offset_x              = 0; +            driver->base.offset_y              = 0; + +            // SPI and other pin configuration +            driver->base.comms_config                              = &driver->spi_dc_reset_config; +            driver->spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin; +            driver->spi_dc_reset_config.spi_config.divisor         = spi_divisor; +            driver->spi_dc_reset_config.spi_config.lsb_first       = false; +            driver->spi_dc_reset_config.spi_config.mode            = spi_mode; +            driver->spi_dc_reset_config.dc_pin                     = dc_pin; +            driver->spi_dc_reset_config.reset_pin                  = reset_pin; +            return (painter_device_t)driver; +        } +    } +    return NULL; +} + +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/drivers/painter/ili9xxx/qp_ili9488.h b/drivers/painter/ili9xxx/qp_ili9488.h new file mode 100644 index 0000000000..21b8f03322 --- /dev/null +++ b/drivers/painter/ili9xxx/qp_ili9488.h @@ -0,0 +1,37 @@ +// Copyright 2021 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "gpio.h" +#include "qp_internal.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ILI9488 configurables (add to your keyboard's config.h) + +#ifndef ILI9488_NUM_DEVICES +/** + * @def This controls the maximum number of ILI9488 devices that Quantum Painter can communicate with at any one time. + *      Increasing this number allows for multiple displays to be used. + */ +#    define ILI9488_NUM_DEVICES 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ILI9488 device factories + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE +/** + * Factory method for an ILI9488 SPI LCD device. + * + * @param panel_width[in] the width of the display panel + * @param panel_height[in] the height of the display panel + * @param chip_select_pin[in] the GPIO pin used for SPI chip select + * @param dc_pin[in] the GPIO pin used for D/C control + * @param reset_pin[in] the GPIO pin used for RST + * @param spi_divisor[in] the SPI divisor to use when communicating with the display + * @param spi_mode[in] the SPI mode to use when communicating with the display + * @return the device handle used with all drawing routines in Quantum Painter + */ +painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE diff --git a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h index 1fa395cb89..47bb703648 100644 --- a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h +++ b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h @@ -85,6 +85,7 @@  #define ILI9XXX_SET_NGAMMA 0xE1             // Set negative gamma  #define ILI9XXX_SET_DGAMMA_CTL_1 0xE2       // Set digital gamma ctl 1  #define ILI9XXX_SET_DGAMMA_CTL_2 0xE3       // Set digital gamma ctl 2 +#define ILI9XXX_SET_IMAGE_FUNCTION 0xE9     // Set image function  #define ILI9XXX_ENABLE_3_GAMMA 0xF2         // Enable 3 gamma  #define ILI9XXX_SET_IF_CTL 0xF6             // Set interface control  #define ILI9XXX_SET_PUMP_RATIO_CTL 0xF7     // Set pump ratio control diff --git a/drivers/painter/ssd1351/qp_ssd1351.c b/drivers/painter/ssd1351/qp_ssd1351.c index 970e7e67f3..7ce76bab6d 100644 --- a/drivers/painter/ssd1351/qp_ssd1351.c +++ b/drivers/painter/ssd1351/qp_ssd1351.c @@ -71,12 +71,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ssd1351_driver_vtable =              .flush           = qp_tft_panel_flush,              .pixdata         = qp_tft_panel_pixdata,              .viewport        = qp_tft_panel_viewport, -            .palette_convert = qp_tft_panel_palette_convert, -            .append_pixels   = qp_tft_panel_append_pixels, +            .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, +            .append_pixels   = qp_tft_panel_append_pixels_rgb565,          }, -    .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, -    .num_window_bytes      = 1, -    .swap_window_coords    = true, +    .num_window_bytes   = 1, +    .swap_window_coords = true,      .opcodes =          {              .display_on         = SSD1351_DISPLAYON, diff --git a/drivers/painter/st77xx/qp_st7789.c b/drivers/painter/st77xx/qp_st7789.c index d005ece050..49e8436c29 100644 --- a/drivers/painter/st77xx/qp_st7789.c +++ b/drivers/painter/st77xx/qp_st7789.c @@ -90,12 +90,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t st7789_driver_vtable = {              .flush           = qp_tft_panel_flush,              .pixdata         = qp_tft_panel_pixdata,              .viewport        = qp_tft_panel_viewport, -            .palette_convert = qp_tft_panel_palette_convert, -            .append_pixels   = qp_tft_panel_append_pixels, +            .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, +            .append_pixels   = qp_tft_panel_append_pixels_rgb565,          }, -    .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, -    .num_window_bytes      = 2, -    .swap_window_coords    = false, +    .num_window_bytes   = 2, +    .swap_window_coords = false,      .opcodes =          {              .display_on         = ST77XX_CMD_DISPLAY_ON, diff --git a/drivers/painter/tft_panel/qp_tft_panel.c b/drivers/painter/tft_panel/qp_tft_panel.c index 4d636c9509..ad83b6c792 100644 --- a/drivers/painter/tft_panel/qp_tft_panel.c +++ b/drivers/painter/tft_panel/qp_tft_panel.c @@ -10,29 +10,6 @@  #define BYTE_SWAP(x) (((((uint16_t)(x)) >> 8) & 0x00FF) | ((((uint16_t)(x)) << 8) & 0xFF00))  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Native pixel format conversion - -uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { -    uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3); -    return rgb565; -} - -uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b) { -    uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3); -    return BYTE_SWAP(rgb565); -} - -uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b) { -    uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3); -    return bgr565; -} - -uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b) { -    uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3); -    return BYTE_SWAP(bgr565); -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  // Quantum Painter API implementations  // Power control @@ -105,26 +82,49 @@ bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top,  // Stream pixel data to the current write position in GRAM  bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) { -    qp_comms_send(device, pixel_data, native_pixel_count * sizeof(uint16_t)); +    struct painter_driver_t *driver = (struct painter_driver_t *)device; +    qp_comms_send(device, pixel_data, native_pixel_count * driver->native_bits_per_pixel / 8);      return true;  } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  // Convert supplied palette entries into their native equivalents -bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { -    struct painter_driver_t *                          driver = (struct painter_driver_t *)device; -    struct tft_panel_dc_reset_painter_driver_vtable_t *vtable = (struct tft_panel_dc_reset_painter_driver_vtable_t *)driver->driver_vtable; + +bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {      for (int16_t i = 0; i < palette_size; ++i) { -        RGB rgb           = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); -        palette[i].rgb565 = vtable->rgb888_to_native16bit(rgb.r, rgb.g, rgb.b); +        RGB      rgb      = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); +        uint16_t rgb565   = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3); +        palette[i].rgb565 = BYTE_SWAP(rgb565);      }      return true;  } +bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { +    for (int16_t i = 0; i < palette_size; ++i) { +        RGB rgb             = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); +        palette[i].rgb888.r = rgb.r; +        palette[i].rgb888.g = rgb.g; +        palette[i].rgb888.b = rgb.b; +    } +    return true; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  // Append pixels to the target location, keyed by the pixel index -bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { + +bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {      uint16_t *buf = (uint16_t *)target_buffer;      for (uint32_t i = 0; i < pixel_count; ++i) {          buf[pixel_offset + i] = palette[palette_indices[i]].rgb565;      }      return true;  } + +bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { +    for (uint32_t i = 0; i < pixel_count; ++i) { +        target_buffer[(pixel_offset + i) * 3 + 0] = palette[palette_indices[i]].rgb888.r; +        target_buffer[(pixel_offset + i) * 3 + 1] = palette[palette_indices[i]].rgb888.g; +        target_buffer[(pixel_offset + i) * 3 + 2] = palette[palette_indices[i]].rgb888.b; +    } +    return true; +} diff --git a/drivers/painter/tft_panel/qp_tft_panel.h b/drivers/painter/tft_panel/qp_tft_panel.h index 6eddfc503d..3cb015891b 100644 --- a/drivers/painter/tft_panel/qp_tft_panel.h +++ b/drivers/painter/tft_panel/qp_tft_panel.h @@ -11,15 +11,10 @@  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  // Common TFT panel implementation using D/C, and RST pins. -typedef uint16_t (*rgb888_to_native_uint16_t)(uint8_t r, uint8_t g, uint8_t b); -  // Driver vtable with extras  struct tft_panel_dc_reset_painter_driver_vtable_t {      struct painter_driver_vtable_t base; // must be first, so it can be cast to/from the painter_driver_vtable_t* type -    // Conversion function for palette entries -    rgb888_to_native_uint16_t rgb888_to_native16bit; -      // Number of bytes for transmitting x/y coordinates      uint8_t num_window_bytes; @@ -58,10 +53,9 @@ bool qp_tft_panel_clear(painter_device_t device);  bool qp_tft_panel_flush(painter_device_t device);  bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);  bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count); -bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); -bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); -uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b); +bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); +bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); + +bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); +bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); diff --git a/drivers/ps2/ps2.h b/drivers/ps2/ps2.h index f123192852..2465e16235 100644 --- a/drivers/ps2/ps2.h +++ b/drivers/ps2/ps2.h @@ -89,6 +89,7 @@ uint8_t ps2_host_send(uint8_t data);  uint8_t ps2_host_recv_response(void);  uint8_t ps2_host_recv(void);  void    ps2_host_set_led(uint8_t usb_led); +bool    pbuf_has_data(void);  /*--------------------------------------------------------------------   * static functions diff --git a/drivers/ps2/ps2_interrupt.c b/drivers/ps2/ps2_interrupt.c index c49b4f8b75..c9a9f1e1ec 100644 --- a/drivers/ps2/ps2_interrupt.c +++ b/drivers/ps2/ps2_interrupt.c @@ -66,8 +66,8 @@ uint8_t ps2_error = PS2_ERR_NONE;  static inline uint8_t pbuf_dequeue(void);  static inline void    pbuf_enqueue(uint8_t data); -static inline bool    pbuf_has_data(void);  static inline void    pbuf_clear(void); +bool                  pbuf_has_data(void);  #if defined(PROTOCOL_CHIBIOS)  void ps2_interrupt_service_routine(void); @@ -309,7 +309,7 @@ static inline uint8_t pbuf_dequeue(void) {      return val;  } -static inline bool pbuf_has_data(void) { +bool pbuf_has_data(void) {  #if defined(__AVR__)      uint8_t sreg = SREG;      cli(); diff --git a/drivers/ps2/ps2_mouse.c b/drivers/ps2/ps2_mouse.c index ccb0a929ae..66b48bb3c3 100644 --- a/drivers/ps2/ps2_mouse.c +++ b/drivers/ps2/ps2_mouse.c @@ -53,6 +53,7 @@ void ps2_mouse_init(void) {      ps2_mouse_set_remote_mode();  #else      ps2_mouse_enable_data_reporting(); +    ps2_mouse_set_stream_mode();  #endif  #ifdef PS2_MOUSE_ENABLE_SCROLLING @@ -75,19 +76,33 @@ void ps2_mouse_task(void) {      extern int     tp_buttons;      /* receives packet from mouse */ +#ifdef PS2_MOUSE_USE_REMOTE_MODE      uint8_t rcv;      rcv = ps2_host_send(PS2_MOUSE_READ_DATA);      if (rcv == PS2_ACK) {          mouse_report.buttons = ps2_host_recv_response() | tp_buttons;          mouse_report.x       = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER;          mouse_report.y       = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER; -#ifdef PS2_MOUSE_ENABLE_SCROLLING +#    ifdef PS2_MOUSE_ENABLE_SCROLLING          mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER; -#endif +#    endif +    } else { +        if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); +        return; +    } +#else +    if (pbuf_has_data()) { +        mouse_report.buttons = ps2_host_recv_response() | tp_buttons; +        mouse_report.x       = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER; +        mouse_report.y       = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER; +#    ifdef PS2_MOUSE_ENABLE_SCROLLING +        mouse_report.v       = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER; +#    endif      } else {          if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n");          return;      } +#endif      /* if mouse moves or buttons state changes */      if (mouse_report.x || mouse_report.y || mouse_report.v || ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c index 2db7f916fe..1d1e4ccfc6 100644 --- a/drivers/sensors/cirque_pinnacle.c +++ b/drivers/sensors/cirque_pinnacle.c @@ -1,8 +1,13 @@  // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license +// based on https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/tree/master/Circular_Trackpad +// with modifications and changes for QMK +// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/documentation +  #include "cirque_pinnacle.h"  #include "print.h"  #include "debug.h"  #include "wait.h" +#include "timer.h"  // Registers for RAP  // clang-format off @@ -38,11 +43,9 @@  #define ADC_ATTENUATE_3X     0x80  #define ADC_ATTENUATE_4X     0xC0 -// Register config values for this demo -#define SYSCONFIG_1_VALUE    0x00 -#define FEEDCONFIG_1_VALUE   0x03  // 0x03 for absolute mode 0x01 for relative mode -#define FEEDCONFIG_2_VALUE   0x1C  // 0x1F for normal functionality 0x1E for intellimouse disabled -#define Z_IDLE_COUNT_VALUE   0x05 +#ifndef CIRQUE_PINNACLE_ATTENUATION +#    define CIRQUE_PINNACLE_ATTENUATION ADC_ATTENUATE_4X +#endif  // clang-format on  bool     touchpad_init; @@ -110,16 +113,14 @@ void cirque_pinnacle_clear_flags() {  // Enables/Disables the feed  void cirque_pinnacle_enable_feed(bool feedEnable) {      uint8_t temp; -      RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register      if (feedEnable) {          temp |= 0x01; // Set Feed Enable bit -        RAP_Write(0x04, temp);      } else {          temp &= ~0x01; // Clear Feed Enable bit -        RAP_Write(0x04, temp);      } +    RAP_Write(FEEDCONFIG_1, temp);  }  /*  ERA (Extended Register Access) Functions  */ @@ -191,7 +192,7 @@ void cirque_pinnacle_tune_edge_sensitivity(void) {      ERA_ReadBytes(0x0168, &temp, 1);  } -/*  Pinnacle-based TM040040 Functions  */ +/*  Pinnacle-based TM040040/TM035035/TM023023 Functions  */  void cirque_pinnacle_init(void) {  #if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)      spi_init(); @@ -200,39 +201,87 @@ void cirque_pinnacle_init(void) {  #endif      touchpad_init = true; +      // Host clears SW_CC flag      cirque_pinnacle_clear_flags(); -    // Host configures bits of registers 0x03 and 0x05 -    RAP_Write(SYSCONFIG_1, SYSCONFIG_1_VALUE); -    RAP_Write(FEEDCONFIG_2, FEEDCONFIG_2_VALUE); - -    // Host enables preferred output mode (absolute) -    RAP_Write(FEEDCONFIG_1, FEEDCONFIG_1_VALUE); +    // SysConfig1 (Low Power Mode) +    // Bit 0: Reset, 1=Reset +    // Bit 1: Shutdown, 1=Shutdown, 0=Active +    // Bit 2: Sleep Enable, 1=low power mode, 0=normal mode +    // send a RESET command now, in case QMK had a soft-reset without a power cycle +    RAP_Write(SYSCONFIG_1, 0x01); +    wait_ms(30); // Pinnacle needs 10-15ms to boot, so wait long enough before configuring +    RAP_Write(SYSCONFIG_1, 0x00); +    wait_us(50); -    // Host sets z-idle packet count to 5 (default is 30) -    RAP_Write(Z_IDLE_COUNT, Z_IDLE_COUNT_VALUE); +    // FeedConfig2 (Feature flags for Relative Mode Only) +    // Bit 0: IntelliMouse Enable, 1=enable, 0=disable +    // Bit 1: All Taps Disable, 1=disable, 0=enable +    // Bit 2: Secondary Tap Disable, 1=disable, 0=enable +    // Bit 3: Scroll Disable, 1=disable, 0=enable +    // Bit 4: GlideExtend® Disable, 1=disable, 0=enable +    // Bit 5: reserved +    // Bit 6: reserved +    // Bit 7: Swap X & Y, 1=90° rotation, 0=0° rotation +    RAP_Write(FEEDCONFIG_2, 0x00); + +    // FeedConfig1 (Data Output Flags) +    // Bit 0: Feed enable, 1=feed, 0=no feed +    // Bit 1: Data mode, 1=absolute, 0=relative +    // Bit 2: Filter disable, 1=no filter, 0=filter +    // Bit 3: X disable, 1=no X data, 0=X data +    // Bit 4: Y disable, 1=no Y data, 0=Y data +    // Bit 5: reserved +    // Bit 6: X data Invert, 1=X max to 0, 0=0 to Y max +    // Bit 7: Y data Invert, 1=Y max to 0, 0=0 to Y max +    RAP_Write(FEEDCONFIG_1, CIRQUE_PINNACLE_POSITION_MODE << 1); + +    // Host sets z-idle packet count to 5 (default is 0x1F/30) +    RAP_Write(Z_IDLE_COUNT, 5); + +    cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); -    cirque_pinnacle_set_adc_attenuation(0xFF);      cirque_pinnacle_tune_edge_sensitivity();      cirque_pinnacle_enable_feed(true);  } -// Reads XYZ data from Pinnacle registers 0x14 through 0x17 -// Stores result in pinnacle_data_t struct with xValue, yValue, and zValue members  pinnacle_data_t cirque_pinnacle_read_data(void) { -    uint8_t         data[6] = {0}; -    pinnacle_data_t result  = {0}; +    uint8_t         data_ready = 0; +    uint8_t         data[6]    = {0}; +    pinnacle_data_t result     = {0}; + +    // Check if there is valid data available +    RAP_ReadBytes(STATUS_1, &data_ready, 1); // bit2 is Software Data Ready, bit3 is Command Complete, bit0 and bit1 are reserved/unused +    if ((data_ready & 0x04) == 0) { +        // no data available yet +        result.valid = false; // be explicit +        return result; +    } + +    // Read all data bytes      RAP_ReadBytes(PACKET_BYTE_0, data, 6); +    // Get ready for the next data sample      cirque_pinnacle_clear_flags(); -    result.buttonFlags = data[0] & 0x3F; -    result.xValue      = data[2] | ((data[4] & 0x0F) << 8); -    result.yValue      = data[3] | ((data[4] & 0xF0) << 4); -    result.zValue      = data[5] & 0x3F; - -    result.touchDown = (result.xValue != 0 || result.yValue != 0); +#if CIRQUE_PINNACLE_POSITION_MODE +    // Decode data for absolute mode +    // Register 0x13 is unused in this mode (palm detection area) +    result.buttonFlags = data[0] & 0x3F;                             // bit0 to bit5 are switch 0-5, only hardware button presses (from input pin on the Pinnacle chip) +    result.xValue      = data[2] | ((data[4] & 0x0F) << 8);          // merge high and low bits for X +    result.yValue      = data[3] | ((data[4] & 0xF0) << 4);          // merge high and low bits for Y +    result.zValue      = data[5] & 0x3F;                             // Z is only lower 6 bits, upper 2 bits are reserved/unused +    result.touchDown   = (result.xValue != 0 || result.yValue != 0); // (0,0) is a "magic coordinate" to indicate "finger touched down" +#else +    // Decode data for relative mode +    // Registers 0x16 and 0x17 are unused in this mode +    result.buttons    = data[0] & 0x07; // bit0 = primary button, bit1 = secondary button, bit2 = auxilary button, if Taps enabled then also software-recognized taps are reported +    result.xDelta     = data[1]; +    result.yDelta     = data[2]; +    result.wheelCount = data[3]; +#endif +    result.valid = true;      return result;  } diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h index c8cb360e03..d65bdb41b6 100644 --- a/drivers/sensors/cirque_pinnacle.h +++ b/drivers/sensors/cirque_pinnacle.h @@ -5,23 +5,14 @@  #include <stdint.h>  #include <stdbool.h> -// Convenient way to store and access measurements -typedef struct { -    uint16_t xValue; -    uint16_t yValue; -    uint16_t zValue; -    uint8_t  buttonFlags; -    bool     touchDown; -} pinnacle_data_t; - -void            cirque_pinnacle_init(void); -pinnacle_data_t cirque_pinnacle_read_data(void); -void            cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution); -uint16_t        cirque_pinnacle_get_scale(void); -void            cirque_pinnacle_set_scale(uint16_t scale); -  #ifndef CIRQUE_PINNACLE_TIMEOUT -#    define CIRQUE_PINNACLE_TIMEOUT 20 +#    define CIRQUE_PINNACLE_TIMEOUT 20 // I2C timeout in milliseconds +#endif + +#define CIRQUE_PINNACLE_ABSOLUTE_MODE 1 +#define CIRQUE_PINNACLE_RELATIVE_MODE 0 +#ifndef CIRQUE_PINNACLE_POSITION_MODE +#    define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE  #endif  // Coordinate scaling values @@ -43,7 +34,9 @@ void            cirque_pinnacle_set_scale(uint16_t scale);  #ifndef CIRQUE_PINNACLE_Y_RANGE  #    define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER)  #endif - +#if !defined(POINTING_DEVICE_TASK_THROTTLE_MS) +#    define POINTING_DEVICE_TASK_THROTTLE_MS 10 // Cirque Pinnacle in normal operation produces data every 10ms. Advanced configuration for pen/stylus usage might require lower values. +#endif  #if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c)  #    include "i2c_master.h"  // Cirque's 7-bit I2C Slave Address @@ -72,3 +65,26 @@ void            cirque_pinnacle_set_scale(uint16_t scale);  #        endif  #    endif  #endif + +// Convenient way to store and access measurements +typedef struct { +    bool valid; // true if valid data was read, false if no data was ready +#if CIRQUE_PINNACLE_POSITION_MODE +    uint16_t xValue; +    uint16_t yValue; +    uint16_t zValue; +    uint8_t  buttonFlags; +    bool     touchDown; +#else +    uint8_t xDelta; +    uint8_t yDelta; +    uint8_t wheelCount; +    uint8_t buttons; +#endif +} pinnacle_data_t; + +void            cirque_pinnacle_init(void); +pinnacle_data_t cirque_pinnacle_read_data(void); +void            cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution); +uint16_t        cirque_pinnacle_get_scale(void); +void            cirque_pinnacle_set_scale(uint16_t scale); diff --git a/drivers/sensors/cirque_pinnacle_i2c.c b/drivers/sensors/cirque_pinnacle_i2c.c index 8a38f1dcea..b328dd9a7a 100644 --- a/drivers/sensors/cirque_pinnacle_i2c.c +++ b/drivers/sensors/cirque_pinnacle_i2c.c @@ -19,7 +19,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {          i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT);          if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {  #ifdef CONSOLE_ENABLE -            dprintf("error right touchpad\n"); +            dprintf("error cirque_pinnacle i2c_readReg\n");  #endif              touchpad_init = false;          } @@ -34,7 +34,7 @@ void RAP_Write(uint8_t address, uint8_t data) {      if (touchpad_init) {          if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {  #ifdef CONSOLE_ENABLE -            dprintf("error right touchpad\n"); +            dprintf("error cirque_pinnacle i2c_writeReg\n");  #endif              touchpad_init = false;          } diff --git a/drivers/sensors/cirque_pinnacle_spi.c b/drivers/sensors/cirque_pinnacle_spi.c index 34c77df07b..bd980fc863 100644 --- a/drivers/sensors/cirque_pinnacle_spi.c +++ b/drivers/sensors/cirque_pinnacle_spi.c @@ -25,7 +25,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {              }          } else {  #ifdef CONSOLE_ENABLE -            dprintf("error right touchpad\n"); +            dprintf("error cirque_pinnacle spi_start read\n");  #endif              touchpad_init = false;          } @@ -43,7 +43,7 @@ void RAP_Write(uint8_t address, uint8_t data) {              spi_write(data);          } else {  #ifdef CONSOLE_ENABLE -            dprintf("error right touchpad\n"); +            dprintf("error cirque_pinnacle spi_start write\n");  #endif              touchpad_init = false;          } diff --git a/drivers/sensors/pimoroni_trackball.c b/drivers/sensors/pimoroni_trackball.c index 333e017a06..88a351316b 100644 --- a/drivers/sensors/pimoroni_trackball.c +++ b/drivers/sensors/pimoroni_trackball.c @@ -95,16 +95,3 @@ int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_di      uint16_t magnitude = (scale * offset * offset * precision) >> 7;      return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude);  } - -void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset) { -    if (*offset > 127) { -        *mouse = 127; -        *offset -= 127; -    } else if (*offset < -127) { -        *mouse = -127; -        *offset += 127; -    } else { -        *mouse  = *offset; -        *offset = 0; -    } -} diff --git a/drivers/sensors/pimoroni_trackball.h b/drivers/sensors/pimoroni_trackball.h index e20ee748a7..749f381bbd 100644 --- a/drivers/sensors/pimoroni_trackball.h +++ b/drivers/sensors/pimoroni_trackball.h @@ -52,7 +52,6 @@ typedef struct {  void         pimoroni_trackball_device_init(void);  void         pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);  int16_t      pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); -void         pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset);  uint16_t     pimoroni_trackball_get_cpi(void);  void         pimoroni_trackball_set_cpi(uint16_t cpi);  i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data); diff --git a/drivers/serial.h b/drivers/serial.h index 0cfdbd9959..fb91b136e7 100644 --- a/drivers/serial.h +++ b/drivers/serial.h @@ -27,3 +27,13 @@ void soft_serial_initiator_init(void);  void soft_serial_target_init(void);  bool soft_serial_transaction(int sstd_index); + +#ifdef SERIAL_DEBUG +#    include <debug.h> +#    include <print.h> +#    define serial_dprintf(...) dprintf(__VA_ARGS__) +#else +#    define serial_dprintf(...) \ +        do {                    \ +        } while (0) +#endif diff --git a/drivers/wear_leveling/wear_leveling_flash_spi.c b/drivers/wear_leveling/wear_leveling_flash_spi.c new file mode 100644 index 0000000000..6191f8bf09 --- /dev/null +++ b/drivers/wear_leveling/wear_leveling_flash_spi.c @@ -0,0 +1,101 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include <stdbool.h> +#include <hal.h> +#include "util.h" +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT +#    define WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT 32 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT + +bool backing_store_init(void) { +    bs_dprintf("Init\n"); +    flash_init(); +    return true; +} + +bool backing_store_unlock(void) { +    bs_dprintf("Unlock\n"); +    // No-op -- handled by the flash driver as it is. +    return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT +    uint32_t start = timer_read32(); +#endif + +    bool ret = true; +    for (int i = 0; i < (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT); ++i) { +        flash_status_t status = flash_erase_block(((WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) + i) * (EXTERNAL_FLASH_BLOCK_SIZE)); +        if (status != FLASH_STATUS_SUCCESS) { +            ret = false; +            break; +        } +    } + +    bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); +    return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { +    return backing_store_write_bulk(address, &value, 1); +} + +bool backing_store_lock(void) { +    bs_dprintf("Lock  \n"); +    // No-op -- handled by the flash driver as it is. +    return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { +    return backing_store_read_bulk(address, value, 1); +} + +bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { +    bs_dprintf("Read  "); +    uint32_t       offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address; +    flash_status_t status = flash_read_block(offset, values, sizeof(backing_store_int_t) * item_count); +    if (status == FLASH_STATUS_SUCCESS) { +        for (size_t i = 0; i < item_count; ++i) { +            values[i] = ~values[i]; +        } +        wl_dump(offset, values, sizeof(backing_store_int_t) * item_count); +    } +    return status == FLASH_STATUS_SUCCESS; +} + +bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { +    uint32_t            offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address; +    size_t              index  = 0; +    backing_store_int_t temp[WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT]; +    do { +        // Copy out the block of data we want to transmit first +        size_t this_loop = MIN(item_count, WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT); +        for (size_t i = 0; i < this_loop; ++i) { +            temp[i] = values[index + i]; +        } + +        bs_dprintf("Write "); +        wl_dump(offset, temp, sizeof(backing_store_int_t) * this_loop); + +        // Take the complement instead +        for (size_t i = 0; i < this_loop; ++i) { +            temp[i] = ~temp[i]; +        } + +        // Write out the block +        if (flash_write_block(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) { +            return false; +        } + +        offset += this_loop * sizeof(backing_store_int_t); +        index += this_loop; +        item_count -= this_loop; +    } while (item_count > 0); + +    return true; +} diff --git a/drivers/wear_leveling/wear_leveling_flash_spi_config.h b/drivers/wear_leveling/wear_leveling_flash_spi_config.h new file mode 100644 index 0000000000..394370daa3 --- /dev/null +++ b/drivers/wear_leveling/wear_leveling_flash_spi_config.h @@ -0,0 +1,34 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +#    include <stdlib.h> +#    include <stdint.h> +#    include "flash_spi.h" +#endif + +// Use 1 block -- check the config for the SPI flash to determine how big it is +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT +#    define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT 1 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT + +// Start at the first block of the external flash +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET +#    define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET 0 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET + +// 8-byte writes by default +#ifndef BACKING_STORE_WRITE_SIZE +#    define BACKING_STORE_WRITE_SIZE 8 +#endif + +// The space allocated by the block +#ifndef WEAR_LEVELING_BACKING_SIZE +#    define WEAR_LEVELING_BACKING_SIZE ((EXTERNAL_FLASH_BLOCK_SIZE) * (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT)) +#endif // WEAR_LEVELING_BACKING_SIZE + +// Use half of the backing size for logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +#    define WEAR_LEVELING_LOGICAL_SIZE ((WEAR_LEVELING_BACKING_SIZE) / 2) +#endif // WEAR_LEVELING_LOGICAL_SIZE | 
