hdmi5.c (18493B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * HDMI driver for OMAP5 4 * 5 * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ 6 * 7 * Authors: 8 * Yong Zhi 9 * Mythri pk 10 * Archit Taneja <archit@ti.com> 11 * Tomi Valkeinen <tomi.valkeinen@ti.com> 12 */ 13 14#define DSS_SUBSYS_NAME "HDMI" 15 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/err.h> 19#include <linux/io.h> 20#include <linux/interrupt.h> 21#include <linux/mutex.h> 22#include <linux/delay.h> 23#include <linux/string.h> 24#include <linux/platform_device.h> 25#include <linux/pm_runtime.h> 26#include <linux/clk.h> 27#include <linux/regulator/consumer.h> 28#include <linux/component.h> 29#include <linux/of.h> 30#include <linux/of_graph.h> 31#include <sound/omap-hdmi-audio.h> 32 33#include <drm/drm_atomic.h> 34#include <drm/drm_atomic_state_helper.h> 35 36#include "omapdss.h" 37#include "hdmi5_core.h" 38#include "dss.h" 39 40static int hdmi_runtime_get(struct omap_hdmi *hdmi) 41{ 42 int r; 43 44 DSSDBG("hdmi_runtime_get\n"); 45 46 r = pm_runtime_get_sync(&hdmi->pdev->dev); 47 if (WARN_ON(r < 0)) { 48 pm_runtime_put_noidle(&hdmi->pdev->dev); 49 return r; 50 } 51 return 0; 52} 53 54static void hdmi_runtime_put(struct omap_hdmi *hdmi) 55{ 56 int r; 57 58 DSSDBG("hdmi_runtime_put\n"); 59 60 r = pm_runtime_put_sync(&hdmi->pdev->dev); 61 WARN_ON(r < 0 && r != -ENOSYS); 62} 63 64static irqreturn_t hdmi_irq_handler(int irq, void *data) 65{ 66 struct omap_hdmi *hdmi = data; 67 struct hdmi_wp_data *wp = &hdmi->wp; 68 u32 irqstatus; 69 70 irqstatus = hdmi_wp_get_irqstatus(wp); 71 hdmi_wp_set_irqstatus(wp, irqstatus); 72 73 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && 74 irqstatus & HDMI_IRQ_LINK_DISCONNECT) { 75 u32 v; 76 /* 77 * If we get both connect and disconnect interrupts at the same 78 * time, turn off the PHY, clear interrupts, and restart, which 79 * raises connect interrupt if a cable is connected, or nothing 80 * if cable is not connected. 81 */ 82 83 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); 84 85 /* 86 * We always get bogus CONNECT & DISCONNECT interrupts when 87 * setting the PHY to LDOON. To ignore those, we force the RXDET 88 * line to 0 until the PHY power state has been changed. 89 */ 90 v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL); 91 v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */ 92 v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */ 93 hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); 94 95 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | 96 HDMI_IRQ_LINK_DISCONNECT); 97 98 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); 99 100 REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); 101 102 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { 103 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); 104 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { 105 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); 106 } 107 108 return IRQ_HANDLED; 109} 110 111static int hdmi_power_on_core(struct omap_hdmi *hdmi) 112{ 113 int r; 114 115 r = regulator_enable(hdmi->vdda_reg); 116 if (r) 117 return r; 118 119 r = hdmi_runtime_get(hdmi); 120 if (r) 121 goto err_runtime_get; 122 123 /* Make selection of HDMI in DSS */ 124 dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK); 125 126 hdmi->core_enabled = true; 127 128 return 0; 129 130err_runtime_get: 131 regulator_disable(hdmi->vdda_reg); 132 133 return r; 134} 135 136static void hdmi_power_off_core(struct omap_hdmi *hdmi) 137{ 138 hdmi->core_enabled = false; 139 140 hdmi_runtime_put(hdmi); 141 regulator_disable(hdmi->vdda_reg); 142} 143 144static int hdmi_power_on_full(struct omap_hdmi *hdmi) 145{ 146 int r; 147 const struct videomode *vm; 148 struct dss_pll_clock_info hdmi_cinfo = { 0 }; 149 unsigned int pc; 150 151 r = hdmi_power_on_core(hdmi); 152 if (r) 153 return r; 154 155 vm = &hdmi->cfg.vm; 156 157 DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive, 158 vm->vactive); 159 160 pc = vm->pixelclock; 161 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) 162 pc *= 2; 163 164 /* DSS_HDMI_TCLK is bitclk / 10 */ 165 pc *= 10; 166 167 dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin), 168 pc, &hdmi_cinfo); 169 170 /* disable and clear irqs */ 171 hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); 172 hdmi_wp_set_irqstatus(&hdmi->wp, 173 hdmi_wp_get_irqstatus(&hdmi->wp)); 174 175 r = dss_pll_enable(&hdmi->pll.pll); 176 if (r) { 177 DSSERR("Failed to enable PLL\n"); 178 goto err_pll_enable; 179 } 180 181 r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo); 182 if (r) { 183 DSSERR("Failed to configure PLL\n"); 184 goto err_pll_cfg; 185 } 186 187 r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco, 188 hdmi_cinfo.clkout[0]); 189 if (r) { 190 DSSDBG("Failed to start PHY\n"); 191 goto err_phy_cfg; 192 } 193 194 r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON); 195 if (r) 196 goto err_phy_pwr; 197 198 hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); 199 200 r = dss_mgr_enable(&hdmi->output); 201 if (r) 202 goto err_mgr_enable; 203 204 r = hdmi_wp_video_start(&hdmi->wp); 205 if (r) 206 goto err_vid_enable; 207 208 hdmi_wp_set_irqenable(&hdmi->wp, 209 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); 210 211 return 0; 212 213err_vid_enable: 214 dss_mgr_disable(&hdmi->output); 215err_mgr_enable: 216 hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); 217err_phy_pwr: 218err_phy_cfg: 219err_pll_cfg: 220 dss_pll_disable(&hdmi->pll.pll); 221err_pll_enable: 222 hdmi_power_off_core(hdmi); 223 return -EIO; 224} 225 226static void hdmi_power_off_full(struct omap_hdmi *hdmi) 227{ 228 hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); 229 230 hdmi_wp_video_stop(&hdmi->wp); 231 232 dss_mgr_disable(&hdmi->output); 233 234 hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); 235 236 dss_pll_disable(&hdmi->pll.pll); 237 238 hdmi_power_off_core(hdmi); 239} 240 241static int hdmi_dump_regs(struct seq_file *s, void *p) 242{ 243 struct omap_hdmi *hdmi = s->private; 244 245 mutex_lock(&hdmi->lock); 246 247 if (hdmi_runtime_get(hdmi)) { 248 mutex_unlock(&hdmi->lock); 249 return 0; 250 } 251 252 hdmi_wp_dump(&hdmi->wp, s); 253 hdmi_pll_dump(&hdmi->pll, s); 254 hdmi_phy_dump(&hdmi->phy, s); 255 hdmi5_core_dump(&hdmi->core, s); 256 257 hdmi_runtime_put(hdmi); 258 mutex_unlock(&hdmi->lock); 259 return 0; 260} 261 262static void hdmi_start_audio_stream(struct omap_hdmi *hd) 263{ 264 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); 265 hdmi_wp_audio_enable(&hd->wp, true); 266 hdmi_wp_audio_core_req_enable(&hd->wp, true); 267} 268 269static void hdmi_stop_audio_stream(struct omap_hdmi *hd) 270{ 271 hdmi_wp_audio_core_req_enable(&hd->wp, false); 272 hdmi_wp_audio_enable(&hd->wp, false); 273 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); 274} 275 276static int hdmi_core_enable(struct omap_hdmi *hdmi) 277{ 278 int r = 0; 279 280 DSSDBG("ENTER omapdss_hdmi_core_enable\n"); 281 282 mutex_lock(&hdmi->lock); 283 284 r = hdmi_power_on_core(hdmi); 285 if (r) { 286 DSSERR("failed to power on device\n"); 287 goto err0; 288 } 289 290 mutex_unlock(&hdmi->lock); 291 return 0; 292 293err0: 294 mutex_unlock(&hdmi->lock); 295 return r; 296} 297 298static void hdmi_core_disable(struct omap_hdmi *hdmi) 299{ 300 DSSDBG("Enter omapdss_hdmi_core_disable\n"); 301 302 mutex_lock(&hdmi->lock); 303 304 hdmi_power_off_core(hdmi); 305 306 mutex_unlock(&hdmi->lock); 307} 308 309/* ----------------------------------------------------------------------------- 310 * DRM Bridge Operations 311 */ 312 313static int hdmi5_bridge_attach(struct drm_bridge *bridge, 314 enum drm_bridge_attach_flags flags) 315{ 316 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); 317 318 if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) 319 return -EINVAL; 320 321 return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, 322 bridge, flags); 323} 324 325static void hdmi5_bridge_mode_set(struct drm_bridge *bridge, 326 const struct drm_display_mode *mode, 327 const struct drm_display_mode *adjusted_mode) 328{ 329 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); 330 331 mutex_lock(&hdmi->lock); 332 333 drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm); 334 335 dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000); 336 337 mutex_unlock(&hdmi->lock); 338} 339 340static void hdmi5_bridge_enable(struct drm_bridge *bridge, 341 struct drm_bridge_state *bridge_state) 342{ 343 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); 344 struct drm_atomic_state *state = bridge_state->base.state; 345 struct drm_connector_state *conn_state; 346 struct drm_connector *connector; 347 struct drm_crtc_state *crtc_state; 348 unsigned long flags; 349 int ret; 350 351 /* 352 * None of these should fail, as the bridge can't be enabled without a 353 * valid CRTC to connector path with fully populated new states. 354 */ 355 connector = drm_atomic_get_new_connector_for_encoder(state, 356 bridge->encoder); 357 if (WARN_ON(!connector)) 358 return; 359 conn_state = drm_atomic_get_new_connector_state(state, connector); 360 if (WARN_ON(!conn_state)) 361 return; 362 crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); 363 if (WARN_ON(!crtc_state)) 364 return; 365 366 hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi 367 ? HDMI_HDMI : HDMI_DVI; 368 369 if (connector->display_info.is_hdmi) { 370 const struct drm_display_mode *mode; 371 struct hdmi_avi_infoframe avi; 372 373 mode = &crtc_state->adjusted_mode; 374 ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, 375 mode); 376 if (ret == 0) 377 hdmi->cfg.infoframe = avi; 378 } 379 380 mutex_lock(&hdmi->lock); 381 382 ret = hdmi_power_on_full(hdmi); 383 if (ret) { 384 DSSERR("failed to power on device\n"); 385 goto done; 386 } 387 388 if (hdmi->audio_configured) { 389 ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp, 390 &hdmi->audio_config, 391 hdmi->cfg.vm.pixelclock); 392 if (ret) { 393 DSSERR("Error restoring audio configuration: %d", ret); 394 hdmi->audio_abort_cb(&hdmi->pdev->dev); 395 hdmi->audio_configured = false; 396 } 397 } 398 399 spin_lock_irqsave(&hdmi->audio_playing_lock, flags); 400 if (hdmi->audio_configured && hdmi->audio_playing) 401 hdmi_start_audio_stream(hdmi); 402 hdmi->display_enabled = true; 403 spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); 404 405done: 406 mutex_unlock(&hdmi->lock); 407} 408 409static void hdmi5_bridge_disable(struct drm_bridge *bridge, 410 struct drm_bridge_state *bridge_state) 411{ 412 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); 413 unsigned long flags; 414 415 mutex_lock(&hdmi->lock); 416 417 spin_lock_irqsave(&hdmi->audio_playing_lock, flags); 418 hdmi_stop_audio_stream(hdmi); 419 hdmi->display_enabled = false; 420 spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); 421 422 hdmi_power_off_full(hdmi); 423 424 mutex_unlock(&hdmi->lock); 425} 426 427static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, 428 struct drm_connector *connector) 429{ 430 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); 431 struct edid *edid; 432 bool need_enable; 433 int idlemode; 434 int r; 435 436 need_enable = hdmi->core_enabled == false; 437 438 if (need_enable) { 439 r = hdmi_core_enable(hdmi); 440 if (r) 441 return NULL; 442 } 443 444 mutex_lock(&hdmi->lock); 445 r = hdmi_runtime_get(hdmi); 446 BUG_ON(r); 447 448 idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); 449 /* No-idle mode */ 450 REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); 451 452 hdmi5_core_ddc_init(&hdmi->core); 453 454 edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core); 455 456 hdmi5_core_ddc_uninit(&hdmi->core); 457 458 REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); 459 460 hdmi_runtime_put(hdmi); 461 mutex_unlock(&hdmi->lock); 462 463 if (need_enable) 464 hdmi_core_disable(hdmi); 465 466 return (struct edid *)edid; 467} 468 469static const struct drm_bridge_funcs hdmi5_bridge_funcs = { 470 .attach = hdmi5_bridge_attach, 471 .mode_set = hdmi5_bridge_mode_set, 472 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 473 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 474 .atomic_reset = drm_atomic_helper_bridge_reset, 475 .atomic_enable = hdmi5_bridge_enable, 476 .atomic_disable = hdmi5_bridge_disable, 477 .get_edid = hdmi5_bridge_get_edid, 478}; 479 480static void hdmi5_bridge_init(struct omap_hdmi *hdmi) 481{ 482 hdmi->bridge.funcs = &hdmi5_bridge_funcs; 483 hdmi->bridge.of_node = hdmi->pdev->dev.of_node; 484 hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; 485 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 486 487 drm_bridge_add(&hdmi->bridge); 488} 489 490static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi) 491{ 492 drm_bridge_remove(&hdmi->bridge); 493} 494 495/* ----------------------------------------------------------------------------- 496 * Audio Callbacks 497 */ 498 499static int hdmi_audio_startup(struct device *dev, 500 void (*abort_cb)(struct device *dev)) 501{ 502 struct omap_hdmi *hd = dev_get_drvdata(dev); 503 504 mutex_lock(&hd->lock); 505 506 WARN_ON(hd->audio_abort_cb != NULL); 507 508 hd->audio_abort_cb = abort_cb; 509 510 mutex_unlock(&hd->lock); 511 512 return 0; 513} 514 515static int hdmi_audio_shutdown(struct device *dev) 516{ 517 struct omap_hdmi *hd = dev_get_drvdata(dev); 518 519 mutex_lock(&hd->lock); 520 hd->audio_abort_cb = NULL; 521 hd->audio_configured = false; 522 hd->audio_playing = false; 523 mutex_unlock(&hd->lock); 524 525 return 0; 526} 527 528static int hdmi_audio_start(struct device *dev) 529{ 530 struct omap_hdmi *hd = dev_get_drvdata(dev); 531 unsigned long flags; 532 533 spin_lock_irqsave(&hd->audio_playing_lock, flags); 534 535 if (hd->display_enabled) { 536 if (!hdmi_mode_has_audio(&hd->cfg)) 537 DSSERR("%s: Video mode does not support audio\n", 538 __func__); 539 hdmi_start_audio_stream(hd); 540 } 541 hd->audio_playing = true; 542 543 spin_unlock_irqrestore(&hd->audio_playing_lock, flags); 544 return 0; 545} 546 547static void hdmi_audio_stop(struct device *dev) 548{ 549 struct omap_hdmi *hd = dev_get_drvdata(dev); 550 unsigned long flags; 551 552 if (!hdmi_mode_has_audio(&hd->cfg)) 553 DSSERR("%s: Video mode does not support audio\n", __func__); 554 555 spin_lock_irqsave(&hd->audio_playing_lock, flags); 556 557 if (hd->display_enabled) 558 hdmi_stop_audio_stream(hd); 559 hd->audio_playing = false; 560 561 spin_unlock_irqrestore(&hd->audio_playing_lock, flags); 562} 563 564static int hdmi_audio_config(struct device *dev, 565 struct omap_dss_audio *dss_audio) 566{ 567 struct omap_hdmi *hd = dev_get_drvdata(dev); 568 int ret = 0; 569 570 mutex_lock(&hd->lock); 571 572 if (hd->display_enabled) { 573 ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, 574 hd->cfg.vm.pixelclock); 575 if (ret) 576 goto out; 577 } 578 579 hd->audio_configured = true; 580 hd->audio_config = *dss_audio; 581out: 582 mutex_unlock(&hd->lock); 583 584 return ret; 585} 586 587static const struct omap_hdmi_audio_ops hdmi_audio_ops = { 588 .audio_startup = hdmi_audio_startup, 589 .audio_shutdown = hdmi_audio_shutdown, 590 .audio_start = hdmi_audio_start, 591 .audio_stop = hdmi_audio_stop, 592 .audio_config = hdmi_audio_config, 593}; 594 595static int hdmi_audio_register(struct omap_hdmi *hdmi) 596{ 597 struct omap_hdmi_audio_pdata pdata = { 598 .dev = &hdmi->pdev->dev, 599 .version = 5, 600 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp), 601 .ops = &hdmi_audio_ops, 602 }; 603 604 hdmi->audio_pdev = platform_device_register_data( 605 &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, 606 &pdata, sizeof(pdata)); 607 608 if (IS_ERR(hdmi->audio_pdev)) 609 return PTR_ERR(hdmi->audio_pdev); 610 611 hdmi_runtime_get(hdmi); 612 hdmi->wp_idlemode = 613 REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); 614 hdmi_runtime_put(hdmi); 615 616 return 0; 617} 618 619/* ----------------------------------------------------------------------------- 620 * Component Bind & Unbind 621 */ 622 623static int hdmi5_bind(struct device *dev, struct device *master, void *data) 624{ 625 struct dss_device *dss = dss_get_device(master); 626 struct omap_hdmi *hdmi = dev_get_drvdata(dev); 627 int r; 628 629 hdmi->dss = dss; 630 631 r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp); 632 if (r) 633 return r; 634 635 r = hdmi_audio_register(hdmi); 636 if (r) { 637 DSSERR("Registering HDMI audio failed %d\n", r); 638 goto err_pll_uninit; 639 } 640 641 hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, 642 hdmi); 643 644 return 0; 645 646err_pll_uninit: 647 hdmi_pll_uninit(&hdmi->pll); 648 return r; 649} 650 651static void hdmi5_unbind(struct device *dev, struct device *master, void *data) 652{ 653 struct omap_hdmi *hdmi = dev_get_drvdata(dev); 654 655 dss_debugfs_remove_file(hdmi->debugfs); 656 657 if (hdmi->audio_pdev) 658 platform_device_unregister(hdmi->audio_pdev); 659 660 hdmi_pll_uninit(&hdmi->pll); 661} 662 663static const struct component_ops hdmi5_component_ops = { 664 .bind = hdmi5_bind, 665 .unbind = hdmi5_unbind, 666}; 667 668/* ----------------------------------------------------------------------------- 669 * Probe & Remove, Suspend & Resume 670 */ 671 672static int hdmi5_init_output(struct omap_hdmi *hdmi) 673{ 674 struct omap_dss_device *out = &hdmi->output; 675 int r; 676 677 hdmi5_bridge_init(hdmi); 678 679 out->dev = &hdmi->pdev->dev; 680 out->id = OMAP_DSS_OUTPUT_HDMI; 681 out->type = OMAP_DISPLAY_TYPE_HDMI; 682 out->name = "hdmi.0"; 683 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; 684 out->of_port = 0; 685 686 r = omapdss_device_init_output(out, &hdmi->bridge); 687 if (r < 0) { 688 hdmi5_bridge_cleanup(hdmi); 689 return r; 690 } 691 692 omapdss_device_register(out); 693 694 return 0; 695} 696 697static void hdmi5_uninit_output(struct omap_hdmi *hdmi) 698{ 699 struct omap_dss_device *out = &hdmi->output; 700 701 omapdss_device_unregister(out); 702 omapdss_device_cleanup_output(out); 703 704 hdmi5_bridge_cleanup(hdmi); 705} 706 707static int hdmi5_probe_of(struct omap_hdmi *hdmi) 708{ 709 struct platform_device *pdev = hdmi->pdev; 710 struct device_node *node = pdev->dev.of_node; 711 struct device_node *ep; 712 int r; 713 714 ep = of_graph_get_endpoint_by_regs(node, 0, 0); 715 if (!ep) 716 return 0; 717 718 r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); 719 of_node_put(ep); 720 return r; 721} 722 723static int hdmi5_probe(struct platform_device *pdev) 724{ 725 struct omap_hdmi *hdmi; 726 int irq; 727 int r; 728 729 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); 730 if (!hdmi) 731 return -ENOMEM; 732 733 hdmi->pdev = pdev; 734 735 dev_set_drvdata(&pdev->dev, hdmi); 736 737 mutex_init(&hdmi->lock); 738 spin_lock_init(&hdmi->audio_playing_lock); 739 740 r = hdmi5_probe_of(hdmi); 741 if (r) 742 goto err_free; 743 744 r = hdmi_wp_init(pdev, &hdmi->wp, 5); 745 if (r) 746 goto err_free; 747 748 r = hdmi_phy_init(pdev, &hdmi->phy, 5); 749 if (r) 750 goto err_free; 751 752 r = hdmi5_core_init(pdev, &hdmi->core); 753 if (r) 754 goto err_free; 755 756 irq = platform_get_irq(pdev, 0); 757 if (irq < 0) { 758 DSSERR("platform_get_irq failed\n"); 759 r = -ENODEV; 760 goto err_free; 761 } 762 763 r = devm_request_threaded_irq(&pdev->dev, irq, 764 NULL, hdmi_irq_handler, 765 IRQF_ONESHOT, "OMAP HDMI", hdmi); 766 if (r) { 767 DSSERR("HDMI IRQ request failed\n"); 768 goto err_free; 769 } 770 771 hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda"); 772 if (IS_ERR(hdmi->vdda_reg)) { 773 r = PTR_ERR(hdmi->vdda_reg); 774 if (r != -EPROBE_DEFER) 775 DSSERR("can't get VDDA regulator\n"); 776 goto err_free; 777 } 778 779 pm_runtime_enable(&pdev->dev); 780 781 r = hdmi5_init_output(hdmi); 782 if (r) 783 goto err_pm_disable; 784 785 r = component_add(&pdev->dev, &hdmi5_component_ops); 786 if (r) 787 goto err_uninit_output; 788 789 return 0; 790 791err_uninit_output: 792 hdmi5_uninit_output(hdmi); 793err_pm_disable: 794 pm_runtime_disable(&pdev->dev); 795err_free: 796 kfree(hdmi); 797 return r; 798} 799 800static int hdmi5_remove(struct platform_device *pdev) 801{ 802 struct omap_hdmi *hdmi = platform_get_drvdata(pdev); 803 804 component_del(&pdev->dev, &hdmi5_component_ops); 805 806 hdmi5_uninit_output(hdmi); 807 808 pm_runtime_disable(&pdev->dev); 809 810 kfree(hdmi); 811 return 0; 812} 813 814static const struct of_device_id hdmi_of_match[] = { 815 { .compatible = "ti,omap5-hdmi", }, 816 { .compatible = "ti,dra7-hdmi", }, 817 {}, 818}; 819 820struct platform_driver omapdss_hdmi5hw_driver = { 821 .probe = hdmi5_probe, 822 .remove = hdmi5_remove, 823 .driver = { 824 .name = "omapdss_hdmi5", 825 .of_match_table = hdmi_of_match, 826 .suppress_bind_attrs = true, 827 }, 828};