gpu: drm: exynos: Add extcon notification for hdmi connection 60/156260/5 accepted/tizen/4.0/unified/20171018.231844 accepted/tizen/unified/20171018.165341 submit/tizen/20171018.070350 submit/tizen_4.0/20171018.070324 tizen_4.0.m2_release
authorDongwoo Lee <dwoo08.lee@samsung.com>
Tue, 17 Oct 2017 23:21:05 +0000 (08:21 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 18 Oct 2017 06:37:08 +0000 (15:37 +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.

Change-Id: I831d53ed345631273fc797c3625c67a70443ae25
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_hdmi.c

index 26ee292546963770c75f7cb75dbe527f060784eb..89d9371d192353e1351932154b83f7dc1f8cb506 100644 (file)
@@ -65,6 +65,7 @@ config DRM_EXYNOS_DP
 config DRM_EXYNOS_HDMI
        bool "Exynos DRM HDMI"
        depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
+       select EXTCON
        help
          Choose this option if you want to use Exynos HDMI for DRM.
 
index 591ce56d9c64b105bc2bd95219b91dc686600f50..06f8d9efbfaff0d80287bcd0240a7d642397d96c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/component.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/extcon.h>
 
 #include <drm/exynos_drm.h>
 
@@ -124,6 +125,7 @@ struct hdmi_context {
        struct delayed_work             hotplug_work;
        struct drm_display_mode         current_mode;
        const struct hdmi_driver_data   *drv_data;
+       struct extcon_dev               *edev;
 
        void __iomem                    *regs;
        void __iomem                    *regs_hdmiphy;
@@ -140,6 +142,11 @@ struct hdmi_context {
        struct exynos_drm_clk           phy_clk;
 };
 
+static const char *extcon_cable_list[] = {
+       "HDMI",
+       NULL,
+};
+
 static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
 {
        return container_of(d, struct hdmi_context, display);
@@ -1686,12 +1693,29 @@ static struct exynos_drm_display_ops hdmi_display_ops = {
        .commit         = hdmi_commit,
 };
 
+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_cable_state(hdata->edev, "HDMI", 1);
+       else if (plug == connector_status_disconnected)
+               extcon_set_cable_state(hdata->edev, "HDMI", 0);
+}
+
 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);
 }
@@ -1960,6 +1984,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)
 {
        const struct of_device_id *match;
@@ -2001,6 +2044,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;