drm/omap: dss: hdmi4: Move initialization code from bind to probe
[linux-2.6-block.git] / drivers / gpu / drm / omapdrm / dss / hdmi5.c
CommitLineData
f5bab222
TV
1/*
2 * HDMI driver for OMAP5
3 *
bb5cdf8d 4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
f5bab222
TV
5 *
6 * Authors:
7 * Yong Zhi
8 * Mythri pk
9 * Archit Taneja <archit@ti.com>
10 * Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25#define DSS_SUBSYS_NAME "HDMI"
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/err.h>
30#include <linux/io.h>
31#include <linux/interrupt.h>
32#include <linux/mutex.h>
33#include <linux/delay.h>
34#include <linux/string.h>
35#include <linux/platform_device.h>
36#include <linux/pm_runtime.h>
37#include <linux/clk.h>
38#include <linux/gpio.h>
39#include <linux/regulator/consumer.h>
736e60dd 40#include <linux/component.h>
d9e32ecd 41#include <linux/of.h>
09bffa6e 42#include <linux/of_graph.h>
45302d7e 43#include <sound/omap-hdmi-audio.h>
f5bab222 44
32043da7 45#include "omapdss.h"
f5bab222
TV
46#include "hdmi5_core.h"
47#include "dss.h"
f5bab222 48
c44991ce 49static int hdmi_runtime_get(struct omap_hdmi *hdmi)
f5bab222
TV
50{
51 int r;
52
53 DSSDBG("hdmi_runtime_get\n");
54
c44991ce 55 r = pm_runtime_get_sync(&hdmi->pdev->dev);
f5bab222
TV
56 WARN_ON(r < 0);
57 if (r < 0)
58 return r;
59
60 return 0;
61}
62
c44991ce 63static void hdmi_runtime_put(struct omap_hdmi *hdmi)
f5bab222
TV
64{
65 int r;
66
67 DSSDBG("hdmi_runtime_put\n");
68
c44991ce 69 r = pm_runtime_put_sync(&hdmi->pdev->dev);
f5bab222
TV
70 WARN_ON(r < 0 && r != -ENOSYS);
71}
72
73static irqreturn_t hdmi_irq_handler(int irq, void *data)
74{
c44991ce
LP
75 struct omap_hdmi *hdmi = data;
76 struct hdmi_wp_data *wp = &hdmi->wp;
f5bab222
TV
77 u32 irqstatus;
78
79 irqstatus = hdmi_wp_get_irqstatus(wp);
80 hdmi_wp_set_irqstatus(wp, irqstatus);
81
82 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
83 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
84 u32 v;
85 /*
86 * If we get both connect and disconnect interrupts at the same
87 * time, turn off the PHY, clear interrupts, and restart, which
88 * raises connect interrupt if a cable is connected, or nothing
89 * if cable is not connected.
90 */
91
92 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
93
94 /*
95 * We always get bogus CONNECT & DISCONNECT interrupts when
96 * setting the PHY to LDOON. To ignore those, we force the RXDET
97 * line to 0 until the PHY power state has been changed.
98 */
c44991ce 99 v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
f5bab222
TV
100 v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
101 v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
c44991ce 102 hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
f5bab222
TV
103
104 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
105 HDMI_IRQ_LINK_DISCONNECT);
106
107 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
108
c44991ce 109 REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
f5bab222
TV
110
111 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
112 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
113 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
114 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
115 }
116
117 return IRQ_HANDLED;
118}
119
c44991ce 120static int hdmi_init_regulator(struct omap_hdmi *hdmi)
f5bab222 121{
f5bab222
TV
122 struct regulator *reg;
123
c44991ce 124 if (hdmi->vdda_reg != NULL)
f5bab222
TV
125 return 0;
126
c44991ce 127 reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
f5bab222
TV
128 if (IS_ERR(reg)) {
129 DSSERR("can't get VDDA regulator\n");
130 return PTR_ERR(reg);
131 }
132
c44991ce 133 hdmi->vdda_reg = reg;
f5bab222
TV
134
135 return 0;
136}
137
c44991ce 138static int hdmi_power_on_core(struct omap_hdmi *hdmi)
f5bab222
TV
139{
140 int r;
141
c44991ce 142 r = regulator_enable(hdmi->vdda_reg);
f5bab222
TV
143 if (r)
144 return r;
145
c44991ce 146 r = hdmi_runtime_get(hdmi);
f5bab222
TV
147 if (r)
148 goto err_runtime_get;
149
150 /* Make selection of HDMI in DSS */
c44991ce 151 dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
f5bab222 152
c44991ce 153 hdmi->core_enabled = true;
f5bab222
TV
154
155 return 0;
156
157err_runtime_get:
c44991ce 158 regulator_disable(hdmi->vdda_reg);
f5bab222
TV
159
160 return r;
161}
162
c44991ce 163static void hdmi_power_off_core(struct omap_hdmi *hdmi)
f5bab222 164{
c44991ce 165 hdmi->core_enabled = false;
f5bab222 166
c44991ce
LP
167 hdmi_runtime_put(hdmi);
168 regulator_disable(hdmi->vdda_reg);
f5bab222
TV
169}
170
c44991ce 171static int hdmi_power_on_full(struct omap_hdmi *hdmi)
f5bab222
TV
172{
173 int r;
da11bbbb 174 struct videomode *vm;
c84c3a5b 175 struct dss_pll_clock_info hdmi_cinfo = { 0 };
d11e5c82 176 unsigned int pc;
f5bab222 177
c44991ce 178 r = hdmi_power_on_core(hdmi);
f5bab222
TV
179 if (r)
180 return r;
181
c44991ce 182 vm = &hdmi->cfg.vm;
f5bab222 183
da11bbbb
PU
184 DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
185 vm->vactive);
f5bab222 186
da11bbbb
PU
187 pc = vm->pixelclock;
188 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
67d8ffdd
TV
189 pc *= 2;
190
c107751d
TV
191 /* DSS_HDMI_TCLK is bitclk / 10 */
192 pc *= 10;
193
c44991ce 194 dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
c17dc0e3 195 pc, &hdmi_cinfo);
f5bab222
TV
196
197 /* disable and clear irqs */
c44991ce
LP
198 hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
199 hdmi_wp_set_irqstatus(&hdmi->wp,
200 hdmi_wp_get_irqstatus(&hdmi->wp));
f5bab222 201
c44991ce 202 r = dss_pll_enable(&hdmi->pll.pll);
f5bab222 203 if (r) {
c2fbd061 204 DSSERR("Failed to enable PLL\n");
f5bab222
TV
205 goto err_pll_enable;
206 }
207
c44991ce 208 r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
c2fbd061
TV
209 if (r) {
210 DSSERR("Failed to configure PLL\n");
211 goto err_pll_cfg;
212 }
213
c44991ce 214 r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
c84c3a5b 215 hdmi_cinfo.clkout[0]);
f5bab222
TV
216 if (r) {
217 DSSDBG("Failed to start PHY\n");
218 goto err_phy_cfg;
219 }
220
c44991ce 221 r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON);
f5bab222
TV
222 if (r)
223 goto err_phy_pwr;
224
c44991ce 225 hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
f5bab222 226
f5bab222 227 /* tv size */
c44991ce 228 dss_mgr_set_timings(&hdmi->output, vm);
f5bab222 229
c44991ce 230 r = dss_mgr_enable(&hdmi->output);
f5bab222
TV
231 if (r)
232 goto err_mgr_enable;
233
c44991ce 234 r = hdmi_wp_video_start(&hdmi->wp);
4e4b53ce
TV
235 if (r)
236 goto err_vid_enable;
237
c44991ce 238 hdmi_wp_set_irqenable(&hdmi->wp,
f5bab222
TV
239 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
240
241 return 0;
242
f5bab222 243err_vid_enable:
c44991ce 244 dss_mgr_disable(&hdmi->output);
4e4b53ce 245err_mgr_enable:
c44991ce 246 hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
f5bab222
TV
247err_phy_pwr:
248err_phy_cfg:
c2fbd061 249err_pll_cfg:
c44991ce 250 dss_pll_disable(&hdmi->pll.pll);
f5bab222 251err_pll_enable:
c44991ce 252 hdmi_power_off_core(hdmi);
f5bab222
TV
253 return -EIO;
254}
255
c44991ce 256static void hdmi_power_off_full(struct omap_hdmi *hdmi)
f5bab222 257{
c44991ce 258 hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
f5bab222 259
c44991ce 260 hdmi_wp_video_stop(&hdmi->wp);
f5bab222 261
c44991ce 262 dss_mgr_disable(&hdmi->output);
4e4b53ce 263
c44991ce 264 hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
f5bab222 265
c44991ce 266 dss_pll_disable(&hdmi->pll.pll);
f5bab222 267
c44991ce 268 hdmi_power_off_core(hdmi);
f5bab222
TV
269}
270
271static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
da11bbbb 272 struct videomode *vm)
f5bab222 273{
c44991ce
LP
274 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
275
276 if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
f5bab222
TV
277 return -EINVAL;
278
279 return 0;
280}
281
282static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
da11bbbb 283 struct videomode *vm)
f5bab222 284{
c44991ce
LP
285 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
286
287 mutex_lock(&hdmi->lock);
f5bab222 288
c44991ce 289 hdmi->cfg.vm = *vm;
f5bab222 290
c44991ce 291 dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
f5bab222 292
c44991ce 293 mutex_unlock(&hdmi->lock);
f5bab222
TV
294}
295
f33656e1 296static int hdmi_dump_regs(struct seq_file *s, void *p)
f5bab222 297{
c44991ce
LP
298 struct omap_hdmi *hdmi = s->private;
299
300 mutex_lock(&hdmi->lock);
f5bab222 301
c44991ce
LP
302 if (hdmi_runtime_get(hdmi)) {
303 mutex_unlock(&hdmi->lock);
f33656e1 304 return 0;
f5bab222
TV
305 }
306
c44991ce
LP
307 hdmi_wp_dump(&hdmi->wp, s);
308 hdmi_pll_dump(&hdmi->pll, s);
309 hdmi_phy_dump(&hdmi->phy, s);
310 hdmi5_core_dump(&hdmi->core, s);
f5bab222 311
c44991ce
LP
312 hdmi_runtime_put(hdmi);
313 mutex_unlock(&hdmi->lock);
f33656e1 314 return 0;
f5bab222
TV
315}
316
c44991ce 317static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
f5bab222
TV
318{
319 int r;
320 int idlemode;
321
c44991ce 322 mutex_lock(&hdmi->lock);
f5bab222 323
c44991ce 324 r = hdmi_runtime_get(hdmi);
f5bab222
TV
325 BUG_ON(r);
326
c44991ce 327 idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
f5bab222 328 /* No-idle mode */
c44991ce 329 REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
f5bab222 330
c44991ce 331 r = hdmi5_read_edid(&hdmi->core, buf, len);
f5bab222 332
c44991ce 333 REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
f5bab222 334
c44991ce
LP
335 hdmi_runtime_put(hdmi);
336 mutex_unlock(&hdmi->lock);
f5bab222
TV
337
338 return r;
339}
340
8a9d4626
JS
341static void hdmi_start_audio_stream(struct omap_hdmi *hd)
342{
c44991ce 343 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
8a9d4626
JS
344 hdmi_wp_audio_enable(&hd->wp, true);
345 hdmi_wp_audio_core_req_enable(&hd->wp, true);
346}
347
348static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
349{
350 hdmi_wp_audio_core_req_enable(&hd->wp, false);
351 hdmi_wp_audio_enable(&hd->wp, false);
352 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
353}
354
f5bab222
TV
355static int hdmi_display_enable(struct omap_dss_device *dssdev)
356{
c44991ce 357 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
8a9d4626 358 unsigned long flags;
f5bab222
TV
359 int r = 0;
360
361 DSSDBG("ENTER hdmi_display_enable\n");
362
c44991ce 363 mutex_lock(&hdmi->lock);
f5bab222 364
c44991ce 365 if (!dssdev->dispc_channel_connected) {
f5bab222
TV
366 DSSERR("failed to enable display: no output/manager\n");
367 r = -ENODEV;
368 goto err0;
369 }
370
c44991ce 371 r = hdmi_power_on_full(hdmi);
f5bab222
TV
372 if (r) {
373 DSSERR("failed to power on device\n");
374 goto err0;
375 }
376
c44991ce
LP
377 if (hdmi->audio_configured) {
378 r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
379 &hdmi->audio_config,
380 hdmi->cfg.vm.pixelclock);
8a9d4626
JS
381 if (r) {
382 DSSERR("Error restoring audio configuration: %d", r);
c44991ce
LP
383 hdmi->audio_abort_cb(&hdmi->pdev->dev);
384 hdmi->audio_configured = false;
8a9d4626
JS
385 }
386 }
387
c44991ce
LP
388 spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
389 if (hdmi->audio_configured && hdmi->audio_playing)
390 hdmi_start_audio_stream(hdmi);
391 hdmi->display_enabled = true;
392 spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
45302d7e 393
c44991ce 394 mutex_unlock(&hdmi->lock);
f5bab222
TV
395 return 0;
396
397err0:
c44991ce 398 mutex_unlock(&hdmi->lock);
f5bab222
TV
399 return r;
400}
401
402static void hdmi_display_disable(struct omap_dss_device *dssdev)
403{
c44991ce 404 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
8a9d4626
JS
405 unsigned long flags;
406
f5bab222
TV
407 DSSDBG("Enter hdmi_display_disable\n");
408
c44991ce 409 mutex_lock(&hdmi->lock);
f5bab222 410
c44991ce
LP
411 spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
412 hdmi_stop_audio_stream(hdmi);
413 hdmi->display_enabled = false;
414 spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
45302d7e 415
c44991ce 416 hdmi_power_off_full(hdmi);
f5bab222 417
c44991ce 418 mutex_unlock(&hdmi->lock);
f5bab222
TV
419}
420
c44991ce 421static int hdmi_core_enable(struct omap_hdmi *hdmi)
f5bab222
TV
422{
423 int r = 0;
424
425 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
426
c44991ce 427 mutex_lock(&hdmi->lock);
f5bab222 428
c44991ce 429 r = hdmi_power_on_core(hdmi);
f5bab222
TV
430 if (r) {
431 DSSERR("failed to power on device\n");
432 goto err0;
433 }
434
c44991ce 435 mutex_unlock(&hdmi->lock);
f5bab222
TV
436 return 0;
437
438err0:
c44991ce 439 mutex_unlock(&hdmi->lock);
f5bab222
TV
440 return r;
441}
442
c44991ce 443static void hdmi_core_disable(struct omap_hdmi *hdmi)
f5bab222
TV
444{
445 DSSDBG("Enter omapdss_hdmi_core_disable\n");
446
c44991ce 447 mutex_lock(&hdmi->lock);
f5bab222 448
c44991ce 449 hdmi_power_off_core(hdmi);
f5bab222 450
c44991ce 451 mutex_unlock(&hdmi->lock);
f5bab222
TV
452}
453
f5bab222
TV
454static int hdmi_connect(struct omap_dss_device *dssdev,
455 struct omap_dss_device *dst)
456{
c44991ce 457 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
f5bab222
TV
458 int r;
459
c44991ce 460 r = hdmi_init_regulator(hdmi);
f5bab222
TV
461 if (r)
462 return r;
463
c44991ce 464 r = dss_mgr_connect(&hdmi->output, dssdev);
f5bab222
TV
465 if (r)
466 return r;
467
468 r = omapdss_output_set_device(dssdev, dst);
469 if (r) {
470 DSSERR("failed to connect output to new device: %s\n",
471 dst->name);
c44991ce 472 dss_mgr_disconnect(&hdmi->output, dssdev);
f5bab222
TV
473 return r;
474 }
475
476 return 0;
477}
478
479static void hdmi_disconnect(struct omap_dss_device *dssdev,
480 struct omap_dss_device *dst)
481{
c44991ce
LP
482 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
483
f5bab222
TV
484 omapdss_output_unset_device(dssdev);
485
c44991ce 486 dss_mgr_disconnect(&hdmi->output, dssdev);
f5bab222
TV
487}
488
489static int hdmi_read_edid(struct omap_dss_device *dssdev,
490 u8 *edid, int len)
491{
c44991ce 492 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
f5bab222
TV
493 bool need_enable;
494 int r;
495
c44991ce 496 need_enable = hdmi->core_enabled == false;
f5bab222
TV
497
498 if (need_enable) {
c44991ce 499 r = hdmi_core_enable(hdmi);
f5bab222
TV
500 if (r)
501 return r;
502 }
503
c44991ce 504 r = read_edid(hdmi, edid, len);
f5bab222
TV
505
506 if (need_enable)
c44991ce 507 hdmi_core_disable(hdmi);
f5bab222
TV
508
509 return r;
510}
511
769dcb11
TV
512static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
513 const struct hdmi_avi_infoframe *avi)
514{
c44991ce
LP
515 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
516
517 hdmi->cfg.infoframe = *avi;
769dcb11
TV
518 return 0;
519}
520
521static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
522 bool hdmi_mode)
523{
c44991ce
LP
524 struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
525
526 hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
769dcb11
TV
527 return 0;
528}
529
b93109d7 530static const struct omap_dss_device_ops hdmi_ops = {
f5bab222
TV
531 .connect = hdmi_connect,
532 .disconnect = hdmi_disconnect,
533
534 .enable = hdmi_display_enable,
535 .disable = hdmi_display_disable,
536
537 .check_timings = hdmi_display_check_timing,
538 .set_timings = hdmi_display_set_timing,
f5bab222 539
b93109d7
LP
540 .hdmi = {
541 .read_edid = hdmi_read_edid,
542 .set_infoframe = hdmi_set_infoframe,
543 .set_hdmi_mode = hdmi_set_hdmi_mode,
544 },
f5bab222
TV
545};
546
c44991ce 547static void hdmi_init_output(struct omap_hdmi *hdmi)
f5bab222 548{
c44991ce 549 struct omap_dss_device *out = &hdmi->output;
f5bab222 550
c44991ce 551 out->dev = &hdmi->pdev->dev;
f5bab222
TV
552 out->id = OMAP_DSS_OUTPUT_HDMI;
553 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
554 out->name = "hdmi.0";
555 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
b93109d7 556 out->ops = &hdmi_ops;
f5bab222 557 out->owner = THIS_MODULE;
4e20bda6 558 out->of_ports = BIT(0);
f5bab222 559
de57e9db 560 omapdss_device_register(out);
f5bab222
TV
561}
562
c44991ce 563static void hdmi_uninit_output(struct omap_hdmi *hdmi)
f5bab222 564{
c44991ce 565 struct omap_dss_device *out = &hdmi->output;
f5bab222 566
de57e9db 567 omapdss_device_unregister(out);
f5bab222
TV
568}
569
c44991ce 570static int hdmi_probe_of(struct omap_hdmi *hdmi)
f5bab222 571{
c44991ce 572 struct platform_device *pdev = hdmi->pdev;
f5bab222
TV
573 struct device_node *node = pdev->dev.of_node;
574 struct device_node *ep;
575 int r;
576
09bffa6e 577 ep = of_graph_get_endpoint_by_regs(node, 0, 0);
f5bab222
TV
578 if (!ep)
579 return 0;
580
c44991ce 581 r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
f5bab222
TV
582 if (r)
583 goto err;
584
585 of_node_put(ep);
586 return 0;
587
588err:
589 of_node_put(ep);
590 return r;
591}
592
45302d7e
JS
593/* Audio callbacks */
594static int hdmi_audio_startup(struct device *dev,
595 void (*abort_cb)(struct device *dev))
596{
597 struct omap_hdmi *hd = dev_get_drvdata(dev);
45302d7e
JS
598
599 mutex_lock(&hd->lock);
600
c1899cb3 601 WARN_ON(hd->audio_abort_cb != NULL);
45302d7e
JS
602
603 hd->audio_abort_cb = abort_cb;
604
45302d7e
JS
605 mutex_unlock(&hd->lock);
606
c1899cb3 607 return 0;
45302d7e
JS
608}
609
610static int hdmi_audio_shutdown(struct device *dev)
611{
612 struct omap_hdmi *hd = dev_get_drvdata(dev);
613
614 mutex_lock(&hd->lock);
615 hd->audio_abort_cb = NULL;
8a9d4626
JS
616 hd->audio_configured = false;
617 hd->audio_playing = false;
45302d7e
JS
618 mutex_unlock(&hd->lock);
619
620 return 0;
621}
622
623static int hdmi_audio_start(struct device *dev)
624{
625 struct omap_hdmi *hd = dev_get_drvdata(dev);
8a9d4626 626 unsigned long flags;
45302d7e 627
8a9d4626 628 spin_lock_irqsave(&hd->audio_playing_lock, flags);
2d7639bc 629
c1899cb3
JS
630 if (hd->display_enabled) {
631 if (!hdmi_mode_has_audio(&hd->cfg))
632 DSSERR("%s: Video mode does not support audio\n",
633 __func__);
8a9d4626 634 hdmi_start_audio_stream(hd);
c1899cb3 635 }
8a9d4626 636 hd->audio_playing = true;
45302d7e 637
8a9d4626 638 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
45302d7e
JS
639 return 0;
640}
641
642static void hdmi_audio_stop(struct device *dev)
643{
644 struct omap_hdmi *hd = dev_get_drvdata(dev);
8a9d4626 645 unsigned long flags;
45302d7e 646
c1899cb3
JS
647 if (!hdmi_mode_has_audio(&hd->cfg))
648 DSSERR("%s: Video mode does not support audio\n", __func__);
45302d7e 649
8a9d4626
JS
650 spin_lock_irqsave(&hd->audio_playing_lock, flags);
651
652 if (hd->display_enabled)
653 hdmi_stop_audio_stream(hd);
654 hd->audio_playing = false;
2d7639bc 655
8a9d4626 656 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
45302d7e
JS
657}
658
659static int hdmi_audio_config(struct device *dev,
660 struct omap_dss_audio *dss_audio)
661{
662 struct omap_hdmi *hd = dev_get_drvdata(dev);
77eeac24 663 int ret = 0;
45302d7e
JS
664
665 mutex_lock(&hd->lock);
666
c1899cb3
JS
667 if (hd->display_enabled) {
668 ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
669 hd->cfg.vm.pixelclock);
670 if (ret)
671 goto out;
45302d7e
JS
672 }
673
c1899cb3
JS
674 hd->audio_configured = true;
675 hd->audio_config = *dss_audio;
45302d7e
JS
676out:
677 mutex_unlock(&hd->lock);
678
679 return ret;
680}
681
682static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
683 .audio_startup = hdmi_audio_startup,
684 .audio_shutdown = hdmi_audio_shutdown,
685 .audio_start = hdmi_audio_start,
686 .audio_stop = hdmi_audio_stop,
687 .audio_config = hdmi_audio_config,
688};
689
c44991ce 690static int hdmi_audio_register(struct omap_hdmi *hdmi)
45302d7e
JS
691{
692 struct omap_hdmi_audio_pdata pdata = {
c44991ce 693 .dev = &hdmi->pdev->dev,
d20fa5a0 694 .version = 5,
c44991ce 695 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
45302d7e
JS
696 .ops = &hdmi_audio_ops,
697 };
698
c44991ce
LP
699 hdmi->audio_pdev = platform_device_register_data(
700 &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
45302d7e
JS
701 &pdata, sizeof(pdata));
702
c44991ce
LP
703 if (IS_ERR(hdmi->audio_pdev))
704 return PTR_ERR(hdmi->audio_pdev);
45302d7e 705
c44991ce
LP
706 hdmi_runtime_get(hdmi);
707 hdmi->wp_idlemode =
708 REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
709 hdmi_runtime_put(hdmi);
8a9d4626 710
45302d7e
JS
711 return 0;
712}
713
f5bab222 714/* HDMI HW IP initialisation */
736e60dd 715static int hdmi5_bind(struct device *dev, struct device *master, void *data)
f5bab222 716{
736e60dd 717 struct platform_device *pdev = to_platform_device(dev);
7b295257 718 struct dss_device *dss = dss_get_device(master);
c44991ce 719 struct omap_hdmi *hdmi;
f5bab222
TV
720 int r;
721 int irq;
722
c44991ce
LP
723 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
724 if (!hdmi)
725 return -ENOMEM;
f5bab222 726
c44991ce
LP
727 hdmi->pdev = pdev;
728 hdmi->dss = dss;
729 dev_set_drvdata(&pdev->dev, hdmi);
f5bab222 730
c44991ce
LP
731 mutex_init(&hdmi->lock);
732 spin_lock_init(&hdmi->audio_playing_lock);
733
734 r = hdmi_probe_of(hdmi);
1dff212c 735 if (r)
c44991ce 736 goto err_free;
f5bab222 737
c44991ce 738 r = hdmi_wp_init(pdev, &hdmi->wp, 5);
f5bab222 739 if (r)
c44991ce 740 goto err_free;
f5bab222 741
c44991ce 742 r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp);
f5bab222 743 if (r)
c44991ce 744 goto err_free;
f5bab222 745
c44991ce 746 r = hdmi_phy_init(pdev, &hdmi->phy, 5);
f5bab222 747 if (r)
c44991ce 748 goto err_pll;
f5bab222 749
c44991ce 750 r = hdmi5_core_init(pdev, &hdmi->core);
f5bab222 751 if (r)
c44991ce 752 goto err_pll;
f5bab222
TV
753
754 irq = platform_get_irq(pdev, 0);
755 if (irq < 0) {
756 DSSERR("platform_get_irq failed\n");
c84c3a5b 757 r = -ENODEV;
c44991ce 758 goto err_pll;
f5bab222
TV
759 }
760
761 r = devm_request_threaded_irq(&pdev->dev, irq,
762 NULL, hdmi_irq_handler,
c44991ce 763 IRQF_ONESHOT, "OMAP HDMI", hdmi);
f5bab222
TV
764 if (r) {
765 DSSERR("HDMI IRQ request failed\n");
c44991ce 766 goto err_pll;
f5bab222
TV
767 }
768
769 pm_runtime_enable(&pdev->dev);
770
c44991ce 771 hdmi_init_output(hdmi);
f5bab222 772
c44991ce 773 r = hdmi_audio_register(hdmi);
45302d7e
JS
774 if (r) {
775 DSSERR("Registering HDMI audio failed %d\n", r);
66aacfe2 776 goto err_uninit_output;
45302d7e
JS
777 }
778
c44991ce
LP
779 hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
780 hdmi);
f5bab222
TV
781
782 return 0;
c44991ce 783
66aacfe2
LP
784err_uninit_output:
785 hdmi_uninit_output(hdmi);
786 pm_runtime_disable(&pdev->dev);
c44991ce
LP
787err_pll:
788 hdmi_pll_uninit(&hdmi->pll);
789err_free:
790 kfree(hdmi);
c84c3a5b 791 return r;
f5bab222
TV
792}
793
736e60dd 794static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
f5bab222 795{
c44991ce
LP
796 struct omap_hdmi *hdmi = dev_get_drvdata(dev);
797
798 dss_debugfs_remove_file(hdmi->debugfs);
736e60dd 799
c44991ce
LP
800 if (hdmi->audio_pdev)
801 platform_device_unregister(hdmi->audio_pdev);
f33656e1 802
c44991ce 803 hdmi_uninit_output(hdmi);
45302d7e 804
c44991ce 805 hdmi_pll_uninit(&hdmi->pll);
f5bab222 806
c44991ce 807 pm_runtime_disable(dev);
c84c3a5b 808
c44991ce 809 kfree(hdmi);
736e60dd
TV
810}
811
812static const struct component_ops hdmi5_component_ops = {
813 .bind = hdmi5_bind,
814 .unbind = hdmi5_unbind,
815};
f5bab222 816
736e60dd
TV
817static int hdmi5_probe(struct platform_device *pdev)
818{
819 return component_add(&pdev->dev, &hdmi5_component_ops);
820}
821
822static int hdmi5_remove(struct platform_device *pdev)
823{
824 component_del(&pdev->dev, &hdmi5_component_ops);
f5bab222
TV
825 return 0;
826}
827
828static int hdmi_runtime_suspend(struct device *dev)
829{
50638ae5
LP
830 struct omap_hdmi *hdmi = dev_get_drvdata(dev);
831
832 dispc_runtime_put(hdmi->dss->dispc);
f5bab222
TV
833
834 return 0;
835}
836
837static int hdmi_runtime_resume(struct device *dev)
838{
50638ae5 839 struct omap_hdmi *hdmi = dev_get_drvdata(dev);
f5bab222
TV
840 int r;
841
50638ae5 842 r = dispc_runtime_get(hdmi->dss->dispc);
f5bab222
TV
843 if (r < 0)
844 return r;
845
f5bab222
TV
846 return 0;
847}
848
849static const struct dev_pm_ops hdmi_pm_ops = {
850 .runtime_suspend = hdmi_runtime_suspend,
851 .runtime_resume = hdmi_runtime_resume,
852};
853
854static const struct of_device_id hdmi_of_match[] = {
855 { .compatible = "ti,omap5-hdmi", },
adb5ff83 856 { .compatible = "ti,dra7-hdmi", },
f5bab222
TV
857 {},
858};
859
d66c36a3 860struct platform_driver omapdss_hdmi5hw_driver = {
736e60dd
TV
861 .probe = hdmi5_probe,
862 .remove = hdmi5_remove,
f5bab222
TV
863 .driver = {
864 .name = "omapdss_hdmi5",
f5bab222
TV
865 .pm = &hdmi_pm_ops,
866 .of_match_table = hdmi_of_match,
422ccbd5 867 .suppress_bind_attrs = true,
f5bab222
TV
868 },
869};