gpu: drm: exynos: Add extcon notification for hdmi connection 46/205546/1 accepted/tizen/unified/20190508.111058 submit/tizen/20190507.092632
authorDongwoo Lee <dwoo08.lee@samsung.com>
Tue, 17 Oct 2017 23:21:05 +0000 (08:21 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 7 May 2019 09:14:20 +0000 (18:14 +0900)
Currently, hdmi connection generates only uevent by drm core. In
addition, it has no information about connection state. But, Tizen
starts TV-out behavior along with extcon uevent. To this end, this
patch will add extcon notification for hdmi connection.

Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
[sw0312.kim: port to v4.14]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: I20a2d13deff07e566ce4f50c7fc64600ce10ca9f

drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_hdmi.c

index f56e3b5..25f0364 100644 (file)
@@ -77,6 +77,7 @@ config DRM_EXYNOS_HDMI
        bool "HDMI"
        depends on DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON
        select CEC_CORE if CEC_NOTIFIER
+       select EXTCON
        help
          Choose this option if you want to use Exynos HDMI for DRM.
 
index 32c1920..d2e5c51 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/component.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/extcon-provider.h>
 #include <sound/hdmi-codec.h>
 #include <drm/exynos_drm.h>
 
@@ -127,6 +128,7 @@ struct hdmi_context {
        struct delayed_work             hotplug_work;
        struct cec_notifier             *notifier;
        const struct hdmi_driver_data   *drv_data;
+       struct extcon_dev               *edev;
 
        void __iomem                    *regs;
        void __iomem                    *regs_hdmiphy;
@@ -149,6 +151,11 @@ struct hdmi_context {
        bool                            powered;
 };
 
+static const unsigned int extcon_cable_list[] = {
+       EXTCON_DISP_HDMI,
+       EXTCON_NONE,
+};
+
 static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
 {
        return container_of(e, struct hdmi_context, encoder);
@@ -1637,12 +1644,29 @@ static int hdmi_register_audio_device(struct hdmi_context *hdata)
        return PTR_ERR_OR_ZERO(hdata->audio.pdev);
 }
 
+static void hdmi_extcon_notify(struct hdmi_context *hdata)
+{
+       enum drm_connector_status plug;
+
+       if (!hdata->edev)
+               return;
+
+       plug = hdmi_detect(&hdata->connector, false);
+
+       if (plug == connector_status_connected)
+               extcon_set_state_sync(hdata->edev, EXTCON_DISP_HDMI, true);
+       else if (plug == connector_status_disconnected)
+               extcon_set_state_sync(hdata->edev, EXTCON_DISP_HDMI, false);
+}
+
 static void hdmi_hotplug_work_func(struct work_struct *work)
 {
        struct hdmi_context *hdata;
 
        hdata = container_of(work, struct hdmi_context, hotplug_work.work);
 
+       hdmi_extcon_notify(hdata);
+
        if (hdata->drm_dev)
                drm_helper_hpd_irq_event(hdata->drm_dev);
 }
@@ -1928,6 +1952,25 @@ out:
        return ret;
 }
 
+static int hdmi_extcon_init(struct hdmi_context *hdata)
+{
+       struct device *dev = hdata->dev;
+       struct extcon_dev *edev;
+       int ret;
+
+       edev = devm_extcon_dev_allocate(dev, extcon_cable_list);
+       if (IS_ERR(edev))
+               return PTR_ERR(edev);
+
+       ret = devm_extcon_dev_register(dev, edev);
+       if (ret)
+               return ret;
+
+       hdata->edev = edev;
+
+       return 0;
+}
+
 static int hdmi_probe(struct platform_device *pdev)
 {
        struct hdmi_audio_infoframe *audio_infoframe;
@@ -1962,6 +2005,10 @@ static int hdmi_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = hdmi_extcon_init(hdata);
+       if (ret)
+               DRM_INFO("extcon notify won't be supported due to init. fail");
+
        ret = hdmi_get_ddc_adapter(hdata);
        if (ret)
                return ret;