drm/bridge: analogix_dp: Fix hpd handling for GPIO

Change-Id: I0d62201095ab82f5ed0ddcfd53abaef6089a2e9d
Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
Wyon Bi
2020-01-02 17:48:27 +08:00
committed by Tao Huang
parent ec64749b4e
commit 8c15e0b8c5
2 changed files with 56 additions and 44 deletions

View File

@@ -800,25 +800,44 @@ static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
return ret < 0 ? ret : 0;
}
static irqreturn_t analogix_dp_hpd_irq_handler(int irq, void *arg)
{
struct analogix_dp_device *dp = arg;
if (dp->drm_dev)
drm_helper_hpd_irq_event(dp->drm_dev);
return IRQ_HANDLED;
}
static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
{
struct analogix_dp_device *dp = arg;
irqreturn_t ret = IRQ_NONE;
enum dp_irq_type irq_type;
int ret;
ret = pm_runtime_get_sync(dp->dev);
if (ret < 0)
return IRQ_NONE;
irq_type = analogix_dp_get_irq_type(dp);
if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
if (irq_type != DP_IRQ_TYPE_UNKNOWN)
analogix_dp_mute_hpd_interrupt(dp);
ret = IRQ_WAKE_THREAD;
}
return ret;
pm_runtime_put_sync(dp->dev);
return IRQ_WAKE_THREAD;
}
static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
{
struct analogix_dp_device *dp = arg;
enum dp_irq_type irq_type;
int ret;
ret = pm_runtime_get_sync(dp->dev);
if (ret < 0)
return IRQ_NONE;
irq_type = analogix_dp_get_irq_type(dp);
if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN ||
@@ -833,6 +852,8 @@ static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
analogix_dp_unmute_hpd_interrupt(dp);
}
pm_runtime_put_sync(dp->dev);
return IRQ_HANDLED;
}
@@ -1567,7 +1588,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
struct platform_device *pdev = to_platform_device(dev);
struct analogix_dp_device *dp;
struct resource *res;
unsigned int irq_flags;
int ret;
if (!plat_data) {
@@ -1640,20 +1660,21 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
}
if (dp->hpd_gpiod) {
/*
* Set up the hotplug GPIO from the device tree as an interrupt.
* Simply specifying a different interrupt in the device tree
* doesn't work since we handle hotplug rather differently when
* using a GPIO. We also need the actual GPIO specifier so
* that we can get the current state of the GPIO.
*/
dp->irq = gpiod_to_irq(dp->hpd_gpiod);
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
} else {
dp->irq = platform_get_irq(pdev, 0);
irq_flags = 0;
ret = devm_request_threaded_irq(dev,
gpiod_to_irq(dp->hpd_gpiod),
NULL,
analogix_dp_hpd_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"analogix-hpd", dp);
if (ret) {
dev_err(dev, "failed to request hpd IRQ: %d\n", ret);
return ERR_PTR(ret);
}
}
dp->irq = platform_get_irq(pdev, 0);
if (dp->irq == -ENXIO) {
dev_err(&pdev->dev, "failed to get irq\n");
return ERR_PTR(-ENODEV);
@@ -1663,7 +1684,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
analogix_dp_hardirq,
analogix_dp_irq_thread,
irq_flags, "analogix-dp", dp);
0, "analogix-dp", dp);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
return ERR_PTR(ret);

View File

@@ -22,7 +22,6 @@
#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
static void analogix_dp_write(struct analogix_dp_device *dp, u32 reg, u32 val)
{
@@ -203,11 +202,10 @@ void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
reg = COMMON_INT_MASK_3;
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_3, reg);
reg = COMMON_INT_MASK_4;
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
reg = INT_STA_MASK;
analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
if (dp->force_hpd || dp->hpd_gpiod)
analogix_dp_mute_hpd_interrupt(dp);
else
analogix_dp_unmute_hpd_interrupt(dp);
}
void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
@@ -220,7 +218,7 @@ void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA_MASK);
reg &= ~INT_STA_MASK;
reg &= ~INT_HPD;
analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
}
@@ -232,7 +230,8 @@ void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
reg = COMMON_INT_MASK_4;
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
reg = INT_STA_MASK;
reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA_MASK);
reg |= INT_HPD;
analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
}
@@ -437,27 +436,19 @@ enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)
{
u32 reg;
if (dp->hpd_gpiod) {
reg = gpiod_get_value(dp->hpd_gpiod);
if (reg)
return DP_IRQ_TYPE_HP_CABLE_IN;
else
return DP_IRQ_TYPE_HP_CABLE_OUT;
} else {
/* Parse hotplug interrupt status register */
reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_STA_4);
/* Parse hotplug interrupt status register */
reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_STA_4);
if (reg & PLUG)
return DP_IRQ_TYPE_HP_CABLE_IN;
if (reg & PLUG)
return DP_IRQ_TYPE_HP_CABLE_IN;
if (reg & HPD_LOST)
return DP_IRQ_TYPE_HP_CABLE_OUT;
if (reg & HPD_LOST)
return DP_IRQ_TYPE_HP_CABLE_OUT;
if (reg & HOTPLUG_CHG)
return DP_IRQ_TYPE_HP_CHANGE;
if (reg & HOTPLUG_CHG)
return DP_IRQ_TYPE_HP_CHANGE;
return DP_IRQ_TYPE_UNKNOWN;
}
return DP_IRQ_TYPE_UNKNOWN;
}
void analogix_dp_reset_aux(struct analogix_dp_device *dp)