1 /*
2  * Copyright 2023, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7  /* Based on dsi_mcux.c, which is (c) 2022 NXP */
8 
9 #define DT_DRV_COMPAT nxp_mipi_dsi_2l
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/mipi_dsi.h>
14 #include <zephyr/drivers/mipi_dsi/mipi_dsi_mcux_2l.h>
15 #include <zephyr/drivers/dma.h>
16 #include <zephyr/drivers/dma/dma_mcux_smartdma.h>
17 #include <zephyr/logging/log.h>
18 
19 #include <fsl_inputmux.h>
20 #include <fsl_mipi_dsi.h>
21 #include <fsl_clock.h>
22 
23 #include <soc.h>
24 
25 LOG_MODULE_REGISTER(dsi_mcux_host, CONFIG_MIPI_DSI_LOG_LEVEL);
26 
27 struct mcux_mipi_dsi_config {
28 	MIPI_DSI_HOST_Type *base;
29 	dsi_dpi_config_t dpi_config;
30 	bool auto_insert_eotp;
31 	bool noncontinuous_hs_clk;
32 	const struct device *bit_clk_dev;
33 	clock_control_subsys_t bit_clk_subsys;
34 	const struct device *esc_clk_dev;
35 	clock_control_subsys_t esc_clk_subsys;
36 	const struct device *pixel_clk_dev;
37 	clock_control_subsys_t pixel_clk_subsys;
38 	uint32_t dphy_ref_freq;
39 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
40 	const struct device *smart_dma;
41 #else
42 	void (*irq_config_func)(const struct device *dev);
43 #endif
44 };
45 
46 struct mcux_mipi_dsi_data {
47 	dsi_handle_t mipi_handle;
48 	struct k_sem transfer_sem;
49 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
50 	uint8_t dma_slot;
51 #endif
52 };
53 
54 
55 /* MAX DSI TX payload */
56 #define DSI_TX_MAX_PAYLOAD_BYTE (64U * 4U)
57 
58 
59 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
60 
61 /* Callback for DSI DMA transfer completion, called in ISR context */
dsi_mcux_dma_cb(const struct device * dma_dev,void * user_data,uint32_t channel,int status)62 static void dsi_mcux_dma_cb(const struct device *dma_dev,
63 				void *user_data, uint32_t channel, int status)
64 {
65 	const struct device *dev = user_data;
66 	const struct mcux_mipi_dsi_config *config = dev->config;
67 	struct mcux_mipi_dsi_data *data = dev->data;
68 	uint32_t int_flags1, int_flags2;
69 
70 	if (status != 0) {
71 		LOG_ERR("SMARTDMA transfer failed");
72 	} else {
73 		/* Disable DSI interrupts at transfer completion */
74 		DSI_DisableInterrupts(config->base, kDSI_InterruptGroup1ApbTxDone |
75 						kDSI_InterruptGroup1HtxTo, 0U);
76 		DSI_GetAndClearInterruptStatus(config->base, &int_flags1, &int_flags2);
77 		k_sem_give(&data->transfer_sem);
78 	}
79 }
80 
81 /* Helper function to transfer DSI color (DMA based implementation) */
dsi_mcux_tx_color(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)82 static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
83 			     struct mipi_dsi_msg *msg)
84 {
85 	/*
86 	 * Color streams are a special case for this DSI peripheral, because
87 	 * the SMARTDMA peripheral (if enabled) can be used to accelerate
88 	 * the transfer of data to the DSI. The SMARTDMA has the additional
89 	 * advantage over traditional DMA of being able to automatically
90 	 * byte swap color data. This is advantageous, as most graphical
91 	 * frameworks store RGB data in little endian format, but many
92 	 * MIPI displays expect color data in big endian format.
93 	 */
94 	const struct mcux_mipi_dsi_config *config = dev->config;
95 	struct mcux_mipi_dsi_data *data = dev->data;
96 	struct dma_config dma_cfg = {0};
97 	struct dma_block_config block = {0};
98 	int ret;
99 
100 	if (channel != 0) {
101 		return -ENOTSUP; /* DMA can only transfer on virtual channel 0 */
102 	}
103 
104 	/* Configure smartDMA device, and run transfer */
105 	block.source_address = (uint32_t)msg->tx_buf;
106 	block.block_size = msg->tx_len;
107 
108 	dma_cfg.dma_callback = dsi_mcux_dma_cb;
109 	dma_cfg.user_data = (struct device *)dev;
110 	dma_cfg.head_block = &block;
111 	dma_cfg.block_count = 1;
112 	dma_cfg.dma_slot = data->dma_slot;
113 	dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
114 	ret = dma_config(config->smart_dma, 0, &dma_cfg);
115 	if (ret < 0) {
116 		LOG_ERR("Could not configure SMARTDMA");
117 		return ret;
118 	}
119 	/*
120 	 * SMARTDMA uses DSI interrupt line as input for the DMA
121 	 * transfer trigger. Therefore, we need to enable DSI TX
122 	 * interrupts in order to trigger the DMA engine.
123 	 * Note that if the MIPI IRQ is enabled in
124 	 * the NVIC, it will fire on every SMARTDMA transfer
125 	 */
126 	DSI_EnableInterrupts(config->base, kDSI_InterruptGroup1ApbTxDone |
127 					kDSI_InterruptGroup1HtxTo, 0U);
128 	/* Trigger DMA engine */
129 	ret = dma_start(config->smart_dma, 0);
130 	if (ret < 0) {
131 		LOG_ERR("Could not start SMARTDMA");
132 		return ret;
133 	}
134 	/* Wait for TX completion */
135 	k_sem_take(&data->transfer_sem, K_FOREVER);
136 	return msg->tx_len;
137 }
138 
139 #else /* CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA is not set */
140 
141 /* Callback for DSI transfer completion, called in ISR context */
dsi_transfer_complete(MIPI_DSI_HOST_Type * base,dsi_handle_t * handle,status_t status,void * userData)142 static void dsi_transfer_complete(MIPI_DSI_HOST_Type *base,
143 	dsi_handle_t *handle, status_t status, void *userData)
144 {
145 	struct mcux_mipi_dsi_data *data = userData;
146 
147 	k_sem_give(&data->transfer_sem);
148 }
149 
150 
151 /* Helper function to transfer DSI color (Interrupt based implementation) */
dsi_mcux_tx_color(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)152 static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
153 			     struct mipi_dsi_msg *msg)
154 {
155 	const struct mcux_mipi_dsi_config *config = dev->config;
156 	struct mcux_mipi_dsi_data *data = dev->data;
157 	status_t status;
158 	dsi_transfer_t xfer = {
159 		.virtualChannel = channel,
160 		.txData = msg->tx_buf,
161 		.rxDataSize = (uint16_t)msg->rx_len,
162 		.rxData = msg->rx_buf,
163 		.sendDscCmd = true,
164 		.dscCmd = msg->cmd,
165 		.txDataType = kDSI_TxDataDcsLongWr,
166 		/* default to high speed unless told to use low power */
167 		.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed,
168 	};
169 
170 	/*
171 	 * Cap transfer size. Note that we subtract six bytes here,
172 	 * one for the DSC command and five to insure that
173 	 * transfers are still aligned on a pixel boundary
174 	 * (two or three byte pixel sizes are supported).
175 	 */
176 	xfer.txDataSize = MIN(msg->tx_len, (DSI_TX_MAX_PAYLOAD_BYTE - 6));
177 
178 	if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) {
179 		/* Manually swap the 16 byte color data in software */
180 		uint8_t *src = (uint8_t *)xfer.txData;
181 		uint8_t tmp;
182 
183 		for (uint32_t i = 0; i < xfer.txDataSize; i += 2) {
184 			tmp = src[i];
185 			src[i] = src[i + 1];
186 			src[i + 1] = tmp;
187 		}
188 	}
189 	/* Send TX data using non-blocking DSI API */
190 	status = DSI_TransferNonBlocking(config->base,
191 					&data->mipi_handle, &xfer);
192 	/* Wait for transfer completion */
193 	k_sem_take(&data->transfer_sem, K_FOREVER);
194 	if (status != kStatus_Success) {
195 		LOG_ERR("Transmission failed");
196 		return -EIO;
197 	}
198 	return xfer.txDataSize;
199 }
200 
201 /* ISR is used for DSI interrupt based implementation, unnecessary if DMA is used */
mipi_dsi_isr(const struct device * dev)202 static int mipi_dsi_isr(const struct device *dev)
203 {
204 	const struct mcux_mipi_dsi_config *config = dev->config;
205 	struct mcux_mipi_dsi_data *data = dev->data;
206 
207 	DSI_TransferHandleIRQ(config->base, &data->mipi_handle);
208 	return 0;
209 }
210 
211 #endif
212 
dsi_mcux_attach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)213 static int dsi_mcux_attach(const struct device *dev,
214 			   uint8_t channel,
215 			   const struct mipi_dsi_device *mdev)
216 {
217 	const struct mcux_mipi_dsi_config *config = dev->config;
218 	dsi_dphy_config_t dphy_config;
219 	dsi_config_t dsi_config;
220 	uint32_t dphy_bit_clk_freq;
221 	uint32_t dphy_esc_clk_freq;
222 	uint32_t dsi_pixel_clk_freq;
223 	uint32_t bit_width;
224 
225 	DSI_GetDefaultConfig(&dsi_config);
226 	dsi_config.numLanes = mdev->data_lanes;
227 	dsi_config.autoInsertEoTp = config->auto_insert_eotp;
228 	dsi_config.enableNonContinuousHsClk = config->noncontinuous_hs_clk;
229 
230 	imxrt_pre_init_display_interface();
231 
232 	/* Init the DSI module. */
233 	DSI_Init(config->base, &dsi_config);
234 
235 #ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
236 	/* Connect DSI IRQ line to SMARTDMA trigger via
237 	 * INPUTMUX.
238 	 */
239 	/* Attach INPUTMUX from MIPI to SMARTDMA */
240 	INPUTMUX_Init(INPUTMUX);
241 	INPUTMUX_AttachSignal(INPUTMUX, 0, kINPUTMUX_MipiIrqToSmartDmaInput);
242 	/* Gate inputmux clock to save power */
243 	INPUTMUX_Deinit(INPUTMUX);
244 
245 	if (!device_is_ready(config->smart_dma)) {
246 		return -ENODEV;
247 	}
248 
249 	struct mcux_mipi_dsi_data *data = dev->data;
250 
251 	switch (mdev->pixfmt) {
252 	case MIPI_DSI_PIXFMT_RGB888:
253 		data->dma_slot = DMA_SMARTDMA_MIPI_RGB888_DMA;
254 		break;
255 	case MIPI_DSI_PIXFMT_RGB565:
256 		if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) {
257 			data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP;
258 		} else {
259 			data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA;
260 		}
261 		break;
262 	default:
263 		LOG_ERR("SMARTDMA does not support pixel_format %u",
264 			mdev->pixfmt);
265 		return -ENODEV;
266 	}
267 #else
268 	struct mcux_mipi_dsi_data *data = dev->data;
269 
270 	/* Create transfer handle */
271 	if (DSI_TransferCreateHandle(config->base, &data->mipi_handle,
272 				dsi_transfer_complete, data) != kStatus_Success) {
273 		return -ENODEV;
274 	}
275 #endif
276 
277 	/* Get the DPHY bit clock frequency */
278 	if (clock_control_get_rate(config->bit_clk_dev,
279 				config->bit_clk_subsys,
280 				&dphy_bit_clk_freq)) {
281 		return -EINVAL;
282 	};
283 	/* Get the DPHY ESC clock frequency */
284 	if (clock_control_get_rate(config->esc_clk_dev,
285 				config->esc_clk_subsys,
286 				&dphy_esc_clk_freq)) {
287 		return -EINVAL;
288 	}
289 	/* Get the Pixel clock frequency */
290 	if (clock_control_get_rate(config->pixel_clk_dev,
291 				config->pixel_clk_subsys,
292 				&dsi_pixel_clk_freq)) {
293 		return -EINVAL;
294 	}
295 
296 	switch (config->dpi_config.pixelPacket) {
297 	case kDSI_PixelPacket16Bit:
298 		bit_width = 16;
299 		break;
300 	case kDSI_PixelPacket18Bit:
301 		__fallthrough;
302 	case kDSI_PixelPacket18BitLoosely:
303 		bit_width = 18;
304 		break;
305 	case kDSI_PixelPacket24Bit:
306 		bit_width = 24;
307 		break;
308 	default:
309 		return -EINVAL; /* Invalid bit width enum value? */
310 	}
311 	/* Init DPHY.
312 	 *
313 	 * The DPHY bit clock must be fast enough to send out the pixels, it should be
314 	 * larger than:
315 	 *
316 	 *         (Pixel clock * bit per output pixel) / number of MIPI data lane
317 	 */
318 	if (((dsi_pixel_clk_freq * bit_width) / mdev->data_lanes) > dphy_bit_clk_freq) {
319 		return -EINVAL;
320 	}
321 
322 	DSI_GetDphyDefaultConfig(&dphy_config, dphy_bit_clk_freq, dphy_esc_clk_freq);
323 
324 	if (config->dphy_ref_freq != 0) {
325 		dphy_bit_clk_freq = DSI_InitDphy(config->base,
326 					&dphy_config, config->dphy_ref_freq);
327 	} else {
328 		/* DPHY PLL is not present, ref clock is unused */
329 		DSI_InitDphy(config->base, &dphy_config, 0);
330 	}
331 
332 	/*
333 	 * If nxp,lcdif node is present, then the MIPI DSI driver will
334 	 * accept input on the DPI port from the LCDIF, and convert the output
335 	 * to DSI data. This is useful for video mode, where the LCDIF can
336 	 * constantly refresh the MIPI panel.
337 	 */
338 	if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO) {
339 		/* Init DPI interface. */
340 		DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes,
341 						dsi_pixel_clk_freq, dphy_bit_clk_freq);
342 	}
343 
344 	imxrt_post_init_display_interface();
345 
346 	return 0;
347 }
348 
dsi_mcux_detach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)349 static int dsi_mcux_detach(const struct device *dev, uint8_t channel,
350 			   const struct mipi_dsi_device *mdev)
351 {
352 	const struct mcux_mipi_dsi_config *config = dev->config;
353 
354 	/* Enable DPHY auto power down */
355 	DSI_DeinitDphy(config->base);
356 	/* Fully power off DPHY */
357 	config->base->PD_DPHY = 0x1;
358 	/* Deinit MIPI */
359 	DSI_Deinit(config->base);
360 	/* Call IMX RT clock function to gate clocks and power at SOC level */
361 	imxrt_deinit_display_interface();
362 	return 0;
363 }
364 
365 
366 
dsi_mcux_transfer(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)367 static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
368 				 struct mipi_dsi_msg *msg)
369 {
370 	const struct mcux_mipi_dsi_config *config = dev->config;
371 	dsi_transfer_t dsi_xfer = {0};
372 	status_t status;
373 	int ret;
374 
375 	dsi_xfer.virtualChannel = channel;
376 	dsi_xfer.txDataSize = msg->tx_len;
377 	dsi_xfer.txData = msg->tx_buf;
378 	dsi_xfer.rxDataSize = msg->rx_len;
379 	dsi_xfer.rxData = msg->rx_buf;
380 	/* default to high speed unless told to use low power */
381 	dsi_xfer.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed;
382 
383 	switch (msg->type) {
384 	case MIPI_DSI_DCS_READ:
385 		LOG_ERR("DCS Read not yet implemented or used");
386 		return -ENOTSUP;
387 	case MIPI_DSI_DCS_SHORT_WRITE:
388 		dsi_xfer.sendDscCmd = true;
389 		dsi_xfer.dscCmd = msg->cmd;
390 		dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam;
391 		break;
392 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
393 		dsi_xfer.sendDscCmd = true;
394 		dsi_xfer.dscCmd = msg->cmd;
395 		dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam;
396 		break;
397 	case MIPI_DSI_DCS_LONG_WRITE:
398 		dsi_xfer.sendDscCmd = true;
399 		dsi_xfer.dscCmd = msg->cmd;
400 		dsi_xfer.txDataType = kDSI_TxDataDcsLongWr;
401 		if (msg->flags & MCUX_DSI_2L_FB_DATA) {
402 			/*
403 			 * Special case- transfer framebuffer data using
404 			 * SMARTDMA or non blocking DSI API. The framebuffer
405 			 * will also be color swapped, if enabled.
406 			 */
407 			ret = dsi_mcux_tx_color(dev, channel, msg);
408 			if (ret < 0) {
409 				LOG_ERR("Transmission failed");
410 				return -EIO;
411 			}
412 			return ret;
413 		}
414 		break;
415 	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
416 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam;
417 		break;
418 	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
419 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrOneParam;
420 		break;
421 	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
422 		dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam;
423 		break;
424 	case MIPI_DSI_GENERIC_LONG_WRITE:
425 		dsi_xfer.txDataType = kDSI_TxDataGenLongWr;
426 		break;
427 	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
428 		__fallthrough;
429 	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
430 		__fallthrough;
431 	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
432 		LOG_ERR("Generic Read not yet implemented or used");
433 		return -ENOTSUP;
434 	default:
435 		LOG_ERR("Unsupported message type (%d)", msg->type);
436 		return -ENOTSUP;
437 	}
438 
439 	status = DSI_TransferBlocking(config->base, &dsi_xfer);
440 	if (status != kStatus_Success) {
441 		LOG_ERR("Transmission failed");
442 		return -EIO;
443 	}
444 
445 	if (msg->rx_len != 0) {
446 		/* Return rx_len on a read */
447 		return msg->rx_len;
448 	}
449 
450 	/* Return tx_len on a write */
451 	return msg->tx_len;
452 
453 }
454 
455 static struct mipi_dsi_driver_api dsi_mcux_api = {
456 	.attach = dsi_mcux_attach,
457 	.detach = dsi_mcux_detach,
458 	.transfer = dsi_mcux_transfer,
459 };
460 
mcux_mipi_dsi_init(const struct device * dev)461 static int mcux_mipi_dsi_init(const struct device *dev)
462 {
463 	const struct mcux_mipi_dsi_config *config = dev->config;
464 	struct mcux_mipi_dsi_data *data = dev->data;
465 
466 #ifndef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA
467 	/* Enable IRQ */
468 	config->irq_config_func(dev);
469 #endif
470 
471 	k_sem_init(&data->transfer_sem, 0, 1);
472 
473 	if (!device_is_ready(config->bit_clk_dev) ||
474 			!device_is_ready(config->esc_clk_dev) ||
475 			!device_is_ready(config->pixel_clk_dev)) {
476 		return -ENODEV;
477 	}
478 	return 0;
479 }
480 
481 #define MCUX_DSI_DPI_CONFIG(id)									\
482 	IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(id), nxp_lcdif),				\
483 	(.dpi_config = {									\
484 		.dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding),			\
485 		.pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet),				\
486 		.videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode),				\
487 		.bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode),				\
488 		.pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width),		\
489 		.panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height),			\
490 		.polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),		\
491 					display_timings),  vsync_active) ?			\
492 					kDSI_DpiVsyncActiveHigh :				\
493 					kDSI_DpiVsyncActiveLow) |				\
494 				(DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),		\
495 					display_timings),  hsync_active) ?			\
496 					kDSI_DpiHsyncActiveHigh :				\
497 					kDSI_DpiHsyncActiveLow),				\
498 		.hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
499 					display_timings),  hfront_porch),			\
500 		.hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
501 					display_timings),  hback_porch),			\
502 		.hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
503 					display_timings),  hsync_len),				\
504 		.vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
505 					display_timings),  vfront_porch),			\
506 		.vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif),				\
507 					display_timings),  vback_porch),			\
508 	},))
509 
510 #define MCUX_MIPI_DSI_DEVICE(id)								\
511 	COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA,						\
512 	(), (static void mipi_dsi_##n##_irq_config_func(const struct device *dev)		\
513 	{											\
514 		IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority),			\
515 			mipi_dsi_isr, DEVICE_DT_INST_GET(id), 0);				\
516 			irq_enable(DT_INST_IRQN(id));						\
517 	}))											\
518 												\
519 	static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = {			\
520 		MCUX_DSI_DPI_CONFIG(id)								\
521 		COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA,					\
522 		(.smart_dma = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, smartdma)),),		\
523 		(.irq_config_func = mipi_dsi_##n##_irq_config_func,))				\
524 		.base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id),				\
525 		.auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp),				\
526 		.noncontinuous_hs_clk = DT_INST_PROP(id, noncontinuous_hs_clk),			\
527 		.dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0),			\
528 		.bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)),		\
529 		.bit_clk_subsys =								\
530 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, dphy, name),	\
531 		.esc_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, esc)),		\
532 		.esc_clk_subsys =								\
533 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, esc, name),	\
534 		.pixel_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, pixel)),		\
535 		.pixel_clk_subsys =								\
536 			(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, pixel, name),	\
537 	};											\
538 												\
539 	static struct mcux_mipi_dsi_data mipi_dsi_data_##id;					\
540 	DEVICE_DT_INST_DEFINE(id,								\
541 			    &mcux_mipi_dsi_init,						\
542 			    NULL,								\
543 			    &mipi_dsi_data_##id,						\
544 			    &mipi_dsi_config_##id,						\
545 			    POST_KERNEL,							\
546 			    CONFIG_MIPI_DSI_INIT_PRIORITY,					\
547 			    &dsi_mcux_api);
548 
549 DT_INST_FOREACH_STATUS_OKAY(MCUX_MIPI_DSI_DEVICE)
550