From 289059c61b2cd58d400cf542ed6e76c5e65b1473 Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Fri, 28 Sep 2018 11:22:03 +0800 Subject: [PATCH] drm/bridge: analogix_dp: rework hpd gpio detection Change-Id: I0d62201095ab82f5ed0ddcfd53abaef6089a2e9d Signed-off-by: Wyon Bi --- .../bindings/display/bridge/analogix_dp.txt | 2 + .../drm/bridge/analogix/analogix_dp_core.c | 82 +++++++++++-------- .../drm/bridge/analogix/analogix_dp_core.h | 3 +- .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 43 +++------- 4 files changed, 66 insertions(+), 64 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt index 797c6ded735d..ad352d22be38 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt @@ -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: diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index dca915c74cb8..fbde564c072e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -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); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 79940b0b75db..7d566136d384 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -15,6 +15,7 @@ #include #include +#include #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; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 2f7c1819739b..9205d91e8d8f 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -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; }