Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HDMI driver for OMAP5
0004  *
0005  * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/
0006  *
0007  * Authors:
0008  *  Yong Zhi
0009  *  Mythri pk
0010  *  Archit Taneja <archit@ti.com>
0011  *  Tomi Valkeinen <tomi.valkeinen@ti.com>
0012  */
0013 
0014 #define DSS_SUBSYS_NAME "HDMI"
0015 
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/err.h>
0019 #include <linux/io.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/mutex.h>
0022 #include <linux/delay.h>
0023 #include <linux/string.h>
0024 #include <linux/platform_device.h>
0025 #include <linux/pm_runtime.h>
0026 #include <linux/clk.h>
0027 #include <linux/regulator/consumer.h>
0028 #include <linux/component.h>
0029 #include <linux/of.h>
0030 #include <linux/of_graph.h>
0031 #include <sound/omap-hdmi-audio.h>
0032 
0033 #include <drm/drm_atomic.h>
0034 #include <drm/drm_atomic_state_helper.h>
0035 #include <drm/drm_edid.h>
0036 
0037 #include "omapdss.h"
0038 #include "hdmi5_core.h"
0039 #include "dss.h"
0040 
0041 static int hdmi_runtime_get(struct omap_hdmi *hdmi)
0042 {
0043     int r;
0044 
0045     DSSDBG("hdmi_runtime_get\n");
0046 
0047     r = pm_runtime_get_sync(&hdmi->pdev->dev);
0048     if (WARN_ON(r < 0)) {
0049         pm_runtime_put_noidle(&hdmi->pdev->dev);
0050         return r;
0051     }
0052     return 0;
0053 }
0054 
0055 static void hdmi_runtime_put(struct omap_hdmi *hdmi)
0056 {
0057     int r;
0058 
0059     DSSDBG("hdmi_runtime_put\n");
0060 
0061     r = pm_runtime_put_sync(&hdmi->pdev->dev);
0062     WARN_ON(r < 0 && r != -ENOSYS);
0063 }
0064 
0065 static irqreturn_t hdmi_irq_handler(int irq, void *data)
0066 {
0067     struct omap_hdmi *hdmi = data;
0068     struct hdmi_wp_data *wp = &hdmi->wp;
0069     u32 irqstatus;
0070 
0071     irqstatus = hdmi_wp_get_irqstatus(wp);
0072     hdmi_wp_set_irqstatus(wp, irqstatus);
0073 
0074     if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
0075             irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
0076         u32 v;
0077         /*
0078          * If we get both connect and disconnect interrupts at the same
0079          * time, turn off the PHY, clear interrupts, and restart, which
0080          * raises connect interrupt if a cable is connected, or nothing
0081          * if cable is not connected.
0082          */
0083 
0084         hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
0085 
0086         /*
0087          * We always get bogus CONNECT & DISCONNECT interrupts when
0088          * setting the PHY to LDOON. To ignore those, we force the RXDET
0089          * line to 0 until the PHY power state has been changed.
0090          */
0091         v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
0092         v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
0093         v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
0094         hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
0095 
0096         hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
0097                 HDMI_IRQ_LINK_DISCONNECT);
0098 
0099         hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
0100 
0101         REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
0102 
0103     } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
0104         hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
0105     } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
0106         hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
0107     }
0108 
0109     return IRQ_HANDLED;
0110 }
0111 
0112 static int hdmi_power_on_core(struct omap_hdmi *hdmi)
0113 {
0114     int r;
0115 
0116     r = regulator_enable(hdmi->vdda_reg);
0117     if (r)
0118         return r;
0119 
0120     r = hdmi_runtime_get(hdmi);
0121     if (r)
0122         goto err_runtime_get;
0123 
0124     /* Make selection of HDMI in DSS */
0125     dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
0126 
0127     hdmi->core_enabled = true;
0128 
0129     return 0;
0130 
0131 err_runtime_get:
0132     regulator_disable(hdmi->vdda_reg);
0133 
0134     return r;
0135 }
0136 
0137 static void hdmi_power_off_core(struct omap_hdmi *hdmi)
0138 {
0139     hdmi->core_enabled = false;
0140 
0141     hdmi_runtime_put(hdmi);
0142     regulator_disable(hdmi->vdda_reg);
0143 }
0144 
0145 static int hdmi_power_on_full(struct omap_hdmi *hdmi)
0146 {
0147     int r;
0148     const struct videomode *vm;
0149     struct dss_pll_clock_info hdmi_cinfo = { 0 };
0150     unsigned int pc;
0151 
0152     r = hdmi_power_on_core(hdmi);
0153     if (r)
0154         return r;
0155 
0156     vm = &hdmi->cfg.vm;
0157 
0158     DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
0159            vm->vactive);
0160 
0161     pc = vm->pixelclock;
0162     if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
0163         pc *= 2;
0164 
0165     /* DSS_HDMI_TCLK is bitclk / 10 */
0166     pc *= 10;
0167 
0168     dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
0169         pc, &hdmi_cinfo);
0170 
0171     /* disable and clear irqs */
0172     hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
0173     hdmi_wp_set_irqstatus(&hdmi->wp,
0174             hdmi_wp_get_irqstatus(&hdmi->wp));
0175 
0176     r = dss_pll_enable(&hdmi->pll.pll);
0177     if (r) {
0178         DSSERR("Failed to enable PLL\n");
0179         goto err_pll_enable;
0180     }
0181 
0182     r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
0183     if (r) {
0184         DSSERR("Failed to configure PLL\n");
0185         goto err_pll_cfg;
0186     }
0187 
0188     r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
0189         hdmi_cinfo.clkout[0]);
0190     if (r) {
0191         DSSDBG("Failed to start PHY\n");
0192         goto err_phy_cfg;
0193     }
0194 
0195     r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON);
0196     if (r)
0197         goto err_phy_pwr;
0198 
0199     hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
0200 
0201     r = dss_mgr_enable(&hdmi->output);
0202     if (r)
0203         goto err_mgr_enable;
0204 
0205     r = hdmi_wp_video_start(&hdmi->wp);
0206     if (r)
0207         goto err_vid_enable;
0208 
0209     hdmi_wp_set_irqenable(&hdmi->wp,
0210             HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
0211 
0212     return 0;
0213 
0214 err_vid_enable:
0215     dss_mgr_disable(&hdmi->output);
0216 err_mgr_enable:
0217     hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
0218 err_phy_pwr:
0219 err_phy_cfg:
0220 err_pll_cfg:
0221     dss_pll_disable(&hdmi->pll.pll);
0222 err_pll_enable:
0223     hdmi_power_off_core(hdmi);
0224     return -EIO;
0225 }
0226 
0227 static void hdmi_power_off_full(struct omap_hdmi *hdmi)
0228 {
0229     hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
0230 
0231     hdmi_wp_video_stop(&hdmi->wp);
0232 
0233     dss_mgr_disable(&hdmi->output);
0234 
0235     hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
0236 
0237     dss_pll_disable(&hdmi->pll.pll);
0238 
0239     hdmi_power_off_core(hdmi);
0240 }
0241 
0242 static int hdmi_dump_regs(struct seq_file *s, void *p)
0243 {
0244     struct omap_hdmi *hdmi = s->private;
0245 
0246     mutex_lock(&hdmi->lock);
0247 
0248     if (hdmi_runtime_get(hdmi)) {
0249         mutex_unlock(&hdmi->lock);
0250         return 0;
0251     }
0252 
0253     hdmi_wp_dump(&hdmi->wp, s);
0254     hdmi_pll_dump(&hdmi->pll, s);
0255     hdmi_phy_dump(&hdmi->phy, s);
0256     hdmi5_core_dump(&hdmi->core, s);
0257 
0258     hdmi_runtime_put(hdmi);
0259     mutex_unlock(&hdmi->lock);
0260     return 0;
0261 }
0262 
0263 static void hdmi_start_audio_stream(struct omap_hdmi *hd)
0264 {
0265     REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
0266     hdmi_wp_audio_enable(&hd->wp, true);
0267     hdmi_wp_audio_core_req_enable(&hd->wp, true);
0268 }
0269 
0270 static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
0271 {
0272     hdmi_wp_audio_core_req_enable(&hd->wp, false);
0273     hdmi_wp_audio_enable(&hd->wp, false);
0274     REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
0275 }
0276 
0277 static int hdmi_core_enable(struct omap_hdmi *hdmi)
0278 {
0279     int r = 0;
0280 
0281     DSSDBG("ENTER omapdss_hdmi_core_enable\n");
0282 
0283     mutex_lock(&hdmi->lock);
0284 
0285     r = hdmi_power_on_core(hdmi);
0286     if (r) {
0287         DSSERR("failed to power on device\n");
0288         goto err0;
0289     }
0290 
0291     mutex_unlock(&hdmi->lock);
0292     return 0;
0293 
0294 err0:
0295     mutex_unlock(&hdmi->lock);
0296     return r;
0297 }
0298 
0299 static void hdmi_core_disable(struct omap_hdmi *hdmi)
0300 {
0301     DSSDBG("Enter omapdss_hdmi_core_disable\n");
0302 
0303     mutex_lock(&hdmi->lock);
0304 
0305     hdmi_power_off_core(hdmi);
0306 
0307     mutex_unlock(&hdmi->lock);
0308 }
0309 
0310 /* -----------------------------------------------------------------------------
0311  * DRM Bridge Operations
0312  */
0313 
0314 static int hdmi5_bridge_attach(struct drm_bridge *bridge,
0315                    enum drm_bridge_attach_flags flags)
0316 {
0317     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
0318 
0319     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
0320         return -EINVAL;
0321 
0322     return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
0323                  bridge, flags);
0324 }
0325 
0326 static void hdmi5_bridge_mode_set(struct drm_bridge *bridge,
0327                   const struct drm_display_mode *mode,
0328                   const struct drm_display_mode *adjusted_mode)
0329 {
0330     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
0331 
0332     mutex_lock(&hdmi->lock);
0333 
0334     drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);
0335 
0336     dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);
0337 
0338     mutex_unlock(&hdmi->lock);
0339 }
0340 
0341 static void hdmi5_bridge_enable(struct drm_bridge *bridge,
0342                 struct drm_bridge_state *bridge_state)
0343 {
0344     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
0345     struct drm_atomic_state *state = bridge_state->base.state;
0346     struct drm_connector_state *conn_state;
0347     struct drm_connector *connector;
0348     struct drm_crtc_state *crtc_state;
0349     unsigned long flags;
0350     int ret;
0351 
0352     /*
0353      * None of these should fail, as the bridge can't be enabled without a
0354      * valid CRTC to connector path with fully populated new states.
0355      */
0356     connector = drm_atomic_get_new_connector_for_encoder(state,
0357                                  bridge->encoder);
0358     if (WARN_ON(!connector))
0359         return;
0360     conn_state = drm_atomic_get_new_connector_state(state, connector);
0361     if (WARN_ON(!conn_state))
0362         return;
0363     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
0364     if (WARN_ON(!crtc_state))
0365         return;
0366 
0367     hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
0368                 ? HDMI_HDMI : HDMI_DVI;
0369 
0370     if (connector->display_info.is_hdmi) {
0371         const struct drm_display_mode *mode;
0372         struct hdmi_avi_infoframe avi;
0373 
0374         mode = &crtc_state->adjusted_mode;
0375         ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
0376                                    mode);
0377         if (ret == 0)
0378             hdmi->cfg.infoframe = avi;
0379     }
0380 
0381     mutex_lock(&hdmi->lock);
0382 
0383     ret = hdmi_power_on_full(hdmi);
0384     if (ret) {
0385         DSSERR("failed to power on device\n");
0386         goto done;
0387     }
0388 
0389     if (hdmi->audio_configured) {
0390         ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
0391                      &hdmi->audio_config,
0392                      hdmi->cfg.vm.pixelclock);
0393         if (ret) {
0394             DSSERR("Error restoring audio configuration: %d", ret);
0395             hdmi->audio_abort_cb(&hdmi->pdev->dev);
0396             hdmi->audio_configured = false;
0397         }
0398     }
0399 
0400     spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
0401     if (hdmi->audio_configured && hdmi->audio_playing)
0402         hdmi_start_audio_stream(hdmi);
0403     hdmi->display_enabled = true;
0404     spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
0405 
0406 done:
0407     mutex_unlock(&hdmi->lock);
0408 }
0409 
0410 static void hdmi5_bridge_disable(struct drm_bridge *bridge,
0411                  struct drm_bridge_state *bridge_state)
0412 {
0413     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
0414     unsigned long flags;
0415 
0416     mutex_lock(&hdmi->lock);
0417 
0418     spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
0419     hdmi_stop_audio_stream(hdmi);
0420     hdmi->display_enabled = false;
0421     spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
0422 
0423     hdmi_power_off_full(hdmi);
0424 
0425     mutex_unlock(&hdmi->lock);
0426 }
0427 
0428 static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge,
0429                       struct drm_connector *connector)
0430 {
0431     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
0432     struct edid *edid;
0433     bool need_enable;
0434     int idlemode;
0435     int r;
0436 
0437     need_enable = hdmi->core_enabled == false;
0438 
0439     if (need_enable) {
0440         r = hdmi_core_enable(hdmi);
0441         if (r)
0442             return NULL;
0443     }
0444 
0445     mutex_lock(&hdmi->lock);
0446     r = hdmi_runtime_get(hdmi);
0447     BUG_ON(r);
0448 
0449     idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
0450     /* No-idle mode */
0451     REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
0452 
0453     hdmi5_core_ddc_init(&hdmi->core);
0454 
0455     edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core);
0456 
0457     hdmi5_core_ddc_uninit(&hdmi->core);
0458 
0459     REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
0460 
0461     hdmi_runtime_put(hdmi);
0462     mutex_unlock(&hdmi->lock);
0463 
0464     if (need_enable)
0465         hdmi_core_disable(hdmi);
0466 
0467     return (struct edid *)edid;
0468 }
0469 
0470 static const struct drm_bridge_funcs hdmi5_bridge_funcs = {
0471     .attach = hdmi5_bridge_attach,
0472     .mode_set = hdmi5_bridge_mode_set,
0473     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
0474     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
0475     .atomic_reset = drm_atomic_helper_bridge_reset,
0476     .atomic_enable = hdmi5_bridge_enable,
0477     .atomic_disable = hdmi5_bridge_disable,
0478     .get_edid = hdmi5_bridge_get_edid,
0479 };
0480 
0481 static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
0482 {
0483     hdmi->bridge.funcs = &hdmi5_bridge_funcs;
0484     hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
0485     hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
0486     hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
0487 
0488     drm_bridge_add(&hdmi->bridge);
0489 }
0490 
0491 static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi)
0492 {
0493     drm_bridge_remove(&hdmi->bridge);
0494 }
0495 
0496 /* -----------------------------------------------------------------------------
0497  * Audio Callbacks
0498  */
0499 
0500 static int hdmi_audio_startup(struct device *dev,
0501                   void (*abort_cb)(struct device *dev))
0502 {
0503     struct omap_hdmi *hd = dev_get_drvdata(dev);
0504 
0505     mutex_lock(&hd->lock);
0506 
0507     WARN_ON(hd->audio_abort_cb != NULL);
0508 
0509     hd->audio_abort_cb = abort_cb;
0510 
0511     mutex_unlock(&hd->lock);
0512 
0513     return 0;
0514 }
0515 
0516 static int hdmi_audio_shutdown(struct device *dev)
0517 {
0518     struct omap_hdmi *hd = dev_get_drvdata(dev);
0519 
0520     mutex_lock(&hd->lock);
0521     hd->audio_abort_cb = NULL;
0522     hd->audio_configured = false;
0523     hd->audio_playing = false;
0524     mutex_unlock(&hd->lock);
0525 
0526     return 0;
0527 }
0528 
0529 static int hdmi_audio_start(struct device *dev)
0530 {
0531     struct omap_hdmi *hd = dev_get_drvdata(dev);
0532     unsigned long flags;
0533 
0534     spin_lock_irqsave(&hd->audio_playing_lock, flags);
0535 
0536     if (hd->display_enabled) {
0537         if (!hdmi_mode_has_audio(&hd->cfg))
0538             DSSERR("%s: Video mode does not support audio\n",
0539                    __func__);
0540         hdmi_start_audio_stream(hd);
0541     }
0542     hd->audio_playing = true;
0543 
0544     spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
0545     return 0;
0546 }
0547 
0548 static void hdmi_audio_stop(struct device *dev)
0549 {
0550     struct omap_hdmi *hd = dev_get_drvdata(dev);
0551     unsigned long flags;
0552 
0553     if (!hdmi_mode_has_audio(&hd->cfg))
0554         DSSERR("%s: Video mode does not support audio\n", __func__);
0555 
0556     spin_lock_irqsave(&hd->audio_playing_lock, flags);
0557 
0558     if (hd->display_enabled)
0559         hdmi_stop_audio_stream(hd);
0560     hd->audio_playing = false;
0561 
0562     spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
0563 }
0564 
0565 static int hdmi_audio_config(struct device *dev,
0566                  struct omap_dss_audio *dss_audio)
0567 {
0568     struct omap_hdmi *hd = dev_get_drvdata(dev);
0569     int ret = 0;
0570 
0571     mutex_lock(&hd->lock);
0572 
0573     if (hd->display_enabled) {
0574         ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
0575                      hd->cfg.vm.pixelclock);
0576         if (ret)
0577             goto out;
0578     }
0579 
0580     hd->audio_configured = true;
0581     hd->audio_config = *dss_audio;
0582 out:
0583     mutex_unlock(&hd->lock);
0584 
0585     return ret;
0586 }
0587 
0588 static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
0589     .audio_startup = hdmi_audio_startup,
0590     .audio_shutdown = hdmi_audio_shutdown,
0591     .audio_start = hdmi_audio_start,
0592     .audio_stop = hdmi_audio_stop,
0593     .audio_config = hdmi_audio_config,
0594 };
0595 
0596 static int hdmi_audio_register(struct omap_hdmi *hdmi)
0597 {
0598     struct omap_hdmi_audio_pdata pdata = {
0599         .dev = &hdmi->pdev->dev,
0600         .version = 5,
0601         .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
0602         .ops = &hdmi_audio_ops,
0603     };
0604 
0605     hdmi->audio_pdev = platform_device_register_data(
0606         &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
0607         &pdata, sizeof(pdata));
0608 
0609     if (IS_ERR(hdmi->audio_pdev))
0610         return PTR_ERR(hdmi->audio_pdev);
0611 
0612     hdmi_runtime_get(hdmi);
0613     hdmi->wp_idlemode =
0614         REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
0615     hdmi_runtime_put(hdmi);
0616 
0617     return 0;
0618 }
0619 
0620 /* -----------------------------------------------------------------------------
0621  * Component Bind & Unbind
0622  */
0623 
0624 static int hdmi5_bind(struct device *dev, struct device *master, void *data)
0625 {
0626     struct dss_device *dss = dss_get_device(master);
0627     struct omap_hdmi *hdmi = dev_get_drvdata(dev);
0628     int r;
0629 
0630     hdmi->dss = dss;
0631 
0632     r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
0633     if (r)
0634         return r;
0635 
0636     r = hdmi_audio_register(hdmi);
0637     if (r) {
0638         DSSERR("Registering HDMI audio failed %d\n", r);
0639         goto err_pll_uninit;
0640     }
0641 
0642     hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
0643                         hdmi);
0644 
0645     return 0;
0646 
0647 err_pll_uninit:
0648     hdmi_pll_uninit(&hdmi->pll);
0649     return r;
0650 }
0651 
0652 static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
0653 {
0654     struct omap_hdmi *hdmi = dev_get_drvdata(dev);
0655 
0656     dss_debugfs_remove_file(hdmi->debugfs);
0657 
0658     if (hdmi->audio_pdev)
0659         platform_device_unregister(hdmi->audio_pdev);
0660 
0661     hdmi_pll_uninit(&hdmi->pll);
0662 }
0663 
0664 static const struct component_ops hdmi5_component_ops = {
0665     .bind   = hdmi5_bind,
0666     .unbind = hdmi5_unbind,
0667 };
0668 
0669 /* -----------------------------------------------------------------------------
0670  * Probe & Remove, Suspend & Resume
0671  */
0672 
0673 static int hdmi5_init_output(struct omap_hdmi *hdmi)
0674 {
0675     struct omap_dss_device *out = &hdmi->output;
0676     int r;
0677 
0678     hdmi5_bridge_init(hdmi);
0679 
0680     out->dev = &hdmi->pdev->dev;
0681     out->id = OMAP_DSS_OUTPUT_HDMI;
0682     out->type = OMAP_DISPLAY_TYPE_HDMI;
0683     out->name = "hdmi.0";
0684     out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
0685     out->of_port = 0;
0686 
0687     r = omapdss_device_init_output(out, &hdmi->bridge);
0688     if (r < 0) {
0689         hdmi5_bridge_cleanup(hdmi);
0690         return r;
0691     }
0692 
0693     omapdss_device_register(out);
0694 
0695     return 0;
0696 }
0697 
0698 static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
0699 {
0700     struct omap_dss_device *out = &hdmi->output;
0701 
0702     omapdss_device_unregister(out);
0703     omapdss_device_cleanup_output(out);
0704 
0705     hdmi5_bridge_cleanup(hdmi);
0706 }
0707 
0708 static int hdmi5_probe_of(struct omap_hdmi *hdmi)
0709 {
0710     struct platform_device *pdev = hdmi->pdev;
0711     struct device_node *node = pdev->dev.of_node;
0712     struct device_node *ep;
0713     int r;
0714 
0715     ep = of_graph_get_endpoint_by_regs(node, 0, 0);
0716     if (!ep)
0717         return 0;
0718 
0719     r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
0720     of_node_put(ep);
0721     return r;
0722 }
0723 
0724 static int hdmi5_probe(struct platform_device *pdev)
0725 {
0726     struct omap_hdmi *hdmi;
0727     int irq;
0728     int r;
0729 
0730     hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
0731     if (!hdmi)
0732         return -ENOMEM;
0733 
0734     hdmi->pdev = pdev;
0735 
0736     dev_set_drvdata(&pdev->dev, hdmi);
0737 
0738     mutex_init(&hdmi->lock);
0739     spin_lock_init(&hdmi->audio_playing_lock);
0740 
0741     r = hdmi5_probe_of(hdmi);
0742     if (r)
0743         goto err_free;
0744 
0745     r = hdmi_wp_init(pdev, &hdmi->wp, 5);
0746     if (r)
0747         goto err_free;
0748 
0749     r = hdmi_phy_init(pdev, &hdmi->phy, 5);
0750     if (r)
0751         goto err_free;
0752 
0753     r = hdmi5_core_init(pdev, &hdmi->core);
0754     if (r)
0755         goto err_free;
0756 
0757     irq = platform_get_irq(pdev, 0);
0758     if (irq < 0) {
0759         DSSERR("platform_get_irq failed\n");
0760         r = -ENODEV;
0761         goto err_free;
0762     }
0763 
0764     r = devm_request_threaded_irq(&pdev->dev, irq,
0765             NULL, hdmi_irq_handler,
0766             IRQF_ONESHOT, "OMAP HDMI", hdmi);
0767     if (r) {
0768         DSSERR("HDMI IRQ request failed\n");
0769         goto err_free;
0770     }
0771 
0772     hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
0773     if (IS_ERR(hdmi->vdda_reg)) {
0774         r = PTR_ERR(hdmi->vdda_reg);
0775         if (r != -EPROBE_DEFER)
0776             DSSERR("can't get VDDA regulator\n");
0777         goto err_free;
0778     }
0779 
0780     pm_runtime_enable(&pdev->dev);
0781 
0782     r = hdmi5_init_output(hdmi);
0783     if (r)
0784         goto err_pm_disable;
0785 
0786     r = component_add(&pdev->dev, &hdmi5_component_ops);
0787     if (r)
0788         goto err_uninit_output;
0789 
0790     return 0;
0791 
0792 err_uninit_output:
0793     hdmi5_uninit_output(hdmi);
0794 err_pm_disable:
0795     pm_runtime_disable(&pdev->dev);
0796 err_free:
0797     kfree(hdmi);
0798     return r;
0799 }
0800 
0801 static int hdmi5_remove(struct platform_device *pdev)
0802 {
0803     struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
0804 
0805     component_del(&pdev->dev, &hdmi5_component_ops);
0806 
0807     hdmi5_uninit_output(hdmi);
0808 
0809     pm_runtime_disable(&pdev->dev);
0810 
0811     kfree(hdmi);
0812     return 0;
0813 }
0814 
0815 static const struct of_device_id hdmi_of_match[] = {
0816     { .compatible = "ti,omap5-hdmi", },
0817     { .compatible = "ti,dra7-hdmi", },
0818     {},
0819 };
0820 
0821 struct platform_driver omapdss_hdmi5hw_driver = {
0822     .probe      = hdmi5_probe,
0823     .remove     = hdmi5_remove,
0824     .driver         = {
0825         .name   = "omapdss_hdmi5",
0826         .of_match_table = hdmi_of_match,
0827         .suppress_bind_attrs = true,
0828     },
0829 };