From 3b5a40159413df06482677f636dfde8bf07fba0f Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 16 Jul 2026 22:47:26 +0200 Subject: [PATCH] Device migrations, new drivers, cleanup (#567) * **New Features** * Added native display support for ST7796, ILI9341, and ST7789 panels across supported boards. * Added FT5x06 and FT6x36 touchscreen support. * Generic PWM driver * ESP32 PWM driver * Generic RGB LED driver * RGB PWM LED driver * RGB GPIO LED driver * Implementation of RGB LED for various boards * **Improvements** * Updated board hardware descriptions to use explicit display/touch/backlight device-tree bindings and disabled deprecated HAL usage. * Improved display and touch-driver cleanup to prevent stale resources and improve shutdown reliability. * Pinned esp-hosted library to a fixed version * **Deletions** * Obsolete placeholder display * Legacy ILI9488 support. * ESP32-specific LEDC PWM implementation --- .../bigtreetech,panda-touch.dts | 15 +- Devices/cyd-2432s024c/CMakeLists.txt | 2 +- Devices/cyd-2432s024c/cyd,2432s024c.dts | 54 ++- Devices/cyd-2432s024c/source/module.cpp | 12 - Devices/cyd-2432s024r/CMakeLists.txt | 2 +- Devices/cyd-2432s024r/cyd,2432s024r.dts | 54 ++- Devices/cyd-2432s024r/source/module.cpp | 2 - Devices/cyd-2432s028r/CMakeLists.txt | 2 +- Devices/cyd-2432s028r/cyd,2432s028r.dts | 54 ++- Devices/cyd-2432s028r/source/module.cpp | 13 - Devices/cyd-2432s028rv3/CMakeLists.txt | 2 +- Devices/cyd-2432s028rv3/cyd,2432s028rv3.dts | 54 ++- Devices/cyd-2432s028rv3/source/module.cpp | 12 - Devices/cyd-2432s032c/CMakeLists.txt | 5 +- .../cyd-2432s032c/Source/Configuration.cpp | 47 --- .../cyd-2432s032c/Source/devices/Display.cpp | 48 --- .../cyd-2432s032c/Source/devices/Display.h | 18 - Devices/cyd-2432s032c/cyd,2432s032c.dts | 83 ++++- Devices/cyd-2432s032c/device.properties | 2 + Devices/cyd-2432s032c/devicetree.yaml | 2 + .../{Source => source}/module.cpp | 2 - Devices/cyd-3248s035c/CMakeLists.txt | 5 +- .../cyd-3248s035c/Source/Configuration.cpp | 32 -- .../cyd-3248s035c/Source/devices/Display.cpp | 40 -- .../cyd-3248s035c/Source/devices/Display.h | 20 - Devices/cyd-3248s035c/cyd,3248s035c.dts | 78 +++- Devices/cyd-3248s035c/device.properties | 2 + Devices/cyd-3248s035c/devicetree.yaml | 4 +- .../{Source => source}/module.cpp | 2 - Devices/cyd-8048s043c/CMakeLists.txt | 5 +- .../cyd-8048s043c/Source/Configuration.cpp | 22 -- .../cyd-8048s043c/Source/devices/Display.cpp | 108 ------ .../cyd-8048s043c/Source/devices/Display.h | 5 - Devices/cyd-8048s043c/cyd,8048s043c.dts | 67 +++- Devices/cyd-8048s043c/device.properties | 2 + Devices/cyd-8048s043c/devicetree.yaml | 2 + .../{Source => source}/module.cpp | 2 - Devices/cyd-e32r28t/CMakeLists.txt | 2 +- Devices/cyd-e32r28t/cyd,e32r28t.dts | 55 ++- Devices/cyd-e32r28t/source/module.cpp | 2 - Devices/cyd-e32r32p/CMakeLists.txt | 2 +- Devices/cyd-e32r32p/cyd,e32r32p.dts | 54 ++- Devices/cyd-e32r32p/source/module.cpp | 2 - .../CMakeLists.txt | 5 +- .../Source/Configuration.cpp | 21 -- .../Source/devices/Display.cpp | 46 --- .../Source/devices/Display.h | 16 - .../device.properties | 2 + .../devicetree.yaml | 2 + .../elecrow,crowpanel-advance-28.dts | 37 +- .../{Source => source}/module.cpp | 2 - .../CMakeLists.txt | 2 +- .../elecrow,crowpanel-advance-35.dts | 16 +- .../elecrow,crowpanel-advance-50.dts | 6 +- .../elecrow-crowpanel-basic-28/CMakeLists.txt | 2 +- .../elecrow,crowpanel-basic-28.dts | 16 +- .../source/module.cpp | 2 - .../elecrow-crowpanel-basic-35/CMakeLists.txt | 2 +- .../elecrow,crowpanel-basic-35.dts | 16 +- .../elecrow,crowpanel-basic-50.dts | 16 +- Devices/generic-esp32/CMakeLists.txt | 5 +- .../generic-esp32/Source/Configuration.cpp | 3 - Devices/generic-esp32/device.properties | 2 + .../{Source => source}/module.cpp | 2 - Devices/generic-esp32c6/CMakeLists.txt | 5 +- .../generic-esp32c6/Source/Configuration.cpp | 3 - Devices/generic-esp32c6/device.properties | 2 + .../{Source => source}/module.cpp | 2 - Devices/generic-esp32p4/CMakeLists.txt | 5 +- .../generic-esp32p4/Source/Configuration.cpp | 3 - Devices/generic-esp32p4/device.properties | 2 + .../{Source => source}/module.cpp | 2 - Devices/generic-esp32s3/CMakeLists.txt | 5 +- .../generic-esp32s3/Source/Configuration.cpp | 3 - Devices/generic-esp32s3/device.properties | 2 + .../{Source => source}/module.cpp | 2 - .../Source/Configuration.cpp | 11 - Devices/guition-jc2432w328c/Source/module.cpp | 2 - .../guition,jc2432w328c.dts | 41 ++- .../lilygo-tdeck-plus/lilygo,tdeck-plus.dts | 20 +- Devices/lilygo-tdeck/lilygo,tdeck.dts | 20 +- Devices/lilygo-thmi/lilygo,thmi.dts | 20 +- .../m5stack,cardputer-adv.dts | 16 +- .../m5stack-cardputer/m5stack,cardputer.dts | 16 +- .../m5stack,stickc-plus2.dts | 16 +- Devices/unphone/unphone.dts | 18 +- Devices/waveshare-s3-lcd-13/CMakeLists.txt | 5 +- .../Source/Configuration.cpp | 21 -- .../Source/devices/Display.cpp | 32 -- .../Source/devices/Display.h | 10 - Devices/waveshare-s3-lcd-13/device.properties | 2 + Devices/waveshare-s3-lcd-13/devicetree.yaml | 1 + .../{Source => source}/module.cpp | 2 - .../waveshare,s3-lcd-13.dts | 30 +- Drivers/ILI9488/CMakeLists.txt | 5 - Drivers/ILI9488/README.md | 6 - Drivers/ILI9488/Source/Ili9488Display.cpp | 117 ------ Drivers/ILI9488/Source/Ili9488Display.h | 98 ----- Drivers/cst816s-module/source/cst816s.cpp | 23 +- Drivers/ft5x06-module/CMakeLists.txt | 11 + Drivers/ft5x06-module/LICENSE-Apache-2.0.md | 195 ++++++++++ .../bindings/focaltech,ft5x06.yaml | 45 +++ Drivers/ft5x06-module/devicetree.yaml | 3 + .../ft5x06-module/include/bindings/ft5x06.h | 7 + .../ft5x06-module/include/drivers/ft5x06.h | 30 ++ .../ft5x06-module/include/ft5x06_module.h | 6 +- Drivers/ft5x06-module/source/ft5x06.cpp | 210 +++++++++++ Drivers/ft5x06-module/source/module.cpp | 32 ++ Drivers/ft6x36-module/CMakeLists.txt | 11 + Drivers/ft6x36-module/LICENSE-Apache-2.0.md | 195 ++++++++++ .../bindings/focaltech,ft6x36.yaml | 45 +++ Drivers/ft6x36-module/devicetree.yaml | 3 + .../ft6x36-module/include/bindings/ft6x36.h | 7 + .../ft6x36-module/include/drivers/ft6x36.h | 30 ++ Drivers/ft6x36-module/include/ft6x36_module.h | 14 + Drivers/ft6x36-module/source/ft6x36.cpp | 210 +++++++++++ Drivers/ft6x36-module/source/module.cpp | 32 ++ Drivers/gt911-module/source/gt911.cpp | 23 +- Drivers/ili9341-module/source/ili9341.cpp | 24 +- Drivers/ili9488-module/source/ili9488.cpp | 20 +- .../rgb-display-module/source/rgb_display.cpp | 12 +- .../source/st7789_i8080.cpp | 24 +- Drivers/st7789-module/source/st7789.cpp | 20 +- Drivers/st7796-module/CMakeLists.txt | 11 + Drivers/st7796-module/LICENSE-Apache-2.0.md | 195 ++++++++++ .../bindings/sitronix,st7796.yaml | 77 ++++ Drivers/st7796-module/devicetree.yaml | 3 + .../st7796-module/include/bindings/st7796.h | 7 + .../st7796-module/include/drivers/st7796.h | 38 ++ Drivers/st7796-module/include/st7796_module.h | 14 + Drivers/st7796-module/source/module.cpp | 32 ++ Drivers/st7796-module/source/st7796.cpp | 341 ++++++++++++++++++ Drivers/xpt2046-module/source/xpt2046.cpp | 24 +- Firmware/idf_component.yml | 2 +- .../espressif,esp32-ledc-backlight.yaml | 29 -- .../bindings/espressif,esp32-pwm-ledc.yaml | 33 ++ .../tactility/bindings/esp32_gpio_backlight.h | 15 - .../tactility/bindings/esp32_ledc_backlight.h | 15 - .../tactility/bindings/esp32_pwm_ledc.h | 4 +- .../tactility/drivers/esp32_gpio_backlight.h | 18 - ...sp32_ledc_backlight.h => esp32_pwm_ledc.h} | 13 +- .../source/drivers/esp32_gpio_backlight.cpp | 119 ------ .../source/drivers/esp32_ledc_backlight.cpp | 139 ------- .../source/drivers/esp32_pwm_ledc.cpp | 253 +++++++++++++ Platforms/platform-esp32/source/module.cpp | 9 +- .../bindings/gpio-backlight.yaml | 8 +- ...{tactility,gpio-hog.yaml => gpio-hog.yaml} | 2 +- TactilityKernel/bindings/pwm-backlight.yaml | 19 + TactilityKernel/bindings/pwm.yaml | 20 + TactilityKernel/bindings/rgb-led-gpio.yaml | 27 ++ TactilityKernel/bindings/rgb-led-pwm.yaml | 27 ++ TactilityKernel/bindings/spi-peripheral.yaml | 5 - .../tactility/bindings/gpio_backlight.h | 7 + .../tactility/bindings/pointer_placeholder.h | 15 - .../tactility/bindings/pwm_backlight.h | 7 + .../include/tactility/bindings/rgb_led_gpio.h | 7 + .../include/tactility/bindings/rgb_led_pwm.h | 7 + .../tactility/drivers/gpio_backlight.h | 24 ++ .../include/tactility/drivers/pwm.h | 150 ++++++++ .../include/tactility/drivers/pwm_backlight.h | 27 ++ .../include/tactility/drivers/rgb_led.h | 81 +++++ .../include/tactility/drivers/rgb_led_gpio.h | 31 ++ .../include/tactility/drivers/rgb_led_pwm.h | 31 ++ .../tactility/drivers/spi_peripheral.h | 19 - .../source/drivers/gpio_backlight.cpp | 147 ++++++++ TactilityKernel/source/drivers/gpio_hog.cpp | 2 +- .../source/drivers/pointer_placeholder.cpp | 26 -- TactilityKernel/source/drivers/pwm.cpp | 58 +++ .../source/drivers/pwm_backlight.cpp | 142 ++++++++ TactilityKernel/source/drivers/rgb_led.cpp | 33 ++ .../source/drivers/rgb_led_gpio.cpp | 171 +++++++++ .../source/drivers/rgb_led_pwm.cpp | 157 ++++++++ .../source/drivers/spi_peripheral.cpp | 28 -- TactilityKernel/source/kernel_init.cpp | 12 +- TactilityKernel/source/kernel_symbols.c | 3 - 175 files changed, 4218 insertions(+), 1462 deletions(-) delete mode 100644 Devices/cyd-2432s032c/Source/Configuration.cpp delete mode 100644 Devices/cyd-2432s032c/Source/devices/Display.cpp delete mode 100644 Devices/cyd-2432s032c/Source/devices/Display.h rename Devices/cyd-2432s032c/{Source => source}/module.cpp (87%) delete mode 100644 Devices/cyd-3248s035c/Source/Configuration.cpp delete mode 100644 Devices/cyd-3248s035c/Source/devices/Display.cpp delete mode 100644 Devices/cyd-3248s035c/Source/devices/Display.h rename Devices/cyd-3248s035c/{Source => source}/module.cpp (82%) delete mode 100644 Devices/cyd-8048s043c/Source/Configuration.cpp delete mode 100644 Devices/cyd-8048s043c/Source/devices/Display.cpp delete mode 100644 Devices/cyd-8048s043c/Source/devices/Display.h rename Devices/cyd-8048s043c/{Source => source}/module.cpp (87%) delete mode 100644 Devices/elecrow-crowpanel-advance-28/Source/Configuration.cpp delete mode 100644 Devices/elecrow-crowpanel-advance-28/Source/devices/Display.cpp delete mode 100644 Devices/elecrow-crowpanel-advance-28/Source/devices/Display.h rename Devices/elecrow-crowpanel-advance-28/{Source => source}/module.cpp (88%) delete mode 100644 Devices/generic-esp32/Source/Configuration.cpp rename Devices/generic-esp32/{Source => source}/module.cpp (87%) delete mode 100644 Devices/generic-esp32c6/Source/Configuration.cpp rename Devices/generic-esp32c6/{Source => source}/module.cpp (88%) delete mode 100644 Devices/generic-esp32p4/Source/Configuration.cpp rename Devices/generic-esp32p4/{Source => source}/module.cpp (88%) delete mode 100644 Devices/generic-esp32s3/Source/Configuration.cpp rename Devices/generic-esp32s3/{Source => source}/module.cpp (88%) delete mode 100644 Devices/waveshare-s3-lcd-13/Source/Configuration.cpp delete mode 100644 Devices/waveshare-s3-lcd-13/Source/devices/Display.cpp delete mode 100644 Devices/waveshare-s3-lcd-13/Source/devices/Display.h rename Devices/waveshare-s3-lcd-13/{Source => source}/module.cpp (88%) delete mode 100644 Drivers/ILI9488/CMakeLists.txt delete mode 100644 Drivers/ILI9488/README.md delete mode 100644 Drivers/ILI9488/Source/Ili9488Display.cpp delete mode 100644 Drivers/ILI9488/Source/Ili9488Display.h create mode 100644 Drivers/ft5x06-module/CMakeLists.txt create mode 100644 Drivers/ft5x06-module/LICENSE-Apache-2.0.md create mode 100644 Drivers/ft5x06-module/bindings/focaltech,ft5x06.yaml create mode 100644 Drivers/ft5x06-module/devicetree.yaml create mode 100644 Drivers/ft5x06-module/include/bindings/ft5x06.h create mode 100644 Drivers/ft5x06-module/include/drivers/ft5x06.h rename TactilityKernel/include/tactility/drivers/pointer_placeholder.h => Drivers/ft5x06-module/include/ft5x06_module.h (61%) create mode 100644 Drivers/ft5x06-module/source/ft5x06.cpp create mode 100644 Drivers/ft5x06-module/source/module.cpp create mode 100644 Drivers/ft6x36-module/CMakeLists.txt create mode 100644 Drivers/ft6x36-module/LICENSE-Apache-2.0.md create mode 100644 Drivers/ft6x36-module/bindings/focaltech,ft6x36.yaml create mode 100644 Drivers/ft6x36-module/devicetree.yaml create mode 100644 Drivers/ft6x36-module/include/bindings/ft6x36.h create mode 100644 Drivers/ft6x36-module/include/drivers/ft6x36.h create mode 100644 Drivers/ft6x36-module/include/ft6x36_module.h create mode 100644 Drivers/ft6x36-module/source/ft6x36.cpp create mode 100644 Drivers/ft6x36-module/source/module.cpp create mode 100644 Drivers/st7796-module/CMakeLists.txt create mode 100644 Drivers/st7796-module/LICENSE-Apache-2.0.md create mode 100644 Drivers/st7796-module/bindings/sitronix,st7796.yaml create mode 100644 Drivers/st7796-module/devicetree.yaml create mode 100644 Drivers/st7796-module/include/bindings/st7796.h create mode 100644 Drivers/st7796-module/include/drivers/st7796.h create mode 100644 Drivers/st7796-module/include/st7796_module.h create mode 100644 Drivers/st7796-module/source/module.cpp create mode 100644 Drivers/st7796-module/source/st7796.cpp delete mode 100644 Platforms/platform-esp32/bindings/espressif,esp32-ledc-backlight.yaml create mode 100644 Platforms/platform-esp32/bindings/espressif,esp32-pwm-ledc.yaml delete mode 100644 Platforms/platform-esp32/include/tactility/bindings/esp32_gpio_backlight.h delete mode 100644 Platforms/platform-esp32/include/tactility/bindings/esp32_ledc_backlight.h rename TactilityKernel/include/tactility/bindings/spi_peripheral.h => Platforms/platform-esp32/include/tactility/bindings/esp32_pwm_ledc.h (60%) delete mode 100644 Platforms/platform-esp32/include/tactility/drivers/esp32_gpio_backlight.h rename Platforms/platform-esp32/include/tactility/drivers/{esp32_ledc_backlight.h => esp32_pwm_ledc.h} (52%) delete mode 100644 Platforms/platform-esp32/source/drivers/esp32_gpio_backlight.cpp delete mode 100644 Platforms/platform-esp32/source/drivers/esp32_ledc_backlight.cpp create mode 100644 Platforms/platform-esp32/source/drivers/esp32_pwm_ledc.cpp rename Platforms/platform-esp32/bindings/espressif,esp32-gpio-backlight.yaml => TactilityKernel/bindings/gpio-backlight.yaml (82%) rename TactilityKernel/bindings/{tactility,gpio-hog.yaml => gpio-hog.yaml} (96%) create mode 100644 TactilityKernel/bindings/pwm-backlight.yaml create mode 100644 TactilityKernel/bindings/pwm.yaml create mode 100644 TactilityKernel/bindings/rgb-led-gpio.yaml create mode 100644 TactilityKernel/bindings/rgb-led-pwm.yaml delete mode 100644 TactilityKernel/bindings/spi-peripheral.yaml create mode 100644 TactilityKernel/include/tactility/bindings/gpio_backlight.h delete mode 100644 TactilityKernel/include/tactility/bindings/pointer_placeholder.h create mode 100644 TactilityKernel/include/tactility/bindings/pwm_backlight.h create mode 100644 TactilityKernel/include/tactility/bindings/rgb_led_gpio.h create mode 100644 TactilityKernel/include/tactility/bindings/rgb_led_pwm.h create mode 100644 TactilityKernel/include/tactility/drivers/gpio_backlight.h create mode 100644 TactilityKernel/include/tactility/drivers/pwm.h create mode 100644 TactilityKernel/include/tactility/drivers/pwm_backlight.h create mode 100644 TactilityKernel/include/tactility/drivers/rgb_led.h create mode 100644 TactilityKernel/include/tactility/drivers/rgb_led_gpio.h create mode 100644 TactilityKernel/include/tactility/drivers/rgb_led_pwm.h delete mode 100644 TactilityKernel/include/tactility/drivers/spi_peripheral.h create mode 100644 TactilityKernel/source/drivers/gpio_backlight.cpp delete mode 100644 TactilityKernel/source/drivers/pointer_placeholder.cpp create mode 100644 TactilityKernel/source/drivers/pwm.cpp create mode 100644 TactilityKernel/source/drivers/pwm_backlight.cpp create mode 100644 TactilityKernel/source/drivers/rgb_led.cpp create mode 100644 TactilityKernel/source/drivers/rgb_led_gpio.cpp create mode 100644 TactilityKernel/source/drivers/rgb_led_pwm.cpp delete mode 100644 TactilityKernel/source/drivers/spi_peripheral.cpp diff --git a/Devices/btt-panda-touch/bigtreetech,panda-touch.dts b/Devices/btt-panda-touch/bigtreetech,panda-touch.dts index 6f56d6a7a..d106f1ce4 100644 --- a/Devices/btt-panda-touch/bigtreetech,panda-touch.dts +++ b/Devices/btt-panda-touch/bigtreetech,panda-touch.dts @@ -6,7 +6,8 @@ #include #include #include -#include +#include +#include #include #include @@ -55,9 +56,17 @@ pin-scl = <&gpio0 3 GPIO_FLAG_NONE>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 21 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; - pin-backlight = <&gpio0 21 GPIO_FLAG_NONE>; + compatible = "pwm-backlight"; + pwm = <&display_backlight_pwm>; }; display0 { diff --git a/Devices/cyd-2432s024c/CMakeLists.txt b/Devices/cyd-2432s024c/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-2432s024c/CMakeLists.txt +++ b/Devices/cyd-2432s024c/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-2432s024c/cyd,2432s024c.dts b/Devices/cyd-2432s024c/cyd,2432s024c.dts index ee3049995..dadaf0bc6 100644 --- a/Devices/cyd-2432s024c/cyd,2432s024c.dts +++ b/Devices/cyd-2432s024c/cyd,2432s024c.dts @@ -6,7 +6,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -39,13 +41,57 @@ }; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/cyd-2432s024c/source/module.cpp b/Devices/cyd-2432s024c/source/module.cpp index 47010a742..e05e61583 100644 --- a/Devices/cyd-2432s024c/source/module.cpp +++ b/Devices/cyd-2432s024c/source/module.cpp @@ -1,20 +1,8 @@ #include -#include - -#include extern "C" { static error_t start() { - // Set the RGB LED pins to output and turn them off (0 on, 1 off) - gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT); // Red - gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT); // Green - gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); // Blue - - gpio_set_level(GPIO_NUM_4, 1); // Red - gpio_set_level(GPIO_NUM_16, 1); // Green - gpio_set_level(GPIO_NUM_17, 1); // Blue - return ERROR_NONE; } diff --git a/Devices/cyd-2432s024r/CMakeLists.txt b/Devices/cyd-2432s024r/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-2432s024r/CMakeLists.txt +++ b/Devices/cyd-2432s024r/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-2432s024r/cyd,2432s024r.dts b/Devices/cyd-2432s024r/cyd,2432s024r.dts index 928fb9a14..06f7c9741 100644 --- a/Devices/cyd-2432s024r/cyd,2432s024r.dts +++ b/Devices/cyd-2432s024r/cyd,2432s024r.dts @@ -6,7 +6,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -24,13 +26,57 @@ gpio-count = <40>; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/cyd-2432s024r/source/module.cpp b/Devices/cyd-2432s024r/source/module.cpp index 2cd4c7385..3b2590086 100644 --- a/Devices/cyd-2432s024r/source/module.cpp +++ b/Devices/cyd-2432s024r/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-2432s028r/CMakeLists.txt b/Devices/cyd-2432s028r/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-2432s028r/CMakeLists.txt +++ b/Devices/cyd-2432s028r/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-2432s028r/cyd,2432s028r.dts b/Devices/cyd-2432s028r/cyd,2432s028r.dts index 4a4378ea2..9aa1dcefb 100644 --- a/Devices/cyd-2432s028r/cyd,2432s028r.dts +++ b/Devices/cyd-2432s028r/cyd,2432s028r.dts @@ -7,7 +7,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -33,13 +35,57 @@ pin-scl = <&gpio0 22 GPIO_FLAG_NONE>; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 21 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 21 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; touch { diff --git a/Devices/cyd-2432s028r/source/module.cpp b/Devices/cyd-2432s028r/source/module.cpp index 83bd0960d..26ff57688 100644 --- a/Devices/cyd-2432s028r/source/module.cpp +++ b/Devices/cyd-2432s028r/source/module.cpp @@ -1,25 +1,12 @@ #include -#include - -#include extern "C" { static error_t start() { - // Set the RGB LED pins to output and turn them off (0 on, 1 off) - gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT); // Red - gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT); // Green - gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); // Blue - - gpio_set_level(GPIO_NUM_4, 1); // Red - gpio_set_level(GPIO_NUM_16, 1); // Green - gpio_set_level(GPIO_NUM_17, 1); // Blue - return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-2432s028rv3/CMakeLists.txt b/Devices/cyd-2432s028rv3/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-2432s028rv3/CMakeLists.txt +++ b/Devices/cyd-2432s028rv3/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-2432s028rv3/cyd,2432s028rv3.dts b/Devices/cyd-2432s028rv3/cyd,2432s028rv3.dts index 48c105288..2b1efc462 100644 --- a/Devices/cyd-2432s028rv3/cyd,2432s028rv3.dts +++ b/Devices/cyd-2432s028rv3/cyd,2432s028rv3.dts @@ -7,7 +7,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -33,13 +35,57 @@ pin-scl = <&gpio0 22 GPIO_FLAG_NONE>; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 21 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 21 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; touch { diff --git a/Devices/cyd-2432s028rv3/source/module.cpp b/Devices/cyd-2432s028rv3/source/module.cpp index 3f7e4f1cc..ed7f9255e 100644 --- a/Devices/cyd-2432s028rv3/source/module.cpp +++ b/Devices/cyd-2432s028rv3/source/module.cpp @@ -1,20 +1,8 @@ #include -#include - -#include extern "C" { static error_t start() { - // Set the RGB LED pins to output and turn them off (0 on, 1 off) - gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT); // Red - gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT); // Green - gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); // Blue - - gpio_set_level(GPIO_NUM_4, 1); // Red - gpio_set_level(GPIO_NUM_16, 1); // Green - gpio_set_level(GPIO_NUM_17, 1); // Blue - return ERROR_NONE; } diff --git a/Devices/cyd-2432s032c/CMakeLists.txt b/Devices/cyd-2432s032c/CMakeLists.txt index 3b5cbbbe8..a7d3e6712 100644 --- a/Devices/cyd-2432s032c/CMakeLists.txt +++ b/Devices/cyd-2432s032c/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port ILI934x GT911 PwmBacklight driver vfs fatfs + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-2432s032c/Source/Configuration.cpp b/Devices/cyd-2432s032c/Source/Configuration.cpp deleted file mode 100644 index 9e5abd20c..000000000 --- a/Devices/cyd-2432s032c/Source/Configuration.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "devices/Display.h" -#include - -#include -#include -#include - -#include - -static bool init_boot() { - if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT)) { - return false; - } - - // Set the RGB LED Pins to output and turn them off - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT)); // Red - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT)); // Green - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT)); // Blue - - // 0 on, 1 off - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_4, 1)); // Red - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_16, 1)); // Green - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_17, 1)); // Blue - - // This display has a weird glitch with gamma during boot, which results in uneven dark gray colours. - // Setting gamma curve index to 0 doesn't work at boot for an unknown reason, so we set the curve index to 1: - tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootSplash, [](auto) { - auto display = tt::hal::findFirstDevice(tt::hal::Device::Type::Display); - assert(display != nullptr); - tt::lvgl::lock(portMAX_DELAY); - display->setGammaCurve(1U); - tt::lvgl::unlock(); - }); - - return true; -} - -static tt::hal::DeviceVector createDevices() { - return { - createDisplay(), - }; -} - -extern const tt::hal::Configuration hardwareConfiguration = { - .initBoot = init_boot, - .createDevices = createDevices -}; diff --git a/Devices/cyd-2432s032c/Source/devices/Display.cpp b/Devices/cyd-2432s032c/Source/devices/Display.cpp deleted file mode 100644 index d0bb5ddd2..000000000 --- a/Devices/cyd-2432s032c/Source/devices/Display.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "Display.h" - -#include -#include -#include -#include -#include - -static std::shared_ptr createTouch() { - auto* i2c = device_find_by_name("i2c0"); - check(i2c); - auto configuration = std::make_unique( - i2c, - LCD_HORIZONTAL_RESOLUTION, - LCD_VERTICAL_RESOLUTION - ); - - return std::make_shared(std::move(configuration)); -} - -std::shared_ptr createDisplay() { - Ili934xDisplay::Configuration panel_configuration = { - .horizontalResolution = LCD_HORIZONTAL_RESOLUTION, - .verticalResolution = LCD_VERTICAL_RESOLUTION, - .gapX = 0, - .gapY = 0, - .swapXY = true, - .mirrorX = true, - .mirrorY = true, - .invertColor = true, - .swapBytes = true, - .bufferSize = LCD_BUFFER_SIZE, - .touch = createTouch(), - .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty, - .resetPin = GPIO_NUM_NC, - .rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB - }; - - auto spi_configuration = std::make_shared(Ili934xDisplay::SpiConfiguration { - .spiHostDevice = LCD_SPI_HOST, - .csPin = LCD_PIN_CS, - .dcPin = LCD_PIN_DC, - .pixelClockFrequency = 40'000'000, - .transactionQueueDepth = 10 - }); - - return std::make_shared(panel_configuration, spi_configuration, true); -} diff --git a/Devices/cyd-2432s032c/Source/devices/Display.h b/Devices/cyd-2432s032c/Source/devices/Display.h deleted file mode 100644 index 8a54f1e1a..000000000 --- a/Devices/cyd-2432s032c/Source/devices/Display.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Display -constexpr auto LCD_SPI_HOST = SPI2_HOST; -constexpr auto LCD_PIN_CS = GPIO_NUM_15; -constexpr auto LCD_PIN_DC = GPIO_NUM_2; -constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_27; -constexpr auto LCD_HORIZONTAL_RESOLUTION = 240; -constexpr auto LCD_VERTICAL_RESOLUTION = 320; -constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 10; -constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT; - -std::shared_ptr createDisplay(); diff --git a/Devices/cyd-2432s032c/cyd,2432s032c.dts b/Devices/cyd-2432s032c/cyd,2432s032c.dts index 4dbc0c74d..940b9ac50 100644 --- a/Devices/cyd-2432s032c/cyd,2432s032c.dts +++ b/Devices/cyd-2432s032c/cyd,2432s032c.dts @@ -6,7 +6,11 @@ #include #include #include -#include +#include +#include +#include +#include +#include / { compatible = "root"; @@ -28,6 +32,66 @@ clock-frequency = <400000>; pin-sda = <&gpio0 33 GPIO_FLAG_NONE>; pin-scl = <&gpio0 32 GPIO_FLAG_NONE>; + + touch { + compatible = "goodix,gt911"; + reg = <0x5D>; + x-max = <240>; + y-max = <320>; + }; + }; + + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + + display_backlight { + compatible = "pwm-backlight"; + // Off by default so display power-on won't show the screen from before the last power loss. + // The display backlight is turned on during the boot process. + status = "disabled"; + pwm = <&display_backlight_pwm>; }; spi0 { @@ -36,9 +100,20 @@ cs-gpios = <&gpio0 15 GPIO_FLAG_NONE>; pin-mosi = <&gpio0 13 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 14 GPIO_FLAG_NONE>; - - display { - compatible = "display-placeholder"; + + display@0 { + compatible = "ilitek,ili9341"; + horizontal-resolution = <240>; + vertical-resolution = <320>; + swap-xy; + mirror-x; + mirror-y; + invert-color; + // Curve 0 doesn't apply cleanly at boot on this panel (uneven dark-gray gamma glitch); 1 does. + gamma-curve = <1>; + pixel-clock-hz = <40000000>; + pin-dc = <&gpio0 2 GPIO_FLAG_NONE>; + backlight = <&display_backlight>; }; }; diff --git a/Devices/cyd-2432s032c/device.properties b/Devices/cyd-2432s032c/device.properties index e483bd8c2..dc563dae6 100644 --- a/Devices/cyd-2432s032c/device.properties +++ b/Devices/cyd-2432s032c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=SD display.size=3.2" diff --git a/Devices/cyd-2432s032c/devicetree.yaml b/Devices/cyd-2432s032c/devicetree.yaml index 98ce41688..b7f4d0173 100644 --- a/Devices/cyd-2432s032c/devicetree.yaml +++ b/Devices/cyd-2432s032c/devicetree.yaml @@ -1,3 +1,5 @@ dependencies: - Platforms/platform-esp32 + - Drivers/ili9341-module + - Drivers/gt911-module dts: cyd,2432s032c.dts diff --git a/Devices/cyd-2432s032c/Source/module.cpp b/Devices/cyd-2432s032c/source/module.cpp similarity index 87% rename from Devices/cyd-2432s032c/Source/module.cpp rename to Devices/cyd-2432s032c/source/module.cpp index 348f0204d..ee8c6422b 100644 --- a/Devices/cyd-2432s032c/Source/module.cpp +++ b/Devices/cyd-2432s032c/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-3248s035c/CMakeLists.txt b/Devices/cyd-3248s035c/CMakeLists.txt index 2d90a08fd..731e5e601 100644 --- a/Devices/cyd-3248s035c/CMakeLists.txt +++ b/Devices/cyd-3248s035c/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port ST7796 GT911 PwmBacklight driver vfs fatfs + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-3248s035c/Source/Configuration.cpp b/Devices/cyd-3248s035c/Source/Configuration.cpp deleted file mode 100644 index 9734b668f..000000000 --- a/Devices/cyd-3248s035c/Source/Configuration.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "devices/Display.h" -#include - -#include -#include - -using namespace tt::hal; - -static bool initBoot() { - //Set the RGB Led Pins to output and turn them off - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT)); //Red - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT)); //Green - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT)); //Blue - - //0 on, 1 off... yep it's backwards. - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_4, 1)); //Red - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_16, 1)); //Green - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_17, 1)); //Blue - - return driver::pwmbacklight::init(LCD_PIN_BACKLIGHT); -} - -static DeviceVector createDevices() { - return { - createDisplay(), - }; -} - -extern const Configuration hardwareConfiguration = { - .initBoot = initBoot, - .createDevices = createDevices -}; diff --git a/Devices/cyd-3248s035c/Source/devices/Display.cpp b/Devices/cyd-3248s035c/Source/devices/Display.cpp deleted file mode 100644 index d67a8cf60..000000000 --- a/Devices/cyd-3248s035c/Source/devices/Display.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Display.h" - -#include -#include -#include -#include -#include - -static std::shared_ptr createTouch() { - auto* i2c = device_find_by_name("i2c0"); - check(i2c); - auto configuration = std::make_unique( - i2c, - LCD_HORIZONTAL_RESOLUTION, - LCD_VERTICAL_RESOLUTION - ); - - return std::make_shared(std::move(configuration)); -} - -std::shared_ptr createDisplay() { - auto touch = createTouch(); - auto configuration = std::make_unique( - LCD_SPI_HOST, - LCD_PIN_CS, - LCD_PIN_DC, - LCD_HORIZONTAL_RESOLUTION, - LCD_VERTICAL_RESOLUTION, - touch, - false, - true, - false, - false - ); - - configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty; - - auto display = std::make_shared(std::move(configuration)); - return std::reinterpret_pointer_cast(display); -} diff --git a/Devices/cyd-3248s035c/Source/devices/Display.h b/Devices/cyd-3248s035c/Source/devices/Display.h deleted file mode 100644 index 47cff95ae..000000000 --- a/Devices/cyd-3248s035c/Source/devices/Display.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Display backlight (PWM) -constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_27; - -// Display -constexpr auto LCD_SPI_HOST = SPI2_HOST; -constexpr auto LCD_PIN_CS = GPIO_NUM_15; -constexpr auto LCD_PIN_DC = GPIO_NUM_2; -constexpr auto LCD_HORIZONTAL_RESOLUTION = 320; -constexpr auto LCD_VERTICAL_RESOLUTION = 480; -constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 10; -constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT; - -std::shared_ptr createDisplay(); diff --git a/Devices/cyd-3248s035c/cyd,3248s035c.dts b/Devices/cyd-3248s035c/cyd,3248s035c.dts index 3edce5d2b..dd8e8647c 100644 --- a/Devices/cyd-3248s035c/cyd,3248s035c.dts +++ b/Devices/cyd-3248s035c/cyd,3248s035c.dts @@ -7,7 +7,11 @@ #include #include #include -#include +#include +#include +#include +#include +#include / { compatible = "root"; @@ -29,6 +33,13 @@ clock-frequency = <400000>; pin-sda = <&gpio0 33 GPIO_FLAG_NONE>; pin-scl = <&gpio0 32 GPIO_FLAG_NONE>; + + touch { + compatible = "goodix,gt911"; + reg = <0x5D>; + x-max = <320>; + y-max = <480>; + }; }; // CN1 header @@ -40,15 +51,74 @@ pin-scl = <&gpio0 22 GPIO_FLAG_NONE>; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + + display_backlight { + compatible = "pwm-backlight"; + // Off by default so display power-on won't show the screen from before the last power loss. + // The display backlight is turned on during the boot process. + status = "disabled"; + pwm = <&display_backlight_pwm>; + }; + spi0 { compatible = "espressif,esp32-spi"; host = ; cs-gpios = <&gpio0 15 GPIO_FLAG_NONE>; pin-mosi = <&gpio0 13 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 14 GPIO_FLAG_NONE>; - - display { - compatible = "display-placeholder"; + + display@0 { + compatible = "sitronix,st7796"; + horizontal-resolution = <320>; + vertical-resolution = <480>; + mirror-x; + pixel-clock-hz = <80000000>; + pin-dc = <&gpio0 2 GPIO_FLAG_NONE>; + backlight = <&display_backlight>; }; }; diff --git a/Devices/cyd-3248s035c/device.properties b/Devices/cyd-3248s035c/device.properties index c8fc929d1..b166661c7 100644 --- a/Devices/cyd-3248s035c/device.properties +++ b/Devices/cyd-3248s035c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=SD display.size=3.5" diff --git a/Devices/cyd-3248s035c/devicetree.yaml b/Devices/cyd-3248s035c/devicetree.yaml index 45ca5398e..22496f063 100644 --- a/Devices/cyd-3248s035c/devicetree.yaml +++ b/Devices/cyd-3248s035c/devicetree.yaml @@ -1,3 +1,5 @@ dependencies: -- Platforms/platform-esp32 + - Platforms/platform-esp32 + - Drivers/st7796-module + - Drivers/gt911-module dts: cyd,3248s035c.dts diff --git a/Devices/cyd-3248s035c/Source/module.cpp b/Devices/cyd-3248s035c/source/module.cpp similarity index 82% rename from Devices/cyd-3248s035c/Source/module.cpp rename to Devices/cyd-3248s035c/source/module.cpp index bf43c7b2c..6c5b2cd9c 100644 --- a/Devices/cyd-3248s035c/Source/module.cpp +++ b/Devices/cyd-3248s035c/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-8048s043c/CMakeLists.txt b/Devices/cyd-8048s043c/CMakeLists.txt index c6e98b904..a832a83a2 100644 --- a/Devices/cyd-8048s043c/CMakeLists.txt +++ b/Devices/cyd-8048s043c/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd RgbDisplay GT911 PwmBacklight driver vfs fatfs + REQUIRES TactilityKernel driver ) diff --git a/Devices/cyd-8048s043c/Source/Configuration.cpp b/Devices/cyd-8048s043c/Source/Configuration.cpp deleted file mode 100644 index fb4a31a9d..000000000 --- a/Devices/cyd-8048s043c/Source/Configuration.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "PwmBacklight.h" -#include "devices/Display.h" - -#include - -using namespace tt::hal; - -static bool initBoot() { - // Display backlight - return driver::pwmbacklight::init(GPIO_NUM_2, 200); -} - -static DeviceVector createDevices() { - return { - createDisplay(), - }; -} - -extern const Configuration hardwareConfiguration = { - .initBoot = initBoot, - .createDevices = createDevices -}; diff --git a/Devices/cyd-8048s043c/Source/devices/Display.cpp b/Devices/cyd-8048s043c/Source/devices/Display.cpp deleted file mode 100644 index c2ecaae72..000000000 --- a/Devices/cyd-8048s043c/Source/devices/Display.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "Display.h" - -#include -#include -#include -#include -#include - -std::shared_ptr createTouch() { - // Note for future changes: Reset pin is 38 and interrupt pin is 18 - // or INT = NC, schematic and other info floating around is kinda conflicting... - auto* i2c = device_find_by_name("i2c_internal"); - check(i2c); - auto configuration = std::make_unique( - i2c, - 800, - 480 - ); - - return std::make_shared(std::move(configuration)); -} - -std::shared_ptr createDisplay() { - auto touch = createTouch(); - - constexpr uint32_t bufferPixels = 800 * 10; - - esp_lcd_rgb_panel_config_t rgb_panel_config = { - .clk_src = LCD_CLK_SRC_DEFAULT, - .timings = { - .pclk_hz = 16000000, - .h_res = 800, - .v_res = 480, - .hsync_pulse_width = 4, - .hsync_back_porch = 8, - .hsync_front_porch = 8, - .vsync_pulse_width = 4, - .vsync_back_porch = 8, - .vsync_front_porch = 8, - .flags = { - .hsync_idle_low = false, - .vsync_idle_low = false, - .de_idle_high = false, - .pclk_active_neg = true, - .pclk_idle_high = false - } - }, - .data_width = 16, - .bits_per_pixel = 0, - .num_fbs = 2, - .bounce_buffer_size_px = bufferPixels, - .sram_trans_align = 8, - .psram_trans_align = 64, - .hsync_gpio_num = GPIO_NUM_39, - .vsync_gpio_num = GPIO_NUM_41, - .de_gpio_num = GPIO_NUM_40 , - .pclk_gpio_num = GPIO_NUM_42, - .disp_gpio_num = GPIO_NUM_NC, - .data_gpio_nums = { - GPIO_NUM_8, // B3 - GPIO_NUM_3, // B4 - GPIO_NUM_46, // B5 - GPIO_NUM_9, // B6 - GPIO_NUM_1, // B7 - GPIO_NUM_5, // G2 - GPIO_NUM_6, // G3 - GPIO_NUM_7, // G4 - GPIO_NUM_15, // G5 - GPIO_NUM_16, // G6 - GPIO_NUM_4, // G7 - GPIO_NUM_45, // R3 - GPIO_NUM_48, // R4 - GPIO_NUM_47, // R5 - GPIO_NUM_21, // R6 - GPIO_NUM_14, // R7 - }, - .flags = { - .disp_active_low = false, - .refresh_on_demand = false, - .fb_in_psram = true, - .double_fb = true, - .no_fb = false, - .bb_invalidate_cache = false - } - }; - - RgbDisplay::BufferConfiguration buffer_config = { - .size = (800 * 480), - .useSpi = true, - .doubleBuffer = true, - .bounceBufferMode = true, - .avoidTearing = false - }; - - auto configuration = std::make_unique( - rgb_panel_config, - buffer_config, - touch, - LV_COLOR_FORMAT_RGB565, - false, - false, - false, - false, - driver::pwmbacklight::setBacklightDuty - ); - - return std::make_shared(std::move(configuration)); -} diff --git a/Devices/cyd-8048s043c/Source/devices/Display.h b/Devices/cyd-8048s043c/Source/devices/Display.h deleted file mode 100644 index 5a0d81b38..000000000 --- a/Devices/cyd-8048s043c/Source/devices/Display.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "Tactility/hal/display/DisplayDevice.h" - -std::shared_ptr createDisplay(); diff --git a/Devices/cyd-8048s043c/cyd,8048s043c.dts b/Devices/cyd-8048s043c/cyd,8048s043c.dts index 68087ce95..71b477695 100644 --- a/Devices/cyd-8048s043c/cyd,8048s043c.dts +++ b/Devices/cyd-8048s043c/cyd,8048s043c.dts @@ -8,6 +8,10 @@ #include #include #include +#include +#include +#include +#include / { compatible = "root"; @@ -34,6 +38,16 @@ clock-frequency = <400000>; pin-sda = <&gpio0 19 GPIO_FLAG_NONE>; pin-scl = <&gpio0 20 GPIO_FLAG_NONE>; + + touch0 { + // Reset pin 38 and interrupt pin 18 (or INT = NC) exist on the board but are not + // wired up here - conflicting schematic info, unverified (matches the original + // deprecated-HAL config). + compatible = "goodix,gt911"; + reg = <0x5D>; + x-max = <800>; + y-max = <480>; + }; }; i2c_external { @@ -51,13 +65,64 @@ pin-mosi = <&gpio0 11 GPIO_FLAG_NONE>; pin-miso = <&gpio0 13 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>; - + sdcard@0 { compatible = "espressif,esp32-sdspi"; frequency-khz = <20000>; }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 2 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + + display_backlight { + compatible = "pwm-backlight"; + pwm = <&display_backlight_pwm>; + }; + + display0 { + compatible = "espressif,esp32-rgb-display"; + horizontal-resolution = <800>; + vertical-resolution = <480>; + pixel-clock-hz = <16000000>; + hsync-pulse-width = <4>; + hsync-back-porch = <8>; + hsync-front-porch = <8>; + vsync-pulse-width = <4>; + vsync-back-porch = <8>; + vsync-front-porch = <8>; + pclk-active-neg; + num-fbs = <2>; + double-fb; + bounce-buffer-size-px = <8000>; + pin-hsync = <&gpio0 39 GPIO_FLAG_NONE>; + pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>; + pin-de = <&gpio0 40 GPIO_FLAG_NONE>; + pin-pclk = <&gpio0 42 GPIO_FLAG_NONE>; + pin-data0 = <&gpio0 8 GPIO_FLAG_NONE>; // B3 + pin-data1 = <&gpio0 3 GPIO_FLAG_NONE>; // B4 + pin-data2 = <&gpio0 46 GPIO_FLAG_NONE>; // B5 + pin-data3 = <&gpio0 9 GPIO_FLAG_NONE>; // B6 + pin-data4 = <&gpio0 1 GPIO_FLAG_NONE>; // B7 + pin-data5 = <&gpio0 5 GPIO_FLAG_NONE>; // G2 + pin-data6 = <&gpio0 6 GPIO_FLAG_NONE>; // G3 + pin-data7 = <&gpio0 7 GPIO_FLAG_NONE>; // G4 + pin-data8 = <&gpio0 15 GPIO_FLAG_NONE>; // G5 + pin-data9 = <&gpio0 16 GPIO_FLAG_NONE>; // G6 + pin-data10 = <&gpio0 4 GPIO_FLAG_NONE>; // G7 + pin-data11 = <&gpio0 45 GPIO_FLAG_NONE>; // R3 + pin-data12 = <&gpio0 48 GPIO_FLAG_NONE>; // R4 + pin-data13 = <&gpio0 47 GPIO_FLAG_NONE>; // R5 + pin-data14 = <&gpio0 21 GPIO_FLAG_NONE>; // R6 + pin-data15 = <&gpio0 14 GPIO_FLAG_NONE>; // R7 + backlight = <&display_backlight>; + }; + uart1 { compatible = "espressif,esp32-uart"; status = "disabled"; diff --git a/Devices/cyd-8048s043c/device.properties b/Devices/cyd-8048s043c/device.properties index 8056421d5..6b9a7b3e7 100644 --- a/Devices/cyd-8048s043c/device.properties +++ b/Devices/cyd-8048s043c/device.properties @@ -12,6 +12,8 @@ hardware.spiRamSpeed=80M hardware.esptoolFlashFreq=80M hardware.bluetooth=true +dependencies.useDeprecatedHal=false + storage.userDataLocation=SD display.size=4.3" diff --git a/Devices/cyd-8048s043c/devicetree.yaml b/Devices/cyd-8048s043c/devicetree.yaml index 59692b414..bc3c70e6c 100644 --- a/Devices/cyd-8048s043c/devicetree.yaml +++ b/Devices/cyd-8048s043c/devicetree.yaml @@ -1,3 +1,5 @@ dependencies: - Platforms/platform-esp32 + - Drivers/rgb-display-module + - Drivers/gt911-module dts: cyd,8048s043c.dts diff --git a/Devices/cyd-8048s043c/Source/module.cpp b/Devices/cyd-8048s043c/source/module.cpp similarity index 87% rename from Devices/cyd-8048s043c/Source/module.cpp rename to Devices/cyd-8048s043c/source/module.cpp index acb29a758..d638238dc 100644 --- a/Devices/cyd-8048s043c/Source/module.cpp +++ b/Devices/cyd-8048s043c/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-e32r28t/CMakeLists.txt b/Devices/cyd-e32r28t/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-e32r28t/CMakeLists.txt +++ b/Devices/cyd-e32r28t/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-e32r28t/cyd,e32r28t.dts b/Devices/cyd-e32r28t/cyd,e32r28t.dts index 2ae405d13..e5e111e41 100644 --- a/Devices/cyd-e32r28t/cyd,e32r28t.dts +++ b/Devices/cyd-e32r28t/cyd,e32r28t.dts @@ -5,7 +5,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -23,13 +25,58 @@ gpio-count = <40>; }; + + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 22 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 21 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 21 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; touch { diff --git a/Devices/cyd-e32r28t/source/module.cpp b/Devices/cyd-e32r28t/source/module.cpp index 7806af3d0..3ee0556ca 100644 --- a/Devices/cyd-e32r28t/source/module.cpp +++ b/Devices/cyd-e32r28t/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/cyd-e32r32p/CMakeLists.txt b/Devices/cyd-e32r32p/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/cyd-e32r32p/CMakeLists.txt +++ b/Devices/cyd-e32r32p/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/cyd-e32r32p/cyd,e32r32p.dts b/Devices/cyd-e32r32p/cyd,e32r32p.dts index bdbc379d7..2953bf9d3 100644 --- a/Devices/cyd-e32r32p/cyd,e32r32p.dts +++ b/Devices/cyd-e32r32p/cyd,e32r32p.dts @@ -8,7 +8,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -40,6 +42,43 @@ channels = ; }; + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 22 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; + // Matches the deprecated HAL's old ChargeFromAdcVoltage config: adcMultiplier=2.11, // adcRefVoltage=3.3 (default), voltageMin/Max=3.2/4.2 (default, same as battery-sense's own // fixed curve - see TactilityKernel/source/drivers/battery_sense.cpp). @@ -50,13 +89,20 @@ multiplier = <2110>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <25000>; + ledc-timer = <1>; + ledc-channel = <3>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <40000>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/cyd-e32r32p/source/module.cpp b/Devices/cyd-e32r32p/source/module.cpp index 65488c2b9..1a3df3034 100644 --- a/Devices/cyd-e32r32p/source/module.cpp +++ b/Devices/cyd-e32r32p/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/elecrow-crowpanel-advance-28/CMakeLists.txt b/Devices/elecrow-crowpanel-advance-28/CMakeLists.txt index a115d11b2..a7d3e6712 100644 --- a/Devices/elecrow-crowpanel-advance-28/CMakeLists.txt +++ b/Devices/elecrow-crowpanel-advance-28/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility FT5x06 ST7789 PwmBacklight driver + REQUIRES TactilityKernel ) diff --git a/Devices/elecrow-crowpanel-advance-28/Source/Configuration.cpp b/Devices/elecrow-crowpanel-advance-28/Source/Configuration.cpp deleted file mode 100644 index 168fa4a68..000000000 --- a/Devices/elecrow-crowpanel-advance-28/Source/Configuration.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "PwmBacklight.h" -#include "devices/Display.h" - -#include - -using namespace tt::hal; - -static bool initBoot() { - return driver::pwmbacklight::init(GPIO_NUM_38); -} - -static DeviceVector createDevices() { - return { - createDisplay(), - }; -} - -extern const Configuration hardwareConfiguration = { - .initBoot = initBoot, - .createDevices = createDevices -}; diff --git a/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.cpp b/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.cpp deleted file mode 100644 index 3d1d12b29..000000000 --- a/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "Display.h" - -#include -#include -#include - -static std::shared_ptr createTouch() { - auto configuration = std::make_unique( - I2C_NUM_0, - LCD_HORIZONTAL_RESOLUTION, - LCD_VERTICAL_RESOLUTION, - false, - false, - false - ); - - return std::make_shared(std::move(configuration)); -} - -std::shared_ptr createDisplay() { - St7789Display::Configuration panel_configuration = { - .horizontalResolution = LCD_HORIZONTAL_RESOLUTION, - .verticalResolution = LCD_VERTICAL_RESOLUTION, - .gapX = 0, - .gapY = 0, - .swapXY = false, - .mirrorX = false, - .mirrorY = false, - .invertColor = true, - .bufferSize = LCD_BUFFER_SIZE, - .touch = createTouch(), - .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty, - .resetPin = GPIO_NUM_NC, - .lvglSwapBytes = false - }; - - auto spi_configuration = std::make_shared(St7789Display::SpiConfiguration { - .spiHostDevice = LCD_SPI_HOST, - .csPin = LCD_PIN_CS, - .dcPin = LCD_PIN_DC, - .pixelClockFrequency = 62'500'000, - .transactionQueueDepth = 10 - }); - - return std::make_shared(panel_configuration, spi_configuration); -} diff --git a/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.h b/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.h deleted file mode 100644 index 7d579c125..000000000 --- a/Devices/elecrow-crowpanel-advance-28/Source/devices/Display.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include -#include - -constexpr auto LCD_SPI_HOST = SPI2_HOST; -constexpr auto LCD_PIN_CS = GPIO_NUM_40; -constexpr auto LCD_PIN_DC = GPIO_NUM_41; // RS -constexpr auto LCD_HORIZONTAL_RESOLUTION = 240; -constexpr auto LCD_VERTICAL_RESOLUTION = 320; -constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 10; -constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT; - -std::shared_ptr createDisplay(); diff --git a/Devices/elecrow-crowpanel-advance-28/device.properties b/Devices/elecrow-crowpanel-advance-28/device.properties index 9d2fd7949..99ae3f7d9 100644 --- a/Devices/elecrow-crowpanel-advance-28/device.properties +++ b/Devices/elecrow-crowpanel-advance-28/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +dependencies.useDeprecatedHal=false + storage.userDataLocation=SD display.size=2.8" diff --git a/Devices/elecrow-crowpanel-advance-28/devicetree.yaml b/Devices/elecrow-crowpanel-advance-28/devicetree.yaml index bb752ac5e..45e44f88c 100644 --- a/Devices/elecrow-crowpanel-advance-28/devicetree.yaml +++ b/Devices/elecrow-crowpanel-advance-28/devicetree.yaml @@ -1,3 +1,5 @@ dependencies: - Platforms/platform-esp32 + - Drivers/st7789-module + - Drivers/ft5x06-module dts: elecrow,crowpanel-advance-28.dts diff --git a/Devices/elecrow-crowpanel-advance-28/elecrow,crowpanel-advance-28.dts b/Devices/elecrow-crowpanel-advance-28/elecrow,crowpanel-advance-28.dts index b365f905d..fe6881c60 100644 --- a/Devices/elecrow-crowpanel-advance-28/elecrow,crowpanel-advance-28.dts +++ b/Devices/elecrow-crowpanel-advance-28/elecrow,crowpanel-advance-28.dts @@ -8,7 +8,10 @@ #include #include #include -#include +#include +#include +#include +#include / { compatible = "root"; @@ -35,6 +38,26 @@ clock-frequency = <400000>; pin-sda = <&gpio0 15 GPIO_FLAG_NONE>; pin-scl = <&gpio0 16 GPIO_FLAG_NONE>; + + touch0 { + compatible = "focaltech,ft5x06"; + reg = <0x38>; + x-max = <240>; + y-max = <320>; + }; + }; + + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 38 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + + display_backlight { + compatible = "pwm-backlight"; + pwm = <&display_backlight_pwm>; }; spi0 { @@ -43,9 +66,15 @@ cs-gpios = <&gpio0 40 GPIO_FLAG_NONE>; pin-mosi = <&gpio0 39 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 42 GPIO_FLAG_NONE>; - - display { - compatible = "display-placeholder"; + + display@0 { + compatible = "sitronix,st7789"; + horizontal-resolution = <240>; + vertical-resolution = <320>; + invert-color; + pixel-clock-hz = <62500000>; + pin-dc = <&gpio0 41 GPIO_FLAG_NONE>; + backlight = <&display_backlight>; }; }; diff --git a/Devices/elecrow-crowpanel-advance-28/Source/module.cpp b/Devices/elecrow-crowpanel-advance-28/source/module.cpp similarity index 88% rename from Devices/elecrow-crowpanel-advance-28/Source/module.cpp rename to Devices/elecrow-crowpanel-advance-28/source/module.cpp index e7bd2bba3..df8623120 100644 --- a/Devices/elecrow-crowpanel-advance-28/Source/module.cpp +++ b/Devices/elecrow-crowpanel-advance-28/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/elecrow-crowpanel-advance-35/CMakeLists.txt b/Devices/elecrow-crowpanel-advance-35/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/elecrow-crowpanel-advance-35/CMakeLists.txt +++ b/Devices/elecrow-crowpanel-advance-35/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/elecrow-crowpanel-advance-35/elecrow,crowpanel-advance-35.dts b/Devices/elecrow-crowpanel-advance-35/elecrow,crowpanel-advance-35.dts index e6f6cf168..173c9cd40 100644 --- a/Devices/elecrow-crowpanel-advance-35/elecrow,crowpanel-advance-35.dts +++ b/Devices/elecrow-crowpanel-advance-35/elecrow,crowpanel-advance-35.dts @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include @@ -46,13 +47,20 @@ }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 38 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 38 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/elecrow-crowpanel-advance-50/elecrow,crowpanel-advance-50.dts b/Devices/elecrow-crowpanel-advance-50/elecrow,crowpanel-advance-50.dts index 0be96a1ea..4cffd6041 100644 --- a/Devices/elecrow-crowpanel-advance-50/elecrow,crowpanel-advance-50.dts +++ b/Devices/elecrow-crowpanel-advance-50/elecrow,crowpanel-advance-50.dts @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,8 +70,8 @@ }; display_backlight { - compatible = "espressif,esp32-gpio-backlight"; - pin-backlight = <&io_expander0 1 GPIO_FLAG_NONE>; + compatible = "gpio-backlight"; + pin = <&io_expander0 1 GPIO_FLAG_NONE>; }; display0 { diff --git a/Devices/elecrow-crowpanel-basic-28/CMakeLists.txt b/Devices/elecrow-crowpanel-basic-28/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/elecrow-crowpanel-basic-28/CMakeLists.txt +++ b/Devices/elecrow-crowpanel-basic-28/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/elecrow-crowpanel-basic-28/elecrow,crowpanel-basic-28.dts b/Devices/elecrow-crowpanel-basic-28/elecrow,crowpanel-basic-28.dts index 58945c75a..5c04fcab3 100644 --- a/Devices/elecrow-crowpanel-basic-28/elecrow,crowpanel-basic-28.dts +++ b/Devices/elecrow-crowpanel-basic-28/elecrow,crowpanel-basic-28.dts @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include @@ -33,13 +34,20 @@ pin-scl = <&gpio0 21 GPIO_FLAG_NONE>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <25000>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <40000>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/elecrow-crowpanel-basic-28/source/module.cpp b/Devices/elecrow-crowpanel-basic-28/source/module.cpp index e9cdd36d4..4f792da31 100644 --- a/Devices/elecrow-crowpanel-basic-28/source/module.cpp +++ b/Devices/elecrow-crowpanel-basic-28/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/elecrow-crowpanel-basic-35/CMakeLists.txt b/Devices/elecrow-crowpanel-basic-35/CMakeLists.txt index a832a83a2..a7d3e6712 100644 --- a/Devices/elecrow-crowpanel-basic-35/CMakeLists.txt +++ b/Devices/elecrow-crowpanel-basic-35/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel driver + REQUIRES TactilityKernel ) diff --git a/Devices/elecrow-crowpanel-basic-35/elecrow,crowpanel-basic-35.dts b/Devices/elecrow-crowpanel-basic-35/elecrow,crowpanel-basic-35.dts index e7f888b5e..de27790aa 100644 --- a/Devices/elecrow-crowpanel-basic-35/elecrow,crowpanel-basic-35.dts +++ b/Devices/elecrow-crowpanel-basic-35/elecrow,crowpanel-basic-35.dts @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include @@ -33,13 +34,20 @@ pin-scl = <&gpio0 21 GPIO_FLAG_NONE>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/elecrow-crowpanel-basic-50/elecrow,crowpanel-basic-50.dts b/Devices/elecrow-crowpanel-basic-50/elecrow,crowpanel-basic-50.dts index 8477a403e..1bf9d0bfb 100644 --- a/Devices/elecrow-crowpanel-basic-50/elecrow,crowpanel-basic-50.dts +++ b/Devices/elecrow-crowpanel-basic-50/elecrow,crowpanel-basic-50.dts @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include @@ -63,10 +64,17 @@ }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 2 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; - pin-backlight = <&gpio0 2 GPIO_FLAG_NONE>; - frequency-hz = <512>; + compatible = "pwm-backlight"; + pwm = <&display_backlight_pwm>; }; display0 { diff --git a/Devices/generic-esp32/CMakeLists.txt b/Devices/generic-esp32/CMakeLists.txt index b2352d223..a7d3e6712 100644 --- a/Devices/generic-esp32/CMakeLists.txt +++ b/Devices/generic-esp32/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility + REQUIRES TactilityKernel ) diff --git a/Devices/generic-esp32/Source/Configuration.cpp b/Devices/generic-esp32/Source/Configuration.cpp deleted file mode 100644 index 180cffb23..000000000 --- a/Devices/generic-esp32/Source/Configuration.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -extern const tt::hal::Configuration hardwareConfiguration = {}; diff --git a/Devices/generic-esp32/device.properties b/Devices/generic-esp32/device.properties index 8b803a84d..03f143e8b 100644 --- a/Devices/generic-esp32/device.properties +++ b/Devices/generic-esp32/device.properties @@ -7,4 +7,6 @@ hardware.target=ESP32 hardware.flashSize=8MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=Internal diff --git a/Devices/generic-esp32/Source/module.cpp b/Devices/generic-esp32/source/module.cpp similarity index 87% rename from Devices/generic-esp32/Source/module.cpp rename to Devices/generic-esp32/source/module.cpp index 6b0d3d849..70fa7604b 100644 --- a/Devices/generic-esp32/Source/module.cpp +++ b/Devices/generic-esp32/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/generic-esp32c6/CMakeLists.txt b/Devices/generic-esp32c6/CMakeLists.txt index b2352d223..a7d3e6712 100644 --- a/Devices/generic-esp32c6/CMakeLists.txt +++ b/Devices/generic-esp32c6/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility + REQUIRES TactilityKernel ) diff --git a/Devices/generic-esp32c6/Source/Configuration.cpp b/Devices/generic-esp32c6/Source/Configuration.cpp deleted file mode 100644 index 180cffb23..000000000 --- a/Devices/generic-esp32c6/Source/Configuration.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -extern const tt::hal::Configuration hardwareConfiguration = {}; diff --git a/Devices/generic-esp32c6/device.properties b/Devices/generic-esp32c6/device.properties index bd332c250..310bae863 100644 --- a/Devices/generic-esp32c6/device.properties +++ b/Devices/generic-esp32c6/device.properties @@ -7,4 +7,6 @@ hardware.target=ESP32C6 hardware.flashSize=8MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=Internal diff --git a/Devices/generic-esp32c6/Source/module.cpp b/Devices/generic-esp32c6/source/module.cpp similarity index 88% rename from Devices/generic-esp32c6/Source/module.cpp rename to Devices/generic-esp32c6/source/module.cpp index fb7def5f9..2113d5cc9 100644 --- a/Devices/generic-esp32c6/Source/module.cpp +++ b/Devices/generic-esp32c6/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/generic-esp32p4/CMakeLists.txt b/Devices/generic-esp32p4/CMakeLists.txt index b2352d223..a7d3e6712 100644 --- a/Devices/generic-esp32p4/CMakeLists.txt +++ b/Devices/generic-esp32p4/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility + REQUIRES TactilityKernel ) diff --git a/Devices/generic-esp32p4/Source/Configuration.cpp b/Devices/generic-esp32p4/Source/Configuration.cpp deleted file mode 100644 index 180cffb23..000000000 --- a/Devices/generic-esp32p4/Source/Configuration.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -extern const tt::hal::Configuration hardwareConfiguration = {}; diff --git a/Devices/generic-esp32p4/device.properties b/Devices/generic-esp32p4/device.properties index 4a050b399..d2641c1fb 100644 --- a/Devices/generic-esp32p4/device.properties +++ b/Devices/generic-esp32p4/device.properties @@ -7,4 +7,6 @@ hardware.target=ESP32P4 hardware.flashSize=8MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=Internal diff --git a/Devices/generic-esp32p4/Source/module.cpp b/Devices/generic-esp32p4/source/module.cpp similarity index 88% rename from Devices/generic-esp32p4/Source/module.cpp rename to Devices/generic-esp32p4/source/module.cpp index 00f8cf7db..3a54bde16 100644 --- a/Devices/generic-esp32p4/Source/module.cpp +++ b/Devices/generic-esp32p4/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/generic-esp32s3/CMakeLists.txt b/Devices/generic-esp32s3/CMakeLists.txt index b2352d223..a7d3e6712 100644 --- a/Devices/generic-esp32s3/CMakeLists.txt +++ b/Devices/generic-esp32s3/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility + REQUIRES TactilityKernel ) diff --git a/Devices/generic-esp32s3/Source/Configuration.cpp b/Devices/generic-esp32s3/Source/Configuration.cpp deleted file mode 100644 index 180cffb23..000000000 --- a/Devices/generic-esp32s3/Source/Configuration.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -extern const tt::hal::Configuration hardwareConfiguration = {}; diff --git a/Devices/generic-esp32s3/device.properties b/Devices/generic-esp32s3/device.properties index 8512a4506..132ea86ce 100644 --- a/Devices/generic-esp32s3/device.properties +++ b/Devices/generic-esp32s3/device.properties @@ -7,4 +7,6 @@ hardware.target=ESP32S3 hardware.flashSize=8MB hardware.spiRam=false +dependencies.useDeprecatedHal=false + storage.userDataLocation=Internal diff --git a/Devices/generic-esp32s3/Source/module.cpp b/Devices/generic-esp32s3/source/module.cpp similarity index 88% rename from Devices/generic-esp32s3/Source/module.cpp rename to Devices/generic-esp32s3/source/module.cpp index 566d17c3b..05fe7d0dc 100644 --- a/Devices/generic-esp32s3/Source/module.cpp +++ b/Devices/generic-esp32s3/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/guition-jc2432w328c/Source/Configuration.cpp b/Devices/guition-jc2432w328c/Source/Configuration.cpp index 9734b668f..8324dcffe 100644 --- a/Devices/guition-jc2432w328c/Source/Configuration.cpp +++ b/Devices/guition-jc2432w328c/Source/Configuration.cpp @@ -1,5 +1,4 @@ #include "devices/Display.h" -#include #include #include @@ -7,16 +6,6 @@ using namespace tt::hal; static bool initBoot() { - //Set the RGB Led Pins to output and turn them off - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT)); //Red - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT)); //Green - ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT)); //Blue - - //0 on, 1 off... yep it's backwards. - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_4, 1)); //Red - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_16, 1)); //Green - ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_17, 1)); //Blue - return driver::pwmbacklight::init(LCD_PIN_BACKLIGHT); } diff --git a/Devices/guition-jc2432w328c/Source/module.cpp b/Devices/guition-jc2432w328c/Source/module.cpp index 0abd3887e..d1e1fe373 100644 --- a/Devices/guition-jc2432w328c/Source/module.cpp +++ b/Devices/guition-jc2432w328c/Source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/guition-jc2432w328c/guition,jc2432w328c.dts b/Devices/guition-jc2432w328c/guition,jc2432w328c.dts index 0a76eaff6..acad47f5f 100644 --- a/Devices/guition-jc2432w328c/guition,jc2432w328c.dts +++ b/Devices/guition-jc2432w328c/guition,jc2432w328c.dts @@ -1,13 +1,15 @@ /dts-v1/; #include -#include #include #include +#include #include #include #include +#include #include +#include / { compatible = "root"; @@ -74,4 +76,41 @@ pin-tx = <&gpio0 22 GPIO_FLAG_NONE>; pin-rx = <&gpio0 21 GPIO_FLAG_NONE>; }; + + rgb_led_channel_red { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 4 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <0>; + inverted; + }; + + rgb_led_channel_green { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 16 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <1>; + inverted; + }; + + rgb_led_channel_blue { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 17 GPIO_FLAG_NONE>; + period-ns = <500000>; + ledc-timer = <0>; + ledc-channel = <2>; + inverted; + }; + + rgb_led_pwm { + compatible = "rgb-led-pwm"; + pwm-red = <&rgb_led_channel_red>; + pwm-green = <&rgb_led_channel_green>; + pwm-blue = <&rgb_led_channel_blue>; + // Default is red, and we want to reset it to off by default + default-color = <0 0 0>; + enabled; + }; }; diff --git a/Devices/lilygo-tdeck-plus/lilygo,tdeck-plus.dts b/Devices/lilygo-tdeck-plus/lilygo,tdeck-plus.dts index 6e7b737f8..1cfc2c93d 100644 --- a/Devices/lilygo-tdeck-plus/lilygo,tdeck-plus.dts +++ b/Devices/lilygo-tdeck-plus/lilygo,tdeck-plus.dts @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -134,15 +135,22 @@ }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 42 GPIO_FLAG_NONE>; + // 32 KHz and higher causes the screen to start dimming again above 80% brightness + // when moving the brightness slider rapidly from a lower setting to 100% (debug-traced, not a slider bug). + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so dispaly power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 42 GPIO_FLAG_NONE>; - // 32 KHz and higher causes the screen to start dimming again above 80% brightness - // when moving the brightness slider rapidly from a lower setting to 100% (debug-traced, not a slider bug). - frequency-hz = <30000>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/lilygo-tdeck/lilygo,tdeck.dts b/Devices/lilygo-tdeck/lilygo,tdeck.dts index da408c310..62ede4f77 100644 --- a/Devices/lilygo-tdeck/lilygo,tdeck.dts +++ b/Devices/lilygo-tdeck/lilygo,tdeck.dts @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -134,15 +135,22 @@ }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 42 GPIO_FLAG_NONE>; + // 32 KHz and higher causes the screen to start dimming again above 80% brightness + // when moving the brightness slider rapidly from a lower setting to 100% (debug-traced, not a slider bug). + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so dispaly power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 42 GPIO_FLAG_NONE>; - // 32 KHz and higher causes the screen to start dimming again above 80% brightness - // when moving the brightness slider rapidly from a lower setting to 100% (debug-traced, not a slider bug). - frequency-hz = <30000>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/lilygo-thmi/lilygo,thmi.dts b/Devices/lilygo-thmi/lilygo,thmi.dts index 33f023cec..d724d9a3a 100644 --- a/Devices/lilygo-thmi/lilygo,thmi.dts +++ b/Devices/lilygo-thmi/lilygo,thmi.dts @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -39,13 +40,13 @@ // HAL's initBoot() used to run. gpio-hog nodes run in declaration order, so they must stay // before the i8080 bus node. power_on { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&gpio0 14 GPIO_FLAG_NONE>; mode = ; }; power_en { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&gpio0 10 GPIO_FLAG_NONE>; mode = ; }; @@ -68,13 +69,20 @@ multiplier = <2000>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 38 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 38 GPIO_FLAG_NONE>; - frequency-hz = <30000>; + pwm = <&display_backlight_pwm>; }; i8080_0 { diff --git a/Devices/m5stack-cardputer-adv/m5stack,cardputer-adv.dts b/Devices/m5stack-cardputer-adv/m5stack,cardputer-adv.dts index a00145083..e47a2cd7c 100644 --- a/Devices/m5stack-cardputer-adv/m5stack,cardputer-adv.dts +++ b/Devices/m5stack-cardputer-adv/m5stack,cardputer-adv.dts @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include #include #include @@ -81,13 +82,20 @@ i2cClockFrequency = <400000>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 38 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 38 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/m5stack-cardputer/m5stack,cardputer.dts b/Devices/m5stack-cardputer/m5stack,cardputer.dts index cc34fca94..bd802d2f4 100644 --- a/Devices/m5stack-cardputer/m5stack,cardputer.dts +++ b/Devices/m5stack-cardputer/m5stack,cardputer.dts @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include #include @@ -64,13 +65,20 @@ i2cClockFrequency = <400000>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 38 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 38 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/m5stack-stickc-plus2/m5stack,stickc-plus2.dts b/Devices/m5stack-stickc-plus2/m5stack,stickc-plus2.dts index 47a5dac7a..701040f98 100644 --- a/Devices/m5stack-stickc-plus2/m5stack,stickc-plus2.dts +++ b/Devices/m5stack-stickc-plus2/m5stack,stickc-plus2.dts @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include @@ -52,13 +53,20 @@ pin-scl = <&gpio0 33 GPIO_FLAG_NONE>; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 27 GPIO_FLAG_NONE>; + period-ns = <1953125>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + display_backlight { - compatible = "espressif,esp32-ledc-backlight"; + compatible = "pwm-backlight"; // Off by default so display power-on won't show the screen from before the last power loss. // The display backlight is turned on during the boot process. status = "disabled"; - pin-backlight = <&gpio0 27 GPIO_FLAG_NONE>; - frequency-hz = <512>; + pwm = <&display_backlight_pwm>; }; spi0 { diff --git a/Devices/unphone/unphone.dts b/Devices/unphone/unphone.dts index 323ef0532..f0c3c3999 100644 --- a/Devices/unphone/unphone.dts +++ b/Devices/unphone/unphone.dts @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include / { @@ -66,42 +66,42 @@ }; display_backlight { - compatible = "espressif,esp32-gpio-backlight"; - pin-backlight = <&tca9535 2 GPIO_FLAG_NONE>; + compatible = "gpio-backlight"; + pin = <&tca9535 2 GPIO_FLAG_NONE>; }; usb_vsense { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&tca9535 14 GPIO_FLAG_NONE>; mode = ; }; vibration_motor { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&tca9535 7 GPIO_FLAG_NONE>; mode = ; }; ir_leds { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&gpio0 12 GPIO_FLAG_NONE>; mode = ; }; red_led { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&gpio0 13 GPIO_FLAG_NONE>; mode = ; }; green_led { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&tca9535 9 GPIO_FLAG_NONE>; mode = ; }; blue_led { - compatible = "tactility,gpio-hog"; + compatible = "gpio-hog"; pin = <&tca9535 13 GPIO_FLAG_NONE>; mode = ; }; diff --git a/Devices/waveshare-s3-lcd-13/CMakeLists.txt b/Devices/waveshare-s3-lcd-13/CMakeLists.txt index c3a0c54bf..a832a83a2 100644 --- a/Devices/waveshare-s3-lcd-13/CMakeLists.txt +++ b/Devices/waveshare-s3-lcd-13/CMakeLists.txt @@ -1,7 +1,6 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port ST7789 CST816S PwmBacklight driver + REQUIRES TactilityKernel driver ) diff --git a/Devices/waveshare-s3-lcd-13/Source/Configuration.cpp b/Devices/waveshare-s3-lcd-13/Source/Configuration.cpp deleted file mode 100644 index 6b77798ba..000000000 --- a/Devices/waveshare-s3-lcd-13/Source/Configuration.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "devices/Display.h" - -#include -#include - -using namespace tt::hal; - -static DeviceVector createDevices() { - return { - createDisplay(), - }; -} - -static bool initBoot() { - return driver::pwmbacklight::init(GPIO_NUM_20, 256); -} - -extern const Configuration hardwareConfiguration = { - .initBoot = initBoot, - .createDevices = createDevices -}; diff --git a/Devices/waveshare-s3-lcd-13/Source/devices/Display.cpp b/Devices/waveshare-s3-lcd-13/Source/devices/Display.cpp deleted file mode 100644 index 97d92f766..000000000 --- a/Devices/waveshare-s3-lcd-13/Source/devices/Display.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "Display.h" - -#include -#include - -std::shared_ptr createDisplay() { - St7789Display::Configuration panel_configuration = { - .horizontalResolution = LCD_HORIZONTAL_RESOLUTION, - .verticalResolution = LCD_VERTICAL_RESOLUTION, - .gapX = 0, - .gapY = 0, - .swapXY = false, - .mirrorX = false, - .mirrorY = false, - .invertColor = true, - .bufferSize = LCD_BUFFER_SIZE, - .touch = nullptr, - .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty, - .resetPin = GPIO_NUM_42, - .lvglSwapBytes = false - }; - - auto spi_configuration = std::make_shared(St7789Display::SpiConfiguration { - .spiHostDevice = SPI2_HOST, - .csPin = GPIO_NUM_39, - .dcPin = GPIO_NUM_38, - .pixelClockFrequency = 62'500'000, - .transactionQueueDepth = 10 - }); - - return std::make_shared(panel_configuration, spi_configuration); -} diff --git a/Devices/waveshare-s3-lcd-13/Source/devices/Display.h b/Devices/waveshare-s3-lcd-13/Source/devices/Display.h deleted file mode 100644 index a1cd4fe6c..000000000 --- a/Devices/waveshare-s3-lcd-13/Source/devices/Display.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -std::shared_ptr createDisplay(); - -constexpr auto LCD_HORIZONTAL_RESOLUTION = 240; -constexpr auto LCD_VERTICAL_RESOLUTION = 240; -constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 3; -constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT; diff --git a/Devices/waveshare-s3-lcd-13/device.properties b/Devices/waveshare-s3-lcd-13/device.properties index ed6889941..656d0e0d4 100644 --- a/Devices/waveshare-s3-lcd-13/device.properties +++ b/Devices/waveshare-s3-lcd-13/device.properties @@ -14,6 +14,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +dependencies.useDeprecatedHal=false + storage.userDataLocation=SD display.size=1.3" diff --git a/Devices/waveshare-s3-lcd-13/devicetree.yaml b/Devices/waveshare-s3-lcd-13/devicetree.yaml index 1b96c2dd5..eea0d0d89 100644 --- a/Devices/waveshare-s3-lcd-13/devicetree.yaml +++ b/Devices/waveshare-s3-lcd-13/devicetree.yaml @@ -1,4 +1,5 @@ dependencies: - Platforms/platform-esp32 - Drivers/qmi8658-module +- Drivers/st7789-module dts: waveshare,s3-lcd-13.dts diff --git a/Devices/waveshare-s3-lcd-13/Source/module.cpp b/Devices/waveshare-s3-lcd-13/source/module.cpp similarity index 88% rename from Devices/waveshare-s3-lcd-13/Source/module.cpp rename to Devices/waveshare-s3-lcd-13/source/module.cpp index 20187b5c3..ea67b6649 100644 --- a/Devices/waveshare-s3-lcd-13/Source/module.cpp +++ b/Devices/waveshare-s3-lcd-13/source/module.cpp @@ -3,12 +3,10 @@ extern "C" { static error_t start() { - // Empty for now return ERROR_NONE; } static error_t stop() { - // Empty for now return ERROR_NONE; } diff --git a/Devices/waveshare-s3-lcd-13/waveshare,s3-lcd-13.dts b/Devices/waveshare-s3-lcd-13/waveshare,s3-lcd-13.dts index 8dcb3495a..eadabedee 100644 --- a/Devices/waveshare-s3-lcd-13/waveshare,s3-lcd-13.dts +++ b/Devices/waveshare-s3-lcd-13/waveshare,s3-lcd-13.dts @@ -8,7 +8,9 @@ #include #include #include -#include +#include +#include +#include // Reference: https://www.waveshare.com/wiki/ESP32-S3-LCD-1.3 / { @@ -43,15 +45,35 @@ }; }; + display_backlight_pwm { + compatible = "espressif,esp32-pwm-ledc"; + pin = <&gpio0 20 GPIO_FLAG_NONE>; + period-ns = <33333>; + ledc-timer = <0>; + ledc-channel = <0>; + }; + + display_backlight { + compatible = "pwm-backlight"; + pwm = <&display_backlight_pwm>; + }; + spi0 { compatible = "espressif,esp32-spi"; host = ; cs-gpios = <&gpio0 39 GPIO_FLAG_NONE>; pin-mosi = <&gpio0 41 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>; - - display { - compatible = "display-placeholder"; + + display@0 { + compatible = "sitronix,st7789"; + horizontal-resolution = <240>; + vertical-resolution = <240>; + invert-color; + pixel-clock-hz = <62500000>; + pin-dc = <&gpio0 38 GPIO_FLAG_NONE>; + pin-reset = <&gpio0 42 GPIO_FLAG_NONE>; + backlight = <&display_backlight>; }; }; diff --git a/Drivers/ILI9488/CMakeLists.txt b/Drivers/ILI9488/CMakeLists.txt deleted file mode 100644 index 6fc0164fe..000000000 --- a/Drivers/ILI9488/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -idf_component_register( - SRC_DIRS "Source" - INCLUDE_DIRS "Source" - REQUIRES Tactility EspLcdCompat esp_lcd_ili9488 driver -) diff --git a/Drivers/ILI9488/README.md b/Drivers/ILI9488/README.md deleted file mode 100644 index a63475f3c..000000000 --- a/Drivers/ILI9488/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# ILI9488 - -A basic Tactility display driver for ILI9488 panels. - -**Warning:** This driver uses 3 or 18 bits per pixel in SPI mode. This requires a software pixel conversion at runtime -and comes with a big performance penalty. It lowers the rate of rendering and it also requires an extra display buffer. diff --git a/Drivers/ILI9488/Source/Ili9488Display.cpp b/Drivers/ILI9488/Source/Ili9488Display.cpp deleted file mode 100644 index 67273f338..000000000 --- a/Drivers/ILI9488/Source/Ili9488Display.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "Ili9488Display.h" - -#include - -#include -#include -#include - -constexpr auto* TAG = "ILI9488"; - -bool Ili9488Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) { - const esp_lcd_panel_io_spi_config_t panel_io_config = { - .cs_gpio_num = configuration->csPin, - .dc_gpio_num = configuration->dcPin, - .spi_mode = 0, - .pclk_hz = configuration->pixelClockFrequency, - .trans_queue_depth = configuration->transactionQueueDepth, - .on_color_trans_done = nullptr, - .user_ctx = nullptr, - .lcd_cmd_bits = 8, - .lcd_param_bits = 8, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .flags = { - .dc_high_on_cmd = 0, - .dc_low_on_data = 0, - .dc_low_on_param = 0, - .octal_mode = 0, - .quad_mode = 0, - .sio_mode = 0, - .lsb_first = 0, - .cs_high_active = 0 - } - }; - - return esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) == ESP_OK; -} - -bool Ili9488Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) { - - const esp_lcd_panel_dev_config_t panel_config = { - .reset_gpio_num = configuration->resetPin, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, - .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, - .bits_per_pixel = 18, - .flags = { - .reset_active_high = false - }, - .vendor_config = nullptr - }; - - if (esp_lcd_new_panel_ili9488(ioHandle, &panel_config, configuration->bufferSize, &panelHandle) != ESP_OK) { - LOG_E(TAG, "Failed to create panel"); - return false; - } - - if (esp_lcd_panel_reset(panelHandle) != ESP_OK) { - LOG_E(TAG, "Failed to reset panel"); - return false; - } - - if (esp_lcd_panel_init(panelHandle) != ESP_OK) { - LOG_E(TAG, "Failed to init panel"); - return false; - } - - if (esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) { - LOG_E(TAG, "Failed to swap XY "); - return false; - } - - if (esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) { - LOG_E(TAG, "Failed to set panel to mirror"); - return false; - } - - if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { - LOG_E(TAG, "Failed to set panel to invert"); - return false; - } - - if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) { - LOG_E(TAG, "Failed to turn display on"); - return false; - } - - return true; -} - - -lvgl_port_display_cfg_t Ili9488Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) { - return { - .io_handle = ioHandle, - .panel_handle = panelHandle, - .control_handle = nullptr, - .buffer_size = configuration->bufferSize, - .double_buffer = false, - .trans_size = 0, - .hres = configuration->horizontalResolution, - .vres = configuration->verticalResolution, - .monochrome = false, - .rotation = { - .swap_xy = configuration->swapXY, - .mirror_x = configuration->mirrorX, - .mirror_y = configuration->mirrorY, - }, - .color_format = LV_COLOR_FORMAT_RGB565, - .flags = { - .buff_dma = true, - .buff_spiram = false, - .sw_rotate = false, - .swap_bytes = false, - .full_refresh = false, - .direct_mode = false - } - }; -} diff --git a/Drivers/ILI9488/Source/Ili9488Display.h b/Drivers/ILI9488/Source/Ili9488Display.h deleted file mode 100644 index 438170e44..000000000 --- a/Drivers/ILI9488/Source/Ili9488Display.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include -#include -#include - -class Ili9488Display final : public EspLcdDisplay { - -public: - - class Configuration { - - public: - - Configuration( - spi_host_device_t spiHostDevice, - gpio_num_t csPin, - gpio_num_t dcPin, - unsigned int horizontalResolution, - unsigned int verticalResolution, - std::shared_ptr touch, - bool swapXY = false, - bool mirrorX = false, - bool mirrorY = false, - bool invertColor = false, - uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size - ) : spiHostDevice(spiHostDevice), - csPin(csPin), - dcPin(dcPin), - horizontalResolution(horizontalResolution), - verticalResolution(verticalResolution), - swapXY(swapXY), - mirrorX(mirrorX), - mirrorY(mirrorY), - invertColor(invertColor), - bufferSize(bufferSize), - touch(std::move(touch)) { - if (this->bufferSize == 0) { - this->bufferSize = horizontalResolution * verticalResolution / 10; - } - } - - spi_host_device_t spiHostDevice; - gpio_num_t csPin; - gpio_num_t dcPin; - gpio_num_t resetPin = GPIO_NUM_NC; - unsigned int pixelClockFrequency = 40'000'000; // Hertz - size_t transactionQueueDepth = 10; - unsigned int horizontalResolution; - unsigned int verticalResolution; - bool swapXY = false; - bool mirrorX = false; - bool mirrorY = false; - bool invertColor = false; - uint32_t bufferSize = 0; // Size in pixel count. 0 means default, which is 1/10 of the screen size - std::shared_ptr touch; - std::function _Nullable backlightDutyFunction = nullptr; - }; - -private: - - std::unique_ptr configuration; - - bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override; - - bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override; - - lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override; - -public: - - explicit Ili9488Display(std::unique_ptr inConfiguration) : - configuration(std::move(inConfiguration) - ) { - assert(configuration != nullptr); - } - - std::string getName() const override { return "ILI9488"; } - - std::string getDescription() const override { return "ILI9488 display"; } - - std::shared_ptr _Nullable getTouchDevice() override { return configuration->touch; } - - void setBacklightDuty(uint8_t backlightDuty) override { - if (configuration->backlightDutyFunction != nullptr) { - configuration->backlightDutyFunction(backlightDuty); - } - } - - bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; } -}; - -std::shared_ptr createDisplay(); diff --git a/Drivers/cst816s-module/source/cst816s.cpp b/Drivers/cst816s-module/source/cst816s.cpp index fd38472c4..b1cb713b7 100644 --- a/Drivers/cst816s-module/source/cst816s.cpp +++ b/Drivers/cst816s-module/source/cst816s.cpp @@ -105,22 +105,27 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - bool ok = true; - // esp_lcd_touch_del() only releases the touch-side resources; the panel IO handle is owned // separately and needs its own deletion. - if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete touch handle"); - ok = false; + if (internal->touch_handle != nullptr) { + if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete touch handle"); + return ERROR_RESOURCE; + } + internal->touch_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO handle"); - ok = false; + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO handle"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } free(internal); - return ok ? ERROR_NONE : ERROR_RESOURCE; + device_set_driver_data(device, nullptr); + return ERROR_NONE; } // endregion diff --git a/Drivers/ft5x06-module/CMakeLists.txt b/Drivers/ft5x06-module/CMakeLists.txt new file mode 100644 index 000000000..ba38086a2 --- /dev/null +++ b/Drivers/ft5x06-module/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20) + +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "source/*.c*") + +tactility_add_module(ft5x06-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS include/ + REQUIRES TactilityKernel platform-esp32 esp_lcd_touch_ft5x06 esp_lcd driver +) diff --git a/Drivers/ft5x06-module/LICENSE-Apache-2.0.md b/Drivers/ft5x06-module/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Drivers/ft5x06-module/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Drivers/ft5x06-module/bindings/focaltech,ft5x06.yaml b/Drivers/ft5x06-module/bindings/focaltech,ft5x06.yaml new file mode 100644 index 000000000..557f2a409 --- /dev/null +++ b/Drivers/ft5x06-module/bindings/focaltech,ft5x06.yaml @@ -0,0 +1,45 @@ +description: FocalTech FT5x06 capacitive touch controller + +include: ["i2c-device.yaml"] + +compatible: "focaltech,ft5x06" + +bus: i2c + +properties: + x-max: + type: int + required: true + description: Maximum X coordinate reported by the controller (typically the panel's horizontal resolution) + y-max: + type: int + required: true + description: Maximum Y coordinate reported by the controller (typically the panel's vertical resolution) + swap-xy: + type: boolean + default: false + description: Swap the X and Y axes + mirror-x: + type: boolean + default: false + description: Mirror the X axis + mirror-y: + type: boolean + default: false + description: Mirror the Y axis + pin-reset: + type: phandles + default: GPIO_PIN_SPEC_NONE + description: Reset GPIO pin + pin-interrupt: + type: phandles + default: GPIO_PIN_SPEC_NONE + description: Interrupt GPIO pin + reset-active-high: + type: boolean + default: false + description: Whether the reset pin is active high + interrupt-active-high: + type: boolean + default: false + description: Whether the interrupt pin is active high diff --git a/Drivers/ft5x06-module/devicetree.yaml b/Drivers/ft5x06-module/devicetree.yaml new file mode 100644 index 000000000..a07d6f334 --- /dev/null +++ b/Drivers/ft5x06-module/devicetree.yaml @@ -0,0 +1,3 @@ +dependencies: + - TactilityKernel +bindings: bindings diff --git a/Drivers/ft5x06-module/include/bindings/ft5x06.h b/Drivers/ft5x06-module/include/bindings/ft5x06.h new file mode 100644 index 000000000..abd371269 --- /dev/null +++ b/Drivers/ft5x06-module/include/bindings/ft5x06.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(ft5x06, struct Ft5x06Config) diff --git a/Drivers/ft5x06-module/include/drivers/ft5x06.h b/Drivers/ft5x06-module/include/drivers/ft5x06.h new file mode 100644 index 000000000..7a7aba57f --- /dev/null +++ b/Drivers/ft5x06-module/include/drivers/ft5x06.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +struct Ft5x06Config { + // Devicetree address hint. Unused by the driver: the FT5x06 always sits at a fixed + // I2C address (0x38, see ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS). + uint8_t address; + uint16_t x_max; + uint16_t y_max; + bool swap_xy; + bool mirror_x; + bool mirror_y; + struct GpioPinSpec pin_reset; + struct GpioPinSpec pin_interrupt; + bool reset_active_high; + bool interrupt_active_high; +}; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/pointer_placeholder.h b/Drivers/ft5x06-module/include/ft5x06_module.h similarity index 61% rename from TactilityKernel/include/tactility/drivers/pointer_placeholder.h rename to Drivers/ft5x06-module/include/ft5x06_module.h index e8b1553a5..cd0d4621a 100644 --- a/TactilityKernel/include/tactility/drivers/pointer_placeholder.h +++ b/Drivers/ft5x06-module/include/ft5x06_module.h @@ -1,15 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#include +#include #ifdef __cplusplus extern "C" { #endif -struct PointerPlaceholderConfig { - uint8_t _unused; -}; +extern struct Module ft5x06_module; #ifdef __cplusplus } diff --git a/Drivers/ft5x06-module/source/ft5x06.cpp b/Drivers/ft5x06-module/source/ft5x06.cpp new file mode 100644 index 000000000..72141596f --- /dev/null +++ b/Drivers/ft5x06-module/source/ft5x06.cpp @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define TAG "FT5x06" +#define GET_CONFIG(device) (static_cast((device)->config)) + +struct Ft5x06Internal { + esp_lcd_panel_io_handle_t io_handle; + esp_lcd_touch_handle_t touch_handle; +}; + +static inline gpio_num_t pin_or_nc(const struct GpioPinSpec& pin) { + return pin.gpio_controller == nullptr ? GPIO_NUM_NC : static_cast(pin.pin); +} + +// region Driver lifecycle + +// FT5x06 always sits at a fixed I2C address, unlike GT911's strapping-dependent address, +// so no bus probing is needed here. +static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out_handle) { + esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG(); + + auto* parent_driver = device_get_driver(parent); + if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) { + auto port = static_cast(parent->config)->port; + return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle); + } + if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) { + auto bus = esp32_i2c_master_get_bus_handle(parent); + io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent); + return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle); + } + + LOG_E(TAG, "Unsupported I2C driver"); + return ESP_ERR_NOT_SUPPORTED; +} + +static error_t start(Device* device) { + auto* parent = device_get_parent(device); + check(device_get_type(parent) == &I2C_CONTROLLER_TYPE); + + const auto* config = GET_CONFIG(device); + + auto* internal = static_cast(malloc(sizeof(Ft5x06Internal))); + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + + esp_err_t ret = create_io_handle(parent, &internal->io_handle); + if (ret != ESP_OK) { + free(internal); + return ERROR_RESOURCE; + } + + esp_lcd_touch_config_t touch_config = { + .x_max = config->x_max, + .y_max = config->y_max, + .rst_gpio_num = pin_or_nc(config->pin_reset), + .int_gpio_num = pin_or_nc(config->pin_interrupt), + .levels = { + .reset = config->reset_active_high ? 1u : 0u, + .interrupt = config->interrupt_active_high ? 1u : 0u, + }, + .flags = { + .swap_xy = config->swap_xy ? 1u : 0u, + .mirror_x = config->mirror_x ? 1u : 0u, + .mirror_y = config->mirror_y ? 1u : 0u, + }, + .process_coordinates = nullptr, + .interrupt_callback = nullptr, + .user_data = nullptr, + .driver_data = nullptr, + }; + + ret = esp_lcd_touch_new_i2c_ft5x06(internal->io_handle, &touch_config, &internal->touch_handle); + if (ret != ESP_OK) { + LOG_E(TAG, "Failed to create touch handle: %s", esp_err_to_name(ret)); + esp_lcd_panel_io_del(internal->io_handle); + free(internal); + return ERROR_RESOURCE; + } + + device_set_driver_data(device, internal); + return ERROR_NONE; +} + +static error_t stop(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + + // esp_lcd_touch_del() only releases the touch-side resources; the panel IO handle is owned + // separately and needs its own deletion. + if (internal->touch_handle != nullptr) { + if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete touch handle"); + return ERROR_RESOURCE; + } + internal->touch_handle = nullptr; + } + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO handle"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; + } + + free(internal); + device_set_driver_data(device, nullptr); + return ERROR_NONE; +} + +// endregion + +// region PointerApi + +static error_t ft5x06_enter_sleep(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_enter_sleep(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_exit_sleep(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_exit_sleep(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_read_data(Device* device, TickType_t timeout) { + (void)timeout; // esp_lcd_touch_read_data() has no timeout parameter + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_read_data(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static bool ft5x06_get_touched_points(Device* device, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_coordinates(internal->touch_handle, x, y, strength, point_count, max_point_count); +} + +static error_t ft5x06_set_swap_xy(Device* device, bool swap) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_swap_xy(internal->touch_handle, swap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_get_swap_xy(Device* device, bool* swap) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_swap_xy(internal->touch_handle, swap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_set_mirror_x(Device* device, bool mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_mirror_x(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_get_mirror_x(Device* device, bool* mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_mirror_x(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_set_mirror_y(Device* device, bool mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_mirror_y(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft5x06_get_mirror_y(Device* device, bool* mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_mirror_y(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +// endregion + +static const PointerApi ft5x06_pointer_api = { + .enter_sleep = ft5x06_enter_sleep, + .exit_sleep = ft5x06_exit_sleep, + .read_data = ft5x06_read_data, + .get_touched_points = ft5x06_get_touched_points, + .set_swap_xy = ft5x06_set_swap_xy, + .get_swap_xy = ft5x06_get_swap_xy, + .set_mirror_x = ft5x06_set_mirror_x, + .get_mirror_x = ft5x06_get_mirror_x, + .set_mirror_y = ft5x06_set_mirror_y, + .get_mirror_y = ft5x06_get_mirror_y, +}; + +Driver ft5x06_driver = { + .name = "ft5x06", + .compatible = (const char*[]) { "focaltech,ft5x06", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &ft5x06_pointer_api, + .device_type = &POINTER_TYPE, + .owner = &ft5x06_module, + .internal = nullptr +}; diff --git a/Drivers/ft5x06-module/source/module.cpp b/Drivers/ft5x06-module/source/module.cpp new file mode 100644 index 000000000..2f0928c84 --- /dev/null +++ b/Drivers/ft5x06-module/source/module.cpp @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include + +extern "C" { + +extern Driver ft5x06_driver; + +static error_t start() { + /* We crash when construct fails, because if a single driver fails to construct, + * there is no guarantee that the previously constructed drivers can be destroyed */ + check(driver_construct_add(&ft5x06_driver) == ERROR_NONE); + return ERROR_NONE; +} + +static error_t stop() { + /* We crash when destruct fails, because if a single driver fails to destruct, + * there is no guarantee that the previously destroyed drivers can be recovered */ + check(driver_remove_destruct(&ft5x06_driver) == ERROR_NONE); + return ERROR_NONE; +} + +Module ft5x06_module = { + .name = "ft5x06", + .start = start, + .stop = stop, + .symbols = nullptr, + .internal = nullptr +}; + +} // extern "C" diff --git a/Drivers/ft6x36-module/CMakeLists.txt b/Drivers/ft6x36-module/CMakeLists.txt new file mode 100644 index 000000000..cc41b229e --- /dev/null +++ b/Drivers/ft6x36-module/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20) + +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "source/*.c*") + +tactility_add_module(ft6x36-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS include/ + REQUIRES TactilityKernel platform-esp32 esp_lcd_touch_ft6336u esp_lcd driver +) diff --git a/Drivers/ft6x36-module/LICENSE-Apache-2.0.md b/Drivers/ft6x36-module/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Drivers/ft6x36-module/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Drivers/ft6x36-module/bindings/focaltech,ft6x36.yaml b/Drivers/ft6x36-module/bindings/focaltech,ft6x36.yaml new file mode 100644 index 000000000..cede0fbde --- /dev/null +++ b/Drivers/ft6x36-module/bindings/focaltech,ft6x36.yaml @@ -0,0 +1,45 @@ +description: FocalTech FT6x36 capacitive touch controller + +include: ["i2c-device.yaml"] + +compatible: "focaltech,ft6x36" + +bus: i2c + +properties: + x-max: + type: int + required: true + description: Maximum X coordinate reported by the controller (typically the panel's horizontal resolution) + y-max: + type: int + required: true + description: Maximum Y coordinate reported by the controller (typically the panel's vertical resolution) + swap-xy: + type: boolean + default: false + description: Swap the X and Y axes + mirror-x: + type: boolean + default: false + description: Mirror the X axis + mirror-y: + type: boolean + default: false + description: Mirror the Y axis + pin-reset: + type: phandles + default: GPIO_PIN_SPEC_NONE + description: Reset GPIO pin + pin-interrupt: + type: phandles + default: GPIO_PIN_SPEC_NONE + description: Interrupt GPIO pin + reset-active-high: + type: boolean + default: false + description: Whether the reset pin is active high + interrupt-active-high: + type: boolean + default: false + description: Whether the interrupt pin is active high diff --git a/Drivers/ft6x36-module/devicetree.yaml b/Drivers/ft6x36-module/devicetree.yaml new file mode 100644 index 000000000..a07d6f334 --- /dev/null +++ b/Drivers/ft6x36-module/devicetree.yaml @@ -0,0 +1,3 @@ +dependencies: + - TactilityKernel +bindings: bindings diff --git a/Drivers/ft6x36-module/include/bindings/ft6x36.h b/Drivers/ft6x36-module/include/bindings/ft6x36.h new file mode 100644 index 000000000..ba79f3f5a --- /dev/null +++ b/Drivers/ft6x36-module/include/bindings/ft6x36.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(ft6x36, struct Ft6x36Config) diff --git a/Drivers/ft6x36-module/include/drivers/ft6x36.h b/Drivers/ft6x36-module/include/drivers/ft6x36.h new file mode 100644 index 000000000..abedfa230 --- /dev/null +++ b/Drivers/ft6x36-module/include/drivers/ft6x36.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +struct Ft6x36Config { + // Devicetree address hint. Unused by the driver: the FT6x36 always sits at a fixed + // I2C address (0x38, see ESP_LCD_TOUCH_IO_I2C_FT6x36_ADDRESS). + uint8_t address; + uint16_t x_max; + uint16_t y_max; + bool swap_xy; + bool mirror_x; + bool mirror_y; + struct GpioPinSpec pin_reset; + struct GpioPinSpec pin_interrupt; + bool reset_active_high; + bool interrupt_active_high; +}; + +#ifdef __cplusplus +} +#endif diff --git a/Drivers/ft6x36-module/include/ft6x36_module.h b/Drivers/ft6x36-module/include/ft6x36_module.h new file mode 100644 index 000000000..50c54e21f --- /dev/null +++ b/Drivers/ft6x36-module/include/ft6x36_module.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Module ft6x36_module; + +#ifdef __cplusplus +} +#endif diff --git a/Drivers/ft6x36-module/source/ft6x36.cpp b/Drivers/ft6x36-module/source/ft6x36.cpp new file mode 100644 index 000000000..ab998e2f7 --- /dev/null +++ b/Drivers/ft6x36-module/source/ft6x36.cpp @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define TAG "FT6x36" +#define GET_CONFIG(device) (static_cast((device)->config)) + +struct Ft6x36Internal { + esp_lcd_panel_io_handle_t io_handle; + esp_lcd_touch_handle_t touch_handle; +}; + +static inline gpio_num_t pin_or_nc(const struct GpioPinSpec& pin) { + return pin.gpio_controller == nullptr ? GPIO_NUM_NC : static_cast(pin.pin); +} + +// region Driver lifecycle + +// FT6x36 always sits at a fixed I2C address, unlike GT911's strapping-dependent address, +// so no bus probing is needed here. +static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out_handle) { + esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT6x36_CONFIG(); + + auto* parent_driver = device_get_driver(parent); + if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) { + auto port = static_cast(parent->config)->port; + return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle); + } + if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) { + auto bus = esp32_i2c_master_get_bus_handle(parent); + io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent); + return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle); + } + + LOG_E(TAG, "Unsupported I2C driver"); + return ESP_ERR_NOT_SUPPORTED; +} + +static error_t start(Device* device) { + auto* parent = device_get_parent(device); + check(device_get_type(parent) == &I2C_CONTROLLER_TYPE); + + const auto* config = GET_CONFIG(device); + + auto* internal = static_cast(malloc(sizeof(Ft6x36Internal))); + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + + esp_err_t ret = create_io_handle(parent, &internal->io_handle); + if (ret != ESP_OK) { + free(internal); + return ERROR_RESOURCE; + } + + esp_lcd_touch_config_t touch_config = { + .x_max = config->x_max, + .y_max = config->y_max, + .rst_gpio_num = pin_or_nc(config->pin_reset), + .int_gpio_num = pin_or_nc(config->pin_interrupt), + .levels = { + .reset = config->reset_active_high ? 1u : 0u, + .interrupt = config->interrupt_active_high ? 1u : 0u, + }, + .flags = { + .swap_xy = config->swap_xy ? 1u : 0u, + .mirror_x = config->mirror_x ? 1u : 0u, + .mirror_y = config->mirror_y ? 1u : 0u, + }, + .process_coordinates = nullptr, + .interrupt_callback = nullptr, + .user_data = nullptr, + .driver_data = nullptr, + }; + + ret = esp_lcd_touch_new_i2c_ft6x36(internal->io_handle, &touch_config, &internal->touch_handle); + if (ret != ESP_OK) { + LOG_E(TAG, "Failed to create touch handle: %s", esp_err_to_name(ret)); + esp_lcd_panel_io_del(internal->io_handle); + free(internal); + return ERROR_RESOURCE; + } + + device_set_driver_data(device, internal); + return ERROR_NONE; +} + +static error_t stop(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + + // esp_lcd_touch_del() only releases the touch-side resources; the panel IO handle is owned + // separately and needs its own deletion. + if (internal->touch_handle != nullptr) { + if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete touch handle"); + return ERROR_RESOURCE; + } + internal->touch_handle = nullptr; + } + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO handle"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; + } + + free(internal); + device_set_driver_data(device, nullptr); + return ERROR_NONE; +} + +// endregion + +// region PointerApi + +static error_t ft6x36_enter_sleep(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_enter_sleep(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_exit_sleep(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_exit_sleep(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_read_data(Device* device, TickType_t timeout) { + (void)timeout; // esp_lcd_touch_read_data() has no timeout parameter + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_read_data(internal->touch_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static bool ft6x36_get_touched_points(Device* device, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_coordinates(internal->touch_handle, x, y, strength, point_count, max_point_count); +} + +static error_t ft6x36_set_swap_xy(Device* device, bool swap) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_swap_xy(internal->touch_handle, swap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_get_swap_xy(Device* device, bool* swap) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_swap_xy(internal->touch_handle, swap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_set_mirror_x(Device* device, bool mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_mirror_x(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_get_mirror_x(Device* device, bool* mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_mirror_x(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_set_mirror_y(Device* device, bool mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_set_mirror_y(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t ft6x36_get_mirror_y(Device* device, bool* mirror) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_touch_get_mirror_y(internal->touch_handle, mirror) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +// endregion + +static const PointerApi ft6x36_pointer_api = { + .enter_sleep = ft6x36_enter_sleep, + .exit_sleep = ft6x36_exit_sleep, + .read_data = ft6x36_read_data, + .get_touched_points = ft6x36_get_touched_points, + .set_swap_xy = ft6x36_set_swap_xy, + .get_swap_xy = ft6x36_get_swap_xy, + .set_mirror_x = ft6x36_set_mirror_x, + .get_mirror_x = ft6x36_get_mirror_x, + .set_mirror_y = ft6x36_set_mirror_y, + .get_mirror_y = ft6x36_get_mirror_y, +}; + +Driver ft6x36_driver = { + .name = "ft6x36", + .compatible = (const char*[]) { "focaltech,ft6x36", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &ft6x36_pointer_api, + .device_type = &POINTER_TYPE, + .owner = &ft6x36_module, + .internal = nullptr +}; diff --git a/Drivers/ft6x36-module/source/module.cpp b/Drivers/ft6x36-module/source/module.cpp new file mode 100644 index 000000000..1d9aaa2d0 --- /dev/null +++ b/Drivers/ft6x36-module/source/module.cpp @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include + +extern "C" { + +extern Driver ft6x36_driver; + +static error_t start() { + /* We crash when construct fails, because if a single driver fails to construct, + * there is no guarantee that the previously constructed drivers can be destroyed */ + check(driver_construct_add(&ft6x36_driver) == ERROR_NONE); + return ERROR_NONE; +} + +static error_t stop() { + /* We crash when destruct fails, because if a single driver fails to destruct, + * there is no guarantee that the previously destroyed drivers can be recovered */ + check(driver_remove_destruct(&ft6x36_driver) == ERROR_NONE); + return ERROR_NONE; +} + +Module ft6x36_module = { + .name = "ft6x36", + .start = start, + .stop = stop, + .symbols = nullptr, + .internal = nullptr +}; + +} // extern "C" diff --git a/Drivers/gt911-module/source/gt911.cpp b/Drivers/gt911-module/source/gt911.cpp index 93e2d9db3..b340439fe 100644 --- a/Drivers/gt911-module/source/gt911.cpp +++ b/Drivers/gt911-module/source/gt911.cpp @@ -114,22 +114,27 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - bool ok = true; - // esp_lcd_touch_del() only releases the touch-side resources; the panel IO handle is owned // separately and needs its own deletion. - if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete touch handle"); - ok = false; + if (internal->touch_handle != nullptr) { + if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete touch handle"); + return ERROR_RESOURCE; + } + internal->touch_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO handle"); - ok = false; + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO handle"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } free(internal); - return ok ? ERROR_NONE : ERROR_RESOURCE; + device_set_driver_data(device, nullptr); + return ERROR_NONE; } // endregion diff --git a/Drivers/ili9341-module/source/ili9341.cpp b/Drivers/ili9341-module/source/ili9341.cpp index 8f7caaa3f..70818577d 100644 --- a/Drivers/ili9341-module/source/ili9341.cpp +++ b/Drivers/ili9341-module/source/ili9341.cpp @@ -165,20 +165,26 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - error_t result = ERROR_NONE; - - if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel"); - result = ERROR_RESOURCE; + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO"); - result = ERROR_RESOURCE; + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } vSemaphoreDelete(internal->draw_done_semaphore); free(internal); - return result; + device_set_driver_data(device, nullptr); + return ERROR_NONE; } // endregion diff --git a/Drivers/ili9488-module/source/ili9488.cpp b/Drivers/ili9488-module/source/ili9488.cpp index 96cc1deca..0a4ba4bea 100644 --- a/Drivers/ili9488-module/source/ili9488.cpp +++ b/Drivers/ili9488-module/source/ili9488.cpp @@ -161,17 +161,25 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel"); - return ERROR_RESOURCE; + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO"); - return ERROR_RESOURCE; + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } vSemaphoreDelete(internal->draw_done_semaphore); free(internal); + device_set_driver_data(device, nullptr); return ERROR_NONE; } diff --git a/Drivers/rgb-display-module/source/rgb_display.cpp b/Drivers/rgb-display-module/source/rgb_display.cpp index 631877b3e..b3c088d88 100644 --- a/Drivers/rgb-display-module/source/rgb_display.cpp +++ b/Drivers/rgb-display-module/source/rgb_display.cpp @@ -256,15 +256,17 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel"); - vSemaphoreDelete(internal->frame_complete_semaphore); - free(internal); - return ERROR_RESOURCE; + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; } vSemaphoreDelete(internal->frame_complete_semaphore); free(internal); + device_set_driver_data(device, nullptr); return ERROR_NONE; } diff --git a/Drivers/st7789-i8080-module/source/st7789_i8080.cpp b/Drivers/st7789-i8080-module/source/st7789_i8080.cpp index 38c121f00..a405cbd27 100644 --- a/Drivers/st7789-i8080-module/source/st7789_i8080.cpp +++ b/Drivers/st7789-i8080-module/source/st7789_i8080.cpp @@ -204,20 +204,26 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - error_t result = ERROR_NONE; - - if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel"); - result = ERROR_RESOURCE; + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO"); - result = ERROR_RESOURCE; + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } vSemaphoreDelete(internal->draw_done_semaphore); free(internal); - return result; + device_set_driver_data(device, nullptr); + return ERROR_NONE; } // endregion diff --git a/Drivers/st7789-module/source/st7789.cpp b/Drivers/st7789-module/source/st7789.cpp index 2c0906422..1f58369ff 100644 --- a/Drivers/st7789-module/source/st7789.cpp +++ b/Drivers/st7789-module/source/st7789.cpp @@ -165,17 +165,25 @@ static error_t start(Device* device) { static error_t stop(Device* device) { auto* internal = static_cast(device_get_driver_data(device)); - if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel"); - return ERROR_RESOURCE; + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO"); - return ERROR_RESOURCE; + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } vSemaphoreDelete(internal->draw_done_semaphore); free(internal); + device_set_driver_data(device, nullptr); return ERROR_NONE; } diff --git a/Drivers/st7796-module/CMakeLists.txt b/Drivers/st7796-module/CMakeLists.txt new file mode 100644 index 000000000..7f0c24a4c --- /dev/null +++ b/Drivers/st7796-module/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20) + +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "source/*.c*") + +tactility_add_module(st7796-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS include/ + REQUIRES TactilityKernel platform-esp32 esp_lcd_st7796 driver +) diff --git a/Drivers/st7796-module/LICENSE-Apache-2.0.md b/Drivers/st7796-module/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Drivers/st7796-module/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Drivers/st7796-module/bindings/sitronix,st7796.yaml b/Drivers/st7796-module/bindings/sitronix,st7796.yaml new file mode 100644 index 000000000..ac9000f74 --- /dev/null +++ b/Drivers/st7796-module/bindings/sitronix,st7796.yaml @@ -0,0 +1,77 @@ +description: Sitronix ST7796 display panel + +compatible: "sitronix,st7796" + +bus: spi + +properties: + horizontal-resolution: + type: int + required: true + description: Horizontal resolution in pixels + vertical-resolution: + type: int + required: true + description: Vertical resolution in pixels + gap-x: + type: int + default: 0 + description: X offset applied to all draw operations + gap-y: + type: int + default: 0 + description: Y offset applied to all draw operations + swap-xy: + type: boolean + default: false + description: Swap the X and Y axes + mirror-x: + type: boolean + default: false + description: Mirror the X axis + mirror-y: + type: boolean + default: false + description: Mirror the Y axis + invert-color: + type: boolean + default: false + description: Invert the panel's color output + bgr-order: + type: boolean + default: false + description: Use BGR element order instead of RGB + bits-per-pixel: + type: int + default: 16 + description: Color depth in bits per pixel + pixel-clock-hz: + type: int + default: 40000000 + description: SPI pixel clock frequency in Hz + transaction-queue-depth: + type: int + default: 10 + description: Size of the internal SPI transaction queue + gamma-curve: + type: int + default: 1 + min: 0 + max: 3 + description: Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up + pin-dc: + type: phandles + required: true + description: Data/Command GPIO pin + pin-reset: + type: phandles + default: GPIO_PIN_SPEC_NONE + description: Reset GPIO pin + reset-active-high: + type: boolean + default: false + description: Whether the reset pin is active high + backlight: + type: phandle + default: "NULL" + description: Optional reference to this display's backlight device diff --git a/Drivers/st7796-module/devicetree.yaml b/Drivers/st7796-module/devicetree.yaml new file mode 100644 index 000000000..a07d6f334 --- /dev/null +++ b/Drivers/st7796-module/devicetree.yaml @@ -0,0 +1,3 @@ +dependencies: + - TactilityKernel +bindings: bindings diff --git a/Drivers/st7796-module/include/bindings/st7796.h b/Drivers/st7796-module/include/bindings/st7796.h new file mode 100644 index 000000000..110214a56 --- /dev/null +++ b/Drivers/st7796-module/include/bindings/st7796.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(st7796, struct St7796Config) diff --git a/Drivers/st7796-module/include/drivers/st7796.h b/Drivers/st7796-module/include/drivers/st7796.h new file mode 100644 index 000000000..2e4a5e7da --- /dev/null +++ b/Drivers/st7796-module/include/drivers/st7796.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +struct St7796Config { + uint16_t horizontal_resolution; + uint16_t vertical_resolution; + int32_t gap_x; + int32_t gap_y; + bool swap_xy; + bool mirror_x; + bool mirror_y; + bool invert_color; + bool bgr_order; + uint32_t bits_per_pixel; + uint32_t pixel_clock_hz; + uint8_t transaction_queue_depth; + // Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up. + uint8_t gamma_curve; + struct GpioPinSpec pin_dc; + struct GpioPinSpec pin_reset; + bool reset_active_high; + // Optional reference to this display's backlight device, NULL if none. + struct Device* backlight; +}; + +#ifdef __cplusplus +} +#endif diff --git a/Drivers/st7796-module/include/st7796_module.h b/Drivers/st7796-module/include/st7796_module.h new file mode 100644 index 000000000..d38ae77c2 --- /dev/null +++ b/Drivers/st7796-module/include/st7796_module.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Module st7796_module; + +#ifdef __cplusplus +} +#endif diff --git a/Drivers/st7796-module/source/module.cpp b/Drivers/st7796-module/source/module.cpp new file mode 100644 index 000000000..271218a49 --- /dev/null +++ b/Drivers/st7796-module/source/module.cpp @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include + +extern "C" { + +extern Driver st7796_driver; + +static error_t start() { + /* We crash when construct fails, because if a single driver fails to construct, + * there is no guarantee that the previously constructed drivers can be destroyed */ + check(driver_construct_add(&st7796_driver) == ERROR_NONE); + return ERROR_NONE; +} + +static error_t stop() { + /* We crash when destruct fails, because if a single driver fails to destruct, + * there is no guarantee that the previously destroyed drivers can be recovered */ + check(driver_remove_destruct(&st7796_driver) == ERROR_NONE); + return ERROR_NONE; +} + +Module st7796_module = { + .name = "st7796", + .start = start, + .stop = stop, + .symbols = nullptr, + .internal = nullptr +}; + +} // extern "C" diff --git a/Drivers/st7796-module/source/st7796.cpp b/Drivers/st7796-module/source/st7796.cpp new file mode 100644 index 000000000..9ea85c414 --- /dev/null +++ b/Drivers/st7796-module/source/st7796.cpp @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define TAG "ST7796" + +#define GET_CONFIG(device) (static_cast((device)->config)) + +// Maps gamma-curve devicetree index [0,3] to the MIPI DCS GAMSET (0x26) parameter value. Mirrors +// the deprecated HAL's St7796Display::setGammaCurve() (Drivers/ST7796) - note the non-linear +// mapping, not index+1. +static const uint8_t GAMMA_CURVE_VALUES[4] = { 0x01, 0x04, 0x02, 0x08 }; + +struct St7796Internal { + esp_lcd_panel_io_handle_t io_handle; + esp_lcd_panel_handle_t panel_handle; + // Given from ISR context by on_color_trans_done() once a queued SPI transfer physically + // completes. draw_bitmap() blocks on this so it can honor DisplayApi's synchronous contract + // (see lvgl_display.c: the caller reuses/overwrites the color buffer as soon as draw_bitmap + // returns) - esp_lcd_panel_draw_bitmap() itself only queues the transfer and returns early. + SemaphoreHandle_t draw_done_semaphore; +}; + +// Fires for every completed SPI transaction on this IO (not just draw_bitmap's color transfers - +// bring-up commands like reset/init/gap go through the same IO), called from ISR context. +static bool IRAM_ATTR on_color_trans_done(esp_lcd_panel_io_handle_t, esp_lcd_panel_io_event_data_t*, void* user_ctx) { + auto* internal = static_cast(user_ctx); + BaseType_t high_task_woken = pdFALSE; + xSemaphoreGiveFromISR(internal->draw_done_semaphore, &high_task_woken); + return high_task_woken == pdTRUE; +} + +static int pin_or_unused(const struct GpioPinSpec& pin) { + return pin.gpio_controller == nullptr ? -1 : static_cast(pin.pin); +} + +// region Driver lifecycle + +static error_t start(Device* device) { + auto* parent = device_get_parent(device); + check(device_get_type(parent) == &SPI_CONTROLLER_TYPE); + + const auto* spi_config = static_cast(parent->config); + const auto* config = GET_CONFIG(device); + + struct GpioPinSpec cs_pin; + if (esp32_spi_get_cs_pin(device, &cs_pin) != ERROR_NONE) { + LOG_E(TAG, "Failed to resolve CS pin"); + return ERROR_RESOURCE; + } + + auto* internal = static_cast(malloc(sizeof(St7796Internal))); + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + + internal->draw_done_semaphore = xSemaphoreCreateBinary(); + if (internal->draw_done_semaphore == nullptr) { + free(internal); + return ERROR_OUT_OF_MEMORY; + } + + esp_lcd_panel_io_spi_config_t io_config = { + .cs_gpio_num = pin_or_unused(cs_pin), + .dc_gpio_num = pin_or_unused(config->pin_dc), + .spi_mode = 0, + .pclk_hz = config->pixel_clock_hz, + .trans_queue_depth = config->transaction_queue_depth, + .on_color_trans_done = on_color_trans_done, + .user_ctx = internal, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .flags = { + .dc_high_on_cmd = 0, + .dc_low_on_data = 0, + .dc_low_on_param = 0, + .octal_mode = 0, + .quad_mode = 0, + .sio_mode = 1, + .lsb_first = 0, + .cs_high_active = 0, + }, + }; + + esp_err_t ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spi_config->host, &io_config, &internal->io_handle); + if (ret != ESP_OK) { + LOG_E(TAG, "Failed to create panel IO: %s", esp_err_to_name(ret)); + vSemaphoreDelete(internal->draw_done_semaphore); + free(internal); + return ERROR_RESOURCE; + } + + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = pin_or_unused(config->pin_reset), + .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = config->bits_per_pixel, + .flags = { .reset_active_high = config->reset_active_high }, + .vendor_config = nullptr, + }; + + ret = esp_lcd_new_panel_st7796(internal->io_handle, &panel_config, &internal->panel_handle); + if (ret != ESP_OK) { + LOG_E(TAG, "Failed to create panel: %s", esp_err_to_name(ret)); + esp_lcd_panel_io_del(internal->io_handle); + vSemaphoreDelete(internal->draw_done_semaphore); + free(internal); + return ERROR_RESOURCE; + } + + // Bring-up sequence, order matches EspLcdDisplayV2::applyConfiguration (proven correct on real ST7796 panels). + // Every failure path below must clean up fully: unlike stop_device, this is never retried by the kernel + // if start_device fails (see device_start() in TactilityKernel), so a partial failure here would leak. + bool ok = + esp_lcd_panel_reset(internal->panel_handle) == ESP_OK && + esp_lcd_panel_init(internal->panel_handle) == ESP_OK && + (!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK); + + if (ok) { + int gap_x = config->swap_xy ? config->gap_y : config->gap_x; + int gap_y = config->swap_xy ? config->gap_x : config->gap_y; + ok = (gap_x == 0 && gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, gap_x, gap_y) == ESP_OK; + } + ok = ok && (!config->swap_xy || esp_lcd_panel_swap_xy(internal->panel_handle, true) == ESP_OK); + ok = ok && ((!config->mirror_x && !config->mirror_y) || esp_lcd_panel_mirror(internal->panel_handle, config->mirror_x, config->mirror_y) == ESP_OK); + ok = ok && (!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK); + ok = ok && (config->gamma_curve >= 4 || esp_lcd_panel_io_tx_param(internal->io_handle, LCD_CMD_GAMSET, &GAMMA_CURVE_VALUES[config->gamma_curve], 1) == ESP_OK); + ok = ok && esp_lcd_panel_disp_on_off(internal->panel_handle, true) == ESP_OK; + + if (!ok) { + LOG_E(TAG, "Failed to bring up panel"); + esp_lcd_panel_del(internal->panel_handle); + esp_lcd_panel_io_del(internal->io_handle); + vSemaphoreDelete(internal->draw_done_semaphore); + free(internal); + return ERROR_RESOURCE; + } + + device_set_driver_data(device, internal); + return ERROR_NONE; +} + +static error_t stop(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + + if (internal->panel_handle != nullptr) { + if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel"); + return ERROR_RESOURCE; + } + internal->panel_handle = nullptr; + } + + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; + } + + vSemaphoreDelete(internal->draw_done_semaphore); + free(internal); + device_set_driver_data(device, nullptr); + return ERROR_NONE; +} + +// endregion + +// region DisplayApi + +static error_t st7796_reset(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_reset(internal->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_init(Device* device) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_init(internal->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_draw_bitmap(Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) { + auto* internal = static_cast(device_get_driver_data(device)); + + // Drain any stale signal left over from a prior non-draw transaction (bring-up commands like + // reset/gap also complete through on_color_trans_done), so the take() below can only be + // satisfied by this draw's own transfer completing. + xSemaphoreTake(internal->draw_done_semaphore, 0); + + if (esp_lcd_panel_draw_bitmap(internal->panel_handle, x_start, y_start, x_end, y_end, color_data) != ESP_OK) { + return ERROR_RESOURCE; + } + + // Block until the SPI transfer physically completes: DisplayApi's draw_bitmap is a synchronous + // contract (see lvgl_display.c), so the caller must be able to safely reuse/overwrite + // color_data as soon as this call returns. esp_lcd_panel_draw_bitmap() only queues the + // transfer and returns once it's handed to the SPI peripheral, not once it's finished. + xSemaphoreTake(internal->draw_done_semaphore, portMAX_DELAY); + return ERROR_NONE; +} + +static error_t st7796_mirror(Device* device, bool x_axis, bool y_axis) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_mirror(internal->panel_handle, x_axis, y_axis) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_swap_xy(Device* device, bool swap_axes) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_swap_xy(internal->panel_handle, swap_axes) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +// Reads the devicetree-configured baseline, not live hardware state: swap_xy()/mirror() calls made after +// start_device() (e.g. by an LVGL rotation binding) intentionally don't change what "rotation 0" means here. +static bool st7796_get_swap_xy(Device* device) { + return GET_CONFIG(device)->swap_xy; +} + +static bool st7796_get_mirror_x(Device* device) { + return GET_CONFIG(device)->mirror_x; +} + +static bool st7796_get_mirror_y(Device* device) { + return GET_CONFIG(device)->mirror_y; +} + +static error_t st7796_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_set_gap(internal->panel_handle, x_gap, y_gap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_invert_color(Device* device, bool invert_color_data) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_invert_color(internal->panel_handle, invert_color_data) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_disp_on_off(Device* device, bool on_off) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_disp_on_off(internal->panel_handle, on_off) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +static error_t st7796_disp_sleep(Device* device, bool sleep) { + auto* internal = static_cast(device_get_driver_data(device)); + return esp_lcd_panel_disp_sleep(internal->panel_handle, sleep) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; +} + +// bgr_order only selects the panel controller's rgb_ele_order (applied in start(), above) so the +// R/B swap happens in hardware over SPI. LVGL always fills RGB565 buffers either way - it has no +// BGR565 format (lvgl_display.c rejects it, "no LVGL equivalent"), and none is needed here. +// +// _SWAPPED (not plain RGB565): the panel expects each 16-bit pixel high-byte-first over SPI, but +// this CPU is little-endian, so a plain RGB565 buffer arrives byte-swapped per pixel. The old +// deprecated-HAL driver had the same requirement (its equivalent knob was esp_lvgl_port's +// `swap_bytes = true` in Devices/cyd-3248s035c/Source/devices/Display.cpp). +static enum DisplayColorFormat st7796_get_color_format(Device*) { + return DISPLAY_COLOR_FORMAT_RGB565_SWAPPED; +} + +static uint16_t st7796_get_resolution_x(Device* device) { + return GET_CONFIG(device)->horizontal_resolution; +} + +static uint16_t st7796_get_resolution_y(Device* device) { + return GET_CONFIG(device)->vertical_resolution; +} + +static void st7796_get_frame_buffer(Device*, uint8_t, void** out_buffer) { + *out_buffer = nullptr; +} + +static uint8_t st7796_get_frame_buffer_count(Device*) { + return 0; +} + +static error_t st7796_get_backlight(Device* device, Device** backlight) { + auto* configured_backlight = GET_CONFIG(device)->backlight; + if (configured_backlight == nullptr) { + return ERROR_NOT_SUPPORTED; + } + *backlight = configured_backlight; + return ERROR_NONE; +} + +// endregion + +static const DisplayApi st7796_display_api = { + .capabilities = DISPLAY_CAPABILITY_CAP_MIRROR | DISPLAY_CAPABILITY_CAP_SWAP_XY | + DISPLAY_CAPABILITY_CAP_SET_GAP | DISPLAY_CAPABILITY_INVERT_COLOR | DISPLAY_CAPABILITY_ON_OFF | + DISPLAY_CAPABILITY_SLEEP | DISPLAY_CAPABILITY_BACKLIGHT, + .reset = st7796_reset, + .init = st7796_init, + .draw_bitmap = st7796_draw_bitmap, + .mirror = st7796_mirror, + .swap_xy = st7796_swap_xy, + .get_swap_xy = st7796_get_swap_xy, + .get_mirror_x = st7796_get_mirror_x, + .get_mirror_y = st7796_get_mirror_y, + .set_gap = st7796_set_gap, + .invert_color = st7796_invert_color, + .disp_on_off = st7796_disp_on_off, + .disp_sleep = st7796_disp_sleep, + .get_color_format = st7796_get_color_format, + .get_resolution_x = st7796_get_resolution_x, + .get_resolution_y = st7796_get_resolution_y, + .get_frame_buffer = st7796_get_frame_buffer, + .get_frame_buffer_count = st7796_get_frame_buffer_count, + .get_backlight = st7796_get_backlight, + .has_capability = nullptr, +}; + +Driver st7796_driver = { + .name = "st7796", + .compatible = (const char*[]) { "sitronix,st7796", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &st7796_display_api, + .device_type = &DISPLAY_TYPE, + .owner = &st7796_module, + .internal = nullptr +}; diff --git a/Drivers/xpt2046-module/source/xpt2046.cpp b/Drivers/xpt2046-module/source/xpt2046.cpp index caea9a141..4bd1d9583 100644 --- a/Drivers/xpt2046-module/source/xpt2046.cpp +++ b/Drivers/xpt2046-module/source/xpt2046.cpp @@ -239,24 +239,30 @@ static error_t stop(Device* device) { if (internal->power_supply_device != nullptr) { destroy_power_supply_child(internal->power_supply_device); + internal->power_supply_device = nullptr; } - bool ok = true; - // esp_lcd_touch_del() only releases the touch-side resources; the panel IO handle is owned // separately and needs its own deletion. - if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete touch handle"); - ok = false; + if (internal->touch_handle != nullptr) { + if (esp_lcd_touch_del(internal->touch_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete touch handle"); + return ERROR_RESOURCE; + } + internal->touch_handle = nullptr; } - if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { - LOG_E(TAG, "Failed to delete panel IO handle"); - ok = false; + if (internal->io_handle != nullptr) { + if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) { + LOG_E(TAG, "Failed to delete panel IO handle"); + return ERROR_RESOURCE; + } + internal->io_handle = nullptr; } free(internal); - return ok ? ERROR_NONE : ERROR_RESOURCE; + device_set_driver_data(device, nullptr); + return ERROR_NONE; } // endregion diff --git a/Firmware/idf_component.yml b/Firmware/idf_component.yml index 69a1698d9..67cbc7714 100644 --- a/Firmware/idf_component.yml +++ b/Firmware/idf_component.yml @@ -5,7 +5,7 @@ dependencies: rules: - if: "target in [esp32s3, esp32c6, esp32p4]" espressif/esp_hosted: - version: "*" + version: "2.12.11" rules: - if: "target == esp32p4" espressif/esp_wifi_remote: diff --git a/Platforms/platform-esp32/bindings/espressif,esp32-ledc-backlight.yaml b/Platforms/platform-esp32/bindings/espressif,esp32-ledc-backlight.yaml deleted file mode 100644 index d91066e30..000000000 --- a/Platforms/platform-esp32/bindings/espressif,esp32-ledc-backlight.yaml +++ /dev/null @@ -1,29 +0,0 @@ -description: ESP32 LEDC-backed PWM backlight - -compatible: "espressif,esp32-ledc-backlight" - -properties: - pin-backlight: - type: phandles - required: true - description: Backlight PWM output pin - frequency-hz: - type: int - default: 30000 - description: PWM frequency in Hz - brightness-level-range: - type: values - default: [0, 255] - description: Inclusive [min,max] brightness range. The minimum value turns the backlight off. - brightness-default: - type: int - default: 200 - description: Default brightness level, applied by set_brightness_default(). Should fall within brightness-level-range. - ledc-timer: - type: int - default: 0 - description: LEDC timer index, defined by ledc_timer_t - ledc-channel: - type: int - default: 0 - description: LEDC channel index, defined by ledc_channel_t diff --git a/Platforms/platform-esp32/bindings/espressif,esp32-pwm-ledc.yaml b/Platforms/platform-esp32/bindings/espressif,esp32-pwm-ledc.yaml new file mode 100644 index 000000000..073ec3855 --- /dev/null +++ b/Platforms/platform-esp32/bindings/espressif,esp32-pwm-ledc.yaml @@ -0,0 +1,33 @@ +description: ESP32 LEDC-backed generic PWM output + +compatible: "espressif,esp32-pwm-ledc" + +properties: + pin: + type: phandles + required: true + description: PWM output pin + period-ns: + type: int + required: true + description: The PWM period, in nanoseconds + duty-ns: + type: int + default: 0 + description: The PWM duty cycle (active time within one period), in nanoseconds + inverted: + type: boolean + default: false + description: Whether the output polarity is inverted + duty-resolution: + type: int + default: 10 + description: LEDC duty resolution in bits, defined by ledc_timer_bit_t + ledc-timer: + type: int + required: true + description: LEDC timer index, defined by ledc_timer_t + ledc-channel: + type: int + required: true + description: LEDC channel index, defined by ledc_channel_t diff --git a/Platforms/platform-esp32/include/tactility/bindings/esp32_gpio_backlight.h b/Platforms/platform-esp32/include/tactility/bindings/esp32_gpio_backlight.h deleted file mode 100644 index e91550339..000000000 --- a/Platforms/platform-esp32/include/tactility/bindings/esp32_gpio_backlight.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -DEFINE_DEVICETREE(esp32_gpio_backlight, struct Esp32GpioBacklightConfig) - -#ifdef __cplusplus -} -#endif diff --git a/Platforms/platform-esp32/include/tactility/bindings/esp32_ledc_backlight.h b/Platforms/platform-esp32/include/tactility/bindings/esp32_ledc_backlight.h deleted file mode 100644 index 625872d89..000000000 --- a/Platforms/platform-esp32/include/tactility/bindings/esp32_ledc_backlight.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -DEFINE_DEVICETREE(esp32_ledc_backlight, struct Esp32LedcBacklightConfig) - -#ifdef __cplusplus -} -#endif diff --git a/TactilityKernel/include/tactility/bindings/spi_peripheral.h b/Platforms/platform-esp32/include/tactility/bindings/esp32_pwm_ledc.h similarity index 60% rename from TactilityKernel/include/tactility/bindings/spi_peripheral.h rename to Platforms/platform-esp32/include/tactility/bindings/esp32_pwm_ledc.h index 30cccd85f..9a2813d2c 100644 --- a/TactilityKernel/include/tactility/bindings/spi_peripheral.h +++ b/Platforms/platform-esp32/include/tactility/bindings/esp32_pwm_ledc.h @@ -2,13 +2,13 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { #endif -DEFINE_DEVICETREE(spi_peripheral, struct SpiPeripheralConfig) +DEFINE_DEVICETREE(esp32_pwm_ledc, struct Esp32PwmLedcConfig) #ifdef __cplusplus } diff --git a/Platforms/platform-esp32/include/tactility/drivers/esp32_gpio_backlight.h b/Platforms/platform-esp32/include/tactility/drivers/esp32_gpio_backlight.h deleted file mode 100644 index c64547428..000000000 --- a/Platforms/platform-esp32/include/tactility/drivers/esp32_gpio_backlight.h +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct Esp32GpioBacklightConfig { - struct GpioPinSpec pin_backlight; - bool default_on; -}; - -#ifdef __cplusplus -} -#endif diff --git a/Platforms/platform-esp32/include/tactility/drivers/esp32_ledc_backlight.h b/Platforms/platform-esp32/include/tactility/drivers/esp32_pwm_ledc.h similarity index 52% rename from Platforms/platform-esp32/include/tactility/drivers/esp32_ledc_backlight.h rename to Platforms/platform-esp32/include/tactility/drivers/esp32_pwm_ledc.h index 3b75ccf59..021b81a81 100644 --- a/Platforms/platform-esp32/include/tactility/drivers/esp32_ledc_backlight.h +++ b/Platforms/platform-esp32/include/tactility/drivers/esp32_pwm_ledc.h @@ -2,18 +2,19 @@ #pragma once #include -#include #include +#include #ifdef __cplusplus extern "C" { #endif -struct Esp32LedcBacklightConfig { - struct GpioPinSpec pin_backlight; - uint32_t frequency_hz; - struct BrightnessLevelRange brightness_range; - uint8_t brightness_default; +struct Esp32PwmLedcConfig { + struct GpioPinSpec pin; + uint32_t period_ns; + uint32_t duty_ns; + bool inverted; + ledc_timer_bit_t duty_resolution; ledc_timer_t ledc_timer; ledc_channel_t ledc_channel; }; diff --git a/Platforms/platform-esp32/source/drivers/esp32_gpio_backlight.cpp b/Platforms/platform-esp32/source/drivers/esp32_gpio_backlight.cpp deleted file mode 100644 index 64fcb32d9..000000000 --- a/Platforms/platform-esp32/source/drivers/esp32_gpio_backlight.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include - -#include -#include -#include -#include -#include -#include - -#include - -#define TAG "Esp32GpioBacklight" -#define GET_CONFIG(device) (static_cast((device)->config)) - -struct Esp32GpioBacklightInternal { - GpioDescriptor* descriptor; - uint8_t brightness; -}; - -// region Driver lifecycle - -static error_t start(Device* device) { - const auto* config = GET_CONFIG(device); - - auto* descriptor = gpio_descriptor_acquire(config->pin_backlight.gpio_controller, config->pin_backlight.pin, GPIO_OWNER_GPIO); - if (descriptor == nullptr) { - LOG_E(TAG, "Failed to acquire GPIO descriptor"); - return ERROR_RESOURCE; - } - - if (gpio_descriptor_set_flags(descriptor, config->pin_backlight.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) { - LOG_E(TAG, "Failed to configure backlight pin as output"); - gpio_descriptor_release(descriptor); - return ERROR_RESOURCE; - } - - auto* internal = static_cast(malloc(sizeof(Esp32GpioBacklightInternal))); - if (internal == nullptr) { - gpio_descriptor_release(descriptor); - return ERROR_OUT_OF_MEMORY; - } - internal->descriptor = descriptor; - internal->brightness = 0; - - device_set_driver_data(device, internal); - - backlight_set_brightness_default(device); // Allowed to fail, we don't care about the result - - return ERROR_NONE; -} - -static error_t stop(Device* device) { - backlight_set_brightness(device, 0); // Allowed to fail, we don't care about the result - - auto* internal = static_cast(device_get_driver_data(device)); - gpio_descriptor_release(internal->descriptor); - free(internal); - - return ERROR_NONE; -} - -// endregion - -// region BacklightApi - -static error_t esp32_gpio_backlight_set_brightness(Device* device, uint8_t brightness) { - auto* internal = static_cast(device_get_driver_data(device)); - - error_t error = gpio_descriptor_set_level(internal->descriptor, brightness > 0); - if (error != ERROR_NONE) { - LOG_E(TAG, "Failed to set backlight level"); - return error; - } - - internal->brightness = brightness; - return ERROR_NONE; -} - -static error_t esp32_gpio_backlight_set_brightness_default(Device* device) { - return esp32_gpio_backlight_set_brightness(device, GET_CONFIG(device)->default_on ? 1 : 0); -} - -static error_t esp32_gpio_backlight_get_brightness(Device* device, uint8_t* out_brightness) { - auto* internal = static_cast(device_get_driver_data(device)); - *out_brightness = internal->brightness; - return ERROR_NONE; -} - -static uint8_t esp32_gpio_backlight_get_min_brightness(Device*) { - return 0; -} - -static uint8_t esp32_gpio_backlight_get_max_brightness(Device*) { - return 1; -} - -// endregion - -static const BacklightApi esp32_gpio_backlight_api = { - .set_brightness = esp32_gpio_backlight_set_brightness, - .set_brightness_default = esp32_gpio_backlight_set_brightness_default, - .get_brightness = esp32_gpio_backlight_get_brightness, - .get_min_brightness = esp32_gpio_backlight_get_min_brightness, - .get_max_brightness = esp32_gpio_backlight_get_max_brightness, -}; - -extern Module platform_esp32_module; - -Driver esp32_gpio_backlight_driver = { - .name = "esp32_gpio_backlight", - .compatible = (const char*[]) { "espressif,esp32-gpio-backlight", nullptr }, - .start_device = start, - .stop_device = stop, - .api = &esp32_gpio_backlight_api, - .device_type = &BACKLIGHT_TYPE, - .owner = &platform_esp32_module, - .internal = nullptr -}; diff --git a/Platforms/platform-esp32/source/drivers/esp32_ledc_backlight.cpp b/Platforms/platform-esp32/source/drivers/esp32_ledc_backlight.cpp deleted file mode 100644 index f1d075e26..000000000 --- a/Platforms/platform-esp32/source/drivers/esp32_ledc_backlight.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#define TAG "Esp32LedcBacklight" -#define GET_CONFIG(device) (static_cast((device)->config)) - -struct Esp32LedcBacklightInternal { - uint8_t brightness; -}; - -// region Driver lifecycle - -static error_t start(Device* device) { - const auto* config = GET_CONFIG(device); - - ledc_timer_config_t timer_config = { - .speed_mode = LEDC_LOW_SPEED_MODE, - .duty_resolution = LEDC_TIMER_8_BIT, - .timer_num = config->ledc_timer, - .freq_hz = config->frequency_hz, - .clk_cfg = LEDC_AUTO_CLK, - .deconfigure = false, - }; - if (ledc_timer_config(&timer_config) != ESP_OK) { - LOG_E(TAG, "Failed to configure LEDC timer"); - return ERROR_RESOURCE; - } - - ledc_channel_config_t channel_config = { - .gpio_num = (int)config->pin_backlight.pin, - .speed_mode = LEDC_LOW_SPEED_MODE, - .channel = config->ledc_channel, - .intr_type = LEDC_INTR_DISABLE, - .timer_sel = config->ledc_timer, - .duty = config->brightness_range.min, - .hpoint = 0, - .sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD, - .flags = { - .output_invert = 0, - }, - }; - if (ledc_channel_config(&channel_config) != ESP_OK) { - LOG_E(TAG, "Failed to configure LEDC channel"); - return ERROR_RESOURCE; - } - - auto* internal = static_cast(malloc(sizeof(Esp32LedcBacklightInternal))); - if (internal == nullptr) { - return ERROR_OUT_OF_MEMORY; - } - internal->brightness = config->brightness_range.min; - - device_set_driver_data(device, internal); - - backlight_set_brightness_default(device); // Allowed to fail, we don't care about the result - - return ERROR_NONE; -} - -static error_t stop(Device* device) { - backlight_set_brightness(device, 0); // Allowed to fail, we don't care about the result - - auto* internal = static_cast(device_get_driver_data(device)); - free(internal); - - return ERROR_NONE; -} - -// endregion - -// region BacklightApi - -static error_t esp32_ledc_backlight_set_brightness(Device* device, uint8_t brightness) { - const auto* config = GET_CONFIG(device); - auto* internal = static_cast(device_get_driver_data(device)); - - esp_err_t ret = ledc_set_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel, brightness); - if (ret == ESP_OK) { - ret = ledc_update_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel); - } - if (ret != ESP_OK) { - LOG_E(TAG, "Failed to set brightness: %s", esp_err_to_name(ret)); - return ERROR_RESOURCE; - } - - internal->brightness = brightness; - return ERROR_NONE; -} - -static error_t esp32_ledc_backlight_set_brightness_default(Device* device) { - return esp32_ledc_backlight_set_brightness(device, GET_CONFIG(device)->brightness_default); -} - -static error_t esp32_ledc_backlight_get_brightness(Device* device, uint8_t* out_brightness) { - auto* internal = static_cast(device_get_driver_data(device)); - *out_brightness = internal->brightness; - return ERROR_NONE; -} - -static uint8_t esp32_ledc_backlight_get_min_brightness(Device* device) { - return GET_CONFIG(device)->brightness_range.min; -} - -static uint8_t esp32_ledc_backlight_get_max_brightness(Device* device) { - return GET_CONFIG(device)->brightness_range.max; -} - -// endregion - -static const BacklightApi esp32_ledc_backlight_api = { - .set_brightness = esp32_ledc_backlight_set_brightness, - .set_brightness_default = esp32_ledc_backlight_set_brightness_default, - .get_brightness = esp32_ledc_backlight_get_brightness, - .get_min_brightness = esp32_ledc_backlight_get_min_brightness, - .get_max_brightness = esp32_ledc_backlight_get_max_brightness, -}; - -extern Module platform_esp32_module; - -Driver esp32_ledc_backlight_driver = { - .name = "esp32_ledc_backlight", - .compatible = (const char*[]) { "espressif,esp32-ledc-backlight", nullptr }, - .start_device = start, - .stop_device = stop, - .api = &esp32_ledc_backlight_api, - .device_type = &BACKLIGHT_TYPE, - .owner = &platform_esp32_module, - .internal = nullptr -}; diff --git a/Platforms/platform-esp32/source/drivers/esp32_pwm_ledc.cpp b/Platforms/platform-esp32/source/drivers/esp32_pwm_ledc.cpp new file mode 100644 index 000000000..0c55e0aa1 --- /dev/null +++ b/Platforms/platform-esp32/source/drivers/esp32_pwm_ledc.cpp @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define TAG "Esp32PwmLedc" +#define GET_CONFIG(device) (static_cast((device)->config)) +#define GET_INTERNAL(device) (static_cast(device_get_driver_data(device))) + +struct Esp32PwmLedcInternal { + uint32_t period_ns; + uint32_t duty_ns; + bool inverted; + bool enabled; +}; + +// region Helpers + +static uint32_t compute_freq_hz(uint32_t period_ns) { + return period_ns > 0 ? (uint32_t)(1000000000ULL / period_ns) : 0; +} + +static uint32_t compute_raw_duty(uint32_t duty_ns, uint32_t period_ns, ledc_timer_bit_t duty_resolution) { + if (period_ns == 0) return 0; + uint64_t max_duty = 1ULL << duty_resolution; + uint64_t raw_duty = ((uint64_t)duty_ns * max_duty) / period_ns; + return (uint32_t)(raw_duty > max_duty ? max_duty : raw_duty); +} + +// Reprograms the LEDC timer's frequency/resolution. Independent of the enabled state: it doesn't +// touch the channel's signal-output-enable bit, so it's safe to call while output is stopped. +static error_t apply_period(Device* device) { + const auto* config = GET_CONFIG(device); + const auto* internal = GET_INTERNAL(device); + + ledc_timer_config_t timer_config = { + .speed_mode = LEDC_LOW_SPEED_MODE, + .duty_resolution = config->duty_resolution, + .timer_num = config->ledc_timer, + .freq_hz = compute_freq_hz(internal->period_ns), + .clk_cfg = LEDC_AUTO_CLK, + .deconfigure = false, + }; + if (ledc_timer_config(&timer_config) != ESP_OK) { + LOG_E(TAG, "Failed to configure LEDC timer"); + return ERROR_RESOURCE; + } + return ERROR_NONE; +} + +// ledc_update_duty() unconditionally re-enables the channel's signal output, so this only +// touches hardware while the device is enabled; a pending duty/period change made while disabled +// is picked up from internal state the next time enable() is called. +static error_t apply_duty(Device* device) { + const auto* config = GET_CONFIG(device); + const auto* internal = GET_INTERNAL(device); + if (!internal->enabled) { + return ERROR_NONE; + } + + uint32_t raw_duty = compute_raw_duty(internal->duty_ns, internal->period_ns, config->duty_resolution); + esp_err_t ret = ledc_set_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel, raw_duty); + if (ret == ESP_OK) { + ret = ledc_update_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel); + } + if (ret != ESP_OK) { + LOG_E(TAG, "Failed to set duty: %s", esp_err_to_name(ret)); + return ERROR_RESOURCE; + } + return ERROR_NONE; +} + +// Rebuilds the LEDC channel (duty, output polarity, timer/pin binding) from current internal +// state. Like ledc_update_duty(), this unconditionally re-enables the channel's signal output, +// so callers must only invoke this while the device is meant to be enabled. +static error_t apply_channel(Device* device) { + const auto* config = GET_CONFIG(device); + const auto* internal = GET_INTERNAL(device); + + ledc_channel_config_t channel_config = { + .gpio_num = (int)config->pin.pin, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = config->ledc_channel, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = config->ledc_timer, + .duty = compute_raw_duty(internal->duty_ns, internal->period_ns, config->duty_resolution), + .hpoint = 0, + .sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD, + .flags = { + .output_invert = internal->inverted ? 1u : 0u, + }, + }; + if (ledc_channel_config(&channel_config) != ESP_OK) { + LOG_E(TAG, "Failed to configure LEDC channel"); + return ERROR_RESOURCE; + } + return ERROR_NONE; +} + +// endregion + +// region Driver lifecycle + +// Nothing here touches LEDC hardware: period/duty/inverted may be overridden via the PwmApi +// before the first enable() call, so construction only needs to seed tracked state from config. +// enable() is what actually programs the timer and channel from that tracked state. +static error_t start(Device* device) { + const auto* config = GET_CONFIG(device); + + auto* internal = static_cast(malloc(sizeof(Esp32PwmLedcInternal))); + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + internal->period_ns = config->period_ns; + internal->duty_ns = config->duty_ns; + internal->inverted = config->inverted; + internal->enabled = false; + + device_set_driver_data(device, internal); + + return ERROR_NONE; +} + +static error_t stop(Device* device) { + auto* internal = GET_INTERNAL(device); + if (internal->enabled) { + const auto* config = GET_CONFIG(device); + ledc_stop(LEDC_LOW_SPEED_MODE, config->ledc_channel, 0); // Allowed to fail, we don't care about the result + } + + device_set_driver_data(device, nullptr); + free(internal); + + return ERROR_NONE; +} + +// endregion + +// region PwmApi + +static error_t esp32_pwm_ledc_set_period(Device* device, uint32_t period_ns) { + GET_INTERNAL(device)->period_ns = period_ns; + error_t error = apply_period(device); + if (error != ERROR_NONE) { + return error; + } + return apply_duty(device); +} + +static error_t esp32_pwm_ledc_get_period(Device* device, uint32_t* period_ns) { + *period_ns = GET_INTERNAL(device)->period_ns; + return ERROR_NONE; +} + +static error_t esp32_pwm_ledc_set_duty(Device* device, uint32_t duty_ns) { + GET_INTERNAL(device)->duty_ns = duty_ns; + return apply_duty(device); +} + +static error_t esp32_pwm_ledc_get_duty(Device* device, uint32_t* duty_ns) { + *duty_ns = GET_INTERNAL(device)->duty_ns; + return ERROR_NONE; +} + +static error_t esp32_pwm_ledc_set_inverted(Device* device, bool inverted) { + auto* internal = GET_INTERNAL(device); + internal->inverted = inverted; + + // While disabled, just track the override; apply_channel() rebuilds the channel with it + // (and every other tracked setting) the next time enable() runs. + if (!internal->enabled) { + return ERROR_NONE; + } + return apply_channel(device); +} + +static error_t esp32_pwm_ledc_is_inverted(Device* device, bool* inverted) { + *inverted = GET_INTERNAL(device)->inverted; + return ERROR_NONE; +} + +// Applies the tracked period, duty and inverted settings (whether they came from the config +// defaults or were overridden beforehand) and turns the output on. +static error_t esp32_pwm_ledc_enable(Device* device) { + error_t error = apply_period(device); + if (error != ERROR_NONE) { + return error; + } + + error = apply_channel(device); + if (error != ERROR_NONE) { + return error; + } + + GET_INTERNAL(device)->enabled = true; + return ERROR_NONE; +} + +static error_t esp32_pwm_ledc_disable(Device* device) { + auto* internal = GET_INTERNAL(device); + if (!internal->enabled) { + return ERROR_NONE; + } + + const auto* config = GET_CONFIG(device); + internal->enabled = false; + + if (ledc_stop(LEDC_LOW_SPEED_MODE, config->ledc_channel, 0) != ESP_OK) { + LOG_E(TAG, "Failed to stop LEDC channel"); + return ERROR_RESOURCE; + } + return ERROR_NONE; +} + +static error_t esp32_pwm_ledc_is_enabled(Device* device, bool* enabled) { + *enabled = GET_INTERNAL(device)->enabled; + return ERROR_NONE; +} + +// endregion + +static const PwmApi esp32_pwm_ledc_api = { + .set_period = esp32_pwm_ledc_set_period, + .get_period = esp32_pwm_ledc_get_period, + .set_duty = esp32_pwm_ledc_set_duty, + .get_duty = esp32_pwm_ledc_get_duty, + .set_inverted = esp32_pwm_ledc_set_inverted, + .is_inverted = esp32_pwm_ledc_is_inverted, + .enable = esp32_pwm_ledc_enable, + .disable = esp32_pwm_ledc_disable, + .is_enabled = esp32_pwm_ledc_is_enabled, +}; + +extern Module platform_esp32_module; + +Driver esp32_pwm_ledc_driver = { + .name = "esp32_pwm_ledc", + .compatible = (const char*[]) { "espressif,esp32-pwm-ledc", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &esp32_pwm_ledc_api, + .device_type = &PWM_TYPE, + .owner = &platform_esp32_module, + .internal = nullptr +}; diff --git a/Platforms/platform-esp32/source/module.cpp b/Platforms/platform-esp32/source/module.cpp index 833be4c73..02614d245 100644 --- a/Platforms/platform-esp32/source/module.cpp +++ b/Platforms/platform-esp32/source/module.cpp @@ -19,8 +19,7 @@ extern Driver esp32_i2s_driver; #if SOC_LCD_I80_SUPPORTED extern Driver esp32_i8080_driver; #endif -extern Driver esp32_gpio_backlight_driver; -extern Driver esp32_ledc_backlight_driver; +extern Driver esp32_pwm_ledc_driver; #if SOC_SDMMC_HOST_SUPPORTED extern Driver esp32_sdmmc_driver; #endif @@ -56,8 +55,7 @@ static error_t start() { #if SOC_LCD_I80_SUPPORTED check(driver_construct_add(&esp32_i8080_driver) == ERROR_NONE); #endif - check(driver_construct_add(&esp32_gpio_backlight_driver) == ERROR_NONE); - check(driver_construct_add(&esp32_ledc_backlight_driver) == ERROR_NONE); + check(driver_construct_add(&esp32_pwm_ledc_driver) == ERROR_NONE); #if SOC_SDMMC_HOST_SUPPORTED check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE); #endif @@ -111,8 +109,7 @@ static error_t stop() { #if SOC_LCD_I80_SUPPORTED check(driver_remove_destruct(&esp32_i8080_driver) == ERROR_NONE); #endif - check(driver_remove_destruct(&esp32_ledc_backlight_driver) == ERROR_NONE); - check(driver_remove_destruct(&esp32_gpio_backlight_driver) == ERROR_NONE); + check(driver_remove_destruct(&esp32_pwm_ledc_driver) == ERROR_NONE); #if SOC_SDMMC_HOST_SUPPORTED check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE); #endif diff --git a/Platforms/platform-esp32/bindings/espressif,esp32-gpio-backlight.yaml b/TactilityKernel/bindings/gpio-backlight.yaml similarity index 82% rename from Platforms/platform-esp32/bindings/espressif,esp32-gpio-backlight.yaml rename to TactilityKernel/bindings/gpio-backlight.yaml index e60cdc12b..1e785d182 100644 --- a/Platforms/platform-esp32/bindings/espressif,esp32-gpio-backlight.yaml +++ b/TactilityKernel/bindings/gpio-backlight.yaml @@ -3,14 +3,14 @@ description: > enable pin rather than a PWM-dimmable one. Brightness is treated as boolean: any value greater than 0 turns the backlight on, 0 turns it off. -compatible: "espressif,esp32-gpio-backlight" +compatible: "gpio-backlight" properties: - pin-backlight: + pin: type: phandles required: true description: Backlight enable output pin - default-on: + enabled: type: boolean - default: true + default: false description: Whether the backlight is turned on by set_brightness_default() diff --git a/TactilityKernel/bindings/tactility,gpio-hog.yaml b/TactilityKernel/bindings/gpio-hog.yaml similarity index 96% rename from TactilityKernel/bindings/tactility,gpio-hog.yaml rename to TactilityKernel/bindings/gpio-hog.yaml index 1cd39f002..b8de224e6 100644 --- a/TactilityKernel/bindings/tactility,gpio-hog.yaml +++ b/TactilityKernel/bindings/gpio-hog.yaml @@ -6,7 +6,7 @@ description: > HAL's initBoot() hook. Declare a gpio-hog node before the dependent device(s) in the .dts source so it runs first. -compatible: "tactility,gpio-hog" +compatible: "gpio-hog" properties: pin: diff --git a/TactilityKernel/bindings/pwm-backlight.yaml b/TactilityKernel/bindings/pwm-backlight.yaml new file mode 100644 index 000000000..0632c1a38 --- /dev/null +++ b/TactilityKernel/bindings/pwm-backlight.yaml @@ -0,0 +1,19 @@ +description: > + PWM-driven display backlight. Wraps any PWM_TYPE device (e.g. espressif,esp32-pwm-ledc or + pwm-generic) and maps the brightness-level-range onto its duty cycle. + +compatible: "pwm-backlight" + +properties: + pwm: + type: phandles + required: true + description: The PWM device driving the backlight + brightness-level-range: + type: values + default: [0, 255] + description: Inclusive [min,max] brightness range. The minimum value turns the backlight off. + brightness-default: + type: int + default: 200 + description: Default brightness level, applied by set_brightness_default(). Should fall within brightness-level-range. diff --git a/TactilityKernel/bindings/pwm.yaml b/TactilityKernel/bindings/pwm.yaml new file mode 100644 index 000000000..386fcfc0c --- /dev/null +++ b/TactilityKernel/bindings/pwm.yaml @@ -0,0 +1,20 @@ +description: > + Generic PWM device that tracks period, duty cycle, polarity and enabled state in memory + without driving real hardware. Useful as a placeholder on boards without a real PWM + peripheral wired up yet, or in the POSIX simulator. + +compatible: "pwm-generic" + +properties: + period-ns: + type: int + required: true + description: The PWM period, in nanoseconds + duty-ns: + type: int + default: 0 + description: The PWM duty cycle (active time within one period), in nanoseconds + inverted: + type: boolean + default: false + description: Whether the output polarity is inverted diff --git a/TactilityKernel/bindings/rgb-led-gpio.yaml b/TactilityKernel/bindings/rgb-led-gpio.yaml new file mode 100644 index 000000000..b4692bd73 --- /dev/null +++ b/TactilityKernel/bindings/rgb-led-gpio.yaml @@ -0,0 +1,27 @@ +description: > + RGB LED driven by 3 plain digital GPIO pins. Each channel is on/off only (no dimming): + a color component greater than 0 turns that channel's pin on. + +compatible: "rgb-led-gpio" + +properties: + pin-red: + type: phandles + required: true + description: Red channel output pin + pin-green: + type: phandles + required: true + description: Green channel output pin + pin-blue: + type: phandles + required: true + description: Blue channel output pin + enabled: + type: boolean + default: false + description: Whether the LED is turned on by default + default-color: + type: values + default: [255, 255, 255] + description: Color applied when the LED is turned on by default diff --git a/TactilityKernel/bindings/rgb-led-pwm.yaml b/TactilityKernel/bindings/rgb-led-pwm.yaml new file mode 100644 index 000000000..0b6582e08 --- /dev/null +++ b/TactilityKernel/bindings/rgb-led-pwm.yaml @@ -0,0 +1,27 @@ +description: > + RGB LED driven by 3 PWM devices (e.g. espressif,esp32-pwm-ledc or pwm-generic), + one per channel, giving each channel dimming via the wrapped device's duty cycle. + +compatible: "rgb-led-pwm" + +properties: + pwm-red: + type: phandle + required: true + description: PWM device driving the red channel + pwm-green: + type: phandle + required: true + description: PWM device driving the green channel + pwm-blue: + type: phandle + required: true + description: PWM device driving the blue channel + enabled: + type: boolean + default: false + description: Whether the LED is turned on by default + default-color: + type: values + default: [255, 255, 255] + description: Color applied when the LED is turned on by default diff --git a/TactilityKernel/bindings/spi-peripheral.yaml b/TactilityKernel/bindings/spi-peripheral.yaml deleted file mode 100644 index 623c671d8..000000000 --- a/TactilityKernel/bindings/spi-peripheral.yaml +++ /dev/null @@ -1,5 +0,0 @@ -description: SPI peripheral - -compatible: "spi-peripheral" - -properties: {} diff --git a/TactilityKernel/include/tactility/bindings/gpio_backlight.h b/TactilityKernel/include/tactility/bindings/gpio_backlight.h new file mode 100644 index 000000000..8bd58cc1b --- /dev/null +++ b/TactilityKernel/include/tactility/bindings/gpio_backlight.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(gpio_backlight, struct GpioBacklightConfig) diff --git a/TactilityKernel/include/tactility/bindings/pointer_placeholder.h b/TactilityKernel/include/tactility/bindings/pointer_placeholder.h deleted file mode 100644 index d5d026f49..000000000 --- a/TactilityKernel/include/tactility/bindings/pointer_placeholder.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -DEFINE_DEVICETREE(pointer_placeholder, struct PointerPlaceholderConfig) - -#ifdef __cplusplus -} -#endif diff --git a/TactilityKernel/include/tactility/bindings/pwm_backlight.h b/TactilityKernel/include/tactility/bindings/pwm_backlight.h new file mode 100644 index 000000000..bd3e6a4b7 --- /dev/null +++ b/TactilityKernel/include/tactility/bindings/pwm_backlight.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(pwm_backlight, struct PwmBacklightConfig) diff --git a/TactilityKernel/include/tactility/bindings/rgb_led_gpio.h b/TactilityKernel/include/tactility/bindings/rgb_led_gpio.h new file mode 100644 index 000000000..4f363f3cd --- /dev/null +++ b/TactilityKernel/include/tactility/bindings/rgb_led_gpio.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(rgb_led_gpio, struct RgbLedGpioConfig) diff --git a/TactilityKernel/include/tactility/bindings/rgb_led_pwm.h b/TactilityKernel/include/tactility/bindings/rgb_led_pwm.h new file mode 100644 index 000000000..3c007ac11 --- /dev/null +++ b/TactilityKernel/include/tactility/bindings/rgb_led_pwm.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +DEFINE_DEVICETREE(rgb_led_pwm, struct RgbLedPwmConfig) diff --git a/TactilityKernel/include/tactility/drivers/gpio_backlight.h b/TactilityKernel/include/tactility/drivers/gpio_backlight.h new file mode 100644 index 000000000..00b1d3b4a --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/gpio_backlight.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** + * @brief Devicetree configuration for a GPIO-driven on/off backlight. + */ +struct GpioBacklightConfig { + /** Backlight enable output pin */ + struct GpioPinSpec pin; + /** Whether the backlight is turned on by set_brightness_default() */ + bool enabled; +}; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/pwm.h b/TactilityKernel/include/tactility/drivers/pwm.h new file mode 100644 index 000000000..4b59be0a7 --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/pwm.h @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +/** + * @brief Devicetree configuration for a PWM device. + */ +struct PwmConfig { + /** The PWM period, in nanoseconds */ + uint32_t period_ns; + /** The PWM duty cycle (active time within one period), in nanoseconds */ + uint32_t duty_ns; + /** Whether the output polarity is inverted */ + bool inverted; +}; + +/** + * @brief API for PWM drivers. + */ +struct PwmApi { + /** + * @brief Sets the PWM period. + * @param[in] device the PWM device + * @param[in] period_ns the period, in nanoseconds + * @retval ERROR_NONE when the operation was successful + */ + error_t (*set_period)(struct Device* device, uint32_t period_ns); + + /** + * @brief Gets the PWM period. + * @param[in] device the PWM device + * @param[out] period_ns the period, in nanoseconds + * @retval ERROR_NONE when the operation was successful + */ + error_t (*get_period)(struct Device* device, uint32_t* period_ns); + + /** + * @brief Sets the PWM duty cycle. + * @param[in] device the PWM device + * @param[in] duty_ns the active time within one period, in nanoseconds + * @retval ERROR_NONE when the operation was successful + */ + error_t (*set_duty)(struct Device* device, uint32_t duty_ns); + + /** + * @brief Gets the PWM duty cycle. + * @param[in] device the PWM device + * @param[out] duty_ns the active time within one period, in nanoseconds + * @retval ERROR_NONE when the operation was successful + */ + error_t (*get_duty)(struct Device* device, uint32_t* duty_ns); + + /** + * @brief Sets whether the output polarity is inverted. + * @param[in] device the PWM device + * @param[in] inverted true to invert the output polarity + * @retval ERROR_NONE when the operation was successful + */ + error_t (*set_inverted)(struct Device* device, bool inverted); + + /** + * @brief Gets whether the output polarity is inverted. + * @param[in] device the PWM device + * @param[out] inverted true when the output polarity is inverted + * @retval ERROR_NONE when the operation was successful + */ + error_t (*is_inverted)(struct Device* device, bool* inverted); + + /** + * @brief Enables the PWM output. + * @param[in] device the PWM device + * @retval ERROR_NONE when the operation was successful + */ + error_t (*enable)(struct Device* device); + + /** + * @brief Disables the PWM output. + * @param[in] device the PWM device + * @retval ERROR_NONE when the operation was successful + */ + error_t (*disable)(struct Device* device); + + /** + * @brief Gets whether the PWM output is enabled. + * @param[in] device the PWM device + * @param[out] enabled true when the output is enabled + * @retval ERROR_NONE when the operation was successful + */ + error_t (*is_enabled)(struct Device* device, bool* enabled); +}; + +/** + * @brief Sets the PWM period using the specified PWM device. + */ +error_t pwm_set_period(struct Device* device, uint32_t period_ns); + +/** + * @brief Gets the PWM period using the specified PWM device. + */ +error_t pwm_get_period(struct Device* device, uint32_t* period_ns); + +/** + * @brief Sets the PWM duty cycle using the specified PWM device. + */ +error_t pwm_set_duty(struct Device* device, uint32_t duty_ns); + +/** + * @brief Gets the PWM duty cycle using the specified PWM device. + */ +error_t pwm_get_duty(struct Device* device, uint32_t* duty_ns); + +/** + * @brief Sets whether the output polarity is inverted using the specified PWM device. + */ +error_t pwm_set_inverted(struct Device* device, bool inverted); + +/** + * @brief Gets whether the output polarity is inverted using the specified PWM device. + */ +error_t pwm_is_inverted(struct Device* device, bool* inverted); + +/** + * @brief Enables the PWM output using the specified PWM device. + */ +error_t pwm_enable(struct Device* device); + +/** + * @brief Disables the PWM output using the specified PWM device. + */ +error_t pwm_disable(struct Device* device); + +/** + * @brief Gets whether the PWM output is enabled using the specified PWM device. + */ +error_t pwm_is_enabled(struct Device* device, bool* enabled); + +extern const struct DeviceType PWM_TYPE; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/pwm_backlight.h b/TactilityKernel/include/tactility/drivers/pwm_backlight.h new file mode 100644 index 000000000..a13a59cb1 --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/pwm_backlight.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * @brief Devicetree configuration for a PWM-driven backlight. + */ +struct PwmBacklightConfig { + /** The PWM device driving the backlight */ + struct Device* pwm; + /** Inclusive [min,max] brightness range. The minimum value turns the backlight off. */ + struct BrightnessLevelRange brightness_range; + /** Default brightness level, applied by set_brightness_default() */ + uint8_t brightness_default; +}; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/rgb_led.h b/TactilityKernel/include/tactility/drivers/rgb_led.h new file mode 100644 index 000000000..d3333f319 --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/rgb_led.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +/** + * @brief An RGB color value. + */ +struct RgbLedColor { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +/** + * @brief API for RGB LED drivers. + */ +struct RgbLedApi { + /** + * @brief Sets the LED color. + * @param[in] device the RGB LED device + * @param[in] color the color to set + * @retval ERROR_NONE when the operation was successful + */ + error_t (*set_color)(struct Device* device, const struct RgbLedColor color); + + /** + * @brief Gets the LED color. + * @param[in] device the RGB LED device + * @param[out] out_color the current color + * @retval ERROR_NONE when the operation was successful + */ + error_t (*get_color)(struct Device* device, struct RgbLedColor* out_color); + + /** + * @brief Enables the LED output. + * @param[in] device the RGB LED device + * @retval ERROR_NONE when the operation was successful + */ + error_t (*enable)(struct Device* device); + + /** + * @brief Disables the LED output. + * @param[in] device the RGB LED device + */ + void (*disable)(struct Device* device); +}; + +/** + * @brief Sets the LED color using the specified RGB LED device. + */ +error_t rgb_led_set_color(struct Device* device, struct RgbLedColor color); + +/** + * @brief Gets the LED color using the specified RGB LED device. + */ +error_t rgb_led_get_color(struct Device* device, struct RgbLedColor* out_color); + +/** + * @brief Enables the LED output using the specified RGB LED device. + */ +error_t rgb_led_enable(struct Device* device); + +/** + * @brief Disables the LED output using the specified RGB LED device. + */ +void rgb_led_disable(struct Device* device); + +extern const struct DeviceType RGB_LED_TYPE; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/rgb_led_gpio.h b/TactilityKernel/include/tactility/drivers/rgb_led_gpio.h new file mode 100644 index 000000000..a1861fe92 --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/rgb_led_gpio.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * @brief Devicetree configuration for the GPIO-driven RGB LED. + */ +struct RgbLedGpioConfig { + /** Red channel output pin */ + struct GpioPinSpec pin_red; + /** Green channel output pin */ + struct GpioPinSpec pin_green; + /** Blue channel output pin */ + struct GpioPinSpec pin_blue; + /** Whether the LED is turned on by default */ + bool enabled; + /** Color applied when the LED is turned on by default */ + struct RgbLedColor default_color; +}; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/rgb_led_pwm.h b/TactilityKernel/include/tactility/drivers/rgb_led_pwm.h new file mode 100644 index 000000000..85076f51e --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/rgb_led_pwm.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * @brief Devicetree configuration for the PWM-driven RGB LED. + */ +struct RgbLedPwmConfig { + /** PWM device driving the red channel */ + struct Device* pwm_red; + /** PWM device driving the green channel */ + struct Device* pwm_green; + /** PWM device driving the blue channel */ + struct Device* pwm_blue; + /** Whether the LED is turned on by default */ + bool enabled; + /** Color applied when the LED is turned on by default */ + struct RgbLedColor default_color; +}; + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/include/tactility/drivers/spi_peripheral.h b/TactilityKernel/include/tactility/drivers/spi_peripheral.h deleted file mode 100644 index fa725569c..000000000 --- a/TactilityKernel/include/tactility/drivers/spi_peripheral.h +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct SpiPeripheralConfig { - uint8_t _unused; -}; - -extern const struct DeviceType SPI_PERIPHERAL_TYPE; - -#ifdef __cplusplus -} -#endif diff --git a/TactilityKernel/source/drivers/gpio_backlight.cpp b/TactilityKernel/source/drivers/gpio_backlight.cpp new file mode 100644 index 000000000..b9bde8b4d --- /dev/null +++ b/TactilityKernel/source/drivers/gpio_backlight.cpp @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "GpioBacklight" +#define GET_CONFIG(device) (static_cast((device)->config)) +#define GET_INTERNAL(device) (static_cast(device_get_driver_data(device))) + +extern "C" { + +struct GpioBacklightInternal { + GpioDescriptor* descriptor; + bool enabled; +}; + +// region GpioBacklightApi + +static error_t enable(Device* device) { + auto* internal = GET_INTERNAL(device); + + error_t error = gpio_descriptor_set_level(internal->descriptor, true); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to enable backlight"); + return error; + } + + internal->enabled = true; + return ERROR_NONE; +} + +static error_t disable(Device* device) { + auto* internal = GET_INTERNAL(device); + + error_t error = gpio_descriptor_set_level(internal->descriptor, false); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to disable backlight"); + return error; + } + + internal->enabled = false; + return ERROR_NONE; +} + +// endregion + +// region BacklightApi + +static error_t gpio_backlight_set_brightness(Device* device, uint8_t brightness) { + return brightness > 0 ? enable(device) : disable(device); +} + +static error_t gpio_backlight_set_brightness_default(Device* device) { + return GET_CONFIG(device)->enabled ? enable(device) : disable(device); +} + +static error_t gpio_backlight_get_brightness(Device* device, uint8_t* out_brightness) { + *out_brightness = GET_INTERNAL(device)->enabled ? 1 : 0; + return ERROR_NONE; +} + +static uint8_t gpio_backlight_get_min_brightness(Device*) { + return 0; +} + +static uint8_t gpio_backlight_get_max_brightness(Device*) { + return 1; +} + +// endregion + +static constexpr BacklightApi GPIO_BACKLIGHT_API = { + .set_brightness = gpio_backlight_set_brightness, + .set_brightness_default = gpio_backlight_set_brightness_default, + .get_brightness = gpio_backlight_get_brightness, + .get_min_brightness = gpio_backlight_get_min_brightness, + .get_max_brightness = gpio_backlight_get_max_brightness, +}; + +// region Driver lifecycle + +static error_t start(Device* device) { + const auto* config = GET_CONFIG(device); + + auto* descriptor = gpio_descriptor_acquire(config->pin.gpio_controller, config->pin.pin, GPIO_OWNER_GPIO); + if (descriptor == nullptr) { + LOG_E(TAG, "Failed to acquire GPIO descriptor"); + return ERROR_RESOURCE; + } + + if (gpio_descriptor_set_flags(descriptor, config->pin.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) { + LOG_E(TAG, "Failed to configure backlight pin as output"); + gpio_descriptor_release(descriptor); + return ERROR_RESOURCE; + } + + auto* internal = new(std::nothrow) GpioBacklightInternal { .descriptor = descriptor, .enabled = false }; + if (internal == nullptr) { + gpio_descriptor_release(descriptor); + return ERROR_OUT_OF_MEMORY; + } + + device_set_driver_data(device, internal); + + if (gpio_backlight_set_brightness_default(device) != ERROR_NONE) { + // Allowed to fail, we don't care about the result + LOG_W(TAG, "gpio_backlight_set_brightness_default(%s) failed", device->name); + } + + return ERROR_NONE; +} + +static error_t stop(Device* device) { + disable(device); // Allowed to fail, we don't care about the result + + auto* internal = GET_INTERNAL(device); + gpio_descriptor_release(internal->descriptor); + device_set_driver_data(device, nullptr); + delete internal; + + return ERROR_NONE; +} + +// endregion + +extern Module root_module; + +Driver gpio_backlight_driver = { + .name = "gpio_backlight", + .compatible = (const char*[]) { "gpio-backlight", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &GPIO_BACKLIGHT_API, + .device_type = &BACKLIGHT_TYPE, + .owner = &root_module, + .internal = nullptr +}; + +} diff --git a/TactilityKernel/source/drivers/gpio_hog.cpp b/TactilityKernel/source/drivers/gpio_hog.cpp index d3f08cab0..c331588ff 100644 --- a/TactilityKernel/source/drivers/gpio_hog.cpp +++ b/TactilityKernel/source/drivers/gpio_hog.cpp @@ -62,7 +62,7 @@ extern Module root_module; Driver gpio_hog_driver = { .name = "gpio_hog", - .compatible = (const char*[]) { "tactility,gpio-hog", nullptr }, + .compatible = (const char*[]) { "gpio-hog", nullptr }, .start_device = start, .stop_device = stop, .api = nullptr, diff --git a/TactilityKernel/source/drivers/pointer_placeholder.cpp b/TactilityKernel/source/drivers/pointer_placeholder.cpp deleted file mode 100644 index b3d329af9..000000000 --- a/TactilityKernel/source/drivers/pointer_placeholder.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include -#include -#include -#include -#include - -extern "C" { - -static error_t start(Device*) { return ERROR_NONE; } -static error_t stop(Device*) { return ERROR_NONE; } - -extern Module root_module; - -Driver pointer_placeholder_driver = { - .name = "pointer_placeholder", - .compatible = (const char*[]) { "pointer-placeholder", nullptr }, - .start_device = start, - .stop_device = stop, - .api = nullptr, - .device_type = &POINTER_TYPE, - .owner = &root_module, - .internal = nullptr -}; - -} diff --git a/TactilityKernel/source/drivers/pwm.cpp b/TactilityKernel/source/drivers/pwm.cpp new file mode 100644 index 000000000..bd67cb106 --- /dev/null +++ b/TactilityKernel/source/drivers/pwm.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#define PWM_DRIVER_API(driver) ((struct PwmApi*)driver->api) + +extern "C" { + +error_t pwm_set_period(Device* device, uint32_t period_ns) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->set_period(device, period_ns); +} + +error_t pwm_get_period(Device* device, uint32_t* period_ns) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->get_period(device, period_ns); +} + +error_t pwm_set_duty(Device* device, uint32_t duty_ns) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->set_duty(device, duty_ns); +} + +error_t pwm_get_duty(Device* device, uint32_t* duty_ns) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->get_duty(device, duty_ns); +} + +error_t pwm_set_inverted(Device* device, bool inverted) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->set_inverted(device, inverted); +} + +error_t pwm_is_inverted(Device* device, bool* inverted) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->is_inverted(device, inverted); +} + +error_t pwm_enable(Device* device) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->enable(device); +} + +error_t pwm_disable(Device* device) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->disable(device); +} + +error_t pwm_is_enabled(Device* device, bool* enabled) { + const auto* driver = device_get_driver(device); + return PWM_DRIVER_API(driver)->is_enabled(device, enabled); +} + +const DeviceType PWM_TYPE { + .name = "pwm" +}; + +} diff --git a/TactilityKernel/source/drivers/pwm_backlight.cpp b/TactilityKernel/source/drivers/pwm_backlight.cpp new file mode 100644 index 000000000..5135cdd90 --- /dev/null +++ b/TactilityKernel/source/drivers/pwm_backlight.cpp @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "PwmBacklight" +#define GET_CONFIG(device) (static_cast((device)->config)) +#define GET_INTERNAL(device) (static_cast(device_get_driver_data(device))) + +extern "C" { + +struct PwmBacklightInternal { + uint8_t brightness; +}; + +// region BacklightApi + +static error_t apply_brightness(Device* device, uint8_t brightness) { + const auto* config = GET_CONFIG(device); + + if (brightness <= config->brightness_range.min) { + error_t error = pwm_disable(config->pwm); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to disable PWM"); + return error; + } + return ERROR_NONE; + } + + if (brightness > config->brightness_range.max) { + brightness = config->brightness_range.max; + } + + uint32_t period_ns; + error_t error = pwm_get_period(config->pwm, &period_ns); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to get PWM period"); + return error; + } + + uint8_t level = brightness - config->brightness_range.min; + uint8_t range = config->brightness_range.max - config->brightness_range.min; + uint32_t duty_ns = (uint32_t)(((uint64_t)level * period_ns) / range); + + error = pwm_set_duty(config->pwm, duty_ns); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to set PWM duty"); + return error; + } + + return pwm_enable(config->pwm); +} + +static error_t pwm_backlight_set_brightness(Device* device, uint8_t brightness) { + error_t error = apply_brightness(device, brightness); + if (error != ERROR_NONE) { + return error; + } + GET_INTERNAL(device)->brightness = brightness; + return ERROR_NONE; +} + +static error_t pwm_backlight_set_brightness_default(Device* device) { + return pwm_backlight_set_brightness(device, GET_CONFIG(device)->brightness_default); +} + +static error_t pwm_backlight_get_brightness(Device* device, uint8_t* out_brightness) { + *out_brightness = GET_INTERNAL(device)->brightness; + return ERROR_NONE; +} + +static uint8_t pwm_backlight_get_min_brightness(Device* device) { + return GET_CONFIG(device)->brightness_range.min; +} + +static uint8_t pwm_backlight_get_max_brightness(Device* device) { + return GET_CONFIG(device)->brightness_range.max; +} + +// endregion + +static constexpr BacklightApi PWM_BACKLIGHT_API = { + .set_brightness = pwm_backlight_set_brightness, + .set_brightness_default = pwm_backlight_set_brightness_default, + .get_brightness = pwm_backlight_get_brightness, + .get_min_brightness = pwm_backlight_get_min_brightness, + .get_max_brightness = pwm_backlight_get_max_brightness, +}; + +// region Driver lifecycle + +static error_t start(Device* device) { + const auto* config = GET_CONFIG(device); + if (config->brightness_range.max <= config->brightness_range.min) { + return ERROR_INVALID_ARGUMENT; + } + + auto* internal = new(std::nothrow) PwmBacklightInternal { .brightness = GET_CONFIG(device)->brightness_range.min }; + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + + device_set_driver_data(device, internal); + + pwm_backlight_set_brightness_default(device); // Allowed to fail, we don't care about the result + + return ERROR_NONE; +} + +static error_t stop(Device* device) { + pwm_backlight_set_brightness(device, GET_CONFIG(device)->brightness_range.min); // Allowed to fail, we don't care about the result + + auto* internal = GET_INTERNAL(device); + device_set_driver_data(device, nullptr); + delete internal; + + return ERROR_NONE; +} + +// endregion + +extern Module root_module; + +Driver pwm_backlight_driver = { + .name = "pwm_backlight", + .compatible = (const char*[]) { "pwm-backlight", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &PWM_BACKLIGHT_API, + .device_type = &BACKLIGHT_TYPE, + .owner = &root_module, + .internal = nullptr +}; + +} diff --git a/TactilityKernel/source/drivers/rgb_led.cpp b/TactilityKernel/source/drivers/rgb_led.cpp new file mode 100644 index 000000000..8f4b90e79 --- /dev/null +++ b/TactilityKernel/source/drivers/rgb_led.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#define RGB_LED_DRIVER_API(driver) ((struct RgbLedApi*)driver->api) + +extern "C" { + +error_t rgb_led_set_color(Device* device, RgbLedColor color) { + const auto* driver = device_get_driver(device); + return RGB_LED_DRIVER_API(driver)->set_color(device, color); +} + +error_t rgb_led_get_color(Device* device, RgbLedColor* out_color) { + const auto* driver = device_get_driver(device); + return RGB_LED_DRIVER_API(driver)->get_color(device, out_color); +} + +error_t rgb_led_enable(Device* device) { + const auto* driver = device_get_driver(device); + return RGB_LED_DRIVER_API(driver)->enable(device); +} + +void rgb_led_disable(Device* device) { + const auto* driver = device_get_driver(device); + RGB_LED_DRIVER_API(driver)->disable(device); +} + +const DeviceType RGB_LED_TYPE { + .name = "rgb_led" +}; + +} diff --git a/TactilityKernel/source/drivers/rgb_led_gpio.cpp b/TactilityKernel/source/drivers/rgb_led_gpio.cpp new file mode 100644 index 000000000..49efc83a7 --- /dev/null +++ b/TactilityKernel/source/drivers/rgb_led_gpio.cpp @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "RgbLedGpio" +#define GET_CONFIG(device) (static_cast((device)->config)) +#define GET_INTERNAL(device) (static_cast(device_get_driver_data(device))) + +extern "C" { + +struct RgbLedGpioInternal { + GpioDescriptor* descriptor_red; + GpioDescriptor* descriptor_green; + GpioDescriptor* descriptor_blue; + RgbLedColor color; + bool enabled; +}; + +// region RgbLedApi + +static error_t apply_levels(Device* device) { + auto* internal = GET_INTERNAL(device); + bool on = internal->enabled; + + error_t error = gpio_descriptor_set_level(internal->descriptor_red, on && internal->color.r > 0); + if (error == ERROR_NONE) { + error = gpio_descriptor_set_level(internal->descriptor_green, on && internal->color.g > 0); + } + if (error == ERROR_NONE) { + error = gpio_descriptor_set_level(internal->descriptor_blue, on && internal->color.b > 0); + } + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to apply LED levels"); + } + return error; +} + +static error_t rgb_led_gpio_set_color(Device* device, RgbLedColor color) { + GET_INTERNAL(device)->color = color; + return apply_levels(device); +} + +static error_t rgb_led_gpio_get_color(Device* device, RgbLedColor* out_color) { + *out_color = GET_INTERNAL(device)->color; + return ERROR_NONE; +} + +static error_t rgb_led_gpio_enable(Device* device) { + GET_INTERNAL(device)->enabled = true; + return apply_levels(device); +} + +static void rgb_led_gpio_disable(Device* device) { + GET_INTERNAL(device)->enabled = false; + apply_levels(device); // Allowed to fail, we don't care about the result +} + +// endregion + +static constexpr RgbLedApi RGB_LED_GPIO_API = { + .set_color = rgb_led_gpio_set_color, + .get_color = rgb_led_gpio_get_color, + .enable = rgb_led_gpio_enable, + .disable = rgb_led_gpio_disable, +}; + +// region Driver lifecycle + +static error_t start(Device* device) { + const auto* config = GET_CONFIG(device); + + auto* descriptor_red = gpio_descriptor_acquire(config->pin_red.gpio_controller, config->pin_red.pin, GPIO_OWNER_GPIO); + if (descriptor_red == nullptr) { + LOG_E(TAG, "Failed to acquire red GPIO descriptor"); + return ERROR_RESOURCE; + } + + auto* descriptor_green = gpio_descriptor_acquire(config->pin_green.gpio_controller, config->pin_green.pin, GPIO_OWNER_GPIO); + if (descriptor_green == nullptr) { + LOG_E(TAG, "Failed to acquire green GPIO descriptor"); + gpio_descriptor_release(descriptor_red); + return ERROR_RESOURCE; + } + + auto* descriptor_blue = gpio_descriptor_acquire(config->pin_blue.gpio_controller, config->pin_blue.pin, GPIO_OWNER_GPIO); + if (descriptor_blue == nullptr) { + LOG_E(TAG, "Failed to acquire blue GPIO descriptor"); + gpio_descriptor_release(descriptor_red); + gpio_descriptor_release(descriptor_green); + return ERROR_RESOURCE; + } + + bool ok = gpio_descriptor_set_flags(descriptor_red, config->pin_red.flags | GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE && + gpio_descriptor_set_flags(descriptor_green, config->pin_green.flags | GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE && + gpio_descriptor_set_flags(descriptor_blue, config->pin_blue.flags | GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE; + if (!ok) { + LOG_E(TAG, "Failed to configure LED pins as outputs"); + gpio_descriptor_release(descriptor_red); + gpio_descriptor_release(descriptor_green); + gpio_descriptor_release(descriptor_blue); + return ERROR_RESOURCE; + } + + auto* internal = new(std::nothrow) RgbLedGpioInternal { + .descriptor_red = descriptor_red, + .descriptor_green = descriptor_green, + .descriptor_blue = descriptor_blue, + .color = config->default_color, + .enabled = false + }; + if (internal == nullptr) { + gpio_descriptor_release(descriptor_red); + gpio_descriptor_release(descriptor_green); + gpio_descriptor_release(descriptor_blue); + return ERROR_OUT_OF_MEMORY; + } + + device_set_driver_data(device, internal); + + if (config->enabled) { + if (rgb_led_gpio_enable(device) != ERROR_NONE) { + // Allowed to fail, we don't care about the result + LOG_W(TAG, "led_gpio_enable(%s) failed", device->name); + } + } else { + if (apply_levels(device) != ERROR_NONE) { + // Allowed to fail, we don't care about the result + LOG_W(TAG, "led_gpio_apply_levels(%s) failed", device->name); + } + } + + return ERROR_NONE; +} + +static error_t stop(Device* device) { + rgb_led_gpio_disable(device); + + auto* internal = GET_INTERNAL(device); + gpio_descriptor_release(internal->descriptor_red); + gpio_descriptor_release(internal->descriptor_green); + gpio_descriptor_release(internal->descriptor_blue); + device_set_driver_data(device, nullptr); + delete internal; + + return ERROR_NONE; +} + +// endregion + +extern Module root_module; + +Driver rgb_led_gpio_driver = { + .name = "rgb_led_gpio", + .compatible = (const char*[]) { "rgb-led-gpio", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &RGB_LED_GPIO_API, + .device_type = &RGB_LED_TYPE, + .owner = &root_module, + .internal = nullptr +}; + +} diff --git a/TactilityKernel/source/drivers/rgb_led_pwm.cpp b/TactilityKernel/source/drivers/rgb_led_pwm.cpp new file mode 100644 index 000000000..814086b1d --- /dev/null +++ b/TactilityKernel/source/drivers/rgb_led_pwm.cpp @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include +#include +#include +#include + +#include + +#define TAG "RgbLedPwm" +#define GET_CONFIG(device) (static_cast((device)->config)) +#define GET_INTERNAL(device) (static_cast(device_get_driver_data(device))) + +extern "C" { + +struct RgbLedPwmInternal { + RgbLedColor color; + bool enabled; +}; + +// region RgbLedApi + +static error_t apply_channel(Device* pwm_device, uint8_t component) { + uint32_t period_ns; + error_t error = pwm_get_period(pwm_device, &period_ns); + if (error != ERROR_NONE) { + return error; + } + + uint32_t duty_ns = (uint32_t)(((uint64_t)component * period_ns) / 255); + return pwm_set_duty(pwm_device, duty_ns); +} + +static error_t apply_color(Device* device) { + const auto* config = GET_CONFIG(device); + const auto* internal = GET_INTERNAL(device); + + error_t error = apply_channel(config->pwm_red, internal->color.r); + if (error == ERROR_NONE) { + error = apply_channel(config->pwm_green, internal->color.g); + } + if (error == ERROR_NONE) { + error = apply_channel(config->pwm_blue, internal->color.b); + } + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to apply LED color"); + } + return error; +} + +static error_t rgb_led_pwm_set_color(Device* device, RgbLedColor color) { + GET_INTERNAL(device)->color = color; + return apply_color(device); +} + +static error_t rgb_led_pwm_get_color(Device* device, RgbLedColor* out_color) { + *out_color = GET_INTERNAL(device)->color; + return ERROR_NONE; +} + +static error_t rgb_led_pwm_enable(Device* device) { + const auto* config = GET_CONFIG(device); + error_t error = pwm_enable(config->pwm_red); + if (error != ERROR_NONE) { + return error; + } + error = pwm_enable(config->pwm_green); + if (error != ERROR_NONE) { + pwm_disable(config->pwm_red); + return error; + } + error = pwm_enable(config->pwm_blue); + if (error != ERROR_NONE) { + pwm_disable(config->pwm_green); + pwm_disable(config->pwm_red); + LOG_E(TAG, "Failed to enable LED"); + return error; + } + GET_INTERNAL(device)->enabled = true; + return ERROR_NONE; +} + +static void rgb_led_pwm_disable(Device* device) { + const auto* config = GET_CONFIG(device); + GET_INTERNAL(device)->enabled = false; + + pwm_disable(config->pwm_red); + pwm_disable(config->pwm_green); + pwm_disable(config->pwm_blue); +} + +// endregion + +static constexpr RgbLedApi RGB_LED_PWM_API = { + .set_color = rgb_led_pwm_set_color, + .get_color = rgb_led_pwm_get_color, + .enable = rgb_led_pwm_enable, + .disable = rgb_led_pwm_disable, +}; + +// region Driver lifecycle + +static error_t start(Device* device) { + const auto* config = GET_CONFIG(device); + + auto* internal = new(std::nothrow) RgbLedPwmInternal { + .color = config->default_color, + .enabled = false + }; + if (internal == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + + device_set_driver_data(device, internal); + + error_t error = apply_color(device); + if (error != ERROR_NONE) { + device_set_driver_data(device, nullptr); + delete internal; + return error; + } + + if (config->enabled) { + rgb_led_pwm_enable(device); // Allowed to fail, we don't care about the result + } + + return ERROR_NONE; +} + +static error_t stop(Device* device) { + rgb_led_pwm_disable(device); + + auto* internal = GET_INTERNAL(device); + device_set_driver_data(device, nullptr); + delete internal; + + return ERROR_NONE; +} + +// endregion + +extern Module root_module; + +Driver rgb_led_pwm_driver = { + .name = "rgb_led_pwm", + .compatible = (const char*[]) { "rgb-led-pwm", nullptr }, + .start_device = start, + .stop_device = stop, + .api = &RGB_LED_PWM_API, + .device_type = &RGB_LED_TYPE, + .owner = &root_module, + .internal = nullptr +}; + +} diff --git a/TactilityKernel/source/drivers/spi_peripheral.cpp b/TactilityKernel/source/drivers/spi_peripheral.cpp deleted file mode 100644 index 8e9a3956b..000000000 --- a/TactilityKernel/source/drivers/spi_peripheral.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include -#include -#include - -extern "C" { - -static error_t start(Device*) { return ERROR_NONE; } -static error_t stop(Device*) { return ERROR_NONE; } - -const DeviceType SPI_PERIPHERAL_TYPE = { - .name = "spi_peripheral" -}; - -extern Module root_module; - -Driver spi_peripheral_driver = { - .name = "spi_peripheral", - .compatible = (const char*[]) { "spi-peripheral", nullptr }, - .start_device = start, - .stop_device = stop, - .api = nullptr, - .device_type = &SPI_PERIPHERAL_TYPE, - .owner = &root_module, - .internal = nullptr -}; - -} diff --git a/TactilityKernel/source/kernel_init.cpp b/TactilityKernel/source/kernel_init.cpp index d02cad9bf..0aad44468 100644 --- a/TactilityKernel/source/kernel_init.cpp +++ b/TactilityKernel/source/kernel_init.cpp @@ -16,16 +16,20 @@ static error_t start() { if (driver_construct_add(&root_driver) != ERROR_NONE) return ERROR_RESOURCE; extern Driver display_placeholder_driver; if (driver_construct_add(&display_placeholder_driver) != ERROR_NONE) return ERROR_RESOURCE; - extern Driver pointer_placeholder_driver; - if (driver_construct_add(&pointer_placeholder_driver) != ERROR_NONE) return ERROR_RESOURCE; - extern Driver spi_peripheral_driver; - if (driver_construct_add(&spi_peripheral_driver) != ERROR_NONE) return ERROR_RESOURCE; extern Driver battery_sense_driver; if (driver_construct_add(&battery_sense_driver) != ERROR_NONE) return ERROR_RESOURCE; extern Driver battery_sense_power_supply_driver; if (driver_construct_add(&battery_sense_power_supply_driver) != ERROR_NONE) return ERROR_RESOURCE; extern Driver gpio_hog_driver; if (driver_construct_add(&gpio_hog_driver) != ERROR_NONE) return ERROR_RESOURCE; + extern Driver pwm_backlight_driver; + if (driver_construct_add(&pwm_backlight_driver) != ERROR_NONE) return ERROR_RESOURCE; + extern Driver gpio_backlight_driver; + if (driver_construct_add(&gpio_backlight_driver) != ERROR_NONE) return ERROR_RESOURCE; + extern Driver rgb_led_gpio_driver; + if (driver_construct_add(&rgb_led_gpio_driver) != ERROR_NONE) return ERROR_RESOURCE; + extern Driver rgb_led_pwm_driver; + if (driver_construct_add(&rgb_led_pwm_driver) != ERROR_NONE) return ERROR_RESOURCE; return ERROR_NONE; } diff --git a/TactilityKernel/source/kernel_symbols.c b/TactilityKernel/source/kernel_symbols.c index 0d4945da2..42ff02a2a 100644 --- a/TactilityKernel/source/kernel_symbols.c +++ b/TactilityKernel/source/kernel_symbols.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -243,8 +242,6 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = { DEFINE_MODULE_SYMBOL(spi_controller_try_lock), DEFINE_MODULE_SYMBOL(spi_controller_unlock), DEFINE_MODULE_SYMBOL(SPI_CONTROLLER_TYPE), - // drivers/spi_peripheral - DEFINE_MODULE_SYMBOL(SPI_PERIPHERAL_TYPE), // drivers/uart_controller DEFINE_MODULE_SYMBOL(uart_controller_open), DEFINE_MODULE_SYMBOL(uart_controller_close),