drm/vc4: add extcon hdmi connection uevent
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 30 Jun 2020 05:32:02 +0000 (14:32 +0900)
committerHoegeun Kwon <hoegeun.kwon@samsung.com>
Mon, 6 Jul 2020 09:09:48 +0000 (18:09 +0900)
Add extcon hdmi connection and disconnection uevent 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>
Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h

index 031d4e5..200f30b 100644 (file)
@@ -36,6 +36,7 @@
 #include <drm/drm_probe_helper.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>
@@ -114,6 +115,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
 {
        struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
        bool connected = false;
+       enum drm_connector_status status;
 
        if (vc4_hdmi->hpd_gpio) {
                if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
@@ -134,10 +136,22 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                                kfree(edid);
                        }
                }
-               return connector_status_connected;
+               status = connector_status_connected;
+               goto out;
        }
        cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
-       return connector_status_disconnected;
+       status = connector_status_disconnected;
+
+out:
+#ifdef CONFIG_EXTCON
+       if (status != vc4_hdmi->status) {
+               extcon_set_state_sync(vc4_hdmi->edev, EXTCON_DISP_HDMI,
+                                     (status == connector_status_connected ?
+                                     true : false));
+               vc4_hdmi->status = status;
+       }
+#endif
+       return status;
 }
 
 static void vc4_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1640,6 +1654,13 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
        return 0;
 }
 
+#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);
@@ -1677,6 +1698,23 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
                return -EPROBE_DEFER;
        }
 
+#ifdef CONFIG_EXTCON
+       vc4_hdmi->status = connector_status_disconnected;
+
+       /* Initialize extcon device */
+       vc4_hdmi->edev = devm_extcon_dev_allocate(dev, vc4_hdmi_extcon_cable);
+       if (IS_ERR(vc4_hdmi->edev)) {
+               dev_err(dev, "failed to allocate memory for extcon\n");
+               return PTR_ERR(vc4_hdmi->edev);
+       }
+
+       ret = devm_extcon_dev_register(dev, vc4_hdmi->edev);
+       if (ret) {
+               dev_err(dev, "failed to register extcon device\n");
+               return ret;
+       }
+#endif
+
        /* Only use the GPIO HPD pin if present in the DT, otherwise
         * we'll use the HDMI core's register.
         */
index 60f7bf9..c312558 100644 (file)
@@ -26,6 +26,10 @@ struct drm_display_mode;
 struct vc4_hdmi;
 struct vc4_hdmi_register;
 
+#ifdef CONFIG_EXTCON
+struct extcon_dev;
+#endif
+
 enum vc4_hdmi_phy_channel {
        PHY_LANE_0 = 0,
        PHY_LANE_1,
@@ -161,6 +165,11 @@ struct vc4_hdmi {
 
        struct debugfs_regset32 hdmi_regset;
        struct debugfs_regset32 hd_regset;
+
+#ifdef CONFIG_EXTCON
+       enum drm_connector_status status;
+       struct extcon_dev *edev;
+#endif
 };
 
 static inline struct vc4_hdmi *