From 724fd140d568f472120b550ec10343ee022a307f Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 9 May 2014 15:05:10 +0900 Subject: [PATCH] drm/exynos: Debounce HDMI hotplug interrupts This patch debounces hotplug interrupts generated by the HDMI hotplug gpio. The reason this is needed is that we get multiple (5) interrupts every time a monitor is inserted which causes us to needlessly enable and disable the IP block. Signed-off-by: Sean Paul Signed-off-by: Rahul Sharma Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c7329d97413a..73a7acb1283c 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -50,6 +50,8 @@ #define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) +#define HOTPLUG_DEBOUNCE_MS 1100 + /* AVI header and aspect ratio */ #define HDMI_AVI_VERSION 0x02 #define HDMI_AVI_LENGTH 0x0D @@ -187,6 +189,7 @@ struct hdmi_context { void __iomem *regs; int irq; + struct delayed_work hotplug_work; struct i2c_adapter *ddc_adpt; struct i2c_client *hdmiphy_port; @@ -1857,6 +1860,8 @@ static void hdmi_poweroff(struct exynos_drm_display *display) hdmiphy_poweroff(hdata); + cancel_delayed_work(&hdata->hotplug_work); + clk_disable_unprepare(res->sclk_hdmi); clk_disable_unprepare(res->hdmi); clk_disable_unprepare(res->hdmiphy); @@ -1903,9 +1908,11 @@ static struct exynos_drm_display hdmi_display = { .ops = &hdmi_display_ops, }; -static irqreturn_t hdmi_irq_thread(int irq, void *arg) +static void hdmi_hotplug_work_func(struct work_struct *work) { - struct hdmi_context *hdata = arg; + struct hdmi_context *hdata; + + hdata = container_of(work, struct hdmi_context, hotplug_work.work); mutex_lock(&hdata->hdmi_mutex); hdata->hpd = gpio_get_value(hdata->hpd_gpio); @@ -1913,6 +1920,14 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) if (hdata->drm_dev) drm_helper_hpd_irq_event(hdata->drm_dev); +} + +static irqreturn_t hdmi_irq_thread(int irq, void *arg) +{ + struct hdmi_context *hdata = arg; + + mod_delayed_work(system_wq, &hdata->hotplug_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); return IRQ_HANDLED; } @@ -2142,6 +2157,8 @@ static int hdmi_probe(struct platform_device *pdev) hdata->hpd = gpio_get_value(hdata->hpd_gpio); + INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); + ret = devm_request_threaded_irq(dev, hdata->irq, NULL, hdmi_irq_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, @@ -2167,6 +2184,8 @@ static int hdmi_remove(struct platform_device *pdev) { struct hdmi_context *hdata = hdmi_display.ctx; + cancel_delayed_work_sync(&hdata->hotplug_work); + put_device(&hdata->hdmiphy_port->dev); put_device(&hdata->ddc_adpt->dev); -- 2.30.2