summaryrefslogtreecommitdiff
path: root/drivers/video/omap2/dss/hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r--drivers/video/omap2/dss/hdmi.c238
1 files changed, 230 insertions, 8 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index e1c0992b522b..44a885b92825 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -70,6 +70,8 @@ static struct {
int ls_oe_gpio;
int hpd_gpio;
+ bool core_enabled;
+
struct omap_dss_device output;
} hdmi;
@@ -515,8 +517,10 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
{
int r;
- gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
- gpio_set_value(hdmi.ls_oe_gpio, 1);
+ if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
+ if (gpio_is_valid(hdmi.ls_oe_gpio))
+ gpio_set_value(hdmi.ls_oe_gpio, 1);
/* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
udelay(300);
@@ -532,22 +536,30 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
/* Make selection of HDMI in DSS */
dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+ hdmi.core_enabled = true;
+
return 0;
err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg);
err_vdac_enable:
- gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
- gpio_set_value(hdmi.ls_oe_gpio, 0);
+ if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ if (gpio_is_valid(hdmi.ls_oe_gpio))
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
return r;
}
static void hdmi_power_off_core(struct omap_dss_device *dssdev)
{
+ hdmi.core_enabled = false;
+
hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg);
- gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
- gpio_set_value(hdmi.ls_oe_gpio, 0);
+ if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ if (gpio_is_valid(hdmi.ls_oe_gpio))
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
}
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
@@ -662,6 +674,18 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
mutex_unlock(&hdmi.lock);
}
+static void omapdss_hdmi_display_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ const struct hdmi_config *cfg;
+
+ cfg = hdmi_get_timings();
+ if (cfg == NULL)
+ cfg = &vesa_timings[0];
+
+ memcpy(timings, &cfg->timings, sizeof(cfg->timings));
+}
+
static void hdmi_dump_regs(struct seq_file *s)
{
mutex_lock(&hdmi.lock);
@@ -1025,6 +1049,199 @@ static int hdmi_probe_pdata(struct platform_device *pdev)
return 0;
}
+static int hdmi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version());
+
+ r = hdmi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void hdmi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->device);
+
+ if (dst != dssdev->device)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static int hdmi_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ bool need_enable;
+ int r;
+
+ need_enable = hdmi.core_enabled == false;
+
+ if (need_enable) {
+ r = omapdss_hdmi_core_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ r = omapdss_hdmi_read_edid(edid, len);
+
+ if (need_enable)
+ omapdss_hdmi_core_disable(dssdev);
+
+ return r;
+}
+
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ mutex_lock(&hdmi.lock);
+
+ if (!hdmi_mode_has_audio()) {
+ r = -EPERM;
+ goto err;
+ }
+
+ r = hdmi_audio_enable();
+ if (r)
+ goto err;
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev)
+{
+ hdmi_audio_disable();
+}
+
+static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev)
+{
+ return hdmi_audio_start();
+}
+
+static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev)
+{
+ hdmi_audio_stop();
+}
+
+static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev)
+{
+ bool r;
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_mode_has_audio();
+
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev,
+ struct omap_dss_audio *audio)
+{
+ int r;
+
+ mutex_lock(&hdmi.lock);
+
+ if (!hdmi_mode_has_audio()) {
+ r = -EPERM;
+ goto err;
+ }
+
+ r = hdmi_audio_config(audio);
+ if (r)
+ goto err;
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+#else
+static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev)
+{
+ return -EPERM;
+}
+
+static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev)
+{
+}
+
+static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev)
+{
+ return -EPERM;
+}
+
+static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev)
+{
+}
+
+static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev)
+{
+ return false;
+}
+
+static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev,
+ struct omap_dss_audio *audio)
+{
+ return -EPERM;
+}
+#endif
+
+static const struct omapdss_hdmi_ops hdmi_ops = {
+ .connect = hdmi_connect,
+ .disconnect = hdmi_disconnect,
+
+ .enable = omapdss_hdmi_display_enable,
+ .disable = omapdss_hdmi_display_disable,
+
+ .check_timings = omapdss_hdmi_display_check_timing,
+ .set_timings = omapdss_hdmi_display_set_timing,
+ .get_timings = omapdss_hdmi_display_get_timings,
+
+ .read_edid = hdmi_read_edid,
+
+ .audio_enable = omapdss_hdmi_audio_enable,
+ .audio_disable = omapdss_hdmi_audio_disable,
+ .audio_start = omapdss_hdmi_audio_start,
+ .audio_stop = omapdss_hdmi_audio_stop,
+ .audio_supported = omapdss_hdmi_audio_supported,
+ .audio_config = omapdss_hdmi_audio_config,
+};
+
static void hdmi_init_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
@@ -1034,16 +1251,17 @@ static void hdmi_init_output(struct platform_device *pdev)
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+ out->ops.hdmi = &hdmi_ops;
out->owner = THIS_MODULE;
- dss_register_output(out);
+ omapdss_register_output(out);
}
static void __exit hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
- dss_unregister_output(out);
+ omapdss_unregister_output(out);
}
/* HDMI HW IP initialisation */
@@ -1083,6 +1301,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
+ hdmi.ct_cp_hpd_gpio = -1;
+ hdmi.ls_oe_gpio = -1;
+ hdmi.hpd_gpio = -1;
+
hdmi_init_output(pdev);
r = hdmi_panel_init();