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
static int hdmi_connect(struct omap_dss_device *src,
			struct omap_dss_device *dst)
438 439 440
{
	int r;

441
	r = omapdss_device_connect(dst->dss, dst, dst->next);
442
	if (r)
443
		return r;
444

445
	dst->dispc_channel_connected = true;
446 447 448
	return 0;
}

449 450
static void hdmi_disconnect(struct omap_dss_device *src,
			    struct omap_dss_device *dst)
451
{
452 453
	dst->dispc_channel_connected = false;

454
	omapdss_device_disconnect(dst, dst->next);
455 456 457 458 459
}

static int hdmi_read_edid(struct omap_dss_device *dssdev,
		u8 *edid, int len)
{
460
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
461 462 463
	bool need_enable;
	int r;

464
	need_enable = hdmi->core_enabled == false;
465 466

	if (need_enable) {
467
		r = hdmi_core_enable(hdmi);
468 469 470 471
		if (r)
			return r;
	}

472
	r = read_edid(hdmi, edid, len);
473 474

	if (need_enable)
475
		hdmi_core_disable(hdmi);
476 477 478 479

	return r;
}

480 481 482
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
483 484 485
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
486 487 488 489 490 491
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
492 493 494
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
495 496 497
	return 0;
}

498
static const struct omap_dss_device_ops hdmi_ops = {
499 500 501 502 503 504 505 506 507
	.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,

508 509 510 511 512
	.hdmi = {
		.read_edid		= hdmi_read_edid,
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
513 514
};

515 516 517
/* -----------------------------------------------------------------------------
 * Audio Callbacks
 */
518

519 520 521 522 523 524 525
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);

526
	WARN_ON(hd->audio_abort_cb != NULL);
527 528 529 530 531

	hd->audio_abort_cb = abort_cb;

	mutex_unlock(&hd->lock);

532
	return 0;
533 534 535 536 537 538 539 540
}

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;
541 542
	hd->audio_configured = false;
	hd->audio_playing = false;
543 544 545 546 547 548 549 550
	mutex_unlock(&hd->lock);

	return 0;
}

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

553
	spin_lock_irqsave(&hd->audio_playing_lock, flags);
554

555 556 557 558
	if (hd->display_enabled) {
		if (!hdmi_mode_has_audio(&hd->cfg))
			DSSERR("%s: Video mode does not support audio\n",
			       __func__);
559
		hdmi_start_audio_stream(hd);
560
	}
561
	hd->audio_playing = true;
562

563
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
564 565 566 567 568 569
	return 0;
}

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

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

575 576 577 578 579
	spin_lock_irqsave(&hd->audio_playing_lock, flags);

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

581
	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
582 583 584 585 586 587
}

static int hdmi_audio_config(struct device *dev,
			     struct omap_dss_audio *dss_audio)
{
	struct omap_hdmi *hd = dev_get_drvdata(dev);
588
	int ret = 0;
589 590 591

	mutex_lock(&hd->lock);

592 593 594 595 596
	if (hd->display_enabled) {
		ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
					 hd->cfg.vm.pixelclock);
		if (ret)
			goto out;
597 598
	}

599 600
	hd->audio_configured = true;
	hd->audio_config = *dss_audio;
601 602 603 604 605 606 607 608 609 610 611 612 613 614
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,
};

615
static int hdmi_audio_register(struct omap_hdmi *hdmi)
616 617
{
	struct omap_hdmi_audio_pdata pdata = {
618
		.dev = &hdmi->pdev->dev,
619
		.version = 5,
620
		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
621 622 623
		.ops = &hdmi_audio_ops,
	};

624 625
	hdmi->audio_pdev = platform_device_register_data(
		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
626 627
		&pdata, sizeof(pdata));

628 629
	if (IS_ERR(hdmi->audio_pdev))
		return PTR_ERR(hdmi->audio_pdev);
630

631 632 633 634
	hdmi_runtime_get(hdmi);
	hdmi->wp_idlemode =
		REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
	hdmi_runtime_put(hdmi);
635

636 637 638
	return 0;
}

639 640 641 642
/* -----------------------------------------------------------------------------
 * Component Bind & Unbind
 */

T
Tomi Valkeinen 已提交
643
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
644
{
645
	struct dss_device *dss = dss_get_device(master);
646
	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
647
	int r;
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 681 682 683 684 685 686 687 688 689 690 691

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

692
static int hdmi5_init_output(struct omap_hdmi *hdmi)
693 694
{
	struct omap_dss_device *out = &hdmi->output;
695
	int r;
696 697 698 699 700 701 702 703 704 705

	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);

706 707 708 709 710 711 712
	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);
	}

713 714 715 716 717 718 719
	r = omapdss_output_validate(out);
	if (r) {
		omapdss_device_put(out->next);
		out->next = NULL;
		return r;
	}

720
	omapdss_device_register(out);
721 722

	return 0;
723 724 725 726 727 728
}

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

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

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

760
	hdmi->pdev = pdev;
761

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

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

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

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

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

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

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

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

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

806 807
	pm_runtime_enable(&pdev->dev);

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

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

	return 0;
817

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

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

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

833
	hdmi5_uninit_output(hdmi);
834

835
	pm_runtime_disable(&pdev->dev);
836

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

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

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

	return 0;
}

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

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

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