[alsa-devel] [RFC PATCH V2] ASoC: hdac_hdmi: add device PM dependency

libin.yang at intel.com libin.yang at intel.com
Tue Apr 2 10:35:32 CEST 2019


From: Libin Yang <libin.yang at intel.com>

HDMI audio codec register operation depends on the display audio power
domain. The hdmi audio codec dapm event callback must be called after
display audio power is turned on.

Add hdac_hdmi_device_link_add/del() in HDMI audio codec driver. The
customer audio driver, such as cAVS/SST and SOF audio driver, can call
the function to set/remove the audio power dependency.

Signed-off-by: Libin Yang <libin.yang at intel.com>
---
 sound/soc/codecs/hdac_hdmi.c | 86 ++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/hdac_hdmi.h |  7 ++++
 2 files changed, 93 insertions(+)

diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 5eeb0fe..7490219 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -133,6 +133,12 @@ struct hdac_hdmi_drv_data {
 	int port_num;
 };
 
+/* each supplier - consumer pair has one instance of this structure */
+struct hdac_hdmi_dev_link {
+	struct list_head head;
+	struct device_link *link;
+};
+
 struct hdac_hdmi_priv {
 	struct hdac_device *hdev;
 	struct snd_soc_component *component;
@@ -141,10 +147,12 @@ struct hdac_hdmi_priv {
 	struct list_head pin_list;
 	struct list_head cvt_list;
 	struct list_head pcm_list;
+	struct list_head link_list;	/* supplier - consumer pairs */
 	int num_pin;
 	int num_cvt;
 	int num_ports;
 	struct mutex pin_mutex;
+	struct mutex link_mutex;
 	struct hdac_chmap chmap;
 	struct hdac_hdmi_drv_data *drv_data;
 	struct snd_soc_dai_driver *dai_drv;
@@ -1792,6 +1800,72 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
 }
 EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
 
+/**
+ * hdac_hdmi_device_link_add - add a link between consumer and hdev device
+ * @consumer: Consumer end of the link.
+ * @component: The hdmi codec component.
+ * @flags: Link flags.
+ *
+ * If there is a consumer of the hdev device, which means a consumer device
+ * operation depends on the hdev device power status, the consumer device
+ * driver should call this function. It supports several consumers depending
+ * on the same hdmi codec hdev device.
+ *
+ * Return: pointer of device_link, or NULL if fails to create device_link
+ */
+struct device_link *
+hdac_hdmi_device_link_add(struct device *consumer,
+			  struct snd_soc_component *component,
+			  u32 flags)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_dev_link *dev_link;
+
+	dev_link = devm_kzalloc(&hdev->dev, sizeof(*dev_link), GFP_KERNEL);
+	if (!dev_link)
+		return NULL;
+
+	dev_link->link = device_link_add(consumer, &hdev->dev, flags);
+
+	mutex_lock(&hdmi->link_mutex);
+	if (dev_link->link)
+		list_add(&dev_link->head, &hdmi->link_list);
+	mutex_unlock(&hdmi->link_mutex);
+
+	return dev_link->link;
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_device_link_add);
+
+/**
+ * hdac_hdmi_device_link_del - del the link between consumer and hdev device
+ * @consumer: Consumer end of the link.
+ * @component: The hdmi codec component.
+ *
+ * If the consumer doesn't need the dependency any longer, the consumer device
+ * driver should call this function to release the device_link
+ */
+void hdac_hdmi_device_link_del(struct device *consumer,
+			       struct snd_soc_component *component)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_dev_link *dev_link, *tmp;
+
+	mutex_lock(&hdmi->link_mutex);
+	list_for_each_entry_safe(dev_link, tmp, &hdmi->link_list, head) {
+		if (dev_link->link->consumer == consumer &&
+		    dev_link->link->supplier == &hdev->dev) {
+			device_link_del(dev_link->link);
+			list_del(&dev_link->head);
+			devm_kfree(&hdev->dev, dev_link);
+			return;
+		}
+	}
+	mutex_unlock(&hdmi->link_mutex);
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_device_link_del);
+
 static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev,
 			struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
 {
@@ -2031,7 +2105,9 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
 	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
 	INIT_LIST_HEAD(&hdmi_priv->pcm_list);
+	INIT_LIST_HEAD(&hdmi_priv->link_list);
 	mutex_init(&hdmi_priv->pin_mutex);
+	mutex_init(&hdmi_priv->link_mutex);
 
 	/*
 	 * Turned off in the runtime_suspend during the first explicit
@@ -2058,8 +2134,18 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
 
 static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
 {
+	struct hdac_hdmi_dev_link *dev_link, *tmp;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+
 	snd_hdac_display_power(hdev->bus, hdev->addr, false);
 
+	mutex_unlock(&hdmi->link_mutex);
+	list_for_each_entry_safe(dev_link, tmp, &hdmi->link_list, head) {
+		device_link_del(dev_link->link);
+		list_del(&dev_link->head);
+	}
+	mutex_unlock(&hdmi->link_mutex);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
index 4fa2fc9..e877167 100644
--- a/sound/soc/codecs/hdac_hdmi.h
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -7,4 +7,11 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
 
 int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
 			struct snd_soc_dapm_context *dapm);
+
+struct device_link *
+hdac_hdmi_device_link_add(struct device *consumer,
+			  struct snd_soc_component *component,
+			  u32 flags);
+void hdac_hdmi_device_link_del(struct device *consumer,
+			       struct snd_soc_component *component);
 #endif /* __HDAC_HDMI_H__ */
-- 
2.7.4



More information about the Alsa-devel mailing list