Files
mr-library/drivers/gpio/gpio.c
MacRsh 8bfc6c9390 feat(service): Added service macro functions.
1.New macros for obtaining the number of variable parameters, adaptive parameter concatenation macros, and separated concatenation macros have been added (in preparation for the device tree).
2025-10-12 22:19:06 +08:00

368 lines
9.9 KiB
C

/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <drivers/gpio/mr_gpio.h>
#if defined(MR_USE_DRIVER_GPIO)
#include <libc/mr_malloc.h>
/* GPIO driver operations(dynamic & static) */
static mr_err_t gpio_deinit_dyn(const mr_driver_t *drv);
static mr_err_t gpio_deinit(const mr_driver_t *drv);
static mr_err_t gpio_init(const mr_driver_t *drv);
MR_DRIVER_DOPS_DYNAMIC_DEFINE(gpio, gpio_init, gpio_deinit_dyn);
MR_DRIVER_DOPS_DEFINE(gpio, gpio_init, gpio_deinit);
mr_err_t mr_gpio_init(mr_driver_t *drv, mr_gpio_data_t *data, void *priv,
mr_gpio_ops_t *ops) {
const mr_driver_dops_t *dops = MR_DRIVER_DOPS_FIND(gpio);
/* Check parameter */
MR_ASSERT(drv != MR_NULL);
MR_ASSERT(data != MR_NULL);
MR_ASSERT(ops != MR_NULL);
/* Init GPIO driver */
return mr_driver_init(drv, MR_DRIVER_TYPE_GPIO, dops, data, priv, ops);
}
mr_driver_t *mr_gpio_create(mr_gpio_data_t *data, void *priv,
mr_gpio_ops_t *ops) {
const mr_driver_dops_t *dops = MR_DRIVER_DOPS_DYNAMIC_FIND(gpio);
/* Check parameter */
MR_ASSERT(data != MR_NULL);
MR_ASSERT(ops != MR_NULL);
/* Create GPIO driver */
return mr_driver_create(MR_DRIVER_TYPE_GPIO, dops, data, priv, ops);
}
mr_err_t mr_gpio_pin_mode_set(const mr_driver_t *drv, mr_uint32_t pin,
mr_uint32_t mode) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT((mode & MR_GPIO_OTYPE_MASK) != MR_GPIO_OTYPE_MASK);
MR_ASSERT((mode & MR_GPIO_PULL_MASK) != MR_GPIO_PULL_MASK);
MR_ASSERT((mode & MR_GPIO_DIR_MASK) != MR_GPIO_DIR_MASK);
MR_ASSERT(pin < 32);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Check if pin is existed */
if (!(gp_data->exist_mask & (1U << pin))) {
return -MR_EINVAL;
}
/* Set pin active level */
if (!(mode & MR_GPIO_ACTIVE_LOW)) {
gp_data->invert &= ~(1U << pin);
} else {
gp_data->invert |= (1U << pin);
}
/* Set pin mode */
ret = gp_ops->pin_mode_set(drv, pin, mode);
if (ret != 0) {
return ret;
}
/* If pin is output, set pin default value */
if (mode & MR_GPIO_DIR_OUTPUT) {
return gp_ops->pin_set(drv, pin, !!(mode & MR_GPIO_LEVEL_MASK));
}
return 0;
}
mr_err_t mr_gpio_pin_mode_get(const mr_driver_t *drv, mr_uint32_t pin,
mr_uint32_t *mode) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT(mode != MR_NULL);
MR_ASSERT(pin < 32);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Check if pin is existed */
if (!(gp_data->exist_mask & (1U << pin))) {
return -MR_EINVAL;
}
/* Get pin mode */
ret = gp_ops->pin_mode_get(drv, pin, mode);
if (ret != 0) {
return ret;
}
/* Get pin active level */
if (!(gp_data->invert & (1U << pin))) {
*mode &= ~MR_GPIO_ACTIVE_LOW;
} else {
*mode |= MR_GPIO_ACTIVE_LOW;
}
return 0;
}
mr_err_t mr_gpio_pin_set(const mr_driver_t *drv, mr_uint32_t pin,
mr_uint8_t value) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT(pin < 32);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Check if pin is existed */
if (!(gp_data->exist_mask & (1U << pin))) {
return -MR_EINVAL;
}
/* Set pin value */
value = (!!value) ^ (!!(gp_data->invert & (1U << pin)));
return gp_ops->pin_set(drv, pin, value);
}
int mr_gpio_pin_get(const mr_driver_t *drv, mr_uint32_t pin) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
mr_uint8_t value;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT(pin < 32);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Check if pin is existed */
if (!(gp_data->exist_mask & (1U << pin))) {
return -MR_EINVAL;
}
/* Get pin value */
ret = gp_ops->pin_get(drv, pin, &value);
if (ret != 0) {
return (int)ret;
}
return (int)((!!value) ^ (!!(gp_data->invert & (1U << pin))));
}
mr_err_t mr_gpio_pin_toggle(const mr_driver_t *drv, mr_uint32_t pin) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
mr_uint8_t value;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT(pin < 32);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Check if pin is existed */
if (!(gp_data->exist_mask & (1U << pin))) {
return -MR_EINVAL;
}
/* Get pin value */
ret = gp_ops->pin_get(drv, pin, &value);
if (ret != 0) {
return (int)ret;
}
/* Toggle pin value */
value = (!!value) ^ MR_UINT8_MAX;
return gp_ops->pin_set(drv, pin, value);
}
mr_err_t mr_gpio_port_set(const mr_driver_t *drv, mr_uint32_t mask) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Set port value */
mask = mask ^ gp_data->invert;
return gp_ops->port_set(drv, mask);
}
mr_err_t mr_gpio_port_get(const mr_driver_t *drv, mr_uint32_t *mask) {
mr_gpio_data_t *gp_data;
mr_gpio_ops_t *gp_ops;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
MR_ASSERT(mask != MR_NULL);
/* Get GPIO data and operations */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Get port value */
ret = gp_ops->port_get(drv, mask);
if (ret != 0) {
return ret;
}
*mask = *mask ^ gp_data->invert;
return 0;
}
mr_err_t mr_gpio_port_toggle(const mr_driver_t *drv) {
mr_gpio_ops_t *gp_ops;
mr_uint32_t mask;
mr_err_t ret;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(MR_DRIVER_OPS(drv) != MR_NULL);
/* Get GPIO operations */
gp_ops = (mr_gpio_ops_t *)MR_DRIVER_OPS(drv);
/* Get port value */
ret = gp_ops->port_get(drv, &mask);
if (ret != 0) {
return ret;
}
/* Toggle port value */
mask = mask ^ MR_UINT32_MAX;
return gp_ops->port_set(drv, mask);
}
#if defined(MR_USE_DRIVER_GPIO_IRQ)
mr_err_t mr_gpio_irq_attach(mr_driver_t *drv, mr_waiter_t *entry) {
mr_gpio_data_t *gp_data;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(entry != MR_NULL);
/* Get GPIO data */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
/* Auto set GPIO irq event */
mr_waiter_event_set(entry, mr_waiter_event(entry) | MR_WAIT_IN);
/* Attach GPIO irq */
return mr_waiter_wait(entry, &gp_data->irq);
}
mr_err_t mr_gpio_irq_handle(mr_driver_t *drv, mr_uint32_t pin) {
mr_gpio_data_t *gp_data;
/* Check parameter */
MR_DRIVER_ASSERT(drv, MR_DRIVER_TYPE_GPIO);
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
MR_ASSERT(pin < 32);
/* Get GPIO data */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
/* Raise GPIO irq */
return mr_waitable_raise(&gp_data->irq, MR_WAIT_IN | pin);
}
#endif /* defined(MR_USE_DRIVER_GPIO_IRQ) */
static mr_err_t gpio_init(const mr_driver_t *drv) {
mr_gpio_data_t *gp_data;
mr_err_t ret;
/* Check parameter */
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
/* Get GPIO data */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
#if defined(MR_USE_DRIVER_GPIO_IRQ)
/* Init GPIO irq */
ret = mr_waitable_init(&gp_data->irq, MR_NULL, MR_NULL);
if (ret != 0) {
return ret;
}
#else
MR_UNUSED(gp_data);
MR_UNUSED(ret);
#endif /* defined(MR_USE_DRIVER_GPIO_IRQ) */
return 0;
}
static mr_err_t gpio_deinit(const mr_driver_t *drv) {
mr_gpio_data_t *gp_data;
/* Check parameter */
MR_ASSERT(MR_DRIVER_DATA(drv) != MR_NULL);
/* Get GPIO data */
gp_data = (mr_gpio_data_t *)MR_DRIVER_DATA(drv);
#if defined(MR_USE_DRIVER_GPIO_IRQ)
/* Deinit GPIO irq */
mr_waitable_del(&gp_data->irq);
#else
MR_UNUSED(gp_data);
#endif /* defined(MR_USE_DRIVER_GPIO_IRQ) */
return 0;
}
static mr_err_t gpio_deinit_dyn(const mr_driver_t *drv) {
mr_err_t ret;
/* Deinit GPIO */
ret = gpio_deinit(drv);
if (ret != 0) {
return ret;
}
/* Free GPIO data */
mr_free(MR_DRIVER_DATA(drv));
return 0;
}
#endif /* defined(MR_USE_DRIVER_GPIO) */