hdmi5.c 18.3 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
	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

	/* tv size */
210
	dss_mgr_set_timings(&hdmi->output, vm);
211

212
	r = dss_mgr_enable(&hdmi->output);
213 214 215
	if (r)
		goto err_mgr_enable;

216
	r = hdmi_wp_video_start(&hdmi->wp);
217 218 219
	if (r)
		goto err_vid_enable;

220
	hdmi_wp_set_irqenable(&hdmi->wp,
221 222 223 224 225
			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

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

238
static void hdmi_power_off_full(struct omap_hdmi *hdmi)
239
{
240
	hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
241

242
	hdmi_wp_video_stop(&hdmi->wp);
243

244
	dss_mgr_disable(&hdmi->output);
245

246
	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
247

248
	dss_pll_disable(&hdmi->pll.pll);
249

250
	hdmi_power_off_core(hdmi);
251 252
}

253
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
254
				     const struct videomode *vm)
255
{
256 257 258
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	mutex_lock(&hdmi->lock);
259

260
	hdmi->cfg.vm = *vm;
261

262
	dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
263

264
	mutex_unlock(&hdmi->lock);
265 266
}

267
static int hdmi_dump_regs(struct seq_file *s, void *p)
268
{
269 270 271
	struct omap_hdmi *hdmi = s->private;

	mutex_lock(&hdmi->lock);
272

273 274
	if (hdmi_runtime_get(hdmi)) {
		mutex_unlock(&hdmi->lock);
275
		return 0;
276 277
	}

278 279 280 281
	hdmi_wp_dump(&hdmi->wp, s);
	hdmi_pll_dump(&hdmi->pll, s);
	hdmi_phy_dump(&hdmi->phy, s);
	hdmi5_core_dump(&hdmi->core, s);
282

283 284
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
285
	return 0;
286 287
}

288
static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
289 290 291 292
{
	int r;
	int idlemode;

293
	mutex_lock(&hdmi->lock);
294

295
	r = hdmi_runtime_get(hdmi);
296 297
	BUG_ON(r);

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

302
	r = hdmi5_read_edid(&hdmi->core,  buf, len);
303

304
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
305

306 307
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
308 309 310 311

	return r;
}

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

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

	DSSDBG("ENTER hdmi_display_enable\n");

334
	mutex_lock(&hdmi->lock);
335

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

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

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

359 360 361 362 363
	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);
364

365
	mutex_unlock(&hdmi->lock);
366 367 368
	return 0;

err0:
369
	mutex_unlock(&hdmi->lock);
370 371 372 373 374
	return r;
}

static void hdmi_display_disable(struct omap_dss_device *dssdev)
{
375
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
376 377
	unsigned long flags;

378 379
	DSSDBG("Enter hdmi_display_disable\n");

380
	mutex_lock(&hdmi->lock);
381

382 383 384 385
	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);
386

387
	hdmi_power_off_full(hdmi);
388

389
	mutex_unlock(&hdmi->lock);
390 391
}

392
static int hdmi_core_enable(struct omap_hdmi *hdmi)
393 394 395 396 397
{
	int r = 0;

	DSSDBG("ENTER omapdss_hdmi_core_enable\n");

398
	mutex_lock(&hdmi->lock);
399

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

406
	mutex_unlock(&hdmi->lock);
407 408 409
	return 0;

err0:
410
	mutex_unlock(&hdmi->lock);
411 412 413
	return r;
}

414
static void hdmi_core_disable(struct omap_hdmi *hdmi)
415 416 417
{
	DSSDBG("Enter omapdss_hdmi_core_disable\n");

418
	mutex_lock(&hdmi->lock);
419

420
	hdmi_power_off_core(hdmi);
421

422
	mutex_unlock(&hdmi->lock);
423 424
}

425 426
static int hdmi_connect(struct omap_dss_device *src,
			struct omap_dss_device *dst)
427 428 429
{
	int r;

430
	r = omapdss_device_connect(dst->dss, dst, dst->next);
431
	if (r)
432
		return r;
433

434
	dst->dispc_channel_connected = true;
435 436 437
	return 0;
}

438 439
static void hdmi_disconnect(struct omap_dss_device *src,
			    struct omap_dss_device *dst)
440
{
441 442
	dst->dispc_channel_connected = false;

443
	omapdss_device_disconnect(dst, dst->next);
444 445 446 447 448
}

static int hdmi_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
449
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
450 451 452
	bool need_enable;
	int r;

453
	need_enable = hdmi->core_enabled == false;
454 455

	if (need_enable) {
456
		r = hdmi_core_enable(hdmi);
457 458 459 460
		if (r)
			return r;
	}

461
	r = read_edid(hdmi, edid, len);
462 463

	if (need_enable)
464
		hdmi_core_disable(hdmi);
465 466 467 468

	return r;
}

469 470 471
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
472 473 474
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
475 476 477 478 479 480
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
481 482 483
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
484 485 486
	return 0;
}

487
static const struct omap_dss_device_ops hdmi_ops = {
488 489 490 491 492 493
	.connect		= hdmi_connect,
	.disconnect		= hdmi_disconnect,

	.enable			= hdmi_display_enable,
	.disable		= hdmi_display_disable,

494
	.set_timings		= hdmi_display_set_timings,
495

496 497
	.read_edid		= hdmi_read_edid,

498 499 500 501
	.hdmi = {
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
502 503
};

504 505 506
/* -----------------------------------------------------------------------------
 * Audio Callbacks
 */
507

508 509 510 511 512 513 514
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);

515
	WARN_ON(hd->audio_abort_cb != NULL);
516 517 518 519 520

	hd->audio_abort_cb = abort_cb;

	mutex_unlock(&hd->lock);

521
	return 0;
522 523 524 525 526 527 528 529
}

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

	return 0;
}

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

542
	spin_lock_irqsave(&hd->audio_playing_lock, flags);
543

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

552
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
553 554 555 556 557 558
	return 0;
}

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

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

564 565 566 567 568
	spin_lock_irqsave(&hd->audio_playing_lock, flags);

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

570
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
571 572 573 574 575 576
}

static int hdmi_audio_config(struct device *dev,
			     struct omap_dss_audio *dss_audio)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
577
	int ret = 0;
578 579 580

	mutex_lock(&hd->lock);

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

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

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

613 614
	hdmi->audio_pdev = platform_device_register_data(
		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
615 616
		&pdata, sizeof(pdata));

617 618
	if (IS_ERR(hdmi->audio_pdev))
		return PTR_ERR(hdmi->audio_pdev);
619

620 621 622 623
	hdmi_runtime_get(hdmi);
	hdmi->wp_idlemode =
		REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
	hdmi_runtime_put(hdmi);
624

625 626 627
	return 0;
}

628 629 630 631
/* -----------------------------------------------------------------------------
 * Component Bind & Unbind
 */

T
Tomi Valkeinen 已提交
632
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
633
{
634
	struct dss_device *dss = dss_get_device(master);
635
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
636
	int r;
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 678 679 680

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

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

	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);
694
	out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
695

696 697 698 699 700 701 702
	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);
	}

703 704 705 706 707 708 709
	r = omapdss_output_validate(out);
	if (r) {
		omapdss_device_put(out->next);
		out->next = NULL;
		return r;
	}

710
	omapdss_device_register(out);
711 712

	return 0;
713 714 715 716 717 718
}

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

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

746 747 748
	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
	if (!hdmi)
		return -ENOMEM;
749

750
	hdmi->pdev = pdev;
751

752
	dev_set_drvdata(&pdev->dev, hdmi);
753

754 755 756
	mutex_init(&hdmi->lock);
	spin_lock_init(&hdmi->audio_playing_lock);

757
	r = hdmi5_probe_of(hdmi);
758
	if (r)
759
		goto err_free;
760

761
	r = hdmi_wp_init(pdev, &hdmi->wp, 5);
762
	if (r)
763
		goto err_free;
764

765
	r = hdmi_phy_init(pdev, &hdmi->phy, 5);
766
	if (r)
767
		goto err_free;
768

769
	r = hdmi5_core_init(pdev, &hdmi->core);
770
	if (r)
771
		goto err_free;
772 773 774 775

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

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

788 789 790 791 792 793 794 795
	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;
	}

796 797
	pm_runtime_enable(&pdev->dev);

798 799 800
	r = hdmi5_init_output(hdmi);
	if (r)
		goto err_pm_disable;
801

802 803
	r = component_add(&pdev->dev, &hdmi5_component_ops);
	if (r)
804
		goto err_uninit_output;
805 806

	return 0;
807

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

817
static int hdmi5_remove(struct platform_device *pdev)
818
{
819
	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
T
Tomi Valkeinen 已提交
820

821
	component_del(&pdev->dev, &hdmi5_component_ops);
822

823
	hdmi5_uninit_output(hdmi);
824

825
	pm_runtime_disable(&pdev->dev);
826

827
	kfree(hdmi);
828 829 830 831 832
	return 0;
}

static int hdmi_runtime_suspend(struct device *dev)
{
833 834 835
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);

	dispc_runtime_put(hdmi->dss->dispc);
836 837 838 839 840 841

	return 0;
}

static int hdmi_runtime_resume(struct device *dev)
{
842
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
843 844
	int r;

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

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