zephyr/drivers/gpio/gpio_mspm0.c
Parthiban Nallathambi 455e76f68f drivers: gpio: fix pincm lut size
LUT sizes directly reflects the global data when enabled in dts
(even if no or few pins are really consumed). Also the PINCM
numbering across the series (g, l and c) is within 255, so fix
to use uint8_t to save the global space.

Signed-off-by: Parthiban Nallathambi <parthiban@linumiz.com>
2025-07-21 07:25:50 -04:00

400 lines
12 KiB
C

/*
* Copyright (c) 2025 Texas Instruments
* Copyright (c) 2025 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_mspm0_gpio
/* Zephyr includes */
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/irq.h>
/* Driverlib includes */
#include <ti/driverlib/dl_gpio.h>
struct gpio_mspm0_config {
/* gpio_mspm0_config needs to be first (doesn't actually get used) */
struct gpio_driver_config common;
/* port base address */
GPIO_Regs *base;
/* port pincm lookup table */
uint8_t *pincm_lut;
};
struct gpio_mspm0_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
sys_slist_t callbacks; /* List of interrupt callbacks */
};
/* Two polarity registers and HAL api used for pins (0-15) and pins (16-32) */
#define MSPM0_PINS_LOW_GROUP 16
/* GPIO defines */
#define GPIOA_NODE DT_NODELABEL(gpioa)
#if DT_NODE_HAS_STATUS(GPIOA_NODE, okay)
#if CONFIG_SOC_SERIES_MSPM0G
#define NUM_GPIOA_PIN 32
#define gpioa_pins NUM_GPIOA_PIN
static uint8_t gpioa_pincm_lut[NUM_GPIOA_PIN] = {
IOMUX_PINCM1, IOMUX_PINCM2, IOMUX_PINCM7, IOMUX_PINCM8, IOMUX_PINCM9, IOMUX_PINCM10,
IOMUX_PINCM11, IOMUX_PINCM14, IOMUX_PINCM19, IOMUX_PINCM20, IOMUX_PINCM21, IOMUX_PINCM22,
IOMUX_PINCM34, IOMUX_PINCM35, IOMUX_PINCM36, IOMUX_PINCM37, IOMUX_PINCM38, IOMUX_PINCM39,
IOMUX_PINCM40, IOMUX_PINCM41, IOMUX_PINCM42, IOMUX_PINCM46, IOMUX_PINCM47, IOMUX_PINCM53,
IOMUX_PINCM54, IOMUX_PINCM55, IOMUX_PINCM59, IOMUX_PINCM60, IOMUX_PINCM3, IOMUX_PINCM4,
IOMUX_PINCM5, IOMUX_PINCM6,
};
#elif CONFIG_SOC_SERIES_MSPM0L /* if CONFIG_SOC_SERIES_MSPM0L */
#define GPIOA_NODE DT_NODELABEL(gpioa)
#define NUM_GPIOA_PIN 31
#define gpioa_pins NUM_GPIOA_PIN
static uint8_t gpioa_pincm_lut[NUM_GPIOA_PIN] = {
IOMUX_PINCM1, IOMUX_PINCM2, IOMUX_PINCM7, IOMUX_PINCM8, IOMUX_PINCM9, IOMUX_PINCM10,
IOMUX_PINCM11, IOMUX_PINCM14, IOMUX_PINCM19, IOMUX_PINCM20, IOMUX_PINCM25, IOMUX_PINCM26,
IOMUX_PINCM38, IOMUX_PINCM39, IOMUX_PINCM40, IOMUX_PINCM41, IOMUX_PINCM42, IOMUX_PINCM49,
IOMUX_PINCM50, IOMUX_PINCM51, IOMUX_PINCM52, IOMUX_PINCM56, IOMUX_PINCM57, IOMUX_PINCM67,
IOMUX_PINCM68, IOMUX_PINCM69, IOMUX_PINCM73, IOMUX_PINCM74, IOMUX_PINCM3, IOMUX_PINCM4,
IOMUX_PINCM5
};
#else
#error "Series lookup table not supported"
#endif /* if CONFIG_SOC_SERIES_MSPM0G */
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */
#define GPIOB_NODE DT_NODELABEL(gpiob)
#if DT_NODE_HAS_STATUS(GPIOB_NODE, okay)
#ifdef CONFIG_SOC_SERIES_MSPM0G
#define NUM_GPIOB_PIN 28
#define gpiob_pins NUM_GPIOB_PIN
static uint8_t gpiob_pincm_lut[NUM_GPIOB_PIN] = {
IOMUX_PINCM12, IOMUX_PINCM13, IOMUX_PINCM15, IOMUX_PINCM16, IOMUX_PINCM17, IOMUX_PINCM18,
IOMUX_PINCM23, IOMUX_PINCM24, IOMUX_PINCM25, IOMUX_PINCM26, IOMUX_PINCM27, IOMUX_PINCM28,
IOMUX_PINCM29, IOMUX_PINCM30, IOMUX_PINCM31, IOMUX_PINCM32, IOMUX_PINCM33, IOMUX_PINCM43,
IOMUX_PINCM44, IOMUX_PINCM45, IOMUX_PINCM48, IOMUX_PINCM49, IOMUX_PINCM50, IOMUX_PINCM51,
IOMUX_PINCM52, IOMUX_PINCM56, IOMUX_PINCM57, IOMUX_PINCM58,
};
#elif CONFIG_SOC_SERIES_MSPM0L /* if CONFIG_SOC_SERIES_MSPM0L */
#define GPIOB_NODE DT_NODELABEL(gpiob)
#define NUM_GPIOB_PIN 32
#define gpiob_pins NUM_GPIOB_PIN
static uint8_t gpiob_pincm_lut[NUM_GPIOB_PIN] = {
IOMUX_PINCM12, IOMUX_PINCM13, IOMUX_PINCM15, IOMUX_PINCM16, IOMUX_PINCM17, IOMUX_PINCM18,
IOMUX_PINCM27, IOMUX_PINCM28, IOMUX_PINCM29, IOMUX_PINCM30, IOMUX_PINCM31, IOMUX_PINCM32,
IOMUX_PINCM33, IOMUX_PINCM34, IOMUX_PINCM35, IOMUX_PINCM36, IOMUX_PINCM37, IOMUX_PINCM53,
IOMUX_PINCM54, IOMUX_PINCM55, IOMUX_PINCM62, IOMUX_PINCM63, IOMUX_PINCM64, IOMUX_PINCM65,
IOMUX_PINCM66, IOMUX_PINCM70, IOMUX_PINCM71, IOMUX_PINCM72, IOMUX_PINCM21, IOMUX_PINCM22,
IOMUX_PINCM23, IOMUX_PINCM24
};
#endif /* CONFIG_SOC_SERIES_MSPM0G */
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay) */
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioc), okay)
#define GPIOC_NODE DT_NODELABEL(gpioc)
#ifdef CONFIG_SOC_SERIES_MSPM0L
#define NUM_GPIOC_PIN 10
#define gpioc_pins NUM_GPIOC_PIN
static uint8_t gpioc_pincm_lut[NUM_GPIOC_PIN] = {
IOMUX_PINCM43, IOMUX_PINCM44, IOMUX_PINCM45, IOMUX_PINCM46, IOMUX_PINCM47,
IOMUX_PINCM48, IOMUX_PINCM58, IOMUX_PINCM59, IOMUX_PINCM60, IOMUX_PINCM61,
};
#endif /* CONFIG_SOC_SERIES */
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioc), okay) */
static int gpio_mspm0_port_get_raw(const struct device *port, uint32_t *value)
{
const struct gpio_mspm0_config *config = port->config;
/* Read entire port */
*value = DL_GPIO_readPins(config->base, UINT32_MAX);
return 0;
}
static int gpio_mspm0_port_set_masked_raw(const struct device *port,
uint32_t mask, uint32_t value)
{
const struct gpio_mspm0_config *config = port->config;
DL_GPIO_writePinsVal(config->base, mask, value);
return 0;
}
static int gpio_mspm0_port_set_bits_raw(const struct device *port,
uint32_t mask)
{
const struct gpio_mspm0_config *config = port->config;
DL_GPIO_setPins(config->base, mask);
return 0;
}
static int gpio_mspm0_port_clear_bits_raw(const struct device *port,
uint32_t mask)
{
const struct gpio_mspm0_config *config = port->config;
DL_GPIO_clearPins(config->base, mask);
return 0;
}
static int gpio_mspm0_port_toggle_bits(const struct device *port,
uint32_t mask)
{
const struct gpio_mspm0_config *config = port->config;
DL_GPIO_togglePins(config->base, mask);
return 0;
}
static int gpio_mspm0_pin_configure(const struct device *port,
gpio_pin_t pin,
gpio_flags_t flags)
{
const struct gpio_mspm0_config *config = port->config;
/* determine pull up resistor value based on flags */
DL_GPIO_RESISTOR pull_res;
if (flags & GPIO_PULL_UP) {
pull_res = DL_GPIO_RESISTOR_PULL_UP;
} else if (flags & GPIO_PULL_DOWN) {
pull_res = DL_GPIO_RESISTOR_PULL_DOWN;
} else {
pull_res = DL_GPIO_RESISTOR_NONE;
}
/* Config pin based on flags */
switch (flags & (GPIO_INPUT | GPIO_OUTPUT)) {
case GPIO_INPUT:
DL_GPIO_initDigitalInputFeatures(config->pincm_lut[pin],
DL_GPIO_INVERSION_DISABLE,
pull_res,
DL_GPIO_HYSTERESIS_DISABLE,
DL_GPIO_WAKEUP_DISABLE);
DL_GPIO_disableOutput(config->base, BIT(pin));
break;
case GPIO_OUTPUT:
DL_GPIO_initDigitalOutputFeatures(config->pincm_lut[pin],
DL_GPIO_INVERSION_DISABLE,
pull_res,
DL_GPIO_DRIVE_STRENGTH_LOW,
(flags & GPIO_OPEN_DRAIN) ?
DL_GPIO_HIZ_ENABLE :
DL_GPIO_HIZ_DISABLE);
/* Set initial state */
if (flags & GPIO_OUTPUT_INIT_HIGH) {
gpio_mspm0_port_set_bits_raw(port, BIT(pin));
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
gpio_mspm0_port_clear_bits_raw(port, BIT(pin));
}
/* Enable output */
DL_GPIO_enableOutput(config->base, BIT(pin));
break;
case GPIO_DISCONNECTED:
DL_GPIO_disableOutput(config->base, BIT(pin));
break;
default:
return -ENOTSUP;
}
return 0;
}
static int gpio_mspm0_pin_interrupt_configure(const struct device *port,
gpio_pin_t pin,
enum gpio_int_mode mode,
enum gpio_int_trig trig)
{
const struct gpio_mspm0_config *config = port->config;
/* Config interrupt */
switch (mode) {
case GPIO_INT_MODE_DISABLED:
DL_GPIO_clearInterruptStatus(config->base, BIT(pin));
DL_GPIO_disableInterrupt(config->base, BIT(pin));
break;
case GPIO_INT_MODE_EDGE:
uint32_t polarity = 0x00;
if (trig & GPIO_INT_TRIG_LOW) {
polarity |= BIT(1);
}
if (trig & GPIO_INT_TRIG_HIGH) {
polarity |= BIT(0);
}
if (pin < MSPM0_PINS_LOW_GROUP) {
DL_GPIO_setLowerPinsPolarity(config->base,
polarity << (2 * pin));
} else {
DL_GPIO_setUpperPinsPolarity(config->base,
polarity << (2 * (pin - MSPM0_PINS_LOW_GROUP)));
}
DL_GPIO_clearInterruptStatus(config->base, BIT(pin));
DL_GPIO_enableInterrupt(config->base, BIT(pin));
break;
case GPIO_INT_MODE_LEVEL:
return -ENOTSUP;
}
return 0;
}
static int gpio_mspm0_manage_callback(const struct device *port,
struct gpio_callback *callback,
bool set)
{
struct gpio_mspm0_data *data = port->data;
return gpio_manage_callback(&data->callbacks, callback, set);
}
static uint32_t gpio_mspm0_get_pending_int(const struct device *port)
{
const struct gpio_mspm0_config *config = port->config;
return DL_GPIO_getPendingInterrupt(config->base);
}
static void gpio_mspm0_isr(const struct device *port)
{
struct gpio_mspm0_data *data;
const struct gpio_mspm0_config *config;
const struct device *dev_list[] = {
DEVICE_DT_GET_OR_NULL(GPIOA_NODE),
DEVICE_DT_GET_OR_NULL(GPIOB_NODE),
DEVICE_DT_GET_OR_NULL(GPIOC_NODE),
};
for (uint8_t i = 0; i < ARRAY_SIZE(dev_list); i++) {
uint32_t status;
if (dev_list[i] == NULL) {
continue;
}
data = dev_list[i]->data;
config = dev_list[i]->config;
status = DL_GPIO_getEnabledInterruptStatus(config->base,
0xFFFFFFFF);
DL_GPIO_clearInterruptStatus(config->base, status);
if (status != 0) {
gpio_fire_callbacks(&data->callbacks,
dev_list[i], status);
}
}
}
static int gpio_mspm0_init(const struct device *dev)
{
const struct gpio_mspm0_config *cfg = dev->config;
static bool init_irq = true;
/* Reset and enable GPIO banks */
DL_GPIO_reset(cfg->base);
DL_GPIO_enablePower(cfg->base);
/* All the interrupt port share the same irq number, do it once */
if (init_irq) {
init_irq = false;
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
gpio_mspm0_isr, DEVICE_DT_INST_GET(0), 0);
irq_enable(DT_INST_IRQN(0));
}
return 0;
}
#ifdef CONFIG_GPIO_GET_CONFIG
static int gpio_mspm0_pin_get_config(const struct device *port, gpio_pin_t pin,
gpio_flags_t *out_flags)
{
const struct gpio_mspm0_config *config = port->config;
/* Currently only returns current state and not actually all flags */
if (BIT(pin) & config->base->DOE31_0) {
*out_flags = BIT(pin) & config->base->DOUT31_0 ?
GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW;
} else {
*out_flags = GPIO_INPUT;
}
return 0;
}
#endif
#ifdef CONFIG_GPIO_GET_DIRECTION
static int gpio_mspm0_port_get_direction(const struct device *port,
gpio_port_pins_t map,
gpio_port_pins_t *inputs,
gpio_port_pins_t *outputs)
{
const struct gpio_mspm0_config *config = port->config;
map &= config->common.port_pin_mask;
*inputs = map & ~config->base->DOE31_0;
*outputs = map & config->base->DOE31_0;
return 0;
}
#endif /* CONFIG_GPIO_GET_DIRECTION */
static DEVICE_API(gpio, gpio_mspm0_driver_api) = {
.pin_configure = gpio_mspm0_pin_configure,
#ifdef CONFIG_GPIO_GET_CONFIG
.pin_get_config = gpio_mspm0_pin_get_config,
#endif
.port_get_raw = gpio_mspm0_port_get_raw,
.port_set_masked_raw = gpio_mspm0_port_set_masked_raw,
.port_set_bits_raw = gpio_mspm0_port_set_bits_raw,
.port_clear_bits_raw = gpio_mspm0_port_clear_bits_raw,
.port_toggle_bits = gpio_mspm0_port_toggle_bits,
.pin_interrupt_configure = gpio_mspm0_pin_interrupt_configure,
.manage_callback = gpio_mspm0_manage_callback,
.get_pending_int = gpio_mspm0_get_pending_int,
#ifdef CONFIG_GPIO_GET_DIRECTION
.port_get_direction = gpio_mspm0_port_get_direction,
#endif /* CONFIG_GPIO_GET_DIRECTION */
};
#define GPIO_DEVICE_INIT(n, __suffix, __base_addr) \
static const struct gpio_mspm0_config gpio_mspm0_cfg_##__suffix = { \
.common = { .port_pin_mask = \
GPIO_PORT_PIN_MASK_FROM_NGPIOS(gpio##__suffix##_pins), \
}, \
.base = (GPIO_Regs *)__base_addr, \
.pincm_lut = gpio##__suffix##_pincm_lut, \
}; \
static struct gpio_mspm0_data gpio_mspm0_data_##__suffix; \
DEVICE_DT_DEFINE(n, gpio_mspm0_init, NULL, &gpio_mspm0_data_##__suffix, \
&gpio_mspm0_cfg_##__suffix, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
&gpio_mspm0_driver_api)
#define GPIO_DEVICE_INIT_MSPM0(__suffix) \
GPIO_DEVICE_INIT(DT_NODELABEL(gpio##__suffix), __suffix, \
DT_REG_ADDR(DT_NODELABEL(gpio##__suffix)))
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay)
GPIO_DEVICE_INIT_MSPM0(a);
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay)
GPIO_DEVICE_INIT_MSPM0(b);
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay) */
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioc), okay)
GPIO_DEVICE_INIT_MSPM0(c);
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioc), okay) */