All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philipp Zabel <p.zabel@pengutronix.de>
To: dri-devel@lists.freedesktop.org
Cc: Russell King <linux@armlinux.org.uk>,
	Hans Verkuil <hans.verkuil@cisco.com>,
	PC Liao <pc.liao@mediatek.com>,
	linux-mediatek@lists.infradead.org
Subject: [PATCH] drm/mediatek: use HDMI state notifier support
Date: Tue, 15 Nov 2016 19:39:51 +0100	[thread overview]
Message-ID: <20161115183951.840-1-p.zabel@pengutronix.de> (raw)

Issue hot-plug detection, EDID update, and ELD update notifications
from the CEC and HDMI drivers using the HDMI state notifier support.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
This patch depends on the "video: add HDMI state notifier support" patch [1] by
Hans Verkuil, based on Russell King's earlier version. With this we can replace
the custom callback interface between HDMI and CEC drivers with a common
mechanism. It will also allow other drivers such as hdmi-codec to react to the
emitted events.

[1] https://patchwork.linuxtv.org/patch/38109/
---
 drivers/gpu/drm/mediatek/mtk_cec.c  | 56 +++++++++++--------------------------
 drivers/gpu/drm/mediatek/mtk_cec.h  | 26 -----------------
 drivers/gpu/drm/mediatek/mtk_hdmi.c | 46 ++++++++++++++++++------------
 3 files changed, 44 insertions(+), 84 deletions(-)
 delete mode 100644 drivers/gpu/drm/mediatek/mtk_cec.h

diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c
index 7a3eb8c..9a1807b 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -13,12 +13,11 @@
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/hdmi-notifier.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 
-#include "mtk_cec.h"
-
 #define TR_CONFIG		0x00
 #define CLEAR_CEC_IRQ			BIT(15)
 
@@ -55,12 +54,9 @@
 
 struct mtk_cec {
 	void __iomem *regs;
+	struct hdmi_notifier *notifier;
 	struct clk *clk;
 	int irq;
-	bool hpd;
-	void (*hpd_event)(bool hpd, struct device *dev);
-	struct device *hdmi_dev;
-	spinlock_t lock;
 };
 
 static void mtk_cec_clear_bits(struct mtk_cec *cec, unsigned int offset,
@@ -94,20 +90,7 @@ static void mtk_cec_mask(struct mtk_cec *cec, unsigned int offset,
 	writel(val, cec->regs + offset);
 }
 
-void mtk_cec_set_hpd_event(struct device *dev,
-			   void (*hpd_event)(bool hpd, struct device *dev),
-			   struct device *hdmi_dev)
-{
-	struct mtk_cec *cec = dev_get_drvdata(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&cec->lock, flags);
-	cec->hdmi_dev = hdmi_dev;
-	cec->hpd_event = hpd_event;
-	spin_unlock_irqrestore(&cec->lock, flags);
-}
-
-bool mtk_cec_hpd_high(struct device *dev)
+static bool mtk_cec_hpd_high(struct device *dev)
 {
 	struct mtk_cec *cec = dev_get_drvdata(dev);
 	unsigned int status;
@@ -152,21 +135,6 @@ static void mtk_cec_clear_htplg_irq(struct mtk_cec *cec)
 			   RX_INT_32K_CLR | HDMI_HTPLG_INT_32K_CLR);
 }
 
-static void mtk_cec_hpd_event(struct mtk_cec *cec, bool hpd)
-{
-	void (*hpd_event)(bool hpd, struct device *dev);
-	struct device *hdmi_dev;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cec->lock, flags);
-	hpd_event = cec->hpd_event;
-	hdmi_dev = cec->hdmi_dev;
-	spin_unlock_irqrestore(&cec->lock, flags);
-
-	if (hpd_event)
-		hpd_event(hpd, hdmi_dev);
-}
-
 static irqreturn_t mtk_cec_htplg_isr_thread(int irq, void *arg)
 {
 	struct device *dev = arg;
@@ -176,11 +144,13 @@ static irqreturn_t mtk_cec_htplg_isr_thread(int irq, void *arg)
 	mtk_cec_clear_htplg_irq(cec);
 	hpd = mtk_cec_hpd_high(dev);
 
-	if (cec->hpd != hpd) {
+	if (cec->notifier->connected != hpd) {
 		dev_dbg(dev, "hotplug event! cur hpd = %d, hpd = %d\n",
-			cec->hpd, hpd);
-		cec->hpd = hpd;
-		mtk_cec_hpd_event(cec, hpd);
+			cec->notifier->connected, hpd);
+		if (hpd)
+			hdmi_event_connect(cec->notifier);
+		else
+			hdmi_event_disconnect(cec->notifier);
 	}
 	return IRQ_HANDLED;
 }
@@ -197,7 +167,6 @@ static int mtk_cec_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	platform_set_drvdata(pdev, cec);
-	spin_lock_init(&cec->lock);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cec->regs = devm_ioremap_resource(dev, res);
@@ -220,6 +189,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
 		return cec->irq;
 	}
 
+	cec->notifier = hdmi_notifier_get(dev);
+	if (!cec->notifier) {
+		clk_disable_unprepare(cec->clk);
+		return -ENOMEM;
+	}
+
 	ret = devm_request_threaded_irq(dev, cec->irq, NULL,
 					mtk_cec_htplg_isr_thread,
 					IRQF_SHARED | IRQF_TRIGGER_LOW |
@@ -245,6 +220,7 @@ static int mtk_cec_remove(struct platform_device *pdev)
 {
 	struct mtk_cec *cec = platform_get_drvdata(pdev);
 
+	hdmi_notifier_put(cec->notifier);
 	mtk_cec_htplg_irq_disable(cec);
 	clk_disable_unprepare(cec->clk);
 	return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.h b/drivers/gpu/drm/mediatek/mtk_cec.h
deleted file mode 100644
index 10057b7..0000000
--- a/drivers/gpu/drm/mediatek/mtk_cec.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2014 MediaTek Inc.
- * Author: Jie Qiu <jie.qiu@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef _MTK_CEC_H
-#define _MTK_CEC_H
-
-#include <linux/types.h>
-
-struct device;
-
-void mtk_cec_set_hpd_event(struct device *dev,
-			   void (*hotplug_event)(bool hpd, struct device *dev),
-			   struct device *hdmi_dev);
-bool mtk_cec_hpd_high(struct device *dev);
-
-#endif /* _MTK_CEC_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 71227de..c04a71a 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -20,6 +20,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/hdmi.h>
+#include <linux/hdmi-notifier.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -32,7 +33,6 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <sound/hdmi-codec.h>
-#include "mtk_cec.h"
 #include "mtk_hdmi.h"
 #include "mtk_hdmi_regs.h"
 
@@ -153,6 +153,8 @@ struct mtk_hdmi {
 	struct device *dev;
 	struct phy *phy;
 	struct device *cec_dev;
+	struct hdmi_notifier *notifier;
+	struct notifier_block nb;
 	struct i2c_adapter *ddc_adpt;
 	struct clk *clk[MTK_HDMI_CLK_COUNT];
 	struct drm_display_mode mode;
@@ -1196,19 +1198,10 @@ static enum drm_connector_status hdmi_conn_detect(struct drm_connector *conn,
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
 
-	return mtk_cec_hpd_high(hdmi->cec_dev) ?
+	return hdmi->notifier->connected ?
 	       connector_status_connected : connector_status_disconnected;
 }
 
-static void hdmi_conn_destroy(struct drm_connector *conn)
-{
-	struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
-
-	mtk_cec_set_hpd_event(hdmi->cec_dev, NULL, NULL);
-
-	drm_connector_cleanup(conn);
-}
-
 static int mtk_hdmi_conn_get_modes(struct drm_connector *conn)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
@@ -1225,9 +1218,11 @@ static int mtk_hdmi_conn_get_modes(struct drm_connector *conn)
 	hdmi->dvi_mode = !drm_detect_monitor_audio(edid);
 
 	drm_mode_connector_update_edid_property(conn, edid);
+	hdmi_event_new_edid(hdmi->notifier, edid, sizeof(*edid));
 
 	ret = drm_add_edid_modes(conn, edid);
 	drm_edid_to_eld(conn, edid);
+	hdmi_event_new_eld(hdmi->notifier, conn->eld);
 	kfree(edid);
 	return ret;
 }
@@ -1269,7 +1264,7 @@ static const struct drm_connector_funcs mtk_hdmi_connector_funcs = {
 	.dpms = drm_atomic_helper_connector_dpms,
 	.detect = hdmi_conn_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = hdmi_conn_destroy,
+	.destroy = drm_connector_cleanup,
 	.reset = drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -1282,12 +1277,16 @@ static const struct drm_connector_helper_funcs
 	.best_encoder = mtk_hdmi_conn_best_enc,
 };
 
-static void mtk_hdmi_hpd_event(bool hpd, struct device *dev)
+static int mtk_hdmi_notify(struct notifier_block *nb, unsigned long event,
+			    void *data)
 {
-	struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
+	struct mtk_hdmi *hdmi = container_of(nb, struct mtk_hdmi, nb);
 
-	if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev)
+	if ((event == HDMI_CONNECTED || event == HDMI_DISCONNECTED) &&
+	    (hdmi->bridge.encoder && hdmi->bridge.encoder->dev))
 		drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev);
+
+	return NOTIFY_OK;
 }
 
 /*
@@ -1330,8 +1329,6 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
 		}
 	}
 
-	mtk_cec_set_hpd_event(hdmi->cec_dev, mtk_hdmi_hpd_event, hdmi->dev);
-
 	return 0;
 }
 
@@ -1707,6 +1704,15 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	hdmi->notifier = hdmi_notifier_get(hdmi->cec_dev);
+	if (!hdmi->notifier)
+		return -ENOMEM;
+
+	hdmi->nb.notifier_call = mtk_hdmi_notify;
+	ret = hdmi_notifier_register(hdmi->notifier, &hdmi->nb);
+	if (ret)
+		goto err_notifier_put;
+
 	mtk_hdmi_register_audio_driver(dev);
 
 	hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
@@ -1714,7 +1720,7 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
 	ret = drm_bridge_add(&hdmi->bridge);
 	if (ret) {
 		dev_err(dev, "failed to add bridge, ret = %d\n", ret);
-		return ret;
+		goto err_notifier_unregister;
 	}
 
 	ret = mtk_hdmi_clk_enable_audio(hdmi);
@@ -1728,6 +1734,10 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
 
 err_bridge_remove:
 	drm_bridge_remove(&hdmi->bridge);
+err_notifier_unregister:
+	hdmi_notifier_unregister(hdmi->notifier, &hdmi->nb);
+err_notifier_put:
+	hdmi_notifier_put(hdmi->notifier);
 	return ret;
 }
 
-- 
2.10.2

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

                 reply	other threads:[~2016-11-15 18:39 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161115183951.840-1-p.zabel@pengutronix.de \
    --to=p.zabel@pengutronix.de \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hans.verkuil@cisco.com \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux@armlinux.org.uk \
    --cc=pc.liao@mediatek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.