drm/bridge: analogix_dp: rework hpd gpio detection

Change-Id: I0d62201095ab82f5ed0ddcfd53abaef6089a2e9d
Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
Wyon Bi
2018-09-28 11:22:03 +08:00
parent 828b971fb0
commit 289059c61b
4 changed files with 66 additions and 64 deletions

View File

@@ -31,6 +31,8 @@ Optional properties for dp-controller:
-hpd-gpios:
Hotplug detect GPIO.
Indicates which GPIO should be used for hotplug detection
(if the hot-plug detection pin doesn't appear as an interrupt/status
bit in the eDP controller itself)
-port@[X]: SoC specific port nodes with endpoint definitions as defined
in Documentation/devicetree/bindings/media/video-interfaces.txt,
please refer to the SoC specific binding document:

View File

@@ -730,6 +730,20 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
}
}
static irqreturn_t analogix_dp_hpd_irq_handler(int irq, void *arg)
{
struct analogix_dp_device *dp = arg;
dev_info(dp->dev, "hot-plug detect status: %s\n",
gpiod_get_value(dp->hpd_gpio) ?
"connected" : "disconnected");
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;
@@ -876,12 +890,18 @@ analogix_dp_detect(struct drm_connector *connector, bool force)
struct analogix_dp_device *dp = to_dp(connector);
enum drm_connector_status status = connector_status_connected;
pm_runtime_get_sync(dp->dev);
if (dp->hpd_gpio) {
status = gpiod_get_value(dp->hpd_gpio) ?
connector_status_connected :
connector_status_disconnected;
} else {
pm_runtime_get_sync(dp->dev);
if (analogix_dp_detect_hpd(dp))
status = connector_status_disconnected;
if (analogix_dp_detect_hpd(dp))
status = connector_status_disconnected;
pm_runtime_put(dp->dev);
pm_runtime_put(dp->dev);
}
return status;
}
@@ -1170,7 +1190,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
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) {
@@ -1230,33 +1249,18 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
dp->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0);
if (!gpio_is_valid(dp->hpd_gpio))
dp->hpd_gpio = of_get_named_gpio(dev->of_node,
"samsung,hpd-gpio", 0);
if (gpio_is_valid(dp->hpd_gpio)) {
/*
* 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.
*/
ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN,
"hpd_gpio");
if (ret) {
dev_err(&pdev->dev, "failed to get hpd gpio\n");
return ret;
}
dp->irq = gpio_to_irq(dp->hpd_gpio);
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
} else {
dp->hpd_gpio = -ENODEV;
dp->irq = platform_get_irq(pdev, 0);
irq_flags = 0;
/*
* if the hot-plug detection pin doesn't appear as an interrupt/status
* bit in the eDP controller itself, optionally from GPIO.
*/
dp->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
if (IS_ERR(dp->hpd_gpio)) {
ret = PTR_ERR(dp->hpd_gpio);
dev_err(dev, "failed to request hpd GPIO: %d\n", ret);
return ret;
}
dp->irq = platform_get_irq(pdev, 0);
if (dp->irq == -ENXIO) {
dev_err(&pdev->dev, "failed to get irq\n");
return -ENODEV;
@@ -1269,12 +1273,26 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
}
}
if (dp->hpd_gpio) {
ret = devm_request_threaded_irq(dev, gpiod_to_irq(dp->hpd_gpio),
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 ret;
}
}
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");
dev_err(&pdev->dev, "failed to request host irq\n");
return ret;
}
disable_irq(dp->irq);

View File

@@ -15,6 +15,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <linux/gpio/consumer.h>
#define DP_TIMEOUT_LOOP_COUNT 100
#define MAX_CR_LOOP 5
@@ -170,7 +171,7 @@ struct analogix_dp_device {
struct link_train link_train;
struct phy *phy;
int dpms_mode;
int hpd_gpio;
struct gpio_desc *hpd_gpio;
bool force_hpd;
struct analogix_dp_plat_data *plat_data;

View File

@@ -372,9 +372,6 @@ void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)
{
u32 reg;
if (gpio_is_valid(dp->hpd_gpio))
return;
reg = HOTPLUG_CHG | HPD_LOST | PLUG;
writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);
@@ -386,9 +383,6 @@ void analogix_dp_init_hpd(struct analogix_dp_device *dp)
{
u32 reg;
if (gpio_is_valid(dp->hpd_gpio))
return;
analogix_dp_clear_hotplug_interrupts(dp);
reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
@@ -409,27 +403,19 @@ enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)
{
u32 reg;
if (gpio_is_valid(dp->hpd_gpio)) {
reg = gpio_get_value(dp->hpd_gpio);
if (reg)
return DP_IRQ_TYPE_HP_CABLE_IN;
else
return DP_IRQ_TYPE_HP_CABLE_OUT;
} else {
/* Parse hotplug interrupt status register */
reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);
/* Parse hotplug interrupt status register */
reg = readl(dp->reg_base + 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)
@@ -477,14 +463,9 @@ int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp)
{
u32 reg;
if (gpio_is_valid(dp->hpd_gpio)) {
if (gpio_get_value(dp->hpd_gpio))
return 0;
} else {
reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
if (reg & HPD_STATUS)
return 0;
}
reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
if (reg & HPD_STATUS)
return 0;
return -EINVAL;
}