1 /*
2 * Copyright 2023 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stdint.h>
9
10 #include <zephyr/drivers/pinctrl.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/arch/arch_interface.h>
14
15 #ifndef M_PI
16 #define M_PI 3.14159265358979323846
17 #endif
18
19 #define EMIOS_CHANNEL_COUNT 2U
20 #define EMIOS_CW_CH_IDX 0
21 #define EMIOS_CCW_CH_IDX 1
22
23 /* LCU LUT control values for each of the 4 LC outputs */
24 /* These values decide the direction of motor rotation */
25 #define LCU_O0_LUT 0xAAAA
26 #define LCU_O1_LUT 0xCCCC
27 #define LCU_O2_LUT 0x4182
28 #define LCU_O3_LUT 0x2814
29
30 LOG_MODULE_REGISTER(nxp_qdec_s32, CONFIG_SENSOR_LOG_LEVEL);
31
32 #include <Emios_Icu_Ip.h>
33 #include <Trgmux_Ip.h>
34 #include <Lcu_Ip.h>
35
36 #define DT_DRV_COMPAT nxp_qdec_s32
37
38 typedef void (*emios_callback_t)(void);
39
40 /* Configuration variables from eMIOS Icu driver */
41 extern eMios_Icu_Ip_ChStateType eMios_Icu_Ip_ChState[EMIOS_ICU_IP_NUM_OF_CHANNELS_USED];
42 extern uint8 eMios_Icu_Ip_IndexInChState[EMIOS_ICU_IP_INSTANCE_COUNT][EMIOS_ICU_IP_NUM_OF_CHANNELS];
43
44 struct qdec_s32_config {
45 uint8_t emios_inst;
46 uint8_t emios_channels[EMIOS_CHANNEL_COUNT];
47 const struct pinctrl_dev_config *pincfg;
48
49 const Trgmux_Ip_InitType *trgmux_config;
50
51 const Lcu_Ip_InitType *lcu_config;
52 emios_callback_t emios_cw_overflow_cb;
53 emios_callback_t emios_ccw_overflow_cb;
54 };
55
56 struct qdec_s32_data {
57 uint32_t counter_CW;
58 uint32_t counter_CCW;
59 int32_t abs_counter;
60 double micro_ticks_per_rev;
61 uint32_t ticks_per_sec;
62 uint32_t emios_cw_overflow_count;
63 uint32_t emios_ccw_overflow_count;
64 };
65
qdec_emios_overflow_count_cw_callback(const struct device * dev)66 static void qdec_emios_overflow_count_cw_callback(const struct device *dev)
67 {
68 struct qdec_s32_data *data = dev->data;
69
70 data->emios_cw_overflow_count++;
71 }
72
qdec_emios_overflow_count_ccw_callback(const struct device * dev)73 static void qdec_emios_overflow_count_ccw_callback(const struct device *dev)
74 {
75 struct qdec_s32_data *data = dev->data;
76
77 data->emios_ccw_overflow_count++;
78 }
79
qdec_s32_fetch(const struct device * dev,enum sensor_channel ch)80 static int qdec_s32_fetch(const struct device *dev, enum sensor_channel ch)
81 {
82 const struct qdec_s32_config *config = dev->config;
83 struct qdec_s32_data *data = dev->data;
84
85 if (ch != SENSOR_CHAN_ALL) {
86 return -ENOTSUP;
87 }
88
89 data->counter_CW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers(
90 config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX])); /* CW counter */
91 data->counter_CCW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers(
92 config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]));/* CCW counter*/
93
94 data->abs_counter = (int32_t)(
95 +(data->counter_CW + EMIOS_ICU_IP_COUNTER_MASK *
96 data->emios_cw_overflow_count)
97 -(data->counter_CCW + EMIOS_ICU_IP_COUNTER_MASK *
98 data->emios_ccw_overflow_count));
99
100 LOG_DBG("ABS_COUNT = %d CW = %u OverFlow_CW = %u CCW = %u Overflow_CCW = %u",
101 data->abs_counter, data->counter_CW,
102 data->emios_cw_overflow_count,
103 data->counter_CCW, data->emios_ccw_overflow_count);
104
105 return 0;
106 }
107
qdec_s32_ch_get(const struct device * dev,enum sensor_channel ch,struct sensor_value * val)108 static int qdec_s32_ch_get(const struct device *dev, enum sensor_channel ch,
109 struct sensor_value *val)
110 {
111 struct qdec_s32_data *data = dev->data;
112
113 double rotation = (data->abs_counter * 2.0 * M_PI) / data->micro_ticks_per_rev;
114
115 switch (ch) {
116 case SENSOR_CHAN_ROTATION:
117 sensor_value_from_double(val, rotation);
118 break;
119 default:
120 return -ENOTSUP;
121 }
122
123 return 0;
124 }
125
126 static DEVICE_API(sensor, qdec_s32_api) = {
127 .sample_fetch = &qdec_s32_fetch,
128 .channel_get = &qdec_s32_ch_get,
129 };
130
qdec_s32_initialize(const struct device * dev)131 static int qdec_s32_initialize(const struct device *dev)
132 {
133 const struct qdec_s32_config *config = dev->config;
134 uint8_t emios_inst, emios_hw_ch_cw, emios_hw_ch_ccw;
135
136 pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
137
138 if (Trgmux_Ip_Init(config->trgmux_config)) {
139 LOG_ERR("Could not initialize Trgmux");
140 return -EINVAL;
141 }
142
143 LOG_DBG("TRGMUX ACCESS Input[0] =%d Output[0]=%d",
144 config->trgmux_config->paxLogicTrigger[0]->Input,
145 config->trgmux_config->paxLogicTrigger[0]->Output);
146
147 if (Lcu_Ip_Init(config->lcu_config)) {
148 LOG_ERR("Could not initialize Lcu");
149 return -EINVAL;
150 }
151
152 /* Unmask relevant LCU OUT Channels */
153 Lcu_Ip_SyncOutputValueType EncLcuEnable[4U];
154
155 EncLcuEnable[0].LogicOutputId = LCU_LOGIC_OUTPUT_0;
156 EncLcuEnable[0].Value = 1U;
157 EncLcuEnable[1].LogicOutputId = LCU_LOGIC_OUTPUT_1;
158 EncLcuEnable[1].Value = 1U;
159 EncLcuEnable[2].LogicOutputId = LCU_LOGIC_OUTPUT_2;
160 EncLcuEnable[2].Value = 1U;
161 EncLcuEnable[3].LogicOutputId = LCU_LOGIC_OUTPUT_3;
162 EncLcuEnable[3].Value = 1U;
163 Lcu_Ip_SetSyncOutputEnable(EncLcuEnable, 4U);
164
165 emios_inst = config->emios_inst;
166 emios_hw_ch_cw = config->emios_channels[EMIOS_CW_CH_IDX];
167 emios_hw_ch_ccw = config->emios_channels[EMIOS_CCW_CH_IDX];
168
169 /* Initialize the positions of the eMios hw channels used for QDEC
170 * to be beyond the eMios pwm hw channels. Currently only pwm and qdec
171 * are using the eMios channels so qdec ones are the last two.
172 */
173 eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw]
174 = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 2;
175 eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw]
176 = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 1;
177
178 /* Set Overflow Notification for eMIOS channels meant
179 * for Clockwise and Counterclock rotation counters
180 */
181 eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw]]
182 .eMiosOverflowNotification = config->emios_cw_overflow_cb;
183 eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw]]
184 .eMiosOverflowNotification = config->emios_ccw_overflow_cb;
185
186 Emios_Icu_Ip_SetInitialCounterValue(
187 config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX], (uint32_t)0x1U);
188 Emios_Icu_Ip_SetInitialCounterValue(
189 config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX], (uint32_t)0x1U);
190
191 Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst,
192 config->emios_channels[EMIOS_CW_CH_IDX],
193 EMIOS_ICU_IP_COUNTER_MASK);
194 Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst,
195 config->emios_channels[EMIOS_CCW_CH_IDX],
196 EMIOS_ICU_IP_COUNTER_MASK);
197
198 /* This API sets MCB/EMIOS_ICU_MODE_EDGE_COUNTER mode */
199 Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX]);
200 Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]);
201
202 LOG_DBG("Init complete");
203
204 return 0;
205 }
206
207 #define EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \
208 static void qdec##n##_emios_overflow_count_cw_callback(void) \
209 { \
210 qdec_emios_overflow_count_cw_callback(DEVICE_DT_INST_GET(n)); \
211 } \
212 \
213 static void qdec##n##_emios_overflow_count_ccw_callback(void) \
214 { \
215 qdec_emios_overflow_count_ccw_callback(DEVICE_DT_INST_GET(n)); \
216 }
217
218 #define EMIOS_NXP_S32_INSTANCE_CHECK(idx, node_id) \
219 ((DT_REG_ADDR(node_id) == IP_EMIOS_##idx##_BASE) ? idx : 0)
220
221 #define EMIOS_NXP_S32_GET_INSTANCE(node_id) \
222 LISTIFY(__DEBRACKET eMIOS_INSTANCE_COUNT, EMIOS_NXP_S32_INSTANCE_CHECK, (|), node_id)
223
224 #define LCU_NXP_S32_INSTANCE_CHECK(idx, node_id) \
225 ((DT_REG_ADDR(node_id) == IP_LCU_##idx##_BASE) ? idx : 0)
226
227 #define LCU_NXP_S32_GET_INSTANCE(node_id) \
228 LISTIFY(__DEBRACKET LCU_INSTANCE_COUNT, LCU_NXP_S32_INSTANCE_CHECK, (|), node_id)
229
230 #define TRGMUX_NXP_S32_INSTANCE_CHECK(node_id) \
231 ((DT_REG_ADDR(node_id) == IP_TRGMUX_BASE) ? 0 : -1)
232
233 #define TRGMUX_NXP_S32_GET_INSTANCE(node_id) TRGMUX_NXP_S32_INSTANCE_CHECK(node_id)
234
235 /* LCU Logic Input Configuration */
236 #define LogicInputCfg_Common(n, mux_sel_idx) \
237 { \
238 .MuxSel = DT_INST_PROP_BY_IDX(n, lcu_mux_sel, mux_sel_idx), \
239 .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \
240 .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \
241 };
242 #define LogicInput_Config_Common(n, hw_lc_input_id, logic_input_n_cfg) \
243 { \
244 .xLogicInputId = { \
245 .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \
246 .HwLcInputId = DT_INST_PROP_BY_IDX(n, lcu_input_idx, hw_lc_input_id), \
247 }, \
248 .pxLcInputConfig = &logic_input_n_cfg, \
249 };
250
251 /* LCU Logic Output Configuration */
252 #define LogicOutputCfg_Common(En_Debug_Mode, Lut_Control, Lut_Rise_Filt, Lut_Fall_Filt) \
253 { \
254 .EnDebugMode = (boolean)En_Debug_Mode, \
255 .LutControl = Lut_Control, \
256 .LutRiseFilt = Lut_Rise_Filt, \
257 .LutFallFilt = Lut_Fall_Filt, \
258 .EnLutDma = (boolean)FALSE, \
259 .EnForceDma = (boolean)FALSE, \
260 .EnLutInt = (boolean)FALSE, \
261 .EnForceInt = (boolean)FALSE, \
262 .InvertOutput = (boolean)FALSE, \
263 .ForceSignalSel = 0U, \
264 .ClearForceMode = LCU_IP_CLEAR_FORCE_SIGNAL_IMMEDIATE, \
265 .ForceSyncSel = LCU_IP_SYNC_SEL_INPUT0, \
266 };
267 #define LogicOutput_Config_Common(n, logic_output_cfg, hw_lc_output_id) \
268 { \
269 .xLogicOutputId = { \
270 .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \
271 .HwLcOutputId = hw_lc_output_id, \
272 .IntCallback = NULL_PTR, \
273 }, \
274 .pxLcOutputConfig = &logic_output_cfg, \
275 };
276
277 #define LCU_IP_INIT_CONFIG(n) \
278 const Lcu_Ip_LogicInputConfigType LogicInput##n##_0_Cfg = \
279 LogicInputCfg_Common(n, 0) \
280 const Lcu_Ip_LogicInputConfigType LogicInput##n##_1_Cfg = \
281 LogicInputCfg_Common(n, 1) \
282 const Lcu_Ip_LogicInputConfigType LogicInput##n##_2_Cfg = \
283 LogicInputCfg_Common(n, 2) \
284 const Lcu_Ip_LogicInputConfigType LogicInput##n##_3_Cfg = \
285 LogicInputCfg_Common(n, 3) \
286 \
287 const Lcu_Ip_LogicInputType LogicInput##n##_0_Config = \
288 LogicInput_Config_Common(n, 0, LogicInput##n##_0_Cfg) \
289 const Lcu_Ip_LogicInputType LogicInput##n##_1_Config = \
290 LogicInput_Config_Common(n, 1, LogicInput##n##_1_Cfg) \
291 const Lcu_Ip_LogicInputType LogicInput##n##_2_Config = \
292 LogicInput_Config_Common(n, 2, LogicInput##n##_2_Cfg) \
293 const Lcu_Ip_LogicInputType LogicInput##n##_3_Config = \
294 LogicInput_Config_Common(n, 3, LogicInput##n##_3_Cfg) \
295 \
296 const Lcu_Ip_LogicInputType \
297 *const Lcu_Ip_ppxLogicInputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INPUTS] = { \
298 &LogicInput##n##_0_Config, \
299 &LogicInput##n##_1_Config, \
300 &LogicInput##n##_2_Config, \
301 &LogicInput##n##_3_Config, \
302 }; \
303 \
304 const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_0_Cfg = LogicOutputCfg_Common( \
305 LCU_IP_DEBUG_DISABLE, LCU_O0_LUT, \
306 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 1), \
307 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 2)) \
308 const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_1_Cfg = LogicOutputCfg_Common( \
309 LCU_IP_DEBUG_DISABLE, LCU_O1_LUT, \
310 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 4), \
311 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 5)) \
312 const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_2_Cfg = LogicOutputCfg_Common( \
313 LCU_IP_DEBUG_ENABLE, LCU_O2_LUT, \
314 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 7), \
315 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 8)) \
316 const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_3_Cfg = LogicOutputCfg_Common( \
317 LCU_IP_DEBUG_ENABLE, LCU_O3_LUT, \
318 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 10), \
319 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 11)) \
320 \
321 const Lcu_Ip_LogicOutputType LogicOutput##n##_0_Config = \
322 LogicOutput_Config_Common(n, LogicOutput##n##_0_Cfg, \
323 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 0)) \
324 const Lcu_Ip_LogicOutputType LogicOutput##n##_1_Config = \
325 LogicOutput_Config_Common(n, LogicOutput##n##_1_Cfg, \
326 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 3)) \
327 const Lcu_Ip_LogicOutputType LogicOutput##n##_2_Config = \
328 LogicOutput_Config_Common(n, LogicOutput##n##_2_Cfg, \
329 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 6)) \
330 const Lcu_Ip_LogicOutputType LogicOutput##n##_3_Config = \
331 LogicOutput_Config_Common(n, LogicOutput##n##_3_Cfg, \
332 DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 9)) \
333 \
334 const Lcu_Ip_LogicOutputType \
335 *const Lcu_Ip_ppxLogicOutputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \
336 &LogicOutput##n##_0_Config, \
337 &LogicOutput##n##_1_Config, \
338 &LogicOutput##n##_2_Config, \
339 &LogicOutput##n##_3_Config, \
340 }; \
341 \
342 const Lcu_Ip_LogicInputConfigType Lcu_Ip_LogicInputResetConfig##n = { \
343 .MuxSel = LCU_IP_MUX_SEL_LOGIC_0, \
344 .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \
345 .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \
346 }; \
347 \
348 const Lcu_Ip_LogicOutputConfigType Lcu_Ip_LogicOutputResetConfig##n = \
349 LogicOutputCfg_Common(LCU_IP_DEBUG_DISABLE, 0U, 0U, 0U) \
350 \
351 const Lcu_Ip_LogicInstanceType LcuLogicInstance##n##_0_Config = { \
352 .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \
353 .NumLogicCellConfig = 0U, \
354 .ppxLogicCellConfigArray = NULL_PTR, \
355 .OperationMode = LCU_IP_INTERRUPT_MODE, \
356 }; \
357 const Lcu_Ip_LogicInstanceType \
358 *const Lcu_Ip_ppxLogicInstanceArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INSTANCES] = { \
359 &LcuLogicInstance##n##_0_Config, \
360 }; \
361 \
362 Lcu_Ip_HwOutputStateType HwOutput##n##_0_State_Config; \
363 Lcu_Ip_HwOutputStateType HwOutput##n##_1_State_Config; \
364 Lcu_Ip_HwOutputStateType HwOutput##n##_2_State_Config; \
365 Lcu_Ip_HwOutputStateType HwOutput##n##_3_State_Config; \
366 Lcu_Ip_HwOutputStateType \
367 *Lcu_Ip_ppxHwOutputStateArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \
368 &HwOutput##n##_0_State_Config, \
369 &HwOutput##n##_1_State_Config, \
370 &HwOutput##n##_2_State_Config, \
371 &HwOutput##n##_3_State_Config, \
372 }; \
373 \
374 const Lcu_Ip_InitType Lcu_Ip_Init_Config##n = { \
375 .ppxHwOutputStateArray = &Lcu_Ip_ppxHwOutputStateArray##n##_Config[0], \
376 .ppxLogicInstanceConfigArray = &Lcu_Ip_ppxLogicInstanceArray##n##_Config[0], \
377 .pxLogicOutputResetConfigArray = &Lcu_Ip_LogicOutputResetConfig##n, \
378 .pxLogicInputResetConfigArray = &Lcu_Ip_LogicInputResetConfig##n, \
379 .ppxLogicOutputConfigArray = &Lcu_Ip_ppxLogicOutputArray##n##_Config[0], \
380 .ppxLogicInputConfigArray = &Lcu_Ip_ppxLogicInputArray##n##_Config[0], \
381 };
382
383 #define Trgmux_Ip_LogicTrigger_Config(n, logic_channel, output, input) \
384 { \
385 .LogicChannel = logic_channel, \
386 .Output = output, \
387 .Input = input, \
388 .HwInstId = TRGMUX_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, trgmux)), \
389 .Lock = (boolean)FALSE, \
390 };
391
392 #define TRGMUX_IP_INIT_CONFIG(n) \
393 const Trgmux_Ip_LogicTriggerType \
394 Trgmux_Ip_LogicTrigger##n##_0_Config = Trgmux_Ip_LogicTrigger_Config(n, \
395 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 0), \
396 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 1), \
397 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 2)) \
398 const Trgmux_Ip_LogicTriggerType \
399 Trgmux_Ip_LogicTrigger##n##_1_Config = Trgmux_Ip_LogicTrigger_Config(n, \
400 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 3), \
401 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 4), \
402 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 5)) \
403 const Trgmux_Ip_LogicTriggerType \
404 Trgmux_Ip_LogicTrigger##n##_2_Config = Trgmux_Ip_LogicTrigger_Config(n, \
405 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 6), \
406 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 7), \
407 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 8)) \
408 const Trgmux_Ip_LogicTriggerType \
409 Trgmux_Ip_LogicTrigger##n##_3_Config = Trgmux_Ip_LogicTrigger_Config(n, \
410 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 9), \
411 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 10), \
412 DT_INST_PROP_BY_IDX(n, trgmux_io_config, 11)) \
413 const Trgmux_Ip_InitType Trgmux_Ip_Init_##n##_Config = { \
414 .paxLogicTrigger = { \
415 &Trgmux_Ip_LogicTrigger##n##_0_Config, \
416 &Trgmux_Ip_LogicTrigger##n##_1_Config, \
417 &Trgmux_Ip_LogicTrigger##n##_2_Config, \
418 &Trgmux_Ip_LogicTrigger##n##_3_Config, \
419 }, \
420 };
421
422
423 #define QDEC_NXP_S32_INIT(n) \
424 \
425 static struct qdec_s32_data qdec_s32_##n##_data = { \
426 .micro_ticks_per_rev = (double)(DT_INST_PROP(n, micro_ticks_per_rev) / 1000000),\
427 .counter_CW = 1, \
428 .counter_CCW = 1, \
429 }; \
430 \
431 PINCTRL_DT_INST_DEFINE(n); \
432 TRGMUX_IP_INIT_CONFIG(n) \
433 LCU_IP_INIT_CONFIG(n) \
434 EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \
435 \
436 static const struct qdec_s32_config qdec_s32_##n##_config = { \
437 .emios_inst = EMIOS_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, emios)), \
438 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
439 .trgmux_config = &Trgmux_Ip_Init_##n##_Config, \
440 .lcu_config = &Lcu_Ip_Init_Config##n, \
441 .emios_channels = {DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CW_CH_IDX), \
442 DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CCW_CH_IDX)}, \
443 .emios_cw_overflow_cb = &qdec##n##_emios_overflow_count_cw_callback, \
444 .emios_ccw_overflow_cb = &qdec##n##_emios_overflow_count_ccw_callback, \
445 }; \
446 \
447 SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_s32_initialize, NULL, &qdec_s32_##n##_data, \
448 &qdec_s32_##n##_config, POST_KERNEL, \
449 CONFIG_SENSOR_INIT_PRIORITY, &qdec_s32_api);
450
451 DT_INST_FOREACH_STATUS_OKAY(QDEC_NXP_S32_INIT)
452