hdmi5.c 18.2 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_power_on_core(struct omap_hdmi *hdmi)
121 122 123
{
	int r;

124
	r = regulator_enable(hdmi->vdda_reg);
125 126 127
	if (r)
		return r;

128
	r = hdmi_runtime_get(hdmi);
129 130 131 132
	if (r)
		goto err_runtime_get;

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

135
	hdmi->core_enabled = true;
136 137 138 139

	return 0;

err_runtime_get:
140
	regulator_disable(hdmi->vdda_reg);
141 142 143 144

	return r;
}

145
static void hdmi_power_off_core(struct omap_hdmi *hdmi)
146
{
147
	hdmi->core_enabled = false;
148

149 150
	hdmi_runtime_put(hdmi);
	regulator_disable(hdmi->vdda_reg);
151 152
}

153
static int hdmi_power_on_full(struct omap_hdmi *hdmi)
154 155
{
	int r;
156
	const struct videomode *vm;
157
	struct dss_pll_clock_info hdmi_cinfo = { 0 };
158
	unsigned int pc;
159

160
	r = hdmi_power_on_core(hdmi);
161 162 163
	if (r)
		return r;

164
	vm = &hdmi->cfg.vm;
165

166 167
	DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
	       vm->vactive);
168

169 170
	pc = vm->pixelclock;
	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
171 172
		pc *= 2;

173 174 175
	/* DSS_HDMI_TCLK is bitclk / 10 */
	pc *= 10;

176
	dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
177
		pc, &hdmi_cinfo);
178 179

	/* disable and clear irqs */
180 181 182
	hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
	hdmi_wp_set_irqstatus(&hdmi->wp,
			hdmi_wp_get_irqstatus(&hdmi->wp));
183

184
	r = dss_pll_enable(&hdmi->pll.pll);
185
	if (r) {
186
		DSSERR("Failed to enable PLL\n");
187 188 189
		goto err_pll_enable;
	}

190
	r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
191 192 193 194 195
	if (r) {
		DSSERR("Failed to configure PLL\n");
		goto err_pll_cfg;
	}

196
	r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
197
		hdmi_cinfo.clkout[0]);
198 199 200 201 202
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_cfg;
	}

203
	r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON);
204 205 206
	if (r)
		goto err_phy_pwr;

207
	hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
208

209
	r = dss_mgr_enable(&hdmi->output);
210 211 212
	if (r)
		goto err_mgr_enable;

213
	r = hdmi_wp_video_start(&hdmi->wp);
214 215 216
	if (r)
		goto err_vid_enable;

217
	hdmi_wp_set_irqenable(&hdmi->wp,
218 219 220 221 222
			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

err_vid_enable:
223
	dss_mgr_disable(&hdmi->output);
224
err_mgr_enable:
225
	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
226 227
err_phy_pwr:
err_phy_cfg:
228
err_pll_cfg:
229
	dss_pll_disable(&hdmi->pll.pll);
230
err_pll_enable:
231
	hdmi_power_off_core(hdmi);
232 233 234
	return -EIO;
}

235
static void hdmi_power_off_full(struct omap_hdmi *hdmi)
236
{
237
	hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
238

239
	hdmi_wp_video_stop(&hdmi->wp);
240

241
	dss_mgr_disable(&hdmi->output);
242

243
	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
244

245
	dss_pll_disable(&hdmi->pll.pll);
246

247
	hdmi_power_off_core(hdmi);
248 249
}

250
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
251
				     const struct videomode *vm)
252
{
253 254 255
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	mutex_lock(&hdmi->lock);
256

257
	hdmi->cfg.vm = *vm;
258

259
	dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
260

261
	mutex_unlock(&hdmi->lock);
262 263
}

264
static int hdmi_dump_regs(struct seq_file *s, void *p)
265
{
266 267 268
	struct omap_hdmi *hdmi = s->private;

	mutex_lock(&hdmi->lock);
269

270 271
	if (hdmi_runtime_get(hdmi)) {
		mutex_unlock(&hdmi->lock);
272
		return 0;
273 274
	}

275 276 277 278
	hdmi_wp_dump(&hdmi->wp, s);
	hdmi_pll_dump(&hdmi->pll, s);
	hdmi_phy_dump(&hdmi->phy, s);
	hdmi5_core_dump(&hdmi->core, s);
279

280 281
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
282
	return 0;
283 284
}

285
static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
286 287 288 289
{
	int r;
	int idlemode;

290
	mutex_lock(&hdmi->lock);
291

292
	r = hdmi_runtime_get(hdmi);
293 294
	BUG_ON(r);

295
	idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
296
	/* No-idle mode */
297
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
298

299
	r = hdmi5_read_edid(&hdmi->core,  buf, len);
300

301
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
302

303 304
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
305 306 307 308

	return r;
}

309 310
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
311
	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
312 313 314 315 316 317 318 319 320 321 322
	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);
}

323 324
static int hdmi_display_enable(struct omap_dss_device *dssdev)
{
325
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
326
	unsigned long flags;
327 328 329 330
	int r = 0;

	DSSDBG("ENTER hdmi_display_enable\n");

331
	mutex_lock(&hdmi->lock);
332

333
	if (!dssdev->dispc_channel_connected) {
334 335 336 337 338
		DSSERR("failed to enable display: no output/manager\n");
		r = -ENODEV;
		goto err0;
	}

339
	r = hdmi_power_on_full(hdmi);
340 341 342 343 344
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

345 346 347 348
	if (hdmi->audio_configured) {
		r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
				       &hdmi->audio_config,
				       hdmi->cfg.vm.pixelclock);
349 350
		if (r) {
			DSSERR("Error restoring audio configuration: %d", r);
351 352
			hdmi->audio_abort_cb(&hdmi->pdev->dev);
			hdmi->audio_configured = false;
353 354 355
		}
	}

356 357 358 359 360
	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);
361

362
	mutex_unlock(&hdmi->lock);
363 364 365
	return 0;

err0:
366
	mutex_unlock(&hdmi->lock);
367 368 369 370 371
	return r;
}

static void hdmi_display_disable(struct omap_dss_device *dssdev)
{
372
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
373 374
	unsigned long flags;

375 376
	DSSDBG("Enter hdmi_display_disable\n");

377
	mutex_lock(&hdmi->lock);
378

379 380 381 382
	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);
383

384
	hdmi_power_off_full(hdmi);
385

386
	mutex_unlock(&hdmi->lock);
387 388
}

389
static int hdmi_core_enable(struct omap_hdmi *hdmi)
390 391 392 393 394
{
	int r = 0;

	DSSDBG("ENTER omapdss_hdmi_core_enable\n");

395
	mutex_lock(&hdmi->lock);
396

397
	r = hdmi_power_on_core(hdmi);
398 399 400 401 402
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

403
	mutex_unlock(&hdmi->lock);
404 405 406
	return 0;

err0:
407
	mutex_unlock(&hdmi->lock);
408 409 410
	return r;
}

411
static void hdmi_core_disable(struct omap_hdmi *hdmi)
412 413 414
{
	DSSDBG("Enter omapdss_hdmi_core_disable\n");

415
	mutex_lock(&hdmi->lock);
416

417
	hdmi_power_off_core(hdmi);
418

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

422 423
static int hdmi_connect(struct omap_dss_device *src,
			struct omap_dss_device *dst)
424 425 426
{
	int r;

427
	r = omapdss_device_connect(dst->dss, dst, dst->next);
428
	if (r)
429
		return r;
430

431
	dst->dispc_channel_connected = true;
432 433 434
	return 0;
}

435 436
static void hdmi_disconnect(struct omap_dss_device *src,
			    struct omap_dss_device *dst)
437
{
438 439
	dst->dispc_channel_connected = false;

440
	omapdss_device_disconnect(dst, dst->next);
441 442 443 444 445
}

static int hdmi_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
446
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
447 448 449
	bool need_enable;
	int r;

450
	need_enable = hdmi->core_enabled == false;
451 452

	if (need_enable) {
453
		r = hdmi_core_enable(hdmi);
454 455 456 457
		if (r)
			return r;
	}

458
	r = read_edid(hdmi, edid, len);
459 460

	if (need_enable)
461
		hdmi_core_disable(hdmi);
462 463 464 465

	return r;
}

466 467 468
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
469 470 471
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
472 473 474 475 476 477
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
478 479 480
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
481 482 483
	return 0;
}

484
static const struct omap_dss_device_ops hdmi_ops = {
485 486 487 488 489 490
	.connect		= hdmi_connect,
	.disconnect		= hdmi_disconnect,

	.enable			= hdmi_display_enable,
	.disable		= hdmi_display_disable,

491
	.set_timings		= hdmi_display_set_timings,
492

493 494
	.read_edid		= hdmi_read_edid,

495 496 497 498
	.hdmi = {
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
499 500
};

501 502 503
/* -----------------------------------------------------------------------------
 * Audio Callbacks
 */
504

505 506 507 508 509 510 511
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);

512
	WARN_ON(hd->audio_abort_cb != NULL);
513 514 515 516 517

	hd->audio_abort_cb = abort_cb;

	mutex_unlock(&hd->lock);

518
	return 0;
519 520 521 522 523 524 525 526
}

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;
527 528
	hd->audio_configured = false;
	hd->audio_playing = false;
529 530 531 532 533 534 535 536
	mutex_unlock(&hd->lock);

	return 0;
}

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

539
	spin_lock_irqsave(&hd->audio_playing_lock, flags);
540

541 542 543 544
	if (hd->display_enabled) {
		if (!hdmi_mode_has_audio(&hd->cfg))
			DSSERR("%s: Video mode does not support audio\n",
			       __func__);
545
		hdmi_start_audio_stream(hd);
546
	}
547
	hd->audio_playing = true;
548

549
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
550 551 552 553 554 555
	return 0;
}

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

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

561 562 563 564 565
	spin_lock_irqsave(&hd->audio_playing_lock, flags);

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

567
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
568 569 570 571 572 573
}

static int hdmi_audio_config(struct device *dev,
			     struct omap_dss_audio *dss_audio)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
574
	int ret = 0;
575 576 577

	mutex_lock(&hd->lock);

578 579 580 581 582
	if (hd->display_enabled) {
		ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
					 hd->cfg.vm.pixelclock);
		if (ret)
			goto out;
583 584
	}

585 586
	hd->audio_configured = true;
	hd->audio_config = *dss_audio;
587 588 589 590 591 592 593 594 595 596 597 598 599 600
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,
};

601
static int hdmi_audio_register(struct omap_hdmi *hdmi)
602 603
{
	struct omap_hdmi_audio_pdata pdata = {
604
		.dev = &hdmi->pdev->dev,
605
		.version = 5,
606
		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
607 608 609
		.ops = &hdmi_audio_ops,
	};

610 611
	hdmi->audio_pdev = platform_device_register_data(
		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
612 613
		&pdata, sizeof(pdata));

614 615
	if (IS_ERR(hdmi->audio_pdev))
		return PTR_ERR(hdmi->audio_pdev);
616

617 618 619 620
	hdmi_runtime_get(hdmi);
	hdmi->wp_idlemode =
		REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
	hdmi_runtime_put(hdmi);
621

622 623 624
	return 0;
}

625 626 627 628
/* -----------------------------------------------------------------------------
 * Component Bind & Unbind
 */

T
Tomi Valkeinen 已提交
629
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
630
{
631
	struct dss_device *dss = dss_get_device(master);
632
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
633
	int r;
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677

	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
 */

678
static int hdmi5_init_output(struct omap_hdmi *hdmi)
679 680
{
	struct omap_dss_device *out = &hdmi->output;
681
	int r;
682 683 684 685 686 687 688 689 690

	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);
691
	out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
692

693 694 695 696 697 698 699
	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);
	}

700 701 702 703 704 705 706
	r = omapdss_output_validate(out);
	if (r) {
		omapdss_device_put(out->next);
		out->next = NULL;
		return r;
	}

707
	omapdss_device_register(out);
708 709

	return 0;
710 711 712 713 714 715
}

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

716 717
	if (out->next)
		omapdss_device_put(out->next);
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
	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;
740
	int irq;
741
	int r;
742

743 744 745
	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
	if (!hdmi)
		return -ENOMEM;
746

747
	hdmi->pdev = pdev;
748

749
	dev_set_drvdata(&pdev->dev, hdmi);
750

751 752 753
	mutex_init(&hdmi->lock);
	spin_lock_init(&hdmi->audio_playing_lock);

754
	r = hdmi5_probe_of(hdmi);
755
	if (r)
756
		goto err_free;
757

758
	r = hdmi_wp_init(pdev, &hdmi->wp, 5);
759
	if (r)
760
		goto err_free;
761

762
	r = hdmi_phy_init(pdev, &hdmi->phy, 5);
763
	if (r)
764
		goto err_free;
765

766
	r = hdmi5_core_init(pdev, &hdmi->core);
767
	if (r)
768
		goto err_free;
769 770 771 772

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		DSSERR("platform_get_irq failed\n");
773
		r = -ENODEV;
774
		goto err_free;
775 776 777 778
	}

	r = devm_request_threaded_irq(&pdev->dev, irq,
			NULL, hdmi_irq_handler,
779
			IRQF_ONESHOT, "OMAP HDMI", hdmi);
780 781
	if (r) {
		DSSERR("HDMI IRQ request failed\n");
782
		goto err_free;
783 784
	}

785 786 787 788 789 790 791 792
	hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
	if (IS_ERR(hdmi->vdda_reg)) {
		r = PTR_ERR(hdmi->vdda_reg);
		if (r != -EPROBE_DEFER)
			DSSERR("can't get VDDA regulator\n");
		goto err_free;
	}

793 794
	pm_runtime_enable(&pdev->dev);

795 796 797
	r = hdmi5_init_output(hdmi);
	if (r)
		goto err_pm_disable;
798

799 800
	r = component_add(&pdev->dev, &hdmi5_component_ops);
	if (r)
801
		goto err_uninit_output;
802 803

	return 0;
804

805
err_uninit_output:
806
	hdmi5_uninit_output(hdmi);
807
err_pm_disable:
808
	pm_runtime_disable(&pdev->dev);
809 810
err_free:
	kfree(hdmi);
811
	return r;
812 813
}

814
static int hdmi5_remove(struct platform_device *pdev)
815
{
816
	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
T
Tomi Valkeinen 已提交
817

818
	component_del(&pdev->dev, &hdmi5_component_ops);
819

820
	hdmi5_uninit_output(hdmi);
821

822
	pm_runtime_disable(&pdev->dev);
823

824
	kfree(hdmi);
825 826 827 828 829
	return 0;
}

static int hdmi_runtime_suspend(struct device *dev)
{
830 831 832
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);

	dispc_runtime_put(hdmi->dss->dispc);
833 834 835 836 837 838

	return 0;
}

static int hdmi_runtime_resume(struct device *dev)
{
839
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
840 841
	int r;

842
	r = dispc_runtime_get(hdmi->dss->dispc);
843 844 845 846 847 848 849 850 851 852 853 854 855
	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", },
856
	{ .compatible = "ti,dra7-hdmi", },
857 858 859
	{},
};

860
struct platform_driver omapdss_hdmi5hw_driver = {
T
Tomi Valkeinen 已提交
861 862
	.probe		= hdmi5_probe,
	.remove		= hdmi5_remove,
863 864 865 866
	.driver         = {
		.name   = "omapdss_hdmi5",
		.pm	= &hdmi_pm_ops,
		.of_match_table = hdmi_of_match,
T
Tomi Valkeinen 已提交
867
		.suppress_bind_attrs = true,
868 869
	},
};