mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
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:
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user