xref: /openbmc/linux/drivers/gpu/drm/omapdrm/dss/dpi.c (revision e82c878d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2009 Nokia Corporation
4  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
5  *
6  * Some code and ideas taken from drivers/video/omap/ driver
7  * by Imre Deak.
8  */
9 
10 #define DSS_SUBSYS_NAME "DPI"
11 
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/err.h>
15 #include <linux/errno.h>
16 #include <linux/export.h>
17 #include <linux/kernel.h>
18 #include <linux/of.h>
19 #include <linux/platform_device.h>
20 #include <linux/regulator/consumer.h>
21 #include <linux/string.h>
22 #include <linux/sys_soc.h>
23 
24 #include <drm/drm_bridge.h>
25 
26 #include "dss.h"
27 #include "omapdss.h"
28 
29 struct dpi_data {
30 	struct platform_device *pdev;
31 	enum dss_model dss_model;
32 	struct dss_device *dss;
33 	unsigned int id;
34 
35 	struct regulator *vdds_dsi_reg;
36 	enum dss_clk_source clk_src;
37 	struct dss_pll *pll;
38 
39 	struct dss_lcd_mgr_config mgr_config;
40 	unsigned long pixelclock;
41 	int data_lines;
42 
43 	struct omap_dss_device output;
44 	struct drm_bridge bridge;
45 };
46 
47 #define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
48 
49 /* -----------------------------------------------------------------------------
50  * Clock Handling and PLL
51  */
52 
53 static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,
54 						  enum omap_channel channel)
55 {
56 	/*
57 	 * Possible clock sources:
58 	 * LCD1: FCK/PLL1_1/HDMI_PLL
59 	 * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)
60 	 * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)
61 	 */
62 
63 	switch (channel) {
64 	case OMAP_DSS_CHANNEL_LCD:
65 	{
66 		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))
67 			return DSS_CLK_SRC_PLL1_1;
68 		break;
69 	}
70 	case OMAP_DSS_CHANNEL_LCD2:
71 	{
72 		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
73 			return DSS_CLK_SRC_PLL1_3;
74 		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))
75 			return DSS_CLK_SRC_PLL2_3;
76 		break;
77 	}
78 	case OMAP_DSS_CHANNEL_LCD3:
79 	{
80 		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))
81 			return DSS_CLK_SRC_PLL2_1;
82 		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
83 			return DSS_CLK_SRC_PLL1_3;
84 		break;
85 	}
86 	default:
87 		break;
88 	}
89 
90 	return DSS_CLK_SRC_FCK;
91 }
92 
93 static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)
94 {
95 	enum omap_channel channel = dpi->output.dispc_channel;
96 
97 	/*
98 	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
99 	 * would also be used for DISPC fclk. Meaning, when the DPI output is
100 	 * disabled, DISPC clock will be disabled, and TV out will stop.
101 	 */
102 	switch (dpi->dss_model) {
103 	case DSS_MODEL_OMAP2:
104 	case DSS_MODEL_OMAP3:
105 		return DSS_CLK_SRC_FCK;
106 
107 	case DSS_MODEL_OMAP4:
108 		switch (channel) {
109 		case OMAP_DSS_CHANNEL_LCD:
110 			return DSS_CLK_SRC_PLL1_1;
111 		case OMAP_DSS_CHANNEL_LCD2:
112 			return DSS_CLK_SRC_PLL2_1;
113 		default:
114 			return DSS_CLK_SRC_FCK;
115 		}
116 
117 	case DSS_MODEL_OMAP5:
118 		switch (channel) {
119 		case OMAP_DSS_CHANNEL_LCD:
120 			return DSS_CLK_SRC_PLL1_1;
121 		case OMAP_DSS_CHANNEL_LCD3:
122 			return DSS_CLK_SRC_PLL2_1;
123 		case OMAP_DSS_CHANNEL_LCD2:
124 		default:
125 			return DSS_CLK_SRC_FCK;
126 		}
127 
128 	case DSS_MODEL_DRA7:
129 		return dpi_get_clk_src_dra7xx(dpi, channel);
130 
131 	default:
132 		return DSS_CLK_SRC_FCK;
133 	}
134 }
135 
136 struct dpi_clk_calc_ctx {
137 	struct dpi_data *dpi;
138 	unsigned int clkout_idx;
139 
140 	/* inputs */
141 
142 	unsigned long pck_min, pck_max;
143 
144 	/* outputs */
145 
146 	struct dss_pll_clock_info pll_cinfo;
147 	unsigned long fck;
148 	struct dispc_clock_info dispc_cinfo;
149 };
150 
151 static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
152 		unsigned long pck, void *data)
153 {
154 	struct dpi_clk_calc_ctx *ctx = data;
155 
156 	/*
157 	 * Odd dividers give us uneven duty cycle, causing problem when level
158 	 * shifted. So skip all odd dividers when the pixel clock is on the
159 	 * higher side.
160 	 */
161 	if (ctx->pck_min >= 100000000) {
162 		if (lckd > 1 && lckd % 2 != 0)
163 			return false;
164 
165 		if (pckd > 1 && pckd % 2 != 0)
166 			return false;
167 	}
168 
169 	ctx->dispc_cinfo.lck_div = lckd;
170 	ctx->dispc_cinfo.pck_div = pckd;
171 	ctx->dispc_cinfo.lck = lck;
172 	ctx->dispc_cinfo.pck = pck;
173 
174 	return true;
175 }
176 
177 
178 static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
179 		void *data)
180 {
181 	struct dpi_clk_calc_ctx *ctx = data;
182 
183 	ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;
184 	ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;
185 
186 	return dispc_div_calc(ctx->dpi->dss->dispc, dispc,
187 			      ctx->pck_min, ctx->pck_max,
188 			      dpi_calc_dispc_cb, ctx);
189 }
190 
191 
192 static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
193 		unsigned long clkdco,
194 		void *data)
195 {
196 	struct dpi_clk_calc_ctx *ctx = data;
197 
198 	ctx->pll_cinfo.n = n;
199 	ctx->pll_cinfo.m = m;
200 	ctx->pll_cinfo.fint = fint;
201 	ctx->pll_cinfo.clkdco = clkdco;
202 
203 	return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,
204 		ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),
205 		dpi_calc_hsdiv_cb, ctx);
206 }
207 
208 static bool dpi_calc_dss_cb(unsigned long fck, void *data)
209 {
210 	struct dpi_clk_calc_ctx *ctx = data;
211 
212 	ctx->fck = fck;
213 
214 	return dispc_div_calc(ctx->dpi->dss->dispc, fck,
215 			      ctx->pck_min, ctx->pck_max,
216 			      dpi_calc_dispc_cb, ctx);
217 }
218 
219 static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,
220 		struct dpi_clk_calc_ctx *ctx)
221 {
222 	unsigned long clkin;
223 
224 	memset(ctx, 0, sizeof(*ctx));
225 	ctx->dpi = dpi;
226 	ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
227 
228 	clkin = clk_get_rate(dpi->pll->clkin);
229 
230 	if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
231 		unsigned long pll_min, pll_max;
232 
233 		ctx->pck_min = pck - 1000;
234 		ctx->pck_max = pck + 1000;
235 
236 		pll_min = 0;
237 		pll_max = 0;
238 
239 		return dss_pll_calc_a(ctx->dpi->pll, clkin,
240 				pll_min, pll_max,
241 				dpi_calc_pll_cb, ctx);
242 	} else { /* DSS_PLL_TYPE_B */
243 		dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);
244 
245 		ctx->dispc_cinfo.lck_div = 1;
246 		ctx->dispc_cinfo.pck_div = 1;
247 		ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];
248 		ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
249 
250 		return true;
251 	}
252 }
253 
254 static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,
255 			     struct dpi_clk_calc_ctx *ctx)
256 {
257 	int i;
258 
259 	/*
260 	 * DSS fck gives us very few possibilities, so finding a good pixel
261 	 * clock may not be possible. We try multiple times to find the clock,
262 	 * each time widening the pixel clock range we look for, up to
263 	 * +/- ~15MHz.
264 	 */
265 
266 	for (i = 0; i < 25; ++i) {
267 		bool ok;
268 
269 		memset(ctx, 0, sizeof(*ctx));
270 		ctx->dpi = dpi;
271 		if (pck > 1000 * i * i * i)
272 			ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
273 		else
274 			ctx->pck_min = 0;
275 		ctx->pck_max = pck + 1000 * i * i * i;
276 
277 		ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,
278 				  dpi_calc_dss_cb, ctx);
279 		if (ok)
280 			return ok;
281 	}
282 
283 	return false;
284 }
285 
286 
287 
288 static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)
289 {
290 	struct dpi_clk_calc_ctx ctx;
291 	int r;
292 	bool ok;
293 
294 	ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);
295 	if (!ok)
296 		return -EINVAL;
297 
298 	r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);
299 	if (r)
300 		return r;
301 
302 	dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
303 				  dpi->clk_src);
304 
305 	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
306 
307 	return 0;
308 }
309 
310 static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)
311 {
312 	struct dpi_clk_calc_ctx ctx;
313 	int r;
314 	bool ok;
315 
316 	ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);
317 	if (!ok)
318 		return -EINVAL;
319 
320 	r = dss_set_fck_rate(dpi->dss, ctx.fck);
321 	if (r)
322 		return r;
323 
324 	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
325 
326 	return 0;
327 }
328 
329 static int dpi_set_mode(struct dpi_data *dpi)
330 {
331 	int r;
332 
333 	if (dpi->pll)
334 		r = dpi_set_pll_clk(dpi, dpi->pixelclock);
335 	else
336 		r = dpi_set_dispc_clk(dpi, dpi->pixelclock);
337 
338 	return r;
339 }
340 
341 static void dpi_config_lcd_manager(struct dpi_data *dpi)
342 {
343 	dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
344 
345 	dpi->mgr_config.stallmode = false;
346 	dpi->mgr_config.fifohandcheck = false;
347 
348 	dpi->mgr_config.video_port_width = dpi->data_lines;
349 
350 	dpi->mgr_config.lcden_sig_polarity = 0;
351 
352 	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
353 }
354 
355 static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
356 {
357 	int lck_div, pck_div;
358 	unsigned long fck;
359 	struct dpi_clk_calc_ctx ctx;
360 
361 	if (dpi->pll) {
362 		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
363 			return -EINVAL;
364 
365 		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
366 	} else {
367 		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
368 			return -EINVAL;
369 
370 		fck = ctx.fck;
371 	}
372 
373 	lck_div = ctx.dispc_cinfo.lck_div;
374 	pck_div = ctx.dispc_cinfo.pck_div;
375 
376 	*clock = fck / lck_div / pck_div;
377 
378 	return 0;
379 }
380 
381 static int dpi_verify_pll(struct dss_pll *pll)
382 {
383 	int r;
384 
385 	/* do initial setup with the PLL to see if it is operational */
386 
387 	r = dss_pll_enable(pll);
388 	if (r)
389 		return r;
390 
391 	dss_pll_disable(pll);
392 
393 	return 0;
394 }
395 
396 static void dpi_init_pll(struct dpi_data *dpi)
397 {
398 	struct dss_pll *pll;
399 
400 	if (dpi->pll)
401 		return;
402 
403 	dpi->clk_src = dpi_get_clk_src(dpi);
404 
405 	pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
406 	if (!pll)
407 		return;
408 
409 	if (dpi_verify_pll(pll)) {
410 		DSSWARN("PLL not operational\n");
411 		return;
412 	}
413 
414 	dpi->pll = pll;
415 }
416 
417 /* -----------------------------------------------------------------------------
418  * DRM Bridge Operations
419  */
420 
421 static int dpi_bridge_attach(struct drm_bridge *bridge,
422 			     enum drm_bridge_attach_flags flags)
423 {
424 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
425 
426 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
427 		return -EINVAL;
428 
429 	dpi_init_pll(dpi);
430 
431 	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
432 				 bridge, flags);
433 }
434 
435 static enum drm_mode_status
436 dpi_bridge_mode_valid(struct drm_bridge *bridge,
437 		       const struct drm_display_mode *mode)
438 {
439 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
440 	unsigned long clock = mode->clock * 1000;
441 	int ret;
442 
443 	if (mode->hdisplay % 8 != 0)
444 		return MODE_BAD_WIDTH;
445 
446 	if (mode->clock == 0)
447 		return MODE_NOCLOCK;
448 
449 	ret = dpi_clock_update(dpi, &clock);
450 	if (ret < 0)
451 		return MODE_CLOCK_RANGE;
452 
453 	return MODE_OK;
454 }
455 
456 static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
457 				   const struct drm_display_mode *mode,
458 				   struct drm_display_mode *adjusted_mode)
459 {
460 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
461 	unsigned long clock = mode->clock * 1000;
462 	int ret;
463 
464 	ret = dpi_clock_update(dpi, &clock);
465 	if (ret < 0)
466 		return false;
467 
468 	adjusted_mode->clock = clock / 1000;
469 
470 	return true;
471 }
472 
473 static void dpi_bridge_mode_set(struct drm_bridge *bridge,
474 				 const struct drm_display_mode *mode,
475 				 const struct drm_display_mode *adjusted_mode)
476 {
477 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
478 
479 	dpi->pixelclock = adjusted_mode->clock * 1000;
480 }
481 
482 static void dpi_bridge_enable(struct drm_bridge *bridge)
483 {
484 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
485 	int r;
486 
487 	if (dpi->vdds_dsi_reg) {
488 		r = regulator_enable(dpi->vdds_dsi_reg);
489 		if (r)
490 			return;
491 	}
492 
493 	r = dispc_runtime_get(dpi->dss->dispc);
494 	if (r)
495 		goto err_get_dispc;
496 
497 	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
498 	if (r)
499 		goto err_src_sel;
500 
501 	if (dpi->pll) {
502 		r = dss_pll_enable(dpi->pll);
503 		if (r)
504 			goto err_pll_init;
505 	}
506 
507 	r = dpi_set_mode(dpi);
508 	if (r)
509 		goto err_set_mode;
510 
511 	dpi_config_lcd_manager(dpi);
512 
513 	mdelay(2);
514 
515 	r = dss_mgr_enable(&dpi->output);
516 	if (r)
517 		goto err_mgr_enable;
518 
519 	return;
520 
521 err_mgr_enable:
522 err_set_mode:
523 	if (dpi->pll)
524 		dss_pll_disable(dpi->pll);
525 err_pll_init:
526 err_src_sel:
527 	dispc_runtime_put(dpi->dss->dispc);
528 err_get_dispc:
529 	if (dpi->vdds_dsi_reg)
530 		regulator_disable(dpi->vdds_dsi_reg);
531 }
532 
533 static void dpi_bridge_disable(struct drm_bridge *bridge)
534 {
535 	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
536 
537 	dss_mgr_disable(&dpi->output);
538 
539 	if (dpi->pll) {
540 		dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
541 					  DSS_CLK_SRC_FCK);
542 		dss_pll_disable(dpi->pll);
543 	}
544 
545 	dispc_runtime_put(dpi->dss->dispc);
546 
547 	if (dpi->vdds_dsi_reg)
548 		regulator_disable(dpi->vdds_dsi_reg);
549 }
550 
551 static const struct drm_bridge_funcs dpi_bridge_funcs = {
552 	.attach = dpi_bridge_attach,
553 	.mode_valid = dpi_bridge_mode_valid,
554 	.mode_fixup = dpi_bridge_mode_fixup,
555 	.mode_set = dpi_bridge_mode_set,
556 	.enable = dpi_bridge_enable,
557 	.disable = dpi_bridge_disable,
558 };
559 
560 static void dpi_bridge_init(struct dpi_data *dpi)
561 {
562 	dpi->bridge.funcs = &dpi_bridge_funcs;
563 	dpi->bridge.of_node = dpi->pdev->dev.of_node;
564 	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
565 
566 	drm_bridge_add(&dpi->bridge);
567 }
568 
569 static void dpi_bridge_cleanup(struct dpi_data *dpi)
570 {
571 	drm_bridge_remove(&dpi->bridge);
572 }
573 
574 /* -----------------------------------------------------------------------------
575  * Initialisation and Cleanup
576  */
577 
578 /*
579  * Return a hardcoded channel for the DPI output. This should work for
580  * current use cases, but this can be later expanded to either resolve
581  * the channel in some more dynamic manner, or get the channel as a user
582  * parameter.
583  */
584 static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
585 {
586 	switch (dpi->dss_model) {
587 	case DSS_MODEL_OMAP2:
588 	case DSS_MODEL_OMAP3:
589 		return OMAP_DSS_CHANNEL_LCD;
590 
591 	case DSS_MODEL_DRA7:
592 		switch (dpi->id) {
593 		case 2:
594 			return OMAP_DSS_CHANNEL_LCD3;
595 		case 1:
596 			return OMAP_DSS_CHANNEL_LCD2;
597 		case 0:
598 		default:
599 			return OMAP_DSS_CHANNEL_LCD;
600 		}
601 
602 	case DSS_MODEL_OMAP4:
603 		return OMAP_DSS_CHANNEL_LCD2;
604 
605 	case DSS_MODEL_OMAP5:
606 		return OMAP_DSS_CHANNEL_LCD3;
607 
608 	default:
609 		DSSWARN("unsupported DSS version\n");
610 		return OMAP_DSS_CHANNEL_LCD;
611 	}
612 }
613 
614 static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
615 {
616 	struct omap_dss_device *out = &dpi->output;
617 	u32 port_num = 0;
618 	int r;
619 
620 	dpi_bridge_init(dpi);
621 
622 	of_property_read_u32(port, "reg", &port_num);
623 	dpi->id = port_num <= 2 ? port_num : 0;
624 
625 	switch (port_num) {
626 	case 2:
627 		out->name = "dpi.2";
628 		break;
629 	case 1:
630 		out->name = "dpi.1";
631 		break;
632 	case 0:
633 	default:
634 		out->name = "dpi.0";
635 		break;
636 	}
637 
638 	out->dev = &dpi->pdev->dev;
639 	out->id = OMAP_DSS_OUTPUT_DPI;
640 	out->type = OMAP_DISPLAY_TYPE_DPI;
641 	out->dispc_channel = dpi_get_channel(dpi);
642 	out->of_port = port_num;
643 	out->owner = THIS_MODULE;
644 
645 	r = omapdss_device_init_output(out, &dpi->bridge);
646 	if (r < 0) {
647 		dpi_bridge_cleanup(dpi);
648 		return r;
649 	}
650 
651 	omapdss_device_register(out);
652 
653 	return 0;
654 }
655 
656 static void dpi_uninit_output_port(struct device_node *port)
657 {
658 	struct dpi_data *dpi = port->data;
659 	struct omap_dss_device *out = &dpi->output;
660 
661 	omapdss_device_unregister(out);
662 	omapdss_device_cleanup_output(out);
663 
664 	dpi_bridge_cleanup(dpi);
665 }
666 
667 /* -----------------------------------------------------------------------------
668  * Initialisation and Cleanup
669  */
670 
671 static const struct soc_device_attribute dpi_soc_devices[] = {
672 	{ .machine = "OMAP3[456]*" },
673 	{ .machine = "[AD]M37*" },
674 	{ /* sentinel */ }
675 };
676 
677 static int dpi_init_regulator(struct dpi_data *dpi)
678 {
679 	struct regulator *vdds_dsi;
680 
681 	/*
682 	 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
683 	 * DM37xx only.
684 	 */
685 	if (!soc_device_match(dpi_soc_devices))
686 		return 0;
687 
688 	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
689 	if (IS_ERR(vdds_dsi)) {
690 		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
691 			DSSERR("can't get VDDS_DSI regulator\n");
692 		return PTR_ERR(vdds_dsi);
693 	}
694 
695 	dpi->vdds_dsi_reg = vdds_dsi;
696 
697 	return 0;
698 }
699 
700 int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
701 		  struct device_node *port, enum dss_model dss_model)
702 {
703 	struct dpi_data *dpi;
704 	struct device_node *ep;
705 	u32 datalines;
706 	int r;
707 
708 	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
709 	if (!dpi)
710 		return -ENOMEM;
711 
712 	ep = of_get_next_child(port, NULL);
713 	if (!ep)
714 		return 0;
715 
716 	r = of_property_read_u32(ep, "data-lines", &datalines);
717 	of_node_put(ep);
718 	if (r) {
719 		DSSERR("failed to parse datalines\n");
720 		return r;
721 	}
722 
723 	dpi->data_lines = datalines;
724 
725 	dpi->pdev = pdev;
726 	dpi->dss_model = dss_model;
727 	dpi->dss = dss;
728 	port->data = dpi;
729 
730 	r = dpi_init_regulator(dpi);
731 	if (r)
732 		return r;
733 
734 	return dpi_init_output_port(dpi, port);
735 }
736 
737 void dpi_uninit_port(struct device_node *port)
738 {
739 	struct dpi_data *dpi = port->data;
740 
741 	if (!dpi)
742 		return;
743 
744 	dpi_uninit_output_port(port);
745 }
746