drivers: intc: renesas: Add gpio interrupt (tint) for RZ family
Add support for gpio interrupt (tint) for Renesas RZ familiy. Signed-off-by: Nhut Nguyen <nhut.nguyen.kc@renesas.com>
This commit is contained in:
committed by
Fabio Baltieri
parent
0037a5fc4b
commit
982231a8fe
@@ -60,6 +60,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_SIUL2_EIRQ intc_nxp_siul2_eirq.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PLIC intc_plic.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RENESAS_RX_ICU intc_renesas_rx_icu.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RENESAS_RZ_EXT_IRQ intc_renesas_rz_ext_irq.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RENESAS_RZ_TINT intc_renesas_rz_tint.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RV32M1_INTMUX intc_rv32m1_intmux.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SAM0_EIC intc_sam0_eic.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SHARED_IRQ intc_shared_irq.c)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2024 Renesas Electronics Corporation
|
||||
# Copyright (c) 2024-2025 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config RENESAS_RZ_EXT_IRQ
|
||||
@@ -20,3 +20,30 @@ config RENESAS_RZ_INTC_HAS_NMI
|
||||
Renesas RZ interrupt controller has NMI (Non Maskable Interrupt) pin
|
||||
|
||||
endif
|
||||
|
||||
config RENESAS_RZ_INTC_SELECT_INTERRUPT
|
||||
bool "Renesas RZ INTC select interrupt"
|
||||
default y
|
||||
depends on DT_HAS_RENESAS_RZ_INTC_V2_ENABLED
|
||||
help
|
||||
Renesas RZ INTC select interrupt
|
||||
|
||||
config RENESAS_RZ_TINT
|
||||
bool "Renesas RZ GPIO interrupt (TINT) controller driver"
|
||||
default y
|
||||
depends on DT_HAS_RENESAS_RZ_TINT_ENABLED
|
||||
help
|
||||
Renesas RZ GPIO interrupt (TINT) controller driver
|
||||
|
||||
if RENESAS_RZ_TINT
|
||||
|
||||
config RENESAS_RZ_TINT_SUPPORT_STATUS_CLEAR_REG
|
||||
bool "Renesas RZ TINT support status clear register"
|
||||
default y
|
||||
depends on DT_HAS_RENESAS_RZ_INTC_V2_ENABLED
|
||||
help
|
||||
Renesas RZ/V2H, RZ/V2N support a Status Clear Register
|
||||
to reset interrupt flags, while the remaining SoCs
|
||||
reset interrupt flags in the Status Register.
|
||||
|
||||
endif
|
||||
|
||||
256
drivers/interrupt_controller/intc_renesas_rz_tint.c
Normal file
256
drivers/interrupt_controller/intc_renesas_rz_tint.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Renesas Electronics Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT renesas_rz_tint
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/drivers/interrupt_controller/gic.h>
|
||||
#include <zephyr/drivers/interrupt_controller/intc_rz_tint.h>
|
||||
#include <zephyr/dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(rz_intc, CONFIG_INTC_LOG_LEVEL);
|
||||
|
||||
struct intc_rz_tint_config {
|
||||
uint8_t tint;
|
||||
uint8_t max_gpioint;
|
||||
uint32_t irq;
|
||||
uint32_t prio;
|
||||
};
|
||||
|
||||
struct intc_rz_tint_data {
|
||||
uint8_t port;
|
||||
uint8_t pin;
|
||||
uint8_t gpioint;
|
||||
enum intc_rz_tint_trigger trigger_type;
|
||||
intc_rz_tint_callback_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
#define RZ_INTC_BASE DT_REG_ADDR(DT_NODELABEL(intc))
|
||||
#define RZ_INTC_TSCR (RZ_INTC_BASE + DT_REG_ADDR_BY_NAME(DT_NODELABEL(intc), tscr))
|
||||
#define RZ_INTC_TITSR0 (RZ_INTC_BASE + DT_REG_ADDR_BY_NAME(DT_NODELABEL(intc), titsr0))
|
||||
#define RZ_INTC_TSSR0 (RZ_INTC_BASE + DT_REG_ADDR_BY_NAME(DT_NODELABEL(intc), tssr0))
|
||||
#define RZ_INTC_INTSEL (RZ_INTC_BASE + DT_REG_ADDR_BY_NAME(DT_NODELABEL(intc), intsel))
|
||||
|
||||
#define REG_TITSR_READ(tint) sys_read32(RZ_INTC_TITSR0 + ((tint) / 16) * 4)
|
||||
#define REG_TITSR_WRITE(tint, v) sys_write32((v), RZ_INTC_TITSR0 + ((tint) / 16) * 4)
|
||||
#define REG_TITSR_TITSEL_MASK(tint) (BIT_MASK(2) << ((tint % 16) * 2))
|
||||
|
||||
#define REG_TSSR_READ(tint) sys_read32(RZ_INTC_TSSR0 + ((tint) / 4) * 4)
|
||||
#define REG_TSSR_WRITE(tint, v) sys_write32((v), RZ_INTC_TSSR0 + ((tint) / 4) * 4)
|
||||
#define REG_TSSR_TSSEL_MASK(tint) (BIT_MASK(7) << ((tint % 4) * 8))
|
||||
#define REG_TSSR_TIEN_MASK(tint) (BIT(7) << ((tint % 4) * 8))
|
||||
|
||||
#if defined(CONFIG_RENESAS_RZ_TINT_SUPPORT_STATUS_CLEAR_REG)
|
||||
/* V2H, V2N */
|
||||
#define REG_TSCTR_READ(tint) sys_read32(RZ_INTC_TSCR)
|
||||
#define REG_TSCLR_WRITE(tint, v) sys_write32((v), RZ_INTC_TSCR + 4)
|
||||
#define TINT_STATUS_READ(tint) REG_TSCTR_READ(tint)
|
||||
#define TINT_STATUS_CLEAR(tint) REG_TSCLR_WRITE(tint, TINT_STATUS_READ(tint) | BIT(tint))
|
||||
#else
|
||||
#define REG_TSCR_READ(tint) sys_read32(RZ_INTC_TSCR)
|
||||
#define REG_TSCR_WRITE(tint, v) sys_write32((v), RZ_INTC_TSCR)
|
||||
#define TINT_STATUS_READ(tint) REG_TSCR_READ(tint)
|
||||
#define TINT_STATUS_CLEAR(tint) REG_TSCR_WRITE(tint, TINT_STATUS_READ(tint) & ~BIT(tint))
|
||||
#endif
|
||||
|
||||
#define OFFSET(irq) ((irq) - 353 - COND_CODE_1(CONFIG_GIC, (32), (0)))
|
||||
#define REG_INTSEL_READ(irq) sys_read32(RZ_INTC_INTSEL + (OFFSET(irq) / 3) * 4)
|
||||
#define REG_INTSEL_WRITE(irq, v) sys_write32((v), RZ_INTC_INTSEL + (OFFSET(irq) / 3) * 4)
|
||||
#define REG_INTSEL_SPIk_SEL_MASK(irq) (BIT_MASK(10) << ((OFFSET(irq) % 3) * 10))
|
||||
|
||||
static const uint8_t gpioint_table[] = DT_PROP(DT_NODELABEL(intc), gpioint_table);
|
||||
|
||||
static inline void intc_rz_tint_clear_irq_status(const struct device *dev)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
uint8_t tint = config->tint;
|
||||
|
||||
TINT_STATUS_CLEAR(tint);
|
||||
|
||||
/*
|
||||
* User's manual: Clear Timing of Interrupt Cause
|
||||
* Dummy read is required after write
|
||||
*/
|
||||
TINT_STATUS_READ(tint);
|
||||
}
|
||||
|
||||
int intc_rz_tint_enable(const struct device *dev)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
|
||||
irq_enable(config->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_rz_tint_disable(const struct device *dev)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
|
||||
irq_disable(config->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_rz_tint_set_type(const struct device *dev, enum intc_rz_tint_trigger trig)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
struct intc_rz_tint_data *data = dev->data;
|
||||
uint8_t tint = config->tint;
|
||||
uint32_t reg_val = REG_TITSR_READ(tint);
|
||||
uint32_t flags = IRQ_TYPE_LEVEL;
|
||||
uint32_t set = 0;
|
||||
|
||||
switch (trig) {
|
||||
case RZ_TINT_FAILING_EDGE:
|
||||
set = 1;
|
||||
break;
|
||||
case RZ_TINT_RISING_EDGE:
|
||||
set = 0;
|
||||
break;
|
||||
case RZ_TINT_LOW_LEVEL:
|
||||
set = 3;
|
||||
break;
|
||||
case RZ_TINT_HIGH_LEVEL:
|
||||
set = 2;
|
||||
break;
|
||||
case RZ_TINT_BOTH_EDGE:
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Select interrupt type */
|
||||
reg_val = (reg_val & ~REG_TITSR_TITSEL_MASK(tint)) |
|
||||
FIELD_PREP(REG_TITSR_TITSEL_MASK(tint), set);
|
||||
REG_TITSR_WRITE(tint, reg_val);
|
||||
|
||||
/*
|
||||
* User's manual: Precaution when Changing Interrupt Settings
|
||||
* When changing the TINT interrupt detection method to the edge type,
|
||||
* write 0 to the TSTATn bit of TSCR.
|
||||
*/
|
||||
if ((trig == RZ_TINT_RISING_EDGE) || (trig == RZ_TINT_FAILING_EDGE)) {
|
||||
flags = IRQ_TYPE_EDGE;
|
||||
intc_rz_tint_clear_irq_status(dev);
|
||||
}
|
||||
|
||||
/* Set interrupt type for GIC, and clear pending interrupt */
|
||||
#ifdef CONFIG_GIC
|
||||
arm_gic_irq_set_priority(config->irq, config->prio, flags);
|
||||
arm_gic_irq_clear_pending(config->irq);
|
||||
#else
|
||||
NVIC_ClearPendingIRQ(config->irq);
|
||||
#endif
|
||||
|
||||
data->trigger_type = trig;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intc_rz_tint_isr(const struct device *dev)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
struct intc_rz_tint_data *data = dev->data;
|
||||
|
||||
intc_rz_tint_clear_irq_status(dev);
|
||||
|
||||
/* Clear pending interrupt */
|
||||
#ifdef CONFIG_GIC
|
||||
arm_gic_irq_clear_pending(config->irq);
|
||||
#else
|
||||
NVIC_ClearPendingIRQ(config->irq);
|
||||
#endif
|
||||
|
||||
if (data->callback) {
|
||||
data->callback(data->callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
static int intc_rz_tint_init(const struct device *dev)
|
||||
{
|
||||
struct intc_rz_tint_data *data = dev->data;
|
||||
|
||||
#if defined(CONFIG_RENESAS_RZ_INTC_SELECT_INTERRUPT)
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
uint8_t tint = config->tint;
|
||||
uint32_t irq = config->irq;
|
||||
uint32_t reg_val = REG_INTSEL_READ(irq);
|
||||
|
||||
reg_val &= ~REG_INTSEL_SPIk_SEL_MASK(irq);
|
||||
reg_val |= FIELD_PREP(REG_INTSEL_SPIk_SEL_MASK(irq), tint);
|
||||
|
||||
REG_INTSEL_WRITE(irq, reg_val);
|
||||
#endif
|
||||
return intc_rz_tint_set_type(dev, data->trigger_type);
|
||||
};
|
||||
|
||||
int intc_rz_tint_connect(const struct device *dev, uint8_t port, uint8_t pin)
|
||||
{
|
||||
const struct intc_rz_tint_config *config = dev->config;
|
||||
struct intc_rz_tint_data *data = dev->data;
|
||||
|
||||
uint8_t tint = config->tint;
|
||||
|
||||
/* Map to GPIOINT */
|
||||
uint8_t gpioint = gpioint_table[port] + pin;
|
||||
|
||||
if (gpioint > config->max_gpioint) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint32_t reg_val = REG_TSSR_READ(tint);
|
||||
|
||||
reg_val &= ~(REG_TSSR_TSSEL_MASK(tint) | REG_TSSR_TIEN_MASK(tint));
|
||||
reg_val |= FIELD_PREP(REG_TSSR_TSSEL_MASK(tint), gpioint);
|
||||
reg_val |= FIELD_PREP(REG_TSSR_TIEN_MASK(tint), 1U);
|
||||
REG_TSSR_WRITE(tint, reg_val);
|
||||
|
||||
data->gpioint = gpioint;
|
||||
data->port = port;
|
||||
data->pin = pin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_rz_tint_set_callback(const struct device *dev, intc_rz_tint_callback_t cb, void *arg)
|
||||
{
|
||||
struct intc_rz_tint_data *data = dev->data;
|
||||
|
||||
data->callback = cb;
|
||||
data->callback_data = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TINT_RZ_IRQ_CONNECT(index, isr) \
|
||||
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(index, 0, irq), DT_INST_IRQ_BY_IDX(index, 0, priority), \
|
||||
isr, DEVICE_DT_INST_GET(index), \
|
||||
COND_CODE_1(CONFIG_GIC, (DT_INST_IRQ_BY_IDX(index, 0, flags)), (0)));
|
||||
|
||||
#define INTC_RZ_TINT_INIT(index) \
|
||||
static const struct intc_rz_tint_config intc_rz_tint_config##index = { \
|
||||
.tint = DT_INST_REG_ADDR(index), \
|
||||
.irq = DT_INST_IRQ_BY_IDX(index, 0, irq), \
|
||||
.prio = DT_INST_IRQ_BY_IDX(index, 0, priority), \
|
||||
.max_gpioint = DT_PROP(DT_INST_PARENT(index), max_gpioint), \
|
||||
}; \
|
||||
struct intc_rz_tint_data intc_rz_tint_data##index = { \
|
||||
.trigger_type = DT_INST_ENUM_IDX_OR(index, trigger_type, 0), \
|
||||
}; \
|
||||
static int intc_rz_tint_init##index(const struct device *dev) \
|
||||
{ \
|
||||
TINT_RZ_IRQ_CONNECT(index, intc_rz_tint_isr) \
|
||||
return intc_rz_tint_init(dev); \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(index, intc_rz_tint_init##index, NULL, &intc_rz_tint_data##index, \
|
||||
&intc_rz_tint_config##index, PRE_KERNEL_2, \
|
||||
CONFIG_INTC_INIT_PRIORITY, NULL);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(INTC_RZ_TINT_INIT)
|
||||
21
dts/bindings/interrupt-controller/renesas,rz-intc-v2.yaml
Normal file
21
dts/bindings/interrupt-controller/renesas,rz-intc-v2.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Renesas RZ Interrupt Controller
|
||||
compatible: "renesas,rz-intc-v2"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
reg-names:
|
||||
required: true
|
||||
|
||||
gpioint-table:
|
||||
type: array
|
||||
|
||||
max-gpioint:
|
||||
required: true
|
||||
type: int
|
||||
@@ -9,3 +9,13 @@ include: base.yaml
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
reg-names:
|
||||
required: true
|
||||
|
||||
gpioint-table:
|
||||
type: array
|
||||
|
||||
max-gpioint:
|
||||
required: true
|
||||
type: int
|
||||
|
||||
27
dts/bindings/interrupt-controller/renesas,rz-tint.yaml
Normal file
27
dts/bindings/interrupt-controller/renesas,rz-tint.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Renesas RZ GPIO interrupt (TINT) controller
|
||||
|
||||
compatible: "renesas,rz-tint"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
trigger-type:
|
||||
required: true
|
||||
type: string
|
||||
description: |
|
||||
Indicates the condition that will trigger an interrupt when detected.
|
||||
enum:
|
||||
- "rising"
|
||||
- "falling"
|
||||
- "high_level"
|
||||
- "low_level"
|
||||
|
||||
"#irq-cells":
|
||||
type: int
|
||||
const: 1
|
||||
|
||||
irq-cells:
|
||||
- pin
|
||||
66
include/zephyr/drivers/interrupt_controller/intc_rz_tint.h
Normal file
66
include/zephyr/drivers/interrupt_controller/intc_rz_tint.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Renesas Electronics Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
enum intc_rz_tint_trigger {
|
||||
/** Interrupt triggered on falling edge */
|
||||
RZ_TINT_FAILING_EDGE,
|
||||
/** Interrupt triggered on rising edge */
|
||||
RZ_TINT_RISING_EDGE,
|
||||
/** Interrupt triggered on both edges */
|
||||
RZ_TINT_BOTH_EDGE,
|
||||
/** Interrupt triggered on low-level */
|
||||
RZ_TINT_LOW_LEVEL,
|
||||
/** Interrupt triggered on high-level */
|
||||
RZ_TINT_HIGH_LEVEL,
|
||||
};
|
||||
|
||||
/** RZ GPIO interrupt (TINT) callback */
|
||||
typedef void (*intc_rz_tint_callback_t)(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Connect a TINT channel to a specific GPIO pins
|
||||
*
|
||||
* @param dev: pointer to interrupt controller instance
|
||||
* @param port: GPIO port
|
||||
* @param pin: GPIO pin
|
||||
* @return 0 on success, or negative value on error
|
||||
*/
|
||||
int intc_rz_tint_connect(const struct device *dev, uint8_t port, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief Change trigger interrupt type
|
||||
*
|
||||
* @param dev: pointer to interrupt controller instance
|
||||
* @param trig: trigger type to be changed
|
||||
* @return 0 on success, or negative value on error
|
||||
*/
|
||||
int intc_rz_tint_set_type(const struct device *dev, enum intc_rz_tint_trigger trig);
|
||||
|
||||
/**
|
||||
* @brief Enable TINT interrupt.
|
||||
*
|
||||
* @param dev: pointer to interrupt controller instance
|
||||
* @return 0 on success, or negative value on error
|
||||
*/
|
||||
int intc_rz_tint_enable(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Disable TINT interrupt.
|
||||
*
|
||||
* @param dev: pointer to interrupt controller instance
|
||||
* @return 0 on success, or negative value on error
|
||||
*/
|
||||
int intc_rz_tint_disable(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Updates the user callback
|
||||
*
|
||||
* @param dev: pointer to interrupt controller instance
|
||||
* @param cb: callback to set
|
||||
* @param arg: user data passed to callback
|
||||
* @return 0 on success, or negative value on error
|
||||
*/
|
||||
int intc_rz_tint_set_callback(const struct device *dev, intc_rz_tint_callback_t cb, void *arg);
|
||||
Reference in New Issue
Block a user