Files
2026-07-20 23:43:17 +02:00

111 lines
3.6 KiB
C++

#include <tactility/module.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/device_listener.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/log.h>
#include <cstring>
#include "devices/detect.h"
#include "devices/tab5_headphone_detect.h"
#include "devices/tab5_keyboard.h"
#include "devices/tab5_power_control.h"
#include "devices/tab_5_camera.h"
#define TAG "Tab5"
// PI4IOE5V6408-0 (0x43) bit 1
constexpr auto GPIO_EXP0_PIN_SPEAKER_ENABLE = 1;
// PI4IOE5V6408-0 (0x43) bit 7
constexpr auto GPIO_EXP0_PIN_HEADPHONE_DETECT = 7;
static void tab5_init_expander0(Device* io_expander0) {
// Speaker and heapdhone pins are managed at runtime, so we can't have them as a hog in the dts file
// We have to init them manually.
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
check(speaker_enable_pin);
auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO);
check(headphone_detect_pin);
gpio_descriptor_set_flags(speaker_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_flags(headphone_detect_pin, GPIO_FLAG_DIRECTION_INPUT);
gpio_descriptor_set_level(speaker_enable_pin, false);
gpio_descriptor_release(speaker_enable_pin);
gpio_descriptor_release(headphone_detect_pin);
}
static void tab5_enable_speaker_amp(Device* io_expander0) {
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
check(speaker_enable_pin, "Failed to acquire speaker enable pin");
error_t error = gpio_descriptor_set_level(speaker_enable_pin, true);
gpio_descriptor_release(speaker_enable_pin);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to enable amplifier: %s", error_to_string(error));
}
}
// Fires for every device's start/stop in the system; initializes io_expander0's pins and enables
// the speaker amplifier once io_expander0 itself has started.
static void on_io_expander0_started(Device* device, DeviceEvent event, void* context) {
(void)context;
static bool did_init = false;
if (did_init || event != DEVICE_EVENT_STARTED || strcmp(device->name, "io_expander0") != 0) {
return;
}
did_init = true;
tab5_init_expander0(device);
tab5_enable_speaker_amp(device);
}
extern "C" {
static error_t start() {
/* 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(&tab5_keyboard_driver) == ERROR_NONE);
check(driver_construct_add(&tab5_power_control_driver) == ERROR_NONE);
tab5_detect_start();
tab5_camera_init();
device_listener_add(on_io_expander0_started, nullptr);
tab5_headphone_detect_start();
return ERROR_NONE;
}
static error_t stop() {
tab5_headphone_detect_stop();
device_listener_remove(on_io_expander0_started);
tab5_detect_stop();
/* 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(&tab5_keyboard_driver) == ERROR_NONE);
check(driver_remove_destruct(&tab5_power_control_driver) == ERROR_NONE);
return ERROR_NONE;
}
Module m5stack_tab5_module = {
.name = "m5stack-tab5",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}