From 5612984b6ef7e17578e0cadb407f578a6139e70e Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 18 Oct 2017 08:21:05 +0900 Subject: [PATCH] gpu: drm: exynos: Add extcon notification for hdmi connection 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 [sw0312.kim: port to v4.14] Signed-off-by: Seung-Woo Kim Change-Id: I20a2d13deff07e566ce4f50c7fc64600ce10ca9f --- drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index f56e3b5..25f0364 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -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. diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 32c1920..d2e5c51 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -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; -- 2.7.4