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/omapdss.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        int r;
 123        struct regulator *reg;
 124
 125        if (hdmi.vdda_reg != NULL)
 126                return 0;
 127
 128        reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
 129        if (IS_ERR(reg)) {
 130                DSSERR("can't get VDDA regulator\n");
 131                return PTR_ERR(reg);
 132        }
 133
 134        if (regulator_can_change_voltage(reg)) {
 135                r = regulator_set_voltage(reg, 1800000, 1800000);
 136                if (r) {
 137                        devm_regulator_put(reg);
 138                        DSSWARN("can't set the regulator voltage\n");
 139                        return r;
 140                }
 141        }
 142
 143        hdmi.vdda_reg = reg;
 144
 145        return 0;
 146}
 147
 148static int hdmi_power_on_core(struct omap_dss_device *dssdev)
 149{
 150        int r;
 151
 152        r = regulator_enable(hdmi.vdda_reg);
 153        if (r)
 154                return r;
 155
 156        r = hdmi_runtime_get();
 157        if (r)
 158                goto err_runtime_get;
 159
 160        /* Make selection of HDMI in DSS */
 161        dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
 162
 163        hdmi.core_enabled = true;
 164
 165        return 0;
 166
 167err_runtime_get:
 168        regulator_disable(hdmi.vdda_reg);
 169
 170        return r;
 171}
 172
 173static void hdmi_power_off_core(struct omap_dss_device *dssdev)
 174{
 175        hdmi.core_enabled = false;
 176
 177        hdmi_runtime_put();
 178        regulator_disable(hdmi.vdda_reg);
 179}
 180
 181static int hdmi_power_on_full(struct omap_dss_device *dssdev)
 182{
 183        int r;
 184        struct omap_video_timings *p;
 185        struct omap_overlay_manager *mgr = hdmi.output.manager;
 186        struct dss_pll_clock_info hdmi_cinfo = { 0 };
 187
 188        r = hdmi_power_on_core(dssdev);
 189        if (r)
 190                return r;
 191
 192        p = &hdmi.cfg.timings;
 193
 194        DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
 195
 196        hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
 197
 198        /* disable and clear irqs */
 199        hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
 200        hdmi_wp_set_irqstatus(&hdmi.wp,
 201                        hdmi_wp_get_irqstatus(&hdmi.wp));
 202
 203        r = dss_pll_enable(&hdmi.pll.pll);
 204        if (r) {
 205                DSSERR("Failed to enable PLL\n");
 206                goto err_pll_enable;
 207        }
 208
 209        r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
 210        if (r) {
 211                DSSERR("Failed to configure PLL\n");
 212                goto err_pll_cfg;
 213        }
 214
 215        r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
 216                hdmi_cinfo.clkout[0]);
 217        if (r) {
 218                DSSDBG("Failed to start PHY\n");
 219                goto err_phy_cfg;
 220        }
 221
 222        r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
 223        if (r)
 224                goto err_phy_pwr;
 225
 226        hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
 227
 228        /* bypass TV gamma table */
 229        dispc_enable_gamma_table(0);
 230
 231        /* tv size */
 232        dss_mgr_set_timings(mgr, p);
 233
 234        r = hdmi_wp_video_start(&hdmi.wp);
 235        if (r)
 236                goto err_vid_enable;
 237
 238        r = dss_mgr_enable(mgr);
 239        if (r)
 240                goto err_mgr_enable;
 241
 242        hdmi_wp_set_irqenable(&hdmi.wp,
 243                        HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
 244
 245        return 0;
 246
 247err_mgr_enable:
 248        hdmi_wp_video_stop(&hdmi.wp);
 249err_vid_enable:
 250        hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 251err_phy_pwr:
 252err_phy_cfg:
 253err_pll_cfg:
 254        dss_pll_disable(&hdmi.pll.pll);
 255err_pll_enable:
 256        hdmi_power_off_core(dssdev);
 257        return -EIO;
 258}
 259
 260static void hdmi_power_off_full(struct omap_dss_device *dssdev)
 261{
 262        struct omap_overlay_manager *mgr = hdmi.output.manager;
 263
 264        hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
 265
 266        dss_mgr_disable(mgr);
 267
 268        hdmi_wp_video_stop(&hdmi.wp);
 269
 270        hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 271
 272        dss_pll_disable(&hdmi.pll.pll);
 273
 274        hdmi_power_off_core(dssdev);
 275}
 276
 277static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
 278                                        struct omap_video_timings *timings)
 279{
 280        struct omap_dss_device *out = &hdmi.output;
 281
 282        /* TODO: proper interlace support */
 283        if (timings->interlace)
 284                return -EINVAL;
 285
 286        if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
 287                return -EINVAL;
 288
 289        return 0;
 290}
 291
 292static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
 293                struct omap_video_timings *timings)
 294{
 295        mutex_lock(&hdmi.lock);
 296
 297        hdmi.cfg.timings = *timings;
 298
 299        dispc_set_tv_pclk(timings->pixelclock);
 300
 301        mutex_unlock(&hdmi.lock);
 302}
 303
 304static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
 305                struct omap_video_timings *timings)
 306{
 307        *timings = hdmi.cfg.timings;
 308}
 309
 310static void hdmi_dump_regs(struct seq_file *s)
 311{
 312        mutex_lock(&hdmi.lock);
 313
 314        if (hdmi_runtime_get()) {
 315                mutex_unlock(&hdmi.lock);
 316                return;
 317        }
 318
 319        hdmi_wp_dump(&hdmi.wp, s);
 320        hdmi_pll_dump(&hdmi.pll, s);
 321        hdmi_phy_dump(&hdmi.phy, s);
 322        hdmi5_core_dump(&hdmi.core, s);
 323
 324        hdmi_runtime_put();
 325        mutex_unlock(&hdmi.lock);
 326}
 327
 328static int read_edid(u8 *buf, int len)
 329{
 330        int r;
 331        int idlemode;
 332
 333        mutex_lock(&hdmi.lock);
 334
 335        r = hdmi_runtime_get();
 336        BUG_ON(r);
 337
 338        idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
 339        /* No-idle mode */
 340        REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
 341
 342        r = hdmi5_read_edid(&hdmi.core,  buf, len);
 343
 344        REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
 345
 346        hdmi_runtime_put();
 347        mutex_unlock(&hdmi.lock);
 348
 349        return r;
 350}
 351
 352static void hdmi_start_audio_stream(struct omap_hdmi *hd)
 353{
 354        REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
 355        hdmi_wp_audio_enable(&hd->wp, true);
 356        hdmi_wp_audio_core_req_enable(&hd->wp, true);
 357}
 358
 359static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
 360{
 361        hdmi_wp_audio_core_req_enable(&hd->wp, false);
 362        hdmi_wp_audio_enable(&hd->wp, false);
 363        REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
 364}
 365
 366static int hdmi_display_enable(struct omap_dss_device *dssdev)
 367{
 368        struct omap_dss_device *out = &hdmi.output;
 369        unsigned long flags;
 370        int r = 0;
 371
 372        DSSDBG("ENTER hdmi_display_enable\n");
 373
 374        mutex_lock(&hdmi.lock);
 375
 376        if (out->manager == NULL) {
 377                DSSERR("failed to enable display: no output/manager\n");
 378                r = -ENODEV;
 379                goto err0;
 380        }
 381
 382        r = hdmi_power_on_full(dssdev);
 383        if (r) {
 384                DSSERR("failed to power on device\n");
 385                goto err0;
 386        }
 387
 388        if (hdmi.audio_configured) {
 389                r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
 390                                       hdmi.cfg.timings.pixelclock);
 391                if (r) {
 392                        DSSERR("Error restoring audio configuration: %d", r);
 393                        hdmi.audio_abort_cb(&hdmi.pdev->dev);
 394                        hdmi.audio_configured = false;
 395                }
 396        }
 397
 398        spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
 399        if (hdmi.audio_configured && hdmi.audio_playing)
 400                hdmi_start_audio_stream(&hdmi);
 401        hdmi.display_enabled = true;
 402        spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
 403
 404        mutex_unlock(&hdmi.lock);
 405        return 0;
 406
 407err0:
 408        mutex_unlock(&hdmi.lock);
 409        return r;
 410}
 411
 412static void hdmi_display_disable(struct omap_dss_device *dssdev)
 413{
 414        unsigned long flags;
 415
 416        DSSDBG("Enter hdmi_display_disable\n");
 417
 418        mutex_lock(&hdmi.lock);
 419
 420        spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
 421        hdmi_stop_audio_stream(&hdmi);
 422        hdmi.display_enabled = false;
 423        spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
 424
 425        hdmi_power_off_full(dssdev);
 426
 427        mutex_unlock(&hdmi.lock);
 428}
 429
 430static int hdmi_core_enable(struct omap_dss_device *dssdev)
 431{
 432        int r = 0;
 433
 434        DSSDBG("ENTER omapdss_hdmi_core_enable\n");
 435
 436        mutex_lock(&hdmi.lock);
 437
 438        r = hdmi_power_on_core(dssdev);
 439        if (r) {
 440                DSSERR("failed to power on device\n");
 441                goto err0;
 442        }
 443
 444        mutex_unlock(&hdmi.lock);
 445        return 0;
 446
 447err0:
 448        mutex_unlock(&hdmi.lock);
 449        return r;
 450}
 451
 452static void hdmi_core_disable(struct omap_dss_device *dssdev)
 453{
 454        DSSDBG("Enter omapdss_hdmi_core_disable\n");
 455
 456        mutex_lock(&hdmi.lock);
 457
 458        hdmi_power_off_core(dssdev);
 459
 460        mutex_unlock(&hdmi.lock);
 461}
 462
 463static int hdmi_connect(struct omap_dss_device *dssdev,
 464                struct omap_dss_device *dst)
 465{
 466        struct omap_overlay_manager *mgr;
 467        int r;
 468
 469        r = hdmi_init_regulator();
 470        if (r)
 471                return r;
 472
 473        mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
 474        if (!mgr)
 475                return -ENODEV;
 476
 477        r = dss_mgr_connect(mgr, dssdev);
 478        if (r)
 479                return r;
 480
 481        r = omapdss_output_set_device(dssdev, dst);
 482        if (r) {
 483                DSSERR("failed to connect output to new device: %s\n",
 484                                dst->name);
 485                dss_mgr_disconnect(mgr, dssdev);
 486                return r;
 487        }
 488
 489        return 0;
 490}
 491
 492static void hdmi_disconnect(struct omap_dss_device *dssdev,
 493                struct omap_dss_device *dst)
 494{
 495        WARN_ON(dst != dssdev->dst);
 496
 497        if (dst != dssdev->dst)
 498                return;
 499
 500        omapdss_output_unset_device(dssdev);
 501
 502        if (dssdev->manager)
 503                dss_mgr_disconnect(dssdev->manager, dssdev);
 504}
 505
 506static int hdmi_read_edid(struct omap_dss_device *dssdev,
 507                u8 *edid, int len)
 508{
 509        bool need_enable;
 510        int r;
 511
 512        need_enable = hdmi.core_enabled == false;
 513
 514        if (need_enable) {
 515                r = hdmi_core_enable(dssdev);
 516                if (r)
 517                        return r;
 518        }
 519
 520        r = read_edid(edid, len);
 521
 522        if (need_enable)
 523                hdmi_core_disable(dssdev);
 524
 525        return r;
 526}
 527
 528static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
 529                const struct hdmi_avi_infoframe *avi)
 530{
 531        hdmi.cfg.infoframe = *avi;
 532        return 0;
 533}
 534
 535static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
 536                bool hdmi_mode)
 537{
 538        hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
 539        return 0;
 540}
 541
 542static const struct omapdss_hdmi_ops hdmi_ops = {
 543        .connect                = hdmi_connect,
 544        .disconnect             = hdmi_disconnect,
 545
 546        .enable                 = hdmi_display_enable,
 547        .disable                = hdmi_display_disable,
 548
 549        .check_timings          = hdmi_display_check_timing,
 550        .set_timings            = hdmi_display_set_timing,
 551        .get_timings            = hdmi_display_get_timings,
 552
 553        .read_edid              = hdmi_read_edid,
 554        .set_infoframe          = hdmi_set_infoframe,
 555        .set_hdmi_mode          = hdmi_set_hdmi_mode,
 556};
 557
 558static void hdmi_init_output(struct platform_device *pdev)
 559{
 560        struct omap_dss_device *out = &hdmi.output;
 561
 562        out->dev = &pdev->dev;
 563        out->id = OMAP_DSS_OUTPUT_HDMI;
 564        out->output_type = OMAP_DISPLAY_TYPE_HDMI;
 565        out->name = "hdmi.0";
 566        out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
 567        out->ops.hdmi = &hdmi_ops;
 568        out->owner = THIS_MODULE;
 569
 570        omapdss_register_output(out);
 571}
 572
 573static void hdmi_uninit_output(struct platform_device *pdev)
 574{
 575        struct omap_dss_device *out = &hdmi.output;
 576
 577        omapdss_unregister_output(out);
 578}
 579
 580static int hdmi_probe_of(struct platform_device *pdev)
 581{
 582        struct device_node *node = pdev->dev.of_node;
 583        struct device_node *ep;
 584        int r;
 585
 586        ep = omapdss_of_get_first_endpoint(node);
 587        if (!ep)
 588                return 0;
 589
 590        r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
 591        if (r)
 592                goto err;
 593
 594        of_node_put(ep);
 595        return 0;
 596
 597err:
 598        of_node_put(ep);
 599        return r;
 600}
 601
 602/* Audio callbacks */
 603static int hdmi_audio_startup(struct device *dev,
 604                              void (*abort_cb)(struct device *dev))
 605{
 606        struct omap_hdmi *hd = dev_get_drvdata(dev);
 607        int ret = 0;
 608
 609        mutex_lock(&hd->lock);
 610
 611        if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
 612                ret = -EPERM;
 613                goto out;
 614        }
 615
 616        hd->audio_abort_cb = abort_cb;
 617
 618out:
 619        mutex_unlock(&hd->lock);
 620
 621        return ret;
 622}
 623
 624static int hdmi_audio_shutdown(struct device *dev)
 625{
 626        struct omap_hdmi *hd = dev_get_drvdata(dev);
 627
 628        mutex_lock(&hd->lock);
 629        hd->audio_abort_cb = NULL;
 630        hd->audio_configured = false;
 631        hd->audio_playing = false;
 632        mutex_unlock(&hd->lock);
 633
 634        return 0;
 635}
 636
 637static int hdmi_audio_start(struct device *dev)
 638{
 639        struct omap_hdmi *hd = dev_get_drvdata(dev);
 640        unsigned long flags;
 641
 642        WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
 643
 644        spin_lock_irqsave(&hd->audio_playing_lock, flags);
 645
 646        if (hd->display_enabled)
 647                hdmi_start_audio_stream(hd);
 648        hd->audio_playing = true;
 649
 650        spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
 651        return 0;
 652}
 653
 654static void hdmi_audio_stop(struct device *dev)
 655{
 656        struct omap_hdmi *hd = dev_get_drvdata(dev);
 657        unsigned long flags;
 658
 659        WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
 660
 661        spin_lock_irqsave(&hd->audio_playing_lock, flags);
 662
 663        if (hd->display_enabled)
 664                hdmi_stop_audio_stream(hd);
 665        hd->audio_playing = false;
 666
 667        spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
 668}
 669
 670static int hdmi_audio_config(struct device *dev,
 671                             struct omap_dss_audio *dss_audio)
 672{
 673        struct omap_hdmi *hd = dev_get_drvdata(dev);
 674        int ret;
 675
 676        mutex_lock(&hd->lock);
 677
 678        if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
 679                ret = -EPERM;
 680                goto out;
 681        }
 682
 683        ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
 684                                 hd->cfg.timings.pixelclock);
 685
 686        if (!ret) {
 687                hd->audio_configured = true;
 688                hd->audio_config = *dss_audio;
 689        }
 690out:
 691        mutex_unlock(&hd->lock);
 692
 693        return ret;
 694}
 695
 696static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
 697        .audio_startup = hdmi_audio_startup,
 698        .audio_shutdown = hdmi_audio_shutdown,
 699        .audio_start = hdmi_audio_start,
 700        .audio_stop = hdmi_audio_stop,
 701        .audio_config = hdmi_audio_config,
 702};
 703
 704static int hdmi_audio_register(struct device *dev)
 705{
 706        struct omap_hdmi_audio_pdata pdata = {
 707                .dev = dev,
 708                .dss_version = omapdss_get_version(),
 709                .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
 710                .ops = &hdmi_audio_ops,
 711        };
 712
 713        hdmi.audio_pdev = platform_device_register_data(
 714                dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
 715                &pdata, sizeof(pdata));
 716
 717        if (IS_ERR(hdmi.audio_pdev))
 718                return PTR_ERR(hdmi.audio_pdev);
 719
 720        hdmi_runtime_get();
 721        hdmi.wp_idlemode =
 722                REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
 723        hdmi_runtime_put();
 724
 725        return 0;
 726}
 727
 728/* HDMI HW IP initialisation */
 729static int hdmi5_bind(struct device *dev, struct device *master, void *data)
 730{
 731        struct platform_device *pdev = to_platform_device(dev);
 732        int r;
 733        int irq;
 734
 735        hdmi.pdev = pdev;
 736        dev_set_drvdata(&pdev->dev, &hdmi);
 737
 738        mutex_init(&hdmi.lock);
 739        spin_lock_init(&hdmi.audio_playing_lock);
 740
 741        if (pdev->dev.of_node) {
 742                r = hdmi_probe_of(pdev);
 743                if (r)
 744                        return r;
 745        }
 746
 747        r = hdmi_wp_init(pdev, &hdmi.wp);
 748        if (r)
 749                return r;
 750
 751        r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
 752        if (r)
 753                return r;
 754
 755        r = hdmi_phy_init(pdev, &hdmi.phy);
 756        if (r)
 757                goto err;
 758
 759        r = hdmi5_core_init(pdev, &hdmi.core);
 760        if (r)
 761                goto err;
 762
 763        irq = platform_get_irq(pdev, 0);
 764        if (irq < 0) {
 765                DSSERR("platform_get_irq failed\n");
 766                r = -ENODEV;
 767                goto err;
 768        }
 769
 770        r = devm_request_threaded_irq(&pdev->dev, irq,
 771                        NULL, hdmi_irq_handler,
 772                        IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
 773        if (r) {
 774                DSSERR("HDMI IRQ request failed\n");
 775                goto err;
 776        }
 777
 778        pm_runtime_enable(&pdev->dev);
 779
 780        hdmi_init_output(pdev);
 781
 782        r = hdmi_audio_register(&pdev->dev);
 783        if (r) {
 784                DSSERR("Registering HDMI audio failed %d\n", r);
 785                hdmi_uninit_output(pdev);
 786                pm_runtime_disable(&pdev->dev);
 787                return r;
 788        }
 789
 790        dss_debugfs_create_file("hdmi", hdmi_dump_regs);
 791
 792        return 0;
 793err:
 794        hdmi_pll_uninit(&hdmi.pll);
 795        return r;
 796}
 797
 798static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
 799{
 800        struct platform_device *pdev = to_platform_device(dev);
 801
 802        if (hdmi.audio_pdev)
 803                platform_device_unregister(hdmi.audio_pdev);
 804
 805        hdmi_uninit_output(pdev);
 806
 807        hdmi_pll_uninit(&hdmi.pll);
 808
 809        pm_runtime_disable(&pdev->dev);
 810}
 811
 812static const struct component_ops hdmi5_component_ops = {
 813        .bind   = hdmi5_bind,
 814        .unbind = hdmi5_unbind,
 815};
 816
 817static int hdmi5_probe(struct platform_device *pdev)
 818{
 819        return component_add(&pdev->dev, &hdmi5_component_ops);
 820}
 821
 822static int hdmi5_remove(struct platform_device *pdev)
 823{
 824        component_del(&pdev->dev, &hdmi5_component_ops);
 825        return 0;
 826}
 827
 828static int hdmi_runtime_suspend(struct device *dev)
 829{
 830        dispc_runtime_put();
 831
 832        return 0;
 833}
 834
 835static int hdmi_runtime_resume(struct device *dev)
 836{
 837        int r;
 838
 839        r = dispc_runtime_get();
 840        if (r < 0)
 841                return r;
 842
 843        return 0;
 844}
 845
 846static const struct dev_pm_ops hdmi_pm_ops = {
 847        .runtime_suspend = hdmi_runtime_suspend,
 848        .runtime_resume = hdmi_runtime_resume,
 849};
 850
 851static const struct of_device_id hdmi_of_match[] = {
 852        { .compatible = "ti,omap5-hdmi", },
 853        { .compatible = "ti,dra7-hdmi", },
 854        {},
 855};
 856
 857static struct platform_driver omapdss_hdmihw_driver = {
 858        .probe          = hdmi5_probe,
 859        .remove         = hdmi5_remove,
 860        .driver         = {
 861                .name   = "omapdss_hdmi5",
 862                .pm     = &hdmi_pm_ops,
 863                .of_match_table = hdmi_of_match,
 864                .suppress_bind_attrs = true,
 865        },
 866};
 867
 868int __init hdmi5_init_platform_driver(void)
 869{
 870        return platform_driver_register(&omapdss_hdmihw_driver);
 871}
 872
 873void hdmi5_uninit_platform_driver(void)
 874{
 875        platform_driver_unregister(&omapdss_hdmihw_driver);
 876}
 877