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