GPIO refactored (#495)

* **Refactor**
  * GPIO subsystem moved to a descriptor-based model for per-pin ownership and runtime pin management; many platform drivers now acquire/release descriptors.
  * Device trees and drivers now use GPIO phandle-style pin specifications across all boards and all drivers.

* **Behavior**
  * Device list now encodes per-device status (ok/disabled); boot will skip disabled devices accordingly.

* **Deprecation**
  * Legacy GPIO HAL marked deprecated and replaced with descriptor-based interfaces.

* **Chores**
  * Bindings and platform configs updated to the new GPIO pin-spec format.
This commit is contained in:
Ken Van Hoeylandt
2026-02-11 20:34:54 +01:00
committed by GitHub
parent dff93cb655
commit 26c17986c6
80 changed files with 1129 additions and 665 deletions
@@ -43,16 +43,6 @@ struct Device {
struct DeviceInternal* internal;
};
/**
* Holds a device pointer and a compatible string.
* The device must not be constructed, added or started yet.
* This is used by the devicetree code generator and the application init sequence.
*/
struct CompatibleDevice {
struct Device* device;
const char* compatible;
};
/**
* Initialize the properties of a device.
*
@@ -10,24 +10,24 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
#define GPIO_OPTIONS_MASK 0x1f
#define GPIO_ACTIVE_HIGH (0 << 0)
#define GPIO_ACTIVE_LOW (1 << 0)
#define GPIO_DIRECTION_INPUT (1 << 1)
#define GPIO_DIRECTION_OUTPUT (1 << 2)
#define GPIO_DIRECTION_INPUT_OUTPUT (GPIO_DIRECTION_INPUT | GPIO_DIRECTION_OUTPUT)
#define GPIO_PULL_UP (0 << 3)
#define GPIO_PULL_DOWN (1 << 4)
#define GPIO_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
#define GPIO_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_INTERRUPT_BITMASK) >> 5)
#define GPIO_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5))
#define GPIO_FLAGS_MASK 0x1f
#define GPIO_PIN_NONE -1
#define GPIO_PIN_SPEC_NONE ((struct GpioPinSpec) { NULL, 0, GPIO_FLAG_NONE })
#define GPIO_FLAG_NONE 0
#define GPIO_FLAG_ACTIVE_HIGH (0 << 0)
#define GPIO_FLAG_ACTIVE_LOW (1 << 0)
#define GPIO_FLAG_DIRECTION_INPUT (1 << 1)
#define GPIO_FLAG_DIRECTION_OUTPUT (1 << 2)
#define GPIO_FLAG_DIRECTION_INPUT_OUTPUT (GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_DIRECTION_OUTPUT)
#define GPIO_FLAG_PULL_UP (0 << 3)
#define GPIO_FLAG_PULL_DOWN (1 << 4)
#define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
#define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5)
#define GPIO_FLAG_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5))
typedef enum {
GPIO_INTERRUPT_DISABLE = 0,
GPIO_INTERRUPT_POS_EDGE = 1,
@@ -35,35 +35,39 @@ typedef enum {
GPIO_INTERRUPT_ANY_EDGE = 3,
GPIO_INTERRUPT_LOW_LEVEL = 4,
GPIO_INTERRUPT_HIGH_LEVEL = 5,
GPIO__MAX,
GPIO_MAX,
} GpioInterruptType;
enum GpioOwnerType {
/** @brief Pin is unclaimed/free */
GPIO_OWNER_NONE,
/** @brief Pin is owned by a hog */
GPIO_OWNER_HOG,
/** @brief Pin is claimed by a regular consumer */
GPIO_OWNER_GPIO,
/** @brief Pin is owned by SPI. This is a special case because of CS pin transfer from hog to SPI controller. */
GPIO_OWNER_SPI
};
/** The index of a GPIO pin on a GPIO Controller */
typedef uint8_t gpio_pin_t;
/** Specifies the configuration flags for a GPIO pin (or set of pins) */
typedef uint16_t gpio_flags_t;
/** A configuration for a single GPIO pin */
struct GpioPinConfig {
/**
* Specifies a pin and its properties for a specific GPIO controller.
* Used by the devicetree, drivers and application code to refer to GPIO pins and acquire them via the gpio_controller API.
*/
struct GpioPinSpec {
/** GPIO device controlling the pin */
const struct Device* port;
struct Device* gpio_controller;
/** The pin's number on the device */
gpio_pin_t pin;
/** The pin's configuration flags as specified in devicetree */
gpio_flags_t flags;
};
/**
* Check if the pin is ready to be used.
*
* @param pinConfig the specifications of the pin
* @return true if the pin is ready to be used
*/
static inline bool gpio_is_ready(const struct GpioPinConfig* pinConfig) {
return device_is_ready(pinConfig->port);
}
#ifdef __cplusplus
}
#endif
@@ -10,106 +10,136 @@ extern "C" {
#include <tactility/error.h>
struct Device;
struct GpioDescriptor;
struct GpioControllerApi {
/**
* @brief Sets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in,out] descriptor the pin descriptor
* @param[in] high true to set the pin high, false to set it low
* @return ERROR_NONE if successful
*/
error_t (*set_level)(struct Device* device, gpio_pin_t pin, bool high);
error_t (*set_level)(struct GpioDescriptor* descriptor, bool high);
/**
* @brief Gets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] descriptor the pin descriptor
* @param[out] high pointer to store the pin level
* @return ERROR_NONE if successful
*/
error_t (*get_level)(struct Device* device, gpio_pin_t pin, bool* high);
error_t (*get_level)(struct GpioDescriptor* descriptor, bool* high);
/**
* @brief Configures the options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] options configuration flags (direction, pull-up/down, etc.)
* @param[in,out] descriptor the pin descriptor
* @param[in] flags configuration flags (direction, pull-up/down, etc.)
* @return ERROR_NONE if successful
*/
error_t (*set_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t options);
error_t (*set_flags)(struct GpioDescriptor* descriptor, gpio_flags_t flags);
/**
* @brief Gets the configuration options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[out] options pointer to store the configuration flags
* @param[in] descriptor the pin descriptor
* @param[out] flags pointer to store the configuration flags
* @return ERROR_NONE if successful
*/
error_t (*get_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t* options);
error_t (*get_flags)(struct GpioDescriptor* descriptor, gpio_flags_t* flags);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[out] count pointer to store the number of pins
* @brief Gets the native pin number associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] pin_number pointer to store the pin number
* @return ERROR_NONE if successful
*/
error_t (*get_pin_count)(struct Device* device, uint32_t* count);
error_t (*get_native_pin_number)(struct GpioDescriptor* descriptor, void* pin_number);
};
struct GpioDescriptor* gpio_descriptor_acquire(
struct Device* controller,
gpio_pin_t pin_number,
enum GpioOwnerType owner
);
error_t gpio_descriptor_release(struct GpioDescriptor* descriptor);
/**
* @brief Gets the pin number associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] pin pointer to store the pin number
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin);
/**
* @brief Gets the pin owner type associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] owner_type pointer to output owner type
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_get_owner_type(struct GpioDescriptor* descriptor, enum GpioOwnerType* owner_type);
/**
* @brief Sets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] descriptor the pin descriptor
* @param[in] high true to set the pin high, false to set it low
* @return ERROR_NONE if successful
*/
error_t gpio_controller_set_level(struct Device* device, gpio_pin_t pin, bool high);
error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high);
/**
* @brief Gets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] descriptor the pin descriptor
* @param[out] high pointer to store the pin level
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_level(struct Device* device, gpio_pin_t pin, bool* high);
error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high);
/**
* @brief Configures the options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] options configuration flags (direction, pull-up/down, etc.)
* @param[in] descriptor the pin descriptor
* @param[in] flags configuration flags (direction, pull-up/down, etc.)
* @return ERROR_NONE if successful
*/
error_t gpio_controller_set_options(struct Device* device, gpio_pin_t pin, gpio_flags_t options);
error_t gpio_descriptor_set_flags(struct GpioDescriptor* descriptor, gpio_flags_t flags);
/**
* @brief Gets the configuration options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[out] options pointer to store the configuration flags
* @param[in] descriptor the pin descriptor
* @param[out] flags pointer to store the configuration flags
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_options(struct Device* device, gpio_pin_t pin, gpio_flags_t* options);
error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_t* flags);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[out] count pointer to store the number of pins
* @return ERROR_NONE if successful
*/
* @brief Gets the native pin number associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] pin_number pointer to store the pin number
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[out] count pointer to store the number of pins
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count);
/**
* @brief Configures the options for a GPIO pin using a pin configuration structure.
* @param[in] device the GPIO controller device
* @param[in] config the pin configuration structure
* @brief Initializes GPIO descriptors for a controller.
* @param[in,out] device the GPIO controller device
* @param[in] controller_context pointer to store in the controller's internal data
* @return ERROR_NONE if successful
*/
static inline error_t gpio_set_options_config(struct Device* device, const struct GpioPinConfig* config) {
return gpio_controller_set_options(device, config->pin, config->flags);
}
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context);
/**
* @brief Deinitializes GPIO descriptors for a controller.
* @param[in,out] device the GPIO controller device
* @return ERROR_NONE if successful
*/
error_t gpio_controller_deinit_descriptors(struct Device* device);
extern const struct DeviceType GPIO_CONTROLLER_TYPE;
@@ -0,0 +1,16 @@
#pragma once
#include "gpio.h"
struct Device;
struct GpioDescriptor {
/** @brief The controller that owns this pin */
struct Device* controller;
/** @brief Physical pin number */
gpio_pin_t pin;
/** @brief Current owner */
enum GpioOwnerType owner_type;
/** @brief Implementation-specific context (e.g. from esp32 controller internally) */
void* controller_context;
};
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <stddef.h>
struct Device;
/** Signals the intended state of a device. */
enum DtsDeviceStatus {
/** Device should be constructed, added and started. */
DTS_DEVICE_STATUS_OKAY,
/** Device should be constructed and added, but not started. */
DTS_DEVICE_STATUS_DISABLED
};
/**
* Holds a device pointer and a compatible string.
* The device must not be constructed, added or started yet.
* This is used by the devicetree code generator and the application init sequence.
*/
struct DtsDevice {
/** A pointer to a device. */
struct Device* device;
/** The compatible string contains the identifier of the driver that this device is compatible with. */
const char* compatible;
/** The intended state of the device. */
const enum DtsDeviceStatus status;
};
/** Signals the end of the device array in the generated dts code. */
#define DTS_DEVICE_TERMINATOR { NULL, NULL, DTS_DEVICE_STATUS_DISABLED }
@@ -12,10 +12,10 @@ extern "C" {
* Initialize the kernel with platform and device modules, and a device tree.
* @param platform_module The platform module to start. This module should not be constructed yet.
* @param device_module The device module to start. This module should not be constructed yet. This parameter can be NULL.
* @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL }. This parameter can be NULL.
* @param dts_devices The list of generated devices from the devicetree. The array must be terminated with DTS_DEVICE_TERMINATOR. This parameter can be NULL.
* @return ERROR_NONE on success, otherwise an error code
*/
error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct CompatibleDevice devicetree_devices[]);
error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct DtsDevice dts_devices[]);
#ifdef __cplusplus
}