diff options
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi.h | 1 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 81 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | 1 |
4 files changed, 51 insertions, 38 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0f93903d440..0fb3662e28b 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -1072,6 +1072,12 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) if (IS_ERR(hdmi.ip_data.base_wp)) return PTR_ERR(hdmi.ip_data.base_wp); + hdmi.ip_data.irq = platform_get_irq(pdev, 0); + if (hdmi.ip_data.irq < 0) { + DSSERR("platform_get_irq failed\n"); + return -ENODEV; + } + r = hdmi_get_clocks(pdev); if (r) { DSSERR("can't get clocks\n"); diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 216aa704f9d..2f7fbc89457 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -155,6 +155,7 @@ struct hdmi_ip_data { unsigned long core_av_offset; unsigned long pll_offset; unsigned long phy_offset; + int irq; const struct ti_hdmi_ip_ops *ops; struct hdmi_config cfg; struct hdmi_pll_info pll_data; diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e18b222ed73..052f2db35d6 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -38,6 +38,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 +236,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 +277,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 +308,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); } diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 8366ae19e82..6ef2f929a76 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h @@ -33,6 +33,7 @@ #define HDMI_WP_IRQSTATUS 0x28 #define HDMI_WP_PWR_CTRL 0x40 #define HDMI_WP_IRQENABLE_SET 0x2C +#define HDMI_WP_IRQENABLE_CLR 0x30 #define HDMI_WP_VIDEO_CFG 0x50 #define HDMI_WP_VIDEO_SIZE 0x60 #define HDMI_WP_VIDEO_TIMING_H 0x68 |