diff options
author | Seung-Woo Kim <sw0312.kim@samsung.com> | 2019-10-11 13:43:33 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2019-10-11 14:20:24 +0900 |
commit | 737c6b871eab9b7ae3b940609509da8c187341e9 (patch) | |
tree | 8570014c6b3a9eff0d1207c489b5217932b4c69a | |
parent | 89dcbe9b298c1c5428abe8fe0fe1a1fddf088286 (diff) | |
download | linux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.tar.gz linux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.tar.bz2 linux-rpi3-737c6b871eab9b7ae3b940609509da8c187341e9.zip |
drm/vc4: add extcon hdmi connection uevent
Add extcon hdmi connection and disconnection ueven 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>
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.c | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index fd5522fd179e..022c4965a26e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -47,6 +47,7 @@ #include <drm/drm_edid.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> @@ -97,6 +98,11 @@ struct vc4_hdmi { struct clk *pixel_clock; struct clk *hsm_clock; + + enum drm_connector_status status; +#ifdef CONFIG_EXTCON + struct extcon_dev *edev; +#endif }; #define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) @@ -238,22 +244,40 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); + enum drm_connector_status status; if (vc4->hdmi->hpd_gpio) { if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^ - vc4->hdmi->hpd_active_low) - return connector_status_connected; + vc4->hdmi->hpd_active_low) { + status = connector_status_connected; + goto out; + } cec_phys_addr_invalidate(vc4->hdmi->cec_adap); - return connector_status_disconnected; + status = connector_status_disconnected; + goto out; } - if (drm_probe_ddc(vc4->hdmi->ddc)) - return connector_status_connected; + if (drm_probe_ddc(vc4->hdmi->ddc)) { + status = connector_status_connected; + goto out; + } - if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) - return connector_status_connected; + if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { + status = connector_status_connected; + goto out; + } cec_phys_addr_invalidate(vc4->hdmi->cec_adap); - return connector_status_disconnected; + status = connector_status_disconnected; +out: + if (status != vc4->hdmi->status) { +#ifdef CONFIG_EXTCON + extcon_set_state_sync(vc4->hdmi->edev, EXTCON_DISP_HDMI, + (status == connector_status_connected ? + true : false)); +#endif + vc4->hdmi->status = status; + } + return status; } static void vc4_hdmi_connector_destroy(struct drm_connector *connector) @@ -1292,6 +1316,13 @@ static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = { }; #endif +#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); @@ -1307,6 +1338,23 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (!hdmi) return -ENOMEM; + hdmi->status = connector_status_disconnected; + +#ifdef CONFIG_EXTCON + /* Initialize extcon device */ + hdmi->edev = devm_extcon_dev_allocate(dev, vc4_hdmi_extcon_cable); + if (IS_ERR(hdmi->edev)) { + dev_err(dev, "failed to allocate memory for extcon\n"); + return -ENOMEM; + } + + ret = devm_extcon_dev_register(dev, hdmi->edev); + if (ret) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } +#endif + vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder), GFP_KERNEL); if (!vc4_hdmi_encoder) |