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
@@ -86,9 +86,7 @@
vsync-back-porch = <8>; vsync-back-porch = <8>;
vsync-front-porch = <8>; vsync-front-porch = <8>;
pclk-active-neg; pclk-active-neg;
num-fbs = <2>; bounce-buffer-size-px = <4000>;
double-fb;
bounce-buffer-size-px = <8000>;
pin-hsync = <&gpio0 40 GPIO_FLAG_NONE>; pin-hsync = <&gpio0 40 GPIO_FLAG_NONE>;
pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>; pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>;
pin-de = <&gpio0 42 GPIO_FLAG_NONE>; pin-de = <&gpio0 42 GPIO_FLAG_NONE>;
@@ -89,9 +89,7 @@
vsync-back-porch = <12>; vsync-back-porch = <12>;
vsync-front-porch = <8>; vsync-front-porch = <8>;
pclk-active-neg; pclk-active-neg;
num-fbs = <2>; bounce-buffer-size-px = <4000>;
double-fb;
bounce-buffer-size-px = <8000>;
pin-hsync = <&gpio0 39 GPIO_FLAG_NONE>; pin-hsync = <&gpio0 39 GPIO_FLAG_NONE>;
pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>; pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>;
pin-de = <&gpio0 40 GPIO_FLAG_NONE>; pin-de = <&gpio0 40 GPIO_FLAG_NONE>;
@@ -205,5 +205,4 @@
backlight = <&display_backlight>; backlight = <&display_backlight>;
}; };
}; };
}; };
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include "papers3_power.h" #include "papers3_power.h"
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/power_supply.h> #include <tactility/drivers/power_supply.h>
#include <tactility/drivers/pwm.h> #include <tactility/drivers/pwm.h>
@@ -13,7 +15,7 @@
#include <new> #include <new>
#define TAG "Papers3Power" constexpr auto* TAG = "Papers3Power";
#define GET_CONFIG(device) (static_cast<const Papers3PowerConfig*>((device)->config)) #define GET_CONFIG(device) (static_cast<const Papers3PowerConfig*>((device)->config))
// Power-off signal timing, ported from the old deprecated-HAL PaperS3Power::powerOff(). // Power-off signal timing, ported from the old deprecated-HAL PaperS3Power::powerOff().
@@ -192,17 +194,8 @@ static void destroy_power_supply_child(Device* child) {
// region Driver lifecycle // region Driver lifecycle
static error_t acquire_input(const GpioPinSpec& pin, GpioDescriptor** out_descriptor) { static error_t acquire_input(const GpioPinSpec& pin, GpioDescriptor** out_descriptor) {
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO); *out_descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, pin.flags | GPIO_FLAG_DIRECTION_INPUT, GPIO_OWNER_GPIO);
if (descriptor == nullptr) { return (*out_descriptor != nullptr) ? ERROR_NONE : ERROR_RESOURCE;
return ERROR_RESOURCE;
}
error_t error = gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_INPUT);
if (error != ERROR_NONE) {
gpio_descriptor_release(descriptor);
return error;
}
*out_descriptor = descriptor;
return ERROR_NONE;
} }
static error_t start(Device* device) { static error_t start(Device* device) {
@@ -226,13 +219,8 @@ static error_t start(Device* device) {
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
internal->power_off_descriptor = gpio_descriptor_acquire(config->pin_power_off.gpio_controller, config->pin_power_off.pin, GPIO_OWNER_GPIO); internal->power_off_descriptor = gpio_descriptor_acquire(config->pin_power_off.gpio_controller, config->pin_power_off.pin, config->pin_power_off.flags | GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (internal->power_off_descriptor == nullptr || if (internal->power_off_descriptor == nullptr) {
gpio_descriptor_set_flags(internal->power_off_descriptor, config->pin_power_off.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure power-off pin");
if (internal->power_off_descriptor != nullptr) {
gpio_descriptor_release(internal->power_off_descriptor);
}
gpio_descriptor_release(internal->usb_detect_descriptor); gpio_descriptor_release(internal->usb_detect_descriptor);
gpio_descriptor_release(internal->charge_status_descriptor); gpio_descriptor_release(internal->charge_status_descriptor);
delete internal; delete internal;
@@ -7,8 +7,10 @@
#include <tactility/bindings/esp32_grove.h> #include <tactility/bindings/esp32_grove.h>
#include <tactility/bindings/esp32_i2c.h> #include <tactility/bindings/esp32_i2c.h>
#include <tactility/bindings/esp32_i2s.h> #include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/esp32_spi.h> #include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_uart.h> #include <tactility/bindings/esp32_uart.h>
#include <tactility/bindings/gpio_hog.h>
#include <bindings/aw88298.h> #include <bindings/aw88298.h>
#include <bindings/aw9523b.h> #include <bindings/aw9523b.h>
#include <bindings/axp2101.h> #include <bindings/axp2101.h>
@@ -20,8 +22,6 @@
#include <bindings/ili9341.h> #include <bindings/ili9341.h>
#include <bindings/ina226.h> #include <bindings/ina226.h>
#include <bindings/py32ioexpander.h> #include <bindings/py32ioexpander.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/gpio_hog.h>
// Reference: https://docs.m5stack.com/en/StackChan // Reference: https://docs.m5stack.com/en/StackChan
/ { / {
@@ -101,7 +101,7 @@
aw9523_sdcard_switch { aw9523_sdcard_switch {
compatible = "gpio-hog"; compatible = "gpio-hog";
pin = <&aw9523b 4 GPIO_FLAG_NONE>; pin = <&aw9523b 4 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>; mode = <GPIO_HOG_MODE_INPUT>;
}; };
aw9523_boost_enable { aw9523_boost_enable {
@@ -36,14 +36,14 @@ static void apply_gt911_int_workaround() {
LOG_W(TAG, "display_detect: gpio0 not found, GT911 INT workaround not applied"); LOG_W(TAG, "display_detect: gpio0 not found, GT911 INT workaround not applied");
return; return;
} }
auto* int_pin = gpio_descriptor_acquire(gpio0, 23, GPIO_OWNER_GPIO); auto* int_pin = gpio_descriptor_acquire(gpio0, 23, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
device_put(gpio0); device_put(gpio0);
if (int_pin == nullptr) { if (int_pin == nullptr) {
LOG_W(TAG, "display_detect: failed to acquire GPIO23 for GT911 INT workaround"); LOG_W(TAG, "display_detect: failed to acquire GPIO23 for GT911 INT workaround");
return; return;
} }
gpio_descriptor_set_flags(int_pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_PULL_UP); gpio_descriptor_set_flags(int_pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_PULL_UP);
gpio_descriptor_set_level(int_pin, false); gpio_descriptor_set_level(int_pin, true);
gpio_descriptor_release(int_pin); gpio_descriptor_release(int_pin);
} }
@@ -67,8 +67,6 @@ static void create_gt911_touch(Device* i2c0) {
// Reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a direct SoC GPIO. // Reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a direct SoC GPIO.
.pin_reset = GPIO_PIN_SPEC_NONE, .pin_reset = GPIO_PIN_SPEC_NONE,
.pin_interrupt = GPIO_PIN_SPEC_NONE, .pin_interrupt = GPIO_PIN_SPEC_NONE,
.reset_active_high = false,
.interrupt_active_high = false,
}; };
gt911_device.config = &gt911_config; gt911_device.config = &gt911_config;
@@ -103,7 +101,6 @@ void tab5_create_devices_v1(Device* i2c0) {
// LCD reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a // LCD reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a
// direct SoC GPIO. // direct SoC GPIO.
.pin_reset = GPIO_PIN_SPEC_NONE, .pin_reset = GPIO_PIN_SPEC_NONE,
.reset_active_high = false,
.ldo_channel = 3, .ldo_channel = 3,
.ldo_voltage_mv = 2500, .ldo_voltage_mv = 2500,
.dsi_bus_id = 0, .dsi_bus_id = 0,
@@ -50,8 +50,6 @@ static void create_st7123_touch(Device* i2c0) {
// Reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a direct SoC GPIO. // Reset is pulsed via io_expander0 (detect.cpp's pulse_display_reset_pins), not a direct SoC GPIO.
.pin_reset = GPIO_PIN_SPEC_NONE, .pin_reset = GPIO_PIN_SPEC_NONE,
.pin_interrupt = pin_interrupt, .pin_interrupt = pin_interrupt,
.reset_active_high = false,
.interrupt_active_high = false,
}; };
st7123_touch_device.config = &st7123_touch_config; st7123_touch_device.config = &st7123_touch_config;
@@ -82,7 +80,6 @@ void tab5_create_devices_v2(Device* i2c0) {
.mirror_x = false, .mirror_x = false,
.mirror_y = false, .mirror_y = false,
.pin_reset = GPIO_PIN_SPEC_NONE, .pin_reset = GPIO_PIN_SPEC_NONE,
.reset_active_high = false,
.ldo_channel = 3, .ldo_channel = 3,
.ldo_voltage_mv = 2500, .ldo_voltage_mv = 2500,
.dsi_bus_id = 0, .dsi_bus_id = 0,
@@ -1,6 +1,5 @@
#include "detect.h" #include "detect.h"
#include "../../../../TactilityKernel/include/tactility/log.h"
#include "devices_common.h" #include "devices_common.h"
#include "devices_v1.h" #include "devices_v1.h"
#include "devices_v2.h" #include "devices_v2.h"
@@ -8,6 +7,7 @@
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/device_listener.h> #include <tactility/device_listener.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/log.h> #include <tactility/log.h>
@@ -36,8 +36,8 @@ constexpr auto GPIO_EXP0_PIN_LCD_RESET = 4;
constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5; constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5;
bool pulse_display_reset_pins(Device* io_expander0) { bool pulse_display_reset_pins(Device* io_expander0) {
auto* lcd_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_LCD_RESET, GPIO_OWNER_GPIO); auto* lcd_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_LCD_RESET, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
auto* touch_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_TOUCH_RESET, GPIO_OWNER_GPIO); auto* touch_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_TOUCH_RESET, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
if (lcd_reset_pin == nullptr || touch_reset_pin == nullptr) { if (lcd_reset_pin == nullptr || touch_reset_pin == nullptr) {
LOG_E(TAG, "display_detect: failed to acquire LCD/touch reset pins on io_expander0"); LOG_E(TAG, "display_detect: failed to acquire LCD/touch reset pins on io_expander0");
if (lcd_reset_pin != nullptr) { if (lcd_reset_pin != nullptr) {
@@ -51,11 +51,11 @@ bool pulse_display_reset_pins(Device* io_expander0) {
gpio_descriptor_set_flags(lcd_reset_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(touch_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(lcd_reset_pin, false);
gpio_descriptor_set_level(touch_reset_pin, false);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(lcd_reset_pin, true); gpio_descriptor_set_level(lcd_reset_pin, true);
gpio_descriptor_set_level(touch_reset_pin, true); gpio_descriptor_set_level(touch_reset_pin, true);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(lcd_reset_pin, false);
gpio_descriptor_set_level(touch_reset_pin, false);
gpio_descriptor_release(lcd_reset_pin); gpio_descriptor_release(lcd_reset_pin);
gpio_descriptor_release(touch_reset_pin); gpio_descriptor_release(touch_reset_pin);
@@ -1,6 +1,7 @@
#include "tab5_headphone_detect.h" #include "tab5_headphone_detect.h"
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/log.h> #include <tactility/log.h>
@@ -35,7 +36,7 @@ static void headphone_detect_callback(TimerHandle_t /*timer*/) {
return; // Not ready yet, will retry on next tick return; // Not ready yet, will retry on next tick
} }
auto* hp_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO); auto* hp_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_FLAG_DIRECTION_INPUT, GPIO_OWNER_GPIO);
if (!hp_pin) { if (!hp_pin) {
LOG_W(TAG, "hp_detect: HP_DET pin busy"); LOG_W(TAG, "hp_detect: HP_DET pin busy");
return; return;
@@ -53,7 +54,7 @@ static void headphone_detect_callback(TimerHandle_t /*timer*/) {
LOG_D(TAG, "hp_detect: HP_DET=%d", (int)hp); LOG_D(TAG, "hp_detect: HP_DET=%d", (int)hp);
if (!hp_detect_initialized || hp != hp_detect_last) { if (!hp_detect_initialized || hp != hp_detect_last) {
auto* spk_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO); auto* spk_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (!spk_pin) { if (!spk_pin) {
LOG_W(TAG, "hp_detect: SPK_EN pin busy, will retry"); LOG_W(TAG, "hp_detect: SPK_EN pin busy, will retry");
return; return;
@@ -3,6 +3,7 @@
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/power_supply.h> #include <tactility/drivers/power_supply.h>
#include <tactility/log.h> #include <tactility/log.h>
@@ -51,15 +52,12 @@ static error_t ps_set_allowed_to_charge(Device* device, bool allowed) {
auto* internal = static_cast<Tab5PowerControlInternal*>(device_get_driver_data(device)); auto* internal = static_cast<Tab5PowerControlInternal*>(device_get_driver_data(device));
auto* io_expander1 = device_get_parent(device); auto* io_expander1 = device_get_parent(device);
auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_OWNER_GPIO); auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (pin == nullptr) { if (pin == nullptr) {
LOG_W(TAG, "Failed to acquire CHG_EN pin"); LOG_W(TAG, "Failed to acquire CHG_EN pin");
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
error_t error = gpio_descriptor_set_flags(pin, GPIO_FLAG_DIRECTION_OUTPUT); auto error = gpio_descriptor_set_level(pin, allowed);
if (error == ERROR_NONE) {
error = gpio_descriptor_set_level(pin, allowed);
}
gpio_descriptor_release(pin); gpio_descriptor_release(pin);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
LOG_W(TAG, "Failed to set CHG_EN pin"); LOG_W(TAG, "Failed to set CHG_EN pin");
@@ -83,15 +81,12 @@ static error_t ps_set_quick_charge_enabled(Device* device, bool enabled) {
auto* internal = static_cast<Tab5PowerControlInternal*>(device_get_driver_data(device)); auto* internal = static_cast<Tab5PowerControlInternal*>(device_get_driver_data(device));
auto* io_expander1 = device_get_parent(device); auto* io_expander1 = device_get_parent(device);
auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_OWNER_GPIO); auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (pin == nullptr) { if (pin == nullptr) {
LOG_W(TAG, "Failed to acquire nCHG_QC_EN pin"); LOG_W(TAG, "Failed to acquire nCHG_QC_EN pin");
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
error_t error = gpio_descriptor_set_flags(pin, GPIO_FLAG_DIRECTION_OUTPUT); auto error = gpio_descriptor_set_level(pin, !enabled); // active-low
if (error == ERROR_NONE) {
error = gpio_descriptor_set_level(pin, !enabled); // active-low
}
gpio_descriptor_release(pin); gpio_descriptor_release(pin);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
LOG_W(TAG, "Failed to set nCHG_QC_EN pin"); LOG_W(TAG, "Failed to set nCHG_QC_EN pin");
@@ -108,7 +103,7 @@ static bool ps_supports_power_off(Device*) {
static error_t ps_power_off(Device* device) { static error_t ps_power_off(Device* device) {
auto* io_expander1 = device_get_parent(device); auto* io_expander1 = device_get_parent(device);
auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO); auto* pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (pin == nullptr) { if (pin == nullptr) {
LOG_E(TAG, "Failed to acquire DEVICE_POWER pin"); LOG_E(TAG, "Failed to acquire DEVICE_POWER pin");
return ERROR_RESOURCE; return ERROR_RESOURCE;
@@ -153,9 +148,8 @@ static error_t start(Device* device) {
// as an idle-low output up front so it's in a known state (previously done by Configuration.cpp's // as an idle-low output up front so it's in a known state (previously done by Configuration.cpp's
// initExpander1(), now owned here - see that function's comment for why it no longer touches it). // initExpander1(), now owned here - see that function's comment for why it no longer touches it).
auto* io_expander1 = device_get_parent(device); auto* io_expander1 = device_get_parent(device);
auto* device_power_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO); auto* device_power_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
if (device_power_pin != nullptr) { if (device_power_pin != nullptr) {
gpio_descriptor_set_flags(device_power_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_level(device_power_pin, false); gpio_descriptor_set_level(device_power_pin, false);
gpio_descriptor_release(device_power_pin); gpio_descriptor_release(device_power_pin);
} else { } else {
+4 -6
View File
@@ -1,4 +1,5 @@
#include <tactility/module.h> #include <tactility/module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/device_listener.h> #include <tactility/device_listener.h>
@@ -25,14 +26,11 @@ constexpr auto GPIO_EXP0_PIN_HEADPHONE_DETECT = 7;
static void tab5_init_expander0(Device* io_expander0) { static void tab5_init_expander0(Device* io_expander0) {
// Speaker and heapdhone pins are managed at runtime, so we can't have them as a hog in the dts file // Speaker and heapdhone pins are managed at runtime, so we can't have them as a hog in the dts file
// We have to init them manually. // We have to init them manually.
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO); auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
check(speaker_enable_pin); check(speaker_enable_pin);
auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO); auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_FLAG_DIRECTION_INPUT, GPIO_OWNER_GPIO);
check(headphone_detect_pin); check(headphone_detect_pin);
gpio_descriptor_set_flags(speaker_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
gpio_descriptor_set_flags(headphone_detect_pin, GPIO_FLAG_DIRECTION_INPUT);
gpio_descriptor_set_level(speaker_enable_pin, false); gpio_descriptor_set_level(speaker_enable_pin, false);
gpio_descriptor_release(speaker_enable_pin); gpio_descriptor_release(speaker_enable_pin);
@@ -40,7 +38,7 @@ static void tab5_init_expander0(Device* io_expander0) {
} }
static void tab5_enable_speaker_amp(Device* io_expander0) { static void tab5_enable_speaker_amp(Device* io_expander0) {
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO); auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
check(speaker_enable_pin, "Failed to acquire speaker enable pin"); check(speaker_enable_pin, "Failed to acquire speaker enable pin");
error_t error = gpio_descriptor_set_level(speaker_enable_pin, true); error_t error = gpio_descriptor_set_level(speaker_enable_pin, true);
gpio_descriptor_release(speaker_enable_pin); gpio_descriptor_release(speaker_enable_pin);
+1 -3
View File
@@ -21,10 +21,8 @@ bool BatteryManager::initGpioExpander() {
return false; return false;
} }
expanderPowerPin = gpio_descriptor_acquire(expander, expanderpin::EXPANDER_POWER, GPIO_OWNER_GPIO); expanderPowerPin = gpio_descriptor_acquire(expander, expanderpin::EXPANDER_POWER, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
check(expanderPowerPin != nullptr); check(expanderPowerPin != nullptr);
gpio_descriptor_set_flags(expanderPowerPin, GPIO_FLAG_DIRECTION_OUTPUT);
device_put(expander); device_put(expander);
return true; return true;
@@ -90,21 +90,19 @@ static int32_t nav_buttons_thread_main(UnphoneNavButtonsInternal* internal) {
// region Pin acquisition // region Pin acquisition
static error_t acquire_button(const GpioPinSpec& pin, void (*callback)(void*), void* arg, GpioDescriptor** out_descriptor) { static error_t acquire_button(const GpioPinSpec& pin, void (*callback)(void*), void* arg, GpioDescriptor** out_descriptor) {
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO);
if (descriptor == nullptr) {
return ERROR_RESOURCE;
}
// Digital pull-up; the buttons pull the pin low while pressed. Listen for the release // Digital pull-up; the buttons pull the pin low while pressed. Listen for the release
// (positive edge) rather than the press - if we listen to the press, these buttons can // (positive edge) rather than the press - if we listen to the press, these buttons can
// generate more than one signal when held down (mirrors the original unPhone init). // generate more than one signal when held down (mirrors the original unPhone init).
gpio_flags_t flags = GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP; gpio_flags_t flags = GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP;
flags = GPIO_FLAG_INTERRUPT_TO_OPTIONS(flags, GPIO_INTERRUPT_POS_EDGE); flags = GPIO_FLAG_INTERRUPT_TO_OPTIONS(flags, GPIO_INTERRUPT_POS_EDGE);
error_t error = gpio_descriptor_set_flags(descriptor, flags); auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, flags, GPIO_OWNER_GPIO);
if (error == ERROR_NONE) { if (descriptor == nullptr) {
error = gpio_descriptor_add_callback(descriptor, callback, arg); return ERROR_RESOURCE;
} }
auto error = gpio_descriptor_add_callback(descriptor, callback, arg);
if (error == ERROR_NONE) { if (error == ERROR_NONE) {
error = gpio_descriptor_enable_interrupt(descriptor); error = gpio_descriptor_enable_interrupt(descriptor);
} }
@@ -25,18 +25,12 @@ extern Module unphone_module;
static error_t start(Device* device) { static error_t start(Device* device) {
const auto* config = GET_CONFIG(device); const auto* config = GET_CONFIG(device);
auto* descriptor = gpio_descriptor_acquire(config->pin.gpio_controller, config->pin.pin, GPIO_OWNER_GPIO); auto* descriptor = gpio_descriptor_acquire(config->pin.gpio_controller, config->pin.pin, config->pin.flags | GPIO_FLAG_DIRECTION_INPUT, GPIO_OWNER_GPIO);
if (descriptor == nullptr) { if (descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire GPIO descriptor"); LOG_E(TAG, "Failed to acquire GPIO descriptor");
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
if (gpio_descriptor_set_flags(descriptor, config->pin.flags | GPIO_FLAG_DIRECTION_INPUT) != ERROR_NONE) {
LOG_E(TAG, "Failed to configure power switch pin as input");
gpio_descriptor_release(descriptor);
return ERROR_RESOURCE;
}
gpio_num_t native_pin; gpio_num_t native_pin;
if (gpio_descriptor_get_native_pin_number(descriptor, &native_pin) != ERROR_NONE) { if (gpio_descriptor_get_native_pin_number(descriptor, &native_pin) != ERROR_NONE) {
LOG_E(TAG, "Power switch pin has no native pin number"); LOG_E(TAG, "Power switch pin has no native pin number");
@@ -96,9 +96,8 @@
vsync-back-porch = <8>; vsync-back-porch = <8>;
vsync-front-porch = <8>; vsync-front-porch = <8>;
pclk-active-neg; pclk-active-neg;
num-fbs = <2>; num-fbs = <1>;
double-fb; bounce-buffer-size-px = <4000>;
bounce-buffer-size-px = <8000>;
pin-hsync = <&gpio0 46 GPIO_FLAG_NONE>; pin-hsync = <&gpio0 46 GPIO_FLAG_NONE>;
pin-vsync = <&gpio0 3 GPIO_FLAG_NONE>; pin-vsync = <&gpio0 3 GPIO_FLAG_NONE>;
pin-de = <&gpio0 5 GPIO_FLAG_NONE>; pin-de = <&gpio0 5 GPIO_FLAG_NONE>;
+2
View File
@@ -13,6 +13,8 @@
## Higher Priority ## Higher Priority
- LilyGO T-Dongle S3: 1 button control, stop auto-launching web server
- Core2: support power off via software
- Create `#define` for empty module (for modules that fully rely on device.properties and don't define drivers or have start/stop logic) - Create `#define` for empty module (for modules that fully rely on device.properties and don't define drivers or have start/stop logic)
- Get rid of TactilityC in favour of TactilityKernel and kernel modules - Get rid of TactilityC in favour of TactilityKernel and kernel modules
- Improve SPI kernel driver (implement read, write, transactions) - Improve SPI kernel driver (implement read, write, transactions)
@@ -17,7 +17,7 @@ struct GpioAdapterContext {
static struct GpioAdapterContext* g_context = NULL; 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) { if (g_context == NULL || gpio < 0 || (size_t) gpio >= g_context->pin_count) {
return NULL; return NULL;
} }
@@ -31,24 +31,31 @@ static struct GpioDescriptor* acquire_descriptor(int16_t gpio) {
return NULL; 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) { if (descriptor != NULL) {
gpio_descriptor_set_flags(descriptor, spec->flags);
g_context->descriptors[gpio] = descriptor; g_context->descriptors[gpio] = descriptor;
} }
return descriptor; return descriptor;
} }
static int gpio_setup(int16_t gpio, audio_gpio_dir_t dir, audio_gpio_mode_t mode) { 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) { if (descriptor == NULL) {
return ESP_CODEC_DEV_NOT_FOUND; return ESP_CODEC_DEV_NOT_FOUND;
} }
gpio_flags_t flags = GPIO_FLAG_NONE;
gpio_descriptor_get_flags(descriptor, &flags); gpio_descriptor_get_flags(descriptor, &flags);
flags &= ~(GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_PULL_UP | GPIO_FLAG_PULL_DOWN); 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; flags |= (dir == AUDIO_GPIO_DIR_OUT) ? GPIO_FLAG_DIRECTION_OUTPUT : GPIO_FLAG_DIRECTION_INPUT;
if ((mode & AUDIO_GPIO_MODE_PULL_UP) != 0) { if ((mode & AUDIO_GPIO_MODE_PULL_UP) != 0) {
flags |= GPIO_FLAG_PULL_UP; 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) { 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) { if (descriptor == NULL) {
return ESP_CODEC_DEV_NOT_FOUND; 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 // acquire and a legitimate low reading are indistinguishable to the caller; log so the
// failure is at least visible. // failure is at least visible.
static bool gpio_get(int16_t gpio) { 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) { if (descriptor == NULL) {
LOG_E(TAG, "gpio_get: failed to acquire descriptor for pin %d", gpio); LOG_E(TAG, "gpio_get: failed to acquire descriptor for pin %d", gpio);
return false; 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 // (unlike a board Configuration.cpp initBoot() callback, which only runs after ALL
// devicetree devices, including this one, have already started). // devicetree devices, including this one, have already started).
if (config->reset_pin.gpio_controller != nullptr) { 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) { if (reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin descriptor"); LOG_E(TAG, "Failed to acquire reset pin descriptor");
goto cleanup; 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); gpio_descriptor_set_level(reset_descriptor, true);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_descriptor_set_level(reset_descriptor, false);
vTaskDelay(pdMS_TO_TICKS(50)); vTaskDelay(pdMS_TO_TICKS(50));
gpio_descriptor_release(reset_descriptor); 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 bit = 1U << (descriptor->pin % 8U);
uint8_t reg = portRegister(isPort1, AW9523B_REG_OUTPUT_P0, AW9523B_REG_OUTPUT_P1); 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); return i2c_controller_register8_set_bits(parent, address, reg, bit, portMAX_DELAY);
} else { } else {
return i2c_controller_register8_reset_bits(parent, address, reg, bit, portMAX_DELAY); 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; 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; 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. // Config register is inverted: 0 = output, 1 = input.
*flags = (val & bit) ? GPIO_FLAG_DIRECTION_INPUT : GPIO_FLAG_DIRECTION_OUTPUT; *flags = (val & bit) ? GPIO_FLAG_DIRECTION_INPUT : GPIO_FLAG_DIRECTION_OUTPUT;
*flags |= (descriptor->flags & GPIO_FLAG_ACTIVE_LOW);
return ERROR_NONE; return ERROR_NONE;
} }
@@ -35,14 +35,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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: transmit-timeout:
type: int type: int
default: 100 default: 100
@@ -19,8 +19,6 @@ struct Axs5106Config {
bool mirror_y; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; 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, // 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 // 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), // 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 // SPDX-License-Identifier: Apache-2.0
#include <drivers/axs5106.h> #include <drivers/axs5106.h>
#include <axs5106_module.h> #include <axs5106_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h> #include <tactility/drivers/pointer.h>
#include <tactility/error.h> #include <tactility/error.h>
@@ -41,16 +42,10 @@ struct Axs5106Internal {
// region Driver lifecycle // region Driver lifecycle
// Matches the vendor demo's touch_axs5106_reset(): pulse the reset pin active for 10ms, then static error_t reset_pulse(GpioDescriptor* descriptor) {
// release it for 10ms before any I2C traffic. No separate init step follows - the vendor demo's bool ok = gpio_descriptor_set_level(descriptor, true) == ERROR_NONE;
// 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;
vTaskDelay(pdMS_TO_TICKS(10)); 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)); vTaskDelay(pdMS_TO_TICKS(10));
return ok ? ERROR_NONE : ERROR_RESOURCE; return ok ? ERROR_NONE : ERROR_RESOURCE;
@@ -73,14 +68,14 @@ static error_t start(Device* device) {
internal->point_count = 0; internal->point_count = 0;
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin"); LOG_E(TAG, "Failed to acquire reset pin");
free(internal); free(internal);
return ERROR_RESOURCE; 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"); LOG_E(TAG, "Failed to pulse reset pin");
gpio_descriptor_release(internal->reset_descriptor); gpio_descriptor_release(internal->reset_descriptor);
free(internal); free(internal);
@@ -1,9 +1,11 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/button_control.h> #include <drivers/button_control.h>
#include <button_control_module.h> #include <button_control_module.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/keyboard.h> #include <tactility/drivers/keyboard.h>
#include <tactility/error.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; 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) { if (descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire GPIO descriptor"); LOG_E(TAG, "Failed to acquire GPIO descriptor");
return ERROR_RESOURCE; 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 = { *out_state = {
.descriptor = descriptor, .descriptor = descriptor,
.in_use = true, .in_use = true,
@@ -26,7 +26,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Optional reset GPIO pin. Falls back to a software reset command if not set. 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_x;
bool mirror_y; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+5 -4
View File
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/cst328.h> #include <drivers/cst328.h>
#include <cst328_module.h> #include <cst328_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/delay.h> #include <tactility/delay.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.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. // chip's own software reset command instead.
static void perform_reset(Device* i2c, uint8_t address, const Cst328Config* config) { static void perform_reset(Device* i2c, uint8_t address, const Cst328Config* config) {
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (rst != nullptr) {
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT); gpio_descriptor_set_level(rst, true);
gpio_descriptor_set_level(rst, config->reset_active_high);
delay_millis(100); delay_millis(100);
gpio_descriptor_set_level(rst, !config->reset_active_high); gpio_descriptor_set_level(rst, false);
gpio_descriptor_release(rst); gpio_descriptor_release(rst);
delay_millis(100); delay_millis(100);
return; return;
@@ -35,7 +35,3 @@ properties:
type: phandles type: phandles
required: true required: true
description: Reset GPIO pin. The chip only re-initializes into normal reporting mode after a clean reset pulse. 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_x;
bool mirror_y; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+9 -5
View File
@@ -1,13 +1,14 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/cst66xx.h> #include <drivers/cst66xx.h>
#include <cst66xx_module.h> #include <cst66xx_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/delay.h> #include <tactility/delay.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h> #include <tactility/drivers/pointer.h>
#include <tactility/error.h> #include <tactility/error.h>
@@ -61,15 +62,18 @@ static void perform_hardware_reset(const Cst66xxConfig* config) {
return; 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) { if (rst == nullptr) {
return; return;
} }
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT); gpio_descriptor_set_level(rst, false);
gpio_descriptor_set_level(rst, config->reset_active_high);
delay_millis(10); delay_millis(10);
gpio_descriptor_set_level(rst, !config->reset_active_high); gpio_descriptor_set_level(rst, true);
gpio_descriptor_release(rst); gpio_descriptor_release(rst);
// The reset pulse exits boot mode; give the controller time to re-init. // The reset pulse exits boot mode; give the controller time to re-init.
delay_millis(80); delay_millis(80);
@@ -35,11 +35,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+3 -2
View File
@@ -75,9 +75,10 @@ static error_t start(Device* device) {
.y_max = config->y_max, .y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset), .rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt), .int_gpio_num = pin_or_nc(config->pin_interrupt),
// CST816S's reset and interrupt lines are both fixed active-low in hardware.
.levels = { .levels = {
.reset = config->reset_active_high ? 1u : 0u, .reset = 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u, .interrupt = 0u,
}, },
.flags = { .flags = {
.swap_xy = config->swap_xy ? 1u : 0u, .swap_xy = config->swap_xy ? 1u : 0u,
@@ -35,11 +35,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin (currently unused - reads are polled via read_data()) 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; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+8 -10
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/cst816t.h> #include <drivers/cst816t.h>
#include <cst816t_module.h> #include <cst816t_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h> #include <tactility/drivers/pointer.h>
#include <tactility/error.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 // 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 // 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. // waits another 100ms (Tron) for the chip to finish reinitializing before any I2C traffic.
static error_t reset_pulse(GpioDescriptor* descriptor, bool active_high) { static error_t reset_pulse(GpioDescriptor* descriptor) {
bool idle_level = !active_high; bool ok = gpio_descriptor_set_level(descriptor, false) == ERROR_NONE;
bool ok = gpio_descriptor_set_flags(descriptor, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, idle_level) == ERROR_NONE;
vTaskDelay(pdMS_TO_TICKS(100)); 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)); 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)); vTaskDelay(pdMS_TO_TICKS(100));
return ok ? ERROR_NONE : ERROR_RESOURCE; return ok ? ERROR_NONE : ERROR_RESOURCE;
@@ -77,14 +75,14 @@ static error_t start(Device* device) {
internal->y = 0; internal->y = 0;
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset pin"); LOG_E(TAG, "Failed to acquire reset pin");
free(internal); free(internal);
return ERROR_RESOURCE; 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"); LOG_E(TAG, "Failed to pulse reset pin");
gpio_descriptor_release(internal->reset_descriptor); gpio_descriptor_release(internal->reset_descriptor);
free(internal); free(internal);
@@ -35,11 +35,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #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, // 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. // unrelated physical pin whenever pin_reset actually points at an I2C expander.
GpioDescriptor* reset_descriptor; 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 // 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 // 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 // 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. // 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); 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 static error_t pulse_reset(GpioDescriptor* descriptor) {
// 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) {
if (descriptor == nullptr) { if (descriptor == nullptr) {
return ERROR_NONE; 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) { if (error != ERROR_NONE) {
return error; return error;
} }
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
error = gpio_descriptor_set_level(descriptor, !active_high); error = gpio_descriptor_set_level(descriptor, false);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
return error; return error;
} }
@@ -101,20 +97,13 @@ static error_t start(Device* device) {
} }
internal->reset_descriptor = nullptr; internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor"); LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
free(internal); free(internal);
return ERROR_RESOURCE; 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); esp_err_t ret = create_io_handle(parent, &internal->io_handle);
@@ -126,7 +115,7 @@ static error_t start(Device* device) {
return ERROR_RESOURCE; 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"); LOG_E(TAG, "Failed to pulse reset pin");
esp_lcd_panel_io_del(internal->io_handle); esp_lcd_panel_io_del(internal->io_handle);
if (internal->reset_descriptor != nullptr) { 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. // why); esp_lcd_touch just skips its own no-op reset step when this is NC.
.rst_gpio_num = GPIO_NUM_NC, .rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = pin_or_nc(config->pin_interrupt), .int_gpio_num = pin_or_nc(config->pin_interrupt),
// FT5x06's reset and interrupt lines are both fixed active-low in hardware.
.levels = { .levels = {
.reset = config->reset_active_high ? 1u : 0u, .reset = 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u, .interrupt = 0u,
}, },
.flags = { .flags = {
.swap_xy = config->swap_xy ? 1u : 0u, .swap_xy = config->swap_xy ? 1u : 0u,
@@ -35,11 +35,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+12 -20
View File
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/ft6x36.h> #include <drivers/ft6x36.h>
#include <ft6x36_module.h> #include <ft6x36_module.h>
#include <tactility/check.h> #include <tactility/check.h>
@@ -7,6 +8,7 @@
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h> #include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h> #include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h> #include <tactility/drivers/pointer.h>
@@ -30,13 +32,7 @@ struct Ft6x36Internal {
esp_lcd_panel_io_handle_t io_handle; esp_lcd_panel_io_handle_t io_handle;
esp_lcd_touch_handle_t touch_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 // 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; 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 // 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. // 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 // 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. // 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) { if (descriptor == nullptr) {
return ERROR_NONE; 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) { if (error != ERROR_NONE) {
return error; return error;
} }
vTaskDelay(pdMS_TO_TICKS(50)); 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) { if (error != ERROR_NONE) {
return error; return error;
} }
@@ -101,20 +99,13 @@ static error_t start(Device* device) {
} }
internal->reset_descriptor = nullptr; internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor"); LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
free(internal); free(internal);
return ERROR_RESOURCE; 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); esp_err_t ret = create_io_handle(parent, &internal->io_handle);
@@ -126,7 +117,7 @@ static error_t start(Device* device) {
return ERROR_RESOURCE; 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"); LOG_E(TAG, "Failed to pulse reset pin");
esp_lcd_panel_io_del(internal->io_handle); esp_lcd_panel_io_del(internal->io_handle);
if (internal->reset_descriptor != nullptr) { 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. // why); esp_lcd_touch just skips its own no-op reset step when this is NC.
.rst_gpio_num = GPIO_NUM_NC, .rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = pin_or_nc(config->pin_interrupt), .int_gpio_num = pin_or_nc(config->pin_interrupt),
// FT6x36's reset and interrupt lines are both fixed active-low in hardware.
.levels = { .levels = {
.reset = config->reset_active_high ? 1u : 0u, .reset = 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u, .interrupt = 0u,
}, },
.flags = { .flags = {
.swap_xy = config->swap_xy ? 1u : 0u, .swap_xy = config->swap_xy ? 1u : 0u,
@@ -57,10 +57,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -25,7 +25,6 @@ struct Gc9a01Config {
uint8_t transaction_queue_depth; uint8_t transaction_queue_depth;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16, .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, .vendor_config = nullptr,
}; };
@@ -35,11 +35,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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; bool mirror_y;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+3 -2
View File
@@ -84,9 +84,10 @@ static error_t start(Device* device) {
.y_max = config->y_max, .y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset), .rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt), .int_gpio_num = pin_or_nc(config->pin_interrupt),
// GT911's reset and interrupt lines are both fixed active-low in hardware.
.levels = { .levels = {
.reset = config->reset_active_high ? 1u : 0u, .reset = 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u, .interrupt = 0u,
}, },
.flags = { .flags = {
.swap_xy = config->swap_xy ? 1u : 0u, .swap_xy = config->swap_xy ? 1u : 0u,
@@ -54,10 +54,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -23,7 +23,6 @@ struct Hx8357Config {
uint32_t pixel_clock_hz; uint32_t pixel_clock_hz;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; struct Device* backlight;
}; };
+3 -2
View File
@@ -264,9 +264,10 @@ static error_t start(Device* device) {
free(internal); free(internal);
return ERROR_RESOURCE; 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)); 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)); 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 // 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. // 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. // 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) { if (descriptor == nullptr) {
return ERROR_NONE; 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) { if (error != ERROR_NONE) {
return error; return error;
} }
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
error = gpio_descriptor_set_level(descriptor, !active_high); error = gpio_descriptor_set_level(descriptor, false);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
return error; return error;
} }
@@ -117,20 +117,13 @@ static error_t start(Device* device) {
internal->reset_descriptor = nullptr; internal->reset_descriptor = nullptr;
internal->reset_active_high = config->reset_active_high; internal->reset_active_high = config->reset_active_high;
if (config->pin_reset.gpio_controller != nullptr) { 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) { if (internal->reset_descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor"); LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
vSemaphoreDelete(internal->draw_done_semaphore); vSemaphoreDelete(internal->draw_done_semaphore);
free(internal); free(internal);
return ERROR_RESOURCE; 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 = { 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 // 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. // if start_device fails (see device_start() in TactilityKernel), so a partial failure here would leak.
bool ok = 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_reset(internal->panel_handle) == ESP_OK &&
esp_lcd_panel_init(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); (!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) { static error_t ili9341_reset(Device* device) {
auto* internal = static_cast<Ili9341Internal*>(device_get_driver_data(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) { if (error != ERROR_NONE) {
return error; return error;
} }
@@ -65,10 +65,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -29,7 +29,6 @@ struct Ili9488Config {
uint8_t transaction_queue_depth; uint8_t transaction_queue_depth;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = nullptr,
}; };
@@ -40,10 +40,6 @@ properties:
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set. interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel: ldo-channel:
type: int type: int
required: true 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 // 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()). // DBI command interface (see esp_lcd_ili9881c's panel_ili9881c_reset()).
struct GpioPinSpec pin_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 // 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 // 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = &vendor_config,
}; };
@@ -39,10 +39,6 @@ properties:
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set. interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel: ldo-channel:
type: int type: int
required: true 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 // 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()). // DBI command interface (see esp_lcd_jd9165's panel_jd9165_reset()).
struct GpioPinSpec pin_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 // 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 // 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = &vendor_config,
}; };
@@ -63,10 +63,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -27,7 +27,6 @@ struct Jd9853Config {
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16, .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, .vendor_config = &vendor_config,
}; };
@@ -57,18 +57,15 @@ static void on_click(void* arg) {
// region Pin acquisition // region Pin acquisition
static error_t acquire_pin(const GpioPinSpec& spec, GpioInterruptType interrupt_type, void (*callback)(void*), void* arg, GpioDescriptor** out_descriptor) { 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) { if (descriptor == nullptr) {
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
gpio_flags_t flags = GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP; error_t error = gpio_descriptor_add_callback(descriptor, callback, arg);
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);
}
if (error == ERROR_NONE) { if (error == ERROR_NONE) {
error = gpio_descriptor_enable_interrupt(descriptor); error = gpio_descriptor_enable_interrupt(descriptor);
} }
@@ -3,6 +3,7 @@
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h> #include <tactility/drivers/gpio_descriptor.h>
#include <tactility/log.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) { static error_t get_button_pressed(Device* device, bool* out_pressed) {
auto* internal = GET_INTERNAL(device); auto* internal = GET_INTERNAL(device);
bool high = true; return gpio_descriptor_get_level(internal->pin_enter, out_pressed);
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;
} }
error_t tpager_encoder_read_delta(Device* device, int32_t* out_pulses) { error_t tpager_encoder_read_delta(Device* device, int32_t* out_pulses) {
@@ -148,7 +142,7 @@ static error_t start(Device* device) {
return error; 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) { if (internal->pin_enter == nullptr) {
pcnt_unit_stop(internal->pcnt_unit); pcnt_unit_stop(internal->pcnt_unit);
pcnt_del_unit(internal->pcnt_unit); pcnt_del_unit(internal->pcnt_unit);
@@ -156,15 +150,6 @@ static error_t start(Device* device) {
return ERROR_RESOURCE; 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); device_set_driver_data(device, internal);
return ERROR_NONE; return ERROR_NONE;
} }
@@ -2,11 +2,13 @@
// Matrix-scan and keymap logic ported from the M5Stack Cardputer keyboard driver at // 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). // https://github.com/m5stack/M5Cardputer-UserDemo/tree/main/main/hal/keyboard (MIT licensed).
#include <drivers/cardputer_keyboard.h> #include <drivers/cardputer_keyboard.h>
#include <m5stack_module.h> #include <m5stack_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/keyboard.h> #include <tactility/drivers/keyboard.h>
#include <tactility/error.h> #include <tactility/error.h>
@@ -120,11 +122,7 @@ static error_t start(Device* device) {
for (int i = 0; i < CARDPUTER_OUTPUT_COUNT; i++) { for (int i = 0; i < CARDPUTER_OUTPUT_COUNT; i++) {
const auto& pin = config->pins_output[i]; const auto& pin = config->pins_output[i];
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_OUTPUT, 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;
}
if (descriptor == nullptr) { if (descriptor == nullptr) {
LOG_E(TAG, "Failed to configure output pin %d", i); LOG_E(TAG, "Failed to configure output pin %d", i);
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
@@ -141,8 +139,9 @@ static error_t start(Device* device) {
const auto& pin = config->pins_input[i]; const auto& pin = config->pins_input[i];
// Rows float high and are pulled low through a pressed key by the active output line, // 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. // 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); auto flags = pin.flags | GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP;
if (descriptor == nullptr || gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP) != ERROR_NONE) { 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); LOG_E(TAG, "Failed to configure input pin %d", i);
for (int j = 0; j < CARDPUTER_OUTPUT_COUNT; j++) { for (int j = 0; j < CARDPUTER_OUTPUT_COUNT; j++) {
gpio_descriptor_release(internal->output_descriptors[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; auto address = GET_CONFIG(device)->address;
uint8_t bit = 1 << descriptor->pin; 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); return i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY);
} else { } else {
return i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY); 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; 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; return ERROR_NONE;
} }
@@ -161,6 +165,8 @@ static error_t get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
f |= GPIO_FLAG_HIGH_IMPEDANCE; f |= GPIO_FLAG_HIGH_IMPEDANCE;
} }
f |= (descriptor->flags & GPIO_FLAG_ACTIVE_LOW);
*flags = f; *flags = f;
return ERROR_NONE; return ERROR_NONE;
} }
@@ -9,8 +9,8 @@
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/display.h> #include <tactility/drivers/display.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/error.h> #include <tactility/error.h>
#include <tactility/log.h> #include <tactility/log.h>
@@ -70,17 +70,16 @@ static error_t perform_hardware_reset(const RgbDisplayConfig* config) {
return ERROR_NONE; 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) { if (descriptor == nullptr) {
LOG_E(TAG, "Failed to acquire reset GPIO descriptor"); LOG_E(TAG, "Failed to acquire reset GPIO descriptor");
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
bool ok = gpio_descriptor_set_flags(descriptor, GPIO_FLAG_DIRECTION_OUTPUT) == ERROR_NONE; bool ok = gpio_descriptor_set_level(descriptor, true) == ERROR_NONE;
ok = ok && gpio_descriptor_set_level(descriptor, config->reset_active_high) == ERROR_NONE;
if (ok) { if (ok) {
delay_millis(100); 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); delay_millis(10);
} }
@@ -23,10 +23,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
power-on-delay-ms: power-on-delay-ms:
type: int type: int
default: 0 default: 0
@@ -22,7 +22,6 @@ struct Ssd1306Config {
// Reset pin. GPIO_PIN_SPEC_NONE skips the reset toggle entirely. // Reset pin. GPIO_PIN_SPEC_NONE skips the reset toggle entirely.
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// See the 'power-on-delay-ms' binding property. // See the 'power-on-delay-ms' binding property.
uint32_t power_on_delay_ms; 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_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)); 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)); vTaskDelay(pdMS_TO_TICKS(100));
} }
@@ -37,11 +37,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Interrupt GPIO pin 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 default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command description: Reset GPIO pin. Falls back to a software reset (sent over the DBI command
interface) if not set. interface) if not set.
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
ldo-channel: ldo-channel:
type: int type: int
required: true 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 // 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()). // DBI command interface (see esp_lcd_st7123's panel_st7123_reset()).
struct GpioPinSpec pin_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 // 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 // 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. // 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_reset;
struct GpioPinSpec pin_interrupt; struct GpioPinSpec pin_interrupt;
bool reset_active_high;
bool interrupt_active_high;
}; };
#ifdef __cplusplus #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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = &vendor_config,
}; };
@@ -75,9 +75,10 @@ static error_t start(Device* device) {
.y_max = config->y_max, .y_max = config->y_max,
.rst_gpio_num = pin_or_nc(config->pin_reset), .rst_gpio_num = pin_or_nc(config->pin_reset),
.int_gpio_num = pin_or_nc(config->pin_interrupt), .int_gpio_num = pin_or_nc(config->pin_interrupt),
// ST7123's reset and interrupt lines are both fixed active-low in hardware.
.levels = { .levels = {
.reset = config->reset_active_high ? 1u : 0u, .reset = 0u,
.interrupt = config->interrupt_active_high ? 1u : 0u, .interrupt = 0u,
}, },
.flags = { .flags = {
.swap_xy = config->swap_xy ? 1u : 0u, .swap_xy = config->swap_xy ? 1u : 0u,
@@ -233,10 +233,6 @@ properties:
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Optional hardware reset pin for the panel. Falls back to a software reset description: Optional hardware reset pin for the panel. Falls back to a software reset
(sent over the 3-wire bus) if not set. (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: mirror-by-cmd:
type: boolean type: boolean
default: false default: false
@@ -88,7 +88,6 @@ struct St7701Config {
// Optional hardware reset pin for the panel. GPIO_PIN_SPEC_NONE falls back to a software // 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()). // reset sent over the 3-wire bus (see esp_lcd_st7701's panel_st7701_reset()).
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// See the 'mirror-by-cmd' and 'auto-del-panel-io' binding properties. // See the 'mirror-by-cmd' and 'auto-del-panel-io' binding properties.
bool mirror_by_cmd; 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, .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = &vendor_config,
}; };
@@ -67,10 +67,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -28,7 +28,6 @@ struct St7735Config {
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = nullptr,
}; };
@@ -59,10 +59,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" 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. // Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up.
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16, .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, .vendor_config = nullptr,
}; };
@@ -67,10 +67,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -28,7 +28,6 @@ struct St7789Config {
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = nullptr,
}; };
@@ -59,10 +59,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" 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. // Gamma curve preset index [0,3], sent via the MIPI DCS GAMSET (0x26) command at bring-up.
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16, .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, .vendor_config = nullptr,
}; };
@@ -67,10 +67,6 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Reset GPIO pin description: Reset GPIO pin
reset-active-high:
type: boolean
default: false
description: Whether the reset pin is active high
backlight: backlight:
type: phandle type: phandle
default: "NULL" default: "NULL"
@@ -28,7 +28,6 @@ struct St7796Config {
uint8_t gamma_curve; uint8_t gamma_curve;
struct GpioPinSpec pin_dc; struct GpioPinSpec pin_dc;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
// Optional reference to this display's backlight device, NULL if none. // Optional reference to this display's backlight device, NULL if none.
struct Device* backlight; 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, .rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel, .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, .vendor_config = nullptr,
}; };
@@ -68,7 +68,3 @@ properties:
type: phandles type: phandles
default: GPIO_PIN_SPEC_NONE default: GPIO_PIN_SPEC_NONE
description: Optional reset GPIO pin, pulsed once at start (20 ms assert, 60 ms settle) 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_row;
uint8_t sym_col; uint8_t sym_col;
struct GpioPinSpec pin_reset; struct GpioPinSpec pin_reset;
bool reset_active_high;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+9 -4
View File
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/tca8418.h> #include <drivers/tca8418.h>
#include <tca8418_module.h> #include <tca8418_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/delay.h> #include <tactility/delay.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h> #include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/keyboard.h> #include <tactility/drivers/keyboard.h>
@@ -116,15 +118,18 @@ static void perform_hardware_reset(const Tca8418Config* config) {
return; 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) { if (rst == nullptr) {
return; return;
} }
gpio_descriptor_set_flags(rst, GPIO_FLAG_DIRECTION_OUTPUT); gpio_descriptor_set_level(rst, false);
gpio_descriptor_set_level(rst, config->reset_active_high);
delay_millis(20); delay_millis(20);
gpio_descriptor_set_level(rst, !config->reset_active_high); gpio_descriptor_set_level(rst, true);
gpio_descriptor_release(rst); gpio_descriptor_release(rst);
delay_millis(60); delay_millis(60);
} }
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#include <drivers/xpt2046_softspi.h> #include <drivers/xpt2046_softspi.h>
#include <xpt2046_softspi_module.h> #include <xpt2046_softspi_module.h>
#include <tactility/check.h> #include <tactility/check.h>
#include <tactility/device.h> #include <tactility/device.h>
#include <tactility/driver.h> #include <tactility/driver.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h> #include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/pointer.h> #include <tactility/drivers/pointer.h>
#include <tactility/drivers/power_supply.h> #include <tactility/drivers/power_supply.h>
@@ -15,7 +17,7 @@
#include <cstdlib> #include <cstdlib>
#include <new> #include <new>
#define TAG "XPT2046SoftSPI" constexpr auto* TAG = "XPT2046SoftSPI";
#define GET_CONFIG(device) (static_cast<const Xpt2046SoftSpiConfig*>((device)->config)) #define GET_CONFIG(device) (static_cast<const Xpt2046SoftSpiConfig*>((device)->config))
// Rough LiPo discharge curve floor, used together with the configured reference voltage // Rough LiPo discharge curve floor, used together with the configured reference voltage
@@ -73,10 +75,10 @@ static error_t start(Device* device) {
} }
*internal = {}; *internal = {};
internal->mosi = gpio_descriptor_acquire(config->pin_mosi.gpio_controller, config->pin_mosi.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_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_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_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) { if (internal->mosi == nullptr || internal->miso == nullptr || internal->sck == nullptr || internal->cs == nullptr) {
LOG_E(TAG, "Failed to acquire GPIO descriptors"); LOG_E(TAG, "Failed to acquire GPIO descriptors");
@@ -85,15 +87,8 @@ static error_t start(Device* device) {
return ERROR_RESOURCE; 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. // Idle state: CS high (deselected), SCK/MOSI low.
ok = ok && bool ok = gpio_descriptor_set_level(internal->cs, false) == ERROR_NONE &&
gpio_descriptor_set_level(internal->cs, true) == ERROR_NONE &&
gpio_descriptor_set_level(internal->sck, false) == ERROR_NONE && gpio_descriptor_set_level(internal->sck, false) == ERROR_NONE &&
gpio_descriptor_set_level(internal->mosi, 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) { static int read_spi_command(Xpt2046SoftSpiInternal* internal, uint8_t command) {
int result = 0; int result = 0;
gpio_descriptor_set_level(internal->cs, false); gpio_descriptor_set_level(internal->cs, true);
delay_micros(1); delay_micros(1);
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {
@@ -169,7 +164,7 @@ static int read_spi_command(Xpt2046SoftSpiInternal* internal, uint8_t command) {
delay_micros(1); delay_micros(1);
} }
gpio_descriptor_set_level(internal->cs, true); gpio_descriptor_set_level(internal->cs, false);
return result; return result;
} }
@@ -15,7 +15,7 @@ void release_pin(GpioDescriptor** gpio_descriptor);
* If the pin spec is invalid, the pointer is set to null. * If the pin spec is invalid, the pointer is set to null.
* @return true if the pin was acquired successfully * @return true if the pin was acquired successfully
*/ */
bool acquire_pin_or_set_null(const GpioPinSpec& pin_spec, GpioDescriptor** gpio_descriptor); bool acquire_pin_or_set_null(const GpioPinSpec& pin_spec, gpio_flags_t direction_flags, GpioDescriptor** gpio_descriptor);
/** /**
* Safely acquire the native pin value. * Safely acquire the native pin value.

Some files were not shown because too many files have changed in this diff Show More