diff options
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/hdmi4.c')
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi4.c | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 5c7dd5c06593..626aad2bef46 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -81,6 +81,37 @@ static void hdmi_runtime_put(void) WARN_ON(r < 0 && r != -ENOSYS); } +static irqreturn_t hdmi_irq_handler(int irq, void *data) +{ + struct hdmi_wp_data *wp = data; + u32 irqstatus; + + irqstatus = hdmi_wp_get_irqstatus(wp); + hdmi_wp_set_irqstatus(wp, irqstatus); + + if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && + irqstatus & HDMI_IRQ_LINK_DISCONNECT) { + /* + * If we get both connect and disconnect interrupts at the same + * time, turn off the PHY, clear interrupts, and restart, which + * raises connect interrupt if a cable is connected, or nothing + * if cable is not connected. + */ + hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); + + hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | + HDMI_IRQ_LINK_DISCONNECT); + + hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); + } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { + hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); + } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { + hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); + } + + return IRQ_HANDLED; +} + static int hdmi_init_regulator(void) { int r; @@ -150,11 +181,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) struct omap_video_timings *p; struct omap_overlay_manager *mgr = hdmi.output.manager; unsigned long phy; + struct hdmi_wp_data *wp = &hdmi.wp; r = hdmi_power_on_core(dssdev); if (r) return r; + /* disable and clear irqs */ + hdmi_wp_clear_irqenable(wp, 0xffffffff); + hdmi_wp_set_irqstatus(wp, 0xffffffff); + p = &hdmi.cfg.timings; DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); @@ -171,12 +207,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) goto err_pll_enable; } - r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg); + r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); if (r) { - DSSDBG("Failed to start PHY\n"); - goto err_phy_enable; + DSSDBG("Failed to configure PHY\n"); + goto err_phy_cfg; } + r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); + if (r) + goto err_phy_pwr; + hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); /* bypass TV gamma table */ @@ -193,13 +233,17 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) if (r) goto err_mgr_enable; + hdmi_wp_set_irqenable(wp, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); + return 0; err_mgr_enable: hdmi_wp_video_stop(&hdmi.wp); err_vid_enable: - hdmi_phy_disable(&hdmi.phy, &hdmi.wp); -err_phy_enable: +err_phy_cfg: + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); +err_phy_pwr: hdmi_pll_disable(&hdmi.pll, &hdmi.wp); err_pll_enable: hdmi_power_off_core(dssdev); @@ -210,10 +254,14 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) { struct omap_overlay_manager *mgr = hdmi.output.manager; + hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); + dss_mgr_disable(mgr); hdmi_wp_video_stop(&hdmi.wp); - hdmi_phy_disable(&hdmi.phy, &hdmi.wp); + + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_pll_disable(&hdmi.pll, &hdmi.wp); hdmi_power_off_core(dssdev); @@ -636,6 +684,7 @@ err: static int omapdss_hdmihw_probe(struct platform_device *pdev) { int r; + int irq; hdmi.pdev = pdev; @@ -669,6 +718,20 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) return r; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + DSSERR("platform_get_irq failed\n"); + return -ENODEV; + } + + r = devm_request_threaded_irq(&pdev->dev, irq, + NULL, hdmi_irq_handler, + IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); + if (r) { + DSSERR("HDMI IRQ request failed\n"); + return r; + } + pm_runtime_enable(&pdev->dev); hdmi_init_output(pdev); |