diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 1a7d6cefd3b7..468d7c113dae 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -61,6 +61,13 @@ config SND_SOC_SOF_DEBUG_PROBES Say Y if you want to enable probes. If unsure, select "N". +config SND_SOC_SOF_CLIENT + tristate + select AUXILIARY_BUS + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level. + config SND_SOC_SOF_DEVELOPER_SUPPORT bool "SOF developer options support" depends on EXPERT && SND_SOC_SOF diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 4b9fccacc2b7..38ce2fe376fa 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -2,6 +2,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o +snd-sof-$(CONFIG_SND_SOC_SOF_CLIENT) += sof-client.o snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8f32b5b12b3e..2aabaac9007f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -122,6 +122,27 @@ out: } EXPORT_SYMBOL(sof_print_oops_and_stack); +/* Helper to manage DSP state */ +void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state) +{ + if (sdev->fw_state == new_state) + return; + + dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state); + sdev->fw_state = new_state; + + switch (new_state) { + case SOF_FW_BOOT_NOT_STARTED: + case SOF_FW_BOOT_COMPLETE: + case SOF_FW_CRASHED: + sof_client_fw_state_dispatcher(sdev); + fallthrough; + default: + break; + } +} +EXPORT_SYMBOL(sof_set_fw_state); + /* * FW Boot State Transition Diagram * @@ -266,6 +287,12 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_trace_err; } + ret = sof_register_clients(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to register clients %d\n", ret); + goto sof_machine_err; + } + /* * Some platforms in SOF, ex: BYT, may not have their platform PM * callbacks set. Increment the usage count so as to @@ -281,6 +308,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; +sof_machine_err: + snd_sof_machine_unregister(sdev, plat_data); fw_trace_err: snd_sof_free_trace(sdev); fw_run_err: @@ -329,7 +358,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->pdata = plat_data; sdev->first_boot = true; - sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; #endif @@ -350,9 +378,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->dai_list); INIT_LIST_HEAD(&sdev->route_list); + INIT_LIST_HEAD(&sdev->ipc_client_list); + INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); + INIT_LIST_HEAD(&sdev->fw_state_handler_list); spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); mutex_init(&sdev->power_state_access); + mutex_init(&sdev->ipc_client_mutex); + mutex_init(&sdev->client_event_handler_mutex); /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) @@ -364,6 +397,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) else sdev->boot_timeout = plat_data->desc->boot_timeout; + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { INIT_WORK(&sdev->probe_work, sof_probe_work); schedule_work(&sdev->probe_work); @@ -391,6 +426,12 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); + /* + * Unregister any registered client device first before IPC and debugfs + * to allow client drivers to be removed cleanly + */ + sof_unregister_clients(sdev); + /* * Unregister machine driver. This will unbind the snd_card which * will remove the component driver and unload the topology diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index ee56d4fa4053..c729bb7bf8c8 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -557,22 +557,25 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) break; } - if (rx_callback) { - /* read the full message as we have rx handler for it */ - msg_buf = kmalloc(hdr.size, GFP_KERNEL); - if (!msg_buf) - return; + /* read the full message */ + msg_buf = kmalloc(hdr.size, GFP_KERNEL); + if (!msg_buf) + return; - err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); - if (err < 0) - dev_err(sdev->dev, "%s: Failed to read message: %d\n", - __func__, err); - else + err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); + if (err < 0) { + dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err); + } else { + /* Call local handler for the message */ + if (rx_callback) rx_callback(sdev, msg_buf); - kfree(msg_buf); + /* Notify registered clients */ + sof_client_ipc_rx_dispatcher(sdev, msg_buf); } + kfree(msg_buf); + ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c new file mode 100644 index 000000000000..6f747d051b59 --- /dev/null +++ b/sound/soc/sof/sof-client.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Authors: Ranjani Sridharan +// Peter Ujfalusi +// + +#include +#include +#include +#include +#include +#include +#include "ops.h" +#include "sof-client.h" +#include "sof-priv.h" + +/** + * struct sof_ipc_event_entry - IPC client event description + * @ipc_msg_type: IPC msg type of the event the client is interested + * @cdev: sof_client_dev of the requesting client + * @callback: Callback function of the client + * @list: item in SOF core client event list + */ +struct sof_ipc_event_entry { + u32 ipc_msg_type; + struct sof_client_dev *cdev; + sof_client_event_callback callback; + struct list_head list; +}; + +/** + * struct sof_state_event_entry - DSP panic event subscription entry + * @cdev: sof_client_dev of the requesting client + * @callback: Callback function of the client + * @list: item in SOF core client event list + */ +struct sof_state_event_entry { + struct sof_client_dev *cdev; + sof_client_fw_state_callback callback; + struct list_head list; +}; + +static void sof_client_auxdev_release(struct device *dev) +{ + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); + struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); + + kfree(cdev->auxdev.dev.platform_data); + kfree(cdev); +} + +static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data, + size_t size) +{ + void *d = NULL; + + if (data) { + d = kmemdup(data, size, GFP_KERNEL); + if (!d) + return -ENOMEM; + } + + cdev->auxdev.dev.platform_data = d; + return 0; +} + +int sof_register_clients(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) + return sof_ops(sdev)->register_ipc_clients(sdev); + + return 0; +} + +void sof_unregister_clients(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients) + sof_ops(sdev)->unregister_ipc_clients(sdev); +} + +int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, + const void *data, size_t size) +{ + struct auxiliary_device *auxdev; + struct sof_client_dev *cdev; + int ret; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->sdev = sdev; + auxdev = &cdev->auxdev; + auxdev->name = name; + auxdev->dev.parent = sdev->dev; + auxdev->dev.release = sof_client_auxdev_release; + auxdev->id = id; + + ret = sof_client_dev_add_data(cdev, data, size); + if (ret < 0) + goto err_dev_add_data; + + ret = auxiliary_device_init(auxdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to initialize client dev %s.%d\n", name, id); + goto err_dev_init; + } + + ret = auxiliary_device_add(&cdev->auxdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to add client dev %s.%d\n", name, id); + /* + * sof_client_auxdev_release() will be invoked to free up memory + * allocations through put_device() + */ + auxiliary_device_uninit(&cdev->auxdev); + return ret; + } + + /* add to list of SOF client devices */ + mutex_lock(&sdev->ipc_client_mutex); + list_add(&cdev->list, &sdev->ipc_client_list); + mutex_unlock(&sdev->ipc_client_mutex); + + return 0; + +err_dev_init: + kfree(cdev->auxdev.dev.platform_data); + +err_dev_add_data: + kfree(cdev); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); + +void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) +{ + struct sof_client_dev *cdev; + + mutex_lock(&sdev->ipc_client_mutex); + + /* + * sof_client_auxdev_release() will be invoked to free up memory + * allocations through put_device() + */ + list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) { + list_del(&cdev->list); + auxiliary_device_delete(&cdev->auxdev); + auxiliary_device_uninit(&cdev->auxdev); + break; + } + } + + mutex_unlock(&sdev->ipc_client_mutex); +} +EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); + +int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, + void *reply_data, size_t reply_bytes) +{ + struct sof_ipc_cmd_hdr *hdr = ipc_msg; + + return sof_ipc_tx_message(cdev->sdev->ipc, hdr->cmd, ipc_msg, hdr->size, + reply_data, reply_bytes); +} +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); + +struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) +{ + return cdev->sdev->debugfs_root; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT); + +/* DMA buffer allocation in client drivers must use the core SOF device */ +struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) +{ + return cdev->sdev->dev; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); + +const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return &sdev->fw_ready.version; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); + +/* module refcount management of SOF core */ +int sof_client_core_module_get(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (!try_module_get(sdev->dev->driver->owner)) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); + +void sof_client_core_module_put(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + module_put(sdev->dev->driver->owner); +} +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); + +/* IPC event handling */ +void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) +{ + struct sof_ipc_cmd_hdr *hdr = msg_buf; + u32 msg_type = hdr->cmd & SOF_GLB_TYPE_MASK; + struct sof_ipc_event_entry *event; + + mutex_lock(&sdev->client_event_handler_mutex); + + list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { + if (event->ipc_msg_type == msg_type) + event->callback(event->cdev, msg_buf); + } + + mutex_unlock(&sdev->client_event_handler_mutex); +} + +int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, + u32 ipc_msg_type, + sof_client_event_callback callback) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct sof_ipc_event_entry *event; + + if (!callback || !(ipc_msg_type & SOF_GLB_TYPE_MASK)) + return -EINVAL; + + event = kmalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return -ENOMEM; + + event->ipc_msg_type = ipc_msg_type; + event->cdev = cdev; + event->callback = callback; + + /* add to list of SOF client devices */ + mutex_lock(&sdev->client_event_handler_mutex); + list_add(&event->list, &sdev->ipc_rx_handler_list); + mutex_unlock(&sdev->client_event_handler_mutex); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); + +void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, + u32 ipc_msg_type) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct sof_ipc_event_entry *event; + + mutex_lock(&sdev->client_event_handler_mutex); + + list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { + if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) { + list_del(&event->list); + kfree(event); + break; + } + } + + mutex_unlock(&sdev->client_event_handler_mutex); +} +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); + +/*DSP state notification and query */ +void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) +{ + struct sof_state_event_entry *event; + + mutex_lock(&sdev->client_event_handler_mutex); + + list_for_each_entry(event, &sdev->fw_state_handler_list, list) + event->callback(event->cdev, sdev->fw_state); + + mutex_unlock(&sdev->client_event_handler_mutex); +} + +int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, + sof_client_fw_state_callback callback) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct sof_state_event_entry *event; + + if (!callback) + return -EINVAL; + + event = kmalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return -ENOMEM; + + event->cdev = cdev; + event->callback = callback; + + /* add to list of SOF client devices */ + mutex_lock(&sdev->client_event_handler_mutex); + list_add(&event->list, &sdev->fw_state_handler_list); + mutex_unlock(&sdev->client_event_handler_mutex); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); + +void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct sof_state_event_entry *event; + + mutex_lock(&sdev->client_event_handler_mutex); + + list_for_each_entry(event, &sdev->fw_state_handler_list, list) { + if (event->cdev == cdev) { + list_del(&event->list); + kfree(event); + break; + } + } + + mutex_unlock(&sdev->client_event_handler_mutex); +} +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); + +enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->fw_state; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h new file mode 100644 index 000000000000..4b6394b4c694 --- /dev/null +++ b/sound/soc/sof/sof-client.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_SOF_CLIENT_H +#define __SOC_SOF_CLIENT_H + +#include +#include +#include +#include + +struct sof_ipc_fw_version; +struct sof_ipc_cmd_hdr; +struct snd_sof_dev; +struct dentry; + +/** + * struct sof_client_dev - SOF client device + * @auxdev: auxiliary device + * @sdev: pointer to SOF core device struct + * @list: item in SOF core client dev list + * @data: device specific data + */ +struct sof_client_dev { + struct auxiliary_device auxdev; + struct snd_sof_dev *sdev; + struct list_head list; + void *data; +}; + +#define sof_client_dev_to_sof_dev(cdev) ((cdev)->sdev) + +#define auxiliary_dev_to_sof_client_dev(auxiliary_dev) \ + container_of(auxiliary_dev, struct sof_client_dev, auxdev) + +#define dev_to_sof_client_dev(dev) \ + container_of(to_auxiliary_dev(dev), struct sof_client_dev, auxdev) + +int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, + void *reply_data, size_t reply_bytes); + +struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev); +struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev); +const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev); + +/* module refcount management of SOF core */ +int sof_client_core_module_get(struct sof_client_dev *cdev); +void sof_client_core_module_put(struct sof_client_dev *cdev); + +/* IPC notification */ +typedef void (*sof_client_event_callback)(struct sof_client_dev *cdev, void *msg_buf); + +int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, + u32 ipc_msg_type, + sof_client_event_callback callback); +void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, + u32 ipc_msg_type); + +/* DSP state notification and query */ +typedef void (*sof_client_fw_state_callback)(struct sof_client_dev *cdev, + enum sof_fw_state state); + +int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, + sof_client_fw_state_callback callback); +void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev); +enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev); + +#endif /* __SOC_SOF_CLIENT_H */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 27d2f3ca2f06..f641833f3ff9 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -292,6 +292,10 @@ struct snd_sof_dsp_ops { void (*set_mach_params)(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev); /* optional */ + /* IPC client ops */ + int (*register_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ + void (*unregister_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ + /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; @@ -479,6 +483,30 @@ struct snd_sof_dev { */ int dsp_core_ref_count[SOF_MAX_DSP_NUM_CORES]; + /* + * Used to keep track of registered IPC client devices so that they can + * be removed when the parent SOF module is removed. + */ + struct list_head ipc_client_list; + + /* mutex to protect client list */ + struct mutex ipc_client_mutex; + + /* + * Used for tracking the IPC client's RX registration for DSP initiated + * message handling. + */ + struct list_head ipc_rx_handler_list; + + /* + * Used for tracking the IPC client's registration for DSP state change + * notification + */ + struct list_head fw_state_handler_list; + + /* to protect the ipc_rx_handler_list and dsp_state_handler_list list */ + struct mutex client_event_handler_mutex; + void *private; /* core does not touch this */ }; @@ -582,15 +610,7 @@ extern const struct dsp_arch_ops sof_xtensa_arch_ops; /* * Firmware state tracking */ -static inline void sof_set_fw_state(struct snd_sof_dev *sdev, - enum sof_fw_state new_state) -{ - if (sdev->fw_state == new_state) - return; - - dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state); - sdev->fw_state = new_state; -} +void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state); /* * Utilities @@ -623,4 +643,44 @@ int sof_stream_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); int sof_machine_check(struct snd_sof_dev *sdev); + +/* SOF client support */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CLIENT) +int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, + const void *data, size_t size); +void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id); +int sof_register_clients(struct snd_sof_dev *sdev); +void sof_unregister_clients(struct snd_sof_dev *sdev); +void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf); +void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev); +#else /* CONFIG_SND_SOC_SOF_CLIENT */ +static inline int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, + u32 id, const void *data, size_t size) +{ + return 0; +} + +static inline void sof_client_dev_unregister(struct snd_sof_dev *sdev, + const char *name, u32 id) +{ +} + +static inline int sof_register_clients(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline void sof_unregister_clients(struct snd_sof_dev *sdev) +{ +} + +static inline void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) +{ +} + +static inline void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) +{ +} +#endif /* CONFIG_SND_SOC_SOF_CLIENT */ + #endif