diff options
author | Sean Paul <seanpaul@chromium.org> | 2014-05-09 15:05:10 +0900 |
---|---|---|
committer | Inki Dae <daeinki@gmail.com> | 2014-06-02 02:07:06 +0900 |
commit | 724fd140d568f472120b550ec10343ee022a307f (patch) | |
tree | acf405f66809dba62243697f3bad1cdd2d5fe2e8 /drivers/gpu/drm/exynos | |
parent | 35b95ac5c3fbf93c8d42187d5688db3e89a12f61 (diff) | |
download | linux-724fd140d568f472120b550ec10343ee022a307f.tar.bz2 |
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 <seanpaul@chromium.org>
Signed-off-by: Rahul Sharma <Rahul.Sharma@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 23 |
1 files 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); |