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