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