2 * hdac_i915.c - routines for sync between HD-A core and i915 display driver
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/pci.h>
18 #include <linux/component.h>
19 #include <drm/i915_component.h>
20 #include <sound/core.h>
21 #include <sound/hdaudio.h>
22 #include <sound/hda_i915.h>
24 static struct i915_audio_component
*hdac_acomp
;
26 int snd_hdac_set_codec_wakeup(struct hdac_bus
*bus
, bool enable
)
28 struct i915_audio_component
*acomp
= bus
->audio_component
;
30 if (!acomp
|| !acomp
->ops
)
33 if (!acomp
->ops
->codec_wake_override
) {
35 "Invalid codec wake callback\n");
39 dev_dbg(bus
->dev
, "%s codec wakeup\n",
40 enable
? "enable" : "disable");
42 acomp
->ops
->codec_wake_override(acomp
->dev
, enable
);
46 EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup
);
48 int snd_hdac_display_power(struct hdac_bus
*bus
, bool enable
)
50 struct i915_audio_component
*acomp
= bus
->audio_component
;
52 if (!acomp
|| !acomp
->ops
)
55 dev_dbg(bus
->dev
, "display power %s\n",
56 enable
? "enable" : "disable");
59 if (!bus
->i915_power_refcount
++) {
60 acomp
->ops
->get_power(acomp
->dev
);
61 snd_hdac_set_codec_wakeup(bus
, true);
62 snd_hdac_set_codec_wakeup(bus
, false);
65 WARN_ON(!bus
->i915_power_refcount
);
66 if (!--bus
->i915_power_refcount
)
67 acomp
->ops
->put_power(acomp
->dev
);
72 EXPORT_SYMBOL_GPL(snd_hdac_display_power
);
74 int snd_hdac_get_display_clk(struct hdac_bus
*bus
)
76 struct i915_audio_component
*acomp
= bus
->audio_component
;
78 if (!acomp
|| !acomp
->ops
)
81 return acomp
->ops
->get_cdclk_freq(acomp
->dev
);
83 EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk
);
85 static int hdac_component_master_bind(struct device
*dev
)
87 struct i915_audio_component
*acomp
= hdac_acomp
;
90 ret
= component_bind_all(dev
, acomp
);
94 if (WARN_ON(!(acomp
->dev
&& acomp
->ops
&& acomp
->ops
->get_power
&&
95 acomp
->ops
->put_power
&& acomp
->ops
->get_cdclk_freq
))) {
101 * Atm, we don't support dynamic unbinding initiated by the child
102 * component, so pin its containing module until we unbind.
104 if (!try_module_get(acomp
->ops
->owner
)) {
112 component_unbind_all(dev
, acomp
);
117 static void hdac_component_master_unbind(struct device
*dev
)
119 struct i915_audio_component
*acomp
= hdac_acomp
;
121 module_put(acomp
->ops
->owner
);
122 component_unbind_all(dev
, acomp
);
123 WARN_ON(acomp
->ops
|| acomp
->dev
);
126 static const struct component_master_ops hdac_component_master_ops
= {
127 .bind
= hdac_component_master_bind
,
128 .unbind
= hdac_component_master_unbind
,
131 static int hdac_component_master_match(struct device
*dev
, void *data
)
133 /* i915 is the only supported component */
134 return !strcmp(dev
->driver
->name
, "i915");
137 int snd_hdac_i915_init(struct hdac_bus
*bus
)
139 struct component_match
*match
= NULL
;
140 struct device
*dev
= bus
->dev
;
141 struct i915_audio_component
*acomp
;
144 acomp
= kzalloc(sizeof(*acomp
), GFP_KERNEL
);
147 bus
->audio_component
= acomp
;
150 component_match_add(dev
, &match
, hdac_component_master_match
, bus
);
151 ret
= component_master_add_with_match(dev
, &hdac_component_master_ops
,
157 * Atm, we don't support deferring the component binding, so make sure
158 * i915 is loaded and that the binding successfully completes.
160 request_module("i915");
166 dev_dbg(dev
, "bound to i915 component master\n");
170 component_master_del(dev
, &hdac_component_master_ops
);
173 bus
->audio_component
= NULL
;
174 dev_err(dev
, "failed to add i915 component master (%d)\n", ret
);
178 EXPORT_SYMBOL_GPL(snd_hdac_i915_init
);
180 int snd_hdac_i915_exit(struct hdac_bus
*bus
)
182 struct device
*dev
= bus
->dev
;
183 struct i915_audio_component
*acomp
= bus
->audio_component
;
188 WARN_ON(bus
->i915_power_refcount
);
189 if (bus
->i915_power_refcount
> 0 && acomp
->ops
)
190 acomp
->ops
->put_power(acomp
->dev
);
192 component_master_del(dev
, &hdac_component_master_ops
);
195 bus
->audio_component
= NULL
;
199 EXPORT_SYMBOL_GPL(snd_hdac_i915_exit
);