Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

281 lines
6.8 KiB

/*
* Copyright (c) 2024 Texas Instruments Incorporated
* Copyright (c) 2024 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_cc23x0_gpio
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <driverlib/clkctl.h>
#include <driverlib/gpio.h>
#include <inc/hw_ioc.h>
#define IOC_ADDR(index) (IOC_BASE + IOC_O_IOC0 + (sizeof(uint32_t) * (index)))
struct gpio_cc23x0_config {
/* gpio_driver_config needs to be first */
struct gpio_driver_config common;
};
struct gpio_cc23x0_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
sys_slist_t callbacks;
};
static void set_pin_mask_non_atomic(uint8_t index, uint32_t registerBaseAddress)
{
GPIOSetConfigDio(GPIO_BASE + registerBaseAddress, BIT(index));
}
static int gpio_cc23x0_config(const struct device *port, gpio_pin_t pin, gpio_flags_t flags)
{
uint32_t config = 0;
uint32_t iocfg_reg = IOC_ADDR(pin);
gpio_flags_t direction = flags & GPIO_DIR_MASK;
if (flags & GPIO_PULL_UP) {
config |= IOC_IOC0_PULLCTL_PULL_UP;
} else if (flags & GPIO_PULL_DOWN) {
config |= IOC_IOC0_PULLCTL_PULL_DOWN;
} else {
config |= IOC_IOC0_PULLCTL_PULL_DIS;
}
if (!(flags & GPIO_SINGLE_ENDED)) {
config |= IOC_IOC0_IOMODE_NORMAL;
} else {
if (flags & GPIO_LINE_OPEN_DRAIN) {
config |= IOC_IOC0_IOMODE_OPEND;
} else {
config |= IOC_IOC0_IOMODE_OPENS;
}
}
if (direction & GPIO_INPUT) {
config |= IOC_IOC0_INPEN_EN | IOC_IOC0_HYSTEN_EN;
}
GPIOSetConfigDio(iocfg_reg, config);
if (flags & GPIO_OUTPUT) {
if (flags & GPIO_OUTPUT_INIT_HIGH) {
GPIOSetDio(pin);
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
GPIOClearDio(pin);
}
GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_ENABLE);
} else {
GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_DISABLE);
}
return 0;
}
#ifdef CONFIG_GPIO_GET_CONFIG
static int gpio_cc23x0_get_config(const struct device *port, gpio_pin_t pin, gpio_flags_t *flags)
{
uint32_t out_flag = 0;
uint32_t iocfg_reg = IOC_ADDR(pin);
uint32_t config = GPIOGetConfigDio(iocfg_reg);
/* GPIO input/output configuration flags */
if (config & IOC_IOC0_INPEN_EN) {
out_flag |= GPIO_INPUT;
}
if (GPIOGetOutputEnableDio(pin)) {
out_flag |= GPIO_OUTPUT;
if (GPIOReadDio(pin)) {
out_flag |= GPIO_OUTPUT_INIT_HIGH;
} else {
/* This is the default value. If not explicitly set,
* the returned config will not be symmetric
*/
out_flag |= GPIO_OUTPUT_INIT_LOW;
}
}
/* GPIO interrupt configuration flags */
if ((config & IOC_IOC0_EDGEDET_M) != IOC_IOC0_EDGEDET_EDGE_DIS) {
if (config & IOC_IOC0_EDGEDET_EDGE_POS) {
out_flag |= GPIO_INT_EDGE_RISING;
}
if (config & IOC_IOC0_EDGEDET_EDGE_NEG) {
out_flag |= GPIO_INT_EDGE_FALLING;
}
} else {
/* This is the default value. If not explicitly set,
* the returned config will not be symmetric
*/
out_flag |= GPIO_INT_DISABLE;
}
/* GPIO pin drive flags */
if (config & IOC_IOC0_IOMODE_OPENS) {
out_flag |= GPIO_OPEN_SOURCE;
}
if (config & IOC_IOC0_IOMODE_OPEND) {
out_flag |= IOC_IOC0_IOMODE_OPEND;
}
if (config & IOC_IOC0_PULLCTL_PULL_UP) {
out_flag |= GPIO_PULL_UP;
}
if (config & IOC_IOC0_PULLCTL_PULL_DOWN) {
out_flag |= GPIO_PULL_DOWN;
}
*flags = out_flag;
return 0;
}
#endif
static int gpio_cc23x0_port_get_raw(const struct device *port, uint32_t *value)
{
*value = GPIOReadMultiDio(GPIO_DIO_ALL_MASK);
return 0;
}
static int gpio_cc23x0_port_set_masked_raw(const struct device *port, uint32_t mask, uint32_t value)
{
GPIOWriteMultiDio(mask, value);
return 0;
}
static int gpio_cc23x0_port_set_bits_raw(const struct device *port, uint32_t mask)
{
GPIOSetMultiDio(mask);
return 0;
}
static int gpio_cc23x0_port_clear_bits_raw(const struct device *port, uint32_t mask)
{
GPIOClearMultiDio(mask);
return 0;
}
static int gpio_cc23x0_port_toggle_bits(const struct device *port, uint32_t mask)
{
GPIOToggleMultiDio(mask);
return 0;
}
static int gpio_cc23x0xx_pin_interrupt_configure(const struct device *port, gpio_pin_t pin,
enum gpio_int_mode mode, enum gpio_int_trig trig)
{
if (mode == GPIO_INT_MODE_LEVEL) {
return -ENOTSUP;
}
uint32_t config = GPIOGetConfigDio(IOC_ADDR(pin)) & ~IOC_IOC0_EDGEDET_M;
if (mode == GPIO_INT_MODE_DISABLED) {
config |= IOC_IOC1_EDGEDET_EDGE_DIS;
GPIOSetConfigDio(IOC_ADDR(pin), config);
/* Disable interrupt mask */
set_pin_mask_non_atomic(pin, GPIO_O_IMCLR);
} else if (mode == GPIO_INT_MODE_EDGE) {
switch (trig) {
case GPIO_INT_TRIG_LOW:
config |= IOC_IOC1_EDGEDET_EDGE_NEG;
break;
case GPIO_INT_TRIG_HIGH:
config |= IOC_IOC1_EDGEDET_EDGE_POS;
break;
case GPIO_INT_TRIG_BOTH:
config |= IOC_IOC1_EDGEDET_EDGE_BOTH;
break;
default:
return -ENOTSUP;
}
GPIOSetConfigDio(IOC_ADDR(pin), config);
/* Enable interrupt mask */
set_pin_mask_non_atomic(pin, GPIO_O_ICLR);
set_pin_mask_non_atomic(pin, GPIO_O_IMSET);
}
return 0;
}
static int gpio_cc23x0_manage_callback(const struct device *port, struct gpio_callback *callback,
bool set)
{
struct gpio_cc23x0_data *data = port->data;
return gpio_manage_callback(&data->callbacks, callback, set);
}
static uint32_t gpio_cc23x0_get_pending_int(const struct device *dev)
{
return GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK);
}
static void gpio_cc23x0_isr(const struct device *dev)
{
struct gpio_cc23x0_data *data = dev->data;
uint32_t status = GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK);
GPIOClearEventMultiDio(status);
gpio_fire_callbacks(&data->callbacks, dev, status);
}
static int gpio_cc23x0_init(const struct device *dev)
{
/* Enable GPIO domain clock */
CLKCTLEnable(CLKCTL_BASE, CLKCTL_GPIO);
/* Enable IRQ */
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), gpio_cc23x0_isr,
DEVICE_DT_INST_GET(0), 0);
irq_enable(DT_INST_IRQN(0));
return 0;
}
static DEVICE_API(gpio, gpio_cc23x0_driver_api) = {
.pin_configure = gpio_cc23x0_config,
#ifdef CONFIG_GPIO_GET_CONFIG
.pin_get_config = gpio_cc23x0_get_config,
#endif
.port_get_raw = gpio_cc23x0_port_get_raw,
.port_set_masked_raw = gpio_cc23x0_port_set_masked_raw,
.port_set_bits_raw = gpio_cc23x0_port_set_bits_raw,
.port_clear_bits_raw = gpio_cc23x0_port_clear_bits_raw,
.port_toggle_bits = gpio_cc23x0_port_toggle_bits,
.pin_interrupt_configure = gpio_cc23x0xx_pin_interrupt_configure,
.manage_callback = gpio_cc23x0_manage_callback,
.get_pending_int = gpio_cc23x0_get_pending_int,
};
static const struct gpio_cc23x0_config gpio_cc23x0_config_0 = {
.common = {/* Read ngpios from DT */
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}};
static struct gpio_cc23x0_data gpio_cc23x0_data_0;
DEVICE_DT_INST_DEFINE(0, gpio_cc23x0_init, NULL, &gpio_cc23x0_data_0, &gpio_cc23x0_config_0,
PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_cc23x0_driver_api);