GPIO descriptor fixes (#578)

This commit is contained in:
Ken Van Hoeylandt
2026-07-22 22:43:34 +02:00
committed by GitHub
parent a3fda9ad8f
commit 8b92aa8e5a
116 changed files with 376 additions and 541 deletions
@@ -17,7 +17,7 @@ struct GpioAdapterContext {
static struct GpioAdapterContext* g_context = NULL;
static struct GpioDescriptor* acquire_descriptor(int16_t gpio) {
static struct GpioDescriptor* acquire_descriptor(int16_t gpio, gpio_flags_t flags) {
if (g_context == NULL || gpio < 0 || (size_t) gpio >= g_context->pin_count) {
return NULL;
}
@@ -31,24 +31,31 @@ static struct GpioDescriptor* acquire_descriptor(int16_t gpio) {
return NULL;
}
struct GpioDescriptor* descriptor = gpio_descriptor_acquire(spec->gpio_controller, spec->pin, GPIO_OWNER_GPIO);
struct GpioDescriptor* descriptor = gpio_descriptor_acquire(
spec->gpio_controller, spec->pin, spec->flags | flags, GPIO_OWNER_GPIO
);
if (descriptor != NULL) {
gpio_descriptor_set_flags(descriptor, spec->flags);
g_context->descriptors[gpio] = descriptor;
}
return descriptor;
}
static int gpio_setup(int16_t gpio, audio_gpio_dir_t dir, audio_gpio_mode_t mode) {
struct GpioDescriptor* descriptor = acquire_descriptor(gpio);
gpio_flags_t flags = (dir == AUDIO_GPIO_DIR_OUT) ? GPIO_FLAG_DIRECTION_OUTPUT : GPIO_FLAG_DIRECTION_INPUT;
if ((mode & AUDIO_GPIO_MODE_PULL_UP) != 0) {
flags |= GPIO_FLAG_PULL_UP;
}
if ((mode & AUDIO_GPIO_MODE_PULL_DOWN) != 0) {
flags |= GPIO_FLAG_PULL_DOWN;
}
struct GpioDescriptor* descriptor = acquire_descriptor(gpio, flags);
if (descriptor == NULL) {
return ESP_CODEC_DEV_NOT_FOUND;
}
gpio_flags_t flags = GPIO_FLAG_NONE;
gpio_descriptor_get_flags(descriptor, &flags);
flags &= ~(GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_PULL_UP | GPIO_FLAG_PULL_DOWN);
flags |= (dir == AUDIO_GPIO_DIR_OUT) ? GPIO_FLAG_DIRECTION_OUTPUT : GPIO_FLAG_DIRECTION_INPUT;
if ((mode & AUDIO_GPIO_MODE_PULL_UP) != 0) {
flags |= GPIO_FLAG_PULL_UP;
@@ -61,7 +68,7 @@ static int gpio_setup(int16_t gpio, audio_gpio_dir_t dir, audio_gpio_mode_t mode
}
static int gpio_set(int16_t gpio, bool high) {
struct GpioDescriptor* descriptor = acquire_descriptor(gpio);
struct GpioDescriptor* descriptor = acquire_descriptor(gpio, GPIO_FLAG_DIRECTION_OUTPUT);
if (descriptor == NULL) {
return ESP_CODEC_DEV_NOT_FOUND;
}
@@ -72,7 +79,7 @@ static int gpio_set(int16_t gpio, bool high) {
// acquire and a legitimate low reading are indistinguishable to the caller; log so the
// failure is at least visible.
static bool gpio_get(int16_t gpio) {
struct GpioDescriptor* descriptor = acquire_descriptor(gpio);
struct GpioDescriptor* descriptor = acquire_descriptor(gpio, GPIO_FLAG_DIRECTION_INPUT);
if (descriptor == NULL) {
LOG_E(TAG, "gpio_get: failed to acquire descriptor for pin %d", gpio);
return false;
+3 -4
View File
@@ -253,15 +253,14 @@ error_t start_device(Device* device) {
// (unlike a board Configuration.cpp initBoot() callback, which only runs after ALL
// devicetree devices, including this one, have already started).
if (config->reset_pin.gpio_controller != nullptr) {
auto* reset_descriptor = gpio_descriptor_acquire(config->reset_pin.gpio_controller, config->reset_pin.pin, GPIO_OWNER_GPIO);
auto* reset_descriptor = gpio_descriptor_acquire(config->reset_pin.gpio_controller, config->reset_pin.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin descriptor");
goto cleanup;
}
gpio_descriptor_set_flags(reset_descriptor, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(reset_descriptor, false);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(reset_descriptor, true);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(reset_descriptor, false);
vTaskDelay(pdMS_TO_TICKS(50));
gpio_descriptor_release(reset_descriptor);
}
+7 -2
View File
@@ -69,7 +69,10 @@ static error_t set_level(GpioDescriptor* descriptor, bool high) {
uint8_t bit = 1U << (descriptor->pin % 8U);
uint8_t reg = portRegister(isPort1, AW9523B_REG_OUTPUT_P0, AW9523B_REG_OUTPUT_P1);
if (high) {
// This chip has no output polarity register: active-low must be inverted in software.
bool physical_high = (descriptor->flags & GPIO_FLAG_ACTIVE_LOW) != 0 ? !high : high;
if (physical_high) {
return i2c_controller_register8_set_bits(parent, address, reg, bit, portMAX_DELAY);
} else {
return i2c_controller_register8_reset_bits(parent, address, reg, bit, portMAX_DELAY);
@@ -90,7 +93,8 @@ static error_t get_level(GpioDescriptor* descriptor, bool* high) {
return err;
}
*high = (bits & bit) != 0;
bool physical_high = (bits & bit) != 0;
*high = (descriptor->flags & GPIO_FLAG_ACTIVE_LOW) != 0 ? !physical_high : physical_high;
return ERROR_NONE;
}
@@ -126,6 +130,7 @@ static error_t get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
// Config register is inverted: 0 = output, 1 = input.
*flags = (val & bit) ? GPIO_FLAG_DIRECTION_INPUT : GPIO_FLAG_DIRECTION_OUTPUT;
*flags |= (descriptor->flags & GPIO_FLAG_ACTIVE_LOW);
return ERROR_NONE;
}
@@ -35,14 +35,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
transmit-timeout:
type: int
default: 100
@@ -19,8 +19,6 @@ struct Axs5106Config {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
// Timeout (ms) for the register-address write half of a read, and for the data-read half,
// done as two separate I2C transactions - matches the vendor factory demo's
// i2c_master_transmit()/i2c_master_receive() split (each with its own 100ms timeout),
+7 -12
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/axs5106.h>
#include <axs5106_module.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
#include <tactility/error.h>
@@ -41,16 +42,10 @@ struct Axs5106Internal {
// region Driver lifecycle
// Matches the vendor demo's touch_axs5106_reset(): pulse the reset pin active for 10ms, then
// release it for 10ms before any I2C traffic. No separate init step follows - the vendor demo's
// touch_axs5106_init() is a no-op too.
static error_t reset_pulse(GpioDescriptor* descriptor, bool active_high) {
bool idle_level = !active_high;
bool ok = gpio_descriptor_set_flags(descriptor, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, active_high) == ERROR_NONE;
static error_t reset_pulse(GpioDescriptor* descriptor) {
bool ok = gpio_descriptor_set_level(descriptor, true) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(10));
ok = ok && gpio_descriptor_set_level(descriptor, idle_level) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, false) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(10));
return ok ? ERROR_NONE : ERROR_RESOURCE;
@@ -73,14 +68,14 @@ static error_t start(Device* device) {
internal->point_count = 0;
if (config->pin_reset.gpio_controller != nullptr) {
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin");
free(internal);
return ERROR_RESOURCE;
}
if (reset_pulse(internal->reset_descriptor, config->reset_active_high) != ERROR_NONE) {
if (reset_pulse(internal->reset_descriptor) != ERROR_NONE) {
LOG_E(TAG, "Failed to pulse reset pin");
gpio_descriptor_release(internal->reset_descriptor);
free(internal);
@@ -1,9 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/button_control.h>
#include <button_control_module.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/keyboard.h>
#include <tactility/error.h>
@@ -72,18 +74,12 @@ static error_t acquire_button(const GpioPinSpec& pin, uint32_t short_press_key,
return ERROR_NONE;
}
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO);
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, pin.flags | GPIO_FLAG_DIRECTION_INPUT, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire GPIO descriptor");
return ERROR_RESOURCE;
}
if (gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_INPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure GPIO as input");
gpio_descriptor_release(descriptor);
return ERROR_RESOURCE;
}
*out_state = {
.descriptor = descriptor,
.in_use = true,
@@ -26,7 +26,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Optional reset GPIO pin. Falls back to a software reset command if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
@@ -17,7 +17,6 @@ struct Cst328Config {
bool mirror_x;
bool mirror_y;
struct GpioPinSpec pin_reset;
bool reset_active_high;
};
#ifdef __cplusplus
+5 -4
View File
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/cst328.h>
#include <cst328_module.h>
#include <tactility/check.h>
#include <tactility/delay.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
@@ -55,12 +57,11 @@ static bool query(Device* i2c, uint8_t address, uint8_t b0, uint8_t b1, uint8_t*
// chip's own software reset command instead.
static void perform_reset(Device* i2c, uint8_t address, const Cst328Config* config) {
if (config->pin_reset.gpio_controller != nullptr) {
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (rst != nullptr) {
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(rst, config->reset_active_high);
gpio_descriptor_set_level(rst, true);
delay_millis(100);
gpio_descriptor_set_level(rst, !config->reset_active_high);
gpio_descriptor_set_level(rst, false);
gpio_descriptor_release(rst);
delay_millis(100);
return;
@@ -35,7 +35,3 @@ properties:
type: phandles
required: true
description: Reset GPIO pin. The chip only re-initializes into normal reporting mode after a clean reset pulse.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
@@ -19,7 +19,6 @@ struct Cst66xxConfig {
bool mirror_x;
bool mirror_y;
struct GpioPinSpec pin_reset;
bool reset_active_high;
};
#ifdef __cplusplus
+9 -5
View File
@@ -1,13 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/cst66xx.h>
#include <cst66xx_module.h>
#include <tactility/check.h>
#include <tactility/delay.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
#include <tactility/error.h>
@@ -61,15 +62,18 @@ static void perform_hardware_reset(const Cst66xxConfig* config) {
return;
}
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
// Not requesting GPIO_FLAG_ACTIVE_LOW here: some GPIO expanders (e.g. xl9555/tca95xx/
// tca9534) can only invert what's read back from an input, not what's driven on an
// output, so they reject ACTIVE_LOW combined with OUTPUT. Drive the raw physical level
// instead: this pin's reset line is active-low, so low asserts and high releases.
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (rst == nullptr) {
return;
}
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(rst, config->reset_active_high);
gpio_descriptor_set_level(rst, false);
delay_millis(10);
gpio_descriptor_set_level(rst, !config->reset_active_high);
gpio_descriptor_set_level(rst, true);
gpio_descriptor_release(rst);
// The reset pulse exits boot mode; give the controller time to re-init.
delay_millis(80);
@@ -35,11 +35,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -22,8 +22,6 @@ struct Cst816sConfig {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+3 -2
View File
@@ -75,9 +75,10 @@ static error_t start(Device* device) {
.y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt),
// CST816S's reset and interrupt lines are both fixed active-low in hardware.
.levels = {
.reset = config->reset_active_high ? 1u : 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u,
.reset = 0u,
.interrupt = 0u,
},
.flags = {
.swap_xy = config->swap_xy ? 1u : 0u,
@@ -35,11 +35,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin (currently unused - reads are polled via read_data())
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -19,8 +19,6 @@ struct Cst816tConfig {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+8 -10
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/cst816t.h>
#include <cst816t_module.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
#include <tactility/error.h>
@@ -44,15 +45,12 @@ struct Cst816tInternal {
// Timings match the reference driver linked above: it holds RST high for 100ms (well past the
// datasheet's Tpor/Tron minimum of 100ms), pulses it low for 10ms (Trst minimum is 0.1ms), then
// waits another 100ms (Tron) for the chip to finish reinitializing before any I2C traffic.
static error_t reset_pulse(GpioDescriptor* descriptor, bool active_high) {
bool idle_level = !active_high;
bool ok = gpio_descriptor_set_flags(descriptor, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, idle_level) == ERROR_NONE;
static error_t reset_pulse(GpioDescriptor* descriptor) {
bool ok = gpio_descriptor_set_level(descriptor, false) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(100));
ok = ok && gpio_descriptor_set_level(descriptor, active_high) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, true) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(10));
ok = ok && gpio_descriptor_set_level(descriptor, idle_level) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, false) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(100));
return ok ? ERROR_NONE : ERROR_RESOURCE;
@@ -77,14 +75,14 @@ static error_t start(Device* device) {
internal->y = 0;
if (config->pin_reset.gpio_controller != nullptr) {
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin");
free(internal);
return ERROR_RESOURCE;
}
if (reset_pulse(internal->reset_descriptor, config->reset_active_high) != ERROR_NONE) {
if (reset_pulse(internal->reset_descriptor) != ERROR_NONE) {
LOG_E(TAG, "Failed to pulse reset pin");
gpio_descriptor_release(internal->reset_descriptor);
free(internal);
@@ -35,11 +35,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -21,8 +21,6 @@ struct Ft5x06Config {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+9 -19
View File
@@ -36,30 +36,26 @@ struct Ft5x06Internal {
// over as if it were one (the previous pin_or_nc() behavior below) silently toggles the wrong,
// unrelated physical pin whenever pin_reset actually points at an I2C expander.
GpioDescriptor* reset_descriptor;
bool reset_active_high;
};
// Only valid for pin_interrupt: esp_lcd_touch only ever reads this pin's level / attaches an ISR
// to it, both of which esp_lcd_touch performs via ESP-IDF's native gpio_* calls, so - like
// ili9341-module's cs/dc pins - it must be a real ESP32 GPIO. pin_reset has no such requirement and
// must never go through this helper; see pulse_reset() instead.
static inline gpio_num_t pin_or_nc(const struct GpioPinSpec& pin) {
static inline gpio_num_t pin_or_nc(const GpioPinSpec& pin) {
return pin.gpio_controller == nullptr ? GPIO_NUM_NC : static_cast<gpio_num_t>(pin.pin);
}
// See esp_lcd_ili9341-module's pulse_reset() for the full rationale; same idea, same 10ms/10ms
// timing (matches esp_lcd_touch_ft5x06's own touch_ft5x06_reset()). esp_lcd_touch's rst_gpio_num is
// always left at GPIO_NUM_NC (see start()), under which it just skips its own reset step entirely.
static error_t pulse_reset(GpioDescriptor* descriptor, bool active_high) {
static error_t pulse_reset(GpioDescriptor* descriptor) {
if (descriptor == nullptr) {
return ERROR_NONE;
}
error_t error = gpio_descriptor_set_level(descriptor, active_high);
error_t error = gpio_descriptor_set_level(descriptor, true);
if (error != ERROR_NONE) {
return error;
}
vTaskDelay(pdMS_TO_TICKS(10));
error = gpio_descriptor_set_level(descriptor, !active_high);
error = gpio_descriptor_set_level(descriptor, false);
if (error != ERROR_NONE) {
return error;
}
@@ -101,20 +97,13 @@ static error_t start(Device* device) {
}
internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) {
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
free(internal);
return ERROR_RESOURCE;
}
if (gpio_descriptor_set_flags(internal->reset_descriptor, config->pin_reset.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure reset pin as output");
gpio_descriptor_release(internal->reset_descriptor);
free(internal);
return ERROR_RESOURCE;
}
}
esp_err_t ret = create_io_handle(parent, &internal->io_handle);
@@ -126,7 +115,7 @@ static error_t start(Device* device) {
return ERROR_RESOURCE;
}
if (pulse_reset(internal->reset_descriptor, internal->reset_active_high) != ERROR_NONE) {
if (pulse_reset(internal->reset_descriptor) != ERROR_NONE) {
LOG_E(TAG, "Failed to pulse reset pin");
esp_lcd_panel_io_del(internal->io_handle);
if (internal->reset_descriptor != nullptr) {
@@ -143,9 +132,10 @@ static error_t start(Device* device) {
// why); esp_lcd_touch just skips its own no-op reset step when this is NC.
.rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = pin_or_nc(config->pin_interrupt),
// FT5x06's reset and interrupt lines are both fixed active-low in hardware.
.levels = {
.reset = config->reset_active_high ? 1u : 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u,
.reset = 0u,
.interrupt = 0u,
},
.flags = {
.swap_xy = config->swap_xy ? 1u : 0u,
@@ -35,11 +35,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -21,8 +21,6 @@ struct Ft6x36Config {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+12 -20
View File
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/ft6x36.h>
#include <ft6x36_module.h>
#include <tactility/check.h>
@@ -7,6 +8,7 @@
#include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
@@ -30,13 +32,7 @@ struct Ft6x36Internal {
esp_lcd_panel_io_handle_t io_handle;
esp_lcd_touch_handle_t touch_handle;
// Non-null when pin_reset is configured. Owned/pulsed by this driver instead of esp_lcd_touch
// (see pulse_reset() below) so the reset pin can live on any GPIO_CONTROLLER, not just native
// gpio0 - esp_lcd_touch's rst_gpio_num only accepts a native ESP32 GPIO number (it calls
// gpio_set_level() directly), and just reading a GpioPinSpec's raw pin index and handing it
// over as if it were one (the previous pin_or_nc() behavior below) silently toggles the wrong,
// unrelated physical pin whenever pin_reset actually points at an I2C expander.
GpioDescriptor* reset_descriptor;
bool reset_active_high;
};
// Only valid for pin_interrupt: esp_lcd_touch only ever reads this pin's level / attaches an ISR
@@ -50,16 +46,18 @@ static inline gpio_num_t pin_or_nc(const struct GpioPinSpec& pin) {
// See ili9341-module's pulse_reset() for the full rationale; same idea, same 10ms/10ms timing.
// esp_lcd_touch's rst_gpio_num is always left at GPIO_NUM_NC (see start()), under which it just
// skips its own reset step entirely.
static error_t pulse_reset(GpioDescriptor* descriptor, bool active_high) {
static error_t pulse_reset(GpioDescriptor* descriptor) {
if (descriptor == nullptr) {
return ERROR_NONE;
}
error_t error = gpio_descriptor_set_level(descriptor, active_high);
// Logical high (physical low, because of earlier GPIO_FLAG_ACTIVE_LOW)
error_t error = gpio_descriptor_set_level(descriptor, true);
if (error != ERROR_NONE) {
return error;
}
vTaskDelay(pdMS_TO_TICKS(50));
error = gpio_descriptor_set_level(descriptor, !active_high);
// Logical low (physical high, because of earlier GPIO_FLAG_ACTIVE_LOW)
error = gpio_descriptor_set_level(descriptor, false);
if (error != ERROR_NONE) {
return error;
}
@@ -101,20 +99,13 @@ static error_t start(Device* device) {
}
internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) {
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
free(internal);
return ERROR_RESOURCE;
}
if (gpio_descriptor_set_flags(internal->reset_descriptor, config->pin_reset.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure reset pin as output");
gpio_descriptor_release(internal->reset_descriptor);
free(internal);
return ERROR_RESOURCE;
}
}
esp_err_t ret = create_io_handle(parent, &internal->io_handle);
@@ -126,7 +117,7 @@ static error_t start(Device* device) {
return ERROR_RESOURCE;
}
if (pulse_reset(internal->reset_descriptor, internal->reset_active_high) != ERROR_NONE) {
if (pulse_reset(internal->reset_descriptor) != ERROR_NONE) {
LOG_E(TAG, "Failed to pulse reset pin");
esp_lcd_panel_io_del(internal->io_handle);
if (internal->reset_descriptor != nullptr) {
@@ -143,9 +134,10 @@ static error_t start(Device* device) {
// why); esp_lcd_touch just skips its own no-op reset step when this is NC.
.rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = pin_or_nc(config->pin_interrupt),
// FT6x36's reset and interrupt lines are both fixed active-low in hardware.
.levels = {
.reset = config->reset_active_high ? 1u : 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u,
.reset = 0u,
.interrupt = 0u,
},
.flags = {
.swap_xy = config->swap_xy ? 1u : 0u,
@@ -57,10 +57,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -25,7 +25,6 @@ struct Gc9a01Config {
uint8_t transaction_queue_depth;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -106,7 +106,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.flags = { .reset_active_high = config->reset_active_high },
// GC9A01's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -35,11 +35,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -22,8 +22,6 @@ struct Gt911Config {
bool mirror_y;
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+3 -2
View File
@@ -84,9 +84,10 @@ static error_t start(Device* device) {
.y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt),
// GT911's reset and interrupt lines are both fixed active-low in hardware.
.levels = {
.reset = config->reset_active_high ? 1u : 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u,
.reset = 0u,
.interrupt = 0u,
},
.flags = {
.swap_xy = config->swap_xy ? 1u : 0u,
@@ -54,10 +54,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -23,7 +23,6 @@ struct Hx8357Config {
uint32_t pixel_clock_hz;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+3 -2
View File
@@ -264,9 +264,10 @@ static error_t start(Device* device) {
free(internal);
return ERROR_RESOURCE;
}
gpio_set_level(static_cast<gpio_num_t>(reset_pin), config->reset_active_high ? 1 : 0);
// HX8357's reset line is fixed active-low in hardware.
gpio_set_level(static_cast<gpio_num_t>(reset_pin), 0);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(static_cast<gpio_num_t>(reset_pin), config->reset_active_high ? 0 : 1);
gpio_set_level(static_cast<gpio_num_t>(reset_pin), 1);
vTaskDelay(pdMS_TO_TICKS(120));
}
+6 -13
View File
@@ -71,16 +71,16 @@ static int pin_or_unused(const struct GpioPinSpec& pin) {
// start()), which makes it fall back to sending a SWRESET command instead - itself a valid and
// commonly-recommended reset path, so this pulse plus that fallback is redundant-safe, not harmful.
// Timing (10ms low, 10ms recovery) matches esp_lcd_ili9341's own hardware-reset path exactly.
static error_t pulse_reset(GpioDescriptor* descriptor, bool active_high) {
static error_t pulse_reset(GpioDescriptor* descriptor) {
if (descriptor == nullptr) {
return ERROR_NONE;
}
error_t error = gpio_descriptor_set_level(descriptor, active_high);
error_t error = gpio_descriptor_set_level(descriptor, true);
if (error != ERROR_NONE) {
return error;
}
vTaskDelay(pdMS_TO_TICKS(10));
error = gpio_descriptor_set_level(descriptor, !active_high);
error = gpio_descriptor_set_level(descriptor, false);
if (error != ERROR_NONE) {
return error;
}
@@ -117,20 +117,13 @@ static error_t start(Device* device) {
internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) {
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
internal->reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_RESOURCE;
}
if (gpio_descriptor_set_flags(internal->reset_descriptor, config->pin_reset.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure reset pin as output");
gpio_descriptor_release(internal->reset_descriptor);
vSemaphoreDelete(internal->draw_done_semaphore);
free(internal);
return ERROR_RESOURCE;
}
}
esp_lcd_panel_io_spi_config_t io_config = {
@@ -195,7 +188,7 @@ static error_t start(Device* device) {
// Every failure path below must clean up fully: unlike stop_device, this is never retried by the kernel
// if start_device fails (see device_start() in TactilityKernel), so a partial failure here would leak.
bool ok =
pulse_reset(internal->reset_descriptor, internal->reset_active_high) == ERROR_NONE &&
pulse_reset(internal->reset_descriptor) == ERROR_NONE &&
esp_lcd_panel_reset(internal->panel_handle) == ESP_OK &&
esp_lcd_panel_init(internal->panel_handle) == ESP_OK &&
(!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK);
@@ -263,7 +256,7 @@ static error_t stop(Device* device) {
static error_t ili9341_reset(Device* device) {
auto* internal = static_cast<Ili9341Internal*>(device_get_driver_data(device));
error_t error = pulse_reset(internal->reset_descriptor, internal->reset_active_high);
error_t error = pulse_reset(internal->reset_descriptor);
if (error != ERROR_NONE) {
return error;
}
@@ -65,10 +65,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -29,7 +29,6 @@ struct Ili9488Config {
uint8_t transaction_queue_depth;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -111,7 +111,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ILI9488's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -40,10 +40,6 @@ properties:
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel:
type: int
required: true
@@ -23,7 +23,6 @@ struct Ili9881cConfig {
// Reset pin for the panel. GPIO_PIN_SPEC_NONE falls back to a software reset sent over the
// DBI command interface (see esp_lcd_ili9881c's panel_ili9881c_reset()).
struct GpioPinSpec pin_reset;
bool reset_active_high;
// LDO channel powering the MIPI DSI PHY - the PHY has no power of its own until this is
// acquired, so it must happen before the DSI bus is created. Both fields are int32_t (not
+2 -1
View File
@@ -226,7 +226,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ILI9881C's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
@@ -39,10 +39,6 @@ properties:
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel:
type: int
required: true
@@ -23,7 +23,6 @@ struct Jd9165Config {
// Reset pin for the panel. GPIO_PIN_SPEC_NONE falls back to a software reset sent over the
// DBI command interface (see esp_lcd_jd9165's panel_jd9165_reset()).
struct GpioPinSpec pin_reset;
bool reset_active_high;
// LDO channel powering the MIPI DSI PHY - the PHY has no power of its own until this is
// acquired, so it must happen before the DSI bus is created. Both fields are int32_t (not
+2 -1
View File
@@ -225,7 +225,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// JD9165's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
@@ -63,10 +63,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -27,7 +27,6 @@ struct Jd9853Config {
uint8_t gamma_curve;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -117,7 +117,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.flags = { .reset_active_high = config->reset_active_high },
// JD9853's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
@@ -57,18 +57,15 @@ static void on_click(void* arg) {
// region Pin acquisition
static error_t acquire_pin(const GpioPinSpec& spec, GpioInterruptType interrupt_type, void (*callback)(void*), void* arg, GpioDescriptor** out_descriptor) {
auto* descriptor = gpio_descriptor_acquire(spec.gpio_controller, spec.pin, GPIO_OWNER_GPIO);
gpio_flags_t flags = GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP;
flags = GPIO_FLAG_INTERRUPT_TO_OPTIONS(flags, interrupt_type);
auto* descriptor = gpio_descriptor_acquire(spec.gpio_controller, spec.pin, flags, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
return ERROR_RESOURCE;
}
gpio_flags_t flags = GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP;
flags = GPIO_FLAG_INTERRUPT_TO_OPTIONS(flags, interrupt_type);
error_t error = gpio_descriptor_set_flags(descriptor, flags);
if (error == ERROR_NONE) {
error = gpio_descriptor_add_callback(descriptor, callback, arg);
}
error_t error = gpio_descriptor_add_callback(descriptor, callback, arg);
if (error == ERROR_NONE) {
error = gpio_descriptor_enable_interrupt(descriptor);
}
@@ -3,6 +3,7 @@
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/log.h>
@@ -33,14 +34,7 @@ static error_t read_delta(Device* device, int32_t* out_pulses) {
static error_t get_button_pressed(Device* device, bool* out_pressed) {
auto* internal = GET_INTERNAL(device);
bool high = true;
error_t error = gpio_descriptor_get_level(internal->pin_enter, &high);
if (error != ERROR_NONE) {
return error;
}
// Active low: pressed when level is low.
*out_pressed = !high;
return ERROR_NONE;
return gpio_descriptor_get_level(internal->pin_enter, out_pressed);
}
error_t tpager_encoder_read_delta(Device* device, int32_t* out_pulses) {
@@ -148,7 +142,7 @@ static error_t start(Device* device) {
return error;
}
internal->pin_enter = gpio_descriptor_acquire(config->pin_enter.gpio_controller, config->pin_enter.pin, GPIO_OWNER_GPIO);
internal->pin_enter = gpio_descriptor_acquire(config->pin_enter.gpio_controller, config->pin_enter.pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->pin_enter == nullptr) {
pcnt_unit_stop(internal->pcnt_unit);
pcnt_del_unit(internal->pcnt_unit);
@@ -156,15 +150,6 @@ static error_t start(Device* device) {
return ERROR_RESOURCE;
}
error = gpio_descriptor_set_flags(internal->pin_enter, GPIO_FLAG_DIRECTION_INPUT);
if (error != ERROR_NONE) {
gpio_descriptor_release(internal->pin_enter);
pcnt_unit_stop(internal->pcnt_unit);
pcnt_del_unit(internal->pcnt_unit);
delete internal;
return error;
}
device_set_driver_data(device, internal);
return ERROR_NONE;
}
@@ -2,11 +2,13 @@
// Matrix-scan and keymap logic ported from the M5Stack Cardputer keyboard driver at
// https://github.com/m5stack/M5Cardputer-UserDemo/tree/main/main/hal/keyboard (MIT licensed).
#include <drivers/cardputer_keyboard.h>
#include <m5stack_module.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/keyboard.h>
#include <tactility/error.h>
@@ -120,11 +122,7 @@ static error_t start(Device* device) {
for (int i = 0; i < CARDPUTER_OUTPUT_COUNT; i++) {
const auto& pin = config->pins_output[i];
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO);
if (descriptor != nullptr && gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
gpio_descriptor_release(descriptor);
descriptor = nullptr;
}
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, pin.flags | GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
LOG_E(TAG, "Failed to configure output pin %d", i);
for (int j = 0; j < i; j++) {
@@ -141,8 +139,9 @@ static error_t start(Device* device) {
const auto& pin = config->pins_input[i];
// Rows float high and are pulled low through a pressed key by the active output line,
// so an internal pull-up is required regardless of what the devicetree pin flags say.
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO);
if (descriptor == nullptr || gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP) != ERROR_NONE) {
auto flags = pin.flags | GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP;
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, flags, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
LOG_E(TAG, "Failed to configure input pin %d", i);
for (int j = 0; j < CARDPUTER_OUTPUT_COUNT; j++) {
gpio_descriptor_release(internal->output_descriptors[j]);
@@ -47,7 +47,10 @@ static error_t set_level(GpioDescriptor* descriptor, bool high) {
auto address = GET_CONFIG(device)->address;
uint8_t bit = 1 << descriptor->pin;
if (high) {
// This chip has no output polarity register: active-low must be inverted in software.
bool physical_high = (descriptor->flags & GPIO_FLAG_ACTIVE_LOW) != 0 ? !high : high;
if (physical_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);
@@ -65,7 +68,8 @@ static error_t get_level(GpioDescriptor* descriptor, bool* high) {
return err;
}
*high = (bits & (1 << descriptor->pin)) != 0;
bool physical_high = (bits & (1 << descriptor->pin)) != 0;
*high = (descriptor->flags & GPIO_FLAG_ACTIVE_LOW) != 0 ? !physical_high : physical_high;
return ERROR_NONE;
}
@@ -161,6 +165,8 @@ static error_t get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
f |= GPIO_FLAG_HIGH_IMPEDANCE;
}
f |= (descriptor->flags & GPIO_FLAG_ACTIVE_LOW);
*flags = f;
return ERROR_NONE;
}
@@ -9,8 +9,8 @@
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/display.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/error.h>
#include <tactility/log.h>
@@ -70,17 +70,16 @@ static error_t perform_hardware_reset(const RgbDisplayConfig* config) {
return ERROR_NONE;
}
auto* descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
auto* descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
return ERROR_RESOURCE;
}
bool ok = gpio_descriptor_set_flags(descriptor, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, config->reset_active_high) == ERROR_NONE;
bool ok = gpio_descriptor_set_level(descriptor, true) == ERROR_NONE;
if (ok) {
delay_millis(100);
ok = gpio_descriptor_set_level(descriptor, !config->reset_active_high) == ERROR_NONE;
ok = gpio_descriptor_set_level(descriptor, false) == ERROR_NONE;
delay_millis(10);
}
@@ -23,10 +23,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
power-on-delay-ms:
type: int
default: 0
@@ -22,7 +22,6 @@ struct Ssd1306Config {
// Reset pin. GPIO_PIN_SPEC_NONE skips the reset toggle entirely.
struct GpioPinSpec pin_reset;
bool reset_active_high;
// See the 'power-on-delay-ms' binding property.
uint32_t power_on_delay_ms;
+3 -2
View File
@@ -119,9 +119,10 @@ static void perform_hardware_reset(const Ssd1306Config* config) {
};
gpio_config(&io_conf);
gpio_set_level(pin, config->reset_active_high ? 1 : 0);
// SSD1306's reset line is fixed active-low in hardware.
gpio_set_level(pin, 0);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(pin, config->reset_active_high ? 0 : 1);
gpio_set_level(pin, 1);
vTaskDelay(pdMS_TO_TICKS(100));
}
@@ -37,11 +37,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
interrupt-active-high:
type: boolean
default: false
description: Whether the interrupt pin is active high
@@ -40,10 +40,6 @@ properties:
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel:
type: int
required: true
@@ -23,7 +23,6 @@ struct St7123Config {
// Reset pin for the panel. GPIO_PIN_SPEC_NONE falls back to a software reset sent over the
// DBI command interface (see esp_lcd_st7123's panel_st7123_reset()).
struct GpioPinSpec pin_reset;
bool reset_active_high;
// LDO channel powering the MIPI DSI PHY - the PHY has no power of its own until this is
// acquired, so it must happen before the DSI bus is created. Both fields are int32_t (not
@@ -25,8 +25,6 @@ struct St7123TouchConfig {
// for parity with the other touch drivers (e.g. gt911-module) in case a board wires it directly.
struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
};
#ifdef __cplusplus
+2 -1
View File
@@ -225,7 +225,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ST7123's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
@@ -75,9 +75,10 @@ static error_t start(Device* device) {
.y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt),
// ST7123's reset and interrupt lines are both fixed active-low in hardware.
.levels = {
.reset = config->reset_active_high ? 1u : 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u,
.reset = 0u,
.interrupt = 0u,
},
.flags = {
.swap_xy = config->swap_xy ? 1u : 0u,
@@ -233,10 +233,6 @@ properties:
default: GPIO_PIN_SPEC_NONE
description: Optional hardware reset pin for the panel. Falls back to a software reset
(sent over the 3-wire bus) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
mirror-by-cmd:
type: boolean
default: false
@@ -88,7 +88,6 @@ struct St7701Config {
// Optional hardware reset pin for the panel. GPIO_PIN_SPEC_NONE falls back to a software
// reset sent over the 3-wire bus (see esp_lcd_st7701's panel_st7701_reset()).
struct GpioPinSpec pin_reset;
bool reset_active_high;
// See the 'mirror-by-cmd' and 'auto-del-panel-io' binding properties.
bool mirror_by_cmd;
+2 -1
View File
@@ -238,7 +238,8 @@ static error_t start(Device* device) {
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ST7701's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
@@ -67,10 +67,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -28,7 +28,6 @@ struct St7735Config {
uint8_t gamma_curve;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -117,7 +117,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ST7735's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -59,10 +59,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -26,7 +26,6 @@ struct St7789I8080Config {
// Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up.
uint8_t gamma_curve;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
@@ -148,7 +148,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.flags = { .reset_active_high = config->reset_active_high },
// ST7789's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -67,10 +67,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -28,7 +28,6 @@ struct St7789Config {
uint8_t gamma_curve;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -117,7 +117,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ST7789's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -59,10 +59,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -26,7 +26,6 @@ struct St7796I8080Config {
// Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up.
uint8_t gamma_curve;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
@@ -116,7 +116,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.flags = { .reset_active_high = config->reset_active_high },
// ST7796's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -67,10 +67,6 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight:
type: phandle
default: "NULL"
@@ -28,7 +28,6 @@ struct St7796Config {
uint8_t gamma_curve;
struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none.
struct Device* backlight;
};
+2 -1
View File
@@ -117,7 +117,8 @@ static error_t start(Device* device) {
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// ST7796's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
@@ -68,7 +68,3 @@ properties:
type: phandles
default: GPIO_PIN_SPEC_NONE
description: Optional reset GPIO pin, pulsed once at start (20 ms assert, 60 ms settle)
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
@@ -27,7 +27,6 @@ struct Tca8418Config {
uint8_t sym_row;
uint8_t sym_col;
struct GpioPinSpec pin_reset;
bool reset_active_high;
};
#ifdef __cplusplus
+9 -4
View File
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/tca8418.h>
#include <tca8418_module.h>
#include <tactility/check.h>
#include <tactility/delay.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/keyboard.h>
@@ -116,15 +118,18 @@ static void perform_hardware_reset(const Tca8418Config* config) {
return;
}
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_OWNER_GPIO);
// Not requesting GPIO_FLAG_ACTIVE_LOW here: some GPIO expanders (e.g. xl9555/tca95xx/
// tca9534) can only invert what's read back from an input, not what's driven on an
// output, so they reject ACTIVE_LOW combined with OUTPUT. Drive the raw physical level
// instead: this pin's reset line is active-low, so low asserts and high releases.
auto* rst = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (rst == nullptr) {
return;
}
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(rst, config->reset_active_high);
gpio_descriptor_set_level(rst, false);
delay_millis(20);
gpio_descriptor_set_level(rst, !config->reset_active_high);
gpio_descriptor_set_level(rst, true);
gpio_descriptor_release(rst);
delay_millis(60);
}
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
#include <drivers/xpt2046_softspi.h>
#include <xpt2046_softspi_module.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/pointer.h>
#include <tactility/drivers/power_supply.h>
@@ -15,7 +17,7 @@
#include <cstdlib>
#include <new>
#define TAG "XPT2046SoftSPI"
constexpr auto* TAG = "XPT2046SoftSPI";
#define GET_CONFIG(device) (static_cast<const Xpt2046SoftSpiConfig*>((device)->config))
// Rough LiPo discharge curve floor, used together with the configured reference voltage
@@ -73,10 +75,10 @@ static error_t start(Device* device) {
}
*internal = {};
internal->mosi = gpio_descriptor_acquire(config->pin_mosi.gpio_controller, config->pin_mosi.pin, GPIO_OWNER_GPIO);
internal->miso = gpio_descriptor_acquire(config->pin_miso.gpio_controller, config->pin_miso.pin, GPIO_OWNER_GPIO);
internal->sck = gpio_descriptor_acquire(config->pin_sck.gpio_controller, config->pin_sck.pin, GPIO_OWNER_GPIO);
internal->cs = gpio_descriptor_acquire(config->pin_cs.gpio_controller, config->pin_cs.pin, GPIO_OWNER_GPIO);
internal->mosi = gpio_descriptor_acquire(config->pin_mosi.gpio_controller, config->pin_mosi.pin, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
internal->miso = gpio_descriptor_acquire(config->pin_miso.gpio_controller, config->pin_miso.pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP, GPIO_OWNER_GPIO);
internal->sck = gpio_descriptor_acquire(config->pin_sck.gpio_controller, config->pin_sck.pin, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
internal->cs = gpio_descriptor_acquire(config->pin_cs.gpio_controller, config->pin_cs.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (internal->mosi == nullptr || internal->miso == nullptr || internal->sck == nullptr || internal->cs == nullptr) {
LOG_E(TAG, "Failed to acquire GPIO descriptors");
@@ -85,15 +87,8 @@ static error_t start(Device* device) {
return ERROR_RESOURCE;
}
bool ok =
gpio_descriptor_set_flags(internal->mosi, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE &&
gpio_descriptor_set_flags(internal->sck, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE &&
gpio_descriptor_set_flags(internal->cs, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE &&
gpio_descriptor_set_flags(internal->miso, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP) == ERROR_NONE;
// Idle state: CS high (deselected), SCK/MOSI low.
ok = ok &&
gpio_descriptor_set_level(internal->cs, true) == ERROR_NONE &&
bool ok = gpio_descriptor_set_level(internal->cs, false) == ERROR_NONE &&
gpio_descriptor_set_level(internal->sck, false) == ERROR_NONE &&
gpio_descriptor_set_level(internal->mosi, false) == ERROR_NONE;
@@ -146,7 +141,7 @@ static error_t stop(Device* device) {
static int read_spi_command(Xpt2046SoftSpiInternal* internal, uint8_t command) {
int result = 0;
gpio_descriptor_set_level(internal->cs, false);
gpio_descriptor_set_level(internal->cs, true);
delay_micros(1);
for (int i = 7; i >= 0; i--) {
@@ -169,7 +164,7 @@ static int read_spi_command(Xpt2046SoftSpiInternal* internal, uint8_t command) {
delay_micros(1);
}
gpio_descriptor_set_level(internal->cs, true);
gpio_descriptor_set_level(internal->cs, false);
return result;
}