Ken Van Hoeylandt d2048e01b6
Tab5 power expander driver and devicetree parsing improvements (#507)
* **New Features**
  * PI4IOE5V6408 I2C I/O expander driver with public GPIO APIs
  * CLI tool to list devicetree dependencies

* **Device Tree Updates**
  * M5Stack Tab5 configured with two I2C IO expanders; PI4IOE5V6408 binding added

* **Build / Tooling**
  * Devicetree code generation integrated into build; generated artifacts and dynamic dependency resolution exposed

* **Refactor**
  * Kernel/run APIs updated to accept a null‑terminated devicetree modules array; many module symbols renamed

* **Documentation**
  * Added README and Apache‑2.0 license for new driver module
2026-02-17 22:59:30 +01:00

100 lines
4.1 KiB
C++

// SPDX-License-Identifier: Apache-2.0
#include <drivers/pi4ioe5v6408.h>
#include <pi4ioe5v6408_module.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/log.h>
#define TAG "PI4IOE5V6408"
#define GET_CONFIG(device) (static_cast<const Pi4ioe5v6408Config*>((device)->config))
constexpr auto PI4_REGISTER_DIRECTION = 0x03;
constexpr auto PI4_REGISTER_OUTPUT_LEVEL = 0x05;
constexpr auto PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE = 0x07;
constexpr auto PI4_REGISTER_INPUT_DEFAULT_LEVEL = 0x09;
constexpr auto PI4_REGISTER_PULL_ENABLE = 0x0B;
constexpr auto PI4_REGISTER_PULL_SELECT = 0x0D;
constexpr auto PI4_REGISTER_INPUT_LEVEL = 0x0F;
constexpr auto PI4_REGISTER_INTERRUPT_MASK = 0x11;
constexpr auto PI4_REGISTER_INTERRUPT_LEVEL = 0x13;
static error_t start(Device* device) {
auto* parent = device_get_parent(device);
if (device_get_type(parent) != &I2C_CONTROLLER_TYPE) {
LOG_E(TAG, "Parent device is not I2C");
return ERROR_RESOURCE;
}
LOG_I(TAG, "Started PI4IOE5V6408 device %s", device->name);
return ERROR_NONE;
}
static error_t stop(Device* device) {
return ERROR_NONE;
}
extern "C" {
error_t pi4ioe5v6408_set_direction(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_DIRECTION, bits, timeout);
}
error_t pi4ioe5v6408_set_output_level(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_OUTPUT_LEVEL, bits, timeout);
}
error_t pi4ioe5v6408_get_output_level(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_OUTPUT_LEVEL, bits, timeout);
}
error_t pi4ioe5v6408_set_output_high_impedance(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_OUTPUT_HIGH_IMPEDANCE, bits, timeout);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
Driver pi4ioe5v6408_driver = {
.name = "pi4ioe5v6408",
.compatible = (const char*[]) { "diodes,pi4ioe5v6408", nullptr},
.start_device = start,
.stop_device = stop,
.api = nullptr,
.device_type = nullptr,
.owner = &pi4ioe5v6408_module,
.internal = nullptr
};
}