Files
tactility/Devices/m5stack-tab5/Source/devices/display_detect.cpp
T
2026-07-20 23:43:17 +02:00

139 lines
4.7 KiB
C++

#include "detect.h"
#include "../../../../TactilityKernel/include/tactility/log.h"
#include "devices_common.h"
#include "devices_v1.h"
#include "devices_v2.h"
#include "tab5_keyboard.h"
#include <tactility/device.h>
#include <tactility/device_listener.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/log.h>
#include <cstring>
constexpr auto* TAG = "Tab5";
static Device tab5_power_control_device {};
// Charge-control/quick-charge/power-off for the IP2326 charger IC, driven through io_expander1 (see tab5_power_control.h).
static void tab5_create_power_control(Device* io_expander1) {
tab5_power_control_device = Device {
.address = 0,
.name = "power_control0",
.config = nullptr,
.parent = nullptr,
.internal = nullptr,
};
// Parented to io_expander1 itself: the driver's start()/set_*() use device_get_parent() as
// its GPIO controller.
construct_add_start(&tab5_power_control_device, io_expander1, "m5stack,tab5-power-control");
}
constexpr auto GPIO_EXP0_PIN_LCD_RESET = 4;
constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5;
bool pulse_display_reset_pins(Device* io_expander0) {
auto* lcd_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_LCD_RESET, GPIO_OWNER_GPIO);
auto* touch_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_TOUCH_RESET, GPIO_OWNER_GPIO);
if (lcd_reset_pin == nullptr || touch_reset_pin == nullptr) {
LOG_E(TAG, "display_detect: failed to acquire LCD/touch reset pins on io_expander0");
if (lcd_reset_pin != nullptr) {
gpio_descriptor_release(lcd_reset_pin);
}
if (touch_reset_pin != nullptr) {
gpio_descriptor_release(touch_reset_pin);
}
return false;
}
gpio_descriptor_set_flags(lcd_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_flags(touch_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(lcd_reset_pin, false);
gpio_descriptor_set_level(touch_reset_pin, false);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(lcd_reset_pin, true);
gpio_descriptor_set_level(touch_reset_pin, true);
gpio_descriptor_release(lcd_reset_pin);
gpio_descriptor_release(touch_reset_pin);
return true;
}
// Fires for every device's start/stop in the system.
static void on_display_detect_event(Device* device, DeviceEvent event, void* context) {
(void)context;
static Device* i2c0 = nullptr;
static Device* io_expander0 = nullptr;
static bool did_create_display = false;
static Device* i2c2 = nullptr;
static bool did_create_keyboard = false;
static Device* io_expander1 = nullptr;
static bool did_create_power_control = false;
if (event == DEVICE_EVENT_STARTED) {
if (strcmp(device->name, "i2c0") == 0) {
i2c0 = device;
}
if (strcmp(device->name, "io_expander0") == 0) {
io_expander0 = device;
}
if (strcmp(device->name, "i2c2") == 0) {
i2c2 = device;
}
if (strcmp(device->name, "io_expander1") == 0) {
io_expander1 = device;
}
}
if (io_expander0 != nullptr && tab5_get_variant() == Tab5Variant::Unknown) {
Tab5Variant variant = tab5_probe_variant(i2c0);
tab5_set_variant(variant);
}
// We need i2c0 and io_expander0 to create the display and touch devices
if (!did_create_display && i2c0 != nullptr && io_expander0 != nullptr) {
did_create_display = true;
if (pulse_display_reset_pins(io_expander0)) {
switch (tab5_get_variant()) {
case Tab5Variant::Unknown:
LOG_E(TAG, "Variant not detected yet");
break;
case Tab5Variant::V1:
tab5_create_devices_v1(i2c0);
break;
case Tab5Variant::V2:
tab5_create_devices_v2(i2c0);
break;
}
} else {
LOG_E(TAG, "display_detect: skipping display creation, failed to pulse reset pins");
}
}
// The keyboard lives on the unrelated i2c2 bus, so this is gated independently.
if (!did_create_keyboard && i2c2 != nullptr) {
did_create_keyboard = true;
tab5_create_keyboard(i2c2);
}
// The charger control lines live on io_expander1, unrelated to the display/keyboard buses.
if (!did_create_power_control && io_expander1 != nullptr) {
did_create_power_control = true;
tab5_create_power_control(io_expander1);
}
}
void tab5_detect_start() {
device_listener_add(on_display_detect_event, nullptr);
}
void tab5_detect_stop() {
device_listener_remove(on_display_detect_event);
}