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>
Tue, 30 Mar 2021 01:40:01 +0000 (10:40 +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 f9eb6a5..9b8c622 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/drm_simple_kms_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>
@@ -471,6 +472,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) ^
@@ -493,11 +495,23 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                        }
                }
 
-               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)
@@ -2564,6 +2578,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)
 {
        const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
@@ -2607,6 +2628,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 33b5f12..fac1722 100644 (file)
@@ -25,6 +25,10 @@ struct vc4_hdmi;
 struct vc4_hdmi_register;
 struct vc4_hdmi_connector_state;
 
+#ifdef CONFIG_EXTCON
+struct extcon_dev;
+#endif
+
 enum vc4_hdmi_phy_channel {
        PHY_LANE_0 = 0,
        PHY_LANE_1,
@@ -185,6 +189,11 @@ struct vc4_hdmi {
        struct debugfs_regset32 phy_regset;
        struct debugfs_regset32 ram_regset;
        struct debugfs_regset32 rm_regset;
+
+#ifdef CONFIG_EXTCON
+       enum drm_connector_status status;
+       struct extcon_dev *edev;
+#endif
 };
 
 static inline struct vc4_hdmi *