Hi all, Or if we can assume that consumer will definitely call hdac_hdmi_device_link_del() itself, the patch can be simplified. I attach the simplified version of the patch. I'm not sure which is better. diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 5eeb0fe..346e8e5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1792,6 +1792,49 @@ 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; + + return device_link_add(consumer, &hdev->dev, flags); +} +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; + + device_link_remove(consumer, &hdev->dev); +} +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) { 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 Regards, Libin >-----Original Message----- >From: Yang, Libin >Sent: Tuesday, April 2, 2019 4:36 PM >To: alsa-devel@xxxxxxxxxxxxxxxx; tiwai@xxxxxxx; broonie@xxxxxxxxxx; pierre- >louis.bossart@xxxxxxxxxxxxxxx >Cc: Yang, Libin <libin.yang@xxxxxxxxx> >Subject: [RFC PATCH V2] ASoC: hdac_hdmi: add device PM >dependency > >From: Libin Yang <libin.yang@xxxxxxxxx> > >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@xxxxxxxxx> >--- > 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 _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx https://mailman.alsa-project.org/mailman/listinfo/alsa-devel