]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/video/fbdev/omap2/dss/hdmi4.c
OMAPDSS: hdmi: Make hdmi structure public
[mirror_ubuntu-jammy-kernel.git] / drivers / video / fbdev / omap2 / dss / hdmi4.c
CommitLineData
c3198a5e 1/*
ef26958a 2 * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
c3198a5e
M
3 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
4 * Authors: Yong Zhi
5 * Mythri pk <mythripk@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "HDMI"
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/interrupt.h>
27#include <linux/mutex.h>
28#include <linux/delay.h>
29#include <linux/string.h>
24e6289c 30#include <linux/platform_device.h>
4fbafaf3
TV
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
cca35017 33#include <linux/gpio.h>
17486943 34#include <linux/regulator/consumer.h>
a0b38cc4 35#include <video/omapdss.h>
c3198a5e 36
ef26958a 37#include "hdmi4_core.h"
c3198a5e 38#include "dss.h"
ad44cc32 39#include "dss_features.h"
945514b5 40#include "hdmi.h"
c3198a5e 41
945514b5 42static struct omap_hdmi hdmi;
c3198a5e 43
4fbafaf3
TV
44static int hdmi_runtime_get(void)
45{
46 int r;
47
48 DSSDBG("hdmi_runtime_get\n");
49
50 r = pm_runtime_get_sync(&hdmi.pdev->dev);
51 WARN_ON(r < 0);
a247ce78 52 if (r < 0)
852f0838 53 return r;
a247ce78
AT
54
55 return 0;
4fbafaf3
TV
56}
57
58static void hdmi_runtime_put(void)
59{
60 int r;
61
62 DSSDBG("hdmi_runtime_put\n");
63
0eaf9f52 64 r = pm_runtime_put_sync(&hdmi.pdev->dev);
5be3aebd 65 WARN_ON(r < 0 && r != -ENOSYS);
4fbafaf3
TV
66}
67
dcf5f729
TV
68static irqreturn_t hdmi_irq_handler(int irq, void *data)
69{
70 struct hdmi_wp_data *wp = data;
71 u32 irqstatus;
72
73 irqstatus = hdmi_wp_get_irqstatus(wp);
74 hdmi_wp_set_irqstatus(wp, irqstatus);
75
76 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
77 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
78 /*
79 * If we get both connect and disconnect interrupts at the same
80 * time, turn off the PHY, clear interrupts, and restart, which
81 * raises connect interrupt if a cable is connected, or nothing
82 * if cable is not connected.
83 */
84 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
85
86 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
87 HDMI_IRQ_LINK_DISCONNECT);
88
89 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
90 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
91 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
92 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
93 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
94 }
95
96 return IRQ_HANDLED;
97}
98
e25001d8
TV
99static int hdmi_init_regulator(void)
100{
818a053c 101 int r;
e25001d8
TV
102 struct regulator *reg;
103
945514b5 104 if (hdmi.vdda_reg != NULL)
e25001d8
TV
105 return 0;
106
931d4bd6 107 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
e25001d8
TV
108
109 if (IS_ERR(reg)) {
40359a9b 110 if (PTR_ERR(reg) != -EPROBE_DEFER)
931d4bd6 111 DSSERR("can't get VDDA regulator\n");
e25001d8
TV
112 return PTR_ERR(reg);
113 }
114
818a053c
TV
115 if (regulator_can_change_voltage(reg)) {
116 r = regulator_set_voltage(reg, 1800000, 1800000);
117 if (r) {
118 devm_regulator_put(reg);
119 DSSWARN("can't set the regulator voltage\n");
120 return r;
121 }
122 }
123
945514b5 124 hdmi.vdda_reg = reg;
e25001d8
TV
125
126 return 0;
127}
128
bb426fc9 129static int hdmi_power_on_core(struct omap_dss_device *dssdev)
c3198a5e 130{
46095b2d 131 int r;
c3198a5e 132
945514b5 133 r = regulator_enable(hdmi.vdda_reg);
17486943 134 if (r)
164ebdd1 135 return r;
17486943 136
4fbafaf3
TV
137 r = hdmi_runtime_get();
138 if (r)
cca35017 139 goto err_runtime_get;
c3198a5e 140
bb426fc9
TV
141 /* Make selection of HDMI in DSS */
142 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
143
0b450c31
TV
144 hdmi.core_enabled = true;
145
bb426fc9
TV
146 return 0;
147
148err_runtime_get:
945514b5 149 regulator_disable(hdmi.vdda_reg);
164ebdd1 150
bb426fc9
TV
151 return r;
152}
153
154static void hdmi_power_off_core(struct omap_dss_device *dssdev)
155{
0b450c31
TV
156 hdmi.core_enabled = false;
157
bb426fc9 158 hdmi_runtime_put();
945514b5 159 regulator_disable(hdmi.vdda_reg);
bb426fc9
TV
160}
161
162static int hdmi_power_on_full(struct omap_dss_device *dssdev)
163{
164 int r;
165 struct omap_video_timings *p;
7ae9a71e 166 struct omap_overlay_manager *mgr = hdmi.output.manager;
dcf5f729 167 struct hdmi_wp_data *wp = &hdmi.wp;
c84c3a5b 168 struct dss_pll_clock_info hdmi_cinfo = { 0 };
bb426fc9
TV
169
170 r = hdmi_power_on_core(dssdev);
171 if (r)
172 return r;
173
dcf5f729
TV
174 /* disable and clear irqs */
175 hdmi_wp_clear_irqenable(wp, 0xffffffff);
176 hdmi_wp_set_irqstatus(wp, 0xffffffff);
177
275cfa1a 178 p = &hdmi.cfg.timings;
c3198a5e 179
7849398f 180 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
c3198a5e 181
c84c3a5b 182 hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
c3198a5e 183
c84c3a5b 184 r = dss_pll_enable(&hdmi.pll.pll);
c3198a5e 185 if (r) {
c2fbd061 186 DSSERR("Failed to enable PLL\n");
cca35017 187 goto err_pll_enable;
c3198a5e
M
188 }
189
c84c3a5b 190 r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
c2fbd061
TV
191 if (r) {
192 DSSERR("Failed to configure PLL\n");
193 goto err_pll_cfg;
194 }
195
c84c3a5b
TV
196 r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
197 hdmi_cinfo.clkout[0]);
c3198a5e 198 if (r) {
dcf5f729
TV
199 DSSDBG("Failed to configure PHY\n");
200 goto err_phy_cfg;
c3198a5e
M
201 }
202
dcf5f729
TV
203 r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
204 if (r)
205 goto err_phy_pwr;
206
275cfa1a 207 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
c3198a5e 208
c3198a5e
M
209 /* bypass TV gamma table */
210 dispc_enable_gamma_table(0);
211
212 /* tv size */
cea87b92 213 dss_mgr_set_timings(mgr, p);
c3198a5e 214
275cfa1a 215 r = hdmi_wp_video_start(&hdmi.wp);
c0456be3
RN
216 if (r)
217 goto err_vid_enable;
c3198a5e 218
cea87b92 219 r = dss_mgr_enable(mgr);
33ca237f
TV
220 if (r)
221 goto err_mgr_enable;
3870c909 222
dcf5f729
TV
223 hdmi_wp_set_irqenable(wp,
224 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
225
c3198a5e 226 return 0;
33ca237f
TV
227
228err_mgr_enable:
275cfa1a 229 hdmi_wp_video_stop(&hdmi.wp);
c0456be3 230err_vid_enable:
dcf5f729
TV
231err_phy_cfg:
232 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
233err_phy_pwr:
c2fbd061 234err_pll_cfg:
c84c3a5b 235 dss_pll_disable(&hdmi.pll.pll);
cca35017 236err_pll_enable:
bb426fc9 237 hdmi_power_off_core(dssdev);
c3198a5e
M
238 return -EIO;
239}
240
bb426fc9 241static void hdmi_power_off_full(struct omap_dss_device *dssdev)
c3198a5e 242{
7ae9a71e 243 struct omap_overlay_manager *mgr = hdmi.output.manager;
cea87b92 244
dcf5f729
TV
245 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
246
cea87b92 247 dss_mgr_disable(mgr);
c3198a5e 248
275cfa1a 249 hdmi_wp_video_stop(&hdmi.wp);
dcf5f729
TV
250
251 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
252
c84c3a5b 253 dss_pll_disable(&hdmi.pll.pll);
17486943 254
bb426fc9 255 hdmi_power_off_core(dssdev);
c3198a5e
M
256}
257
164ebdd1 258static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
c3198a5e
M
259 struct omap_video_timings *timings)
260{
1e676248 261 struct omap_dss_device *out = &hdmi.output;
c3198a5e 262
1e676248 263 if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
c3198a5e 264 return -EINVAL;
c3198a5e
M
265
266 return 0;
c3198a5e
M
267}
268
164ebdd1 269static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
7849398f 270 struct omap_video_timings *timings)
c3198a5e 271{
ed1aa900
AT
272 mutex_lock(&hdmi.lock);
273
ab0aee95 274 hdmi.cfg.timings = *timings;
5391e87d 275
ab0aee95 276 dispc_set_tv_pclk(timings->pixelclock);
1e676248 277
ed1aa900 278 mutex_unlock(&hdmi.lock);
c3198a5e
M
279}
280
164ebdd1 281static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
0b450c31
TV
282 struct omap_video_timings *timings)
283{
ab0aee95 284 *timings = hdmi.cfg.timings;
0b450c31
TV
285}
286
e40402cf 287static void hdmi_dump_regs(struct seq_file *s)
162874d5
M
288{
289 mutex_lock(&hdmi.lock);
290
f8fb7d7b
WY
291 if (hdmi_runtime_get()) {
292 mutex_unlock(&hdmi.lock);
162874d5 293 return;
f8fb7d7b 294 }
162874d5 295
275cfa1a
AT
296 hdmi_wp_dump(&hdmi.wp, s);
297 hdmi_pll_dump(&hdmi.pll, s);
298 hdmi_phy_dump(&hdmi.phy, s);
299 hdmi4_core_dump(&hdmi.core, s);
162874d5
M
300
301 hdmi_runtime_put();
302 mutex_unlock(&hdmi.lock);
303}
304
164ebdd1 305static int read_edid(u8 *buf, int len)
47024565
TV
306{
307 int r;
308
309 mutex_lock(&hdmi.lock);
310
311 r = hdmi_runtime_get();
312 BUG_ON(r);
313
275cfa1a 314 r = hdmi4_read_edid(&hdmi.core, buf, len);
47024565
TV
315
316 hdmi_runtime_put();
317 mutex_unlock(&hdmi.lock);
318
319 return r;
320}
321
164ebdd1 322static int hdmi_display_enable(struct omap_dss_device *dssdev)
c3198a5e 323{
1f68d9c4 324 struct omap_dss_device *out = &hdmi.output;
c3198a5e
M
325 int r = 0;
326
327 DSSDBG("ENTER hdmi_display_enable\n");
328
329 mutex_lock(&hdmi.lock);
330
cea87b92
AT
331 if (out == NULL || out->manager == NULL) {
332 DSSERR("failed to enable display: no output/manager\n");
05e1d606
TV
333 r = -ENODEV;
334 goto err0;
335 }
336
bb426fc9 337 r = hdmi_power_on_full(dssdev);
c3198a5e
M
338 if (r) {
339 DSSERR("failed to power on device\n");
d3923933 340 goto err0;
c3198a5e
M
341 }
342
343 mutex_unlock(&hdmi.lock);
344 return 0;
345
c3198a5e
M
346err0:
347 mutex_unlock(&hdmi.lock);
348 return r;
349}
350
164ebdd1 351static void hdmi_display_disable(struct omap_dss_device *dssdev)
c3198a5e
M
352{
353 DSSDBG("Enter hdmi_display_disable\n");
354
355 mutex_lock(&hdmi.lock);
356
bb426fc9 357 hdmi_power_off_full(dssdev);
c3198a5e 358
c3198a5e
M
359 mutex_unlock(&hdmi.lock);
360}
361
164ebdd1 362static int hdmi_core_enable(struct omap_dss_device *dssdev)
4489823c
TV
363{
364 int r = 0;
365
366 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
367
368 mutex_lock(&hdmi.lock);
369
4489823c
TV
370 r = hdmi_power_on_core(dssdev);
371 if (r) {
372 DSSERR("failed to power on device\n");
373 goto err0;
374 }
375
376 mutex_unlock(&hdmi.lock);
377 return 0;
378
379err0:
380 mutex_unlock(&hdmi.lock);
381 return r;
382}
383
164ebdd1 384static void hdmi_core_disable(struct omap_dss_device *dssdev)
4489823c
TV
385{
386 DSSDBG("Enter omapdss_hdmi_core_disable\n");
387
388 mutex_lock(&hdmi.lock);
389
390 hdmi_power_off_core(dssdev);
391
392 mutex_unlock(&hdmi.lock);
393}
394
0b450c31
TV
395static int hdmi_connect(struct omap_dss_device *dssdev,
396 struct omap_dss_device *dst)
397{
398 struct omap_overlay_manager *mgr;
399 int r;
400
0b450c31
TV
401 r = hdmi_init_regulator();
402 if (r)
403 return r;
404
405 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
406 if (!mgr)
407 return -ENODEV;
408
409 r = dss_mgr_connect(mgr, dssdev);
410 if (r)
411 return r;
412
413 r = omapdss_output_set_device(dssdev, dst);
414 if (r) {
415 DSSERR("failed to connect output to new device: %s\n",
416 dst->name);
417 dss_mgr_disconnect(mgr, dssdev);
418 return r;
419 }
420
421 return 0;
422}
423
424static void hdmi_disconnect(struct omap_dss_device *dssdev,
425 struct omap_dss_device *dst)
426{
9560dc10 427 WARN_ON(dst != dssdev->dst);
0b450c31 428
9560dc10 429 if (dst != dssdev->dst)
0b450c31
TV
430 return;
431
432 omapdss_output_unset_device(dssdev);
433
434 if (dssdev->manager)
435 dss_mgr_disconnect(dssdev->manager, dssdev);
436}
437
438static int hdmi_read_edid(struct omap_dss_device *dssdev,
439 u8 *edid, int len)
440{
441 bool need_enable;
442 int r;
443
444 need_enable = hdmi.core_enabled == false;
445
446 if (need_enable) {
164ebdd1 447 r = hdmi_core_enable(dssdev);
0b450c31
TV
448 if (r)
449 return r;
450 }
451
164ebdd1 452 r = read_edid(edid, len);
0b450c31
TV
453
454 if (need_enable)
164ebdd1 455 hdmi_core_disable(dssdev);
0b450c31
TV
456
457 return r;
458}
459
460#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
164ebdd1 461static int hdmi_audio_enable(struct omap_dss_device *dssdev)
0b450c31
TV
462{
463 int r;
464
465 mutex_lock(&hdmi.lock);
466
ab0aee95 467 if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
0b450c31
TV
468 r = -EPERM;
469 goto err;
470 }
471
275cfa1a 472 r = hdmi_wp_audio_enable(&hdmi.wp, true);
0b450c31
TV
473 if (r)
474 goto err;
475
476 mutex_unlock(&hdmi.lock);
477 return 0;
478
479err:
480 mutex_unlock(&hdmi.lock);
481 return r;
482}
483
164ebdd1 484static void hdmi_audio_disable(struct omap_dss_device *dssdev)
0b450c31 485{
275cfa1a 486 hdmi_wp_audio_enable(&hdmi.wp, false);
0b450c31
TV
487}
488
164ebdd1 489static int hdmi_audio_start(struct omap_dss_device *dssdev)
0b450c31 490{
275cfa1a 491 return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
0b450c31
TV
492}
493
164ebdd1 494static void hdmi_audio_stop(struct omap_dss_device *dssdev)
0b450c31 495{
275cfa1a 496 hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
0b450c31
TV
497}
498
164ebdd1 499static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
0b450c31
TV
500{
501 bool r;
502
503 mutex_lock(&hdmi.lock);
504
ab0aee95 505 r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
0b450c31
TV
506
507 mutex_unlock(&hdmi.lock);
508 return r;
509}
510
164ebdd1 511static int hdmi_audio_config(struct omap_dss_device *dssdev,
0b450c31
TV
512 struct omap_dss_audio *audio)
513{
514 int r;
d8d78941 515 u32 pclk = hdmi.cfg.timings.pixelclock;
0b450c31
TV
516
517 mutex_lock(&hdmi.lock);
518
ab0aee95 519 if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
0b450c31
TV
520 r = -EPERM;
521 goto err;
522 }
523
08d83e4e 524 r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
0b450c31
TV
525 if (r)
526 goto err;
527
528 mutex_unlock(&hdmi.lock);
529 return 0;
530
531err:
532 mutex_unlock(&hdmi.lock);
533 return r;
534}
535#else
164ebdd1 536static int hdmi_audio_enable(struct omap_dss_device *dssdev)
0b450c31
TV
537{
538 return -EPERM;
539}
540
164ebdd1 541static void hdmi_audio_disable(struct omap_dss_device *dssdev)
0b450c31
TV
542{
543}
544
164ebdd1 545static int hdmi_audio_start(struct omap_dss_device *dssdev)
0b450c31
TV
546{
547 return -EPERM;
548}
549
164ebdd1 550static void hdmi_audio_stop(struct omap_dss_device *dssdev)
0b450c31
TV
551{
552}
553
164ebdd1 554static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
0b450c31
TV
555{
556 return false;
557}
558
164ebdd1 559static int hdmi_audio_config(struct omap_dss_device *dssdev,
0b450c31
TV
560 struct omap_dss_audio *audio)
561{
562 return -EPERM;
563}
564#endif
565
ab0aee95
TV
566static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
567 const struct hdmi_avi_infoframe *avi)
568{
569 hdmi.cfg.infoframe = *avi;
570 return 0;
571}
572
573static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
574 bool hdmi_mode)
575{
576 hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
577 return 0;
578}
579
0b450c31
TV
580static const struct omapdss_hdmi_ops hdmi_ops = {
581 .connect = hdmi_connect,
582 .disconnect = hdmi_disconnect,
583
164ebdd1
TV
584 .enable = hdmi_display_enable,
585 .disable = hdmi_display_disable,
0b450c31 586
164ebdd1
TV
587 .check_timings = hdmi_display_check_timing,
588 .set_timings = hdmi_display_set_timing,
589 .get_timings = hdmi_display_get_timings,
0b450c31
TV
590
591 .read_edid = hdmi_read_edid,
ab0aee95
TV
592 .set_infoframe = hdmi_set_infoframe,
593 .set_hdmi_mode = hdmi_set_hdmi_mode,
0b450c31 594
164ebdd1
TV
595 .audio_enable = hdmi_audio_enable,
596 .audio_disable = hdmi_audio_disable,
597 .audio_start = hdmi_audio_start,
598 .audio_stop = hdmi_audio_stop,
599 .audio_supported = hdmi_audio_supported,
600 .audio_config = hdmi_audio_config,
0b450c31
TV
601};
602
17ae4e8c 603static void hdmi_init_output(struct platform_device *pdev)
81b87f51 604{
1f68d9c4 605 struct omap_dss_device *out = &hdmi.output;
81b87f51 606
1f68d9c4 607 out->dev = &pdev->dev;
81b87f51 608 out->id = OMAP_DSS_OUTPUT_HDMI;
1f68d9c4 609 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
7286a08f 610 out->name = "hdmi.0";
2eea5ae6 611 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
0b450c31 612 out->ops.hdmi = &hdmi_ops;
b7328e14 613 out->owner = THIS_MODULE;
81b87f51 614
5d47dbc8 615 omapdss_register_output(out);
81b87f51
AT
616}
617
618static void __exit hdmi_uninit_output(struct platform_device *pdev)
619{
1f68d9c4 620 struct omap_dss_device *out = &hdmi.output;
81b87f51 621
5d47dbc8 622 omapdss_unregister_output(out);
81b87f51
AT
623}
624
2f5dc676
TV
625static int hdmi_probe_of(struct platform_device *pdev)
626{
627 struct device_node *node = pdev->dev.of_node;
628 struct device_node *ep;
629 int r;
630
631 ep = omapdss_of_get_first_endpoint(node);
632 if (!ep)
633 return 0;
634
635 r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
636 if (r)
637 goto err;
638
639 of_node_put(ep);
640 return 0;
641
642err:
643 of_node_put(ep);
644 return r;
645}
646
c3198a5e 647/* HDMI HW IP initialisation */
17ae4e8c 648static int omapdss_hdmihw_probe(struct platform_device *pdev)
c3198a5e 649{
38f3daf6 650 int r;
dcf5f729 651 int irq;
c3198a5e 652
c3198a5e 653 hdmi.pdev = pdev;
945514b5 654 dev_set_drvdata(&pdev->dev, &hdmi);
c3198a5e
M
655
656 mutex_init(&hdmi.lock);
657
2f5dc676
TV
658 if (pdev->dev.of_node) {
659 r = hdmi_probe_of(pdev);
660 if (r)
661 return r;
662 }
663
275cfa1a 664 r = hdmi_wp_init(pdev, &hdmi.wp);
f382d9eb
AT
665 if (r)
666 return r;
c3198a5e 667
03aafa2c 668 r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
c1577c1e
AT
669 if (r)
670 return r;
671
275cfa1a 672 r = hdmi_phy_init(pdev, &hdmi.phy);
5cac5aee 673 if (r)
c84c3a5b 674 goto err;
ddb1d5ca 675
275cfa1a 676 r = hdmi4_core_init(pdev, &hdmi.core);
425f02fd 677 if (r)
c84c3a5b 678 goto err;
4fbafaf3 679
dcf5f729
TV
680 irq = platform_get_irq(pdev, 0);
681 if (irq < 0) {
682 DSSERR("platform_get_irq failed\n");
c84c3a5b
TV
683 r = -ENODEV;
684 goto err;
dcf5f729
TV
685 }
686
687 r = devm_request_threaded_irq(&pdev->dev, irq,
688 NULL, hdmi_irq_handler,
689 IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
690 if (r) {
691 DSSERR("HDMI IRQ request failed\n");
c84c3a5b 692 goto err;
dcf5f729
TV
693 }
694
4fbafaf3
TV
695 pm_runtime_enable(&pdev->dev);
696
002d368d
TV
697 hdmi_init_output(pdev);
698
e40402cf
TV
699 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
700
cca35017 701 return 0;
c84c3a5b
TV
702err:
703 hdmi_pll_uninit(&hdmi.pll);
704 return r;
cca35017
TV
705}
706
6e7e8f06 707static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
c3198a5e 708{
81b87f51
AT
709 hdmi_uninit_output(pdev);
710
c84c3a5b
TV
711 hdmi_pll_uninit(&hdmi.pll);
712
4fbafaf3
TV
713 pm_runtime_disable(&pdev->dev);
714
c3198a5e
M
715 return 0;
716}
717
4fbafaf3
TV
718static int hdmi_runtime_suspend(struct device *dev)
719{
4fbafaf3 720 dispc_runtime_put();
4fbafaf3
TV
721
722 return 0;
723}
724
725static int hdmi_runtime_resume(struct device *dev)
726{
727 int r;
728
4fbafaf3
TV
729 r = dispc_runtime_get();
730 if (r < 0)
852f0838 731 return r;
4fbafaf3 732
4fbafaf3 733 return 0;
4fbafaf3
TV
734}
735
736static const struct dev_pm_ops hdmi_pm_ops = {
737 .runtime_suspend = hdmi_runtime_suspend,
738 .runtime_resume = hdmi_runtime_resume,
739};
740
0465616d
TV
741static const struct of_device_id hdmi_of_match[] = {
742 { .compatible = "ti,omap4-hdmi", },
743 {},
744};
745
c3198a5e 746static struct platform_driver omapdss_hdmihw_driver = {
17ae4e8c 747 .probe = omapdss_hdmihw_probe,
6e7e8f06 748 .remove = __exit_p(omapdss_hdmihw_remove),
c3198a5e
M
749 .driver = {
750 .name = "omapdss_hdmi",
751 .owner = THIS_MODULE,
4fbafaf3 752 .pm = &hdmi_pm_ops,
0465616d 753 .of_match_table = hdmi_of_match,
422ccbd5 754 .suppress_bind_attrs = true,
c3198a5e
M
755 },
756};
757
ef26958a 758int __init hdmi4_init_platform_driver(void)
c3198a5e 759{
17ae4e8c 760 return platform_driver_register(&omapdss_hdmihw_driver);
c3198a5e
M
761}
762
ef26958a 763void __exit hdmi4_uninit_platform_driver(void)
c3198a5e 764{
04c742c3 765 platform_driver_unregister(&omapdss_hdmihw_driver);
c3198a5e 766}