Tactility/Devices/tulip-4r11/tulip-4r11.dts
Ken Van Hoeylandt cb4ce5246d
USB host refactored (#684)
- Create `USB_HOST_TYPE` base driver in TactilityKernel
- Refactor esp32_usbhost dts format, and create child devices dynamically
- Use PSRAM for task stacks where possible: saving 20 kB from just the task stacks, but roughly 30 kB when nothing is connected.
- Allow the user to disable USB host interface in the USB settings app, saving an additionaly 20 kB of IRAM when nothing was connected.
- Change listener-based APIs to subscribe and poll/await pattern. This avoids callstacks of apps and services leaking into the USB API

This results in big IRAM savings: 30 kB when USB host is on and nothing is connected, and 50 kB total when USB host is disabled.
This brings the total free IRAM after boot from roughly 170 kB to 200 kB (host enabled) or 220 kB (host disabled).
2026-10-10 13:33:32 +02:00

182 lines
4.9 KiB
Plaintext

/dts-v1/;
#include <tactility/bindings/battery_sense.h>
#include <tactility/bindings/root.h>
#include <tactility/bindings/esp32_adc_oneshot.h>
#include <tactility/bindings/esp32_ble.h>
#include <tactility/bindings/esp32_wifi_pinned.h>
#include <tactility/bindings/esp32_gpio.h>
#include <tactility/bindings/esp32_i2c_master.h>
#include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_usbhost.h>
#include <tactility/bindings/esp32_pwm_ledc.h>
#include <tactility/bindings/gpio_hog.h>
#include <tactility/bindings/pwm_backlight.h>
#include <bindings/rgb_display.h>
#include <bindings/gt911.h>
#include <bindings/dummy_i2s_amp.h>
// Reference: https: //github.com/TulipCC/tulipcc/
/ {
compatible = "root";
model = "Tulip 4 (R11)";
wifi0 {
compatible = "espressif,esp32-wifi-pinned";
};
ble0 {
compatible = "espressif,esp32-ble";
};
gpio0 {
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
// Battery voltage is sensed through the 470K/470K divider (R34/R38) into GPIO3
// (ADC1_CH2), i.e. a straight 2: 1 divider; the RY3730 charger IC has no I2C
// interface to drive. Reference: tulipcc tulip/shared/py/tulip.py battery().
adc0 {
compatible = "espressif,esp32-adc-oneshot";
unit-id = <ADC_UNIT_1>;
channels = <ADC_CHANNEL_2 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
};
battery-sense {
compatible = "battery-sense";
io-channel = <&adc0 0>;
reference-voltage-mv = <3300>;
multiplier = <2000>;
};
// The Grove connector shares this I2C bus with the touch controller
i2c0 {
compatible = "espressif,esp32-i2c-master";
port = <I2C_NUM_0>;
clock-frequency = <100000>;
pin-sda = <&gpio0 17 GPIO_FLAG_PULL_UP>;
pin-scl = <&gpio0 18 GPIO_FLAG_PULL_UP>;
touch0 {
compatible = "goodix,gt911";
reg = <0x5D>;
x-max = <1024>;
y-max = <600>;
// R11 inverts the reset line (active-high) and needs two toggle cycles before it
// starts responding on I2C.
pin-reset = <&gpio0 48 GPIO_FLAG_ACTIVE_HIGH>;
reset-pulses = <2>;
// The controller's programmed Y range (~750) exceeds the panel's 600 rows and the
// sensor sits slightly offset from the panel; calibrate per the reference firmware
x-offset = <-2>;
y-offset = <-10>;
y-scale = <800>;
};
};
// The unused panel data lines (G2 and B3 are unconnected on R11) are driven low exactly
// like the reference firmware does, so the panel never sees floating inputs on them.
panel_data_low_b4 {
compatible = "gpio-hog";
pin = <&gpio0 38 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
panel_data_low_b5 {
compatible = "gpio-hog";
pin = <&gpio0 46 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
panel_data_low_g3 {
compatible = "gpio-hog";
pin = <&gpio0 6 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
panel_data_low_g4 {
compatible = "gpio-hog";
pin = <&gpio0 7 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
panel_data_low_r3 {
compatible = "gpio-hog";
pin = <&gpio0 45 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
panel_data_low_r4 {
compatible = "gpio-hog";
pin = <&gpio0 13 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
// Backlight is active-low: the reference firmware drives duty 0 at max brightness.
display_backlight_pwm {
compatible = "espressif,esp32-pwm-ledc";
pin = <&gpio0 47 GPIO_FLAG_NONE>;
period-ns = <3333333>;
duty-resolution = <13>;
ledc-timer = <1>;
ledc-channel = <1>;
inverted;
};
display_backlight {
compatible = "pwm-backlight";
pwm = <&display_backlight_pwm>;
brightness-level-range = <0 255>;
brightness-default = <200>;
};
display0 {
compatible = "espressif,esp32-rgb-display";
horizontal-resolution = <1024>;
vertical-resolution = <600>;
pixel-clock-hz = <28000000>;
hsync-pulse-width = <30>;
hsync-back-porch = <16>;
hsync-front-porch = <210>;
vsync-pulse-width = <13>;
vsync-back-porch = <10>;
vsync-front-porch = <22>;
data-width = <8>;
bits-per-pixel = <8>;
custom-pixel-format = <RGB_DISPLAY_PIXEL_FORMAT_RGB332>;
num-fbs = <1>;
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 9 GPIO_FLAG_NONE>; // B6
pin-data1 = <&gpio0 1 GPIO_FLAG_NONE>; // B7
pin-data2 = <&gpio0 15 GPIO_FLAG_NONE>; // G5
pin-data3 = <&gpio0 16 GPIO_FLAG_NONE>; // G6
pin-data4 = <&gpio0 4 GPIO_FLAG_NONE>; // G7
pin-data5 = <&gpio0 10 GPIO_FLAG_NONE>; // R5
pin-data6 = <&gpio0 21 GPIO_FLAG_NONE>; // R6
pin-data7 = <&gpio0 14 GPIO_FLAG_NONE>; // R7
backlight = <&display_backlight>;
};
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 8 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 2 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 5 GPIO_FLAG_NONE>;
};
speaker0 {
compatible = "ti,pcm5101a";
i2s = <&i2s0>;
};
usbhost0 {
compatible = "espressif,esp32-usbhost";
};
};