hdmi5.c 18.8 KB
Newer Older
1 2 3
/*
 * HDMI driver for OMAP5
 *
4
 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
 *
 * Authors:
 *	Yong Zhi
 *	Mythri pk
 *	Archit Taneja <archit@ti.com>
 *	Tomi Valkeinen <tomi.valkeinen@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define DSS_SUBSYS_NAME "HDMI"

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
T
Tomi Valkeinen 已提交
40
#include <linux/component.h>
T
Tomi Valkeinen 已提交
41
#include <linux/of.h>
42
#include <linux/of_graph.h>
43
#include <sound/omap-hdmi-audio.h>
44

45
#include "omapdss.h"
46 47 48
#include "hdmi5_core.h"
#include "dss.h"

49
static int hdmi_runtime_get(struct omap_hdmi *hdmi)
50 51 52 53 54
{
	int r;

	DSSDBG("hdmi_runtime_get\n");

55
	r = pm_runtime_get_sync(&hdmi->pdev->dev);
56 57 58 59 60 61 62
	WARN_ON(r < 0);
	if (r < 0)
		return r;

	return 0;
}

63
static void hdmi_runtime_put(struct omap_hdmi *hdmi)
64 65 66 67 68
{
	int r;

	DSSDBG("hdmi_runtime_put\n");

69
	r = pm_runtime_put_sync(&hdmi->pdev->dev);
70 71 72 73 74
	WARN_ON(r < 0 && r != -ENOSYS);
}

static irqreturn_t hdmi_irq_handler(int irq, void *data)
{
75 76
	struct omap_hdmi *hdmi = data;
	struct hdmi_wp_data *wp = &hdmi->wp;
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	u32 irqstatus;

	irqstatus = hdmi_wp_get_irqstatus(wp);
	hdmi_wp_set_irqstatus(wp, irqstatus);

	if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
			irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
		u32 v;
		/*
		 * If we get both connect and disconnect interrupts at the same
		 * time, turn off the PHY, clear interrupts, and restart, which
		 * raises connect interrupt if a cable is connected, or nothing
		 * if cable is not connected.
		 */

		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);

		/*
		 * We always get bogus CONNECT & DISCONNECT interrupts when
		 * setting the PHY to LDOON. To ignore those, we force the RXDET
		 * line to 0 until the PHY power state has been changed.
		 */
99
		v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
100 101
		v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
		v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
102
		hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
103 104 105 106 107 108

		hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
				HDMI_IRQ_LINK_DISCONNECT);

		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);

109
		REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
110 111 112 113 114 115 116 117 118 119

	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
	}

	return IRQ_HANDLED;
}

120
static int hdmi_init_regulator(struct omap_hdmi *hdmi)
121 122 123
{
	struct regulator *reg;

124
	if (hdmi->vdda_reg != NULL)
125 126
		return 0;

127
	reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
128 129 130 131 132
	if (IS_ERR(reg)) {
		DSSERR("can't get VDDA regulator\n");
		return PTR_ERR(reg);
	}

133
	hdmi->vdda_reg = reg;
134 135 136 137

	return 0;
}

138
static int hdmi_power_on_core(struct omap_hdmi *hdmi)
139 140 141
{
	int r;

142
	r = regulator_enable(hdmi->vdda_reg);
143 144 145
	if (r)
		return r;

146
	r = hdmi_runtime_get(hdmi);
147 148 149 150
	if (r)
		goto err_runtime_get;

	/* Make selection of HDMI in DSS */
151
	dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
152

153
	hdmi->core_enabled = true;
154 155 156 157

	return 0;

err_runtime_get:
158
	regulator_disable(hdmi->vdda_reg);
159 160 161 162

	return r;
}

163
static void hdmi_power_off_core(struct omap_hdmi *hdmi)
164
{
165
	hdmi->core_enabled = false;
166

167 168
	hdmi_runtime_put(hdmi);
	regulator_disable(hdmi->vdda_reg);
169 170
}

171
static int hdmi_power_on_full(struct omap_hdmi *hdmi)
172 173
{
	int r;
174
	struct videomode *vm;
175
	struct dss_pll_clock_info hdmi_cinfo = { 0 };
176
	unsigned int pc;
177

178
	r = hdmi_power_on_core(hdmi);
179 180 181
	if (r)
		return r;

182
	vm = &hdmi->cfg.vm;
183

184 185
	DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
	       vm->vactive);
186

187 188
	pc = vm->pixelclock;
	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
189 190
		pc *= 2;

191 192 193
	/* DSS_HDMI_TCLK is bitclk / 10 */
	pc *= 10;

194
	dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
195
		pc, &hdmi_cinfo);
196 197

	/* disable and clear irqs */
198 199 200
	hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
	hdmi_wp_set_irqstatus(&hdmi->wp,
			hdmi_wp_get_irqstatus(&hdmi->wp));
201

202
	r = dss_pll_enable(&hdmi->pll.pll);
203
	if (r) {
204
		DSSERR("Failed to enable PLL\n");
205 206 207
		goto err_pll_enable;
	}

208
	r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
209 210 211 212 213
	if (r) {
		DSSERR("Failed to configure PLL\n");
		goto err_pll_cfg;
	}

214
	r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
215
		hdmi_cinfo.clkout[0]);
216 217 218 219 220
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_cfg;
	}

221
	r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON);
222 223 224
	if (r)
		goto err_phy_pwr;

225
	hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
226 227

	/* tv size */
228
	dss_mgr_set_timings(&hdmi->output, vm);
229

230
	r = dss_mgr_enable(&hdmi->output);
231 232 233
	if (r)
		goto err_mgr_enable;

234
	r = hdmi_wp_video_start(&hdmi->wp);
235 236 237
	if (r)
		goto err_vid_enable;

238
	hdmi_wp_set_irqenable(&hdmi->wp,
239 240 241 242 243
			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

err_vid_enable:
244
	dss_mgr_disable(&hdmi->output);
245
err_mgr_enable:
246
	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
247 248
err_phy_pwr:
err_phy_cfg:
249
err_pll_cfg:
250
	dss_pll_disable(&hdmi->pll.pll);
251
err_pll_enable:
252
	hdmi_power_off_core(hdmi);
253 254 255
	return -EIO;
}

256
static void hdmi_power_off_full(struct omap_hdmi *hdmi)
257
{
258
	hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
259

260
	hdmi_wp_video_stop(&hdmi->wp);
261

262
	dss_mgr_disable(&hdmi->output);
263

264
	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
265

266
	dss_pll_disable(&hdmi->pll.pll);
267

268
	hdmi_power_off_core(hdmi);
269 270 271
}

static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
272
				     struct videomode *vm)
273
{
274 275 276
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
277 278 279 280 281 282
		return -EINVAL;

	return 0;
}

static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
283
				    struct videomode *vm)
284
{
285 286 287
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	mutex_lock(&hdmi->lock);
288

289
	hdmi->cfg.vm = *vm;
290

291
	dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
292

293
	mutex_unlock(&hdmi->lock);
294 295
}

296
static int hdmi_dump_regs(struct seq_file *s, void *p)
297
{
298 299 300
	struct omap_hdmi *hdmi = s->private;

	mutex_lock(&hdmi->lock);
301

302 303
	if (hdmi_runtime_get(hdmi)) {
		mutex_unlock(&hdmi->lock);
304
		return 0;
305 306
	}

307 308 309 310
	hdmi_wp_dump(&hdmi->wp, s);
	hdmi_pll_dump(&hdmi->pll, s);
	hdmi_phy_dump(&hdmi->phy, s);
	hdmi5_core_dump(&hdmi->core, s);
311

312 313
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
314
	return 0;
315 316
}

317
static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
318 319 320 321
{
	int r;
	int idlemode;

322
	mutex_lock(&hdmi->lock);
323

324
	r = hdmi_runtime_get(hdmi);
325 326
	BUG_ON(r);

327
	idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
328
	/* No-idle mode */
329
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
330

331
	r = hdmi5_read_edid(&hdmi->core,  buf, len);
332

333
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
334

335 336
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
337 338 339 340

	return r;
}

341 342
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
343
	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
344 345 346 347 348 349 350 351 352 353 354
	hdmi_wp_audio_enable(&hd->wp, true);
	hdmi_wp_audio_core_req_enable(&hd->wp, true);
}

static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
{
	hdmi_wp_audio_core_req_enable(&hd->wp, false);
	hdmi_wp_audio_enable(&hd->wp, false);
	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
}

355 356
static int hdmi_display_enable(struct omap_dss_device *dssdev)
{
357
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
358
	unsigned long flags;
359 360 361 362
	int r = 0;

	DSSDBG("ENTER hdmi_display_enable\n");

363
	mutex_lock(&hdmi->lock);
364

365
	if (!dssdev->dispc_channel_connected) {
366 367 368 369 370
		DSSERR("failed to enable display: no output/manager\n");
		r = -ENODEV;
		goto err0;
	}

371
	r = hdmi_power_on_full(hdmi);
372 373 374 375 376
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

377 378 379 380
	if (hdmi->audio_configured) {
		r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
				       &hdmi->audio_config,
				       hdmi->cfg.vm.pixelclock);
381 382
		if (r) {
			DSSERR("Error restoring audio configuration: %d", r);
383 384
			hdmi->audio_abort_cb(&hdmi->pdev->dev);
			hdmi->audio_configured = false;
385 386 387
		}
	}

388 389 390 391 392
	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	if (hdmi->audio_configured && hdmi->audio_playing)
		hdmi_start_audio_stream(hdmi);
	hdmi->display_enabled = true;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
393

394
	mutex_unlock(&hdmi->lock);
395 396 397
	return 0;

err0:
398
	mutex_unlock(&hdmi->lock);
399 400 401 402 403
	return r;
}

static void hdmi_display_disable(struct omap_dss_device *dssdev)
{
404
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
405 406
	unsigned long flags;

407 408
	DSSDBG("Enter hdmi_display_disable\n");

409
	mutex_lock(&hdmi->lock);
410

411 412 413 414
	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	hdmi_stop_audio_stream(hdmi);
	hdmi->display_enabled = false;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
415

416
	hdmi_power_off_full(hdmi);
417

418
	mutex_unlock(&hdmi->lock);
419 420
}

421
static int hdmi_core_enable(struct omap_hdmi *hdmi)
422 423 424 425 426
{
	int r = 0;

	DSSDBG("ENTER omapdss_hdmi_core_enable\n");

427
	mutex_lock(&hdmi->lock);
428

429
	r = hdmi_power_on_core(hdmi);
430 431 432 433 434
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

435
	mutex_unlock(&hdmi->lock);
436 437 438
	return 0;

err0:
439
	mutex_unlock(&hdmi->lock);
440 441 442
	return r;
}

443
static void hdmi_core_disable(struct omap_hdmi *hdmi)
444 445 446
{
	DSSDBG("Enter omapdss_hdmi_core_disable\n");

447
	mutex_lock(&hdmi->lock);
448

449
	hdmi_power_off_core(hdmi);
450

451
	mutex_unlock(&hdmi->lock);
452 453 454 455 456
}

static int hdmi_connect(struct omap_dss_device *dssdev,
		struct omap_dss_device *dst)
{
457
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
458 459
	int r;

460
	r = hdmi_init_regulator(hdmi);
461 462 463
	if (r)
		return r;

464
	r = dss_mgr_connect(&hdmi->output, dssdev);
465 466 467 468 469 470 471
	if (r)
		return r;

	r = omapdss_output_set_device(dssdev, dst);
	if (r) {
		DSSERR("failed to connect output to new device: %s\n",
				dst->name);
472
		dss_mgr_disconnect(&hdmi->output, dssdev);
473 474 475 476 477 478 479 480 481
		return r;
	}

	return 0;
}

static void hdmi_disconnect(struct omap_dss_device *dssdev,
		struct omap_dss_device *dst)
{
482 483
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

484 485
	omapdss_output_unset_device(dssdev);

486
	dss_mgr_disconnect(&hdmi->output, dssdev);
487 488 489 490 491
}

static int hdmi_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
492
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
493 494 495
	bool need_enable;
	int r;

496
	need_enable = hdmi->core_enabled == false;
497 498

	if (need_enable) {
499
		r = hdmi_core_enable(hdmi);
500 501 502 503
		if (r)
			return r;
	}

504
	r = read_edid(hdmi, edid, len);
505 506

	if (need_enable)
507
		hdmi_core_disable(hdmi);
508 509 510 511

	return r;
}

512 513 514
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
515 516 517
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
518 519 520 521 522 523
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
524 525 526
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
527 528 529
	return 0;
}

530
static const struct omap_dss_device_ops hdmi_ops = {
531 532 533 534 535 536 537 538 539
	.connect		= hdmi_connect,
	.disconnect		= hdmi_disconnect,

	.enable			= hdmi_display_enable,
	.disable		= hdmi_display_disable,

	.check_timings		= hdmi_display_check_timing,
	.set_timings		= hdmi_display_set_timing,

540 541 542 543 544
	.hdmi = {
		.read_edid		= hdmi_read_edid,
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
545 546
};

547 548 549
/* -----------------------------------------------------------------------------
 * Audio Callbacks
 */
550

551 552 553 554 555 556 557
static int hdmi_audio_startup(struct device *dev,
			      void (*abort_cb)(struct device *dev))
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);

	mutex_lock(&hd->lock);

558
	WARN_ON(hd->audio_abort_cb != NULL);
559 560 561 562 563

	hd->audio_abort_cb = abort_cb;

	mutex_unlock(&hd->lock);

564
	return 0;
565 566 567 568 569 570 571 572
}

static int hdmi_audio_shutdown(struct device *dev)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);

	mutex_lock(&hd->lock);
	hd->audio_abort_cb = NULL;
573 574
	hd->audio_configured = false;
	hd->audio_playing = false;
575 576 577 578 579 580 581 582
	mutex_unlock(&hd->lock);

	return 0;
}

static int hdmi_audio_start(struct device *dev)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
583
	unsigned long flags;
584

585
	spin_lock_irqsave(&hd->audio_playing_lock, flags);
586

587 588 589 590
	if (hd->display_enabled) {
		if (!hdmi_mode_has_audio(&hd->cfg))
			DSSERR("%s: Video mode does not support audio\n",
			       __func__);
591
		hdmi_start_audio_stream(hd);
592
	}
593
	hd->audio_playing = true;
594

595
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
596 597 598 599 600 601
	return 0;
}

static void hdmi_audio_stop(struct device *dev)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
602
	unsigned long flags;
603

604 605
	if (!hdmi_mode_has_audio(&hd->cfg))
		DSSERR("%s: Video mode does not support audio\n", __func__);
606

607 608 609 610 611
	spin_lock_irqsave(&hd->audio_playing_lock, flags);

	if (hd->display_enabled)
		hdmi_stop_audio_stream(hd);
	hd->audio_playing = false;
612

613
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
614 615 616 617 618 619
}

static int hdmi_audio_config(struct device *dev,
			     struct omap_dss_audio *dss_audio)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
620
	int ret = 0;
621 622 623

	mutex_lock(&hd->lock);

624 625 626 627 628
	if (hd->display_enabled) {
		ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
					 hd->cfg.vm.pixelclock);
		if (ret)
			goto out;
629 630
	}

631 632
	hd->audio_configured = true;
	hd->audio_config = *dss_audio;
633 634 635 636 637 638 639 640 641 642 643 644 645 646
out:
	mutex_unlock(&hd->lock);

	return ret;
}

static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
	.audio_startup = hdmi_audio_startup,
	.audio_shutdown = hdmi_audio_shutdown,
	.audio_start = hdmi_audio_start,
	.audio_stop = hdmi_audio_stop,
	.audio_config = hdmi_audio_config,
};

647
static int hdmi_audio_register(struct omap_hdmi *hdmi)
648 649
{
	struct omap_hdmi_audio_pdata pdata = {
650
		.dev = &hdmi->pdev->dev,
651
		.version = 5,
652
		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
653 654 655
		.ops = &hdmi_audio_ops,
	};

656 657
	hdmi->audio_pdev = platform_device_register_data(
		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
658 659
		&pdata, sizeof(pdata));

660 661
	if (IS_ERR(hdmi->audio_pdev))
		return PTR_ERR(hdmi->audio_pdev);
662

663 664 665 666
	hdmi_runtime_get(hdmi);
	hdmi->wp_idlemode =
		REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
	hdmi_runtime_put(hdmi);
667

668 669 670
	return 0;
}

671 672 673 674
/* -----------------------------------------------------------------------------
 * Component Bind & Unbind
 */

T
Tomi Valkeinen 已提交
675
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
676
{
677
	struct dss_device *dss = dss_get_device(master);
678
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
679
	int r;
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723

	hdmi->dss = dss;

	r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
	if (r)
		return r;

	r = hdmi_audio_register(hdmi);
	if (r) {
		DSSERR("Registering HDMI audio failed %d\n", r);
		goto err_pll_uninit;
	}

	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
						hdmi);

	return 0;

err_pll_uninit:
	hdmi_pll_uninit(&hdmi->pll);
	return r;
}

static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
{
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);

	dss_debugfs_remove_file(hdmi->debugfs);

	if (hdmi->audio_pdev)
		platform_device_unregister(hdmi->audio_pdev);

	hdmi_pll_uninit(&hdmi->pll);
}

static const struct component_ops hdmi5_component_ops = {
	.bind	= hdmi5_bind,
	.unbind	= hdmi5_unbind,
};

/* -----------------------------------------------------------------------------
 * Probe & Remove, Suspend & Resume
 */

724
static int hdmi5_init_output(struct omap_hdmi *hdmi)
725 726 727 728 729 730 731 732 733 734 735 736
{
	struct omap_dss_device *out = &hdmi->output;

	out->dev = &hdmi->pdev->dev;
	out->id = OMAP_DSS_OUTPUT_HDMI;
	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
	out->name = "hdmi.0";
	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
	out->ops = &hdmi_ops;
	out->owner = THIS_MODULE;
	out->of_ports = BIT(0);

737 738 739 740 741 742 743
	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
	if (IS_ERR(out->next)) {
		if (PTR_ERR(out->next) != -EPROBE_DEFER)
			dev_err(out->dev, "failed to find video sink\n");
		return PTR_ERR(out->next);
	}

744
	omapdss_device_register(out);
745 746

	return 0;
747 748 749 750 751 752
}

static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
{
	struct omap_dss_device *out = &hdmi->output;

753 754
	if (out->next)
		omapdss_device_put(out->next);
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
	omapdss_device_unregister(out);
}

static int hdmi5_probe_of(struct omap_hdmi *hdmi)
{
	struct platform_device *pdev = hdmi->pdev;
	struct device_node *node = pdev->dev.of_node;
	struct device_node *ep;
	int r;

	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
	if (!ep)
		return 0;

	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
	of_node_put(ep);
	return r;
}

static int hdmi5_probe(struct platform_device *pdev)
{
	struct omap_hdmi *hdmi;
777
	int irq;
778
	int r;
779

780 781 782
	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
	if (!hdmi)
		return -ENOMEM;
783

784
	hdmi->pdev = pdev;
785

786
	dev_set_drvdata(&pdev->dev, hdmi);
787

788 789 790
	mutex_init(&hdmi->lock);
	spin_lock_init(&hdmi->audio_playing_lock);

791
	r = hdmi5_probe_of(hdmi);
792
	if (r)
793
		goto err_free;
794

795
	r = hdmi_wp_init(pdev, &hdmi->wp, 5);
796
	if (r)
797
		goto err_free;
798

799
	r = hdmi_phy_init(pdev, &hdmi->phy, 5);
800
	if (r)
801
		goto err_free;
802

803
	r = hdmi5_core_init(pdev, &hdmi->core);
804
	if (r)
805
		goto err_free;
806 807 808 809

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		DSSERR("platform_get_irq failed\n");
810
		r = -ENODEV;
811
		goto err_free;
812 813 814 815
	}

	r = devm_request_threaded_irq(&pdev->dev, irq,
			NULL, hdmi_irq_handler,
816
			IRQF_ONESHOT, "OMAP HDMI", hdmi);
817 818
	if (r) {
		DSSERR("HDMI IRQ request failed\n");
819
		goto err_free;
820 821 822 823
	}

	pm_runtime_enable(&pdev->dev);

824 825 826
	r = hdmi5_init_output(hdmi);
	if (r)
		goto err_pm_disable;
827

828 829
	r = component_add(&pdev->dev, &hdmi5_component_ops);
	if (r)
830
		goto err_uninit_output;
831 832

	return 0;
833

834
err_uninit_output:
835
	hdmi5_uninit_output(hdmi);
836
err_pm_disable:
837
	pm_runtime_disable(&pdev->dev);
838 839
err_free:
	kfree(hdmi);
840
	return r;
841 842
}

843
static int hdmi5_remove(struct platform_device *pdev)
844
{
845
	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
T
Tomi Valkeinen 已提交
846

847
	component_del(&pdev->dev, &hdmi5_component_ops);
848

849
	hdmi5_uninit_output(hdmi);
850

851
	pm_runtime_disable(&pdev->dev);
852

853
	kfree(hdmi);
854 855 856 857 858
	return 0;
}

static int hdmi_runtime_suspend(struct device *dev)
{
859 860 861
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);

	dispc_runtime_put(hdmi->dss->dispc);
862 863 864 865 866 867

	return 0;
}

static int hdmi_runtime_resume(struct device *dev)
{
868
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
869 870
	int r;

871
	r = dispc_runtime_get(hdmi->dss->dispc);
872 873 874 875 876 877 878 879 880 881 882 883 884
	if (r < 0)
		return r;

	return 0;
}

static const struct dev_pm_ops hdmi_pm_ops = {
	.runtime_suspend = hdmi_runtime_suspend,
	.runtime_resume = hdmi_runtime_resume,
};

static const struct of_device_id hdmi_of_match[] = {
	{ .compatible = "ti,omap5-hdmi", },
885
	{ .compatible = "ti,dra7-hdmi", },
886 887 888
	{},
};

889
struct platform_driver omapdss_hdmi5hw_driver = {
T
Tomi Valkeinen 已提交
890 891
	.probe		= hdmi5_probe,
	.remove		= hdmi5_remove,
892 893 894 895
	.driver         = {
		.name   = "omapdss_hdmi5",
		.pm	= &hdmi_pm_ops,
		.of_match_table = hdmi_of_match,
T
Tomi Valkeinen 已提交
896
		.suppress_bind_attrs = true,
897 898
	},
};