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
hdac_acomp_release(struct device * dev,void * res)14 static void hdac_acomp_release(struct device *dev, void *res)
15 {
16 }
17
hdac_get_acomp(struct device * dev)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 */
snd_hdac_set_codec_wakeup(struct hdac_bus * bus,bool enable)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 */
snd_hdac_display_power(struct hdac_bus * bus,unsigned int idx,bool enable)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 mutex_lock(&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 goto unlock;
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 unlock:
103 mutex_unlock(&bus->lock);
104 }
105 EXPORT_SYMBOL_GPL(snd_hdac_display_power);
106
107 /**
108 * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
109 * @codec: HDA codec
110 * @nid: the pin widget NID
111 * @dev_id: device identifier
112 * @rate: the sample rate to set
113 *
114 * This function is supposed to be used only by a HD-audio controller
115 * driver that needs the interaction with graphics driver.
116 *
117 * This function sets N/CTS value based on the given sample rate.
118 * Returns zero for success, or a negative error code.
119 */
snd_hdac_sync_audio_rate(struct hdac_device * codec,hda_nid_t nid,int dev_id,int rate)120 int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
121 int dev_id, int rate)
122 {
123 struct hdac_bus *bus = codec->bus;
124 struct drm_audio_component *acomp = bus->audio_component;
125 int port, pipe;
126
127 if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
128 return -ENODEV;
129 port = nid;
130 if (acomp->audio_ops && acomp->audio_ops->pin2port) {
131 port = acomp->audio_ops->pin2port(codec, nid);
132 if (port < 0)
133 return -EINVAL;
134 }
135 pipe = dev_id;
136 return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
137 }
138 EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
139
140 /**
141 * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
142 * @codec: HDA codec
143 * @nid: the pin widget NID
144 * @dev_id: device identifier
145 * @audio_enabled: the pointer to store the current audio state
146 * @buffer: the buffer pointer to store ELD bytes
147 * @max_bytes: the max bytes to be stored on @buffer
148 *
149 * This function is supposed to be used only by a HD-audio controller
150 * driver that needs the interaction with graphics driver.
151 *
152 * This function queries the current state of the audio on the given
153 * digital port and fetches the ELD bytes onto the given buffer.
154 * It returns the number of bytes for the total ELD data, zero for
155 * invalid ELD, or a negative error code.
156 *
157 * The return size is the total bytes required for the whole ELD bytes,
158 * thus it may be over @max_bytes. If it's over @max_bytes, it implies
159 * that only a part of ELD bytes have been fetched.
160 */
snd_hdac_acomp_get_eld(struct hdac_device * codec,hda_nid_t nid,int dev_id,bool * audio_enabled,char * buffer,int max_bytes)161 int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
162 bool *audio_enabled, char *buffer, int max_bytes)
163 {
164 struct hdac_bus *bus = codec->bus;
165 struct drm_audio_component *acomp = bus->audio_component;
166 int port, pipe;
167
168 if (!acomp || !acomp->ops || !acomp->ops->get_eld)
169 return -ENODEV;
170
171 port = nid;
172 if (acomp->audio_ops && acomp->audio_ops->pin2port) {
173 port = acomp->audio_ops->pin2port(codec, nid);
174 if (port < 0)
175 return -EINVAL;
176 }
177 pipe = dev_id;
178 return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
179 buffer, max_bytes);
180 }
181 EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
182
hdac_component_master_bind(struct device * dev)183 static int hdac_component_master_bind(struct device *dev)
184 {
185 struct drm_audio_component *acomp = hdac_get_acomp(dev);
186 int ret;
187
188 if (WARN_ON(!acomp))
189 return -EINVAL;
190
191 ret = component_bind_all(dev, acomp);
192 if (ret < 0)
193 return ret;
194
195 if (WARN_ON(!(acomp->dev && acomp->ops))) {
196 ret = -EINVAL;
197 goto out_unbind;
198 }
199
200 /* pin the module to avoid dynamic unbinding, but only if given */
201 if (!try_module_get(acomp->ops->owner)) {
202 ret = -ENODEV;
203 goto out_unbind;
204 }
205
206 if (acomp->audio_ops && acomp->audio_ops->master_bind) {
207 ret = acomp->audio_ops->master_bind(dev, acomp);
208 if (ret < 0)
209 goto module_put;
210 }
211
212 complete_all(&acomp->master_bind_complete);
213 return 0;
214
215 module_put:
216 module_put(acomp->ops->owner);
217 out_unbind:
218 component_unbind_all(dev, acomp);
219 complete_all(&acomp->master_bind_complete);
220
221 return ret;
222 }
223
hdac_component_master_unbind(struct device * dev)224 static void hdac_component_master_unbind(struct device *dev)
225 {
226 struct drm_audio_component *acomp = hdac_get_acomp(dev);
227
228 if (acomp->audio_ops && acomp->audio_ops->master_unbind)
229 acomp->audio_ops->master_unbind(dev, acomp);
230 module_put(acomp->ops->owner);
231 component_unbind_all(dev, acomp);
232 WARN_ON(acomp->ops || acomp->dev);
233 }
234
235 static const struct component_master_ops hdac_component_master_ops = {
236 .bind = hdac_component_master_bind,
237 .unbind = hdac_component_master_unbind,
238 };
239
240 /**
241 * snd_hdac_acomp_register_notifier - Register audio component ops
242 * @bus: HDA core bus
243 * @aops: audio component ops
244 *
245 * This function is supposed to be used only by a HD-audio controller
246 * driver that needs the interaction with graphics driver.
247 *
248 * This function sets the given ops to be called by the graphics driver.
249 *
250 * Returns zero for success or a negative error code.
251 */
snd_hdac_acomp_register_notifier(struct hdac_bus * bus,const struct drm_audio_component_audio_ops * aops)252 int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
253 const struct drm_audio_component_audio_ops *aops)
254 {
255 if (!bus->audio_component)
256 return -ENODEV;
257
258 bus->audio_component->audio_ops = aops;
259 return 0;
260 }
261 EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
262
263 /**
264 * snd_hdac_acomp_init - Initialize audio component
265 * @bus: HDA core bus
266 * @aops: audio component ops
267 * @match_master: match function for finding components
268 * @extra_size: Extra bytes to allocate
269 *
270 * This function is supposed to be used only by a HD-audio controller
271 * driver that needs the interaction with graphics driver.
272 *
273 * This function initializes and sets up the audio component to communicate
274 * with graphics driver.
275 *
276 * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
277 * binding with the DRM component. Each caller needs to sync via master_bind
278 * audio_ops.
279 *
280 * Returns zero for success or a negative error code.
281 */
snd_hdac_acomp_init(struct hdac_bus * bus,const struct drm_audio_component_audio_ops * aops,int (* match_master)(struct device *,int,void *),size_t extra_size)282 int snd_hdac_acomp_init(struct hdac_bus *bus,
283 const struct drm_audio_component_audio_ops *aops,
284 int (*match_master)(struct device *, int, void *),
285 size_t extra_size)
286 {
287 struct component_match *match = NULL;
288 struct device *dev = bus->dev;
289 struct drm_audio_component *acomp;
290 int ret;
291
292 if (WARN_ON(hdac_get_acomp(dev)))
293 return -EBUSY;
294
295 acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
296 GFP_KERNEL);
297 if (!acomp)
298 return -ENOMEM;
299 acomp->audio_ops = aops;
300 init_completion(&acomp->master_bind_complete);
301 bus->audio_component = acomp;
302 devres_add(dev, acomp);
303
304 component_match_add_typed(dev, &match, match_master, bus);
305 ret = component_master_add_with_match(dev, &hdac_component_master_ops,
306 match);
307 if (ret < 0)
308 goto out_err;
309
310 return 0;
311
312 out_err:
313 bus->audio_component = NULL;
314 devres_destroy(dev, hdac_acomp_release, NULL, NULL);
315 dev_info(dev, "failed to add audio component master (%d)\n", ret);
316
317 return ret;
318 }
319 EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
320
321 /**
322 * snd_hdac_acomp_exit - Finalize audio component
323 * @bus: HDA core bus
324 *
325 * This function is supposed to be used only by a HD-audio controller
326 * driver that needs the interaction with graphics driver.
327 *
328 * This function releases the audio component that has been used.
329 *
330 * Returns zero for success or a negative error code.
331 */
snd_hdac_acomp_exit(struct hdac_bus * bus)332 int snd_hdac_acomp_exit(struct hdac_bus *bus)
333 {
334 struct device *dev = bus->dev;
335 struct drm_audio_component *acomp = bus->audio_component;
336
337 if (!acomp)
338 return 0;
339
340 if (WARN_ON(bus->display_power_active) && acomp->ops)
341 acomp->ops->put_power(acomp->dev, bus->display_power_active);
342
343 bus->display_power_active = 0;
344 bus->display_power_status = 0;
345
346 component_master_del(dev, &hdac_component_master_ops);
347
348 bus->audio_component = NULL;
349 devres_destroy(dev, hdac_acomp_release, NULL, NULL);
350
351 return 0;
352 }
353 EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
354