summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeung-Woo Kim <sw0312.kim@samsung.com>2019-10-11 13:43:33 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2019-10-11 14:20:24 +0900
commit737c6b871eab9b7ae3b940609509da8c187341e9 (patch)
tree8570014c6b3a9eff0d1207c489b5217932b4c69a
parent89dcbe9b298c1c5428abe8fe0fe1a1fddf088286 (diff)
downloadlinux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.tar.gz
linux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.tar.bz2
linux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.zip
drm/vc4: add extcon hdmi connection uevent
Add extcon hdmi connection and disconnection ueven when extcon module is enabled. The vc4 hdmi detection is done by polling way, so extcon uevent for connection is a bit slow after changing real hdmi cable state. Change-Id: I962f7a39b7a3344f9793e436ef28c36b123571a8 Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c64
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index fd5522fd179e..022c4965a26e 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -47,6 +47,7 @@
#include <drm/drm_edid.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/extcon-provider.h>
#include <linux/i2c.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
@@ -97,6 +98,11 @@ struct vc4_hdmi {
struct clk *pixel_clock;
struct clk *hsm_clock;
+
+ enum drm_connector_status status;
+#ifdef CONFIG_EXTCON
+ struct extcon_dev *edev;
+#endif
};
#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset)
@@ -238,22 +244,40 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ enum drm_connector_status status;
if (vc4->hdmi->hpd_gpio) {
if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
- vc4->hdmi->hpd_active_low)
- return connector_status_connected;
+ vc4->hdmi->hpd_active_low) {
+ status = connector_status_connected;
+ goto out;
+ }
cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
- return connector_status_disconnected;
+ status = connector_status_disconnected;
+ goto out;
}
- if (drm_probe_ddc(vc4->hdmi->ddc))
- return connector_status_connected;
+ if (drm_probe_ddc(vc4->hdmi->ddc)) {
+ status = connector_status_connected;
+ goto out;
+ }
- if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
- return connector_status_connected;
+ if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
+ status = connector_status_connected;
+ goto out;
+ }
cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
- return connector_status_disconnected;
+ status = connector_status_disconnected;
+out:
+ if (status != vc4->hdmi->status) {
+#ifdef CONFIG_EXTCON
+ extcon_set_state_sync(vc4->hdmi->edev, EXTCON_DISP_HDMI,
+ (status == connector_status_connected ?
+ true : false));
+#endif
+ vc4->hdmi->status = status;
+ }
+ return status;
}
static void vc4_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1292,6 +1316,13 @@ static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = {
};
#endif
+#ifdef CONFIG_EXTCON
+static const unsigned int vc4_hdmi_extcon_cable[] = {
+ EXTCON_DISP_HDMI,
+ EXTCON_NONE,
+};
+#endif
+
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1307,6 +1338,23 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
if (!hdmi)
return -ENOMEM;
+ hdmi->status = connector_status_disconnected;
+
+#ifdef CONFIG_EXTCON
+ /* Initialize extcon device */
+ hdmi->edev = devm_extcon_dev_allocate(dev, vc4_hdmi_extcon_cable);
+ if (IS_ERR(hdmi->edev)) {
+ dev_err(dev, "failed to allocate memory for extcon\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_extcon_dev_register(dev, hdmi->edev);
+ if (ret) {
+ dev_err(dev, "failed to register extcon device\n");
+ return ret;
+ }
+#endif
+
vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder),
GFP_KERNEL);
if (!vc4_hdmi_encoder)