New kernel drivers, filesystem API, and more (#513)

* **New Features**
  * BMI270 6-axis IMU driver added; new unified filesystem abstraction for mounted filesystems.
  * Public Wi‑Fi API surface (no implementation yet)
  * SDMMC driver added (kernel drive$)
  * expanded GPIO interrupt/callback support
* **Improvements**
  * M5Stack Tab5: revamped GPIO/power initialization and IMU integration.
  * LVGL updates including device fontSize configuration.
  * Updated all code related to SD card device/fs handling
  * Rename LilyGO T-HMI S3 to LilyGO T-HMI
* **Bug Fixes**
  * Simplified and consolidated SD card handling and mount discovery.
This commit is contained in:
Ken Van Hoeylandt
2026-03-07 16:13:39 +01:00
committed by GitHub
parent 2de35b2d2d
commit aa7530e515
88 changed files with 2792 additions and 846 deletions
@@ -6,7 +6,6 @@
extern "C" {
extern Driver pi4ioe5v6408_driver;
extern const ModuleSymbol pi4ioe5v6408_module_symbols[];
static error_t start() {
/* We crash when construct fails, because if a single driver fails to construct,
@@ -26,7 +25,7 @@ Module pi4ioe5v6408_module = {
.name = "pi4ioe5v6408",
.start = start,
.stop = stop,
.symbols = pi4ioe5v6408_module_symbols,
.symbols = nullptr,
.internal = nullptr
};
@@ -3,6 +3,8 @@
#include <pi4ioe5v6408_module.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/log.h>
@@ -27,72 +29,181 @@ static error_t start(Device* device) {
return ERROR_RESOURCE;
}
LOG_I(TAG, "Started PI4IOE5V6408 device %s", device->name);
return ERROR_NONE;
return gpio_controller_init_descriptors(device, 8, nullptr);
}
static error_t stop(Device* device) {
check(gpio_controller_deinit_descriptors(device) == ERROR_NONE);
return ERROR_NONE;
}
extern "C" {
error_t pi4ioe5v6408_set_direction(Device* device, uint8_t bits, TickType_t timeout) {
static error_t set_level(GpioDescriptor* descriptor, bool high) {
auto* device = descriptor->controller;
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_DIRECTION, bits, timeout);
auto address = GET_CONFIG(device)->address;
uint8_t bit = 1 << descriptor->pin;
if (high) {
return i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY);
} else {
return i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY);
}
}
error_t pi4ioe5v6408_set_output_level(Device* device, uint8_t bits, TickType_t timeout) {
static error_t get_level(GpioDescriptor* descriptor, bool* high) {
auto* device = descriptor->controller;
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_LEVEL, bits, timeout);
auto address = GET_CONFIG(device)->address;
uint8_t bits;
error_t err = i2c_controller_register8_get(parent, address, PI4_REGISTER_INPUT_LEVEL, &bits, portMAX_DELAY);
if (err != ERROR_NONE) {
return err;
}
*high = (bits & (1 << descriptor->pin)) != 0;
return ERROR_NONE;
}
error_t pi4ioe5v6408_get_output_level(Device* device, uint8_t* bits, TickType_t timeout) {
static error_t set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) {
auto* device = descriptor->controller;
auto* parent = device_get_parent(device);
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_LEVEL, bits, timeout);
auto address = GET_CONFIG(device)->address;
uint8_t bit = 1 << descriptor->pin;
error_t err;
// Direction
if (flags & GPIO_FLAG_DIRECTION_OUTPUT) {
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_DIRECTION, bit, portMAX_DELAY);
} else {
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_DIRECTION, bit, portMAX_DELAY);
}
if (err != ERROR_NONE) {
return err;
}
// High Impedance
if (flags & GPIO_FLAG_HIGH_IMPEDANCE) {
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bit, portMAX_DELAY);
} else {
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bit, portMAX_DELAY);
}
if (err != ERROR_NONE) {
return err;
}
// Pull-up/down
if (flags & (GPIO_FLAG_PULL_UP | GPIO_FLAG_PULL_DOWN)) {
// Set pull up or pull down
if (flags & GPIO_FLAG_PULL_UP) {
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_PULL_SELECT, bit, portMAX_DELAY);
} else {
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_PULL_SELECT, bit, portMAX_DELAY);
}
if (err != ERROR_NONE) {
return err;
}
// Enable pull-up/down
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_PULL_ENABLE, bit, portMAX_DELAY);
} else {
// Disable pull-up/down
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_PULL_ENABLE, bit, portMAX_DELAY);
}
return err;
}
error_t pi4ioe5v6408_set_output_high_impedance(struct Device* device, uint8_t bits, TickType_t timeout) {
static error_t get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
auto* device = descriptor->controller;
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bits, timeout);
auto address = GET_CONFIG(device)->address;
uint8_t bit = 1 << descriptor->pin;
uint8_t val;
error_t err;
gpio_flags_t f = GPIO_FLAG_NONE;
// Direction
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_DIRECTION, &val, portMAX_DELAY);
if (err != ERROR_NONE) return err;
if (val & bit) {
f |= GPIO_FLAG_DIRECTION_OUTPUT;
} else {
f |= GPIO_FLAG_DIRECTION_INPUT;
}
// Pull-up/down
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_PULL_ENABLE, &val, portMAX_DELAY);
if (err != ERROR_NONE) return err;
if (val & bit) {
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_PULL_SELECT, &val, portMAX_DELAY);
if (err != ERROR_NONE) return err;
if (val & bit) {
f |= GPIO_FLAG_PULL_UP;
} else {
f |= GPIO_FLAG_PULL_DOWN;
}
}
// High Impedance
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, &val, portMAX_DELAY);
if (err != ERROR_NONE) return err;
if (val & bit) {
f |= GPIO_FLAG_HIGH_IMPEDANCE;
}
*flags = f;
return ERROR_NONE;
}
error_t pi4ioe5v6408_set_input_default_level(struct Device* device, uint8_t bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_INPUT_DEFAULT_LEVEL, bits, timeout);
static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_number) {
return ERROR_NOT_SUPPORTED;
}
error_t pi4ioe5v6408_set_pull_enable(struct Device* device, uint8_t bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_PULL_ENABLE, bits, timeout);
static error_t add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
return ERROR_NOT_SUPPORTED;
}
error_t pi4ioe5v6408_set_pull_select(struct Device* device, uint8_t bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_PULL_SELECT, bits, timeout);
static error_t remove_callback(GpioDescriptor* descriptor) {
return ERROR_NOT_SUPPORTED;
}
error_t pi4ioe5v6408_get_input_level(struct Device* device, uint8_t* bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_INPUT_LEVEL, bits, timeout);
static error_t enable_interrupt(GpioDescriptor* descriptor) {
return ERROR_NOT_SUPPORTED;
}
error_t pi4ioe5v6408_set_interrupt_mask(struct Device* device, uint8_t bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_INTERRUPT_MASK, bits, timeout);
static error_t disable_interrupt(GpioDescriptor* descriptor) {
return ERROR_NOT_SUPPORTED;
}
error_t pi4ioe5v6408_get_interrupt_level(struct Device* device, uint8_t* bits, TickType_t timeout) {
auto* parent = device_get_parent(device);
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_INTERRUPT_LEVEL, bits, timeout);
}
const static GpioControllerApi pi4_gpio_api = {
.set_level = set_level,
.get_level = get_level,
.set_flags = set_flags,
.get_flags = get_flags,
.get_native_pin_number = get_native_pin_number,
.add_callback = add_callback,
.remove_callback = remove_callback,
.enable_interrupt = enable_interrupt,
.disable_interrupt = disable_interrupt
};
Driver pi4ioe5v6408_driver = {
.name = "pi4ioe5v6408",
.compatible = (const char*[]) { "diodes,pi4ioe5v6408", nullptr},
.start_device = start,
.stop_device = stop,
.api = nullptr,
.device_type = nullptr,
.api = static_cast<const void*>(&pi4_gpio_api),
.device_type = &GPIO_CONTROLLER_TYPE,
.owner = &pi4ioe5v6408_module,
.internal = nullptr
};
@@ -1,15 +0,0 @@
#include <drivers/pi4ioe5v6408.h>
#include <tactility/module.h>
const struct ModuleSymbol pi4ioe5v6408_module_symbols[] = {
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_direction),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_output_level),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_output_high_impedance),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_input_default_level),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_pull_enable),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_pull_select),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_get_input_level),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_interrupt_mask),
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_get_interrupt_level),
MODULE_SYMBOL_TERMINATOR
};