ITE drivers/interrupt_controller: add wuc interface

Add wakeup controller interface for ITE it8xxx2 chip.

Signed-off-by: Ruibin Chang <ruibin.chang@ite.com.tw>
This commit is contained in:
Ruibin Chang 2021-09-07 13:45:39 +08:00 committed by Marti Bolivar
commit 4b75cf8f47
11 changed files with 857 additions and 0 deletions

View file

@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_GIC_V3_ITS intc_gicv3_its.c)
zephyr_library_sources_ifdef(CONFIG_INTEL_VTD_ICTL intc_intel_vtd.c)
zephyr_library_sources_ifdef(CONFIG_IOAPIC intc_ioapic.c)
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_INTC intc_ite_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_WUC wuc_ite_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_LEON_IRQMP intc_irqmp.c)
zephyr_library_sources_ifdef(CONFIG_LOAPIC intc_loapic.c intc_system_apic.c)
zephyr_library_sources_ifdef(CONFIG_LOAPIC_SPURIOUS_VECTOR intc_loapic_spurious.S)

View file

@ -51,6 +51,10 @@ config INTC_INIT_PRIORITY
help
Interrupt controller device initialization priority.
module = INTC
module-str = intc
source "subsys/logging/Kconfig.template.log_config"
source "drivers/interrupt_controller/Kconfig.multilevel"
source "drivers/interrupt_controller/Kconfig.loapic"

View file

@ -9,3 +9,15 @@ config ITE_IT8XXX2_INTC
instance of the shared interrupt driver. To conserve RAM set
this value to the lowest practical value.
this software interrupt default set on by device tree.
# Workaround for not being able to have commas in macro arguments
DT_COMPAT_ITE_IT8XXX2_WUC := ite,it8xxx2-wuc
config ITE_IT8XXX2_WUC
bool "ITE it8xxx2 Wakeup controller (WUC) interface"
depends on SOC_IT8XXX2
default $(dt_compat_enabled,$(DT_COMPAT_ITE_IT8XXX2_WUC))
help
This option enables the wakeup controller interface for IT8XXX2
family.
This is required for KSCAN, UART, eSPI, GPIO etc., interrupt support.

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2022 ITE Corporation. All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ite_it8xxx2_wuc
#include <device.h>
#include <drivers/interrupt_controller/wuc_ite_it8xxx2.h>
#include <dt-bindings/interrupt-controller/it8xxx2-wuc.h>
#include <kernel.h>
#include <soc.h>
#include <soc_common.h>
#include <stdlib.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(wuc_ite_it8xxx2, CONFIG_INTC_LOG_LEVEL);
/* Driver config */
struct it8xxx2_wuc_cfg {
/* WUC wakeup edge mode register */
uint8_t *reg_wuemr;
/* WUC wakeup edge sense register */
uint8_t *reg_wuesr;
/* WUC wakeup enable register */
uint8_t *reg_wuenr;
/* WUC wakeup both edge mode register */
uint8_t *reg_wubemr;
};
void it8xxx2_wuc_enable(const struct device *dev, uint8_t mask)
{
const struct it8xxx2_wuc_cfg *config = dev->config;
volatile uint8_t *reg_wuenr = config->reg_wuenr;
/*
* WUC group only 1, 3, and 4 have enable/disable register,
* others are always enabled.
*/
if (reg_wuenr == IT8XXX2_WUC_UNUSED_REG) {
return;
}
/* Enable wakeup interrupt of the pin */
*reg_wuenr |= mask;
}
void it8xxx2_wuc_disable(const struct device *dev, uint8_t mask)
{
const struct it8xxx2_wuc_cfg *config = dev->config;
volatile uint8_t *reg_wuenr = config->reg_wuenr;
/*
* WUC group only 1, 3, and 4 have enable/disable register,
* others are always enabled.
*/
if (reg_wuenr == IT8XXX2_WUC_UNUSED_REG) {
return;
}
/* Disable wakeup interrupt of the pin */
*reg_wuenr &= ~mask;
}
void it8xxx2_wuc_clear_status(const struct device *dev, uint8_t mask)
{
const struct it8xxx2_wuc_cfg *config = dev->config;
volatile uint8_t *reg_wuesr = config->reg_wuesr;
if (reg_wuesr == IT8XXX2_WUC_UNUSED_REG) {
return;
}
/* W/C wakeup interrupt status of the pin */
*reg_wuesr = mask;
}
void it8xxx2_wuc_set_polarity(const struct device *dev, uint8_t mask, uint32_t flags)
{
const struct it8xxx2_wuc_cfg *config = dev->config;
volatile uint8_t *reg_wuemr = config->reg_wuemr;
volatile uint8_t *reg_wubemr = config->reg_wubemr;
if (reg_wuemr == IT8XXX2_WUC_UNUSED_REG) {
return;
}
/* Set wakeup interrupt edge trigger mode of the pin */
if ((flags & WUC_TYPE_EDGE_BOTH) == WUC_TYPE_EDGE_RISING) {
*reg_wubemr &= ~mask;
*reg_wuemr &= ~mask;
} else if ((flags & WUC_TYPE_EDGE_BOTH) == WUC_TYPE_EDGE_FALLING) {
*reg_wubemr &= ~mask;
*reg_wuemr |= mask;
} else {
/* Both edge trigger mode */
*reg_wubemr |= mask;
}
}
static int it8xxx2_wuc_init(const struct device *dev)
{
return 0;
}
#define IT8XXX2_WUC_INIT(inst) \
\
static const struct it8xxx2_wuc_cfg it8xxx2_wuc_cfg_##inst = { \
.reg_wuemr = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(inst, 0), \
.reg_wuesr = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(inst, 1), \
.reg_wuenr = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(inst, 2), \
.reg_wubemr = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(inst, 3), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, \
&it8xxx2_wuc_init, \
NULL, \
NULL, \
&it8xxx2_wuc_cfg_##inst, \
PRE_KERNEL_1, \
CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, \
NULL);
DT_INST_FOREACH_STATUS_OKAY(IT8XXX2_WUC_INIT)