#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>
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)
{
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)
};
#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);
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)