141 lines
4.8 KiB
C
141 lines
4.8 KiB
C
/*
|
|
* Copyright 2023 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/device.h>
|
|
|
|
#define LOG_MODULE_NAME nxp_s32_emios
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_NXP_S32_EMIOS_LOG_LEVEL);
|
|
|
|
#include <Emios_Mcl_Ip.h>
|
|
#include <Emios_Mcl_Ip_Irq.h>
|
|
|
|
#define DT_DRV_COMPAT nxp_s32_emios
|
|
|
|
struct nxp_s32_emios_config {
|
|
uint8_t instance;
|
|
Emios_Mcl_Ip_ConfigType *mcl_info;
|
|
void (*irq_config)(void);
|
|
};
|
|
|
|
static int nxp_s32_emios_init(const struct device *dev)
|
|
{
|
|
const struct nxp_s32_emios_config *config = dev->config;
|
|
|
|
if (Emios_Mcl_Ip_Init(config->instance, config->mcl_info)) {
|
|
LOG_ERR("Could not initialize eMIOS");
|
|
return -EINVAL;
|
|
}
|
|
|
|
config->irq_config();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_MASTER_BUS_PERIOD 65535U
|
|
#define MIN_MASTER_BUS_PERIOD 2U
|
|
#define MAX_GLOB_PRESCALER 256U
|
|
#define MIN_GLOB_PRESCALER 1U
|
|
|
|
#define NXP_S32_EMIOS_MASTER_BUS_MODE(mode) DT_CAT(EMIOS_IP_, mode)
|
|
|
|
#define NXP_S32_EMIOS_INSTANCE_CHECK(idx, n) \
|
|
((DT_INST_REG_ADDR(n) == IP_EMIOS_##idx##_BASE) ? idx : 0)
|
|
|
|
#define NXP_S32_EMIOS_GET_INSTANCE(n) \
|
|
LISTIFY(__DEBRACKET eMIOS_INSTANCE_COUNT, NXP_S32_EMIOS_INSTANCE_CHECK, (|), n)
|
|
|
|
#define NXP_S32_EMIOS_GENERATE_GLOBAL_CONFIG(n) \
|
|
BUILD_ASSERT(IN_RANGE(DT_INST_PROP(n, clock_divider), \
|
|
MIN_GLOB_PRESCALER, MAX_GLOB_PRESCALER), \
|
|
"Divider for eMIOS global prescaler is out of range"); \
|
|
const Emios_Ip_GlobalConfigType nxp_s32_emios_##n##_global_config = { \
|
|
.allowDebugMode = true, \
|
|
.clkDivVal = DT_INST_PROP(n, clock_divider) - 1U, \
|
|
.enableGlobalTimeBase = true \
|
|
};
|
|
|
|
#define NXP_S32_EMIOS_MASTER_BUS_VERIFY(node_id) \
|
|
BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, period), \
|
|
MIN_MASTER_BUS_PERIOD, MAX_MASTER_BUS_PERIOD), \
|
|
"Node "DT_NODE_PATH(node_id)": period is out of range");
|
|
|
|
#define NXP_S32_EMIOS_MASTER_BUS_CONFIG(node_id) \
|
|
{ \
|
|
.hwChannel = DT_PROP(node_id, channel), \
|
|
.defaultPeriod = DT_PROP(node_id, period), \
|
|
.masterBusPrescaler = DT_PROP(node_id, prescaler) - 1, \
|
|
.allowDebugMode = DT_PROP(node_id, freeze), \
|
|
.masterMode = NXP_S32_EMIOS_MASTER_BUS_MODE(DT_STRING_TOKEN(node_id, mode)), \
|
|
.masterBusAltPrescaler = 0, \
|
|
},
|
|
|
|
#define NXP_S32_EMIOS_GENERATE_MASTER_BUS_CONFIG(n) \
|
|
DT_FOREACH_CHILD_STATUS_OKAY(DT_INST_CHILD(n, master_bus), \
|
|
NXP_S32_EMIOS_MASTER_BUS_VERIFY) \
|
|
const Emios_Ip_MasterBusConfigType nxp_s32_emios_##n##_master_bus_config[] = { \
|
|
DT_FOREACH_CHILD_STATUS_OKAY(DT_INST_CHILD(n, master_bus), \
|
|
NXP_S32_EMIOS_MASTER_BUS_CONFIG) \
|
|
};
|
|
|
|
#define NXP_S32_EMIOS_GENERATE_CONFIG(n) \
|
|
NXP_S32_EMIOS_GENERATE_GLOBAL_CONFIG(n) \
|
|
NXP_S32_EMIOS_GENERATE_MASTER_BUS_CONFIG(n) \
|
|
const Emios_Mcl_Ip_ConfigType nxp_s32_emios_##n##_mcl_config = { \
|
|
.channelsNumber = ARRAY_SIZE(nxp_s32_emios_##n##_master_bus_config), \
|
|
.emiosGlobalConfig = &nxp_s32_emios_##n##_global_config, \
|
|
.masterBusConfig = &nxp_s32_emios_##n##_master_bus_config \
|
|
};
|
|
|
|
#define EMIOS_INTERRUPT_NAME(name) DT_CAT3(EMIOS, name, _IRQ)
|
|
|
|
/*
|
|
* The real interrupt handlers only defined in some circumstances, just add
|
|
* weak implementations to avoid populating so many preprocessor directives
|
|
*/
|
|
#define EMIOS_INTERRUPT_DEFINE(node_id, prop, idx) \
|
|
__weak void EMIOS_INTERRUPT_NAME(DT_STRING_TOKEN_BY_IDX(node_id, prop, idx))(void) {}
|
|
|
|
#define NXP_S32_EMIOS_INTERRUPT_DEFINE(n) \
|
|
DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, EMIOS_INTERRUPT_DEFINE)
|
|
|
|
#define EMIOS_INTERRUPT_CONFIG(node_id, prop, idx) \
|
|
do { \
|
|
IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \
|
|
DT_IRQ_BY_IDX(node_id, idx, priority), \
|
|
EMIOS_INTERRUPT_NAME(DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)),\
|
|
DEVICE_DT_GET(node_id), \
|
|
0); \
|
|
irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \
|
|
} while (false);
|
|
|
|
#define NXP_S32_EMIOS_INTERRUPT_CONFIG(n) \
|
|
static void nxp_s32_emios_##n##_interrupt_config(void) \
|
|
{ \
|
|
DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, EMIOS_INTERRUPT_CONFIG) \
|
|
}
|
|
|
|
#define NXP_S32_EMIOS_INIT_DEVICE(n) \
|
|
NXP_S32_EMIOS_GENERATE_CONFIG(n) \
|
|
NXP_S32_EMIOS_INTERRUPT_DEFINE(n) \
|
|
NXP_S32_EMIOS_INTERRUPT_CONFIG(n) \
|
|
const struct nxp_s32_emios_config nxp_s32_emios_##n##_config = { \
|
|
.instance = NXP_S32_EMIOS_GET_INSTANCE(n), \
|
|
.mcl_info = (Emios_Mcl_Ip_ConfigType *)&nxp_s32_emios_##n##_mcl_config, \
|
|
.irq_config = nxp_s32_emios_##n##_interrupt_config, \
|
|
}; \
|
|
DEVICE_DT_INST_DEFINE(n, \
|
|
&nxp_s32_emios_init, \
|
|
NULL, \
|
|
NULL, \
|
|
&nxp_s32_emios_##n##_config, \
|
|
POST_KERNEL, \
|
|
CONFIG_NXP_S32_EMIOS_INIT_PRIORITY, \
|
|
NULL);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(NXP_S32_EMIOS_INIT_DEVICE)
|