diff --git a/Devices/m5stack-tab5/Source/Configuration.cpp b/Devices/m5stack-tab5/Source/Configuration.cpp index d17d47e4..4566b6db 100644 --- a/Devices/m5stack-tab5/Source/Configuration.cpp +++ b/Devices/m5stack-tab5/Source/Configuration.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace tt::hal; @@ -19,50 +20,110 @@ static DeviceVector createDevices() { }; } -static error_t initPower(::Device* io_expander0, ::Device* io_expander1) { +/* + PI4IOE5V6408-0 (0x43) + - Bit 0: RF internal/external switch + - Bit 1: Speaker enable + - Bit 2: External 5V bus enable + - Bit 3: / + - Bit 4: LCD reset + - Bit 5: Touch reset + - Bit 6: Camera reset + - Bit 7: Headphone detect + */ +constexpr auto GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL = 0; +constexpr auto GPIO_EXP0_PIN_SPEAKER_ENABLE = 1; +constexpr auto GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE = 2; +constexpr auto GPIO_EXP0_PIN_LCD_RESET = 4; +constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5; +constexpr auto GPIO_EXP0_PIN_CAMERA_RESET = 6; +constexpr auto GPIO_EXP0_PIN_HEADPHONE_DETECT = 7; + +/* + PI4IOE5V6408-1 (0x44) + - Bit 0: C6 WLAN enable + - Bit 1: / + - Bit 2: / + - Bit 3: USB-A 5V enable + - Bit 4: Device power: PWROFF_PLUSE + - Bit 5: IP2326: nCHG_QC_EN + - Bit 6: IP2326: CHG_STAT_LED + - Bit 7: IP2326: CHG_EN +*/ +constexpr auto GPIO_EXP1_PIN_C6_WLAN_ENABLE = 0; +constexpr auto GPIO_EXP1_PIN_USB_A_5V_ENABLE = 3; +constexpr auto GPIO_EXP1_PIN_DEVICE_POWER = 4; +constexpr auto GPIO_EXP1_PIN_IP2326_NCHG_QC_EN = 5; +constexpr auto GPIO_EXP1_PIN_IP2326_CHG_STAT_LED = 6; +constexpr auto GPIO_EXP1_PIN_IP2326_CHG_EN = 7; + +static void initExpander0(::Device* io_expander0) { constexpr TickType_t i2c_timeout = pdMS_TO_TICKS(10); - /* - PI4IOE5V6408-0 (0x43) - - Bit 0: RF internal/external switch - - Bit 1: Speaker enable - - Bit 2: External 5V bus enable - - Bit 3: / - - Bit 4: LCD reset - - Bit 5: Touch reset - - Bit 6: Camera reset - - Bit 7: Headphone detect - */ + auto* rf_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL, GPIO_OWNER_GPIO); + auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO); + auto* external_5v_bus_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE, GPIO_OWNER_GPIO); + 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); + auto* camera_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_CAMERA_RESET, GPIO_OWNER_GPIO); + auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO); - check(pi4ioe5v6408_set_direction(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_output_level(io_expander0, 0b01000110, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_output_high_impedance(io_expander0, 0b00000000, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_pull_select(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_pull_enable(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE); + gpio_descriptor_set_flags(rf_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(speaker_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(external_5v_bus_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT); + 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_flags(camera_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(headphone_detect_pin, GPIO_FLAG_DIRECTION_INPUT); + + gpio_descriptor_set_level(rf_pin, false); + gpio_descriptor_set_level(speaker_enable_pin, false); + gpio_descriptor_set_level(external_5v_bus_enable_pin, true); + gpio_descriptor_set_level(lcd_reset_pin, false); + gpio_descriptor_set_level(touch_reset_pin, false); + gpio_descriptor_set_level(camera_reset_pin, true); vTaskDelay(pdMS_TO_TICKS(10)); - check(pi4ioe5v6408_set_output_level(io_expander0, 0b01110110, i2c_timeout) == ERROR_NONE); + // Enable touch and lcd, but not the camera + gpio_descriptor_set_level(lcd_reset_pin, true); + gpio_descriptor_set_level(touch_reset_pin, true); - /* - PI4IOE5V6408-1 (0x44) - - Bit 0: C6 WLAN enable - - Bit 1: / - - Bit 2: / - - Bit 3: USB-A 5V enable - - Bit 4: Device power: PWROFF_PLUSE - - Bit 5: IP2326: nCHG_QC_EN - - Bit 6: IP2326: CHG_STAT_LED - - Bit 7: IP2326: CHG_EN - */ + gpio_descriptor_release(rf_pin); + gpio_descriptor_release(speaker_enable_pin); + gpio_descriptor_release(external_5v_bus_enable_pin); + gpio_descriptor_release(lcd_reset_pin); + gpio_descriptor_release(touch_reset_pin); + gpio_descriptor_release(camera_reset_pin); + gpio_descriptor_release(headphone_detect_pin); +} - check(pi4ioe5v6408_set_direction(io_expander1, 0b10111001, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_output_high_impedance(io_expander1, 0b00000110, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_pull_select(io_expander1, 0b10111001, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_pull_enable(io_expander1, 0b11111001, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_input_default_level(io_expander1, 0b01000000, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_interrupt_mask(io_expander1, 0b10111111, i2c_timeout) == ERROR_NONE); - check(pi4ioe5v6408_set_output_level(io_expander1, 0b10001001, i2c_timeout) == ERROR_NONE); +static void initExpander1(::Device* io_expander1) { - return ERROR_NONE; + auto* c6_wlan_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_C6_WLAN_ENABLE, GPIO_OWNER_GPIO); + auto* usb_a_5v_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_USB_A_5V_ENABLE, GPIO_OWNER_GPIO); + auto* device_power_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO); + auto* ip2326_ncharge_qc_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_OWNER_GPIO); + auto* ip2326_charge_state_led_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_STAT_LED, GPIO_OWNER_GPIO); + auto* ip2326_charge_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_OWNER_GPIO); + + gpio_descriptor_set_flags(c6_wlan_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(usb_a_5v_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(device_power_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(ip2326_ncharge_qc_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(ip2326_charge_state_led_pin, GPIO_FLAG_DIRECTION_OUTPUT); + gpio_descriptor_set_flags(ip2326_charge_enable_pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP); + + gpio_descriptor_set_level(c6_wlan_enable_pin, true); + gpio_descriptor_set_level(usb_a_5v_enable_pin, true); + gpio_descriptor_set_level(device_power_pin, false); + gpio_descriptor_set_level(ip2326_ncharge_qc_enable_pin, false); + gpio_descriptor_set_level(ip2326_charge_state_led_pin, false); + + gpio_descriptor_release(c6_wlan_enable_pin); + gpio_descriptor_release(usb_a_5v_enable_pin); + gpio_descriptor_release(device_power_pin); + gpio_descriptor_release(ip2326_ncharge_qc_enable_pin); + gpio_descriptor_release(ip2326_charge_state_led_pin); + gpio_descriptor_release(ip2326_charge_enable_pin); } static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = nullptr) { @@ -113,13 +174,11 @@ static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = null return error; } - uint8_t output_level = 0; - if (pi4ioe5v6408_get_output_level(io_expander0, &output_level, pdMS_TO_TICKS(100)) != ERROR_NONE) { - LOG_E(TAG, "Failed to read power level: %s", error_to_string(error)); - return ERROR_RESOURCE; - } - - if (pi4ioe5v6408_set_output_level(io_expander0, output_level | 0b00000010, pdMS_TO_TICKS(100)) != ERROR_NONE) { + 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 = 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)); return ERROR_RESOURCE; } @@ -132,10 +191,12 @@ static bool initBoot() { check(i2c0, "i2c0 not found"); auto* io_expander0 = device_find_by_name("io_expander0"); + check(io_expander0, "io_expander0 not found"); auto* io_expander1 = device_find_by_name("io_expander1"); - check(i2c0, "i2c0 not found"); + check(io_expander1, "io_expander1 not found"); - initPower(io_expander0, io_expander1); + initExpander0(io_expander0); + initExpander1(io_expander1); error_t error = initSound(i2c0, io_expander0); if (error != ERROR_NONE) { diff --git a/Drivers/pi4ioe5v6408-module/include/drivers/pi4ioe5v6408.h b/Drivers/pi4ioe5v6408-module/include/drivers/pi4ioe5v6408.h index 93f98274..8ca85a02 100644 --- a/Drivers/pi4ioe5v6408-module/include/drivers/pi4ioe5v6408.h +++ b/Drivers/pi4ioe5v6408-module/include/drivers/pi4ioe5v6408.h @@ -2,40 +2,16 @@ #pragma once #include -#include -#include #ifdef __cplusplus extern "C" { #endif -struct Device; - struct Pi4ioe5v6408Config { /** Address on bus */ uint8_t address; }; -error_t pi4ioe5v6408_set_direction(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_output_level(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_get_output_level(struct Device* device, uint8_t* bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_output_high_impedance(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_input_default_level(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_pull_enable(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_pull_select(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_get_input_level(struct Device* device, uint8_t* bits, TickType_t timeout); - -error_t pi4ioe5v6408_set_interrupt_mask(struct Device* device, uint8_t bits, TickType_t timeout); - -error_t pi4ioe5v6408_get_interrupt_level(struct Device* device, uint8_t* bits, TickType_t timeout); - #ifdef __cplusplus } #endif diff --git a/Drivers/pi4ioe5v6408-module/source/module.cpp b/Drivers/pi4ioe5v6408-module/source/module.cpp index d5c31f45..bb744edc 100644 --- a/Drivers/pi4ioe5v6408-module/source/module.cpp +++ b/Drivers/pi4ioe5v6408-module/source/module.cpp @@ -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 }; diff --git a/Drivers/pi4ioe5v6408-module/source/pi4ioe5v6408.cpp b/Drivers/pi4ioe5v6408-module/source/pi4ioe5v6408.cpp index fdc1e94a..82b765c6 100644 --- a/Drivers/pi4ioe5v6408-module/source/pi4ioe5v6408.cpp +++ b/Drivers/pi4ioe5v6408-module/source/pi4ioe5v6408.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -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(&pi4_gpio_api), + .device_type = &GPIO_CONTROLLER_TYPE, .owner = &pi4ioe5v6408_module, .internal = nullptr }; diff --git a/Drivers/pi4ioe5v6408-module/source/symbols.c b/Drivers/pi4ioe5v6408-module/source/symbols.c deleted file mode 100644 index ea1dc7a3..00000000 --- a/Drivers/pi4ioe5v6408-module/source/symbols.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -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 -}; diff --git a/Platforms/platform-esp32/source/drivers/esp32_gpio.cpp b/Platforms/platform-esp32/source/drivers/esp32_gpio.cpp index 802b945f..64ae3c63 100644 --- a/Platforms/platform-esp32/source/drivers/esp32_gpio.cpp +++ b/Platforms/platform-esp32/source/drivers/esp32_gpio.cpp @@ -17,7 +17,7 @@ struct Esp32GpioInternal { }; #define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config) -#define GET_INTERNAL(device) ((struct Esp32GpioInternal*)device->internal) +#define GET_INTERNAL_FROM_DESCRIPTOR(gpio_descriptor) ((struct Esp32GpioInternal*)gpio_descriptor->controller_context) extern "C" { @@ -102,18 +102,18 @@ static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_numbe return ERROR_NONE; } -static error_t add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg) { +static error_t add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) { auto esp_error = gpio_isr_handler_add(static_cast(descriptor->pin), callback, arg); return esp_err_to_error(esp_error); } -static error_t remove_callback(struct GpioDescriptor* descriptor) { +static error_t remove_callback(GpioDescriptor* descriptor) { auto esp_error = gpio_isr_handler_remove(static_cast(descriptor->pin)); return esp_err_to_error(esp_error); } -static error_t enable_interrupt(struct GpioDescriptor* descriptor) { - auto* internal = GET_INTERNAL(descriptor->controller); +static error_t enable_interrupt(GpioDescriptor* descriptor) { + auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor); if (internal->isr_service_ref_count == 0) { auto esp_error = gpio_install_isr_service(0); if (esp_error != ESP_OK && esp_error != ESP_ERR_INVALID_STATE) { @@ -127,8 +127,8 @@ static error_t enable_interrupt(struct GpioDescriptor* descriptor) { return esp_err_to_error(esp_error); } -static error_t disable_interrupt(struct GpioDescriptor* descriptor) { - auto* internal = GET_INTERNAL(descriptor->controller); +static error_t disable_interrupt(GpioDescriptor* descriptor) { + auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor); auto esp_error = gpio_intr_disable(static_cast(descriptor->pin)); if (esp_error == ESP_OK && internal->isr_service_ref_count > 0) { internal->isr_service_ref_count--; @@ -142,18 +142,18 @@ static error_t disable_interrupt(struct GpioDescriptor* descriptor) { static error_t start(Device* device) { ESP_LOGI(TAG, "start %s", device->name); const Esp32GpioConfig* config = GET_CONFIG(device); - device_set_driver_data(device, new Esp32GpioInternal()); - return gpio_controller_init_descriptors(device, config->gpioCount, nullptr); + auto* internal = new Esp32GpioInternal(); + return gpio_controller_init_descriptors(device, config->gpioCount, internal); } static error_t stop(Device* device) { ESP_LOGI(TAG, "stop %s", device->name); - auto* internal = GET_INTERNAL(device); + auto* internal = static_cast(gpio_controller_get_controller_context(device)); if (internal->isr_service_ref_count > 0) { gpio_uninstall_isr_service(); } - check(gpio_controller_deinit_descriptors(device) == ERROR_NONE); delete internal; + check(gpio_controller_deinit_descriptors(device) == ERROR_NONE); return ERROR_NONE; } @@ -169,14 +169,14 @@ const static GpioControllerApi esp32_gpio_api = { .disable_interrupt = disable_interrupt }; -extern struct Module platform_esp32_module; +extern Module platform_esp32_module; Driver esp32_gpio_driver = { .name = "esp32_gpio", .compatible = (const char*[]) { "espressif,esp32-gpio", nullptr }, .start_device = start, .stop_device = stop, - .api = (void*)&esp32_gpio_api, + .api = static_cast(&esp32_gpio_api), .device_type = &GPIO_CONTROLLER_TYPE, .owner = &platform_esp32_module, .internal = nullptr diff --git a/TactilityKernel/include/tactility/drivers/gpio.h b/TactilityKernel/include/tactility/drivers/gpio.h index 835ff573..e7a35771 100644 --- a/TactilityKernel/include/tactility/drivers/gpio.h +++ b/TactilityKernel/include/tactility/drivers/gpio.h @@ -7,7 +7,6 @@ extern "C" { #endif #include -#include #include #define GPIO_FLAGS_MASK 0x1f @@ -27,6 +26,7 @@ extern "C" { #define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5] #define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5) #define GPIO_FLAG_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5)) +#define GPIO_FLAG_HIGH_IMPEDANCE (1 << 8) typedef enum { GPIO_INTERRUPT_DISABLE = 0, diff --git a/TactilityKernel/include/tactility/drivers/gpio_controller.h b/TactilityKernel/include/tactility/drivers/gpio_controller.h index 796041b5..9cdd2883 100644 --- a/TactilityKernel/include/tactility/drivers/gpio_controller.h +++ b/TactilityKernel/include/tactility/drivers/gpio_controller.h @@ -201,6 +201,15 @@ error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_cou */ error_t gpio_controller_deinit_descriptors(struct Device* device); +/** + * Unlike other drivers, a GPIO controller's internal data is created and set by gpio_controller_init_descriptors() + * This means that the specific controller implementation cannot set the device's driver data, as it's already set by the GPIO controller base coded. + * When calling init descriptors, the caller can pass a controller_context, which is an optional pointer that holds the implementation's internal data. + * @param device the GPIO controller device + * @return ERROR_NONE if successful + */ +void* gpio_controller_get_controller_context(struct Device* device); + extern const struct DeviceType GPIO_CONTROLLER_TYPE; #ifdef __cplusplus diff --git a/TactilityKernel/include/tactility/drivers/gpio_descriptor.h b/TactilityKernel/include/tactility/drivers/gpio_descriptor.h index 383961aa..80d4d52b 100644 --- a/TactilityKernel/include/tactility/drivers/gpio_descriptor.h +++ b/TactilityKernel/include/tactility/drivers/gpio_descriptor.h @@ -11,6 +11,11 @@ struct GpioDescriptor { gpio_pin_t pin; /** @brief Current owner */ enum GpioOwnerType owner_type; - /** @brief Implementation-specific context (e.g. from esp32 controller internally) */ + /** + * @brief Implementation-specific context (e.g. from esp32 controller internally) + * Unlike other drivers, a GPIO controller's internal data is created and set by gpio_controller_init_descriptors() + * This means that the specific controller implementation cannot set the device's driver data, as it's already set by the GPIO controller base coded. + * When calling init descriptors, the caller can pass a controller_context, which is an optional pointer that holds the implementation's internal data. + */ void* controller_context; }; diff --git a/TactilityKernel/source/drivers/gpio_controller.cpp b/TactilityKernel/source/drivers/gpio_controller.cpp index 76b0ce1f..c2e2bfae 100644 --- a/TactilityKernel/source/drivers/gpio_controller.cpp +++ b/TactilityKernel/source/drivers/gpio_controller.cpp @@ -14,22 +14,25 @@ extern "C" { struct GpioControllerData { - struct Mutex mutex {}; + Mutex mutex {}; uint32_t pin_count; - struct GpioDescriptor* descriptors = nullptr; + GpioDescriptor* descriptors = nullptr; + void* controller_context; - explicit GpioControllerData(uint32_t pin_count) : pin_count(pin_count) { + explicit GpioControllerData( + uint32_t pin_count, void* controller_context + ) : pin_count(pin_count), controller_context(controller_context) { mutex_construct(&mutex); } - error_t init_descriptors(Device* device, void* controller_context) { - descriptors = (struct GpioDescriptor*)calloc(pin_count, sizeof(struct GpioDescriptor)); + error_t init_descriptors(Device* device) { + descriptors = static_cast(calloc(pin_count, sizeof(GpioDescriptor))); if (!descriptors) return ERROR_OUT_OF_MEMORY; for (uint32_t i = 0; i < pin_count; ++i) { descriptors[i].controller = device; - descriptors[i].pin = (gpio_pin_t)i; + descriptors[i].pin = static_cast(i); descriptors[i].owner_type = GPIO_OWNER_NONE; - descriptors[i].controller_context = controller_context; + descriptors[i].controller_context = this->controller_context; } return ERROR_NONE; } @@ -42,14 +45,14 @@ struct GpioControllerData { } }; -struct GpioDescriptor* gpio_descriptor_acquire( - struct Device* controller, +GpioDescriptor* gpio_descriptor_acquire( + Device* controller, gpio_pin_t pin_number, - enum GpioOwnerType owner + GpioOwnerType owner ) { check(owner != GPIO_OWNER_NONE); - auto* data = (struct GpioControllerData*)device_get_driver_data(controller); + auto* data = static_cast(device_get_driver_data(controller)); mutex_lock(&data->mutex); if (pin_number >= data->pin_count) { @@ -57,7 +60,7 @@ struct GpioDescriptor* gpio_descriptor_acquire( return nullptr; } - struct GpioDescriptor* desc = &data->descriptors[pin_number]; + GpioDescriptor* desc = &data->descriptors[pin_number]; if (desc->owner_type != GPIO_OWNER_NONE) { mutex_unlock(&data->mutex); return nullptr; @@ -69,22 +72,22 @@ struct GpioDescriptor* gpio_descriptor_acquire( return desc; } -error_t gpio_descriptor_release(struct GpioDescriptor* descriptor) { +error_t gpio_descriptor_release(GpioDescriptor* descriptor) { descriptor->owner_type = GPIO_OWNER_NONE; return ERROR_NONE; } -error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count) { - auto* data = (struct GpioControllerData*)device_get_driver_data(device); +error_t gpio_controller_get_pin_count(Device* device, uint32_t* count) { + auto* data = static_cast(device_get_driver_data(device)); *count = data->pin_count; return ERROR_NONE; } -error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context) { - auto* data = new(std::nothrow) GpioControllerData(pin_count); +error_t gpio_controller_init_descriptors(Device* device, uint32_t pin_count, void* controller_context) { + auto* data = new(std::nothrow) GpioControllerData(pin_count, controller_context); if (!data) return ERROR_OUT_OF_MEMORY; - if (data->init_descriptors(device, controller_context) != ERROR_NONE) { + if (data->init_descriptors(device) != ERROR_NONE) { delete data; return ERROR_OUT_OF_MEMORY; } @@ -93,77 +96,82 @@ error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_cou return ERROR_NONE; } -error_t gpio_controller_deinit_descriptors(struct Device* device) { +error_t gpio_controller_deinit_descriptors(Device* device) { auto* data = static_cast(device_get_driver_data(device)); delete data; device_set_driver_data(device, nullptr); return ERROR_NONE; } -error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high) { +void* gpio_controller_get_controller_context(Device* device) { + auto* data = static_cast(device_get_driver_data(device)); + return data->controller_context; +} + +error_t gpio_descriptor_set_level(GpioDescriptor* descriptor, bool high) { const auto* driver = device_get_driver(descriptor->controller); return GPIO_INTERNAL_API(driver)->set_level(descriptor, high); } -error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high) { +error_t gpio_descriptor_get_level(GpioDescriptor* descriptor, bool* high) { const auto* driver = device_get_driver(descriptor->controller); return GPIO_INTERNAL_API(driver)->get_level(descriptor, high); } -error_t gpio_descriptor_set_flags(struct GpioDescriptor* descriptor, gpio_flags_t flags) { +error_t gpio_descriptor_set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) { const auto* driver = device_get_driver(descriptor->controller); return GPIO_INTERNAL_API(driver)->set_flags(descriptor, flags); } -error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_t* flags) { +error_t gpio_descriptor_get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) { const auto* driver = device_get_driver(descriptor->controller); return GPIO_INTERNAL_API(driver)->get_flags(descriptor, flags); } -error_t gpio_descriptor_get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin) { +error_t gpio_descriptor_get_pin_number(GpioDescriptor* descriptor, gpio_pin_t* pin) { *pin = descriptor->pin; return ERROR_NONE; } -error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number) { +error_t gpio_descriptor_get_native_pin_number(GpioDescriptor* descriptor, void* pin_number) { const auto* driver = device_get_driver(descriptor->controller); return GPIO_INTERNAL_API(driver)->get_native_pin_number(descriptor, pin_number); } -error_t gpio_descriptor_add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg) { +error_t gpio_descriptor_add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) { const auto* driver = device_get_driver(descriptor->controller); auto* api = GPIO_INTERNAL_API(driver); if (!api->add_callback) return ERROR_NOT_SUPPORTED; return api->add_callback(descriptor, callback, arg); } -error_t gpio_descriptor_remove_callback(struct GpioDescriptor* descriptor) { +error_t gpio_descriptor_remove_callback(GpioDescriptor* descriptor) { const auto* driver = device_get_driver(descriptor->controller); auto* api = GPIO_INTERNAL_API(driver); if (!api->remove_callback) return ERROR_NOT_SUPPORTED; return api->remove_callback(descriptor); } -error_t gpio_descriptor_enable_interrupt(struct GpioDescriptor* descriptor) { +error_t gpio_descriptor_enable_interrupt(GpioDescriptor* descriptor) { const auto* driver = device_get_driver(descriptor->controller); auto* api = GPIO_INTERNAL_API(driver); if (!api->enable_interrupt) return ERROR_NOT_SUPPORTED; return api->enable_interrupt(descriptor); } -error_t gpio_descriptor_disable_interrupt(struct GpioDescriptor* descriptor) { +error_t gpio_descriptor_disable_interrupt(GpioDescriptor* descriptor) { const auto* driver = device_get_driver(descriptor->controller); auto* api = GPIO_INTERNAL_API(driver); if (!api->disable_interrupt) return ERROR_NOT_SUPPORTED; return api->disable_interrupt(descriptor); } -error_t gpio_descriptor_get_owner_type(struct GpioDescriptor* descriptor, GpioOwnerType* owner_type) { +error_t gpio_descriptor_get_owner_type(GpioDescriptor* descriptor, GpioOwnerType* owner_type) { *owner_type = descriptor->owner_type; return ERROR_NONE; } -const struct DeviceType GPIO_CONTROLLER_TYPE { +const DeviceType GPIO_CONTROLLER_TYPE { .name = "gpio-controller" };