Commit | Line | Data |
---|---|---|
3dc0d709 PU |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // | |
3 | // Copyright(c) 2019-2022 Intel Corporation. All rights reserved. | |
4 | // | |
5 | // Author: Cezary Rojewski <cezary.rojewski@intel.com> | |
6 | // | |
7 | // SOF client support: | |
8 | // Ranjani Sridharan <ranjani.sridharan@linux.intel.com> | |
9 | // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> | |
10 | // | |
11 | ||
12 | #include <linux/debugfs.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/pm_runtime.h> | |
b9163e9b | 15 | #include <linux/string_helpers.h> |
b7b080cf | 16 | #include <linux/stddef.h> |
b9163e9b | 17 | |
3dc0d709 PU |
18 | #include <sound/soc.h> |
19 | #include <sound/sof/header.h> | |
20 | #include "sof-client.h" | |
21 | #include "sof-client-probes.h" | |
22 | ||
23 | #define SOF_PROBES_SUSPEND_DELAY_MS 3000 | |
24 | /* only extraction supported for now */ | |
25 | #define SOF_PROBES_NUM_DAI_LINKS 1 | |
26 | ||
27 | #define SOF_PROBES_INVALID_NODE_ID UINT_MAX | |
28 | ||
29 | static bool __read_mostly sof_probes_enabled; | |
30 | module_param_named(enable, sof_probes_enabled, bool, 0444); | |
31 | MODULE_PARM_DESC(enable, "Enable SOF probes support"); | |
32 | ||
3dc0d709 PU |
33 | static int sof_probes_compr_startup(struct snd_compr_stream *cstream, |
34 | struct snd_soc_dai *dai) | |
35 | { | |
36 | struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); | |
37 | struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); | |
38 | struct sof_probes_priv *priv = cdev->data; | |
39 | const struct sof_probes_host_ops *ops = priv->host_ops; | |
40 | int ret; | |
41 | ||
42 | if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED) | |
43 | return -ENODEV; | |
44 | ||
45 | ret = sof_client_core_module_get(cdev); | |
46 | if (ret) | |
47 | return ret; | |
48 | ||
bdcf7926 | 49 | ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag); |
3dc0d709 | 50 | if (ret) { |
bdcf7926 | 51 | dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret); |
3dc0d709 PU |
52 | priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; |
53 | sof_client_core_module_put(cdev); | |
54 | } | |
55 | ||
56 | return ret; | |
57 | } | |
58 | ||
59 | static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream, | |
60 | struct snd_soc_dai *dai) | |
61 | { | |
62 | struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); | |
63 | struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); | |
64 | struct sof_probes_priv *priv = cdev->data; | |
65 | const struct sof_probes_host_ops *ops = priv->host_ops; | |
ccf06b14 | 66 | const struct sof_probes_ipc_ops *ipc = priv->ipc_ops; |
3dc0d709 PU |
67 | struct sof_probe_point_desc *desc; |
68 | size_t num_desc; | |
69 | int i, ret; | |
70 | ||
71 | /* disconnect all probe points */ | |
ccf06b14 | 72 | ret = ipc->points_info(cdev, &desc, &num_desc); |
3dc0d709 PU |
73 | if (ret < 0) { |
74 | dev_err(dai->dev, "Failed to get probe points: %d\n", ret); | |
75 | goto exit; | |
76 | } | |
77 | ||
78 | for (i = 0; i < num_desc; i++) | |
ccf06b14 | 79 | ipc->points_remove(cdev, &desc[i].buffer_id, 1); |
3dc0d709 PU |
80 | kfree(desc); |
81 | ||
82 | exit: | |
ccf06b14 | 83 | ret = ipc->deinit(cdev); |
3dc0d709 PU |
84 | if (ret < 0) |
85 | dev_err(dai->dev, "Failed to deinit probe: %d\n", ret); | |
86 | ||
87 | priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; | |
88 | snd_compr_free_pages(cstream); | |
89 | ||
bdcf7926 | 90 | ret = ops->shutdown(cdev, cstream, dai); |
3dc0d709 PU |
91 | |
92 | sof_client_core_module_put(cdev); | |
93 | ||
94 | return ret; | |
95 | } | |
96 | ||
97 | static int sof_probes_compr_set_params(struct snd_compr_stream *cstream, | |
98 | struct snd_compr_params *params, | |
99 | struct snd_soc_dai *dai) | |
100 | { | |
101 | struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); | |
102 | struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); | |
103 | struct snd_compr_runtime *rtd = cstream->runtime; | |
104 | struct sof_probes_priv *priv = cdev->data; | |
105 | const struct sof_probes_host_ops *ops = priv->host_ops; | |
ccf06b14 | 106 | const struct sof_probes_ipc_ops *ipc = priv->ipc_ops; |
3dc0d709 PU |
107 | int ret; |
108 | ||
109 | cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; | |
110 | cstream->dma_buffer.dev.dev = sof_client_get_dma_dev(cdev); | |
111 | ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); | |
112 | if (ret < 0) | |
113 | return ret; | |
114 | ||
115 | ret = ops->set_params(cdev, cstream, params, dai); | |
116 | if (ret) | |
117 | return ret; | |
118 | ||
ccf06b14 | 119 | ret = ipc->init(cdev, priv->extractor_stream_tag, rtd->dma_bytes); |
3dc0d709 PU |
120 | if (ret < 0) { |
121 | dev_err(dai->dev, "Failed to init probe: %d\n", ret); | |
122 | return ret; | |
123 | } | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static int sof_probes_compr_trigger(struct snd_compr_stream *cstream, int cmd, | |
129 | struct snd_soc_dai *dai) | |
130 | { | |
131 | struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); | |
132 | struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); | |
133 | struct sof_probes_priv *priv = cdev->data; | |
134 | const struct sof_probes_host_ops *ops = priv->host_ops; | |
135 | ||
136 | return ops->trigger(cdev, cstream, cmd, dai); | |
137 | } | |
138 | ||
139 | static int sof_probes_compr_pointer(struct snd_compr_stream *cstream, | |
140 | struct snd_compr_tstamp *tstamp, | |
141 | struct snd_soc_dai *dai) | |
142 | { | |
143 | struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); | |
144 | struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); | |
145 | struct sof_probes_priv *priv = cdev->data; | |
146 | const struct sof_probes_host_ops *ops = priv->host_ops; | |
147 | ||
148 | return ops->pointer(cdev, cstream, tstamp, dai); | |
149 | } | |
150 | ||
151 | static const struct snd_soc_cdai_ops sof_probes_compr_ops = { | |
152 | .startup = sof_probes_compr_startup, | |
153 | .shutdown = sof_probes_compr_shutdown, | |
154 | .set_params = sof_probes_compr_set_params, | |
155 | .trigger = sof_probes_compr_trigger, | |
156 | .pointer = sof_probes_compr_pointer, | |
157 | }; | |
158 | ||
159 | static int sof_probes_compr_copy(struct snd_soc_component *component, | |
160 | struct snd_compr_stream *cstream, | |
161 | char __user *buf, size_t count) | |
162 | { | |
163 | struct snd_compr_runtime *rtd = cstream->runtime; | |
164 | unsigned int offset, n; | |
165 | void *ptr; | |
166 | int ret; | |
167 | ||
168 | if (count > rtd->buffer_size) | |
169 | count = rtd->buffer_size; | |
170 | ||
171 | div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); | |
172 | ptr = rtd->dma_area + offset; | |
173 | n = rtd->buffer_size - offset; | |
174 | ||
175 | if (count < n) { | |
176 | ret = copy_to_user(buf, ptr, count); | |
177 | } else { | |
178 | ret = copy_to_user(buf, ptr, n); | |
179 | ret += copy_to_user(buf + n, rtd->dma_area, count - n); | |
180 | } | |
181 | ||
182 | if (ret) | |
183 | return count - ret; | |
184 | return count; | |
185 | } | |
186 | ||
187 | static const struct snd_compress_ops sof_probes_compressed_ops = { | |
188 | .copy = sof_probes_compr_copy, | |
189 | }; | |
190 | ||
3dc0d709 PU |
191 | static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, |
192 | size_t count, loff_t *ppos) | |
193 | { | |
194 | struct sof_client_dev *cdev = file->private_data; | |
195 | struct sof_probes_priv *priv = cdev->data; | |
196 | struct device *dev = &cdev->auxdev.dev; | |
197 | struct sof_probe_point_desc *desc; | |
ccf06b14 | 198 | const struct sof_probes_ipc_ops *ipc = priv->ipc_ops; |
3dc0d709 PU |
199 | int remaining, offset; |
200 | size_t num_desc; | |
201 | char *buf; | |
202 | int i, ret, err; | |
203 | ||
204 | if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { | |
205 | dev_warn(dev, "no extractor stream running\n"); | |
206 | return -ENOENT; | |
207 | } | |
208 | ||
209 | buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
210 | if (!buf) | |
211 | return -ENOMEM; | |
212 | ||
b3598fe6 | 213 | ret = pm_runtime_resume_and_get(dev); |
3dc0d709 PU |
214 | if (ret < 0 && ret != -EACCES) { |
215 | dev_err_ratelimited(dev, "debugfs read failed to resume %d\n", ret); | |
3dc0d709 PU |
216 | goto exit; |
217 | } | |
218 | ||
ccf06b14 | 219 | ret = ipc->points_info(cdev, &desc, &num_desc); |
3dc0d709 | 220 | if (ret < 0) |
bc424273 | 221 | goto pm_error; |
3dc0d709 PU |
222 | |
223 | for (i = 0; i < num_desc; i++) { | |
224 | offset = strlen(buf); | |
225 | remaining = PAGE_SIZE - offset; | |
226 | ret = snprintf(buf + offset, remaining, | |
227 | "Id: %#010x Purpose: %u Node id: %#x\n", | |
228 | desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); | |
229 | if (ret < 0 || ret >= remaining) { | |
230 | /* truncate the output buffer at the last full line */ | |
231 | buf[offset] = '\0'; | |
232 | break; | |
233 | } | |
234 | } | |
235 | ||
236 | ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf)); | |
237 | ||
238 | kfree(desc); | |
bc424273 PLB |
239 | |
240 | pm_error: | |
241 | pm_runtime_mark_last_busy(dev); | |
242 | err = pm_runtime_put_autosuspend(dev); | |
243 | if (err < 0) | |
244 | dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err); | |
245 | ||
3dc0d709 PU |
246 | exit: |
247 | kfree(buf); | |
248 | return ret; | |
249 | } | |
250 | ||
251 | static ssize_t | |
252 | sof_probes_dfs_points_write(struct file *file, const char __user *from, | |
253 | size_t count, loff_t *ppos) | |
254 | { | |
255 | struct sof_client_dev *cdev = file->private_data; | |
256 | struct sof_probes_priv *priv = cdev->data; | |
ccf06b14 | 257 | const struct sof_probes_ipc_ops *ipc = priv->ipc_ops; |
3dc0d709 PU |
258 | struct device *dev = &cdev->auxdev.dev; |
259 | struct sof_probe_point_desc *desc; | |
b9163e9b CR |
260 | u32 num_elems, *array; |
261 | size_t bytes; | |
3dc0d709 PU |
262 | int ret, err; |
263 | ||
264 | if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { | |
265 | dev_warn(dev, "no extractor stream running\n"); | |
266 | return -ENOENT; | |
267 | } | |
268 | ||
b9163e9b | 269 | ret = parse_int_array_user(from, count, (int **)&array); |
3dc0d709 PU |
270 | if (ret < 0) |
271 | return ret; | |
b9163e9b CR |
272 | |
273 | num_elems = *array; | |
274 | bytes = sizeof(*array) * num_elems; | |
275 | if (bytes % sizeof(*desc)) { | |
3dc0d709 PU |
276 | ret = -EINVAL; |
277 | goto exit; | |
278 | } | |
279 | ||
b9163e9b | 280 | desc = (struct sof_probe_point_desc *)&array[1]; |
3dc0d709 | 281 | |
b3598fe6 | 282 | ret = pm_runtime_resume_and_get(dev); |
3dc0d709 PU |
283 | if (ret < 0 && ret != -EACCES) { |
284 | dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); | |
3dc0d709 PU |
285 | goto exit; |
286 | } | |
287 | ||
ccf06b14 | 288 | ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc)); |
3dc0d709 PU |
289 | if (!ret) |
290 | ret = count; | |
291 | ||
292 | pm_runtime_mark_last_busy(dev); | |
293 | err = pm_runtime_put_autosuspend(dev); | |
294 | if (err < 0) | |
295 | dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); | |
296 | exit: | |
b9163e9b | 297 | kfree(array); |
3dc0d709 PU |
298 | return ret; |
299 | } | |
300 | ||
301 | static const struct file_operations sof_probes_points_fops = { | |
302 | .open = simple_open, | |
303 | .read = sof_probes_dfs_points_read, | |
304 | .write = sof_probes_dfs_points_write, | |
305 | .llseek = default_llseek, | |
306 | ||
307 | .owner = THIS_MODULE, | |
308 | }; | |
309 | ||
310 | static ssize_t | |
311 | sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, | |
312 | size_t count, loff_t *ppos) | |
313 | { | |
314 | struct sof_client_dev *cdev = file->private_data; | |
315 | struct sof_probes_priv *priv = cdev->data; | |
ccf06b14 | 316 | const struct sof_probes_ipc_ops *ipc = priv->ipc_ops; |
3dc0d709 | 317 | struct device *dev = &cdev->auxdev.dev; |
3dc0d709 | 318 | int ret, err; |
b9163e9b | 319 | u32 *array; |
3dc0d709 PU |
320 | |
321 | if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { | |
322 | dev_warn(dev, "no extractor stream running\n"); | |
323 | return -ENOENT; | |
324 | } | |
325 | ||
b9163e9b | 326 | ret = parse_int_array_user(from, count, (int **)&array); |
3dc0d709 PU |
327 | if (ret < 0) |
328 | return ret; | |
3dc0d709 | 329 | |
b3598fe6 | 330 | ret = pm_runtime_resume_and_get(dev); |
3dc0d709 PU |
331 | if (ret < 0) { |
332 | dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); | |
3dc0d709 PU |
333 | goto exit; |
334 | } | |
335 | ||
ccf06b14 | 336 | ret = ipc->points_remove(cdev, &array[1], array[0]); |
3dc0d709 PU |
337 | if (!ret) |
338 | ret = count; | |
339 | ||
340 | pm_runtime_mark_last_busy(dev); | |
341 | err = pm_runtime_put_autosuspend(dev); | |
342 | if (err < 0) | |
343 | dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); | |
344 | exit: | |
b9163e9b | 345 | kfree(array); |
3dc0d709 PU |
346 | return ret; |
347 | } | |
348 | ||
349 | static const struct file_operations sof_probes_points_remove_fops = { | |
350 | .open = simple_open, | |
351 | .write = sof_probes_dfs_points_remove_write, | |
352 | .llseek = default_llseek, | |
353 | ||
354 | .owner = THIS_MODULE, | |
355 | }; | |
356 | ||
450e7222 KM |
357 | static const struct snd_soc_dai_ops sof_probes_dai_ops = { |
358 | .compress_new = snd_soc_new_compress, | |
359 | }; | |
360 | ||
3dc0d709 PU |
361 | static struct snd_soc_dai_driver sof_probes_dai_drv[] = { |
362 | { | |
363 | .name = "Probe Extraction CPU DAI", | |
450e7222 | 364 | .ops = &sof_probes_dai_ops, |
3dc0d709 PU |
365 | .cops = &sof_probes_compr_ops, |
366 | .capture = { | |
367 | .stream_name = "Probe Extraction", | |
368 | .channels_min = 1, | |
369 | .channels_max = 8, | |
370 | .rates = SNDRV_PCM_RATE_48000, | |
371 | .rate_min = 48000, | |
372 | .rate_max = 48000, | |
373 | }, | |
374 | }, | |
375 | }; | |
376 | ||
377 | static const struct snd_soc_component_driver sof_probes_component = { | |
378 | .name = "sof-probes-component", | |
379 | .compress_ops = &sof_probes_compressed_ops, | |
380 | .module_get_upon_open = 1, | |
a718ba30 | 381 | .legacy_dai_naming = 1, |
3dc0d709 PU |
382 | }; |
383 | ||
3dc0d709 PU |
384 | static int sof_probes_client_probe(struct auxiliary_device *auxdev, |
385 | const struct auxiliary_device_id *id) | |
386 | { | |
387 | struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); | |
388 | struct dentry *dfsroot = sof_client_get_debugfs_root(cdev); | |
389 | struct device *dev = &auxdev->dev; | |
390 | struct snd_soc_dai_link_component platform_component[] = { | |
391 | { | |
392 | .name = dev_name(dev), | |
393 | } | |
394 | }; | |
395 | struct snd_soc_card *card; | |
396 | struct sof_probes_priv *priv; | |
397 | struct snd_soc_dai_link_component *cpus; | |
398 | struct sof_probes_host_ops *ops; | |
399 | struct snd_soc_dai_link *links; | |
400 | int ret; | |
401 | ||
402 | /* do not set up the probes support if it is not enabled */ | |
403 | if (!sof_probes_enabled) | |
404 | return -ENXIO; | |
405 | ||
82b21ca1 AS |
406 | ops = dev_get_platdata(dev); |
407 | if (!ops) { | |
3dc0d709 PU |
408 | dev_err(dev, "missing platform data\n"); |
409 | return -ENODEV; | |
410 | } | |
bdcf7926 | 411 | if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger || |
3dc0d709 PU |
412 | !ops->pointer) { |
413 | dev_err(dev, "missing platform callback(s)\n"); | |
414 | return -ENODEV; | |
415 | } | |
416 | ||
82b21ca1 AS |
417 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
418 | if (!priv) | |
419 | return -ENOMEM; | |
420 | ||
3dc0d709 | 421 | priv->host_ops = ops; |
f5623593 JS |
422 | |
423 | switch (sof_client_get_ipc_type(cdev)) { | |
82f4b383 | 424 | #ifdef CONFIG_SND_SOC_SOF_IPC4 |
ebe18b15 | 425 | case SOF_IPC_TYPE_4: |
f5623593 JS |
426 | priv->ipc_ops = &ipc4_probe_ops; |
427 | break; | |
428 | #endif | |
429 | #ifdef CONFIG_SND_SOC_SOF_IPC3 | |
ebe18b15 | 430 | case SOF_IPC_TYPE_3: |
f5623593 JS |
431 | priv->ipc_ops = &ipc3_probe_ops; |
432 | break; | |
433 | #endif | |
434 | default: | |
435 | dev_err(dev, "Matching IPC ops not found."); | |
436 | return -ENODEV; | |
437 | } | |
438 | ||
3dc0d709 PU |
439 | cdev->data = priv; |
440 | ||
441 | /* register probes component driver and dai */ | |
442 | ret = devm_snd_soc_register_component(dev, &sof_probes_component, | |
443 | sof_probes_dai_drv, | |
444 | ARRAY_SIZE(sof_probes_dai_drv)); | |
445 | if (ret < 0) { | |
446 | dev_err(dev, "failed to register SOF probes DAI driver %d\n", ret); | |
447 | return ret; | |
448 | } | |
449 | ||
450 | /* set client data */ | |
451 | priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; | |
452 | ||
453 | /* create read-write probes_points debugfs entry */ | |
454 | priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot, | |
455 | cdev, &sof_probes_points_fops); | |
456 | ||
457 | /* create read-write probe_points_remove debugfs entry */ | |
458 | priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644, | |
459 | dfsroot, cdev, | |
460 | &sof_probes_points_remove_fops); | |
461 | ||
462 | links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL); | |
463 | cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL); | |
464 | if (!links || !cpus) { | |
465 | debugfs_remove(priv->dfs_points); | |
466 | debugfs_remove(priv->dfs_points_remove); | |
467 | return -ENOMEM; | |
468 | } | |
469 | ||
470 | /* extraction DAI link */ | |
471 | links[0].name = "Compress Probe Capture"; | |
472 | links[0].id = 0; | |
473 | links[0].cpus = &cpus[0]; | |
474 | links[0].num_cpus = 1; | |
475 | links[0].cpus->dai_name = "Probe Extraction CPU DAI"; | |
e8776ff9 | 476 | links[0].codecs = &snd_soc_dummy_dlc; |
3dc0d709 PU |
477 | links[0].num_codecs = 1; |
478 | links[0].platforms = platform_component; | |
479 | links[0].num_platforms = ARRAY_SIZE(platform_component); | |
480 | links[0].nonatomic = 1; | |
481 | ||
482 | card = &priv->card; | |
483 | ||
484 | card->dev = dev; | |
485 | card->name = "sof-probes"; | |
486 | card->owner = THIS_MODULE; | |
487 | card->num_links = SOF_PROBES_NUM_DAI_LINKS; | |
488 | card->dai_link = links; | |
489 | ||
490 | /* set idle_bias_off to prevent the core from resuming the card->dev */ | |
491 | card->dapm.idle_bias_off = true; | |
492 | ||
493 | snd_soc_card_set_drvdata(card, cdev); | |
494 | ||
495 | ret = devm_snd_soc_register_card(dev, card); | |
496 | if (ret < 0) { | |
497 | debugfs_remove(priv->dfs_points); | |
498 | debugfs_remove(priv->dfs_points_remove); | |
499 | dev_err(dev, "Probes card register failed %d\n", ret); | |
500 | return ret; | |
501 | } | |
502 | ||
503 | /* enable runtime PM */ | |
504 | pm_runtime_set_autosuspend_delay(dev, SOF_PROBES_SUSPEND_DELAY_MS); | |
505 | pm_runtime_use_autosuspend(dev); | |
506 | pm_runtime_enable(dev); | |
507 | pm_runtime_mark_last_busy(dev); | |
508 | pm_runtime_idle(dev); | |
509 | ||
510 | return 0; | |
511 | } | |
512 | ||
513 | static void sof_probes_client_remove(struct auxiliary_device *auxdev) | |
514 | { | |
515 | struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); | |
516 | struct sof_probes_priv *priv = cdev->data; | |
517 | ||
518 | if (!sof_probes_enabled) | |
519 | return; | |
520 | ||
521 | pm_runtime_disable(&auxdev->dev); | |
522 | debugfs_remove(priv->dfs_points); | |
523 | debugfs_remove(priv->dfs_points_remove); | |
524 | } | |
525 | ||
526 | static const struct auxiliary_device_id sof_probes_client_id_table[] = { | |
527 | { .name = "snd_sof.hda-probes", }, | |
5e1c5df5 | 528 | { .name = "snd_sof.acp-probes", }, |
3dc0d709 PU |
529 | {}, |
530 | }; | |
531 | MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table); | |
532 | ||
533 | /* driver name will be set based on KBUILD_MODNAME */ | |
534 | static struct auxiliary_driver sof_probes_client_drv = { | |
535 | .probe = sof_probes_client_probe, | |
536 | .remove = sof_probes_client_remove, | |
537 | ||
538 | .id_table = sof_probes_client_id_table, | |
539 | }; | |
540 | ||
541 | module_auxiliary_driver(sof_probes_client_drv); | |
542 | ||
543 | MODULE_DESCRIPTION("SOF Probes Client Driver"); | |
544 | MODULE_LICENSE("GPL v2"); | |
545 | MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); |