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