diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index f3369cf..fadd6a0 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -29,6 +29,7 @@ #include <linux/mutex.h> #include <linux/delay.h> #include <linux/string.h> +#include <linux/gpio.h> #include <video/omapdss.h> #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) @@ -54,6 +55,9 @@ static struct { u8 edid_set; bool custom_set; struct hdmi_config cfg; + + int hpd_gpio; + bool phy_tx_enabled; } hdmi; /* @@ -278,6 +282,47 @@ static int hdmi_pll_reset(void) return 0; } +static int hdmi_check_hpd_state(void) +{ + unsigned long flags; + bool hpd; + int r; + /* this should be in ti_hdmi_4xxx_ip private data */ + static DEFINE_SPINLOCK(phy_tx_lock); + + spin_lock_irqsave(&phy_tx_lock, flags); + + hpd = gpio_get_value(hdmi.hpd_gpio); + + if (hpd == hdmi.phy_tx_enabled) { + spin_unlock_irqrestore(&phy_tx_lock, flags); + return 0; + } + + if (hpd) + r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); + else + r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON); + + if (r) { + DSSERR("Failed to %s PHY TX power\n", + hpd ? "enable" : "disable"); + goto err; + } + + hdmi.phy_tx_enabled = hpd; +err: + spin_unlock_irqrestore(&phy_tx_lock, flags); + return r; +} + +static irqreturn_t hpd_irq_handler(int irq, void *data) +{ + hdmi_check_hpd_state(); + + return IRQ_HANDLED; +} + static int hdmi_phy_init(void) { u16 r = 0; @@ -286,10 +331,6 @@ static int hdmi_phy_init(void) if (r) return r; - r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); - if (r) - return r; - /* * Read address 0 in order to get the SCP reset done completed * Dummy access performed to make sure reset is done @@ -311,6 +352,23 @@ static int hdmi_phy_init(void) /* Write to phy address 3 to change the polarity control */ REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); + r = request_threaded_irq(gpio_to_irq(hdmi.hpd_gpio), + NULL, hpd_irq_handler, + IRQF_DISABLED | IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "hpd", NULL); + if (r) { + DSSERR("HPD IRQ request failed\n"); + hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); + return r; + } + + r = hdmi_check_hpd_state(); + if (r) { + free_irq(gpio_to_irq(hdmi.hpd_gpio), NULL); + hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); + return r; + } + return 0; } @@ -361,7 +419,9 @@ static int hdmi_pll_program(struct hdmi_pll_info *fmt) static void hdmi_phy_off(void) { + free_irq(gpio_to_irq(hdmi.hpd_gpio), NULL); hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); + hdmi.phy_tx_enabled = false; } static int hdmi_core_ddc_edid(u8 *pedid, int ext) @@ -1236,12 +1296,15 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_hdmi_data *priv = dssdev->data; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi.lock); + hdmi.hpd_gpio = priv->hpd_gpio; + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); |