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