Skip to content

Commit

Permalink
video: exynos_dp: Enable hotplug interrupts
Browse files Browse the repository at this point in the history
Enable hotplug interrupts and move the hotplug scheduling into the
interrupt handler. This allows us to introduce a screen at any time
while we're running.

[jg1.han@samsung.com: moved the bit masking of hotplug interrupts]
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
  • Loading branch information
Sean Paul authored and Jingoo Han committed Nov 29, 2012
1 parent 784fa9a commit c30ffb9
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 14 deletions.
38 changes: 30 additions & 8 deletions drivers/video/exynos/exynos_dp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
{
int timeout_loop = 0;

exynos_dp_init_hpd(dp);

usleep_range(200, 210);

while (exynos_dp_get_plug_in_status(dp) != 0) {
timeout_loop++;
if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
Expand Down Expand Up @@ -834,7 +830,32 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
{
struct exynos_dp_device *dp = arg;

dev_err(dp->dev, "exynos_dp_irq_handler\n");
enum dp_irq_type irq_type;

irq_type = exynos_dp_get_irq_type(dp);
switch (irq_type) {
case DP_IRQ_TYPE_HP_CABLE_IN:
dev_dbg(dp->dev, "Received irq - cable in\n");
schedule_work(&dp->hotplug_work);
exynos_dp_clear_hotplug_interrupts(dp);
break;
case DP_IRQ_TYPE_HP_CABLE_OUT:
dev_dbg(dp->dev, "Received irq - cable out\n");
exynos_dp_clear_hotplug_interrupts(dp);
break;
case DP_IRQ_TYPE_HP_CHANGE:
/*
* We get these change notifications once in a while, but there
* is nothing we can do with them. Just ignore it for now and
* only handle cable changes.
*/
dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
exynos_dp_clear_hotplug_interrupts(dp);
break;
default:
dev_err(dp->dev, "Received irq - unknown type!\n");
break;
}
return IRQ_HANDLED;
}

Expand All @@ -847,7 +868,7 @@ static void exynos_dp_hotplug(struct work_struct *work)

ret = exynos_dp_detect_hpd(dp);
if (ret) {
dev_err(dp->dev, "unable to detect hpd\n");
/* Cable has been disconnected, we're done */
return;
}

Expand Down Expand Up @@ -1093,7 +1114,6 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
exynos_dp_init_dp(dp);

platform_set_drvdata(pdev, dp);
schedule_work(&dp->hotplug_work);

return 0;
}
Expand All @@ -1103,6 +1123,8 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);

disable_irq(dp->irq);

if (work_pending(&dp->hotplug_work))
flush_work(&dp->hotplug_work);

Expand Down Expand Up @@ -1159,7 +1181,7 @@ static int exynos_dp_resume(struct device *dev)

exynos_dp_init_dp(dp);

schedule_work(&dp->hotplug_work);
enable_irq(dp->irq);

return 0;
}
Expand Down
9 changes: 9 additions & 0 deletions drivers/video/exynos/exynos_dp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
#ifndef _EXYNOS_DP_CORE_H
#define _EXYNOS_DP_CORE_H

enum dp_irq_type {
DP_IRQ_TYPE_HP_CABLE_IN,
DP_IRQ_TYPE_HP_CABLE_OUT,
DP_IRQ_TYPE_HP_CHANGE,
DP_IRQ_TYPE_UNKNOWN,
};

struct link_train {
int eq_loop;
int cr_loop[4];
Expand Down Expand Up @@ -53,6 +60,8 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
bool enable);
void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
void exynos_dp_init_hpd(struct exynos_dp_device *dp);
enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
void exynos_dp_reset_aux(struct exynos_dp_device *dp);
void exynos_dp_init_aux(struct exynos_dp_device *dp);
int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
Expand Down
38 changes: 32 additions & 6 deletions drivers/video/exynos/exynos_dp_reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
#include "exynos_dp_core.h"
#include "exynos_dp_reg.h"

#define COMMON_INT_MASK_1 (0)
#define COMMON_INT_MASK_2 (0)
#define COMMON_INT_MASK_3 (0)
#define COMMON_INT_MASK_4 (0)
#define INT_STA_MASK (0)
#define COMMON_INT_MASK_1 0
#define COMMON_INT_MASK_2 0
#define COMMON_INT_MASK_3 0
#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)
#define INT_STA_MASK INT_HPD

void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
{
Expand Down Expand Up @@ -324,7 +324,7 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
}

void exynos_dp_init_hpd(struct exynos_dp_device *dp)
void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
{
u32 reg;

Expand All @@ -333,12 +333,38 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp)

reg = INT_HPD;
writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
}

void exynos_dp_init_hpd(struct exynos_dp_device *dp)
{
u32 reg;

exynos_dp_clear_hotplug_interrupts(dp);

reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
reg &= ~(F_HPD | HPD_CTRL);
writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
}

enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
{
u32 reg;

/* Parse hotplug interrupt status register */
reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);

if (reg & PLUG)
return DP_IRQ_TYPE_HP_CABLE_IN;

if (reg & HPD_LOST)
return DP_IRQ_TYPE_HP_CABLE_OUT;

if (reg & HOTPLUG_CHG)
return DP_IRQ_TYPE_HP_CHANGE;

return DP_IRQ_TYPE_UNKNOWN;
}

void exynos_dp_reset_aux(struct exynos_dp_device *dp)
{
u32 reg;
Expand Down

0 comments on commit c30ffb9

Please sign in to comment.