}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
++++static const struct snd_soc_ops null_snd_soc_ops;
++++
static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
INIT_LIST_HEAD(&rtd->component_list);
rtd->card = card;
rtd->dai_link = dai_link;
++++ if (!rtd->dai_link->ops)
++++ rtd->dai_link->ops = &null_snd_soc_ops;
++++
rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
dai_link->num_codecs,
GFP_KERNEL);
static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
{
---- if (rtd && rtd->codec_dais)
---- kfree(rtd->codec_dais);
++++ kfree(rtd->codec_dais);
snd_soc_rtdcom_del_all(rtd);
kfree(rtd);
}
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
---- if (dai->driver && dai->driver->ops->set_sysclk)
++++ if (dai->driver->ops->set_sysclk)
return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
---- if (dai->driver && dai->driver->ops->set_clkdiv)
++++ if (dai->driver->ops->set_clkdiv)
return dai->driver->ops->set_clkdiv(dai, div_id, div);
else
return -EINVAL;
int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
---- if (dai->driver && dai->driver->ops->set_pll)
++++ if (dai->driver->ops->set_pll)
return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
*/
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
{
---- if (dai->driver && dai->driver->ops->set_bclk_ratio)
++++ if (dai->driver->ops->set_bclk_ratio)
return dai->driver->ops->set_bclk_ratio(dai, ratio);
else
return -EINVAL;
/**
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
* @dai: DAI
---- * @fmt: SND_SOC_DAIFMT_ format value.
++++ * @fmt: SND_SOC_DAIFMT_* format value.
*
* Configures the DAI hardware format and clocking.
*/
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
---- if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask)
++++ if (dai->driver->ops->xlate_tdm_slot_mask)
dai->driver->ops->xlate_tdm_slot_mask(slots,
&tx_mask, &rx_mask);
else
dai->tx_mask = tx_mask;
dai->rx_mask = rx_mask;
---- if (dai->driver && dai->driver->ops->set_tdm_slot)
++++ if (dai->driver->ops->set_tdm_slot)
return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
---- if (dai->driver && dai->driver->ops->set_channel_map)
++++ if (dai->driver->ops->set_channel_map)
return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
rx_num, rx_slot);
else
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
---- if (dai->driver && dai->driver->ops->set_tristate)
++++ if (dai->driver->ops->set_tristate)
return dai->driver->ops->set_tristate(dai, tristate);
else
return -EINVAL;
return component->driver->stream_event(component, event);
}
++++static int snd_soc_component_drv_pcm_new(struct snd_soc_component *component,
++++ struct snd_soc_pcm_runtime *rtd)
++++{
++++ if (component->driver->pcm_new)
++++ return component->driver->pcm_new(rtd);
++++
++++ return 0;
++++}
++++
++++static void snd_soc_component_drv_pcm_free(struct snd_soc_component *component,
++++ struct snd_pcm *pcm)
++++{
++++ if (component->driver->pcm_free)
++++ component->driver->pcm_free(pcm);
++++}
++++
++++static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm,
++++ enum snd_soc_bias_level level)
++++{
++++ struct snd_soc_component *component = dapm->component;
++++
++++ return component->driver->set_bias_level(component, level);
++++}
++++
static int snd_soc_component_initialize(struct snd_soc_component *component,
const struct snd_soc_component_driver *driver, struct device *dev)
{
component->set_sysclk = component->driver->set_sysclk;
component->set_pll = component->driver->set_pll;
component->set_jack = component->driver->set_jack;
++++ component->pcm_new = snd_soc_component_drv_pcm_new;
++++ component->pcm_free = snd_soc_component_drv_pcm_free;
dapm = snd_soc_component_get_dapm(component);
dapm->dev = dev;
dapm->component = component;
dapm->bias_level = SND_SOC_BIAS_OFF;
---- dapm->idle_bias_off = true;
++++ dapm->idle_bias_off = !driver->idle_bias_on;
++++ dapm->suspend_bias_off = driver->suspend_bias_off;
if (driver->seq_notifier)
dapm->seq_notifier = snd_soc_component_seq_notifier;
if (driver->stream_event)
dapm->stream_event = snd_soc_component_stream_event;
++++ if (driver->set_bias_level)
++++ dapm->set_bias_level = snd_soc_component_set_bias_level;
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
list_del(&component->list);
}
----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)
++++#define ENDIANNESS_MAP(name) \
++++ (SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
++++static u64 endianness_format_map[] = {
++++ ENDIANNESS_MAP(S16_),
++++ ENDIANNESS_MAP(U16_),
++++ ENDIANNESS_MAP(S24_),
++++ ENDIANNESS_MAP(U24_),
++++ ENDIANNESS_MAP(S32_),
++++ ENDIANNESS_MAP(U32_),
++++ ENDIANNESS_MAP(S24_3),
++++ ENDIANNESS_MAP(U24_3),
++++ ENDIANNESS_MAP(S20_3),
++++ ENDIANNESS_MAP(U20_3),
++++ ENDIANNESS_MAP(S18_3),
++++ ENDIANNESS_MAP(U18_3),
++++ ENDIANNESS_MAP(FLOAT_),
++++ ENDIANNESS_MAP(FLOAT64_),
++++ ENDIANNESS_MAP(IEC958_SUBFRAME_),
++++};
++++
++++/*
++++ * 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)
{
---- struct snd_soc_component *component;
---- int ret;
++++ int i;
---- component = kzalloc(sizeof(*component), GFP_KERNEL);
---- if (!component) {
---- dev_err(dev, "ASoC: Failed to allocate memory\n");
---- return -ENOMEM;
---- }
++++ for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
++++ if (stream->formats & endianness_format_map[i])
++++ stream->formats |= endianness_format_map[i];
++++}
++++
++++int snd_soc_add_component(struct device *dev,
++++ struct snd_soc_component *component,
++++ const struct snd_soc_component_driver *component_driver,
++++ struct snd_soc_dai_driver *dai_drv,
++++ int num_dai)
++++{
++++ int ret;
++++ int i;
ret = snd_soc_component_initialize(component, component_driver, dev);
if (ret)
component->ignore_pmdown_time = true;
component->registered_as_component = true;
---- ret = snd_soc_register_dais(component, dai_drv, num_dai, true);
++++ if (component_driver->endianness) {
++++ for (i = 0; i < num_dai; i++) {
++++ convert_endianness_formats(&dai_drv[i].playback);
++++ convert_endianness_formats(&dai_drv[i].capture);
++++ }
++++ }
++++
++++ ret = snd_soc_register_dais(component, dai_drv, num_dai,
++++ !component_driver->non_legacy_dai_naming);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
goto err_cleanup;
kfree(component);
return ret;
}
++++EXPORT_SYMBOL_GPL(snd_soc_add_component);
++++
++++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)
++++{
++++ struct snd_soc_component *component;
++++
++++ component = kzalloc(sizeof(*component), GFP_KERNEL);
++++ if (!component)
++++ return -ENOMEM;
++++
++++ return snd_soc_add_component(dev, component, component_driver,
++++ dai_drv, num_dai);
++++}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
++++struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
++++ const char *driver_name)
++++{
++++ struct snd_soc_component *component;
++++ struct snd_soc_component *ret;
++++
++++ ret = NULL;
++++ mutex_lock(&client_mutex);
++++ list_for_each_entry(component, &component_list, list) {
++++ if (dev != component->dev)
++++ continue;
++++
++++ if (driver_name &&
++++ (driver_name != component->driver->name) &&
++++ (strcmp(component->driver->name, driver_name) != 0))
++++ continue;
++++
++++ ret = component;
++++ break;
++++ }
++++ mutex_unlock(&client_mutex);
++++
++++ return ret;
++++}
++++EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
++++
static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
platform->driver->remove(platform);
}
++++static int snd_soc_platform_drv_pcm_new(struct snd_soc_component *component,
++++ struct snd_soc_pcm_runtime *rtd)
++++{
++++ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
++++
++++ if (platform->driver->pcm_new)
++++ return platform->driver->pcm_new(rtd);
++++
++++ return 0;
++++}
++++
++++static void snd_soc_platform_drv_pcm_free(struct snd_soc_component *component,
++++ struct snd_pcm *pcm)
++++{
++++ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
++++
++++ if (platform->driver->pcm_free)
++++ platform->driver->pcm_free(pcm);
++++}
++++
/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
platform->component.probe = snd_soc_platform_drv_probe;
if (platform_drv->remove)
platform->component.remove = snd_soc_platform_drv_remove;
++++ if (platform_drv->pcm_new)
++++ platform->component.pcm_new = snd_soc_platform_drv_pcm_new;
++++ if (platform_drv->pcm_free)
++++ platform->component.pcm_free = snd_soc_platform_drv_pcm_free;
#ifdef CONFIG_DEBUG_FS
platform->component.debugfs_prefix = "platform";
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
----static u64 codec_format_map[] = {
---- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
---- SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE,
---- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE,
---- SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
---- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
---- SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE,
---- SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
---- SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
---- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE,
---- SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE,
---- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE,
---- SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE,
---- SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE,
---- SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE,
---- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
---- | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
----};
----
----/* 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 fixup_codec_formats(struct snd_soc_pcm_stream *stream)
----{
---- int i;
----
---- for (i = 0; i < ARRAY_SIZE(codec_format_map); i++)
---- if (stream->formats & codec_format_map[i])
---- stream->formats |= codec_format_map[i];
----}
----
static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
codec->component.regmap = codec_drv->get_regmap(dev);
for (i = 0; i < num_dai; i++) {
---- fixup_codec_formats(&dai_drv[i].playback);
---- fixup_codec_formats(&dai_drv[i].capture);
++++ convert_endianness_formats(&dai_drv[i].playback);
++++ convert_endianness_formats(&dai_drv[i].capture);
}
ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);