xref: /linux/sound/hda/core/component.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: GPL-2.0
2 // hdac_component.c - routines for sync between HD-A core and DRM driver
3 
4 #include <linux/init.h>
5 #include <linux/module.h>
6 #include <linux/pci.h>
7 #include <linux/component.h>
8 #include <linux/string_choices.h>
9 #include <sound/core.h>
10 #include <sound/hdaudio.h>
11 #include <sound/hda_component.h>
12 #include <sound/hda_register.h>
13 
14 static void hdac_acomp_release(struct device *dev, void *res)
15 {
16 }
17 
18 static struct drm_audio_component *hdac_get_acomp(struct device *dev)
19 {
20 	return devres_find(dev, hdac_acomp_release, NULL, NULL);
21 }
22 
23 /**
24  * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
25  * @bus: HDA core bus
26  * @enable: enable or disable the wakeup
27  *
28  * This function is supposed to be used only by a HD-audio controller
29  * driver that needs the interaction with graphics driver.
30  *
31  * This function should be called during the chip reset, also called at
32  * resume for updating STATESTS register read.
33  *
34  * Returns zero for success or a negative error code.
35  */
36 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
37 {
38 	struct drm_audio_component *acomp = bus->audio_component;
39 
40 	if (!acomp || !acomp->ops)
41 		return -ENODEV;
42 
43 	if (!acomp->ops->codec_wake_override)
44 		return 0;
45 
46 	dev_dbg(bus->dev, "%s codec wakeup\n", str_enable_disable(enable));
47 
48 	acomp->ops->codec_wake_override(acomp->dev, enable);
49 
50 	return 0;
51 }
52 EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
53 
54 /**
55  * snd_hdac_display_power - Power up / down the power refcount
56  * @bus: HDA core bus
57  * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
58  * @enable: power up or down
59  *
60  * This function is used by either HD-audio controller or codec driver that
61  * needs the interaction with graphics driver.
62  *
63  * This function updates the power status, and calls the get_power() and
64  * put_power() ops accordingly, toggling the codec wakeup, too.
65  */
66 void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
67 {
68 	struct drm_audio_component *acomp = bus->audio_component;
69 
70 	dev_dbg(bus->dev, "display power %s\n", str_enable_disable(enable));
71 
72 	guard(mutex)(&bus->lock);
73 	if (enable)
74 		set_bit(idx, &bus->display_power_status);
75 	else
76 		clear_bit(idx, &bus->display_power_status);
77 
78 	if (!acomp || !acomp->ops)
79 		return;
80 
81 	if (bus->display_power_status) {
82 		if (!bus->display_power_active) {
83 			unsigned long cookie = -1;
84 
85 			if (acomp->ops->get_power)
86 				cookie = acomp->ops->get_power(acomp->dev);
87 
88 			snd_hdac_set_codec_wakeup(bus, true);
89 			snd_hdac_set_codec_wakeup(bus, false);
90 			bus->display_power_active = cookie;
91 		}
92 	} else {
93 		if (bus->display_power_active) {
94 			unsigned long cookie = bus->display_power_active;
95 
96 			if (acomp->ops->put_power)
97 				acomp->ops->put_power(acomp->dev, cookie);
98 
99 			bus->display_power_active = 0;
100 		}
101 	}
102 }
103 EXPORT_SYMBOL_GPL(snd_hdac_display_power);
104 
105 /**
106  * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
107  * @codec: HDA codec
108  * @nid: the pin widget NID
109  * @dev_id: device identifier
110  * @rate: the sample rate to set
111  *
112  * This function is supposed to be used only by a HD-audio controller
113  * driver that needs the interaction with graphics driver.
114  *
115  * This function sets N/CTS value based on the given sample rate.
116  * Returns zero for success, or a negative error code.
117  */
118 int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
119 			     int dev_id, int rate)
120 {
121 	struct hdac_bus *bus = codec->bus;
122 	struct drm_audio_component *acomp = bus->audio_component;
123 	int port, pipe;
124 
125 	if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
126 		return -ENODEV;
127 	port = nid;
128 	if (acomp->audio_ops && acomp->audio_ops->pin2port) {
129 		port = acomp->audio_ops->pin2port(codec, nid);
130 		if (port < 0)
131 			return -EINVAL;
132 	}
133 	pipe = dev_id;
134 	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
135 }
136 EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
137 
138 /**
139  * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
140  * @codec: HDA codec
141  * @nid: the pin widget NID
142  * @dev_id: device identifier
143  * @audio_enabled: the pointer to store the current audio state
144  * @buffer: the buffer pointer to store ELD bytes
145  * @max_bytes: the max bytes to be stored on @buffer
146  *
147  * This function is supposed to be used only by a HD-audio controller
148  * driver that needs the interaction with graphics driver.
149  *
150  * This function queries the current state of the audio on the given
151  * digital port and fetches the ELD bytes onto the given buffer.
152  * It returns the number of bytes for the total ELD data, zero for
153  * invalid ELD, or a negative error code.
154  *
155  * The return size is the total bytes required for the whole ELD bytes,
156  * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
157  * that only a part of ELD bytes have been fetched.
158  */
159 int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
160 			   bool *audio_enabled, char *buffer, int max_bytes)
161 {
162 	struct hdac_bus *bus = codec->bus;
163 	struct drm_audio_component *acomp = bus->audio_component;
164 	int port, pipe;
165 
166 	if (!acomp || !acomp->ops || !acomp->ops->get_eld)
167 		return -ENODEV;
168 
169 	port = nid;
170 	if (acomp->audio_ops && acomp->audio_ops->pin2port) {
171 		port = acomp->audio_ops->pin2port(codec, nid);
172 		if (port < 0)
173 			return -EINVAL;
174 	}
175 	pipe = dev_id;
176 	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
177 				   buffer, max_bytes);
178 }
179 EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
180 
181 static int hdac_component_master_bind(struct device *dev)
182 {
183 	struct drm_audio_component *acomp = hdac_get_acomp(dev);
184 	int ret;
185 
186 	if (WARN_ON(!acomp))
187 		return -EINVAL;
188 
189 	ret = component_bind_all(dev, acomp);
190 	if (ret < 0)
191 		return ret;
192 
193 	if (WARN_ON(!(acomp->dev && acomp->ops))) {
194 		ret = -EINVAL;
195 		goto out_unbind;
196 	}
197 
198 	/* pin the module to avoid dynamic unbinding, but only if given */
199 	if (!try_module_get(acomp->ops->owner)) {
200 		ret = -ENODEV;
201 		goto out_unbind;
202 	}
203 
204 	if (acomp->audio_ops && acomp->audio_ops->master_bind) {
205 		ret = acomp->audio_ops->master_bind(dev, acomp);
206 		if (ret < 0)
207 			goto module_put;
208 	}
209 
210 	complete_all(&acomp->master_bind_complete);
211 	return 0;
212 
213  module_put:
214 	module_put(acomp->ops->owner);
215 out_unbind:
216 	component_unbind_all(dev, acomp);
217 	complete_all(&acomp->master_bind_complete);
218 
219 	return ret;
220 }
221 
222 static void hdac_component_master_unbind(struct device *dev)
223 {
224 	struct drm_audio_component *acomp = hdac_get_acomp(dev);
225 
226 	if (acomp->audio_ops && acomp->audio_ops->master_unbind)
227 		acomp->audio_ops->master_unbind(dev, acomp);
228 	module_put(acomp->ops->owner);
229 	component_unbind_all(dev, acomp);
230 	WARN_ON(acomp->ops || acomp->dev);
231 }
232 
233 static const struct component_master_ops hdac_component_master_ops = {
234 	.bind = hdac_component_master_bind,
235 	.unbind = hdac_component_master_unbind,
236 };
237 
238 /**
239  * snd_hdac_acomp_register_notifier - Register audio component ops
240  * @bus: HDA core bus
241  * @aops: audio component ops
242  *
243  * This function is supposed to be used only by a HD-audio controller
244  * driver that needs the interaction with graphics driver.
245  *
246  * This function sets the given ops to be called by the graphics driver.
247  *
248  * Returns zero for success or a negative error code.
249  */
250 int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
251 				    const struct drm_audio_component_audio_ops *aops)
252 {
253 	if (!bus->audio_component)
254 		return -ENODEV;
255 
256 	bus->audio_component->audio_ops = aops;
257 	return 0;
258 }
259 EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
260 
261 /**
262  * snd_hdac_acomp_init - Initialize audio component
263  * @bus: HDA core bus
264  * @aops: audio component ops
265  * @match_master: match function for finding components
266  * @extra_size: Extra bytes to allocate
267  *
268  * This function is supposed to be used only by a HD-audio controller
269  * driver that needs the interaction with graphics driver.
270  *
271  * This function initializes and sets up the audio component to communicate
272  * with graphics driver.
273  *
274  * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
275  * binding with the DRM component.  Each caller needs to sync via master_bind
276  * audio_ops.
277  *
278  * Returns zero for success or a negative error code.
279  */
280 int snd_hdac_acomp_init(struct hdac_bus *bus,
281 			const struct drm_audio_component_audio_ops *aops,
282 			int (*match_master)(struct device *, int, void *),
283 			size_t extra_size)
284 {
285 	struct component_match *match = NULL;
286 	struct device *dev = bus->dev;
287 	struct drm_audio_component *acomp;
288 	int ret;
289 
290 	if (WARN_ON(hdac_get_acomp(dev)))
291 		return -EBUSY;
292 
293 	acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
294 			     GFP_KERNEL);
295 	if (!acomp)
296 		return -ENOMEM;
297 	acomp->audio_ops = aops;
298 	init_completion(&acomp->master_bind_complete);
299 	bus->audio_component = acomp;
300 	devres_add(dev, acomp);
301 
302 	component_match_add_typed(dev, &match, match_master, bus);
303 	ret = component_master_add_with_match(dev, &hdac_component_master_ops,
304 					      match);
305 	if (ret < 0)
306 		goto out_err;
307 
308 	return 0;
309 
310 out_err:
311 	bus->audio_component = NULL;
312 	devres_destroy(dev, hdac_acomp_release, NULL, NULL);
313 	dev_info(dev, "failed to add audio component master (%d)\n", ret);
314 
315 	return ret;
316 }
317 EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
318 
319 /**
320  * snd_hdac_acomp_exit - Finalize audio component
321  * @bus: HDA core bus
322  *
323  * This function is supposed to be used only by a HD-audio controller
324  * driver that needs the interaction with graphics driver.
325  *
326  * This function releases the audio component that has been used.
327  *
328  * Returns zero for success or a negative error code.
329  */
330 int snd_hdac_acomp_exit(struct hdac_bus *bus)
331 {
332 	struct device *dev = bus->dev;
333 	struct drm_audio_component *acomp = bus->audio_component;
334 
335 	if (!acomp)
336 		return 0;
337 
338 	if (WARN_ON(bus->display_power_active) && acomp->ops)
339 		acomp->ops->put_power(acomp->dev, bus->display_power_active);
340 
341 	bus->display_power_active = 0;
342 	bus->display_power_status = 0;
343 
344 	component_master_del(dev, &hdac_component_master_ops);
345 
346 	bus->audio_component = NULL;
347 	devres_destroy(dev, hdac_acomp_release, NULL, NULL);
348 
349 	return 0;
350 }
351 EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
352