From 2fff79d38bbed2266232d2526a19d42cde476ea7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Apr 2014 16:42:32 +0200 Subject: [PATCH] drm/tegra: dp - Implement hotplug detection in work queue Calling the drm_helper_hpd_irq_event() helper can sleep, so instead of invoking it directly from the interrupt handler, schedule a work queue and run it from there. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dpaux.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 2b725ba7facc..208fc1bef7c5 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ struct tegra_dpaux { struct regulator *vdd; struct completion complete; + struct work_struct work; struct list_head list; }; @@ -49,6 +51,11 @@ static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) return container_of(aux, struct tegra_dpaux, aux); } +static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work) +{ + return container_of(work, struct tegra_dpaux, work); +} + static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux, unsigned long offset) { @@ -231,6 +238,14 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, return ret; } +static void tegra_dpaux_hotplug(struct work_struct *work) +{ + struct tegra_dpaux *dpaux = work_to_dpaux(work); + + if (dpaux->output) + drm_helper_hpd_irq_event(dpaux->output->connector.dev); +} + static irqreturn_t tegra_dpaux_irq(int irq, void *data) { struct tegra_dpaux *dpaux = data; @@ -241,16 +256,8 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX); tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX); - if (value & DPAUX_INTR_PLUG_EVENT) { - if (dpaux->output) { - drm_helper_hpd_irq_event(dpaux->output->connector.dev); - } - } - - if (value & DPAUX_INTR_UNPLUG_EVENT) { - if (dpaux->output) - drm_helper_hpd_irq_event(dpaux->output->connector.dev); - } + if (value & (DPAUX_INTR_PLUG_EVENT | DPAUX_INTR_UNPLUG_EVENT)) + schedule_work(&dpaux->work); if (value & DPAUX_INTR_IRQ_EVENT) { /* TODO: handle this */ @@ -273,6 +280,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (!dpaux) return -ENOMEM; + INIT_WORK(&dpaux->work, tegra_dpaux_hotplug); init_completion(&dpaux->complete); INIT_LIST_HEAD(&dpaux->list); dpaux->dev = &pdev->dev; @@ -361,6 +369,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev) list_del(&dpaux->list); mutex_unlock(&dpaux_lock); + cancel_work_sync(&dpaux->work); + clk_disable_unprepare(dpaux->clk_parent); reset_control_assert(dpaux->rst); clk_disable_unprepare(dpaux->clk); -- 2.20.1