diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 530 |
1 files changed, 373 insertions, 157 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 921622a01944..c0edac80df34 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -339,11 +339,12 @@ static void soc_cleanup_component_debugfs(struct snd_soc_component *component) static void soc_init_codec_debugfs(struct snd_soc_component *component) { struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + struct dentry *debugfs_reg; - codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->component.debugfs_root, - codec, &codec_reg_fops); - if (!codec->debugfs_reg) + debugfs_reg = debugfs_create_file("codec_reg", 0644, + codec->component.debugfs_root, + codec, &codec_reg_fops); + if (!debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); } @@ -494,7 +495,7 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) static void snd_soc_debugfs_init(void) { snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) { + if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) { pr_warn("ASoC: Failed to create debugfs directory\n"); snd_soc_debugfs_root = NULL; return; @@ -550,6 +551,54 @@ static inline void snd_soc_debugfs_exit(void) #endif +static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_component *component) +{ + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_rtdcom_list *new_rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + /* already connected */ + if (rtdcom->component == component) + return 0; + } + + new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL); + if (!new_rtdcom) + return -ENOMEM; + + new_rtdcom->component = component; + INIT_LIST_HEAD(&new_rtdcom->list); + + list_add_tail(&new_rtdcom->list, &rtd->component_list); + + return 0; +} + +static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2; + + for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) + kfree(rtdcom1); + + INIT_LIST_HEAD(&rtd->component_list); +} + +struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, + const char *driver_name) +{ + struct snd_soc_rtdcom_list *rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + if ((rtdcom->component->driver->name == driver_name) || + strcmp(rtdcom->component->driver->name, driver_name) == 0) + return rtdcom->component; + } + + return NULL; +} + struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) { @@ -565,6 +614,8 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, } 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) { @@ -574,8 +625,12 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( if (!rtd) return NULL; + 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); @@ -589,8 +644,8 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( 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); } @@ -653,9 +708,7 @@ int snd_soc_suspend(struct device *dev) /* Due to the resume being scheduled into a workqueue we could * suspend before that's finished - wait for it to complete. */ - snd_power_lock(card->snd_card); snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); - snd_power_unlock(card->snd_card); /* we're going to block userspace touching us until resume completes */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); @@ -949,7 +1002,7 @@ static struct snd_soc_component *soc_find_component( /** * snd_soc_find_dai - Find a registered DAI * - * @dlc: name of the DAI and optional component info to match + * @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 @@ -977,7 +1030,9 @@ struct snd_soc_dai *snd_soc_find_dai( if (dlc->name && strcmp(component->name, dlc->name)) continue; list_for_each_entry(dai, &component->dai_list, list) { - if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) + && (!dai->driver->name + || strcmp(dai->driver->name, dlc->dai_name))) continue; return dai; @@ -1049,6 +1104,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; + struct snd_soc_component *component; struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; struct device_node *platform_of_node; @@ -1076,6 +1132,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, dai_link->cpu_dai_name); goto _err_defer; } + snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); rtd->num_codecs = dai_link->num_codecs; @@ -1088,6 +1145,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, codecs[i].dai_name); goto _err_defer; } + snd_soc_rtdcom_add(rtd, codec_dais[i]->component); } /* Single codec links expect codec and codec_dai in runtime data */ @@ -1100,6 +1158,23 @@ static int soc_bind_dai_link(struct snd_soc_card *card, platform_name = "snd-soc-dummy"; /* find one from the set of registered platforms */ + list_for_each_entry(component, &component_list, list) { + platform_of_node = component->dev->of_node; + if (!platform_of_node && component->dev->parent->of_node) + platform_of_node = component->dev->parent->of_node; + + if (dai_link->platform_of_node) { + if (platform_of_node != dai_link->platform_of_node) + continue; + } else { + if (strcmp(component->name, platform_name)) + continue; + } + + snd_soc_rtdcom_add(rtd, component); + } + + /* find one from the set of registered platforms */ list_for_each_entry(platform, &platform_list, list) { platform_of_node = platform->dev->of_node; if (!platform_of_node && platform->dev->parent->of_node) @@ -1184,27 +1259,15 @@ static void soc_remove_link_dais(struct snd_soc_card *card, static void soc_remove_link_components(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; - int i; + struct snd_soc_rtdcom_list *rtdcom; - /* remove the platform */ - if (platform && platform->component.driver->remove_order == order) - soc_remove_component(&platform->component); + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; - /* remove the CODEC-side CODEC */ - for (i = 0; i < rtd->num_codecs; i++) { - component = rtd->codec_dais[i]->component; if (component->driver->remove_order == order) soc_remove_component(component); } - - /* remove any CPU-side CODEC */ - if (cpu_dai) { - if (cpu_dai->component->driver->remove_order == order) - soc_remove_component(cpu_dai->component); - } } static void soc_remove_dai_links(struct snd_soc_card *card) @@ -1451,9 +1514,10 @@ static int soc_probe_component(struct snd_soc_card *card, soc_init_component_debugfs(component); - if (component->dapm_widgets) { - ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, - component->num_dapm_widgets); + if (component->driver->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, + component->driver->dapm_widgets, + component->driver->num_dapm_widgets); if (ret != 0) { dev_err(component->dev, @@ -1495,12 +1559,14 @@ static int soc_probe_component(struct snd_soc_card *card, } } - if (component->controls) - snd_soc_add_component_controls(component, component->controls, - component->num_controls); - if (component->dapm_routes) - snd_soc_dapm_add_routes(dapm, component->dapm_routes, - component->num_dapm_routes); + if (component->driver->controls) + snd_soc_add_component_controls(component, + component->driver->controls, + component->driver->num_controls); + if (component->driver->dapm_routes) + snd_soc_dapm_add_routes(dapm, + component->driver->dapm_routes, + component->driver->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); list_add(&component->card_list, &card->component_dev_list); @@ -1556,21 +1622,13 @@ static int soc_probe_link_components(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; - int i, ret; + struct snd_soc_rtdcom_list *rtdcom; + int ret; - /* probe the CPU-side component, if it is a CODEC */ - component = rtd->cpu_dai->component; - if (component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; - } + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; - /* probe the CODEC-side components */ - for (i = 0; i < rtd->num_codecs; i++) { - component = rtd->codec_dais[i]->component; if (component->driver->probe_order == order) { ret = soc_probe_component(card, component); if (ret < 0) @@ -1578,13 +1636,6 @@ static int soc_probe_link_components(struct snd_soc_card *card, } } - /* probe the platform */ - if (platform->component.driver->probe_order == order) { - ret = soc_probe_component(card, &platform->component); - if (ret < 0) - return ret; - } - return 0; } @@ -2585,13 +2636,11 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); 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); - else if (dai->codec && dai->codec->driver->set_sysclk) - return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0, - freq, dir); - else - return -ENOTSUPP; + + return snd_soc_component_set_sysclk(dai->component, clk_id, 0, + freq, dir); } EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); @@ -2617,6 +2666,32 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk); /** + * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. + * @component: COMPONENT + * @clk_id: DAI specific clock ID + * @source: Source for the clock + * @freq: new clock frequency in Hz + * @dir: new clock direction - input/output. + * + * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. + */ +int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id, + int source, unsigned int freq, int dir) +{ + /* will be removed */ + if (component->set_sysclk) + return component->set_sysclk(component, clk_id, source, + freq, dir); + + if (component->driver->set_sysclk) + return component->driver->set_sysclk(component, clk_id, source, + freq, dir); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); + +/** * snd_soc_dai_set_clkdiv - configure DAI clock dividers. * @dai: DAI * @div_id: DAI specific clock divider ID @@ -2629,7 +2704,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk); 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; @@ -2649,14 +2724,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); 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); - else if (dai->codec && dai->codec->driver->set_pll) - return dai->codec->driver->set_pll(dai->codec, pll_id, source, - freq_in, freq_out); - else - return -EINVAL; + + return snd_soc_component_set_pll(dai->component, pll_id, source, + freq_in, freq_out); } EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); @@ -2681,6 +2754,33 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, } EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); +/* + * snd_soc_component_set_pll - configure component PLL. + * @component: COMPONENT + * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL + * @freq_in: PLL input clock frequency in Hz + * @freq_out: requested PLL output clock frequency in Hz + * + * Configures and enables PLL to generate output clock based on input clock. + */ +int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) +{ + /* will be removed */ + if (component->set_pll) + return component->set_pll(component, pll_id, source, + freq_in, freq_out); + + if (component->driver->set_pll) + return component->driver->set_pll(component, pll_id, source, + freq_in, freq_out); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); + /** * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. * @dai: DAI @@ -2690,7 +2790,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); */ 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; @@ -2700,7 +2800,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); /** * 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. */ @@ -2764,7 +2864,7 @@ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, 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 @@ -2773,7 +2873,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, 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 @@ -2797,7 +2897,7 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, 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 @@ -2814,7 +2914,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); */ 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; @@ -3154,6 +3254,30 @@ static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, 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) { @@ -3171,25 +3295,24 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->remove = component->driver->remove; component->suspend = component->driver->suspend; component->resume = component->driver->resume; - component->pcm_new = component->driver->pcm_new; - component->pcm_free = component->driver->pcm_free; + 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 = &component->dapm; + 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; - - component->controls = driver->controls; - component->num_controls = driver->num_controls; - component->dapm_widgets = driver->dapm_widgets; - component->num_dapm_widgets = driver->num_dapm_widgets; - component->dapm_routes = driver->dapm_routes; - component->num_dapm_routes = driver->num_dapm_routes; + 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); @@ -3281,71 +3404,163 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component) list_del(&component->list); } -int snd_soc_register_component(struct device *dev, - const struct snd_soc_component_driver *cmpnt_drv, - 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 *cmpnt; - int ret; + int i; - cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL); - if (!cmpnt) { - 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(cmpnt, cmpnt_drv, dev); + ret = snd_soc_component_initialize(component, component_driver, dev); if (ret) goto err_free; - cmpnt->ignore_pmdown_time = true; - cmpnt->registered_as_component = true; + component->ignore_pmdown_time = true; + component->registered_as_component = 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(cmpnt, dai_drv, num_dai, true); + 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; } - snd_soc_component_add(cmpnt); + snd_soc_component_add(component); return 0; err_cleanup: - snd_soc_component_cleanup(cmpnt); + snd_soc_component_cleanup(component); err_free: - kfree(cmpnt); + 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); /** - * snd_soc_unregister_component - Unregister a component from the ASoC core + * 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) +static int __snd_soc_unregister_component(struct device *dev) { - struct snd_soc_component *cmpnt; + struct snd_soc_component *component; + int found = 0; mutex_lock(&client_mutex); - list_for_each_entry(cmpnt, &component_list, list) { - if (dev == cmpnt->dev && cmpnt->registered_as_component) - goto found; + list_for_each_entry(component, &component_list, list) { + if (dev != component->dev || + !component->registered_as_component) + continue; + + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + snd_soc_component_del_unlocked(component); + found = 1; + break; } mutex_unlock(&client_mutex); - return; -found: - snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL); - snd_soc_component_del_unlocked(cmpnt); - mutex_unlock(&client_mutex); - snd_soc_component_cleanup(cmpnt); - kfree(cmpnt); + if (found) { + snd_soc_component_cleanup(component); + kfree(component); + } + + return found; +} + +void snd_soc_unregister_component(struct device *dev) +{ + while (__snd_soc_unregister_component(dev)); } 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); @@ -3360,20 +3575,21 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) platform->driver->remove(platform); } -static int snd_soc_platform_drv_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int snd_soc_platform_drv_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); if (platform->driver->pcm_new) return platform->driver->pcm_new(rtd); - else - return 0; + + return 0; } -static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm) +static void snd_soc_platform_drv_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); if (platform->driver->pcm_free) platform->driver->pcm_free(pcm); @@ -3503,39 +3719,6 @@ void snd_soc_unregister_platform(struct device *dev) } 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); @@ -3582,6 +3765,31 @@ static int snd_soc_codec_drv_read(struct snd_soc_component *component, return 0; } +static int snd_soc_codec_set_sysclk_(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return snd_soc_codec_set_sysclk(codec, clk_id, source, freq, dir); +} + +static int snd_soc_codec_set_pll_(struct snd_soc_component *component, + int pll_id, int source, unsigned int freq_in, + unsigned int freq_out) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return snd_soc_codec_set_pll(codec, pll_id, source, freq_in, freq_out); +} + +static int snd_soc_codec_set_jack_(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return snd_soc_codec_set_jack(codec, jack, data); +} + static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { @@ -3633,6 +3841,12 @@ int snd_soc_register_codec(struct device *dev, codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; + if (codec_drv->set_sysclk) + codec->component.set_sysclk = snd_soc_codec_set_sysclk_; + if (codec_drv->set_pll) + codec->component.set_pll = snd_soc_codec_set_pll_; + if (codec_drv->set_jack) + codec->component.set_jack = snd_soc_codec_set_jack_; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; dapm = snd_soc_codec_get_dapm(codec); @@ -3655,8 +3869,8 @@ int snd_soc_register_codec(struct device *dev, 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); @@ -4113,6 +4327,8 @@ int snd_soc_get_dai_id(struct device_node *ep) } mutex_unlock(&client_mutex); + of_node_put(node); + return ret; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); |