1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HDMI interface DSS driver for TI's OMAP4 family of SoCs. 4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com/ 5 * Authors: Yong Zhi 6 * Mythri pk <mythripk@ti.com> 7 */ 8 9 #define DSS_SUBSYS_NAME "HDMI" 10 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/err.h> 14 #include <linux/io.h> 15 #include <linux/interrupt.h> 16 #include <linux/mutex.h> 17 #include <linux/delay.h> 18 #include <linux/string.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/clk.h> 22 #include <linux/gpio.h> 23 #include <linux/regulator/consumer.h> 24 #include <linux/component.h> 25 #include <video/omapfb_dss.h> 26 #include <sound/omap-hdmi-audio.h> 27 28 #include "hdmi4_core.h" 29 #include "dss.h" 30 #include "dss_features.h" 31 #include "hdmi.h" 32 33 static struct omap_hdmi hdmi; 34 35 static int hdmi_runtime_get(void) 36 { 37 int r; 38 39 DSSDBG("hdmi_runtime_get\n"); 40 41 r = pm_runtime_get_sync(&hdmi.pdev->dev); 42 if (WARN_ON(r < 0)) { 43 pm_runtime_put_sync(&hdmi.pdev->dev); 44 return r; 45 } 46 47 return 0; 48 } 49 50 static void hdmi_runtime_put(void) 51 { 52 int r; 53 54 DSSDBG("hdmi_runtime_put\n"); 55 56 r = pm_runtime_put_sync(&hdmi.pdev->dev); 57 WARN_ON(r < 0 && r != -ENOSYS); 58 } 59 60 static irqreturn_t hdmi_irq_handler(int irq, void *data) 61 { 62 struct hdmi_wp_data *wp = data; 63 u32 irqstatus; 64 65 irqstatus = hdmi_wp_get_irqstatus(wp); 66 hdmi_wp_set_irqstatus(wp, irqstatus); 67 68 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && 69 irqstatus & HDMI_IRQ_LINK_DISCONNECT) { 70 /* 71 * If we get both connect and disconnect interrupts at the same 72 * time, turn off the PHY, clear interrupts, and restart, which 73 * raises connect interrupt if a cable is connected, or nothing 74 * if cable is not connected. 75 */ 76 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); 77 78 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | 79 HDMI_IRQ_LINK_DISCONNECT); 80 81 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); 82 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { 83 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); 84 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { 85 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); 86 } 87 88 return IRQ_HANDLED; 89 } 90 91 static int hdmi_init_regulator(void) 92 { 93 struct regulator *reg; 94 95 if (hdmi.vdda_reg != NULL) 96 return 0; 97 98 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); 99 100 if (IS_ERR(reg)) { 101 if (PTR_ERR(reg) != -EPROBE_DEFER) 102 DSSERR("can't get VDDA regulator\n"); 103 return PTR_ERR(reg); 104 } 105 106 hdmi.vdda_reg = reg; 107 108 return 0; 109 } 110 111 static int hdmi_power_on_core(struct omap_dss_device *dssdev) 112 { 113 int r; 114 115 r = regulator_enable(hdmi.vdda_reg); 116 if (r) 117 return r; 118 119 r = hdmi_runtime_get(); 120 if (r) 121 goto err_runtime_get; 122 123 /* Make selection of HDMI in DSS */ 124 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); 125 126 hdmi.core_enabled = true; 127 128 return 0; 129 130 err_runtime_get: 131 regulator_disable(hdmi.vdda_reg); 132 133 return r; 134 } 135 136 static void hdmi_power_off_core(struct omap_dss_device *dssdev) 137 { 138 hdmi.core_enabled = false; 139 140 hdmi_runtime_put(); 141 regulator_disable(hdmi.vdda_reg); 142 } 143 144 static int hdmi_power_on_full(struct omap_dss_device *dssdev) 145 { 146 int r; 147 struct omap_video_timings *p; 148 struct omap_overlay_manager *mgr = hdmi.output.manager; 149 struct hdmi_wp_data *wp = &hdmi.wp; 150 struct dss_pll_clock_info hdmi_cinfo = { 0 }; 151 152 r = hdmi_power_on_core(dssdev); 153 if (r) 154 return r; 155 156 /* disable and clear irqs */ 157 hdmi_wp_clear_irqenable(wp, 0xffffffff); 158 hdmi_wp_set_irqstatus(wp, 0xffffffff); 159 160 p = &hdmi.cfg.timings; 161 162 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); 163 164 hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo); 165 166 r = dss_pll_enable(&hdmi.pll.pll); 167 if (r) { 168 DSSERR("Failed to enable PLL\n"); 169 goto err_pll_enable; 170 } 171 172 r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); 173 if (r) { 174 DSSERR("Failed to configure PLL\n"); 175 goto err_pll_cfg; 176 } 177 178 r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, 179 hdmi_cinfo.clkout[0]); 180 if (r) { 181 DSSDBG("Failed to configure PHY\n"); 182 goto err_phy_cfg; 183 } 184 185 r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); 186 if (r) 187 goto err_phy_pwr; 188 189 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); 190 191 /* bypass TV gamma table */ 192 dispc_enable_gamma_table(0); 193 194 /* tv size */ 195 dss_mgr_set_timings(mgr, p); 196 197 r = hdmi_wp_video_start(&hdmi.wp); 198 if (r) 199 goto err_vid_enable; 200 201 r = dss_mgr_enable(mgr); 202 if (r) 203 goto err_mgr_enable; 204 205 hdmi_wp_set_irqenable(wp, 206 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); 207 208 return 0; 209 210 err_mgr_enable: 211 hdmi_wp_video_stop(&hdmi.wp); 212 err_vid_enable: 213 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); 214 err_phy_pwr: 215 err_phy_cfg: 216 err_pll_cfg: 217 dss_pll_disable(&hdmi.pll.pll); 218 err_pll_enable: 219 hdmi_power_off_core(dssdev); 220 return -EIO; 221 } 222 223 static void hdmi_power_off_full(struct omap_dss_device *dssdev) 224 { 225 struct omap_overlay_manager *mgr = hdmi.output.manager; 226 227 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); 228 229 dss_mgr_disable(mgr); 230 231 hdmi_wp_video_stop(&hdmi.wp); 232 233 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); 234 235 dss_pll_disable(&hdmi.pll.pll); 236 237 hdmi_power_off_core(dssdev); 238 } 239 240 static int hdmi_display_check_timing(struct omap_dss_device *dssdev, 241 struct omap_video_timings *timings) 242 { 243 struct omap_dss_device *out = &hdmi.output; 244 245 if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) 246 return -EINVAL; 247 248 return 0; 249 } 250 251 static void hdmi_display_set_timing(struct omap_dss_device *dssdev, 252 struct omap_video_timings *timings) 253 { 254 mutex_lock(&hdmi.lock); 255 256 hdmi.cfg.timings = *timings; 257 258 dispc_set_tv_pclk(timings->pixelclock); 259 260 mutex_unlock(&hdmi.lock); 261 } 262 263 static void hdmi_display_get_timings(struct omap_dss_device *dssdev, 264 struct omap_video_timings *timings) 265 { 266 *timings = hdmi.cfg.timings; 267 } 268 269 static void hdmi_dump_regs(struct seq_file *s) 270 { 271 mutex_lock(&hdmi.lock); 272 273 if (hdmi_runtime_get()) { 274 mutex_unlock(&hdmi.lock); 275 return; 276 } 277 278 hdmi_wp_dump(&hdmi.wp, s); 279 hdmi_pll_dump(&hdmi.pll, s); 280 hdmi_phy_dump(&hdmi.phy, s); 281 hdmi4_core_dump(&hdmi.core, s); 282 283 hdmi_runtime_put(); 284 mutex_unlock(&hdmi.lock); 285 } 286 287 static int read_edid(u8 *buf, int len) 288 { 289 int r; 290 291 mutex_lock(&hdmi.lock); 292 293 r = hdmi_runtime_get(); 294 BUG_ON(r); 295 296 r = hdmi4_read_edid(&hdmi.core, buf, len); 297 298 hdmi_runtime_put(); 299 mutex_unlock(&hdmi.lock); 300 301 return r; 302 } 303 304 static void hdmi_start_audio_stream(struct omap_hdmi *hd) 305 { 306 hdmi_wp_audio_enable(&hd->wp, true); 307 hdmi4_audio_start(&hd->core, &hd->wp); 308 } 309 310 static void hdmi_stop_audio_stream(struct omap_hdmi *hd) 311 { 312 hdmi4_audio_stop(&hd->core, &hd->wp); 313 hdmi_wp_audio_enable(&hd->wp, false); 314 } 315 316 static int hdmi_display_enable(struct omap_dss_device *dssdev) 317 { 318 struct omap_dss_device *out = &hdmi.output; 319 unsigned long flags; 320 int r = 0; 321 322 DSSDBG("ENTER hdmi_display_enable\n"); 323 324 mutex_lock(&hdmi.lock); 325 326 if (out->manager == NULL) { 327 DSSERR("failed to enable display: no output/manager\n"); 328 r = -ENODEV; 329 goto err0; 330 } 331 332 r = hdmi_power_on_full(dssdev); 333 if (r) { 334 DSSERR("failed to power on device\n"); 335 goto err0; 336 } 337 338 if (hdmi.audio_configured) { 339 r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, 340 hdmi.cfg.timings.pixelclock); 341 if (r) { 342 DSSERR("Error restoring audio configuration: %d", r); 343 hdmi.audio_abort_cb(&hdmi.pdev->dev); 344 hdmi.audio_configured = false; 345 } 346 } 347 348 spin_lock_irqsave(&hdmi.audio_playing_lock, flags); 349 if (hdmi.audio_configured && hdmi.audio_playing) 350 hdmi_start_audio_stream(&hdmi); 351 hdmi.display_enabled = true; 352 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); 353 354 mutex_unlock(&hdmi.lock); 355 return 0; 356 357 err0: 358 mutex_unlock(&hdmi.lock); 359 return r; 360 } 361 362 static void hdmi_display_disable(struct omap_dss_device *dssdev) 363 { 364 unsigned long flags; 365 366 DSSDBG("Enter hdmi_display_disable\n"); 367 368 mutex_lock(&hdmi.lock); 369 370 spin_lock_irqsave(&hdmi.audio_playing_lock, flags); 371 hdmi_stop_audio_stream(&hdmi); 372 hdmi.display_enabled = false; 373 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); 374 375 hdmi_power_off_full(dssdev); 376 377 mutex_unlock(&hdmi.lock); 378 } 379 380 static int hdmi_core_enable(struct omap_dss_device *dssdev) 381 { 382 int r = 0; 383 384 DSSDBG("ENTER omapdss_hdmi_core_enable\n"); 385 386 mutex_lock(&hdmi.lock); 387 388 r = hdmi_power_on_core(dssdev); 389 if (r) { 390 DSSERR("failed to power on device\n"); 391 goto err0; 392 } 393 394 mutex_unlock(&hdmi.lock); 395 return 0; 396 397 err0: 398 mutex_unlock(&hdmi.lock); 399 return r; 400 } 401 402 static void hdmi_core_disable(struct omap_dss_device *dssdev) 403 { 404 DSSDBG("Enter omapdss_hdmi_core_disable\n"); 405 406 mutex_lock(&hdmi.lock); 407 408 hdmi_power_off_core(dssdev); 409 410 mutex_unlock(&hdmi.lock); 411 } 412 413 static int hdmi_connect(struct omap_dss_device *dssdev, 414 struct omap_dss_device *dst) 415 { 416 struct omap_overlay_manager *mgr; 417 int r; 418 419 r = hdmi_init_regulator(); 420 if (r) 421 return r; 422 423 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); 424 if (!mgr) 425 return -ENODEV; 426 427 r = dss_mgr_connect(mgr, dssdev); 428 if (r) 429 return r; 430 431 r = omapdss_output_set_device(dssdev, dst); 432 if (r) { 433 DSSERR("failed to connect output to new device: %s\n", 434 dst->name); 435 dss_mgr_disconnect(mgr, dssdev); 436 return r; 437 } 438 439 return 0; 440 } 441 442 static void hdmi_disconnect(struct omap_dss_device *dssdev, 443 struct omap_dss_device *dst) 444 { 445 WARN_ON(dst != dssdev->dst); 446 447 if (dst != dssdev->dst) 448 return; 449 450 omapdss_output_unset_device(dssdev); 451 452 if (dssdev->manager) 453 dss_mgr_disconnect(dssdev->manager, dssdev); 454 } 455 456 static int hdmi_read_edid(struct omap_dss_device *dssdev, 457 u8 *edid, int len) 458 { 459 bool need_enable = !hdmi.core_enabled; 460 int r; 461 462 if (need_enable) { 463 r = hdmi_core_enable(dssdev); 464 if (r) 465 return r; 466 } 467 468 r = read_edid(edid, len); 469 470 if (need_enable) 471 hdmi_core_disable(dssdev); 472 473 return r; 474 } 475 476 static int hdmi_set_infoframe(struct omap_dss_device *dssdev, 477 const struct hdmi_avi_infoframe *avi) 478 { 479 hdmi.cfg.infoframe = *avi; 480 return 0; 481 } 482 483 static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, 484 bool hdmi_mode) 485 { 486 hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; 487 return 0; 488 } 489 490 static const struct omapdss_hdmi_ops hdmi_ops = { 491 .connect = hdmi_connect, 492 .disconnect = hdmi_disconnect, 493 494 .enable = hdmi_display_enable, 495 .disable = hdmi_display_disable, 496 497 .check_timings = hdmi_display_check_timing, 498 .set_timings = hdmi_display_set_timing, 499 .get_timings = hdmi_display_get_timings, 500 501 .read_edid = hdmi_read_edid, 502 .set_infoframe = hdmi_set_infoframe, 503 .set_hdmi_mode = hdmi_set_hdmi_mode, 504 }; 505 506 static void hdmi_init_output(struct platform_device *pdev) 507 { 508 struct omap_dss_device *out = &hdmi.output; 509 510 out->dev = &pdev->dev; 511 out->id = OMAP_DSS_OUTPUT_HDMI; 512 out->output_type = OMAP_DISPLAY_TYPE_HDMI; 513 out->name = "hdmi.0"; 514 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; 515 out->ops.hdmi = &hdmi_ops; 516 out->owner = THIS_MODULE; 517 518 omapdss_register_output(out); 519 } 520 521 static void hdmi_uninit_output(struct platform_device *pdev) 522 { 523 struct omap_dss_device *out = &hdmi.output; 524 525 omapdss_unregister_output(out); 526 } 527 528 static int hdmi_probe_of(struct platform_device *pdev) 529 { 530 struct device_node *node = pdev->dev.of_node; 531 struct device_node *ep; 532 int r; 533 534 ep = omapdss_of_get_first_endpoint(node); 535 if (!ep) 536 return 0; 537 538 r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); 539 if (r) 540 goto err; 541 542 of_node_put(ep); 543 return 0; 544 545 err: 546 of_node_put(ep); 547 return r; 548 } 549 550 /* Audio callbacks */ 551 static int hdmi_audio_startup(struct device *dev, 552 void (*abort_cb)(struct device *dev)) 553 { 554 struct omap_hdmi *hd = dev_get_drvdata(dev); 555 int ret = 0; 556 557 mutex_lock(&hd->lock); 558 559 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { 560 ret = -EPERM; 561 goto out; 562 } 563 564 hd->audio_abort_cb = abort_cb; 565 566 out: 567 mutex_unlock(&hd->lock); 568 569 return ret; 570 } 571 572 static int hdmi_audio_shutdown(struct device *dev) 573 { 574 struct omap_hdmi *hd = dev_get_drvdata(dev); 575 576 mutex_lock(&hd->lock); 577 hd->audio_abort_cb = NULL; 578 hd->audio_configured = false; 579 hd->audio_playing = false; 580 mutex_unlock(&hd->lock); 581 582 return 0; 583 } 584 585 static int hdmi_audio_start(struct device *dev) 586 { 587 struct omap_hdmi *hd = dev_get_drvdata(dev); 588 unsigned long flags; 589 590 WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); 591 592 spin_lock_irqsave(&hd->audio_playing_lock, flags); 593 594 if (hd->display_enabled) 595 hdmi_start_audio_stream(hd); 596 hd->audio_playing = true; 597 598 spin_unlock_irqrestore(&hd->audio_playing_lock, flags); 599 return 0; 600 } 601 602 static void hdmi_audio_stop(struct device *dev) 603 { 604 struct omap_hdmi *hd = dev_get_drvdata(dev); 605 unsigned long flags; 606 607 WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); 608 609 spin_lock_irqsave(&hd->audio_playing_lock, flags); 610 611 if (hd->display_enabled) 612 hdmi_stop_audio_stream(hd); 613 hd->audio_playing = false; 614 615 spin_unlock_irqrestore(&hd->audio_playing_lock, flags); 616 } 617 618 static int hdmi_audio_config(struct device *dev, 619 struct omap_dss_audio *dss_audio) 620 { 621 struct omap_hdmi *hd = dev_get_drvdata(dev); 622 int ret; 623 624 mutex_lock(&hd->lock); 625 626 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { 627 ret = -EPERM; 628 goto out; 629 } 630 631 ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, 632 hd->cfg.timings.pixelclock); 633 if (!ret) { 634 hd->audio_configured = true; 635 hd->audio_config = *dss_audio; 636 } 637 out: 638 mutex_unlock(&hd->lock); 639 640 return ret; 641 } 642 643 static const struct omap_hdmi_audio_ops hdmi_audio_ops = { 644 .audio_startup = hdmi_audio_startup, 645 .audio_shutdown = hdmi_audio_shutdown, 646 .audio_start = hdmi_audio_start, 647 .audio_stop = hdmi_audio_stop, 648 .audio_config = hdmi_audio_config, 649 }; 650 651 static int hdmi_audio_register(struct device *dev) 652 { 653 struct omap_hdmi_audio_pdata pdata = { 654 .dev = dev, 655 .version = 4, 656 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), 657 .ops = &hdmi_audio_ops, 658 }; 659 660 hdmi.audio_pdev = platform_device_register_data( 661 dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, 662 &pdata, sizeof(pdata)); 663 664 return PTR_ERR_OR_ZERO(hdmi.audio_pdev); 665 } 666 667 /* HDMI HW IP initialisation */ 668 static int hdmi4_bind(struct device *dev, struct device *master, void *data) 669 { 670 struct platform_device *pdev = to_platform_device(dev); 671 int r; 672 int irq; 673 674 hdmi.pdev = pdev; 675 dev_set_drvdata(&pdev->dev, &hdmi); 676 677 mutex_init(&hdmi.lock); 678 spin_lock_init(&hdmi.audio_playing_lock); 679 680 if (pdev->dev.of_node) { 681 r = hdmi_probe_of(pdev); 682 if (r) 683 return r; 684 } 685 686 r = hdmi_wp_init(pdev, &hdmi.wp); 687 if (r) 688 return r; 689 690 r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); 691 if (r) 692 return r; 693 694 r = hdmi_phy_init(pdev, &hdmi.phy); 695 if (r) 696 goto err; 697 698 r = hdmi4_core_init(pdev, &hdmi.core); 699 if (r) 700 goto err; 701 702 irq = platform_get_irq(pdev, 0); 703 if (irq < 0) { 704 DSSERR("platform_get_irq failed\n"); 705 r = -ENODEV; 706 goto err; 707 } 708 709 r = devm_request_threaded_irq(&pdev->dev, irq, 710 NULL, hdmi_irq_handler, 711 IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); 712 if (r) { 713 DSSERR("HDMI IRQ request failed\n"); 714 goto err; 715 } 716 717 pm_runtime_enable(&pdev->dev); 718 719 hdmi_init_output(pdev); 720 721 r = hdmi_audio_register(&pdev->dev); 722 if (r) { 723 DSSERR("Registering HDMI audio failed\n"); 724 hdmi_uninit_output(pdev); 725 pm_runtime_disable(&pdev->dev); 726 return r; 727 } 728 729 dss_debugfs_create_file("hdmi", hdmi_dump_regs); 730 731 return 0; 732 err: 733 hdmi_pll_uninit(&hdmi.pll); 734 return r; 735 } 736 737 static void hdmi4_unbind(struct device *dev, struct device *master, void *data) 738 { 739 struct platform_device *pdev = to_platform_device(dev); 740 741 if (hdmi.audio_pdev) 742 platform_device_unregister(hdmi.audio_pdev); 743 744 hdmi_uninit_output(pdev); 745 746 hdmi_pll_uninit(&hdmi.pll); 747 748 pm_runtime_disable(&pdev->dev); 749 } 750 751 static const struct component_ops hdmi4_component_ops = { 752 .bind = hdmi4_bind, 753 .unbind = hdmi4_unbind, 754 }; 755 756 static int hdmi4_probe(struct platform_device *pdev) 757 { 758 return component_add(&pdev->dev, &hdmi4_component_ops); 759 } 760 761 static int hdmi4_remove(struct platform_device *pdev) 762 { 763 component_del(&pdev->dev, &hdmi4_component_ops); 764 return 0; 765 } 766 767 static int hdmi_runtime_suspend(struct device *dev) 768 { 769 dispc_runtime_put(); 770 771 return 0; 772 } 773 774 static int hdmi_runtime_resume(struct device *dev) 775 { 776 int r; 777 778 r = dispc_runtime_get(); 779 if (r < 0) 780 return r; 781 782 return 0; 783 } 784 785 static const struct dev_pm_ops hdmi_pm_ops = { 786 .runtime_suspend = hdmi_runtime_suspend, 787 .runtime_resume = hdmi_runtime_resume, 788 }; 789 790 static const struct of_device_id hdmi_of_match[] = { 791 { .compatible = "ti,omap4-hdmi", }, 792 {}, 793 }; 794 795 static struct platform_driver omapdss_hdmihw_driver = { 796 .probe = hdmi4_probe, 797 .remove = hdmi4_remove, 798 .driver = { 799 .name = "omapdss_hdmi", 800 .pm = &hdmi_pm_ops, 801 .of_match_table = hdmi_of_match, 802 .suppress_bind_attrs = true, 803 }, 804 }; 805 806 int __init hdmi4_init_platform_driver(void) 807 { 808 return platform_driver_register(&omapdss_hdmihw_driver); 809 } 810 811 void hdmi4_uninit_platform_driver(void) 812 { 813 platform_driver_unregister(&omapdss_hdmihw_driver); 814 } 815