-
Notifications
You must be signed in to change notification settings - Fork 6.1k
/
nxp_s32_emios.c
140 lines (115 loc) · 4.79 KB
/
nxp_s32_emios.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
* 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)