@@ -4,13 +4,15 @@
#ifndef __SOUND_HDA_I915_H
#define __SOUND_HDA_I915_H
+#include <linux/component.h>
#include <drm/i915_component.h>
#ifdef CONFIG_SND_HDA_I915
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
int snd_hdac_get_display_clk(struct hdac_bus *bus);
-int snd_hdac_i915_init(struct hdac_bus *bus);
+int snd_hdac_i915_init(struct hdac_bus *bus,
+ const struct component_master_ops *codec_ops);
int snd_hdac_i915_exit(struct hdac_bus *bus);
int snd_hdac_i915_register_notifier(struct hdac_device *codec,
const struct i915_audio_component_audio_ops *);
@@ -27,7 +29,8 @@ static inline int snd_hdac_get_display_clk(struct hdac_bus *bus)
{
return 0;
}
-static inline int snd_hdac_i915_init(struct hdac_bus *bus)
+static inline int snd_hdac_i915_init(struct hdac_bus *bus,
+ const struct component_master_ops *codec_ops)
{
return -ENODEV;
}
@@ -21,6 +21,11 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
+struct hdac_gfx_component {
+ struct i915_audio_component acomp;
+ const struct component_master_ops *ops;
+};
+
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{
struct i915_audio_component *acomp = bus->audio_component;
@@ -85,6 +90,8 @@ static int hdac_component_master_bind(struct device *dev)
struct hdac_device *codec = dev_to_hdac_dev(dev);
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
+ struct hdac_gfx_component *hda_comp =
+ container_of(acomp, struct hdac_gfx_component, acomp);
int ret;
ret = component_bind_all(dev, acomp);
@@ -106,6 +113,14 @@ static int hdac_component_master_bind(struct device *dev)
goto out_unbind;
}
+ if (hda_comp->ops && hda_comp->ops->bind) {
+ ret = hda_comp->ops->bind(dev);
+ if (ret < 0) {
+ module_put(acomp->ops->owner);
+ goto out_unbind;
+ }
+ }
+
return 0;
out_unbind:
@@ -119,7 +134,11 @@ static void hdac_component_master_unbind(struct device *dev)
struct hdac_device *codec = dev_to_hdac_dev(dev);
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
+ struct hdac_gfx_component *hda_comp =
+ container_of(acomp, struct hdac_gfx_component, acomp);
+ if (hda_comp->ops && hda_comp->ops->unbind)
+ hda_comp->ops->unbind(dev);
module_put(acomp->ops->owner);
component_unbind_all(dev, acomp);
WARN_ON(acomp->ops || acomp->dev);
@@ -150,45 +169,22 @@ int snd_hdac_i915_register_notifier(struct hdac_device *codec,
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
-int snd_hdac_i915_init(struct hdac_bus *bus)
+int snd_hdac_i915_init(struct hdac_bus *bus,
+ const struct component_master_ops *codec_ops)
{
struct component_match *match = NULL;
struct device *dev = bus->dev;
- struct i915_audio_component *acomp;
- int ret;
+ struct hdac_gfx_component *hda_comp;
- acomp = kzalloc(sizeof(*acomp), GFP_KERNEL);
- if (!acomp)
+ hda_comp = kzalloc(sizeof(*hda_comp), GFP_KERNEL);
+ if (!hda_comp)
return -ENOMEM;
- bus->audio_component = acomp;
+ bus->audio_component = &hda_comp->acomp;
+ hda_comp->ops = codec_ops;
component_match_add(dev, &match, hdac_component_master_match, bus);
- ret = component_master_add_with_match(dev, &hdac_component_master_ops,
- match);
- if (ret < 0)
- goto out_err;
-
- /*
- * Atm, we don't support deferring the component binding, so make sure
- * i915 is loaded and that the binding successfully completes.
- */
- request_module("i915");
-
- if (!acomp->ops) {
- ret = -ENODEV;
- goto out_master_del;
- }
- dev_dbg(dev, "bound to i915 component master\n");
-
- return 0;
-out_master_del:
- component_master_del(dev, &hdac_component_master_ops);
-out_err:
- kfree(acomp);
- bus->audio_component = NULL;
- dev_err(dev, "failed to add i915 component master (%d)\n", ret);
-
- return ret;
+ return component_master_add_with_match(dev, &hdac_component_master_ops,
+ match);
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
@@ -1884,6 +1884,20 @@ static const struct hda_controller_ops pci_hda_ops = {
.link_power = azx_intel_link_power,
};
+#ifdef CONFIG_SND_HDA_I915
+static int azx_i915_bind(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+
+ return azx_probe_continue(chip);
+}
+
+static const struct component_master_ops component_ops = {
+ .bind = azx_i915_bind,
+};
+#endif /* CONFIG_SND_HDA_I915 */
+
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -1943,10 +1957,19 @@ static int azx_probe(struct pci_dev *pci,
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
-#ifndef CONFIG_SND_HDA_I915
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+#ifdef CONFIG_SND_HDA_I915
+ /* HSW/BDW controllers need this power */
+ if (CONTROLLER_IN_GPU(pci))
+ hda->need_i915_power = 1;
+ err = snd_hdac_i915_init(azx_bus(chip), &component_ops);
+ if (err < 0)
+ goto out_free;
+ schedule_probe = false; /* continue via bind ops */
+#else
dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n");
#endif
+ }
if (schedule_probe)
schedule_work(&hda->probe_work);
@@ -1983,23 +2006,6 @@ static int azx_probe_continue(struct azx *chip)
* display codec needs the power and it can be released after probe.
*/
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- /* HSW/BDW controllers need this power */
- if (CONTROLLER_IN_GPU(pci))
- hda->need_i915_power = 1;
-
- err = snd_hdac_i915_init(bus);
- if (err < 0) {
- /* if the controller is bound only with HDMI/DP
- * (for HSW and BDW), we need to abort the probe;
- * for other chips, still continue probing as other
- * codecs can be on the same link.
- */
- if (CONTROLLER_IN_GPU(pci))
- goto out_free;
- else
- goto skip_i915;
- }
-
err = snd_hdac_display_power(bus, true);
if (err < 0) {
dev_err(chip->card->dev,
@@ -2008,7 +2014,6 @@ static int azx_probe_continue(struct azx *chip)
}
}
- skip_i915:
err = azx_first_init(chip);
if (err < 0)
goto out_free;