xref: /openbmc/linux/drivers/gpu/drm/omapdrm/dss/hdmi4.c (revision f2f4bf5a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
4  *
5  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
6  * Authors: Yong Zhi
7  *	Mythri pk <mythripk@ti.com>
8  */
9 
10 #define DSS_SUBSYS_NAME "HDMI"
11 
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
16 #include <linux/interrupt.h>
17 #include <linux/mutex.h>
18 #include <linux/delay.h>
19 #include <linux/string.h>
20 #include <linux/platform_device.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/clk.h>
23 #include <linux/gpio.h>
24 #include <linux/regulator/consumer.h>
25 #include <linux/component.h>
26 #include <linux/of.h>
27 #include <linux/of_graph.h>
28 #include <sound/omap-hdmi-audio.h>
29 #include <media/cec.h>
30 
31 #include "omapdss.h"
32 #include "hdmi4_core.h"
33 #include "hdmi4_cec.h"
34 #include "dss.h"
35 #include "hdmi.h"
36 
37 static int hdmi_runtime_get(struct omap_hdmi *hdmi)
38 {
39 	int r;
40 
41 	DSSDBG("hdmi_runtime_get\n");
42 
43 	r = pm_runtime_get_sync(&hdmi->pdev->dev);
44 	WARN_ON(r < 0);
45 	if (r < 0)
46 		return r;
47 
48 	return 0;
49 }
50 
51 static void hdmi_runtime_put(struct omap_hdmi *hdmi)
52 {
53 	int r;
54 
55 	DSSDBG("hdmi_runtime_put\n");
56 
57 	r = pm_runtime_put_sync(&hdmi->pdev->dev);
58 	WARN_ON(r < 0 && r != -ENOSYS);
59 }
60 
61 static irqreturn_t hdmi_irq_handler(int irq, void *data)
62 {
63 	struct omap_hdmi *hdmi = data;
64 	struct hdmi_wp_data *wp = &hdmi->wp;
65 	u32 irqstatus;
66 
67 	irqstatus = hdmi_wp_get_irqstatus(wp);
68 	hdmi_wp_set_irqstatus(wp, irqstatus);
69 
70 	if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
71 			irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
72 		/*
73 		 * If we get both connect and disconnect interrupts at the same
74 		 * time, turn off the PHY, clear interrupts, and restart, which
75 		 * raises connect interrupt if a cable is connected, or nothing
76 		 * if cable is not connected.
77 		 */
78 		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
79 
80 		hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
81 				HDMI_IRQ_LINK_DISCONNECT);
82 
83 		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
84 	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
85 		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
86 	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
87 		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
88 	}
89 	if (irqstatus & HDMI_IRQ_CORE) {
90 		u32 intr4 = hdmi_read_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4);
91 
92 		hdmi_write_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4, intr4);
93 		if (intr4 & 8)
94 			hdmi4_cec_irq(&hdmi->core);
95 	}
96 
97 	return IRQ_HANDLED;
98 }
99 
100 static int hdmi_power_on_core(struct omap_hdmi *hdmi)
101 {
102 	int r;
103 
104 	if (hdmi->core.core_pwr_cnt++)
105 		return 0;
106 
107 	r = regulator_enable(hdmi->vdda_reg);
108 	if (r)
109 		goto err_reg_enable;
110 
111 	r = hdmi_runtime_get(hdmi);
112 	if (r)
113 		goto err_runtime_get;
114 
115 	hdmi4_core_powerdown_disable(&hdmi->core);
116 
117 	/* Make selection of HDMI in DSS */
118 	dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
119 
120 	hdmi->core_enabled = true;
121 
122 	return 0;
123 
124 err_runtime_get:
125 	regulator_disable(hdmi->vdda_reg);
126 err_reg_enable:
127 	hdmi->core.core_pwr_cnt--;
128 
129 	return r;
130 }
131 
132 static void hdmi_power_off_core(struct omap_hdmi *hdmi)
133 {
134 	if (--hdmi->core.core_pwr_cnt)
135 		return;
136 
137 	hdmi->core_enabled = false;
138 
139 	hdmi_runtime_put(hdmi);
140 	regulator_disable(hdmi->vdda_reg);
141 }
142 
143 static int hdmi_power_on_full(struct omap_hdmi *hdmi)
144 {
145 	int r;
146 	const struct videomode *vm;
147 	struct hdmi_wp_data *wp = &hdmi->wp;
148 	struct dss_pll_clock_info hdmi_cinfo = { 0 };
149 	unsigned int pc;
150 
151 	r = hdmi_power_on_core(hdmi);
152 	if (r)
153 		return r;
154 
155 	/* disable and clear irqs */
156 	hdmi_wp_clear_irqenable(wp, ~HDMI_IRQ_CORE);
157 	hdmi_wp_set_irqstatus(wp, ~HDMI_IRQ_CORE);
158 
159 	vm = &hdmi->cfg.vm;
160 
161 	DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
162 	       vm->vactive);
163 
164 	pc = vm->pixelclock;
165 	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
166 		pc *= 2;
167 
168 	/* DSS_HDMI_TCLK is bitclk / 10 */
169 	pc *= 10;
170 
171 	dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
172 		pc, &hdmi_cinfo);
173 
174 	r = dss_pll_enable(&hdmi->pll.pll);
175 	if (r) {
176 		DSSERR("Failed to enable PLL\n");
177 		goto err_pll_enable;
178 	}
179 
180 	r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
181 	if (r) {
182 		DSSERR("Failed to configure PLL\n");
183 		goto err_pll_cfg;
184 	}
185 
186 	r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
187 		hdmi_cinfo.clkout[0]);
188 	if (r) {
189 		DSSDBG("Failed to configure PHY\n");
190 		goto err_phy_cfg;
191 	}
192 
193 	r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
194 	if (r)
195 		goto err_phy_pwr;
196 
197 	hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
198 
199 	r = dss_mgr_enable(&hdmi->output);
200 	if (r)
201 		goto err_mgr_enable;
202 
203 	r = hdmi_wp_video_start(&hdmi->wp);
204 	if (r)
205 		goto err_vid_enable;
206 
207 	hdmi_wp_set_irqenable(wp,
208 		HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
209 
210 	return 0;
211 
212 err_vid_enable:
213 	dss_mgr_disable(&hdmi->output);
214 err_mgr_enable:
215 	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
216 err_phy_pwr:
217 err_phy_cfg:
218 err_pll_cfg:
219 	dss_pll_disable(&hdmi->pll.pll);
220 err_pll_enable:
221 	hdmi_power_off_core(hdmi);
222 	return -EIO;
223 }
224 
225 static void hdmi_power_off_full(struct omap_hdmi *hdmi)
226 {
227 	hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE);
228 
229 	hdmi_wp_video_stop(&hdmi->wp);
230 
231 	dss_mgr_disable(&hdmi->output);
232 
233 	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
234 
235 	dss_pll_disable(&hdmi->pll.pll);
236 
237 	hdmi_power_off_core(hdmi);
238 }
239 
240 static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
241 				     const struct drm_display_mode *mode)
242 {
243 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
244 
245 	mutex_lock(&hdmi->lock);
246 
247 	drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);
248 
249 	dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);
250 
251 	mutex_unlock(&hdmi->lock);
252 }
253 
254 static int hdmi_dump_regs(struct seq_file *s, void *p)
255 {
256 	struct omap_hdmi *hdmi = s->private;
257 
258 	mutex_lock(&hdmi->lock);
259 
260 	if (hdmi_runtime_get(hdmi)) {
261 		mutex_unlock(&hdmi->lock);
262 		return 0;
263 	}
264 
265 	hdmi_wp_dump(&hdmi->wp, s);
266 	hdmi_pll_dump(&hdmi->pll, s);
267 	hdmi_phy_dump(&hdmi->phy, s);
268 	hdmi4_core_dump(&hdmi->core, s);
269 
270 	hdmi_runtime_put(hdmi);
271 	mutex_unlock(&hdmi->lock);
272 	return 0;
273 }
274 
275 static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
276 {
277 	int r;
278 
279 	mutex_lock(&hdmi->lock);
280 
281 	r = hdmi_runtime_get(hdmi);
282 	BUG_ON(r);
283 
284 	r = hdmi4_read_edid(&hdmi->core,  buf, len);
285 
286 	hdmi_runtime_put(hdmi);
287 	mutex_unlock(&hdmi->lock);
288 
289 	return r;
290 }
291 
292 static void hdmi_start_audio_stream(struct omap_hdmi *hd)
293 {
294 	hdmi_wp_audio_enable(&hd->wp, true);
295 	hdmi4_audio_start(&hd->core, &hd->wp);
296 }
297 
298 static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
299 {
300 	hdmi4_audio_stop(&hd->core, &hd->wp);
301 	hdmi_wp_audio_enable(&hd->wp, false);
302 }
303 
304 static void hdmi_display_enable(struct omap_dss_device *dssdev)
305 {
306 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
307 	unsigned long flags;
308 	int r;
309 
310 	DSSDBG("ENTER hdmi_display_enable\n");
311 
312 	mutex_lock(&hdmi->lock);
313 
314 	r = hdmi_power_on_full(hdmi);
315 	if (r) {
316 		DSSERR("failed to power on device\n");
317 		goto done;
318 	}
319 
320 	if (hdmi->audio_configured) {
321 		r = hdmi4_audio_config(&hdmi->core, &hdmi->wp,
322 				       &hdmi->audio_config,
323 				       hdmi->cfg.vm.pixelclock);
324 		if (r) {
325 			DSSERR("Error restoring audio configuration: %d", r);
326 			hdmi->audio_abort_cb(&hdmi->pdev->dev);
327 			hdmi->audio_configured = false;
328 		}
329 	}
330 
331 	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
332 	if (hdmi->audio_configured && hdmi->audio_playing)
333 		hdmi_start_audio_stream(hdmi);
334 	hdmi->display_enabled = true;
335 	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
336 
337 done:
338 	mutex_unlock(&hdmi->lock);
339 }
340 
341 static void hdmi_display_disable(struct omap_dss_device *dssdev)
342 {
343 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
344 	unsigned long flags;
345 
346 	DSSDBG("Enter hdmi_display_disable\n");
347 
348 	mutex_lock(&hdmi->lock);
349 
350 	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
351 	hdmi_stop_audio_stream(hdmi);
352 	hdmi->display_enabled = false;
353 	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
354 
355 	hdmi_power_off_full(hdmi);
356 
357 	mutex_unlock(&hdmi->lock);
358 }
359 
360 int hdmi4_core_enable(struct hdmi_core_data *core)
361 {
362 	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
363 	int r = 0;
364 
365 	DSSDBG("ENTER omapdss_hdmi4_core_enable\n");
366 
367 	mutex_lock(&hdmi->lock);
368 
369 	r = hdmi_power_on_core(hdmi);
370 	if (r) {
371 		DSSERR("failed to power on device\n");
372 		goto err0;
373 	}
374 
375 	mutex_unlock(&hdmi->lock);
376 	return 0;
377 
378 err0:
379 	mutex_unlock(&hdmi->lock);
380 	return r;
381 }
382 
383 void hdmi4_core_disable(struct hdmi_core_data *core)
384 {
385 	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
386 
387 	DSSDBG("Enter omapdss_hdmi4_core_disable\n");
388 
389 	mutex_lock(&hdmi->lock);
390 
391 	hdmi_power_off_core(hdmi);
392 
393 	mutex_unlock(&hdmi->lock);
394 }
395 
396 static int hdmi_connect(struct omap_dss_device *src,
397 			struct omap_dss_device *dst)
398 {
399 	return omapdss_device_connect(dst->dss, dst, dst->next);
400 }
401 
402 static void hdmi_disconnect(struct omap_dss_device *src,
403 			    struct omap_dss_device *dst)
404 {
405 	omapdss_device_disconnect(dst, dst->next);
406 }
407 
408 static int hdmi_read_edid(struct omap_dss_device *dssdev,
409 		u8 *edid, int len)
410 {
411 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
412 	bool need_enable;
413 	int r;
414 
415 	need_enable = hdmi->core_enabled == false;
416 
417 	if (need_enable) {
418 		r = hdmi4_core_enable(&hdmi->core);
419 		if (r)
420 			return r;
421 	}
422 
423 	r = read_edid(hdmi, edid, len);
424 	if (r >= 256)
425 		hdmi4_cec_set_phys_addr(&hdmi->core,
426 					cec_get_edid_phys_addr(edid, r, NULL));
427 	else
428 		hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
429 	if (need_enable)
430 		hdmi4_core_disable(&hdmi->core);
431 
432 	return r;
433 }
434 
435 static void hdmi_lost_hotplug(struct omap_dss_device *dssdev)
436 {
437 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
438 
439 	hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
440 }
441 
442 static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
443 		const struct hdmi_avi_infoframe *avi)
444 {
445 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
446 
447 	hdmi->cfg.infoframe = *avi;
448 	return 0;
449 }
450 
451 static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
452 		bool hdmi_mode)
453 {
454 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
455 
456 	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
457 	return 0;
458 }
459 
460 static const struct omap_dss_device_ops hdmi_ops = {
461 	.connect		= hdmi_connect,
462 	.disconnect		= hdmi_disconnect,
463 
464 	.enable			= hdmi_display_enable,
465 	.disable		= hdmi_display_disable,
466 
467 	.set_timings		= hdmi_display_set_timings,
468 
469 	.read_edid		= hdmi_read_edid,
470 
471 	.hdmi = {
472 		.lost_hotplug		= hdmi_lost_hotplug,
473 		.set_infoframe		= hdmi_set_infoframe,
474 		.set_hdmi_mode		= hdmi_set_hdmi_mode,
475 	},
476 };
477 
478 /* -----------------------------------------------------------------------------
479  * Audio Callbacks
480  */
481 
482 static int hdmi_audio_startup(struct device *dev,
483 			      void (*abort_cb)(struct device *dev))
484 {
485 	struct omap_hdmi *hd = dev_get_drvdata(dev);
486 
487 	mutex_lock(&hd->lock);
488 
489 	WARN_ON(hd->audio_abort_cb != NULL);
490 
491 	hd->audio_abort_cb = abort_cb;
492 
493 	mutex_unlock(&hd->lock);
494 
495 	return 0;
496 }
497 
498 static int hdmi_audio_shutdown(struct device *dev)
499 {
500 	struct omap_hdmi *hd = dev_get_drvdata(dev);
501 
502 	mutex_lock(&hd->lock);
503 	hd->audio_abort_cb = NULL;
504 	hd->audio_configured = false;
505 	hd->audio_playing = false;
506 	mutex_unlock(&hd->lock);
507 
508 	return 0;
509 }
510 
511 static int hdmi_audio_start(struct device *dev)
512 {
513 	struct omap_hdmi *hd = dev_get_drvdata(dev);
514 	unsigned long flags;
515 
516 	spin_lock_irqsave(&hd->audio_playing_lock, flags);
517 
518 	if (hd->display_enabled) {
519 		if (!hdmi_mode_has_audio(&hd->cfg))
520 			DSSERR("%s: Video mode does not support audio\n",
521 			       __func__);
522 		hdmi_start_audio_stream(hd);
523 	}
524 	hd->audio_playing = true;
525 
526 	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
527 	return 0;
528 }
529 
530 static void hdmi_audio_stop(struct device *dev)
531 {
532 	struct omap_hdmi *hd = dev_get_drvdata(dev);
533 	unsigned long flags;
534 
535 	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
536 
537 	spin_lock_irqsave(&hd->audio_playing_lock, flags);
538 
539 	if (hd->display_enabled)
540 		hdmi_stop_audio_stream(hd);
541 	hd->audio_playing = false;
542 
543 	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
544 }
545 
546 static int hdmi_audio_config(struct device *dev,
547 			     struct omap_dss_audio *dss_audio)
548 {
549 	struct omap_hdmi *hd = dev_get_drvdata(dev);
550 	int ret = 0;
551 
552 	mutex_lock(&hd->lock);
553 
554 	if (hd->display_enabled) {
555 		ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
556 					 hd->cfg.vm.pixelclock);
557 		if (ret)
558 			goto out;
559 	}
560 
561 	hd->audio_configured = true;
562 	hd->audio_config = *dss_audio;
563 out:
564 	mutex_unlock(&hd->lock);
565 
566 	return ret;
567 }
568 
569 static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
570 	.audio_startup = hdmi_audio_startup,
571 	.audio_shutdown = hdmi_audio_shutdown,
572 	.audio_start = hdmi_audio_start,
573 	.audio_stop = hdmi_audio_stop,
574 	.audio_config = hdmi_audio_config,
575 };
576 
577 static int hdmi_audio_register(struct omap_hdmi *hdmi)
578 {
579 	struct omap_hdmi_audio_pdata pdata = {
580 		.dev = &hdmi->pdev->dev,
581 		.version = 4,
582 		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
583 		.ops = &hdmi_audio_ops,
584 	};
585 
586 	hdmi->audio_pdev = platform_device_register_data(
587 		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
588 		&pdata, sizeof(pdata));
589 
590 	if (IS_ERR(hdmi->audio_pdev))
591 		return PTR_ERR(hdmi->audio_pdev);
592 
593 	return 0;
594 }
595 
596 /* -----------------------------------------------------------------------------
597  * Component Bind & Unbind
598  */
599 
600 static int hdmi4_bind(struct device *dev, struct device *master, void *data)
601 {
602 	struct dss_device *dss = dss_get_device(master);
603 	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
604 	int r;
605 
606 	hdmi->dss = dss;
607 
608 	r = hdmi_runtime_get(hdmi);
609 	if (r)
610 		return r;
611 
612 	r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
613 	if (r)
614 		goto err_runtime_put;
615 
616 	r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
617 	if (r)
618 		goto err_pll_uninit;
619 
620 	r = hdmi_audio_register(hdmi);
621 	if (r) {
622 		DSSERR("Registering HDMI audio failed\n");
623 		goto err_cec_uninit;
624 	}
625 
626 	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
627 					       hdmi);
628 
629 	hdmi_runtime_put(hdmi);
630 
631 	return 0;
632 
633 err_cec_uninit:
634 	hdmi4_cec_uninit(&hdmi->core);
635 err_pll_uninit:
636 	hdmi_pll_uninit(&hdmi->pll);
637 err_runtime_put:
638 	hdmi_runtime_put(hdmi);
639 	return r;
640 }
641 
642 static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
643 {
644 	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
645 
646 	dss_debugfs_remove_file(hdmi->debugfs);
647 
648 	if (hdmi->audio_pdev)
649 		platform_device_unregister(hdmi->audio_pdev);
650 
651 	hdmi4_cec_uninit(&hdmi->core);
652 	hdmi_pll_uninit(&hdmi->pll);
653 }
654 
655 static const struct component_ops hdmi4_component_ops = {
656 	.bind	= hdmi4_bind,
657 	.unbind	= hdmi4_unbind,
658 };
659 
660 /* -----------------------------------------------------------------------------
661  * Probe & Remove, Suspend & Resume
662  */
663 
664 static int hdmi4_init_output(struct omap_hdmi *hdmi)
665 {
666 	struct omap_dss_device *out = &hdmi->output;
667 	int r;
668 
669 	out->dev = &hdmi->pdev->dev;
670 	out->id = OMAP_DSS_OUTPUT_HDMI;
671 	out->type = OMAP_DISPLAY_TYPE_HDMI;
672 	out->name = "hdmi.0";
673 	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
674 	out->ops = &hdmi_ops;
675 	out->owner = THIS_MODULE;
676 	out->of_ports = BIT(0);
677 	out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
678 
679 	r = omapdss_device_init_output(out);
680 	if (r < 0)
681 		return r;
682 
683 	omapdss_device_register(out);
684 
685 	return 0;
686 }
687 
688 static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
689 {
690 	struct omap_dss_device *out = &hdmi->output;
691 
692 	omapdss_device_unregister(out);
693 	omapdss_device_cleanup_output(out);
694 }
695 
696 static int hdmi4_probe_of(struct omap_hdmi *hdmi)
697 {
698 	struct platform_device *pdev = hdmi->pdev;
699 	struct device_node *node = pdev->dev.of_node;
700 	struct device_node *ep;
701 	int r;
702 
703 	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
704 	if (!ep)
705 		return 0;
706 
707 	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
708 	of_node_put(ep);
709 	return r;
710 }
711 
712 static int hdmi4_probe(struct platform_device *pdev)
713 {
714 	struct omap_hdmi *hdmi;
715 	int irq;
716 	int r;
717 
718 	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
719 	if (!hdmi)
720 		return -ENOMEM;
721 
722 	hdmi->pdev = pdev;
723 
724 	dev_set_drvdata(&pdev->dev, hdmi);
725 
726 	mutex_init(&hdmi->lock);
727 	spin_lock_init(&hdmi->audio_playing_lock);
728 
729 	r = hdmi4_probe_of(hdmi);
730 	if (r)
731 		goto err_free;
732 
733 	r = hdmi_wp_init(pdev, &hdmi->wp, 4);
734 	if (r)
735 		goto err_free;
736 
737 	r = hdmi_phy_init(pdev, &hdmi->phy, 4);
738 	if (r)
739 		goto err_free;
740 
741 	r = hdmi4_core_init(pdev, &hdmi->core);
742 	if (r)
743 		goto err_free;
744 
745 	irq = platform_get_irq(pdev, 0);
746 	if (irq < 0) {
747 		DSSERR("platform_get_irq failed\n");
748 		r = -ENODEV;
749 		goto err_free;
750 	}
751 
752 	r = devm_request_threaded_irq(&pdev->dev, irq,
753 			NULL, hdmi_irq_handler,
754 			IRQF_ONESHOT, "OMAP HDMI", hdmi);
755 	if (r) {
756 		DSSERR("HDMI IRQ request failed\n");
757 		goto err_free;
758 	}
759 
760 	hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
761 	if (IS_ERR(hdmi->vdda_reg)) {
762 		r = PTR_ERR(hdmi->vdda_reg);
763 		if (r != -EPROBE_DEFER)
764 			DSSERR("can't get VDDA regulator\n");
765 		goto err_free;
766 	}
767 
768 	pm_runtime_enable(&pdev->dev);
769 
770 	r = hdmi4_init_output(hdmi);
771 	if (r)
772 		goto err_pm_disable;
773 
774 	r = component_add(&pdev->dev, &hdmi4_component_ops);
775 	if (r)
776 		goto err_uninit_output;
777 
778 	return 0;
779 
780 err_uninit_output:
781 	hdmi4_uninit_output(hdmi);
782 err_pm_disable:
783 	pm_runtime_disable(&pdev->dev);
784 err_free:
785 	kfree(hdmi);
786 	return r;
787 }
788 
789 static int hdmi4_remove(struct platform_device *pdev)
790 {
791 	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
792 
793 	component_del(&pdev->dev, &hdmi4_component_ops);
794 
795 	hdmi4_uninit_output(hdmi);
796 
797 	pm_runtime_disable(&pdev->dev);
798 
799 	kfree(hdmi);
800 	return 0;
801 }
802 
803 static const struct of_device_id hdmi_of_match[] = {
804 	{ .compatible = "ti,omap4-hdmi", },
805 	{},
806 };
807 
808 struct platform_driver omapdss_hdmi4hw_driver = {
809 	.probe		= hdmi4_probe,
810 	.remove		= hdmi4_remove,
811 	.driver         = {
812 		.name   = "omapdss_hdmi",
813 		.of_match_table = hdmi_of_match,
814 		.suppress_bind_attrs = true,
815 	},
816 };
817