X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fexynos%2Fexynos_hdmi.c;h=153edeb058a9a9b45eb2882dd3f573317ec813d9;hb=7ecb1cc1462ef33a4cbfd62e14ebc6efc18635f6;hp=a884b495ec7b9ebb82c7950b0d3b7c9c3fe6c4f7;hpb=28b837d445453c19ba00c3bcc06b0aaac25d8c6d;p=cascardo%2Flinux.git diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a884b495ec7b..153edeb058a9 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -47,6 +47,8 @@ #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define HOTPLUG_DEBOUNCE_MS 1100 + struct hdmi_resources { struct clk *hdmi; struct clk *sclk_hdmi; @@ -144,8 +146,7 @@ struct hdmi_context { unsigned int external_irq; unsigned int internal_irq; unsigned int curr_irq; - struct workqueue_struct *wq; - struct work_struct hotplug_work; + struct timer_list hotplug_timer; struct i2c_client *ddc_port; struct i2c_client *hdmiphy_port; @@ -2099,10 +2100,9 @@ static struct exynos_panel_ops hdmi_ops = { /* * Handle hotplug events outside the interrupt handler proper. */ -static void hdmi_hotplug_func(struct work_struct *work) +static void hdmi_hotplug_timer_func(unsigned long data) { - struct hdmi_context *hdata = - container_of(work, struct hdmi_context, hotplug_work); + struct hdmi_context *hdata = (struct hdmi_context *)data; drm_helper_hpd_irq_event(hdata->drm_dev); } @@ -2110,7 +2110,8 @@ static void hdmi_hotplug_func(struct work_struct *work) static irqreturn_t hdmi_irq_handler(int irq, void *arg) { struct hdmi_context *hdata = arg; - u32 intc_flag; + u32 intc_flag, time_ms = HOTPLUG_DEBOUNCE_MS; + if (hdata->is_hdmi_powered_on) { intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG); /* clearing flags for HPD plug/unplug */ @@ -2126,10 +2127,17 @@ static irqreturn_t hdmi_irq_handler(int irq, void *arg) hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0, HDMI_INTC_FLAG_HPD_PLUG); } + + /* + * No need to debounce if we're powered on, the hardware + * has already done it for us. + */ + time_ms = 0; } if (hdata->drm_dev && hdata->hpd_handle) - queue_work(hdata->wq, &hdata->hotplug_work); + mod_timer(&hdata->hotplug_timer, + jiffies + msecs_to_jiffies(time_ms)); return IRQ_HANDLED; } @@ -2393,21 +2401,11 @@ static int __devinit hdmi_probe(struct platform_device *pdev) hdata->external_irq = gpio_to_irq(hdata->hpd_gpio); - /* create workqueue and hotplug work */ - hdata->wq = alloc_workqueue("exynos-drm-hdmi", - WQ_UNBOUND | WQ_NON_REENTRANT, 1); - if (hdata->wq == NULL) { - DRM_ERROR("Failed to create workqueue.\n"); - ret = -ENOMEM; - goto err_hdmiphy; - } - INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func); - ret = request_irq(hdata->internal_irq, hdmi_irq_handler, IRQF_SHARED, "int_hdmi", hdata); if (ret) { DRM_ERROR("request int interrupt failed.\n"); - goto err_workqueue; + goto err_hdmiphy; } disable_irq(hdata->internal_irq); @@ -2420,6 +2418,9 @@ static int __devinit hdmi_probe(struct platform_device *pdev) } disable_irq(hdata->external_irq); + setup_timer(&hdata->hotplug_timer, hdmi_hotplug_timer_func, + (unsigned long)hdata); + if (of_device_is_compatible(dev->of_node, "samsung,exynos5-hdmi")) { ret = hdmi_register_audio_device(pdev); @@ -2445,8 +2446,6 @@ err_ext_irq: free_irq(hdata->external_irq, hdata); err_int_irq: free_irq(hdata->internal_irq, hdata); - err_workqueue: - destroy_workqueue(hdata->wq); err_hdmiphy: put_device(&hdata->hdmiphy_port->dev); err_ddc: @@ -2478,8 +2477,7 @@ static int __devexit hdmi_remove(struct platform_device *pdev) free_irq(hdata->internal_irq, hdata); free_irq(hdata->external_irq, hdata); - cancel_work_sync(&hdata->hotplug_work); - destroy_workqueue(hdata->wq); + del_timer(&hdata->hotplug_timer); clk_disable(res->hdmi); clk_disable(res->sclk_hdmi);