diff options
author | Nick Brassel <[email protected]> | 2024-08-26 10:01:57 +1000 |
---|---|---|
committer | Nick Brassel <[email protected]> | 2024-08-26 10:01:57 +1000 |
commit | 5d76c5280dc0aff398cdce19fa54d0e0725c418d (patch) | |
tree | 40026340f0d524a6006f18f01ef988e15d271075 /drivers | |
parent | e6a898e3eea3521d3f0497ee26937d5269d78fb7 (diff) | |
parent | 81dcf2b547bacc42bd9cf8ccaccd3d7164e69926 (diff) | |
download | qmk_firmware-5d76c5280dc0aff398cdce19fa54d0e0725c418d.tar.gz qmk_firmware-5d76c5280dc0aff398cdce19fa54d0e0725c418d.zip |
Merge branch 'develop'0.26.0
Diffstat (limited to 'drivers')
25 files changed, 739 insertions, 234 deletions
diff --git a/drivers/eeprom/eeprom_custom.c-template b/drivers/eeprom/eeprom_custom.c-template index 5f915f7fab..fb1f0a3a97 100644 --- a/drivers/eeprom/eeprom_custom.c-template +++ b/drivers/eeprom/eeprom_custom.c-template @@ -23,6 +23,17 @@ void eeprom_driver_init(void) { /* Any initialisation code */ } +void eeprom_driver_format(bool erase) { + /* If erase=false, then only do the absolute minimum initialisation necessary + to make sure that the eeprom driver is usable. It doesn't need to guarantee + that the content of the eeprom is reset to any particular value. For many + eeprom drivers this may be a no-op. + + If erase=true, then in addition to making sure the eeprom driver is in a + usable state, also make sure that it is erased. + */ +} + void eeprom_driver_erase(void) { /* Wipe out the EEPROM, setting values to zero */ } diff --git a/drivers/eeprom/eeprom_driver.c b/drivers/eeprom/eeprom_driver.c index 885cf21981..1f3f96f006 100644 --- a/drivers/eeprom/eeprom_driver.c +++ b/drivers/eeprom/eeprom_driver.c @@ -77,3 +77,9 @@ void eeprom_update_dword(uint32_t *addr, uint32_t value) { eeprom_write_dword(addr, value); } } + +void eeprom_driver_format(bool erase) __attribute__((weak)); +void eeprom_driver_format(bool erase) { + (void)erase; /* The default implementation assumes that the eeprom must be erased in order to be usable. */ + eeprom_driver_erase(); +} diff --git a/drivers/eeprom/eeprom_driver.h b/drivers/eeprom/eeprom_driver.h index 74592bc8f0..0c55c497d4 100644 --- a/drivers/eeprom/eeprom_driver.h +++ b/drivers/eeprom/eeprom_driver.h @@ -16,7 +16,9 @@ #pragma once +#include <stdbool.h> #include "eeprom.h" void eeprom_driver_init(void); +void eeprom_driver_format(bool erase); void eeprom_driver_erase(void); diff --git a/drivers/eeprom/eeprom_i2c.c b/drivers/eeprom/eeprom_i2c.c index 0d3d5ccbe5..d29aff5f85 100644 --- a/drivers/eeprom/eeprom_i2c.c +++ b/drivers/eeprom/eeprom_i2c.c @@ -36,6 +36,7 @@ #include "wait.h" #include "i2c_master.h" #include "eeprom.h" +#include "eeprom_driver.h" #include "eeprom_i2c.h" // #define DEBUG_EEPROM_OUTPUT @@ -62,6 +63,13 @@ void eeprom_driver_init(void) { #endif } +void eeprom_driver_format(bool erase) { + /* i2c eeproms do not need to be formatted before use */ + if (erase) { + eeprom_driver_erase(); + } +} + void eeprom_driver_erase(void) { #if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT) uint32_t start = timer_read32(); diff --git a/drivers/eeprom/eeprom_spi.c b/drivers/eeprom/eeprom_spi.c index 51ba25dece..14f0afa68b 100644 --- a/drivers/eeprom/eeprom_spi.c +++ b/drivers/eeprom/eeprom_spi.c @@ -35,6 +35,7 @@ #include "timer.h" #include "spi_master.h" #include "eeprom.h" +#include "eeprom_driver.h" #include "eeprom_spi.h" #define CMD_WREN 6 @@ -92,6 +93,13 @@ void eeprom_driver_init(void) { spi_init(); } +void eeprom_driver_format(bool erase) { + /* spi eeproms do not need to be formatted before use */ + if (erase) { + eeprom_driver_erase(); + } +} + void eeprom_driver_erase(void) { #if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT) uint32_t start = timer_read32(); diff --git a/drivers/eeprom/eeprom_transient.c b/drivers/eeprom/eeprom_transient.c index 9dc4289c27..d9f5db9853 100644 --- a/drivers/eeprom/eeprom_transient.c +++ b/drivers/eeprom/eeprom_transient.c @@ -30,8 +30,13 @@ size_t clamp_length(intptr_t offset, size_t len) { return len; } -void eeprom_driver_init(void) { - eeprom_driver_erase(); +void eeprom_driver_init(void) {} + +void eeprom_driver_format(bool erase) { + /* The transient eeprom driver doesn't necessarily need to be formatted before use, and it always starts up filled with zeros, due to placement in the .bss section */ + if (erase) { + eeprom_driver_erase(); + } } void eeprom_driver_erase(void) { diff --git a/drivers/eeprom/eeprom_wear_leveling.c b/drivers/eeprom/eeprom_wear_leveling.c index bd77eef35c..24ca6c3c6b 100644 --- a/drivers/eeprom/eeprom_wear_leveling.c +++ b/drivers/eeprom/eeprom_wear_leveling.c @@ -10,6 +10,12 @@ void eeprom_driver_init(void) { wear_leveling_init(); } +void eeprom_driver_format(bool erase) { + /* wear leveling requires the write log data structures to be erased before use. */ + (void)erase; + eeprom_driver_erase(); +} + void eeprom_driver_erase(void) { wear_leveling_erase(); } diff --git a/drivers/encoder/encoder_quadrature.c b/drivers/encoder/encoder_quadrature.c index cd589bf1e2..086f500391 100644 --- a/drivers/encoder/encoder_quadrature.c +++ b/drivers/encoder/encoder_quadrature.c @@ -22,7 +22,7 @@ #endif #undef ENCODER_DEFAULT_PIN_API_IMPL -#if defined(ENCODERS_PAD_A) && defined(ENCODERS_PAD_B) +#if defined(ENCODER_A_PINS) && defined(ENCODER_B_PINS) // Inform the quadrature driver that it needs to implement pin init/read functions # define ENCODER_DEFAULT_PIN_API_IMPL #endif @@ -34,8 +34,8 @@ __attribute__((weak)) uint8_t encoder_quadrature_read_pin(uint8_t index, bool pa #ifdef ENCODER_DEFAULT_PIN_API_IMPL -static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_A; -static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_B; +static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODER_A_PINS; +static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODER_B_PINS; __attribute__((weak)) void encoder_wait_pullup_charge(void) { wait_us(100); @@ -123,25 +123,25 @@ void encoder_driver_init(void) { // here, but it's the simplest solution. memset(encoder_state, 0, sizeof(encoder_state)); memset(encoder_pulses, 0, sizeof(encoder_pulses)); - const pin_t encoders_pad_a_left[] = ENCODERS_PAD_A; - const pin_t encoders_pad_b_left[] = ENCODERS_PAD_B; + const pin_t encoders_pad_a_left[] = ENCODER_A_PINS; + const pin_t encoders_pad_b_left[] = ENCODER_B_PINS; for (uint8_t i = 0; i < thisCount; i++) { encoders_pad_a[i] = encoders_pad_a_left[i]; encoders_pad_b[i] = encoders_pad_b_left[i]; } #endif -#if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) +#if defined(SPLIT_KEYBOARD) && defined(ENCODER_A_PINS_RIGHT) && defined(ENCODER_B_PINS_RIGHT) // Re-initialise the pads if it's the right-hand side if (!isLeftHand) { - const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; - const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; + const pin_t encoders_pad_a_right[] = ENCODER_A_PINS_RIGHT; + const pin_t encoders_pad_b_right[] = ENCODER_B_PINS_RIGHT; for (uint8_t i = 0; i < thisCount; i++) { encoders_pad_a[i] = encoders_pad_a_right[i]; encoders_pad_b[i] = encoders_pad_b_right[i]; } } -#endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) +#endif // defined(SPLIT_KEYBOARD) && defined(ENCODER_A_PINS_RIGHT) && defined(ENCODER_B_PINS_RIGHT) // Encoder resolutions is defined differently in config.h, so concatenate #if defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) diff --git a/drivers/flash/flash.h b/drivers/flash/flash.h new file mode 100644 index 0000000000..4d62475139 --- /dev/null +++ b/drivers/flash/flash.h @@ -0,0 +1,126 @@ +// Copyright 2024 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> + +/** + * @brief The status of a flash operation. + */ +enum { + FLASH_STATUS_SUCCESS = 0, //< The operation completed successfully. + FLASH_STATUS_ERROR = -1, //< An error occurred during the operation. + FLASH_STATUS_TIMEOUT = -2, //< The operation timed out. + FLASH_STATUS_BAD_ADDRESS = -3, //< The address is out of bounds. + FLASH_STATUS_BUSY = -4, //< The flash is busy. +}; + +/** + * @brief The status of a flash operation. + */ +typedef int16_t flash_status_t; + +/** + * @brief Initializes the flash driver. + * + * This function initializes the flash driver and prepares it for use. + * It should be called before any other flash-related functions are used. + */ +void flash_init(void); + +/** + * @brief Checks if the flash is busy. + * + * This function checks if the flash is currently busy with an operation. + * + * @return FLASH_STATUS_SUCCESS if the flash is not busy, FLASH_STATUS_BUSY if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_is_busy(void); + +/** + * @brief Initiates a chip erase operation. + * + * This function does not wait for the flash to become ready. + * + * @return FLASH_STATUS_SUCCESS if the erase command was successfully sent, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_begin_erase_chip(void); + +/** + * @brief Waits for the chip erase operation to complete. + * + * This function waits for the chip erase operation to complete. + * + * @return FLASH_STATUS_SUCCESS if the chip erase operation completed successfully, FLASH_STATUS_TIMEOUT if the flash was still busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_wait_erase_chip(void); + +/** + * @brief Erases the entire flash memory chip. + * + * This function initiates an erase operation to erase the entire flash memory chip. + * It waits for the operation to complete. + * + * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_erase_chip(void); + +/** + * @brief Erases a block of flash memory. + * + * This function initiates an erase operation to erase a block of flash memory. + * It waits for the operation to complete. + * + * @param addr The address of the block to erase. + * + * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_erase_block(uint32_t addr); + +/** + * @brief Erases a sector of flash memory. + * + * This function initiates an erase operation to erase a sector of flash memory. + * It waits for the operation to complete. + * + * @param addr The address of the sector to erase. + * + * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_erase_sector(uint32_t addr); + +/** + * @brief Reads a range of flash memory. + * + * This function reads a range of flash memory into a buffer. + * + * @param addr The address of the range to read. + * @param buf A pointer to the buffer to read the range into. + * @param len The length of the range to read. + * + * @return FLASH_STATUS_SUCCESS if the range was successfully read, FLASH_STATUS_BAD_ADDRESS if the address is out of bounds, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_read_range(uint32_t addr, void *buf, size_t len); + +/** + * @brief Writes a range of flash memory. + * + * This function writes a range of flash memory from a buffer. + * + * @param addr The address of the range to write. + * @param buf A pointer to the buffer to write to the range. + * @param len The length of the range to write. + * + * @return FLASH_STATUS_SUCCESS if the range was successfully written, FLASH_STATUS_BAD_ADDRESS if the address is out of bounds, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred. + */ +flash_status_t flash_write_range(uint32_t addr, const void *buf, size_t len); + +#ifdef __cplusplus +} +#endif diff --git a/drivers/flash/flash_spi.c b/drivers/flash/flash_spi.c index 0c0eb8a99e..7226773ff4 100644 --- a/drivers/flash/flash_spi.c +++ b/drivers/flash/flash_spi.c @@ -1,22 +1,10 @@ -/* -Copyright (C) 2021 Westberry Technology (ChangZhou) Corp., Ltd - -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/>. -*/ +// Copyright 2021 Westberry Technology (ChangZhou) Corp., Ltd +// Copyright 2024 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later #include <string.h> +#include "flash.h" #include "util.h" #include "wait.h" #include "debug.h" @@ -69,33 +57,43 @@ static bool spi_flash_start(void) { return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR); } -static flash_status_t spi_flash_wait_while_busy(void) { - uint32_t deadline = timer_read32() + EXTERNAL_FLASH_SPI_TIMEOUT; +static flash_status_t spi_flash_wait_while_busy_multiplier(int multiplier) { flash_status_t response = FLASH_STATUS_SUCCESS; - uint8_t retval; - + uint32_t deadline = timer_read32() + ((EXTERNAL_FLASH_SPI_TIMEOUT)*multiplier); do { - bool res = spi_flash_start(); - if (!res) { - dprint("Failed to start SPI! [spi flash wait while busy]\n"); - return FLASH_STATUS_ERROR; - } - - spi_write(FLASH_CMD_RDSR); - - retval = (uint8_t)spi_read(); - - spi_stop(); - if (timer_read32() >= deadline) { response = FLASH_STATUS_TIMEOUT; break; } - } while (retval & FLASH_FLAG_WIP); + response = flash_is_busy(); + } while (response == FLASH_STATUS_BUSY); return response; } +static flash_status_t spi_flash_wait_while_busy(void) { + return spi_flash_wait_while_busy_multiplier(1); +} + +flash_status_t flash_is_busy(void) { + bool res = spi_flash_start(); + if (!res) { + dprint("Failed to start SPI! [spi flash wait while busy]\n"); + return FLASH_STATUS_ERROR; + } + + spi_write(FLASH_CMD_RDSR); + spi_status_t status = spi_read(); + spi_stop(); + + if (status < 0) { + return status; + } + + uint8_t sr = (uint8_t)status; + return (sr & FLASH_FLAG_WIP) ? FLASH_STATUS_BUSY : FLASH_STATUS_SUCCESS; +} + static flash_status_t spi_flash_write_enable(void) { bool res = spi_flash_start(); if (!res) { @@ -104,7 +102,6 @@ static flash_status_t spi_flash_write_enable(void) { } spi_write(FLASH_CMD_WREN); - spi_stop(); return FLASH_STATUS_SUCCESS; @@ -118,7 +115,6 @@ static flash_status_t spi_flash_write_disable(void) { } spi_write(FLASH_CMD_WRDI); - spi_stop(); return FLASH_STATUS_SUCCESS; @@ -166,7 +162,7 @@ void flash_init(void) { spi_init(); } -flash_status_t flash_erase_chip(void) { +flash_status_t flash_begin_erase_chip(void) { flash_status_t response = FLASH_STATUS_SUCCESS; /* Wait for the write-in-progress bit to be cleared. */ @@ -191,17 +187,28 @@ flash_status_t flash_erase_chip(void) { } spi_write(FLASH_CMD_CE); spi_stop(); + return FLASH_STATUS_SUCCESS; +} - /* Wait for the write-in-progress bit to be cleared.*/ - response = spi_flash_wait_while_busy(); +flash_status_t flash_wait_erase_chip(void) { + flash_status_t response = spi_flash_wait_while_busy_multiplier(250); // Chip erase can take a long time, wait 250x the usual timeout if (response != FLASH_STATUS_SUCCESS) { dprint("Failed to check WIP flag! [spi flash erase chip]\n"); return response; } - return response; } +flash_status_t flash_erase_chip(void) { + flash_status_t response = flash_begin_erase_chip(); + if (response != FLASH_STATUS_SUCCESS) { + dprint("Failed to begin erase chip! [spi flash erase chip]\n"); + return response; + } + + return flash_wait_erase_chip(); +} + flash_status_t flash_erase_sector(uint32_t addr) { flash_status_t response = FLASH_STATUS_SUCCESS; @@ -282,7 +289,7 @@ flash_status_t flash_erase_block(uint32_t addr) { return response; } -flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len) { +flash_status_t flash_read_range(uint32_t addr, void *buf, size_t len) { flash_status_t response = FLASH_STATUS_SUCCESS; uint8_t * read_buf = (uint8_t *)buf; @@ -313,7 +320,7 @@ flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len) { return response; } -flash_status_t flash_write_block(uint32_t addr, const void *buf, size_t len) { +flash_status_t flash_write_range(uint32_t addr, const void *buf, size_t len) { flash_status_t response = FLASH_STATUS_SUCCESS; uint8_t * write_buf = (uint8_t *)buf; diff --git a/drivers/flash/flash_spi.h b/drivers/flash/flash_spi.h index 87460fc210..7a979daf0f 100644 --- a/drivers/flash/flash_spi.h +++ b/drivers/flash/flash_spi.h @@ -17,6 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #pragma once +#include "flash.h" + /* All the following default configurations are based on MX25L4006E Nor FLASH. */ /* @@ -105,32 +107,3 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. The page count of the FLASH, calculated by total FLASH size and page size. */ #define EXTERNAL_FLASH_PAGE_COUNT ((EXTERNAL_FLASH_SIZE) / (EXTERNAL_FLASH_PAGE_SIZE)) - -typedef int16_t flash_status_t; - -#define FLASH_STATUS_SUCCESS (0) -#define FLASH_STATUS_ERROR (-1) -#define FLASH_STATUS_TIMEOUT (-2) -#define FLASH_STATUS_BAD_ADDRESS (-3) - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -void flash_init(void); - -flash_status_t flash_erase_chip(void); - -flash_status_t flash_erase_block(uint32_t addr); - -flash_status_t flash_erase_sector(uint32_t addr); - -flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len); - -flash_status_t flash_write_block(uint32_t addr, const void *buf, size_t len); - -#ifdef __cplusplus -} -#endif diff --git a/drivers/led/apa102.c b/drivers/led/apa102.c index b171b07b12..0cf0ecb401 100644 --- a/drivers/led/apa102.c +++ b/drivers/led/apa102.c @@ -53,7 +53,8 @@ io_wait; \ } while (0) -uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS; +rgb_led_t apa102_leds[APA102_LED_COUNT]; +uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS; static void apa102_send_byte(uint8_t byte) { APA102_SEND_BIT(byte, 7); @@ -121,14 +122,24 @@ void apa102_init(void) { gpio_set_pin_output(APA102_CI_PIN); } -void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds) { - rgb_led_t *end = start_led + num_leds; +void apa102_set_color(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { + apa102_leds[index].r = red; + apa102_leds[index].g = green; + apa102_leds[index].b = blue; +} + +void apa102_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (uint16_t i = 0; i < APA102_LED_COUNT; i++) { + apa102_set_color(i, red, green, blue); + } +} +void apa102_flush(void) { apa102_start_frame(); - for (rgb_led_t *led = start_led; led < end; led++) { - apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness); + for (uint8_t i = 0; i < APA102_LED_COUNT; i++) { + apa102_send_frame(apa102_leds[i].r, apa102_leds[i].g, apa102_leds[i].b, apa102_led_brightness); } - apa102_end_frame(num_leds); + apa102_end_frame(APA102_LED_COUNT); } void apa102_set_brightness(uint8_t brightness) { diff --git a/drivers/led/apa102.h b/drivers/led/apa102.h index 5e2f78658b..42f1344f0c 100644 --- a/drivers/led/apa102.h +++ b/drivers/led/apa102.h @@ -32,17 +32,8 @@ #define APA102_MAX_BRIGHTNESS 31 void apa102_init(void); - -/* User Interface - * - * Input: - * start_led: An array of GRB data describing the LED colors - * num_leds: The number of LEDs to write - * - * The functions will perform the following actions: - * - Set the data-out pin as output - * - Send out the LED data - */ -void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds); +void apa102_set_color(uint16_t index, uint8_t red, uint8_t green, uint8_t blue); +void apa102_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void apa102_flush(void); void apa102_set_brightness(uint8_t brightness); diff --git a/drivers/painter/gc9a01/qp_gc9a01_opcodes.h b/drivers/painter/gc9a01/qp_gc9a01_opcodes.h deleted file mode 100644 index 828e42752b..0000000000 --- a/drivers/painter/gc9a01/qp_gc9a01_opcodes.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2021 Paul Cotter (@gr1mr3aver) -// SPDX-License-Identifier: GPL-2.0-or-later -#pragma once - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Quantum Painter GC9A01 command opcodes -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Level 1 command opcodes - -#define GC9A01_GET_ID_INFO 0x04 // Get ID information -#define GC9A01_GET_STATUS 0x09 // Get status -#define GC9A01_CMD_SLEEP_ON 0x10 // Enter sleep mode -#define GC9A01_CMD_SLEEP_OFF 0x11 // Exit sleep mode -#define GC9A01_CMD_PARTIAL_ON 0x12 // Enter partial mode -#define GC9A01_CMD_PARTIAL_OFF 0x13 // Exit partial mode -#define GC9A01_CMD_INVERT_ON 0x20 // Enter inverted mode -#define GC9A01_CMD_INVERT_OFF 0x21 // Exit inverted mode -#define GC9A01_CMD_DISPLAY_OFF 0x28 // Disable display -#define GC9A01_CMD_DISPLAY_ON 0x29 // Enable display -#define GC9A01_SET_COL_ADDR 0x2A // Set column address -#define GC9A01_SET_PAGE_ADDR 0x2B // Set page address -#define GC9A01_SET_MEM 0x2C // Set memory -#define GC9A01_SET_PARTIAL_AREA 0x30 // Set partial area -#define GC9A01_SET_VSCROLL 0x33 // Set vertical scroll def -#define GC9A01_CMD_TEARING_ON 0x34 // Tearing line enabled -#define GC9A01_CMD_TEARING_OFF 0x35 // Tearing line disabled -#define GC9A01_SET_MEM_ACS_CTL 0x36 // Set mem access ctl -#define GC9A01_SET_VSCROLL_ADDR 0x37 // Set vscroll start addr -#define GC9A01_CMD_IDLE_OFF 0x38 // Exit idle mode -#define GC9A01_CMD_IDLE_ON 0x39 // Enter idle mode -#define GC9A01_SET_PIX_FMT 0x3A // Set pixel format -#define GC9A01_SET_MEM_CONT 0x3C // Set memory continue -#define GC9A01_SET_TEAR_SCANLINE 0x44 // Set tearing scanline -#define GC9A01_GET_TEAR_SCANLINE 0x45 // Get tearing scanline -#define GC9A01_SET_BRIGHTNESS 0x51 // Set brightness -#define GC9A01_SET_DISPLAY_CTL 0x53 // Set display ctl -#define GC9A01_GET_ID1 0xDA // Get ID1 -#define GC9A01_GET_ID2 0xDB // Get ID2 -#define GC9A01_GET_ID3 0xDC // Get ID3 - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Level 2 command opcodes - -#define GC9A01_SET_RGB_IF_SIG_CTL 0xB0 // RGB IF signal ctl -#define GC9A01_SET_BLANKING_PORCH_CTL 0xB5 // Set blanking porch ctl -#define GC9A01_SET_FUNCTION_CTL 0xB6 // Set function ctl -#define GC9A01_SET_TEARING_EFFECT 0xBA // Set backlight ctl 3 -#define GC9A01_SET_IF_CTL 0xF6 // Set interface control - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Level 3 command opcodes - -#define GC9A01_SET_FRAME_RATE 0xE8 // Set frame rate -#define GC9A01_SET_SPI_2DATA 0xE9 // Set frame rate -#define GC9A01_SET_POWER_CTL_1 0xC1 // Set power ctl 1 -#define GC9A01_SET_POWER_CTL_2 0xC3 // Set power ctl 2 -#define GC9A01_SET_POWER_CTL_3 0xC4 // Set power ctl 3 -#define GC9A01_SET_POWER_CTL_4 0xC9 // Set power ctl 4 -#define GC9A01_SET_POWER_CTL_7 0xA7 // Set power ctl 7 -#define GC9A01_SET_INTER_REG_ENABLE1 0xFE // Enable Inter Register 1 -#define GC9A01_SET_INTER_REG_ENABLE2 0xEF // Enable Inter Register 2 -#define GC9A01_SET_GAMMA1 0xF0 // -#define GC9A01_SET_GAMMA2 0xF1 -#define GC9A01_SET_GAMMA3 0xF2 -#define GC9A01_SET_GAMMA4 0xF3 - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// MADCTL Flags -#define GC9A01_MADCTL_MY 0b10000000 -#define GC9A01_MADCTL_MX 0b01000000 -#define GC9A01_MADCTL_MV 0b00100000 -#define GC9A01_MADCTL_ML 0b00010000 -#define GC9A01_MADCTL_RGB 0b00000000 -#define GC9A01_MADCTL_BGR 0b00001000 -#define GC9A01_MADCTL_MH 0b00000100 diff --git a/drivers/painter/gc9xxx/qp_gc9107.c b/drivers/painter/gc9xxx/qp_gc9107.c new file mode 100644 index 0000000000..108344da4f --- /dev/null +++ b/drivers/painter/gc9xxx/qp_gc9107.c @@ -0,0 +1,114 @@ +// Copyright 2024 Fernando Birra +// SPDX-License-Identifier: GPL-2.0-or-later +#include "qp_internal.h" +#include "qp_comms.h" +#include "qp_gc9107.h" +#include "qp_gc9xxx_opcodes.h" +#include "qp_gc9107_opcodes.h" +#include "qp_tft_panel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver storage +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +tft_panel_dc_reset_painter_device_t gc9107_drivers[GC9107_NUM_DEVICES] = {0}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Initialization +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +__attribute__((weak)) bool qp_gc9107_init(painter_device_t device, painter_rotation_t rotation) { + // A lot of these "unknown" opcodes are sourced from other OSS projects and are seemingly required for this display to function. + // clang-format off + const uint8_t gc9107_init_sequence[] = { + GC9XXX_SET_INTER_REG_ENABLE1, 5, 0, + GC9XXX_SET_INTER_REG_ENABLE2, 5, 0, + GC9107_SET_FUNCTION_CTL6, 0, 1, GC9107_ALLOW_SET_COMPLEMENT_RGB | 0x08 | GC9107_ALLOW_SET_FRAMERATE, + GC9107_SET_COMPLEMENT_RGB, 0, 1, GC9107_COMPLEMENT_WITH_LSB, + 0xAB, 0, 1, 0x0E, + GC9107_SET_FRAME_RATE, 0, 1, 0x19, + GC9XXX_SET_PIXEL_FORMAT, 0, 1, GC9107_PIXEL_FORMAT_16_BPP_IFPF, + GC9XXX_CMD_SLEEP_OFF, 120, 0, + GC9XXX_CMD_DISPLAY_ON, 20, 0 + }; + + // clang-format on + qp_comms_bulk_command_sequence(device, gc9107_init_sequence, sizeof(gc9107_init_sequence)); + + // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) + const uint8_t madctl[] = { + [QP_ROTATION_0] = GC9XXX_MADCTL_BGR, + [QP_ROTATION_90] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MX | GC9XXX_MADCTL_MV, + [QP_ROTATION_180] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MX | GC9XXX_MADCTL_MY, + [QP_ROTATION_270] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MV | GC9XXX_MADCTL_MY, + }; + qp_comms_command_databyte(device, GC9XXX_SET_MEM_ACS_CTL, madctl[rotation]); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver vtable +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const tft_panel_dc_reset_painter_driver_vtable_t gc9107_driver_vtable = { + .base = + { + .init = qp_gc9107_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_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, + .append_pixdata = qp_tft_panel_append_pixdata, + }, + .num_window_bytes = 2, + .swap_window_coords = false, + .opcodes = + { + .display_on = GC9XXX_CMD_DISPLAY_ON, + .display_off = GC9XXX_CMD_DISPLAY_OFF, + .set_column_address = GC9XXX_SET_COL_ADDR, + .set_row_address = GC9XXX_SET_ROW_ADDR, + .enable_writes = GC9XXX_SET_MEM, + }, +}; + +#ifdef QUANTUM_PAINTER_GC9107_SPI_ENABLE +// Factory function for creating a handle to the GC9107 device +painter_device_t qp_gc9107_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 < GC9107_NUM_DEVICES; ++i) { + tft_panel_dc_reset_painter_device_t *driver = &gc9107_drivers[i]; + if (!driver->base.driver_vtable) { + driver->base.driver_vtable = (const painter_driver_vtable_t *)&gc9107_driver_vtable; + driver->base.comms_vtable = (const painter_comms_vtable_t *)&spi_comms_with_dc_vtable; + driver->base.native_bits_per_pixel = 16; // RGB565 + driver->base.panel_width = panel_width; + driver->base.panel_height = panel_height; + driver->base.rotation = QP_ROTATION_0; + driver->base.offset_x = 2; + driver->base.offset_y = 1; + + // 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; + driver->spi_dc_reset_config.command_params_uses_command_pin = false; + + if (!qp_internal_register_device((painter_device_t)driver)) { + memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t)); + return NULL; + } + + return (painter_device_t)driver; + } + } + return NULL; +} + +#endif // QUANTUM_PAINTER_GC9107_SPI_ENABLE diff --git a/drivers/painter/gc9xxx/qp_gc9107.h b/drivers/painter/gc9xxx/qp_gc9107.h new file mode 100644 index 0000000000..b0b08f7665 --- /dev/null +++ b/drivers/painter/gc9xxx/qp_gc9107.h @@ -0,0 +1,37 @@ +// Copyright 2024 Fernando Birra (@gr1mr3aver) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include "gpio.h" +#include "qp_internal.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter GC9107 configurables (add to your keyboard's config.h) + +#ifndef GC9107_NUM_DEVICES +/** + * @def This controls the maximum number of GC9107 devices that Quantum Painter can communicate with at any one time. + * Increasing this number allows for multiple displays to be used. + */ +# define GC9107_NUM_DEVICES 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter GC9107 device factories + +#ifdef QUANTUM_PAINTER_GC9107_SPI_ENABLE +/** + * Factory method for an GC9107 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_gc9107_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_GC9107_SPI_ENABLE diff --git a/drivers/painter/gc9xxx/qp_gc9107_opcodes.h b/drivers/painter/gc9xxx/qp_gc9107_opcodes.h new file mode 100644 index 0000000000..e9b308eb49 --- /dev/null +++ b/drivers/painter/gc9xxx/qp_gc9107_opcodes.h @@ -0,0 +1,135 @@ +// Copyright 2024 Fernando Birra +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter GC9107 command opcodes +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define GC9107_GET_POWER_MODE 0x0A // Get power mode +#define GC9107_GET_MADCTL 0x0B // Get MADCTL +#define GC9107_GET_PIXEL_FMT 0x0C // Get pixel format +#define GC9107_GET_IMAGE_FMT 0x0D // Get image format +#define GC9107_GET_SIGNAL_MODE 0x0E // Get signal mode +#define GC9107_GET_DIAG_RESULT 0x0F // Get self-diagnostic results + +#define GC9107_SET_FRAME_RATE 0xA8 // Set frame rate +#define GC9107_SET_COMPLEMENT_RGB 0xAC // Set complement Principle RGB +#define GC9107_SET_BLANK_PORCH 0xAD // Set blank porch control, 0;front_porch[6:0],0;back_porch[6:0] +#define GC9107_SET_FUNCTION_CTL1 0xB1 // Set access to AVDD_VCL_CLK and VGH_VGL_CLK commands +#define GC9107_SET_FUNCTION_CTL2 0xB2 // Set access to VGH, VGH control commands +#define GC9107_SET_FUNCTION_CTL3 0xB3 // Set access to Gamma control commands +#define GC9107_SET_DISPLAY_INVERSION 0xB4 // Set Display Inversion control +#define GC9107_SET_FUNCTION_CTL6 0xB6 // Set access to commands SET_FRAME_RATE, SET_COMPLEMENT_RGB and SET_BLANK_PORCH +#define GC9107_SET_CUSTOM_ID_INFO 0xD3 // Set customized display id information +#define GC9107_AVDD_VCL_CLK 0xE3 // AVDD_CLK +#define GC9107_SET_VGH 0xE8 // Set VGH +#define GC9107_SET_VGL 0xE9 // Set VGL +#define GC9107_SET_VGH_VGL_CLK 0xEA // Set VGH and VGL clock divisors + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GC9107 Parameter constants + +// Parameter values for +// GC9107_SET_PIXEL_FORMAT +#define GC9107_PIXEL_FORMAT_12_BPP_IFPF (0b001 << 0) // 12 bits per pixel +#define GC9107_PIXEL_FORMAT_16_BPP_IFPF (0b101 << 0) // 16 bits per pixel +#define GC9107_PIXEL_FORMAT_18_BPP_IFPB (0b110 << 0) // 18 bits per pixel + +// Parameter values for +// GC9107_SET_COMPLEMENT_RGB +#define GC9107_COMPLEMENT_WITH_0 0x00 // R0 <- B0 <- 0, except if data is FFh +#define GC9107_COMPLEMENT_WITH_1 0x40 // R0 <- B0 <- 1, except if data is 00h +#define GC9107_COMPLEMENT_WITH_MSB 0x80 // R0 <- R5, B0 <- B5 +#define GC9107_COMPLEMENT_WITH_LSB 0xC0 // R0 <- B0 <- G0 +// Parameter masks for +// GC9107_SET_FUNCTION_CTL1 +#define GC9107_ALLOW_AVDD_VCL_CLK 0b00001000 // Allow AVDD_VCL_CLK command +// Parameter masks for +// GC9107_SET_FUNCTION_CTL2 +#define GC9107_ALLOW_SET_VGH 0b00000001 // Allow GC9107_SET_VGH +#define GC9107_ALLOW_SET_VGL 0b00000010 // Allow GC9107_SET_VGL +#define GC9107_ALLOW_SET_VGH_VGL_CLK 0b00000100 // Allow GC9107_SET_VGH_VGL_CLK +// Parameter masks for +// GC9107_SET_FUNCTION_CTL3 +#define GC9107_ALLOW_SET_GAMMA1 0b00000001 // Allow GC9107_SET_GAMMA1 +#define GC9107_ALLOW_SET_GAMMA2 0b00000010 // Allow GC9107_SET_GAMMA2 +// Parameter mask for +// GC9107_SET_FUNCTION_CTL6 +#define GC9107_ALLOW_SET_FRAMERATE 0b000000001 // Allow GC9107_SET_FRAME_RATE +#define GC9107_ALLOW_SET_COMPLEMENT_RGB 0b000010000 // Allow GC9107_SET_COMPLEMENT_RGB +#define GC9107_ALLOW_SET_BLANK_PORCH 0b000100000 // Allow GFC9107_SET_BLANK_PORCH +// Parameter values for +// AVDD_CLK_AD part (Most significant nibble) +#define GC9107_AVDD_CLK_AD_2T 0x00 +#define GC9107_AVDD_CLK_AD_3T 0x10 +#define GC9107_AVDD_CLK_AD_4T 0x20 +#define GC9107_AVDD_CLK_AD_5T 0x30 +#define GC9107_AVDD_CLK_AD_6T 0x40 +#define GC9107_AVDD_CLK_AD_7T 0x50 +#define GC9107_AVDD_CLK_AD_8T 0x60 +#define GC9107_AVDD_CLK_AD_9T 0x70 +// Parameter values for +// VCL_CLK_AD part (Least significant nibble) +#define GC9107_VCL_CLK_AD_2T 0x00 +#define GC9107_VCL_CLK_AD_3T 0x01 +#define GC9107_VCL_CLK_AD_4T 0x02 +#define GC9107_VCL_CLK_AD_5T 0x03 +#define GC9107_VCL_CLK_AD_6T 0x04 +#define GC9107_VCL_CLK_AD_7T 0x05 +#define GC9107_VCL_CLK_AD_8T 0x06 +#define GC9107_VCL_CLK_AD_9T 0x07 +// Parameter values for +// GC9107_SET_VGH +#define GC9107_VGH_P100 0x20 // +10 V +#define GC9107_VGH_P110 0x21 // +11 V +#define GC9107_VGH_P120 0x22 // +12 V +#define GC9107_VGH_P130 0x23 // +13 V +#define GC9107_VGH_P140 0x24 // +14 V +#define GC9107_VGH_P150 0x25 // +15 V +// Parameter values for +// GC9107_SET_VGL +#define VGL_N_075 0x40 // -7.5 V +#define VGL_N_085 0x41 // -8.5 V +#define VGL_N_095 0x42 // -9.5 V +#define VGL_N_100 0x43 // -10.0 V +#define VGL_N_105 0x44 // -10.5 V +#define VGL_N_110 0x45 // -11.0 V +#define VGL_N_120 0x46 // -12.0 V +#define VGL_N_130 0x47 // -13.0 V +// Parameter masks for +// GC9107_SET_VGH_VGL_CLK (VGH Divisor) +#define GC9107_VGH_CLK_DIV_2 0x00 // Clock divisor = 2 -> 6.0 Mhz +#define GC9107_VGH_CLK_DIV_3 0x10 // Clock divisor = 3 -> 4.0 Mhz +#define GC9107_VGH_CLK_DIV_4 0x20 // Clock divisor = 4 -> 3.0 Mhz +#define GC9107_VGH_CLK_DIV_5 0x30 // Clock divisor = 5 -> 2.4 Mhz +#define GC9107_VGH_CLK_DIV_6 0x40 // Clock divisor = 6 -> 2.0 Mhz +#define GC9107_VGH_CLK_DIV_7 0x50 // Clock divisor = 7 -> 1.7 Mhz +#define GC9107_VGH_CLK_DIV_8 0x60 // Clock divisor = 8 -> 1.5 Mhz +#define GC9107_VGH_CLK_DIV_9 0x70 // Clock divisor = 9 -> 1.3 Mhz +#define GC9107_VGH_CLK_DIV_10 0x80 // Clock divisor = 10 -> 1.2 Mhz +#define GC9107_VGH_CLK_DIV_12 0x90 // Clock divisor = 12 -> 1.0 Mhz +#define GC9107_VGH_CLK_DIV_15 0xA0 // Clock divisor = 15 -> 0.8 Mhz +#define GC9107_VGH_CLK_DIV_20 0xB0 // Clock divisor = 20 -> 0.6 Mhz +#define GC9107_VGH_CLK_DIV_24 0xC0 // Clock divisor = 24 -> 0.5 Mhz +#define GC9107_VGH_CLK_DIV_30 0xD0 // Clock divisor = 30 -> 0.4 Mhz +#define GC9107_VGH_CLK_DIV_40 0xE0 // Clock divisor = 40 -> 0.3 Mhz +#define GC9107_VGH_CLK_DIV_60 0xE0 // Clock divisor = 40 -> 0.2 Mhz +// Parameter masks for +// GC9107_SET_VGH_VGL_CLK (VGL Divisor) +#define GC9107_VGL_CLK_DIV_2 0x00 // Clock divisor = 2 -> 6.0 Mhz +#define GC9107_VGL_CLK_DIV_3 0x01 // Clock divisor = 3 -> 4.0 Mhz +#define GC9107_VGL_CLK_DIV_4 0x02 // Clock divisor = 4 -> 3.0 Mhz +#define GC9107_VGL_CLK_DIV_5 0x03 // Clock divisor = 5 -> 2.4 Mhz +#define GC9107_VGL_CLK_DIV_6 0x04 // Clock divisor = 6 -> 2.0 Mhz +#define GC9107_VGL_CLK_DIV_7 0x05 // Clock divisor = 7 -> 1.7 Mhz +#define GC9107_VGL_CLK_DIV_8 0x06 // Clock divisor = 8 -> 1.5 Mhz +#define GC9107_VGL_CLK_DIV_9 0x07 // Clock divisor = 9 -> 1.3 Mhz +#define GC9107_VGL_CLK_DIV_10 0x08 // Clock divisor = 10 -> 1.2 Mhz +#define GC9107_VGL_CLK_DIV_12 0x09 // Clock divisor = 12 -> 1.0 Mhz +#define GC9107_VGL_CLK_DIV_15 0x0A // Clock divisor = 15 -> 0.8 Mhz +#define GC9107_VGL_CLK_DIV_20 0x0B // Clock divisor = 20 -> 0.6 Mhz +#define GC9107_VGL_CLK_DIV_24 0x0C // Clock divisor = 24 -> 0.5 Mhz +#define GC9107_VGL_CLK_DIV_30 0x0D // Clock divisor = 30 -> 0.4 Mhz +#define GC9107_VGL_CLK_DIV_40 0x0E // Clock divisor = 40 -> 0.3 Mhz +#define GC9107_VGL_CLK_DIV_60 0x0E // Clock divisor = 40 -> 0.2 Mhz diff --git a/drivers/painter/gc9a01/qp_gc9a01.c b/drivers/painter/gc9xxx/qp_gc9a01.c index fe6fa7a9d0..f037a4cc87 100644 --- a/drivers/painter/gc9a01/qp_gc9a01.c +++ b/drivers/painter/gc9xxx/qp_gc9a01.c @@ -5,6 +5,7 @@ #include "qp_internal.h" #include "qp_comms.h" #include "qp_gc9a01.h" +#include "qp_gc9xxx_opcodes.h" #include "qp_gc9a01_opcodes.h" #include "qp_tft_panel.h" @@ -20,71 +21,40 @@ tft_panel_dc_reset_painter_device_t gc9a01_drivers[GC9A01_NUM_DEVICES] = {0}; __attribute__((weak)) bool qp_gc9a01_init(painter_device_t device, painter_rotation_t rotation) { // A lot of these "unknown" opcodes are sourced from other OSS projects and are seemingly required for this display to function. // clang-format off + const uint8_t gc9a01_init_sequence[] = { // Command, Delay, N, Data[N] - GC9A01_SET_INTER_REG_ENABLE2, 0, 0, - 0xEB, 0, 1, 0x14, - GC9A01_SET_INTER_REG_ENABLE1, 0, 0, - GC9A01_SET_INTER_REG_ENABLE2, 0, 0, - 0xEB, 0, 1, 0x14, + GC9XXX_SET_INTER_REG_ENABLE1, 0, 0, + GC9XXX_SET_INTER_REG_ENABLE2, 0, 0, 0x84, 0, 1, 0x40, - 0x85, 0, 1, 0xFF, - 0x86, 0, 1, 0xFF, - 0x87, 0, 1, 0xFF, - 0x88, 0, 1, 0x0A, - 0x89, 0, 1, 0x21, - 0x8a, 0, 1, 0x00, - 0x8b, 0, 1, 0x80, - 0x8c, 0, 1, 0x01, - 0x8d, 0, 1, 0x01, - 0x8e, 0, 1, 0xFF, - 0x8f, 0, 1, 0xFF, - GC9A01_SET_FUNCTION_CTL, 0, 2, 0x00, 0x20, - GC9A01_SET_PIX_FMT, 0, 1, 0x55, - 0x90, 0, 4, 0x08, 0x08, 0x08, 0x08, - 0xBD, 0, 1, 0x06, - 0xBC, 0, 1, 0x00, - 0xFF, 0, 3, 0x60, 0x01, 0x04, - GC9A01_SET_POWER_CTL_2, 0, 1, 0x13, - GC9A01_SET_POWER_CTL_3, 0, 1, 0x13, + GC9A01_SET_FUNCTION_CTL, 0, 3, 0x00, GC9A01_SOURCE_OUTPUT_SCAN_DIRECTION_S360_TO_S1 | GC9A01_GATE_OUTPUT_SCAN_DIRECTION_G1_TO_G32, GC9A01_LCD_DRIVE_LINE_240, // Only works if the previous command is present (undocumented) + GC9A01_SET_POWER_CTL_2, 0, 1, 0x20, + GC9A01_SET_POWER_CTL_3, 0, 1, 0x20, GC9A01_SET_POWER_CTL_4, 0, 1, 0x22, - 0xBE, 0, 1, 0x11, - 0xE1, 0, 2, 0x10, 0x0E, - 0xDF, 0, 3, 0x21, 0x0C, 0x02, - GC9A01_SET_GAMMA1, 0, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, - GC9A01_SET_GAMMA2, 0, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, + GC9XXX_SET_GAMMA1, 0, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, + GC9XXX_SET_GAMMA2, 0, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, GC9A01_SET_GAMMA3, 0, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, GC9A01_SET_GAMMA4, 0, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, - 0xED, 0, 2, 0x1B, 0x0B, - 0xAE, 0, 1, 0x77, - 0xCD, 0, 1, 0x63, - 0x70, 0, 9, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03, - GC9A01_SET_FRAME_RATE, 0, 1, 0x34, - 0x62, 0, 12, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70, - 0x63, 0, 12, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70, - 0x64, 0, 7, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07, 0x66, 0, 10, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00, 0x67, 0, 10, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98, - 0x74, 0, 7, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00, - 0x98, 0, 2, 0x3E, 0x07, - GC9A01_CMD_TEARING_OFF, 0, 0, - GC9A01_CMD_INVERT_OFF, 0, 0, - GC9A01_CMD_SLEEP_OFF, 120, 0, - GC9A01_CMD_DISPLAY_ON, 20, 0 + GC9XXX_CMD_TEARING_ON, 0, 0, + GC9XXX_SET_PIXEL_FORMAT, 0, 1, GC9A01_PIXEL_FORMAT_16_BPP_DBI, + GC9XXX_CMD_INVERT_ON, 0, 0, + GC9XXX_CMD_SLEEP_OFF, 120, 0, + GC9XXX_CMD_DISPLAY_ON, 20, 0 }; // clang-format on - // clang-format on qp_comms_bulk_command_sequence(device, gc9a01_init_sequence, sizeof(gc9a01_init_sequence)); // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) const uint8_t madctl[] = { - [QP_ROTATION_0] = GC9A01_MADCTL_BGR, - [QP_ROTATION_90] = GC9A01_MADCTL_BGR | GC9A01_MADCTL_MX | GC9A01_MADCTL_MV, - [QP_ROTATION_180] = GC9A01_MADCTL_BGR | GC9A01_MADCTL_MX | GC9A01_MADCTL_MY, - [QP_ROTATION_270] = GC9A01_MADCTL_BGR | GC9A01_MADCTL_MV | GC9A01_MADCTL_MY, + [QP_ROTATION_0] = GC9XXX_MADCTL_BGR, + [QP_ROTATION_90] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MX | GC9XXX_MADCTL_MV, + [QP_ROTATION_180] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MX | GC9XXX_MADCTL_MY, + [QP_ROTATION_270] = GC9XXX_MADCTL_BGR | GC9XXX_MADCTL_MV | GC9XXX_MADCTL_MY, }; - qp_comms_command_databyte(device, GC9A01_SET_MEM_ACS_CTL, madctl[rotation]); + qp_comms_command_databyte(device, GC9XXX_SET_MEM_ACS_CTL, madctl[rotation]); return true; } @@ -110,11 +80,11 @@ const tft_panel_dc_reset_painter_driver_vtable_t gc9a01_driver_vtable = { .swap_window_coords = false, .opcodes = { - .display_on = GC9A01_CMD_DISPLAY_ON, - .display_off = GC9A01_CMD_DISPLAY_OFF, - .set_column_address = GC9A01_SET_COL_ADDR, - .set_row_address = GC9A01_SET_PAGE_ADDR, - .enable_writes = GC9A01_SET_MEM, + .display_on = GC9XXX_CMD_DISPLAY_ON, + .display_off = GC9XXX_CMD_DISPLAY_OFF, + .set_column_address = GC9XXX_SET_COL_ADDR, + .set_row_address = GC9XXX_SET_ROW_ADDR, + .enable_writes = GC9XXX_SET_MEM, }, }; diff --git a/drivers/painter/gc9a01/qp_gc9a01.h b/drivers/painter/gc9xxx/qp_gc9a01.h index 31a3804b50..31a3804b50 100644 --- a/drivers/painter/gc9a01/qp_gc9a01.h +++ b/drivers/painter/gc9xxx/qp_gc9a01.h diff --git a/drivers/painter/gc9xxx/qp_gc9a01_opcodes.h b/drivers/painter/gc9xxx/qp_gc9a01_opcodes.h new file mode 100644 index 0000000000..5853902e68 --- /dev/null +++ b/drivers/painter/gc9xxx/qp_gc9a01_opcodes.h @@ -0,0 +1,104 @@ +// Copyright 2021 Paul Cotter (@gr1mr3aver) +// Copyright 2024 Fernando Birra +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter GC9A01 command opcodes +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define GC9A01_SET_MEM_CONT 0x3C // Set memory continue +#define GC9A01_SET_BRIGHTNESS 0x51 // Set brightness +#define GC9A01_SET_DISPLAY_CTL 0x53 // Set display ctl + +#define GC9A01_SET_RGB_IF_SIG_CTL 0xB0 // RGB IF signal ctl +#define GC9A01_SET_BLANKING_PORCH_CTL 0xB5 // Set blanking porch ctl +#define GC9A01_SET_FUNCTION_CTL 0xB6 // Set function ctl +#define GC9A01_SET_TEARING_EFFECT 0xBA // Set tering effect control +#define GC9A01_SET_POWER_CTL_7 0xA7 // Set power ctl 7 +#define GC9A01_SET_POWER_CTL_1 0xC1 // Set power ctl 1 +#define GC9A01_SET_POWER_CTL_2 0xC3 // Set power ctl 2 +#define GC9A01_SET_POWER_CTL_3 0xC4 // Set power ctl 3 +#define GC9A01_SET_POWER_CTL_4 0xC9 // Set power ctl 4 +#define GC9A01_SET_FRAME_RATE 0xE8 // Set frame rate +#define GC9A01_SET_SPI_2DATA 0xE9 // Set frame rate +#define GC9A01_SET_GAMMA3 0xF2 // Set gamma 3 +#define GC9A01_SET_GAMMA4 0xF3 // Set gamma 4 +#define GC9A01_SET_IF_CTL 0xF6 // Set interface control + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GC9A01 MADCTL Flags +#define GC9A01_MADCTL_MH 0b00000100 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GC9A01 Parameter constants + +// Parameter values for +// GC9A01_SET_PIXEL_FORMAT +#define GC9A01_PIXEL_FORMAT_12_BPP_DBI (0b011 << 0) // 12 bits/pixel MCU interface format +#define GC9A01_PIXEL_FORMAT_16_BPP_DBI (0b101 << 0) // 16 bits/pixel MCU interface format +#define GC9A01_PIXEL_FORMAT_18_BPP_DBI (0b110 << 0) // 18 bits/pixel MCU interface format +#define GC9A01_PIXEL_FORMAT_16_BPP_DPI (0b101 << 4) // 16 bits/pixel RGB interface format +#define GC9A01_PIXEL_FORMAT_18_BPP_DPI (0b110 << 4) // 18 bits/pixel RGB interface format + +// Parameter values for +// GC9A01_SET_FUNCTION_CTL (2nd parameter) +#define GC9A01_SOURCE_OUTPUT_SCAN_DIRECTION_S1_TO_S360 0b00000000 +#define GC9A01_SOURCE_OUTPUT_SCAN_DIRECTION_S360_TO_S1 0b00100000 +#define GC9A01_GATE_OUTPUT_SCAN_DIRECTION_G1_TO_G32 0b00000000 +#define GC9A01_GATE_OUTPUT_SCAN_DIRECTION_G32_TO_G1 0b01000000 +#define GC9A01_SCAN_MODE_INTER 0x10 + +// Parameter values for +// GC9A01_SET_FUNCTION_CTL (3rd parameter) +#define GC9A01_LCD_DRIVE_LINE_16 0x01 +#define GC9A01_LCD_DRIVE_LINE_24 0x02 +#define GC9A01_LCD_DRIVE_LINE_32 0x03 +#define GC9A01_LCD_DRIVE_LINE_40 0x04 +#define GC9A01_LCD_DRIVE_LINE_48 0x05 +#define GC9A01_LCD_DRIVE_LINE_56 0x06 +#define GC9A01_LCD_DRIVE_LINE_64 0x07 +#define GC9A01_LCD_DRIVE_LINE_72 0x08 +#define GC9A01_LCD_DRIVE_LINE_80 0x09 +#define GC9A01_LCD_DRIVE_LINE_88 0x0A +#define GC9A01_LCD_DRIVE_LINE_96 0x0B +#define GC9A01_LCD_DRIVE_LINE_104 0x0C +#define GC9A01_LCD_DRIVE_LINE_112 0x0D +#define GC9A01_LCD_DRIVE_LINE_120 0x0E +#define GC9A01_LCD_DRIVE_LINE_128 0x0F +#define GC9A01_LCD_DRIVE_LINE_136 0x10 +#define GC9A01_LCD_DRIVE_LINE_144 0x11 +#define GC9A01_LCD_DRIVE_LINE_152 0x12 +#define GC9A01_LCD_DRIVE_LINE_160 0x13 +#define GC9A01_LCD_DRIVE_LINE_168 0x14 +#define GC9A01_LCD_DRIVE_LINE_176 0x15 +#define GC9A01_LCD_DRIVE_LINE_184 0x16 +#define GC9A01_LCD_DRIVE_LINE_192 0x17 +#define GC9A01_LCD_DRIVE_LINE_200 0x18 +#define GC9A01_LCD_DRIVE_LINE_208 0x19 +#define GC9A01_LCD_DRIVE_LINE_216 0x1A +#define GC9A01_LCD_DRIVE_LINE_224 0x1B +#define GC9A01_LCD_DRIVE_LINE_232 0x1C +#define GC9A01_LCD_DRIVE_LINE_240 0x1D + +// Parameter values for +// GC9A01_SET_DISPLAY_CTL +#define GC9A01_BRIGHTNESS_CONTROL_ON 0b00100000 +#define GC9A01_DIMMING_ON 0b00001000 +#define GC9A01_BACKLIGHT_ON 0b00000100 +#define GC9A01_BRIGHTNESS_CONTROL_OFF 0b00000000 +#define GC9A01_DIMMING_OFF 0b00000000 +#define GC9A01_BACKLIGHT_OFF 0b00000000 + +// Parameter values for +// GC9A01_SET_IF_CTL +#define GC9A01_DISPLAY_MODE_INTERNAL_CLOCK 0b00000000 +#define GC9A01_DISPLAY_MODE_RGB_INTERFACE 0b00000100 +#define GC9A01_DISPLAY_MODE_VSYNC_INTERFACE 0b00001000 +#define GC9A01_DSISPLAY_MODE_DISABLED 0b00001100 + +#define GC0A01_GRAM_INTERFACE_VSYNC 0b00000000 +#define GC9A01_GRAM_INTERFACE_RGB 0b00000010 + +#define GC9A01_RGB_INTERFACE_MODE_1_TRANSFER 0b00000000 +#define GC9A01_RGB_INTERFACE_MODE_3_TRANSFER 0b00000001
\ No newline at end of file diff --git a/drivers/painter/gc9xxx/qp_gc9xxx_opcodes.h b/drivers/painter/gc9xxx/qp_gc9xxx_opcodes.h new file mode 100644 index 0000000000..7e0fbf9110 --- /dev/null +++ b/drivers/painter/gc9xxx/qp_gc9xxx_opcodes.h @@ -0,0 +1,55 @@ +// Copyright 2021 Paul Cotter (@gr1mr3aver) +// Copyright 2024 Fernando Birra +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter GC9xxx command opcodes +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define GC9XXX_GET_ID_INFO 0x04 // Get ID information +#define GC9XXX_GET_STATUS 0x09 // Get status + +#define GC9XXX_CMD_SLEEP_ON 0x10 // Enter sleep mode +#define GC9XXX_CMD_SLEEP_OFF 0x11 // Exit sleep mode +#define GC9XXX_CMD_PARTIAL_ON 0x12 // Enter partial mode +#define GC9XXX_CMD_PARTIAL_OFF 0x13 // Exit partial mode + +#define GC9XXX_CMD_INVERT_OFF 0x20 // Exit inverted mode +#define GC9XXX_CMD_INVERT_ON 0x21 // Enter inverted mode +#define GC9XXX_CMD_DISPLAY_OFF 0x28 // Disable display +#define GC9XXX_CMD_DISPLAY_ON 0x29 // Enable display +#define GC9XXX_SET_COL_ADDR 0x2A // Set column address (MSB(StartCol),LSB(StartCol),MSB(EndCol),LSB(EndCol) +#define GC9XXX_SET_ROW_ADDR 0x2B // Set row address (MSB(StartRow),LSB(StartRow),MSB(EndRow),LSB(EndRow) +#define GC9XXX_SET_MEM 0x2C // Set (write) memory + +#define GC9XXX_SET_PARTIAL_AREA 0x30 // Set partial area (MSB(StartRow),LSB(StartRow),MSB(EndRow),LSB(EndRow) +#define GC9XXX_SET_VSCROLL 0x33 // Set vertical scroll MSB(TFA),LSB(TFA),MSB(VSA),LSB(VSA)+ GC9107 extra param: MSB(BFA),LSB(BFA) +#define GC9XXX_CMD_TEARING_OFF 0x34 // Tearing effect line OFF +#define GC9XXX_CMD_TEARING_ON 0x35 // Tearing effect line ON +#define GC9XXX_SET_MEM_ACS_CTL 0x36 // Set mem access ctl +#define GC9XXX_SET_VSCROLL_ADDR 0x37 // Set vscroll start addr +#define GC9XXX_CMD_IDLE_OFF 0x38 // Exit idle mode +#define GC9XXX_CMD_IDLE_ON 0x39 // Enter idle mode +#define GC9XXX_SET_PIXEL_FORMAT 0x3A // Set pixel format +#define GC9XXX_SET_TEAR_SCANLINE 0x44 // Set tearing scanline (Scanline = LS bit of Param 1 (GC9A01) + Param 2(GC9XXX)) +#define GC9XXX_GET_TEAR_SCANLINE 0x45 // Get tearing scanline (Scanline = LS bit of Param 1 (GC9A01) + Param 2(GC9XXX)) +#define GC9XXX_GET_ID1 0xDA // Get ID1 +#define GC9XXX_GET_ID2 0xDB // Get ID2 +#define GC9XXX_GET_ID3 0xDC // Get ID3 +#define GC9XXX_SET_INTER_REG_ENABLE1 0xFE // Enable Inter Register 1 +#define GC9XXX_SET_INTER_REG_ENABLE2 0xEF // Enable Inter Register 2 +#define GC9XXX_SET_GAMMA1 0xF0 // Set gamma 1 +#define GC9XXX_SET_GAMMA2 0xF1 // Set gamma 2 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MADCTL Flags +#define GC9XXX_MADCTL_MY 0b10000000 // Mirror Y (row address order) +#define GC9XXX_MADCTL_MX 0b01000000 // Mirror X (column address order) +#define GC9XXX_MADCTL_MV 0b00100000 // Vertical Refresh Order (bottom to top) +#define GC9XXX_MADCTL_ML 0b00010000 +#define GC9XXX_MADCTL_BGR 0b00001000 +#define GC9XXX_MADCTL_RGB 0b00000000 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GC9XXX Parameter constants diff --git a/drivers/sensors/adns9800.c b/drivers/sensors/adns9800.c index f34529ee90..0ba26a365a 100644 --- a/drivers/sensors/adns9800.c +++ b/drivers/sensors/adns9800.c @@ -115,6 +115,7 @@ void adns9800_init(void) { adns9800_read(REG_Delta_Y_L); adns9800_read(REG_Delta_Y_H); +#ifdef ADNS9800_UPLOAD_SROM // upload firmware // 3k firmware mode @@ -145,6 +146,16 @@ void adns9800_init(void) { spi_stop(); wait_ms(10); +#else + // write reset value to REG_Configuration_IV + adns9800_write(REG_Configuration_IV, 0x0); + + // write reset value to REG_SROM_Enable + adns9800_write(REG_SROM_Enable, 0x0); + + // wait a frame + wait_ms(10); +#endif // enable laser uint8_t laser_ctrl0 = adns9800_read(REG_LASER_CTRL0); diff --git a/drivers/sensors/cirque_pinnacle_gestures.h b/drivers/sensors/cirque_pinnacle_gestures.h index d2aa206b2b..1412c86f7e 100644 --- a/drivers/sensors/cirque_pinnacle_gestures.h +++ b/drivers/sensors/cirque_pinnacle_gestures.h @@ -28,7 +28,7 @@ typedef struct { # ifndef CIRQUE_PINNACLE_TAPPING_TERM # include "action.h" # include "action_tapping.h" -# define CIRQUE_PINNACLE_TAPPING_TERM GET_TAPPING_TERM(KC_BTN1, &(keyrecord_t){}) +# define CIRQUE_PINNACLE_TAPPING_TERM GET_TAPPING_TERM(QK_MOUSE_BUTTON_1, &(keyrecord_t){}) # endif # ifndef CIRQUE_PINNACLE_TOUCH_DEBOUNCE # define CIRQUE_PINNACLE_TOUCH_DEBOUNCE (CIRQUE_PINNACLE_TAPPING_TERM * 8) diff --git a/drivers/sensors/pmw33xx_common.c b/drivers/sensors/pmw33xx_common.c index 82a7ec3297..f1f2d0e865 100644 --- a/drivers/sensors/pmw33xx_common.c +++ b/drivers/sensors/pmw33xx_common.c @@ -154,10 +154,12 @@ bool pmw33xx_init(uint8_t sensor) { pmw33xx_read(sensor, REG_Delta_Y_L); pmw33xx_read(sensor, REG_Delta_Y_H); +#ifdef PMW33XX_UPLOAD_SROM if (!pmw33xx_upload_firmware(sensor)) { pd_dprintf("PMW33XX (%d): firmware upload failed!\n", sensor); return false; } +#endif spi_stop(); @@ -200,7 +202,7 @@ pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor) { spi_write(REG_Motion_Burst); wait_us(35); // waits for tSRAD_MOTBR - spi_receive((uint8_t*)&report, sizeof(report)); + spi_receive((uint8_t *)&report, sizeof(report)); // panic recovery, sometimes burst mode works weird. if (report.motion.w & 0b111) { diff --git a/drivers/wear_leveling/wear_leveling_flash_spi.c b/drivers/wear_leveling/wear_leveling_flash_spi.c index 6191f8bf09..304aed1641 100644 --- a/drivers/wear_leveling/wear_leveling_flash_spi.c +++ b/drivers/wear_leveling/wear_leveling_flash_spi.c @@ -58,7 +58,7 @@ bool backing_store_read(uint32_t address, backing_store_int_t *value) { 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); + flash_status_t status = flash_read_range(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]; @@ -88,7 +88,7 @@ bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, siz } // Write out the block - if (flash_write_block(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) { + if (flash_write_range(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) { return false; } |