drivers: gpio: mec5: Microchip MEC5 HAL based GPIO driver
Add a GPIO driver for the Microchip MEC5 HAL based chips. Current devices are: MEC174x, MEC175x, and HAL version of MEC172x named MECH172x. Signed-off-by: Scott Worley <scott.worley@microchip.com>
This commit is contained in:
parent
020985b38b
commit
f51729aada
6 changed files with 569 additions and 12 deletions
|
|
@ -46,6 +46,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_MAX14906 gpio_max14906.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX14916 gpio_max14916.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX22190 gpio_max22190.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX32 gpio_max32.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCHP_MEC5 gpio_mchp_mec5.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCHP_MSS gpio_mchp_mss.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCP230XX gpio_mcp230xx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23SXX gpio_mcp23sxx.c)
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ source "drivers/gpio/Kconfig.mcux"
|
|||
source "drivers/gpio/Kconfig.mcux_igpio"
|
||||
source "drivers/gpio/Kconfig.mcux_lpc"
|
||||
source "drivers/gpio/Kconfig.mcux_rgpio"
|
||||
source "drivers/gpio/Kconfig.mec5"
|
||||
source "drivers/gpio/Kconfig.mmio32"
|
||||
source "drivers/gpio/Kconfig.nct38xx"
|
||||
source "drivers/gpio/Kconfig.neorv32"
|
||||
|
|
|
|||
11
drivers/gpio/Kconfig.mec5
Normal file
11
drivers/gpio/Kconfig.mec5
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Microchip MEC5 GPIO configuration options
|
||||
|
||||
# Copyright (c) 2024 Microchip Technology Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config GPIO_MCHP_MEC5
|
||||
bool "Microchip MEC5 GPIO driver"
|
||||
default y
|
||||
depends on DT_HAS_MICROCHIP_MEC5_GPIO_ENABLED
|
||||
help
|
||||
Enable the Microchip MEC5 gpio driver.
|
||||
529
drivers/gpio/gpio_mchp_mec5.c
Normal file
529
drivers/gpio/gpio_mchp_mec5.c
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Microchip Technology Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT microchip_mec5_gpio
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/mchp-xec-pinctrl.h>
|
||||
#include <soc.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <mec_gpio_api.h>
|
||||
|
||||
#include <zephyr/drivers/gpio/gpio_utils.h>
|
||||
|
||||
/* 32 pins per bank. Each pin has a 4-byte control register */
|
||||
#define MEC5_GPIO_PIN_CTRL_RSHFT 7
|
||||
#define MEC5_GPIO_PIN_CTRL_ADDR_MSK 0xfu
|
||||
|
||||
struct gpio_mec5_data {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_data common;
|
||||
/* port ISR callback routine address */
|
||||
sys_slist_t callbacks;
|
||||
};
|
||||
|
||||
struct gpio_mec5_config {
|
||||
/* gpio_driver_config needs to be first */
|
||||
struct gpio_driver_config common;
|
||||
uintptr_t pcr1_base;
|
||||
uintptr_t parin_addr;
|
||||
uintptr_t parout_addr;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static inline uint32_t mec5_addr_to_port(uint32_t base_addr)
|
||||
{
|
||||
return ((base_addr >> MEC5_GPIO_PIN_CTRL_RSHFT) & MEC5_GPIO_PIN_CTRL_ADDR_MSK);
|
||||
}
|
||||
|
||||
/* NOTE: gpio_flags_t b[0:15] are defined in the dt-binding gpio header.
|
||||
* b[31:16] are defined in the driver gpio header.
|
||||
*/
|
||||
static int gpio_mec5_validate_flags(gpio_flags_t flags)
|
||||
{
|
||||
if (flags & GPIO_LINE_OPEN_SOURCE) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_OUTPUT_INIT_LOW) && (flags & GPIO_OUTPUT_INIT_HIGH)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mec_gpio_props cfg_props_init[] = {
|
||||
{MEC_GPIO_PWRGT_PROP_ID, MEC_GPIO_PROP_PWRGT_VTR},
|
||||
{MEC_GPIO_OSEL_PROP_ID, MEC_GPIO_PROP_OSEL_CTRL},
|
||||
{MEC_GPIO_INPAD_DIS_PROP_ID, MEC_GPIO_PROP_INPAD_EN},
|
||||
};
|
||||
|
||||
/* Each GPIO pin has two 32-bit control registers. Control 1 configures pin
|
||||
* features except for drive strength and slew rate in Control 2.
|
||||
* A pin's input and output state can be read/written from either the Control 1
|
||||
* register or from corresponding bits in the GPIO parallel input/output registers.
|
||||
* The parallel input and output registers group 32 pins into each register.
|
||||
* The GPIO hardware restricts the pin output state to Control 1 or the parallel bit.
|
||||
* Both output bits reflect each other on read and writes but only one is writable
|
||||
* selected by the output control select bit in Control 1. In the configuration API
|
||||
* we use Control 1 to configure all pin features and output state. Before exiting,
|
||||
* we set the output select for parallel mode enabling writes to the parallel output bit.
|
||||
*/
|
||||
static int gpio_mec5_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t pin_num = 0u;
|
||||
uint32_t port_num = 0u;
|
||||
uint32_t temp = 0u;
|
||||
int ret = 0;
|
||||
size_t idx = 0;
|
||||
struct mec_gpio_props props[8];
|
||||
|
||||
port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
ret = mec_hal_gpio_pin_num(port_num, pin, &pin_num);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mec_hal_gpio_port_pin_valid(port_num, pin);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gpio_mec5_validate_flags(flags);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (flags == GPIO_DISCONNECTED) {
|
||||
ret = mec_hal_gpio_set_property(pin_num, MEC_GPIO_PWRGT_PROP_ID,
|
||||
MEC_GPIO_PROP_PWRGT_OFF);
|
||||
if (ret != MEC_RET_OK) {
|
||||
ret = -EIO;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mec_hal_gpio_set_props(pin_num, cfg_props_init, ARRAY_SIZE(cfg_props_init));
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (flags & GPIO_OUTPUT) {
|
||||
props[idx].prop = MEC_GPIO_DIR_PROP_ID;
|
||||
props[idx].val = MEC_GPIO_PROP_DIR_OUT;
|
||||
idx++;
|
||||
|
||||
props[idx].prop = MEC_GPIO_OBUFT_PROP_ID;
|
||||
props[idx].val = MEC_GPIO_PROP_PUSH_PULL;
|
||||
if (flags & GPIO_LINE_OPEN_DRAIN) {
|
||||
props[idx].val = MEC_GPIO_PROP_OPEN_DRAIN;
|
||||
}
|
||||
idx++;
|
||||
|
||||
props[idx].prop = MEC_GPIO_CTRL_OUT_VAL_ID;
|
||||
props[idx].val = 0u;
|
||||
if (flags & GPIO_OUTPUT_INIT_HIGH) {
|
||||
props[idx].val = 1u;
|
||||
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
|
||||
props[idx].val = 0u;
|
||||
} else {
|
||||
mec_hal_gpio_pad_in(pin_num, &props[idx].val);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (flags & GPIO_INPUT) {
|
||||
props[idx].prop = MEC_GPIO_DIR_PROP_ID;
|
||||
props[idx].val = MEC_GPIO_PROP_DIR_IN;
|
||||
idx++;
|
||||
}
|
||||
|
||||
temp = flags & (GPIO_PULL_UP | GPIO_PULL_DOWN);
|
||||
if (temp) {
|
||||
props[idx].prop = MEC_GPIO_PUD_PROP_ID;
|
||||
if (temp == (GPIO_PULL_UP | GPIO_PULL_DOWN)) {
|
||||
props[idx].val = MEC_GPIO_PROP_REPEATER;
|
||||
} else if (temp & GPIO_PULL_UP) {
|
||||
props[idx].val = MEC_GPIO_PROP_PULL_UP;
|
||||
} else {
|
||||
props[idx].val = MEC_GPIO_PROP_PULL_DN;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
ret = mec_hal_gpio_set_props(pin_num, props, idx);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* make output state in control read-only in control and read-write in parallel reg */
|
||||
ret = mec_hal_gpio_set_property(pin_num, MEC_GPIO_OSEL_PROP_ID, MEC_GPIO_PROP_OSEL_PAROUT);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t gen_gpio_ctrl_icfg(enum gpio_int_mode mode, enum gpio_int_trig trig)
|
||||
{
|
||||
uint8_t idet;
|
||||
|
||||
if (mode == GPIO_INT_MODE_DISABLED) {
|
||||
idet = MEC_GPIO_PROP_IDET_DIS;
|
||||
} else {
|
||||
if (mode == GPIO_INT_MODE_LEVEL) {
|
||||
if (trig == GPIO_INT_TRIG_HIGH) {
|
||||
idet = MEC_GPIO_PROP_IDET_HI_LVL;
|
||||
} else {
|
||||
idet = MEC_GPIO_PROP_IDET_LO_LVL;
|
||||
}
|
||||
} else {
|
||||
switch (trig) {
|
||||
case GPIO_INT_TRIG_LOW:
|
||||
idet = MEC_GPIO_PROP_IDET_EDGE_DN;
|
||||
break;
|
||||
case GPIO_INT_TRIG_HIGH:
|
||||
idet = MEC_GPIO_PROP_IDET_EDGE_UP;
|
||||
break;
|
||||
case GPIO_INT_TRIG_BOTH:
|
||||
idet = MEC_GPIO_PROP_IDET_EDGE_BOTH;
|
||||
break;
|
||||
default:
|
||||
idet = MEC_GPIO_PROP_IDET_DIS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idet;
|
||||
}
|
||||
|
||||
/* Enable interrupt to propagate via its GIRQ to the NVIC */
|
||||
static void gpio_mec5_intr_en(uint8_t port, gpio_pin_t pin, enum gpio_int_mode mode)
|
||||
{
|
||||
uint8_t en = 0u;
|
||||
|
||||
if (mode != GPIO_INT_MODE_DISABLED) {
|
||||
en = 1u;
|
||||
}
|
||||
|
||||
mec_hal_gpio_port_pin_ia_enable(port, pin, en);
|
||||
}
|
||||
|
||||
static const struct mec_gpio_props icfg_props_init[] = {
|
||||
{MEC_GPIO_PWRGT_PROP_ID, MEC_GPIO_PROP_PWRGT_VTR},
|
||||
{MEC_GPIO_INPAD_DIS_PROP_ID, MEC_GPIO_PROP_INPAD_EN},
|
||||
};
|
||||
|
||||
static int gpio_mec5_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
|
||||
enum gpio_int_mode mode, enum gpio_int_trig trig)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t pin_num = (uint32_t)MEC_PIN_MAX;
|
||||
uint32_t port_num = 0;
|
||||
int ret = 0;
|
||||
uint8_t idet = 0, idet_curr = 0;
|
||||
|
||||
/* Validate pin number range in terms of current port */
|
||||
port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
ret = mec_hal_gpio_port_pin_valid(port_num, pin);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if GPIO port supports interrupts */
|
||||
if ((mode != GPIO_INT_MODE_DISABLED) && !(config->flags & GPIO_INT_ENABLE)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Disable interrupt in the EC aggregator */
|
||||
gpio_mec5_intr_en(port_num, pin, 0);
|
||||
|
||||
mec_hal_gpio_pin_num(port_num, pin, &pin_num);
|
||||
ret = mec_hal_gpio_set_props(pin_num, icfg_props_init, ARRAY_SIZE(icfg_props_init));
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
idet_curr = MEC_GPIO_PROP_IDET_DIS;
|
||||
ret = mec_hal_gpio_get_property(pin_num, MEC_GPIO_IDET_PROP_ID, &idet_curr);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
idet = gen_gpio_ctrl_icfg(mode, trig);
|
||||
if (idet_curr == idet) {
|
||||
gpio_mec5_intr_en(port_num, pin, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = mec_hal_gpio_set_property(pin_num, MEC_GPIO_IDET_PROP_ID, idet);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = mec_hal_gpio_pin_ia_status_clr(pin_num);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
gpio_mec5_intr_en(port_num, pin, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
int ret = mec_hal_gpio_parout_port_mask(port_num, value, (const uint32_t)mask);
|
||||
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_port_set_bits_raw(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
int ret = mec_hal_gpio_parout_port_set_bits(port_num, (const uint32_t)mask);
|
||||
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_port_clear_bits_raw(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
int ret = mec_hal_gpio_parout_port_mask(port_num, 0u, (const uint32_t)mask);
|
||||
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_port_toggle_bits(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
|
||||
if (mec_hal_gpio_parout_port_xor(port_num, mask) != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_port_get_raw(const struct device *dev, uint32_t *value)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
|
||||
if (mec_hal_gpio_parin_port(port_num, value) != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mec5_manage_callback(const struct device *dev, struct gpio_callback *callback,
|
||||
bool set)
|
||||
{
|
||||
struct gpio_mec5_data *data = dev->data;
|
||||
|
||||
gpio_manage_callback(&data->callbacks, callback, set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIO_GET_DIRECTION
|
||||
static int gpio_mec5_get_direction(const struct device *port, gpio_port_pins_t map,
|
||||
gpio_port_pins_t *inputs, gpio_port_pins_t *outputs)
|
||||
{
|
||||
if (!port) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct gpio_mec5_config *config = port->config;
|
||||
uint32_t valid_msk = 0u;
|
||||
uint32_t pin_num = 0u, port_num = 0u;
|
||||
int ret = 0;
|
||||
uint8_t pwr_gate = 0u, dir = 0u, in_pad_dis = 0u;
|
||||
|
||||
port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
ret = mec_hal_gpio_port_valid_mask(port_num, &valid_msk);
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*inputs = 0u;
|
||||
*outputs = 0u;
|
||||
for (uint8_t pin_pos = 0; pin_pos < 32; pin++) {
|
||||
if (!map) {
|
||||
break;
|
||||
}
|
||||
if ((map & BIT(pin_pos)) && (valid_msk & BIT(pin_pos))) {
|
||||
mec_hal_gpio_pin_num(port_num, pin, &pin_num);
|
||||
mec_hal_gpio_get_property(pin_num, MEC_GPIO_PWRGT_PROP_ID, &pwr_gate);
|
||||
mec_hal_gpio_get_property(pin_num, MEC_GPIO_DIR_PROP_ID, &dir);
|
||||
mec_hal_gpio_get_property(pin_num, MEC_GPIO_INPAD_DIS_PROP_ID, &in_pad_dis);
|
||||
|
||||
if (pwr_gate != MEC_GPIO_PROP_PWRGT_OFF) {
|
||||
if (outputs && (dir == MEC_GPIO_PROP_DIR_OUT)) {
|
||||
*outputs |= BIT(pin_pos);
|
||||
} else if (inputs && (in_pad_dis == MEC_GPIO_PROP_INPAD_EN)) {
|
||||
*inputs |= BIT(pin_pos);
|
||||
}
|
||||
}
|
||||
|
||||
map &= ~BIT(pin_pos);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIO_GET_CONFIG
|
||||
int gpio_mec5_get_config(const struct device *port, gpio_pin_t pin, gpio_flags_t *flags)
|
||||
{
|
||||
if (!port || !flags) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct gpio_mec5_config *config = port->config;
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
int ret = mec_hal_gpio_port_pin_valid(port_num, pin);
|
||||
|
||||
if (ret != MEC_RET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint32_t pin_ctrl = mec_hal_gpio_port_get_ctrl_nc(port_num, pin);
|
||||
uint32_t pin_flags = 0u;
|
||||
uint8_t prop = MEC_GPIO_PROP_DIR_IN;
|
||||
|
||||
mec_hal_gpio_get_ctrl_property(pin_ctrl, MEC_GPIO_DIR_PROP_ID, &prop);
|
||||
|
||||
if (prop == MEC_GPIO_PROP_DIR_OUT) {
|
||||
pin_flags |= GPIO_OUTPUT;
|
||||
mec_hal_gpio_get_ctrl_property(pin_ctrl, MEC_GPIO_CTRL_OUT_VAL_ID, &prop);
|
||||
if (prop != 0) {
|
||||
pin_flags |= GPIO_OUTPUT_INIT_HIGH;
|
||||
} else {
|
||||
pin_flags |= GPIO_OUTPUT_INIT_LOW;
|
||||
}
|
||||
|
||||
prop = MEC_GPIO_PROP_PUSH_PULL;
|
||||
mec_hal_gpio_get_ctrl_property(pin_ctrl, MEC_GPIO_OBUFT_PROP_ID, &prop);
|
||||
if (prop == MEC_GPIO_PROP_OPEN_DRAIN) {
|
||||
pin_flags |= GPIO_OPEN_DRAIN;
|
||||
}
|
||||
} else {
|
||||
prop = MEC_GPIO_PROP_INPAD_DIS;
|
||||
mec_hal_gpio_get_ctrl_property(pin_ctrl, MEC_GPIO_INPAD_DIS_PROP_ID, &prop);
|
||||
if (prop == MEC_GPIO_PROP_INPAD_EN) {
|
||||
pin_flags |= GPIO_INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (pin_flags) {
|
||||
*flags = pin_flags;
|
||||
} else {
|
||||
*flags = GPIO_DISCONNECTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gpio_mec5_port_isr(const struct device *dev)
|
||||
{
|
||||
const struct gpio_mec5_config *config = dev->config;
|
||||
struct gpio_mec5_data *data = dev->data;
|
||||
uint32_t girq_result = 0xffffffffu;
|
||||
uint32_t port_num = 0u;
|
||||
|
||||
/* Figure out which interrupts have been triggered from the EC
|
||||
* aggregator result register
|
||||
*/
|
||||
port_num = mec5_addr_to_port(config->pcr1_base);
|
||||
mec_hal_gpio_port_ia_result(port_num, &girq_result);
|
||||
|
||||
/* Clear source register in aggregator before firing callbacks */
|
||||
mec_hal_gpio_port_ia_status_clr_mask(port_num, girq_result);
|
||||
|
||||
gpio_fire_callbacks(&data->callbacks, dev, girq_result);
|
||||
}
|
||||
|
||||
/* GPIO driver official API table */
|
||||
static const struct gpio_driver_api gpio_mec5_driver_api = {
|
||||
.pin_configure = gpio_mec5_configure,
|
||||
.port_get_raw = gpio_mec5_port_get_raw,
|
||||
.port_set_masked_raw = gpio_mec5_port_set_masked_raw,
|
||||
.port_set_bits_raw = gpio_mec5_port_set_bits_raw,
|
||||
.port_clear_bits_raw = gpio_mec5_port_clear_bits_raw,
|
||||
.port_toggle_bits = gpio_mec5_port_toggle_bits,
|
||||
.pin_interrupt_configure = gpio_mec5_pin_interrupt_configure,
|
||||
.manage_callback = gpio_mec5_manage_callback,
|
||||
#ifdef CONFIG_GPIO_GET_DIRECTION
|
||||
.port_get_direction = gpio_mec5_get_direction,
|
||||
#endif
|
||||
#ifdef CONFIG_GPIO_GET_CONFIG
|
||||
.pin_get_config = gpio_mec5_get_config,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MEC5_GPIO_PORT_FLAGS(n) ((DT_INST_IRQ_HAS_CELL(n, irq)) ? GPIO_INT_ENABLE : 0)
|
||||
|
||||
/* TODO remove port_num. Derive it from pin & pin_num? */
|
||||
#define MEC5_GPIO_PORT(n) \
|
||||
static int gpio_mec5_port_init_##n(const struct device *dev) \
|
||||
{ \
|
||||
if (!(DT_INST_IRQ_HAS_CELL(n, irq))) { \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
const struct gpio_mec5_config *config = dev->config; \
|
||||
uint32_t port_num = mec5_addr_to_port(config->pcr1_base); \
|
||||
\
|
||||
mec_hal_gpio_port_ia_ctrl(port_num, 1u); \
|
||||
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_mec5_port_isr, \
|
||||
DEVICE_DT_INST_GET(n), 0u); \
|
||||
irq_enable(DT_INST_IRQN(n)); \
|
||||
return 0; \
|
||||
} \
|
||||
static struct gpio_mec5_data gpio_mec5_port_data_##n; \
|
||||
static const struct gpio_mec5_config gpio_mec5_config_##n = { \
|
||||
.common = \
|
||||
{ \
|
||||
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
|
||||
}, \
|
||||
.pcr1_base = (uintptr_t)DT_INST_REG_ADDR_BY_IDX(n, 0), \
|
||||
.parin_addr = (uintptr_t)DT_INST_REG_ADDR_BY_IDX(n, 1), \
|
||||
.parout_addr = (uintptr_t)DT_INST_REG_ADDR_BY_IDX(n, 2), \
|
||||
.flags = MEC5_GPIO_PORT_FLAGS(n), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, gpio_mec5_port_init_##n, NULL, &gpio_mec5_port_data_##n, \
|
||||
&gpio_mec5_config_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
|
||||
&gpio_mec5_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MEC5_GPIO_PORT)
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
|
||||
#include <arm/armv7-m.dtsi>
|
||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
||||
#include <zephyr/dt-bindings/gpio/microchip-xec-gpio.h>
|
||||
#include <freq.h>
|
||||
#include <mem.h>
|
||||
|
||||
|
|
@ -142,57 +144,51 @@
|
|||
reg = <0x40081000 0x1000>;
|
||||
|
||||
gpio_000_036: gpio@40081000 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081000 0x80 0x40081300 0x04
|
||||
0x40081380 0x04 0x400813fc 0x04>;
|
||||
interrupts = <3 2>;
|
||||
gpio-controller;
|
||||
port-id = <0>;
|
||||
girq-id = <11>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
gpio_040_076: gpio@40081080 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081080 0x80 0x40081304 0x04
|
||||
0x40081384 0x04 0x400813f8 0x4>;
|
||||
interrupts = <2 2>;
|
||||
gpio-controller;
|
||||
port-id = <1>;
|
||||
girq-id = <10>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
gpio_100_136: gpio@40081100 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081100 0x80 0x40081308 0x04
|
||||
0x40081388 0x04 0x400813f4 0x04>;
|
||||
gpio-controller;
|
||||
interrupts = <1 2>;
|
||||
port-id = <2>;
|
||||
girq-id = <9>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
gpio_140_176: gpio@40081180 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081180 0x80 0x4008130c 0x04
|
||||
0x4008138c 0x04 0x400813f0 0x04>;
|
||||
gpio-controller;
|
||||
interrupts = <0 2>;
|
||||
port-id = <3>;
|
||||
girq-id = <8>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
gpio_200_236: gpio@40081200 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081200 0x80 0x40081310 0x04
|
||||
0x40081390 0x04 0x400813ec 0x04>;
|
||||
gpio-controller;
|
||||
interrupts = <4 2>;
|
||||
port-id = <4>;
|
||||
girq-id = <12>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
gpio_240_276: gpio@40081280 {
|
||||
compatible = "microchip,mec5-gpio";
|
||||
reg = < 0x40081280 0x80 0x40081314 0x04
|
||||
0x40081394 0x04 0x400813e8 0x04>;
|
||||
gpio-controller;
|
||||
interrupts = <17 2>;
|
||||
port-id = <5>;
|
||||
girq-id = <26>;
|
||||
#gpio-cells=<2>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
19
dts/bindings/gpio/microchip,mec5-gpio.yaml
Normal file
19
dts/bindings/gpio/microchip,mec5-gpio.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2024, Microchip Technology Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Microchip MEC5 GPIO node
|
||||
|
||||
compatible: "microchip,mec5-gpio"
|
||||
|
||||
include: [gpio-controller.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-cells:
|
||||
- pin
|
||||
- flags
|
||||
Loading…
Reference in a new issue