drm/vc4: add extcon hdmi connection uevent 74/215574/2
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Fri, 11 Oct 2019 04:43:33 +0000 (13:43 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Fri, 11 Oct 2019 05:20:24 +0000 (14:20 +0900)
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>
drivers/gpu/drm/vc4/vc4_hdmi.c

index fd5522fd179e56399c63ce819e0f2a3580bc9ec1..022c4965a26e3c514b1a9bfa28de690b2f5b8b1b 100644 (file)
@@ -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)