diff options
-rw-r--r-- | drivers/gpu/drm/tegra/dpaux.c | 30 |
1 files 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 @@ | |||
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/reset.h> | 16 | #include <linux/reset.h> |
17 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/workqueue.h> | ||
18 | 19 | ||
19 | #include <drm/drm_dp_helper.h> | 20 | #include <drm/drm_dp_helper.h> |
20 | #include <drm/drm_panel.h> | 21 | #include <drm/drm_panel.h> |
@@ -41,6 +42,7 @@ struct tegra_dpaux { | |||
41 | struct regulator *vdd; | 42 | struct regulator *vdd; |
42 | 43 | ||
43 | struct completion complete; | 44 | struct completion complete; |
45 | struct work_struct work; | ||
44 | struct list_head list; | 46 | struct list_head list; |
45 | }; | 47 | }; |
46 | 48 | ||
@@ -49,6 +51,11 @@ static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) | |||
49 | return container_of(aux, struct tegra_dpaux, aux); | 51 | return container_of(aux, struct tegra_dpaux, aux); |
50 | } | 52 | } |
51 | 53 | ||
54 | static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work) | ||
55 | { | ||
56 | return container_of(work, struct tegra_dpaux, work); | ||
57 | } | ||
58 | |||
52 | static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux, | 59 | static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux, |
53 | unsigned long offset) | 60 | unsigned long offset) |
54 | { | 61 | { |
@@ -231,6 +238,14 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, | |||
231 | return ret; | 238 | return ret; |
232 | } | 239 | } |
233 | 240 | ||
241 | static void tegra_dpaux_hotplug(struct work_struct *work) | ||
242 | { | ||
243 | struct tegra_dpaux *dpaux = work_to_dpaux(work); | ||
244 | |||
245 | if (dpaux->output) | ||
246 | drm_helper_hpd_irq_event(dpaux->output->connector.dev); | ||
247 | } | ||
248 | |||
234 | static irqreturn_t tegra_dpaux_irq(int irq, void *data) | 249 | static irqreturn_t tegra_dpaux_irq(int irq, void *data) |
235 | { | 250 | { |
236 | struct tegra_dpaux *dpaux = data; | 251 | struct tegra_dpaux *dpaux = data; |
@@ -241,16 +256,8 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) | |||
241 | value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX); | 256 | value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX); |
242 | tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX); | 257 | tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX); |
243 | 258 | ||
244 | if (value & DPAUX_INTR_PLUG_EVENT) { | 259 | if (value & (DPAUX_INTR_PLUG_EVENT | DPAUX_INTR_UNPLUG_EVENT)) |
245 | if (dpaux->output) { | 260 | schedule_work(&dpaux->work); |
246 | drm_helper_hpd_irq_event(dpaux->output->connector.dev); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (value & DPAUX_INTR_UNPLUG_EVENT) { | ||
251 | if (dpaux->output) | ||
252 | drm_helper_hpd_irq_event(dpaux->output->connector.dev); | ||
253 | } | ||
254 | 261 | ||
255 | if (value & DPAUX_INTR_IRQ_EVENT) { | 262 | if (value & DPAUX_INTR_IRQ_EVENT) { |
256 | /* TODO: handle this */ | 263 | /* TODO: handle this */ |
@@ -273,6 +280,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
273 | if (!dpaux) | 280 | if (!dpaux) |
274 | return -ENOMEM; | 281 | return -ENOMEM; |
275 | 282 | ||
283 | INIT_WORK(&dpaux->work, tegra_dpaux_hotplug); | ||
276 | init_completion(&dpaux->complete); | 284 | init_completion(&dpaux->complete); |
277 | INIT_LIST_HEAD(&dpaux->list); | 285 | INIT_LIST_HEAD(&dpaux->list); |
278 | dpaux->dev = &pdev->dev; | 286 | dpaux->dev = &pdev->dev; |
@@ -361,6 +369,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev) | |||
361 | list_del(&dpaux->list); | 369 | list_del(&dpaux->list); |
362 | mutex_unlock(&dpaux_lock); | 370 | mutex_unlock(&dpaux_lock); |
363 | 371 | ||
372 | cancel_work_sync(&dpaux->work); | ||
373 | |||
364 | clk_disable_unprepare(dpaux->clk_parent); | 374 | clk_disable_unprepare(dpaux->clk_parent); |
365 | reset_control_assert(dpaux->rst); | 375 | reset_control_assert(dpaux->rst); |
366 | clk_disable_unprepare(dpaux->clk); | 376 | clk_disable_unprepare(dpaux->clk); |