|  | // SPDX-License-Identifier: GPL-2.0+ | 
|  | // | 
|  | // soc-devres.c  --  ALSA SoC Audio Layer devres functions | 
|  | // | 
|  | // Copyright (C) 2013 Linaro Ltd | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/moduleparam.h> | 
|  | #include <sound/soc.h> | 
|  | #include <sound/dmaengine_pcm.h> | 
|  |  | 
|  | static void devm_component_release(struct device *dev, void *res) | 
|  | { | 
|  | snd_soc_unregister_component(*(struct device **)res); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * devm_snd_soc_register_component - resource managed component registration | 
|  | * @dev: Device used to manage component | 
|  | * @cmpnt_drv: Component driver | 
|  | * @dai_drv: DAI driver | 
|  | * @num_dai: Number of DAIs to register | 
|  | * | 
|  | * Register a component with automatic unregistration when the device is | 
|  | * unregistered. | 
|  | */ | 
|  | int devm_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) | 
|  | { | 
|  | struct device **ptr; | 
|  | int ret; | 
|  |  | 
|  | ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL); | 
|  | if (!ptr) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai); | 
|  | if (ret == 0) { | 
|  | *ptr = dev; | 
|  | devres_add(dev, ptr); | 
|  | } else { | 
|  | devres_free(ptr); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); | 
|  |  | 
|  | static void devm_card_release(struct device *dev, void *res) | 
|  | { | 
|  | snd_soc_unregister_card(*(struct snd_soc_card **)res); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * devm_snd_soc_register_card - resource managed card registration | 
|  | * @dev: Device used to manage card | 
|  | * @card: Card to register | 
|  | * | 
|  | * Register a card with automatic unregistration when the device is | 
|  | * unregistered. | 
|  | */ | 
|  | int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) | 
|  | { | 
|  | struct snd_soc_card **ptr; | 
|  | int ret; | 
|  |  | 
|  | ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); | 
|  | if (!ptr) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ret = snd_soc_register_card(card); | 
|  | if (ret == 0) { | 
|  | *ptr = card; | 
|  | devres_add(dev, ptr); | 
|  | } else { | 
|  | devres_free(ptr); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); | 
|  |  | 
|  | #ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM | 
|  |  | 
|  | static void devm_dmaengine_pcm_release(struct device *dev, void *res) | 
|  | { | 
|  | snd_dmaengine_pcm_unregister(*(struct device **)res); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration | 
|  | * @dev: The parent device for the PCM device | 
|  | * @config: Platform specific PCM configuration | 
|  | * @flags: Platform specific quirks | 
|  | * | 
|  | * Register a dmaengine based PCM device with automatic unregistration when the | 
|  | * device is unregistered. | 
|  | */ | 
|  | int devm_snd_dmaengine_pcm_register(struct device *dev, | 
|  | const struct snd_dmaengine_pcm_config *config, unsigned int flags) | 
|  | { | 
|  | struct device **ptr; | 
|  | int ret; | 
|  |  | 
|  | ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL); | 
|  | if (!ptr) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ret = snd_dmaengine_pcm_register(dev, config, flags); | 
|  | if (ret == 0) { | 
|  | *ptr = dev; | 
|  | devres_add(dev, ptr); | 
|  | } else { | 
|  | devres_free(ptr); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register); | 
|  |  | 
|  | #endif |