linux/sound/soc/soc-core.c

// SPDX-License-Identifier: GPL-2.0+
//
// soc-core.c  --  ALSA SoC Audio Layer
//
// Copyright 2005 Wolfson Microelectronics PLC.
// Copyright 2005 Openedhand Ltd.
// Copyright (C) 2010 Slimlogic Ltd.
// Copyright (C) 2010 Texas Instruments Inc.
//
// Author: Liam Girdwood <[email protected]>
//         with code, comments and ideas from :-
//         Richard Purdie <[email protected]>
//
//  TODO:
//   o Add hw rules to enforce rates, etc.
//   o More testing with other codecs/machines.
//   o Add more codecs and platforms to ensure good API coverage.
//   o Support TDM on PCM and I2S

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dpcm.h>
#include <sound/soc-topology.h>
#include <sound/soc-link.h>
#include <sound/initval.h>

#define CREATE_TRACE_POINTS
#include <trace/events/asoc.h>

static DEFINE_MUTEX(client_mutex);
static LIST_HEAD(component_list);
static LIST_HEAD(unbind_card_list);

#define for_each_component(component)

/*
 * This is used if driver don't need to have CPU/Codec/Platform
 * dai_link. see soc.h
 */
struct snd_soc_dai_link_component null_dailink_component[0];
EXPORT_SYMBOL_GPL();

/*
 * This is a timeout to do a DAPM powerdown after a stream is closed().
 * It can be used to eliminate pops between different playback streams, e.g.
 * between two audio tracks.
 */
static int pmdown_time =;
module_param(pmdown_time, int, 0);
MODULE_PARM_DESC();

static ssize_t pmdown_time_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{}

static ssize_t pmdown_time_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{}

static DEVICE_ATTR_RW(pmdown_time);

static struct attribute *soc_dev_attrs[] =;

static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
				       struct attribute *attr, int idx)
{}

static const struct attribute_group soc_dapm_dev_group =;

static const struct attribute_group soc_dev_group =;

static const struct attribute_group *soc_dev_attr_groups[] =;

#ifdef CONFIG_DEBUG_FS
struct dentry *snd_soc_debugfs_root;
EXPORT_SYMBOL_GPL();

static void soc_init_component_debugfs(struct snd_soc_component *component)
{}

static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
{}

static int dai_list_show(struct seq_file *m, void *v)
{}
DEFINE_SHOW_ATTRIBUTE();

static int component_list_show(struct seq_file *m, void *v)
{}
DEFINE_SHOW_ATTRIBUTE();

static void soc_init_card_debugfs(struct snd_soc_card *card)
{}

static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
{}

static void snd_soc_debugfs_init(void)
{}

static void snd_soc_debugfs_exit(void)
{}

#else

static inline void soc_init_component_debugfs(struct snd_soc_component *component) { }
static inline void soc_cleanup_component_debugfs(struct snd_soc_component *component) { }
static inline void soc_init_card_debugfs(struct snd_soc_card *card) { }
static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) { }
static inline void snd_soc_debugfs_init(void) { }
static inline void snd_soc_debugfs_exit(void) { }

#endif

static int snd_soc_is_match_dai_args(const struct of_phandle_args *args1,
				     const struct of_phandle_args *args2)
{}

static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
{}

static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
{}

static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
{}

static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
				   struct snd_soc_dai *dai)
{}

const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai)
{}
EXPORT_SYMBOL_GPL();

static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
				     struct snd_soc_component *component)
{}

struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
						const char *driver_name)
{}
EXPORT_SYMBOL_GPL();

struct snd_soc_component
*snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name)
{}
EXPORT_SYMBOL_GPL();

struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
						   const char *driver_name)
{}
EXPORT_SYMBOL_GPL();

struct snd_soc_pcm_runtime
*snd_soc_get_pcm_runtime(struct snd_soc_card *card,
			 struct snd_soc_dai_link *dai_link)
{}
EXPORT_SYMBOL_GPL();

/*
 * Power down the audio subsystem pmdown_time msecs after close is called.
 * This is to ensure there are no pops or clicks in between any music tracks
 * due to DAPM power cycling.
 */
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{}
EXPORT_SYMBOL_GPL();

static void soc_release_rtd_dev(struct device *dev)
{}

static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
{}

static void close_delayed_work(struct work_struct *work) {}

static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{}

static void snd_soc_fill_dummy_dai(struct snd_soc_card *card)
{}

static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
{}

#ifdef CONFIG_PM_SLEEP
static void soc_playback_digital_mute(struct snd_soc_card *card, int mute)
{}

static void soc_dapm_suspend_resume(struct snd_soc_card *card, int event)
{}

/* powers down audio subsystem for suspend */
int snd_soc_suspend(struct device *dev)
{}
EXPORT_SYMBOL_GPL();

/*
 * deferred resume work, so resume can complete before we finished
 * setting our codec back up, which can be very slow on I2C
 */
static void soc_resume_deferred(struct work_struct *work)
{}

/* powers up audio subsystem after a suspend */
int snd_soc_resume(struct device *dev)
{}
EXPORT_SYMBOL_GPL();

static void soc_resume_init(struct snd_soc_card *card)
{}
#else
#define snd_soc_suspend
#define snd_soc_resume
static inline void soc_resume_init(struct snd_soc_card *card) { }
#endif

static struct device_node
*soc_component_to_node(struct snd_soc_component *component)
{}

struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
					      const struct of_phandle_args *args)
{}
EXPORT_SYMBOL_GPL();

static int snd_soc_is_matching_component(
	const struct snd_soc_dai_link_component *dlc,
	struct snd_soc_component *component)
{}

static struct snd_soc_component *soc_find_component(
	const struct snd_soc_dai_link_component *dlc)
{}

/**
 * snd_soc_find_dai - Find a registered DAI
 *
 * @dlc: name of the DAI or the DAI driver and optional component info to match
 *
 * This function will search all registered components and their DAIs to
 * find the DAI of the same name. The component's of_node and name
 * should also match if being specified.
 *
 * Return: pointer of DAI, or NULL if not found.
 */
struct snd_soc_dai *snd_soc_find_dai(
	const struct snd_soc_dai_link_component *dlc)
{}
EXPORT_SYMBOL_GPL();

struct snd_soc_dai *snd_soc_find_dai_with_mutex(
	const struct snd_soc_dai_link_component *dlc)
{}
EXPORT_SYMBOL_GPL();

static int soc_dai_link_sanity_check(struct snd_soc_card *card,
				     struct snd_soc_dai_link *link)
{}

#define MAX_DEFAULT_CH_MAP_SIZE
static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] =;
static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] =;
static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] =;
static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card,
						     struct snd_soc_dai_link *dai_link)
{}

/**
 * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
 * @card: The ASoC card to which the pcm_runtime has
 * @rtd: The pcm_runtime to remove
 *
 * This function removes a pcm_runtime from the ASoC card.
 */
void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
				struct snd_soc_pcm_runtime *rtd)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link
 * @card: The ASoC card to which the pcm_runtime is added
 * @dai_link: The DAI link to find pcm_runtime
 *
 * This function adds a pcm_runtime ASoC card by using dai_link.
 *
 * Note: Topology can use this API to add pcm_runtime when probing the
 * topology component. And machine drivers can still define static
 * DAI links in dai_link array.
 */
static int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
				   struct snd_soc_dai_link *dai_link)
{}

int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
			     struct snd_soc_dai_link *dai_link,
			     int num_dai_link)
{}
EXPORT_SYMBOL_GPL();

static void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd)
{}

/**
 * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
 * @rtd: The runtime for which the DAI link format should be changed
 * @dai_fmt: The new DAI link format
 *
 * This function updates the DAI link format for all DAIs connected to the DAI
 * link for the specified runtime.
 *
 * Note: For setups with a static format set the dai_fmt field in the
 * corresponding snd_dai_link struct instead of using this function.
 *
 * Returns 0 on success, otherwise a negative error code.
 */
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
				unsigned int dai_fmt)
{}
EXPORT_SYMBOL_GPL();

static int soc_init_pcm_runtime(struct snd_soc_card *card,
				struct snd_soc_pcm_runtime *rtd)
{}

static void soc_set_name_prefix(struct snd_soc_card *card,
				struct snd_soc_component *component)
{}

static void soc_remove_component(struct snd_soc_component *component,
				 int probed)
{}

static int soc_probe_component(struct snd_soc_card *card,
			       struct snd_soc_component *component)
{}

static void soc_remove_link_dais(struct snd_soc_card *card)
{}

static int soc_probe_link_dais(struct snd_soc_card *card)
{}

static void soc_remove_link_components(struct snd_soc_card *card)
{}

static int soc_probe_link_components(struct snd_soc_card *card)
{}

static void soc_unbind_aux_dev(struct snd_soc_card *card)
{}

static int soc_bind_aux_dev(struct snd_soc_card *card)
{}

static int soc_probe_aux_devices(struct snd_soc_card *card)
{}

static void soc_remove_aux_devices(struct snd_soc_card *card)
{}

#ifdef CONFIG_DMI
/*
 * If a DMI filed contain strings in this blacklist (e.g.
 * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken
 * as invalid and dropped when setting the card long name from DMI info.
 */
static const char * const dmi_blacklist[] =;

/*
 * Trim special characters, and replace '-' with '_' since '-' is used to
 * separate different DMI fields in the card long name. Only number and
 * alphabet characters and a few separator characters are kept.
 */
static void cleanup_dmi_name(char *name)
{}

/*
 * Check if a DMI field is valid, i.e. not containing any string
 * in the black list.
 */
static int is_dmi_valid(const char *field)
{}

/*
 * Append a string to card->dmi_longname with character cleanups.
 */
static void append_dmi_string(struct snd_soc_card *card, const char *str)
{}

/**
 * snd_soc_set_dmi_name() - Register DMI names to card
 * @card: The card to register DMI names
 * @flavour: The flavour "differentiator" for the card amongst its peers.
 *
 * An Intel machine driver may be used by many different devices but are
 * difficult for userspace to differentiate, since machine drivers usually
 * use their own name as the card short name and leave the card long name
 * blank. To differentiate such devices and fix bugs due to lack of
 * device-specific configurations, this function allows DMI info to be used
 * as the sound card long name, in the format of
 * "vendor-product-version-board"
 * (Character '-' is used to separate different DMI fields here).
 * This will help the user space to load the device-specific Use Case Manager
 * (UCM) configurations for the card.
 *
 * Possible card long names may be:
 * DellInc.-XPS139343-01-0310JH
 * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
 * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
 *
 * This function also supports flavoring the card longname to provide
 * the extra differentiation, like "vendor-product-version-board-flavor".
 *
 * We only keep number and alphabet characters and a few separator characters
 * in the card long name since UCM in the user space uses the card long names
 * as card configuration directory names and AudoConf cannot support special
 * characters like SPACE.
 *
 * Returns 0 on success, otherwise a negative error code.
 */
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
{}
EXPORT_SYMBOL_GPL();
#endif /* CONFIG_DMI */

static void soc_check_tplg_fes(struct snd_soc_card *card)
{}

#define soc_setup_card_name(card, name, name1, name2)
static void __soc_setup_card_name(struct snd_soc_card *card,
				  char *name, int len,
				  const char *name1, const char *name2)
{}

static void soc_cleanup_card_resources(struct snd_soc_card *card)
{}

static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
{}

static int snd_soc_bind_card(struct snd_soc_card *card)
{}

/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{}

int snd_soc_poweroff(struct device *dev)
{}
EXPORT_SYMBOL_GPL();

const struct dev_pm_ops snd_soc_pm_ops =;
EXPORT_SYMBOL_GPL();

/* ASoC platform driver */
static struct platform_driver soc_driver =;

/**
 * snd_soc_cnew - create new control
 * @_template: control template
 * @data: control private data
 * @long_name: control long name
 * @prefix: control name prefix
 *
 * Create a new mixer control from a template control.
 *
 * Returns 0 for success, else error.
 */
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
				  void *data, const char *long_name,
				  const char *prefix)
{}
EXPORT_SYMBOL_GPL();

static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
	const struct snd_kcontrol_new *controls, int num_controls,
	const char *prefix, void *data)
{}

/**
 * snd_soc_add_component_controls - Add an array of controls to a component.
 *
 * @component: Component to add controls to
 * @controls: Array of controls to add
 * @num_controls: Number of elements in the array
 *
 * Return: 0 for success, else error.
 */
int snd_soc_add_component_controls(struct snd_soc_component *component,
	const struct snd_kcontrol_new *controls, unsigned int num_controls)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_add_card_controls - add an array of controls to a SoC card.
 * Convenience function to add a list of controls.
 *
 * @soc_card: SoC card to add controls to
 * @controls: array of controls to add
 * @num_controls: number of elements in the array
 *
 * Return 0 for success, else error.
 */
int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
	const struct snd_kcontrol_new *controls, int num_controls)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_add_dai_controls - add an array of controls to a DAI.
 * Convenience function to add a list of controls.
 *
 * @dai: DAI to add controls to
 * @controls: array of controls to add
 * @num_controls: number of elements in the array
 *
 * Return 0 for success, else error.
 */
int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
	const struct snd_kcontrol_new *controls, int num_controls)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_register_card - Register a card with the ASoC core
 *
 * @card: Card to register
 *
 */
int snd_soc_register_card(struct snd_soc_card *card)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_unregister_card - Unregister a card with the ASoC core
 *
 * @card: Card to unregister
 *
 */
void snd_soc_unregister_card(struct snd_soc_card *card)
{}
EXPORT_SYMBOL_GPL();

/*
 * Simplify DAI link configuration by removing ".-1" from device names
 * and sanitizing names.
 */
static char *fmt_single_name(struct device *dev, int *id)
{}

/*
 * Simplify DAI link naming for single devices with multiple DAIs by removing
 * any ".-1" and using the DAI name (instead of device name).
 */
static inline char *fmt_multiple_name(struct device *dev,
		struct snd_soc_dai_driver *dai_drv)
{}

void snd_soc_unregister_dai(struct snd_soc_dai *dai)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_register_dai - Register a DAI dynamically & create its widgets
 *
 * @component: The component the DAIs are registered for
 * @dai_drv: DAI driver to use for the DAI
 * @legacy_dai_naming: if %true, use legacy single-name format;
 * 	if %false, use multiple-name format;
 *
 * Topology can use this API to register DAIs when probing a component.
 * These DAIs's widgets will be freed in the card cleanup and the DAIs
 * will be freed in the component cleanup.
 */
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
					 struct snd_soc_dai_driver *dai_drv,
					 bool legacy_dai_naming)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_unregister_dais - Unregister DAIs from the ASoC core
 *
 * @component: The component for which the DAIs should be unregistered
 */
static void snd_soc_unregister_dais(struct snd_soc_component *component)
{}

/**
 * snd_soc_register_dais - Register a DAI with the ASoC core
 *
 * @component: The component the DAIs are registered for
 * @dai_drv: DAI driver to use for the DAIs
 * @count: Number of DAIs
 */
static int snd_soc_register_dais(struct snd_soc_component *component,
				 struct snd_soc_dai_driver *dai_drv,
				 size_t count)
{}

#define ENDIANNESS_MAP(name)
static u64 endianness_format_map[] =;

/*
 * Fix up the DAI formats for endianness: codecs don't actually see
 * the endianness of the data but we're using the CPU format
 * definitions which do need to include endianness so we ensure that
 * codec DAIs always have both big and little endian variants set.
 */
static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
{}

static void snd_soc_try_rebind_card(void)
{}

static void snd_soc_del_component_unlocked(struct snd_soc_component *component)
{}

int snd_soc_component_initialize(struct snd_soc_component *component,
				 const struct snd_soc_component_driver *driver,
				 struct device *dev)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_add_component(struct snd_soc_component *component,
			  struct snd_soc_dai_driver *dai_drv,
			  int num_dai)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_register_component(struct device *dev,
			const struct snd_soc_component_driver *component_driver,
			struct snd_soc_dai_driver *dai_drv,
			int num_dai)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_unregister_component_by_driver - Unregister component using a given driver
 * from the ASoC core
 *
 * @dev: The device to unregister
 * @component_driver: The component driver to unregister
 */
void snd_soc_unregister_component_by_driver(struct device *dev,
					    const struct snd_soc_component_driver *component_driver)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_soc_unregister_component - Unregister all related component
 * from the ASoC core
 *
 * @dev: The device to unregister
 */
void snd_soc_unregister_component(struct device *dev)
{}
EXPORT_SYMBOL_GPL();

/* Retrieve a card's name from device tree */
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
			       const char *propname)
{}
EXPORT_SYMBOL_GPL();

static const struct snd_soc_dapm_widget simple_widgets[] =;

int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
					  const char *propname)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_get_slot_mask(struct device_node *np,
			     const char *prop_name,
			     unsigned int *mask)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_parse_tdm_slot(struct device_node *np,
			      unsigned int *tx_mask,
			      unsigned int *rx_mask,
			      unsigned int *slots,
			      unsigned int *slot_width)
{}
EXPORT_SYMBOL_GPL();

void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
				     struct snd_soc_dai_link_component *cpus)
{}
EXPORT_SYMBOL_GPL();

void snd_soc_of_parse_node_prefix(struct device_node *np,
				  struct snd_soc_codec_conf *codec_conf,
				  struct device_node *of_node,
				  const char *propname)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
				   const char *propname)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname)
{}
EXPORT_SYMBOL_GPL();

unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt)
{}
EXPORT_SYMBOL_GPL();

unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame)
{}
EXPORT_SYMBOL_GPL();

unsigned int snd_soc_daifmt_parse_format(struct device_node *np,
					 const char *prefix)
{}
EXPORT_SYMBOL_GPL();

unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
						     const char *prefix,
						     struct device_node **bitclkmaster,
						     struct device_node **framemaster)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_get_dai_id(struct device_node *ep)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_component *dlc)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_get_dlc(struct device_node *of_node,
		       struct of_phandle_args *args,
		       struct snd_soc_dai_link_component *dlc,
		       int index)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_get_dai_name(const struct of_phandle_args *args,
			 const char **dai_name)
{}
EXPORT_SYMBOL_GPL();

int snd_soc_of_get_dai_name(struct device_node *of_node,
			    const char **dai_name, int index)
{}
EXPORT_SYMBOL_GPL();

struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_args)
{}
EXPORT_SYMBOL_GPL();

static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
{}

static int __snd_soc_of_get_dai_link_component_alloc(
	struct device *dev, struct device_node *of_node,
	struct snd_soc_dai_link_component **ret_component,
	int *ret_num)
{}

/*
 * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
 * @dai_link: DAI link
 *
 * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
 */
void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
{}
EXPORT_SYMBOL_GPL();

/*
 * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
 * @dev: Card device
 * @of_node: Device node
 * @dai_link: DAI link
 *
 * Builds an array of CODEC DAI components from the DAI link property
 * 'sound-dai'.
 * The array is set in the DAI link and the number of DAIs is set accordingly.
 * The device nodes in the array (of_node) must be dereferenced by calling
 * snd_soc_of_put_dai_link_codecs() on @dai_link.
 *
 * Returns 0 for success
 */
int snd_soc_of_get_dai_link_codecs(struct device *dev,
				   struct device_node *of_node,
				   struct snd_soc_dai_link *dai_link)
{}
EXPORT_SYMBOL_GPL();

/*
 * snd_soc_of_put_dai_link_cpus - Dereference device nodes in the codecs array
 * @dai_link: DAI link
 *
 * Dereference device nodes acquired by snd_soc_of_get_dai_link_cpus().
 */
void snd_soc_of_put_dai_link_cpus(struct snd_soc_dai_link *dai_link)
{}
EXPORT_SYMBOL_GPL();

/*
 * snd_soc_of_get_dai_link_cpus - Parse a list of CPU DAIs in the devicetree
 * @dev: Card device
 * @of_node: Device node
 * @dai_link: DAI link
 *
 * Is analogous to snd_soc_of_get_dai_link_codecs but parses a list of CPU DAIs
 * instead.
 *
 * Returns 0 for success
 */
int snd_soc_of_get_dai_link_cpus(struct device *dev,
				 struct device_node *of_node,
				 struct snd_soc_dai_link *dai_link)
{}
EXPORT_SYMBOL_GPL();

static int __init snd_soc_init(void)
{}
module_init();

static void __exit snd_soc_exit(void)
{}
module_exit(snd_soc_exit);

/* Module information */
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS();