diff options
Diffstat (limited to 'drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c')
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e18b222ed739..e242ed85cb07 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/seq_file.h> -#include <linux/gpio.h> #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) #include <sound/asound.h> #include <sound/asoundef.h> @@ -38,6 +37,9 @@ #include "dss.h" #include "dss_features.h" +#define HDMI_IRQ_LINK_CONNECT (1 << 25) +#define HDMI_IRQ_LINK_DISCONNECT (1 << 26) + static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx, u32 val) { @@ -233,37 +235,39 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); } -static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) +static irqreturn_t hdmi_irq_handler(int irq, void *data) { - bool hpd; - int r; - - mutex_lock(&ip_data->lock); - - hpd = gpio_get_value(ip_data->hpd_gpio); + struct hdmi_ip_data *ip_data = data; + void __iomem *wp_base = hdmi_wp_base(ip_data); + u32 irqstatus; + + irqstatus = hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); + hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, irqstatus); + /* flush posted write */ + hdmi_read_reg(wp_base, HDMI_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_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); - if (hpd) - r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); - else - r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); + /* flush posted write */ + hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); - if (r) { - DSSERR("Failed to %s PHY TX power\n", - hpd ? "enable" : "disable"); - goto err; + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); + } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); } -err: - mutex_unlock(&ip_data->lock); - return r; -} - -static irqreturn_t hpd_irq_handler(int irq, void *data) -{ - struct hdmi_ip_data *ip_data = data; - - hdmi_check_hpd_state(ip_data); - return IRQ_HANDLED; } @@ -272,6 +276,12 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) u16 r = 0; void __iomem *phy_base = hdmi_phy_base(ip_data); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_CLR, + 0xffffffff); + + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQSTATUS, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); if (r) return r; @@ -297,29 +307,23 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) /* Write to phy address 3 to change the polarity control */ REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); - r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), - NULL, hpd_irq_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, "hpd", ip_data); + r = request_threaded_irq(ip_data->irq, NULL, hdmi_irq_handler, + IRQF_ONESHOT, "OMAP HDMI", ip_data); if (r) { - DSSERR("HPD IRQ request failed\n"); + DSSERR("HDMI IRQ request failed\n"); hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); return r; } - r = hdmi_check_hpd_state(ip_data); - if (r) { - free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); - hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); - return r; - } + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_SET, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; } void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) { - free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); + free_irq(ip_data->irq, ip_data); hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); } @@ -476,11 +480,6 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, return l; } -bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) -{ - return gpio_get_value(ip_data->hpd_gpio); -} - static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, struct hdmi_core_infoframe_avi *avi_cfg, struct hdmi_core_packet_enable_repeat *repeat_cfg) |