hdmi5.c 18.5 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 int hdmi_display_check_timing(struct omap_dss_device *dssdev,
254
				     struct videomode *vm)
255
{
256 257 258
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
259 260 261 262 263 264
		return -EINVAL;

	return 0;
}

static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
265
				    struct videomode *vm)
266
{
267 268 269
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	mutex_lock(&hdmi->lock);
270

271
	hdmi->cfg.vm = *vm;
272

273
	dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
274

275
	mutex_unlock(&hdmi->lock);
276 277
}

278
static int hdmi_dump_regs(struct seq_file *s, void *p)
279
{
280 281 282
	struct omap_hdmi *hdmi = s->private;

	mutex_lock(&hdmi->lock);
283

284 285
	if (hdmi_runtime_get(hdmi)) {
		mutex_unlock(&hdmi->lock);
286
		return 0;
287 288
	}

289 290 291 292
	hdmi_wp_dump(&hdmi->wp, s);
	hdmi_pll_dump(&hdmi->pll, s);
	hdmi_phy_dump(&hdmi->phy, s);
	hdmi5_core_dump(&hdmi->core, s);
293

294 295
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
296
	return 0;
297 298
}

299
static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
300 301 302 303
{
	int r;
	int idlemode;

304
	mutex_lock(&hdmi->lock);
305

306
	r = hdmi_runtime_get(hdmi);
307 308
	BUG_ON(r);

309
	idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
310
	/* No-idle mode */
311
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
312

313
	r = hdmi5_read_edid(&hdmi->core,  buf, len);
314

315
	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
316

317 318
	hdmi_runtime_put(hdmi);
	mutex_unlock(&hdmi->lock);
319 320 321 322

	return r;
}

323 324
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
325
	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
326 327 328 329 330 331 332 333 334 335 336
	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);
}

337 338
static int hdmi_display_enable(struct omap_dss_device *dssdev)
{
339
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
340
	unsigned long flags;
341 342 343 344
	int r = 0;

	DSSDBG("ENTER hdmi_display_enable\n");

345
	mutex_lock(&hdmi->lock);
346

347
	if (!dssdev->dispc_channel_connected) {
348 349 350 351 352
		DSSERR("failed to enable display: no output/manager\n");
		r = -ENODEV;
		goto err0;
	}

353
	r = hdmi_power_on_full(hdmi);
354 355 356 357 358
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

359 360 361 362
	if (hdmi->audio_configured) {
		r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
				       &hdmi->audio_config,
				       hdmi->cfg.vm.pixelclock);
363 364
		if (r) {
			DSSERR("Error restoring audio configuration: %d", r);
365 366
			hdmi->audio_abort_cb(&hdmi->pdev->dev);
			hdmi->audio_configured = false;
367 368 369
		}
	}

370 371 372 373 374
	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);
375

376
	mutex_unlock(&hdmi->lock);
377 378 379
	return 0;

err0:
380
	mutex_unlock(&hdmi->lock);
381 382 383 384 385
	return r;
}

static void hdmi_display_disable(struct omap_dss_device *dssdev)
{
386
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
387 388
	unsigned long flags;

389 390
	DSSDBG("Enter hdmi_display_disable\n");

391
	mutex_lock(&hdmi->lock);
392

393 394 395 396
	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);
397

398
	hdmi_power_off_full(hdmi);
399

400
	mutex_unlock(&hdmi->lock);
401 402
}

403
static int hdmi_core_enable(struct omap_hdmi *hdmi)
404 405 406 407 408
{
	int r = 0;

	DSSDBG("ENTER omapdss_hdmi_core_enable\n");

409
	mutex_lock(&hdmi->lock);
410

411
	r = hdmi_power_on_core(hdmi);
412 413 414 415 416
	if (r) {
		DSSERR("failed to power on device\n");
		goto err0;
	}

417
	mutex_unlock(&hdmi->lock);
418 419 420
	return 0;

err0:
421
	mutex_unlock(&hdmi->lock);
422 423 424
	return r;
}

425
static void hdmi_core_disable(struct omap_hdmi *hdmi)
426 427 428
{
	DSSDBG("Enter omapdss_hdmi_core_disable\n");

429
	mutex_lock(&hdmi->lock);
430

431
	hdmi_power_off_core(hdmi);
432

433
	mutex_unlock(&hdmi->lock);
434 435 436 437 438 439 440
}

static int hdmi_connect(struct omap_dss_device *dssdev,
		struct omap_dss_device *dst)
{
	int r;

441
	r = dss_mgr_connect(dssdev);
442 443 444 445 446 447 448
	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);
449
		dss_mgr_disconnect(dssdev);
450 451 452 453 454 455 456 457 458 459 460
		return r;
	}

	return 0;
}

static void hdmi_disconnect(struct omap_dss_device *dssdev,
		struct omap_dss_device *dst)
{
	omapdss_output_unset_device(dssdev);

461
	dss_mgr_disconnect(dssdev);
462 463 464 465 466
}

static int hdmi_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
467
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
468 469 470
	bool need_enable;
	int r;

471
	need_enable = hdmi->core_enabled == false;
472 473

	if (need_enable) {
474
		r = hdmi_core_enable(hdmi);
475 476 477 478
		if (r)
			return r;
	}

479
	r = read_edid(hdmi, edid, len);
480 481

	if (need_enable)
482
		hdmi_core_disable(hdmi);
483 484 485 486

	return r;
}

487 488 489
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
490 491 492
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
493 494 495 496 497 498
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
499 500 501
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
502 503 504
	return 0;
}

505
static const struct omap_dss_device_ops hdmi_ops = {
506 507 508 509 510 511 512 513 514
	.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,

515 516 517 518 519
	.hdmi = {
		.read_edid		= hdmi_read_edid,
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
520 521
};

522 523 524
/* -----------------------------------------------------------------------------
 * Audio Callbacks
 */
525

526 527 528 529 530 531 532
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);

533
	WARN_ON(hd->audio_abort_cb != NULL);
534 535 536 537 538

	hd->audio_abort_cb = abort_cb;

	mutex_unlock(&hd->lock);

539
	return 0;
540 541 542 543 544 545 546 547
}

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;
548 549
	hd->audio_configured = false;
	hd->audio_playing = false;
550 551 552 553 554 555 556 557
	mutex_unlock(&hd->lock);

	return 0;
}

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

560
	spin_lock_irqsave(&hd->audio_playing_lock, flags);
561

562 563 564 565
	if (hd->display_enabled) {
		if (!hdmi_mode_has_audio(&hd->cfg))
			DSSERR("%s: Video mode does not support audio\n",
			       __func__);
566
		hdmi_start_audio_stream(hd);
567
	}
568
	hd->audio_playing = true;
569

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

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

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

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

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

588
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
589 590 591 592 593 594
}

static int hdmi_audio_config(struct device *dev,
			     struct omap_dss_audio *dss_audio)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
595
	int ret = 0;
596 597 598

	mutex_lock(&hd->lock);

599 600 601 602 603
	if (hd->display_enabled) {
		ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
					 hd->cfg.vm.pixelclock);
		if (ret)
			goto out;
604 605
	}

606 607
	hd->audio_configured = true;
	hd->audio_config = *dss_audio;
608 609 610 611 612 613 614 615 616 617 618 619 620 621
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,
};

622
static int hdmi_audio_register(struct omap_hdmi *hdmi)
623 624
{
	struct omap_hdmi_audio_pdata pdata = {
625
		.dev = &hdmi->pdev->dev,
626
		.version = 5,
627
		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
628 629 630
		.ops = &hdmi_audio_ops,
	};

631 632
	hdmi->audio_pdev = platform_device_register_data(
		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
633 634
		&pdata, sizeof(pdata));

635 636
	if (IS_ERR(hdmi->audio_pdev))
		return PTR_ERR(hdmi->audio_pdev);
637

638 639 640 641
	hdmi_runtime_get(hdmi);
	hdmi->wp_idlemode =
		REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
	hdmi_runtime_put(hdmi);
642

643 644 645
	return 0;
}

646 647 648 649
/* -----------------------------------------------------------------------------
 * Component Bind & Unbind
 */

T
Tomi Valkeinen 已提交
650
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
651
{
652
	struct dss_device *dss = dss_get_device(master);
653
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
654
	int r;
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 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698

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

699
static int hdmi5_init_output(struct omap_hdmi *hdmi)
700 701 702 703 704 705 706 707 708 709 710 711
{
	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);

712 713 714 715 716 717 718
	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);
	}

719
	omapdss_device_register(out);
720 721

	return 0;
722 723 724 725 726 727
}

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

728 729
	if (out->next)
		omapdss_device_put(out->next);
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
	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;
752
	int irq;
753
	int r;
754

755 756 757
	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
	if (!hdmi)
		return -ENOMEM;
758

759
	hdmi->pdev = pdev;
760

761
	dev_set_drvdata(&pdev->dev, hdmi);
762

763 764 765
	mutex_init(&hdmi->lock);
	spin_lock_init(&hdmi->audio_playing_lock);

766
	r = hdmi5_probe_of(hdmi);
767
	if (r)
768
		goto err_free;
769

770
	r = hdmi_wp_init(pdev, &hdmi->wp, 5);
771
	if (r)
772
		goto err_free;
773

774
	r = hdmi_phy_init(pdev, &hdmi->phy, 5);
775
	if (r)
776
		goto err_free;
777

778
	r = hdmi5_core_init(pdev, &hdmi->core);
779
	if (r)
780
		goto err_free;
781 782 783 784

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		DSSERR("platform_get_irq failed\n");
785
		r = -ENODEV;
786
		goto err_free;
787 788 789 790
	}

	r = devm_request_threaded_irq(&pdev->dev, irq,
			NULL, hdmi_irq_handler,
791
			IRQF_ONESHOT, "OMAP HDMI", hdmi);
792 793
	if (r) {
		DSSERR("HDMI IRQ request failed\n");
794
		goto err_free;
795 796
	}

797 798 799 800 801 802 803 804
	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;
	}

805 806
	pm_runtime_enable(&pdev->dev);

807 808 809
	r = hdmi5_init_output(hdmi);
	if (r)
		goto err_pm_disable;
810

811 812
	r = component_add(&pdev->dev, &hdmi5_component_ops);
	if (r)
813
		goto err_uninit_output;
814 815

	return 0;
816

817
err_uninit_output:
818
	hdmi5_uninit_output(hdmi);
819
err_pm_disable:
820
	pm_runtime_disable(&pdev->dev);
821 822
err_free:
	kfree(hdmi);
823
	return r;
824 825
}

826
static int hdmi5_remove(struct platform_device *pdev)
827
{
828
	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
T
Tomi Valkeinen 已提交
829

830
	component_del(&pdev->dev, &hdmi5_component_ops);
831

832
	hdmi5_uninit_output(hdmi);
833

834
	pm_runtime_disable(&pdev->dev);
835

836
	kfree(hdmi);
837 838 839 840 841
	return 0;
}

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

	dispc_runtime_put(hdmi->dss->dispc);
845 846 847 848 849 850

	return 0;
}

static int hdmi_runtime_resume(struct device *dev)
{
851
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
852 853
	int r;

854
	r = dispc_runtime_get(hdmi->dss->dispc);
855 856 857 858 859 860 861 862 863 864 865 866 867
	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", },
868
	{ .compatible = "ti,dra7-hdmi", },
869 870 871
	{},
};

872
struct platform_driver omapdss_hdmi5hw_driver = {
T
Tomi Valkeinen 已提交
873 874
	.probe		= hdmi5_probe,
	.remove		= hdmi5_remove,
875 876 877 878
	.driver         = {
		.name   = "omapdss_hdmi5",
		.pm	= &hdmi_pm_ops,
		.of_match_table = hdmi_of_match,
T
Tomi Valkeinen 已提交
879
		.suppress_bind_attrs = true,
880 881
	},
};