Merge remote-tracking branch 'asoc/topic/hdmi' into asoc-next
[platform/kernel/linux-rpi.git] / sound / soc / codecs / hdac_hdmi.c
index f1170e0..3733297 100644 (file)
@@ -1464,10 +1464,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
        struct snd_soc_dapm_context *dapm =
                snd_soc_component_get_dapm(&codec->component);
        struct hdac_hdmi_pin *pin;
+       struct hdac_ext_link *hlink = NULL;
        int ret;
 
        edev->scodec = codec;
 
+       /*
+        * hold the ref while we probe, also no need to drop the ref on
+        * exit, we call pm_runtime_suspend() so that will do for us
+        */
+       hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
+       snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+
        ret = create_fill_widget_route_map(dapm);
        if (ret < 0)
                return ret;
@@ -1506,32 +1514,39 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int hdmi_codec_resume(struct snd_soc_codec *codec)
+static int hdmi_codec_prepare(struct device *dev)
 {
-       struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+       struct hdac_ext_device *edev = to_hda_ext_device(dev);
+       struct hdac_device *hdac = &edev->hdac;
+
+       pm_runtime_get_sync(&edev->hdac.dev);
+
+       /*
+        * Power down afg.
+        * codec_read is preferred over codec_write to set the power state.
+        * This way verb is send to set the power state and response
+        * is received. So setting power state is ensured without using loop
+        * to read the state.
+        */
+       snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+                                                       AC_PWRST_D3);
+
+       return 0;
+}
+
+static void hdmi_codec_complete(struct device *dev)
+{
+       struct hdac_ext_device *edev = to_hda_ext_device(dev);
        struct hdac_hdmi_priv *hdmi = edev->private_data;
        struct hdac_hdmi_pin *pin;
        struct hdac_device *hdac = &edev->hdac;
-       struct hdac_bus *bus = hdac->bus;
-       int err;
-       unsigned long timeout;
-
-       hdac_hdmi_skl_enable_all_pins(&edev->hdac);
-       hdac_hdmi_skl_enable_dp12(&edev->hdac);
 
        /* Power up afg */
-       if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) {
-
-               snd_hdac_codec_write(hdac, hdac->afg, 0,
-                       AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+                                                       AC_PWRST_D0);
 
-               /* Wait till power state is set to D0 */
-               timeout = jiffies + msecs_to_jiffies(1000);
-               while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)
-                               && time_before(jiffies, timeout)) {
-                       msleep(50);
-               }
-       }
+       hdac_hdmi_skl_enable_all_pins(&edev->hdac);
+       hdac_hdmi_skl_enable_dp12(&edev->hdac);
 
        /*
         * As the ELD notify callback request is not entertained while the
@@ -1541,28 +1556,16 @@ static int hdmi_codec_resume(struct snd_soc_codec *codec)
        list_for_each_entry(pin, &hdmi->pin_list, head)
                hdac_hdmi_present_sense(pin, 1);
 
-       /*
-        * Codec power is turned ON during controller resume.
-        * Turn it OFF here
-        */
-       err = snd_hdac_display_power(bus, false);
-       if (err < 0) {
-               dev_err(bus->dev,
-                       "Cannot turn OFF display power on i915, err: %d\n",
-                       err);
-               return err;
-       }
-
-       return 0;
+       pm_runtime_put_sync(&edev->hdac.dev);
 }
 #else
-#define hdmi_codec_resume NULL
+#define hdmi_codec_prepare NULL
+#define hdmi_codec_complete NULL
 #endif
 
 static struct snd_soc_codec_driver hdmi_hda_codec = {
        .probe          = hdmi_codec_probe,
        .remove         = hdmi_codec_remove,
-       .resume         = hdmi_codec_resume,
        .idle_bias_off  = true,
 };
 
@@ -1625,9 +1628,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        struct hdac_device *codec = &edev->hdac;
        struct hdac_hdmi_priv *hdmi_priv;
        struct snd_soc_dai_driver *hdmi_dais = NULL;
+       struct hdac_ext_link *hlink = NULL;
        int num_dais = 0;
        int ret = 0;
 
+       /* hold the ref while we probe */
+       hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
+       snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+
        hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
        if (hdmi_priv == NULL)
                return -ENOMEM;
@@ -1666,8 +1674,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        }
 
        /* ASoC specific initialization */
-       return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
-                       hdmi_dais, num_dais);
+       ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
+                                       hdmi_dais, num_dais);
+
+       snd_hdac_ext_bus_link_put(edev->ebus, hlink);
+
+       return ret;
 }
 
 static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
@@ -1707,6 +1719,8 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
        struct hdac_device *hdac = &edev->hdac;
        struct hdac_bus *bus = hdac->bus;
        unsigned long timeout;
+       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
+       struct hdac_ext_link *hlink = NULL;
        int err;
 
        dev_dbg(dev, "Enter: %s\n", __func__);
@@ -1715,26 +1729,24 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
        if (!bus)
                return 0;
 
-       /* Power down afg */
-       if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) {
-               snd_hdac_codec_write(hdac, hdac->afg, 0,
-                       AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
-               /* Wait till power state is set to D3 */
-               timeout = jiffies + msecs_to_jiffies(1000);
-               while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)
-                               && time_before(jiffies, timeout)) {
-
-                       msleep(50);
-               }
-       }
-
+       /*
+        * Power down afg.
+        * codec_read is preferred over codec_write to set the power state.
+        * This way verb is send to set the power state and response
+        * is received. So setting power state is ensured without using loop
+        * to read the state.
+        */
+       snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+                                                       AC_PWRST_D3);
        err = snd_hdac_display_power(bus, false);
        if (err < 0) {
                dev_err(bus->dev, "Cannot turn on display power on i915\n");
                return err;
        }
 
+       hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+       snd_hdac_ext_bus_link_put(ebus, hlink);
+
        return 0;
 }
 
@@ -1743,6 +1755,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        struct hdac_ext_device *edev = to_hda_ext_device(dev);
        struct hdac_device *hdac = &edev->hdac;
        struct hdac_bus *bus = hdac->bus;
+       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
+       struct hdac_ext_link *hlink = NULL;
        int err;
 
        dev_dbg(dev, "Enter: %s\n", __func__);
@@ -1751,6 +1765,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        if (!bus)
                return 0;
 
+       hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+       snd_hdac_ext_bus_link_get(ebus, hlink);
+
        err = snd_hdac_display_power(bus, true);
        if (err < 0) {
                dev_err(bus->dev, "Cannot turn on display power on i915\n");
@@ -1761,9 +1778,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        hdac_hdmi_skl_enable_dp12(&edev->hdac);
 
        /* Power up afg */
-       if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
-               snd_hdac_codec_write(hdac, hdac->afg, 0,
-                       AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+                                                       AC_PWRST_D0);
 
        return 0;
 }
@@ -1774,6 +1790,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
 
 static const struct dev_pm_ops hdac_hdmi_pm = {
        SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+       .prepare = hdmi_codec_prepare,
+       .complete = hdmi_codec_complete,
 };
 
 static const struct hda_device_id hdmi_list[] = {