1873486edSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+ 2873486edSKuninori Morimoto // 3873486edSKuninori Morimoto // soc-core.c -- ALSA SoC Audio Layer 4873486edSKuninori Morimoto // 5873486edSKuninori Morimoto // Copyright 2005 Wolfson Microelectronics PLC. 6873486edSKuninori Morimoto // Copyright 2005 Openedhand Ltd. 7873486edSKuninori Morimoto // Copyright (C) 2010 Slimlogic Ltd. 8873486edSKuninori Morimoto // Copyright (C) 2010 Texas Instruments Inc. 9873486edSKuninori Morimoto // 10873486edSKuninori Morimoto // Author: Liam Girdwood <lrg@slimlogic.co.uk> 11873486edSKuninori Morimoto // with code, comments and ideas from :- 12873486edSKuninori Morimoto // Richard Purdie <richard@openedhand.com> 13873486edSKuninori Morimoto // 14873486edSKuninori Morimoto // TODO: 15873486edSKuninori Morimoto // o Add hw rules to enforce rates, etc. 16873486edSKuninori Morimoto // o More testing with other codecs/machines. 17873486edSKuninori Morimoto // o Add more codecs and platforms to ensure good API coverage. 18873486edSKuninori Morimoto // o Support TDM on PCM and I2S 19db2a4165SFrank Mandarino 20db2a4165SFrank Mandarino #include <linux/module.h> 21db2a4165SFrank Mandarino #include <linux/moduleparam.h> 22db2a4165SFrank Mandarino #include <linux/init.h> 23db2a4165SFrank Mandarino #include <linux/delay.h> 24db2a4165SFrank Mandarino #include <linux/pm.h> 25db2a4165SFrank Mandarino #include <linux/bitops.h> 2612ef193dSTroy Kisky #include <linux/debugfs.h> 27db2a4165SFrank Mandarino #include <linux/platform_device.h> 28741a509fSMarkus Pargmann #include <linux/pinctrl/consumer.h> 29f0e8ed85SMark Brown #include <linux/ctype.h> 305a0e3ad6STejun Heo #include <linux/slab.h> 31bec4fa05SStephen Warren #include <linux/of.h> 32a180e8b9SKuninori Morimoto #include <linux/of_graph.h> 33345233d7SLiam Girdwood #include <linux/dmi.h> 34db2a4165SFrank Mandarino #include <sound/core.h> 353028eb8cSMark Brown #include <sound/jack.h> 36db2a4165SFrank Mandarino #include <sound/pcm.h> 37db2a4165SFrank Mandarino #include <sound/pcm_params.h> 38db2a4165SFrank Mandarino #include <sound/soc.h> 3901d7584cSLiam Girdwood #include <sound/soc-dpcm.h> 408a978234SLiam Girdwood #include <sound/soc-topology.h> 41db2a4165SFrank Mandarino #include <sound/initval.h> 42db2a4165SFrank Mandarino 43a8b1d34fSMark Brown #define CREATE_TRACE_POINTS 44a8b1d34fSMark Brown #include <trace/events/asoc.h> 45a8b1d34fSMark Brown 46f0fba2adSLiam Girdwood #define NAME_SIZE 32 47f0fba2adSLiam Girdwood 48384c89e2SMark Brown #ifdef CONFIG_DEBUG_FS 498a9dab1aSMark Brown struct dentry *snd_soc_debugfs_root; 508a9dab1aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); 51384c89e2SMark Brown #endif 52384c89e2SMark Brown 53c5af3a2eSMark Brown static DEFINE_MUTEX(client_mutex); 54030e79f6SKuninori Morimoto static LIST_HEAD(component_list); 55e894efefSSrinivas Kandagatla static LIST_HEAD(unbind_card_list); 56c5af3a2eSMark Brown 57368dee94SKuninori Morimoto #define for_each_component(component) \ 58368dee94SKuninori Morimoto list_for_each_entry(component, &component_list, list) 59368dee94SKuninori Morimoto 60db2a4165SFrank Mandarino /* 61587c9844SKuninori Morimoto * This is used if driver don't need to have CPU/Codec/Platform 62587c9844SKuninori Morimoto * dai_link. see soc.h 63587c9844SKuninori Morimoto */ 64587c9844SKuninori Morimoto struct snd_soc_dai_link_component null_dailink_component[0]; 65587c9844SKuninori Morimoto EXPORT_SYMBOL_GPL(null_dailink_component); 66587c9844SKuninori Morimoto 67587c9844SKuninori Morimoto /* 68db2a4165SFrank Mandarino * This is a timeout to do a DAPM powerdown after a stream is closed(). 69db2a4165SFrank Mandarino * It can be used to eliminate pops between different playback streams, e.g. 70db2a4165SFrank Mandarino * between two audio tracks. 71db2a4165SFrank Mandarino */ 72db2a4165SFrank Mandarino static int pmdown_time = 5000; 73db2a4165SFrank Mandarino module_param(pmdown_time, int, 0); 74db2a4165SFrank Mandarino MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); 75db2a4165SFrank Mandarino 76dbe21408SMark Brown static ssize_t pmdown_time_show(struct device *dev, 77dbe21408SMark Brown struct device_attribute *attr, char *buf) 78dbe21408SMark Brown { 7936ae1a96SMark Brown struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); 80dbe21408SMark Brown 81f0fba2adSLiam Girdwood return sprintf(buf, "%ld\n", rtd->pmdown_time); 82dbe21408SMark Brown } 83dbe21408SMark Brown 84dbe21408SMark Brown static ssize_t pmdown_time_set(struct device *dev, 85dbe21408SMark Brown struct device_attribute *attr, 86dbe21408SMark Brown const char *buf, size_t count) 87dbe21408SMark Brown { 8836ae1a96SMark Brown struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); 89c593b520SMark Brown int ret; 90dbe21408SMark Brown 91b785a492SJingoo Han ret = kstrtol(buf, 10, &rtd->pmdown_time); 92c593b520SMark Brown if (ret) 93c593b520SMark Brown return ret; 94dbe21408SMark Brown 95dbe21408SMark Brown return count; 96dbe21408SMark Brown } 97dbe21408SMark Brown 98dbe21408SMark Brown static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); 99dbe21408SMark Brown 100d29697dcSTakashi Iwai static struct attribute *soc_dev_attrs[] = { 101d29697dcSTakashi Iwai &dev_attr_pmdown_time.attr, 102d29697dcSTakashi Iwai NULL 103d29697dcSTakashi Iwai }; 104d29697dcSTakashi Iwai 105d29697dcSTakashi Iwai static umode_t soc_dev_attr_is_visible(struct kobject *kobj, 106d29697dcSTakashi Iwai struct attribute *attr, int idx) 107d29697dcSTakashi Iwai { 108d29697dcSTakashi Iwai struct device *dev = kobj_to_dev(kobj); 109d29697dcSTakashi Iwai struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); 110d29697dcSTakashi Iwai 111d918a376SKuninori Morimoto if (!rtd) 112d918a376SKuninori Morimoto return 0; 113d918a376SKuninori Morimoto 114d29697dcSTakashi Iwai if (attr == &dev_attr_pmdown_time.attr) 115d29697dcSTakashi Iwai return attr->mode; /* always visible */ 1163b6eed8dSKuninori Morimoto return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */ 117d29697dcSTakashi Iwai } 118d29697dcSTakashi Iwai 119d29697dcSTakashi Iwai static const struct attribute_group soc_dapm_dev_group = { 120d29697dcSTakashi Iwai .attrs = soc_dapm_dev_attrs, 121d29697dcSTakashi Iwai .is_visible = soc_dev_attr_is_visible, 122d29697dcSTakashi Iwai }; 123d29697dcSTakashi Iwai 124f7e73b26SMark Brown static const struct attribute_group soc_dev_group = { 125d29697dcSTakashi Iwai .attrs = soc_dev_attrs, 126d29697dcSTakashi Iwai .is_visible = soc_dev_attr_is_visible, 127d29697dcSTakashi Iwai }; 128d29697dcSTakashi Iwai 129d29697dcSTakashi Iwai static const struct attribute_group *soc_dev_attr_groups[] = { 130d29697dcSTakashi Iwai &soc_dapm_dev_group, 131f7e73b26SMark Brown &soc_dev_group, 132d29697dcSTakashi Iwai NULL 133d29697dcSTakashi Iwai }; 134d29697dcSTakashi Iwai 1352624d5faSMark Brown #ifdef CONFIG_DEBUG_FS 13681c7cfd1SLars-Peter Clausen static void soc_init_component_debugfs(struct snd_soc_component *component) 137e73f3de5SRussell King { 1386553bf06SLars-Peter Clausen if (!component->card->debugfs_card_root) 1396553bf06SLars-Peter Clausen return; 1406553bf06SLars-Peter Clausen 14181c7cfd1SLars-Peter Clausen if (component->debugfs_prefix) { 14281c7cfd1SLars-Peter Clausen char *name; 143e73f3de5SRussell King 14481c7cfd1SLars-Peter Clausen name = kasprintf(GFP_KERNEL, "%s:%s", 14581c7cfd1SLars-Peter Clausen component->debugfs_prefix, component->name); 14681c7cfd1SLars-Peter Clausen if (name) { 14781c7cfd1SLars-Peter Clausen component->debugfs_root = debugfs_create_dir(name, 14881c7cfd1SLars-Peter Clausen component->card->debugfs_card_root); 14981c7cfd1SLars-Peter Clausen kfree(name); 15081c7cfd1SLars-Peter Clausen } 15181c7cfd1SLars-Peter Clausen } else { 15281c7cfd1SLars-Peter Clausen component->debugfs_root = debugfs_create_dir(component->name, 15381c7cfd1SLars-Peter Clausen component->card->debugfs_card_root); 154e73f3de5SRussell King } 155e73f3de5SRussell King 15681c7cfd1SLars-Peter Clausen snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), 15781c7cfd1SLars-Peter Clausen component->debugfs_root); 15881c7cfd1SLars-Peter Clausen } 15981c7cfd1SLars-Peter Clausen 16081c7cfd1SLars-Peter Clausen static void soc_cleanup_component_debugfs(struct snd_soc_component *component) 16181c7cfd1SLars-Peter Clausen { 162ad64bfbdSKuninori Morimoto if (!component->debugfs_root) 163ad64bfbdSKuninori Morimoto return; 16481c7cfd1SLars-Peter Clausen debugfs_remove_recursive(component->debugfs_root); 165ad64bfbdSKuninori Morimoto component->debugfs_root = NULL; 16681c7cfd1SLars-Peter Clausen } 16781c7cfd1SLars-Peter Clausen 168c15b2a1dSPeng Donglin static int dai_list_show(struct seq_file *m, void *v) 169f3208780SMark Brown { 1701438c2f6SLars-Peter Clausen struct snd_soc_component *component; 171f3208780SMark Brown struct snd_soc_dai *dai; 172f3208780SMark Brown 17334e81ab4SLars-Peter Clausen mutex_lock(&client_mutex); 17434e81ab4SLars-Peter Clausen 175368dee94SKuninori Morimoto for_each_component(component) 17615a0c645SKuninori Morimoto for_each_component_dais(component, dai) 177700c17caSDonglin Peng seq_printf(m, "%s\n", dai->name); 178f3208780SMark Brown 17934e81ab4SLars-Peter Clausen mutex_unlock(&client_mutex); 18034e81ab4SLars-Peter Clausen 181700c17caSDonglin Peng return 0; 182700c17caSDonglin Peng } 183c15b2a1dSPeng Donglin DEFINE_SHOW_ATTRIBUTE(dai_list); 184f3208780SMark Brown 185db795f9bSKuninori Morimoto static int component_list_show(struct seq_file *m, void *v) 186db795f9bSKuninori Morimoto { 187db795f9bSKuninori Morimoto struct snd_soc_component *component; 188db795f9bSKuninori Morimoto 189db795f9bSKuninori Morimoto mutex_lock(&client_mutex); 190db795f9bSKuninori Morimoto 191368dee94SKuninori Morimoto for_each_component(component) 192db795f9bSKuninori Morimoto seq_printf(m, "%s\n", component->name); 193db795f9bSKuninori Morimoto 194db795f9bSKuninori Morimoto mutex_unlock(&client_mutex); 195db795f9bSKuninori Morimoto 196db795f9bSKuninori Morimoto return 0; 197db795f9bSKuninori Morimoto } 198db795f9bSKuninori Morimoto DEFINE_SHOW_ATTRIBUTE(component_list); 199db795f9bSKuninori Morimoto 200a6052154SJarkko Nikula static void soc_init_card_debugfs(struct snd_soc_card *card) 201a6052154SJarkko Nikula { 202a6052154SJarkko Nikula card->debugfs_card_root = debugfs_create_dir(card->name, 2038a9dab1aSMark Brown snd_soc_debugfs_root); 2043a45b867SJarkko Nikula 205fee531d6SGreg Kroah-Hartman debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root, 2063a45b867SJarkko Nikula &card->pop_time); 207d8ca7a0aSKuninori Morimoto 208d8ca7a0aSKuninori Morimoto snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); 209a6052154SJarkko Nikula } 210a6052154SJarkko Nikula 211a6052154SJarkko Nikula static void soc_cleanup_card_debugfs(struct snd_soc_card *card) 212a6052154SJarkko Nikula { 213a6052154SJarkko Nikula debugfs_remove_recursive(card->debugfs_card_root); 21429040d1aSKuninori Morimoto card->debugfs_card_root = NULL; 215a6052154SJarkko Nikula } 216a6052154SJarkko Nikula 2176553bf06SLars-Peter Clausen static void snd_soc_debugfs_init(void) 2186553bf06SLars-Peter Clausen { 2196553bf06SLars-Peter Clausen snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); 2206553bf06SLars-Peter Clausen 221fee531d6SGreg Kroah-Hartman debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, 222fee531d6SGreg Kroah-Hartman &dai_list_fops); 223db795f9bSKuninori Morimoto 224fee531d6SGreg Kroah-Hartman debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, 225fee531d6SGreg Kroah-Hartman &component_list_fops); 2266553bf06SLars-Peter Clausen } 2276553bf06SLars-Peter Clausen 2286553bf06SLars-Peter Clausen static void snd_soc_debugfs_exit(void) 2296553bf06SLars-Peter Clausen { 2306553bf06SLars-Peter Clausen debugfs_remove_recursive(snd_soc_debugfs_root); 2316553bf06SLars-Peter Clausen } 2326553bf06SLars-Peter Clausen 2332624d5faSMark Brown #else 2342624d5faSMark Brown 23581c7cfd1SLars-Peter Clausen static inline void soc_init_component_debugfs( 23681c7cfd1SLars-Peter Clausen struct snd_soc_component *component) 2372624d5faSMark Brown { 2382624d5faSMark Brown } 2392624d5faSMark Brown 24081c7cfd1SLars-Peter Clausen static inline void soc_cleanup_component_debugfs( 24181c7cfd1SLars-Peter Clausen struct snd_soc_component *component) 242731f1ab2SSebastien Guiriec { 243731f1ab2SSebastien Guiriec } 244731f1ab2SSebastien Guiriec 245b95fccbcSAxel Lin static inline void soc_init_card_debugfs(struct snd_soc_card *card) 246b95fccbcSAxel Lin { 247b95fccbcSAxel Lin } 248b95fccbcSAxel Lin 249b95fccbcSAxel Lin static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) 250b95fccbcSAxel Lin { 251b95fccbcSAxel Lin } 2526553bf06SLars-Peter Clausen 2536553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_init(void) 2546553bf06SLars-Peter Clausen { 2556553bf06SLars-Peter Clausen } 2566553bf06SLars-Peter Clausen 2576553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_exit(void) 2586553bf06SLars-Peter Clausen { 2596553bf06SLars-Peter Clausen } 2606553bf06SLars-Peter Clausen 2612624d5faSMark Brown #endif 2622624d5faSMark Brown 2638ec241c4SKuninori Morimoto /* 2648ec241c4SKuninori Morimoto * This is glue code between snd_pcm_lib_ioctl() and 2658ec241c4SKuninori Morimoto * snd_soc_component_driver :: ioctl 2668ec241c4SKuninori Morimoto */ 2678ec241c4SKuninori Morimoto int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, 2688ec241c4SKuninori Morimoto struct snd_pcm_substream *substream, 2698ec241c4SKuninori Morimoto unsigned int cmd, void *arg) 2708ec241c4SKuninori Morimoto { 2718ec241c4SKuninori Morimoto return snd_pcm_lib_ioctl(substream, cmd, arg); 2728ec241c4SKuninori Morimoto } 2738ec241c4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl); 2748ec241c4SKuninori Morimoto 275a0ac4411SKuninori Morimoto static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, 276a0ac4411SKuninori Morimoto struct snd_soc_component *component) 277a0ac4411SKuninori Morimoto { 278a0ac4411SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 2792b544dd7SKuninori Morimoto struct snd_soc_component *comp; 280a0ac4411SKuninori Morimoto 2812b544dd7SKuninori Morimoto for_each_rtd_components(rtd, rtdcom, comp) { 282a0ac4411SKuninori Morimoto /* already connected */ 2832b544dd7SKuninori Morimoto if (comp == component) 284a0ac4411SKuninori Morimoto return 0; 285a0ac4411SKuninori Morimoto } 286a0ac4411SKuninori Morimoto 287353e16bfSKuninori Morimoto /* 288353e16bfSKuninori Morimoto * created rtdcom here will be freed when rtd->dev was freed. 289353e16bfSKuninori Morimoto * see 290353e16bfSKuninori Morimoto * soc_free_pcm_runtime() :: device_unregister(rtd->dev) 291353e16bfSKuninori Morimoto */ 292353e16bfSKuninori Morimoto rtdcom = devm_kzalloc(rtd->dev, sizeof(*rtdcom), GFP_KERNEL); 29332d2c172SKuninori Morimoto if (!rtdcom) 294a0ac4411SKuninori Morimoto return -ENOMEM; 295a0ac4411SKuninori Morimoto 29632d2c172SKuninori Morimoto rtdcom->component = component; 29732d2c172SKuninori Morimoto INIT_LIST_HEAD(&rtdcom->list); 298a0ac4411SKuninori Morimoto 299353e16bfSKuninori Morimoto /* 300353e16bfSKuninori Morimoto * When rtd was freed, created rtdcom here will be 301353e16bfSKuninori Morimoto * also freed. 302353e16bfSKuninori Morimoto * And we don't need to call list_del(&rtdcom->list) 303353e16bfSKuninori Morimoto * when freed, because rtd is also freed. 304353e16bfSKuninori Morimoto */ 30532d2c172SKuninori Morimoto list_add_tail(&rtdcom->list, &rtd->component_list); 306a0ac4411SKuninori Morimoto 307a0ac4411SKuninori Morimoto return 0; 308a0ac4411SKuninori Morimoto } 309a0ac4411SKuninori Morimoto 310a0ac4411SKuninori Morimoto struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, 311a0ac4411SKuninori Morimoto const char *driver_name) 312a0ac4411SKuninori Morimoto { 313a0ac4411SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 3142b544dd7SKuninori Morimoto struct snd_soc_component *component; 315a0ac4411SKuninori Morimoto 316971da24cSKuninori Morimoto if (!driver_name) 317971da24cSKuninori Morimoto return NULL; 318971da24cSKuninori Morimoto 319a33c0d16SKuninori Morimoto /* 320a33c0d16SKuninori Morimoto * NOTE 321a33c0d16SKuninori Morimoto * 322a33c0d16SKuninori Morimoto * snd_soc_rtdcom_lookup() will find component from rtd by using 323a33c0d16SKuninori Morimoto * specified driver name. 324a33c0d16SKuninori Morimoto * But, if many components which have same driver name are connected 325a33c0d16SKuninori Morimoto * to 1 rtd, this function will return 1st found component. 326a33c0d16SKuninori Morimoto */ 3272b544dd7SKuninori Morimoto for_each_rtd_components(rtd, rtdcom, component) { 3282b544dd7SKuninori Morimoto const char *component_name = component->driver->name; 329971da24cSKuninori Morimoto 330971da24cSKuninori Morimoto if (!component_name) 331971da24cSKuninori Morimoto continue; 332971da24cSKuninori Morimoto 333971da24cSKuninori Morimoto if ((component_name == driver_name) || 334971da24cSKuninori Morimoto strcmp(component_name, driver_name) == 0) 335a0ac4411SKuninori Morimoto return rtdcom->component; 336a0ac4411SKuninori Morimoto } 337a0ac4411SKuninori Morimoto 338a0ac4411SKuninori Morimoto return NULL; 339a0ac4411SKuninori Morimoto } 340031734b7SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup); 341a0ac4411SKuninori Morimoto 34218dd66eaSKuninori Morimoto static struct snd_soc_component 34318dd66eaSKuninori Morimoto *snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name) 344b8132657SKuninori Morimoto { 345b8132657SKuninori Morimoto struct snd_soc_component *component; 3465bd7e08bSKuninori Morimoto struct snd_soc_component *found_component; 347b8132657SKuninori Morimoto 3485bd7e08bSKuninori Morimoto found_component = NULL; 349b8132657SKuninori Morimoto for_each_component(component) { 3505bd7e08bSKuninori Morimoto if ((dev == component->dev) && 3515bd7e08bSKuninori Morimoto (!driver_name || 3525bd7e08bSKuninori Morimoto (driver_name == component->driver->name) || 3535bd7e08bSKuninori Morimoto (strcmp(component->driver->name, driver_name) == 0))) { 3545bd7e08bSKuninori Morimoto found_component = component; 355b8132657SKuninori Morimoto break; 356b8132657SKuninori Morimoto } 3575bd7e08bSKuninori Morimoto } 358b8132657SKuninori Morimoto 3595bd7e08bSKuninori Morimoto return found_component; 360b8132657SKuninori Morimoto } 36118dd66eaSKuninori Morimoto 36218dd66eaSKuninori Morimoto struct snd_soc_component *snd_soc_lookup_component(struct device *dev, 36318dd66eaSKuninori Morimoto const char *driver_name) 36418dd66eaSKuninori Morimoto { 36518dd66eaSKuninori Morimoto struct snd_soc_component *component; 36618dd66eaSKuninori Morimoto 36718dd66eaSKuninori Morimoto mutex_lock(&client_mutex); 36818dd66eaSKuninori Morimoto component = snd_soc_lookup_component_nolocked(dev, driver_name); 36918dd66eaSKuninori Morimoto mutex_unlock(&client_mutex); 37018dd66eaSKuninori Morimoto 37118dd66eaSKuninori Morimoto return component; 37218dd66eaSKuninori Morimoto } 373b8132657SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_lookup_component); 374b8132657SKuninori Morimoto 37575ab9eb6SKuninori Morimoto static const struct snd_soc_ops null_snd_soc_ops; 37675ab9eb6SKuninori Morimoto 37794def8eaSKuninori Morimoto struct snd_soc_pcm_runtime 37894def8eaSKuninori Morimoto *snd_soc_get_pcm_runtime(struct snd_soc_card *card, 3794468189fSKuninori Morimoto struct snd_soc_dai_link *dai_link) 38094def8eaSKuninori Morimoto { 38194def8eaSKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 38294def8eaSKuninori Morimoto 38394def8eaSKuninori Morimoto for_each_card_rtds(card, rtd) { 3844468189fSKuninori Morimoto if (rtd->dai_link == dai_link) 38594def8eaSKuninori Morimoto return rtd; 38694def8eaSKuninori Morimoto } 3874468189fSKuninori Morimoto dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link->name); 38894def8eaSKuninori Morimoto return NULL; 38994def8eaSKuninori Morimoto } 39094def8eaSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); 39194def8eaSKuninori Morimoto 3926e864344SKuninori Morimoto static void soc_release_rtd_dev(struct device *dev) 3936e864344SKuninori Morimoto { 3946e864344SKuninori Morimoto /* "dev" means "rtd->dev" */ 3956e864344SKuninori Morimoto kfree(dev); 3966e864344SKuninori Morimoto } 3976e864344SKuninori Morimoto 3981c93a9e0SKuninori Morimoto static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) 3991c93a9e0SKuninori Morimoto { 4006e864344SKuninori Morimoto if (!rtd) 4016e864344SKuninori Morimoto return; 4026e864344SKuninori Morimoto 403753ace0aSKuninori Morimoto list_del(&rtd->list); 404b7c5bc45SKuninori Morimoto 4059c9b6520SCurtis Malainey if (delayed_work_pending(&rtd->delayed_work)) 4060ced7b05SKuninori Morimoto flush_delayed_work(&rtd->delayed_work); 4070ced7b05SKuninori Morimoto snd_soc_pcm_component_free(rtd); 4080ced7b05SKuninori Morimoto 409b7c5bc45SKuninori Morimoto /* 410b7c5bc45SKuninori Morimoto * we don't need to call kfree() for rtd->dev 411b7c5bc45SKuninori Morimoto * see 412b7c5bc45SKuninori Morimoto * soc_release_rtd_dev() 413d918a376SKuninori Morimoto * 414d918a376SKuninori Morimoto * We don't need rtd->dev NULL check, because 415d918a376SKuninori Morimoto * it is alloced *before* rtd. 416d918a376SKuninori Morimoto * see 417d918a376SKuninori Morimoto * soc_new_pcm_runtime() 418b7c5bc45SKuninori Morimoto */ 419b7c5bc45SKuninori Morimoto device_unregister(rtd->dev); 4201c93a9e0SKuninori Morimoto } 4211c93a9e0SKuninori Morimoto 4224bf2e385SCurtis Malainey static void close_delayed_work(struct work_struct *work) { 4234bf2e385SCurtis Malainey struct snd_soc_pcm_runtime *rtd = 4244bf2e385SCurtis Malainey container_of(work, struct snd_soc_pcm_runtime, 4254bf2e385SCurtis Malainey delayed_work.work); 4264bf2e385SCurtis Malainey 4274bf2e385SCurtis Malainey if (rtd->close_delayed_work_func) 4284bf2e385SCurtis Malainey rtd->close_delayed_work_func(rtd); 4294bf2e385SCurtis Malainey } 4304bf2e385SCurtis Malainey 4311a497983SMengdong Lin static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( 4321a497983SMengdong Lin struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) 4331a497983SMengdong Lin { 4341a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 435d918a376SKuninori Morimoto struct device *dev; 4366e864344SKuninori Morimoto int ret; 4371a497983SMengdong Lin 4386e864344SKuninori Morimoto /* 439d918a376SKuninori Morimoto * for rtd->dev 440d918a376SKuninori Morimoto */ 441d918a376SKuninori Morimoto dev = kzalloc(sizeof(struct device), GFP_KERNEL); 442d918a376SKuninori Morimoto if (!dev) 443d918a376SKuninori Morimoto return NULL; 444d918a376SKuninori Morimoto 445d918a376SKuninori Morimoto dev->parent = card->dev; 446d918a376SKuninori Morimoto dev->release = soc_release_rtd_dev; 447d918a376SKuninori Morimoto dev->groups = soc_dev_attr_groups; 448d918a376SKuninori Morimoto 449d918a376SKuninori Morimoto dev_set_name(dev, "%s", dai_link->name); 450d918a376SKuninori Morimoto 451d918a376SKuninori Morimoto ret = device_register(dev); 452d918a376SKuninori Morimoto if (ret < 0) { 453d918a376SKuninori Morimoto put_device(dev); /* soc_release_rtd_dev */ 454d918a376SKuninori Morimoto return NULL; 455d918a376SKuninori Morimoto } 456d918a376SKuninori Morimoto 457d918a376SKuninori Morimoto /* 4586e864344SKuninori Morimoto * for rtd 4596e864344SKuninori Morimoto */ 4604dc0e7dfSKuninori Morimoto rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); 4611a497983SMengdong Lin if (!rtd) 4626e864344SKuninori Morimoto goto free_rtd; 4631a497983SMengdong Lin 464d918a376SKuninori Morimoto rtd->dev = dev; 465d918a376SKuninori Morimoto dev_set_drvdata(dev, rtd); 4664bf2e385SCurtis Malainey INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); 467d918a376SKuninori Morimoto 4686e864344SKuninori Morimoto /* 4696e864344SKuninori Morimoto * for rtd->codec_dais 4706e864344SKuninori Morimoto */ 4714dc0e7dfSKuninori Morimoto rtd->codec_dais = devm_kcalloc(dev, dai_link->num_codecs, 4726396bb22SKees Cook sizeof(struct snd_soc_dai *), 4731a497983SMengdong Lin GFP_KERNEL); 4746e864344SKuninori Morimoto if (!rtd->codec_dais) 4756e864344SKuninori Morimoto goto free_rtd; 4766e864344SKuninori Morimoto 4776e864344SKuninori Morimoto /* 4786e864344SKuninori Morimoto * rtd remaining settings 4796e864344SKuninori Morimoto */ 480929deb84SKuninori Morimoto INIT_LIST_HEAD(&rtd->component_list); 4816e864344SKuninori Morimoto INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); 4826e864344SKuninori Morimoto INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); 4836e864344SKuninori Morimoto INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); 4846e864344SKuninori Morimoto INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); 4856e864344SKuninori Morimoto 486929deb84SKuninori Morimoto rtd->card = card; 487929deb84SKuninori Morimoto rtd->dai_link = dai_link; 488929deb84SKuninori Morimoto if (!rtd->dai_link->ops) 489929deb84SKuninori Morimoto rtd->dai_link->ops = &null_snd_soc_ops; 490929deb84SKuninori Morimoto 4916634e3d6SKuninori Morimoto /* see for_each_card_rtds */ 4921a497983SMengdong Lin list_add_tail(&rtd->list, &card->rtd_list); 4931a497983SMengdong Lin rtd->num = card->num_rtd; 4941a497983SMengdong Lin card->num_rtd++; 495a848125eSKuninori Morimoto 496a848125eSKuninori Morimoto return rtd; 4976e864344SKuninori Morimoto 4986e864344SKuninori Morimoto free_rtd: 4996e864344SKuninori Morimoto soc_free_pcm_runtime(rtd); 5006e864344SKuninori Morimoto return NULL; 5011a497983SMengdong Lin } 5021a497983SMengdong Lin 50365462e44SKuninori Morimoto static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) 50465462e44SKuninori Morimoto { 50565462e44SKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 50665462e44SKuninori Morimoto 50765462e44SKuninori Morimoto for_each_card_rtds(card, rtd) 50865462e44SKuninori Morimoto flush_delayed_work(&rtd->delayed_work); 50965462e44SKuninori Morimoto } 51065462e44SKuninori Morimoto 5116f8ab4acSMark Brown #ifdef CONFIG_PM_SLEEP 512db2a4165SFrank Mandarino /* powers down audio subsystem for suspend */ 5136f8ab4acSMark Brown int snd_soc_suspend(struct device *dev) 514db2a4165SFrank Mandarino { 5156f8ab4acSMark Brown struct snd_soc_card *card = dev_get_drvdata(dev); 516d9fc4063SKuninori Morimoto struct snd_soc_component *component; 5171a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 5181a497983SMengdong Lin int i; 519db2a4165SFrank Mandarino 520c5599b87SLars-Peter Clausen /* If the card is not initialized yet there is nothing to do */ 521c5599b87SLars-Peter Clausen if (!card->instantiated) 522e3509ff0SDaniel Mack return 0; 523e3509ff0SDaniel Mack 5242c7b696aSMarcel Ziswiler /* 5252c7b696aSMarcel Ziswiler * Due to the resume being scheduled into a workqueue we could 5266ed25978SAndy Green * suspend before that's finished - wait for it to complete. 5276ed25978SAndy Green */ 528f0fba2adSLiam Girdwood snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); 5296ed25978SAndy Green 5306ed25978SAndy Green /* we're going to block userspace touching us until resume completes */ 531f0fba2adSLiam Girdwood snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); 5326ed25978SAndy Green 533a00f90f9SMark Brown /* mute any active DACs */ 534bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 5350b7990e3SKuninori Morimoto struct snd_soc_dai *dai; 5363efab7dcSMark Brown 5371a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 5383efab7dcSMark Brown continue; 5393efab7dcSMark Brown 5400b7990e3SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, dai) { 54188fdffa2SKuninori Morimoto if (dai->playback_active) 54288fdffa2SKuninori Morimoto snd_soc_dai_digital_mute(dai, 1, 54388fdffa2SKuninori Morimoto SNDRV_PCM_STREAM_PLAYBACK); 544db2a4165SFrank Mandarino } 54588bd870fSBenoit Cousson } 546db2a4165SFrank Mandarino 5474ccab3e7SLiam Girdwood /* suspend all pcms */ 548bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 5491a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 5503efab7dcSMark Brown continue; 5513efab7dcSMark Brown 5521a497983SMengdong Lin snd_pcm_suspend_all(rtd->pcm); 5533efab7dcSMark Brown } 5544ccab3e7SLiam Girdwood 55587506549SMark Brown if (card->suspend_pre) 55670b2ac12SMark Brown card->suspend_pre(card); 557db2a4165SFrank Mandarino 558bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 5591a497983SMengdong Lin struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 5603efab7dcSMark Brown 5611a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 5623efab7dcSMark Brown continue; 5633efab7dcSMark Brown 564e0f22622SKuninori Morimoto if (!cpu_dai->driver->bus_control) 565e0f22622SKuninori Morimoto snd_soc_dai_suspend(cpu_dai); 566db2a4165SFrank Mandarino } 567db2a4165SFrank Mandarino 56837660b6dSLars-Peter Clausen /* close any waiting streams */ 56965462e44SKuninori Morimoto snd_soc_flush_all_delayed_work(card); 570db2a4165SFrank Mandarino 571bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 5723efab7dcSMark Brown 5731a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 5743efab7dcSMark Brown continue; 5753efab7dcSMark Brown 5761a497983SMengdong Lin snd_soc_dapm_stream_event(rtd, 5777bd3a6f3SMark Brown SNDRV_PCM_STREAM_PLAYBACK, 578db2a4165SFrank Mandarino SND_SOC_DAPM_STREAM_SUSPEND); 579f0fba2adSLiam Girdwood 5801a497983SMengdong Lin snd_soc_dapm_stream_event(rtd, 5817bd3a6f3SMark Brown SNDRV_PCM_STREAM_CAPTURE, 582db2a4165SFrank Mandarino SND_SOC_DAPM_STREAM_SUSPEND); 583db2a4165SFrank Mandarino } 584db2a4165SFrank Mandarino 5858be4da29SLars-Peter Clausen /* Recheck all endpoints too, their state is affected by suspend */ 5868be4da29SLars-Peter Clausen dapm_mark_endpoints_dirty(card); 587e2d32ff6SMark Brown snd_soc_dapm_sync(&card->dapm); 588e2d32ff6SMark Brown 5899178feb4SKuninori Morimoto /* suspend all COMPONENTs */ 590f70f18f7SKuninori Morimoto for_each_card_components(card, component) { 5912c7b696aSMarcel Ziswiler struct snd_soc_dapm_context *dapm = 5922c7b696aSMarcel Ziswiler snd_soc_component_get_dapm(component); 593d9fc4063SKuninori Morimoto 5942c7b696aSMarcel Ziswiler /* 5952c7b696aSMarcel Ziswiler * If there are paths active then the COMPONENT will be held 5962c7b696aSMarcel Ziswiler * with bias _ON and should not be suspended. 5972c7b696aSMarcel Ziswiler */ 598e40fadbcSKuninori Morimoto if (!snd_soc_component_is_suspended(component)) { 5994890140fSLars-Peter Clausen switch (snd_soc_dapm_get_bias_level(dapm)) { 6001547aba9SMark Brown case SND_SOC_BIAS_STANDBY: 601125a25daSMark Brown /* 6029178feb4SKuninori Morimoto * If the COMPONENT is capable of idle 603125a25daSMark Brown * bias off then being in STANDBY 604125a25daSMark Brown * means it's doing something, 605125a25daSMark Brown * otherwise fall through. 606125a25daSMark Brown */ 6074890140fSLars-Peter Clausen if (dapm->idle_bias_off) { 6089178feb4SKuninori Morimoto dev_dbg(component->dev, 60910e8aa9aSMichał Mirosław "ASoC: idle_bias_off CODEC on over suspend\n"); 610125a25daSMark Brown break; 611125a25daSMark Brown } 6121a12d5dcSGustavo A. R. Silva /* fall through */ 613a8093297SLars-Peter Clausen 6141547aba9SMark Brown case SND_SOC_BIAS_OFF: 61566c51573SKuninori Morimoto snd_soc_component_suspend(component); 6169178feb4SKuninori Morimoto if (component->regmap) 6179178feb4SKuninori Morimoto regcache_mark_dirty(component->regmap); 618988e8cc4SNicolin Chen /* deactivate pins to sleep state */ 6199178feb4SKuninori Morimoto pinctrl_pm_select_sleep_state(component->dev); 6201547aba9SMark Brown break; 6211547aba9SMark Brown default: 6229178feb4SKuninori Morimoto dev_dbg(component->dev, 6239178feb4SKuninori Morimoto "ASoC: COMPONENT is on over suspend\n"); 6241547aba9SMark Brown break; 6251547aba9SMark Brown } 6261547aba9SMark Brown } 627f0fba2adSLiam Girdwood } 628db2a4165SFrank Mandarino 629bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 6301a497983SMengdong Lin struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 6313efab7dcSMark Brown 6321a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 6333efab7dcSMark Brown continue; 6343efab7dcSMark Brown 635e0f22622SKuninori Morimoto if (cpu_dai->driver->bus_control) 636e0f22622SKuninori Morimoto snd_soc_dai_suspend(cpu_dai); 637988e8cc4SNicolin Chen 638988e8cc4SNicolin Chen /* deactivate pins to sleep state */ 639988e8cc4SNicolin Chen pinctrl_pm_select_sleep_state(cpu_dai->dev); 640db2a4165SFrank Mandarino } 641db2a4165SFrank Mandarino 64287506549SMark Brown if (card->suspend_post) 64370b2ac12SMark Brown card->suspend_post(card); 644db2a4165SFrank Mandarino 645db2a4165SFrank Mandarino return 0; 646db2a4165SFrank Mandarino } 6476f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_suspend); 648db2a4165SFrank Mandarino 6492c7b696aSMarcel Ziswiler /* 6502c7b696aSMarcel Ziswiler * deferred resume work, so resume can complete before we finished 6516ed25978SAndy Green * setting our codec back up, which can be very slow on I2C 6526ed25978SAndy Green */ 6536ed25978SAndy Green static void soc_resume_deferred(struct work_struct *work) 654db2a4165SFrank Mandarino { 655f0fba2adSLiam Girdwood struct snd_soc_card *card = 6562c7b696aSMarcel Ziswiler container_of(work, struct snd_soc_card, 6572c7b696aSMarcel Ziswiler deferred_resume_work); 6581a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 659d9fc4063SKuninori Morimoto struct snd_soc_component *component; 6601a497983SMengdong Lin int i; 661db2a4165SFrank Mandarino 6622c7b696aSMarcel Ziswiler /* 6632c7b696aSMarcel Ziswiler * our power state is still SNDRV_CTL_POWER_D3hot from suspend time, 6646ed25978SAndy Green * so userspace apps are blocked from touching us 6656ed25978SAndy Green */ 6666ed25978SAndy Green 667f110bfc7SLiam Girdwood dev_dbg(card->dev, "ASoC: starting resume work\n"); 6686ed25978SAndy Green 6699949788bSMark Brown /* Bring us up into D2 so that DAPM starts enabling things */ 670f0fba2adSLiam Girdwood snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); 6719949788bSMark Brown 67287506549SMark Brown if (card->resume_pre) 67370b2ac12SMark Brown card->resume_pre(card); 674db2a4165SFrank Mandarino 675bc263214SLars-Peter Clausen /* resume control bus DAIs */ 676bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 6771a497983SMengdong Lin struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 6783efab7dcSMark Brown 6791a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 6803efab7dcSMark Brown continue; 6813efab7dcSMark Brown 68224b09d05SKuninori Morimoto if (cpu_dai->driver->bus_control) 68324b09d05SKuninori Morimoto snd_soc_dai_resume(cpu_dai); 684db2a4165SFrank Mandarino } 685db2a4165SFrank Mandarino 686f70f18f7SKuninori Morimoto for_each_card_components(card, component) { 687e40fadbcSKuninori Morimoto if (snd_soc_component_is_suspended(component)) 6889a840cbaSKuninori Morimoto snd_soc_component_resume(component); 6891547aba9SMark Brown } 690db2a4165SFrank Mandarino 691bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 6923efab7dcSMark Brown 6931a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 6943efab7dcSMark Brown continue; 6953efab7dcSMark Brown 6961a497983SMengdong Lin snd_soc_dapm_stream_event(rtd, 697d9b0951bSLiam Girdwood SNDRV_PCM_STREAM_PLAYBACK, 698db2a4165SFrank Mandarino SND_SOC_DAPM_STREAM_RESUME); 699f0fba2adSLiam Girdwood 7001a497983SMengdong Lin snd_soc_dapm_stream_event(rtd, 701d9b0951bSLiam Girdwood SNDRV_PCM_STREAM_CAPTURE, 702db2a4165SFrank Mandarino SND_SOC_DAPM_STREAM_RESUME); 703db2a4165SFrank Mandarino } 704db2a4165SFrank Mandarino 7053ff3f64bSMark Brown /* unmute any active DACs */ 706bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 7070b7990e3SKuninori Morimoto struct snd_soc_dai *dai; 7083efab7dcSMark Brown 7091a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 7103efab7dcSMark Brown continue; 7113efab7dcSMark Brown 7120b7990e3SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, dai) { 71388fdffa2SKuninori Morimoto if (dai->playback_active) 71488fdffa2SKuninori Morimoto snd_soc_dai_digital_mute(dai, 0, 71588fdffa2SKuninori Morimoto SNDRV_PCM_STREAM_PLAYBACK); 716db2a4165SFrank Mandarino } 71788bd870fSBenoit Cousson } 718db2a4165SFrank Mandarino 719bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 7201a497983SMengdong Lin struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 7213efab7dcSMark Brown 7221a497983SMengdong Lin if (rtd->dai_link->ignore_suspend) 7233efab7dcSMark Brown continue; 7243efab7dcSMark Brown 72524b09d05SKuninori Morimoto if (!cpu_dai->driver->bus_control) 72624b09d05SKuninori Morimoto snd_soc_dai_resume(cpu_dai); 727db2a4165SFrank Mandarino } 728db2a4165SFrank Mandarino 72987506549SMark Brown if (card->resume_post) 73070b2ac12SMark Brown card->resume_post(card); 731db2a4165SFrank Mandarino 732f110bfc7SLiam Girdwood dev_dbg(card->dev, "ASoC: resume work completed\n"); 7336ed25978SAndy Green 7348be4da29SLars-Peter Clausen /* Recheck all endpoints too, their state is affected by suspend */ 7358be4da29SLars-Peter Clausen dapm_mark_endpoints_dirty(card); 736e2d32ff6SMark Brown snd_soc_dapm_sync(&card->dapm); 7371a7aaa58SJeeja KP 7381a7aaa58SJeeja KP /* userspace can access us now we are back as we were before */ 7391a7aaa58SJeeja KP snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); 7406ed25978SAndy Green } 7416ed25978SAndy Green 7426ed25978SAndy Green /* powers up audio subsystem after a suspend */ 7436f8ab4acSMark Brown int snd_soc_resume(struct device *dev) 7446ed25978SAndy Green { 7456f8ab4acSMark Brown struct snd_soc_card *card = dev_get_drvdata(dev); 746bc263214SLars-Peter Clausen bool bus_control = false; 7471a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 74822d251a5SKuninori Morimoto struct snd_soc_dai *codec_dai; 74922d251a5SKuninori Morimoto int i; 750b9dd94a8SPeter Ujfalusi 751c5599b87SLars-Peter Clausen /* If the card is not initialized yet there is nothing to do */ 752c5599b87SLars-Peter Clausen if (!card->instantiated) 7535ff1ddf2SEric Miao return 0; 7545ff1ddf2SEric Miao 755988e8cc4SNicolin Chen /* activate pins from sleep state */ 756bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 75788bd870fSBenoit Cousson struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 75888bd870fSBenoit Cousson 759988e8cc4SNicolin Chen if (cpu_dai->active) 760988e8cc4SNicolin Chen pinctrl_pm_select_default_state(cpu_dai->dev); 76188bd870fSBenoit Cousson 76222d251a5SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, codec_dai) { 763988e8cc4SNicolin Chen if (codec_dai->active) 764988e8cc4SNicolin Chen pinctrl_pm_select_default_state(codec_dai->dev); 765988e8cc4SNicolin Chen } 76688bd870fSBenoit Cousson } 767988e8cc4SNicolin Chen 768bc263214SLars-Peter Clausen /* 769bc263214SLars-Peter Clausen * DAIs that also act as the control bus master might have other drivers 770bc263214SLars-Peter Clausen * hanging off them so need to resume immediately. Other drivers don't 771bc263214SLars-Peter Clausen * have that problem and may take a substantial amount of time to resume 77264ab9baaSMark Brown * due to I/O costs and anti-pop so handle them out of line. 77364ab9baaSMark Brown */ 774bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 7751a497983SMengdong Lin struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 7762c7b696aSMarcel Ziswiler 777bc263214SLars-Peter Clausen bus_control |= cpu_dai->driver->bus_control; 77882e14e8bSStephen Warren } 779bc263214SLars-Peter Clausen if (bus_control) { 780bc263214SLars-Peter Clausen dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); 78164ab9baaSMark Brown soc_resume_deferred(&card->deferred_resume_work); 78264ab9baaSMark Brown } else { 783f110bfc7SLiam Girdwood dev_dbg(dev, "ASoC: Scheduling resume work\n"); 7846308419aSMark Brown if (!schedule_work(&card->deferred_resume_work)) 785f110bfc7SLiam Girdwood dev_err(dev, "ASoC: resume work item may be lost\n"); 786f0fba2adSLiam Girdwood } 7876ed25978SAndy Green 788db2a4165SFrank Mandarino return 0; 789db2a4165SFrank Mandarino } 7906f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_resume); 791b3da4251SKuninori Morimoto 792b3da4251SKuninori Morimoto static void soc_resume_init(struct snd_soc_card *card) 793b3da4251SKuninori Morimoto { 794b3da4251SKuninori Morimoto /* deferred resume work */ 795b3da4251SKuninori Morimoto INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); 796b3da4251SKuninori Morimoto } 797db2a4165SFrank Mandarino #else 7986f8ab4acSMark Brown #define snd_soc_suspend NULL 7996f8ab4acSMark Brown #define snd_soc_resume NULL 800b3da4251SKuninori Morimoto static inline void soc_resume_init(struct snd_soc_card *card) 801b3da4251SKuninori Morimoto { 802b3da4251SKuninori Morimoto } 803db2a4165SFrank Mandarino #endif 804db2a4165SFrank Mandarino 80585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops null_dai_ops = { 80602a06d30SBarry Song }; 80702a06d30SBarry Song 808c0834440SKuninori Morimoto static struct device_node 809c0834440SKuninori Morimoto *soc_component_to_node(struct snd_soc_component *component) 81012023a9aSMisael Lopez Cruz { 811c0834440SKuninori Morimoto struct device_node *of_node; 81212023a9aSMisael Lopez Cruz 813c0834440SKuninori Morimoto of_node = component->dev->of_node; 814c0834440SKuninori Morimoto if (!of_node && component->dev->parent) 815c0834440SKuninori Morimoto of_node = component->dev->parent->of_node; 81634e81ab4SLars-Peter Clausen 817c0834440SKuninori Morimoto return of_node; 81812023a9aSMisael Lopez Cruz } 81912023a9aSMisael Lopez Cruz 820be6ac0a9SKuninori Morimoto static int snd_soc_is_matching_component( 821be6ac0a9SKuninori Morimoto const struct snd_soc_dai_link_component *dlc, 822be6ac0a9SKuninori Morimoto struct snd_soc_component *component) 823be6ac0a9SKuninori Morimoto { 824be6ac0a9SKuninori Morimoto struct device_node *component_of_node; 825be6ac0a9SKuninori Morimoto 8267d7db5d3SKuninori Morimoto if (!dlc) 8277d7db5d3SKuninori Morimoto return 0; 8287d7db5d3SKuninori Morimoto 8297d7db5d3SKuninori Morimoto component_of_node = soc_component_to_node(component); 830be6ac0a9SKuninori Morimoto 831be6ac0a9SKuninori Morimoto if (dlc->of_node && component_of_node != dlc->of_node) 832be6ac0a9SKuninori Morimoto return 0; 833be6ac0a9SKuninori Morimoto if (dlc->name && strcmp(component->name, dlc->name)) 834be6ac0a9SKuninori Morimoto return 0; 835be6ac0a9SKuninori Morimoto 836be6ac0a9SKuninori Morimoto return 1; 837be6ac0a9SKuninori Morimoto } 838be6ac0a9SKuninori Morimoto 839db2a4165SFrank Mandarino static struct snd_soc_component *soc_find_component( 840c1e230f0SKuninori Morimoto const struct snd_soc_dai_link_component *dlc) 841db2a4165SFrank Mandarino { 842db2a4165SFrank Mandarino struct snd_soc_component *component; 843db2a4165SFrank Mandarino 844db2a4165SFrank Mandarino lockdep_assert_held(&client_mutex); 845db2a4165SFrank Mandarino 846e3303268SKuninori Morimoto /* 847e3303268SKuninori Morimoto * NOTE 848e3303268SKuninori Morimoto * 849e3303268SKuninori Morimoto * It returns *1st* found component, but some driver 850e3303268SKuninori Morimoto * has few components by same of_node/name 851e3303268SKuninori Morimoto * ex) 852e3303268SKuninori Morimoto * CPU component and generic DMAEngine component 853e3303268SKuninori Morimoto */ 854c1e230f0SKuninori Morimoto for_each_component(component) 855c1e230f0SKuninori Morimoto if (snd_soc_is_matching_component(dlc, component)) 856db2a4165SFrank Mandarino return component; 857db2a4165SFrank Mandarino 858db2a4165SFrank Mandarino return NULL; 85912023a9aSMisael Lopez Cruz } 86012023a9aSMisael Lopez Cruz 861fbb88b5cSMengdong Lin /** 862fbb88b5cSMengdong Lin * snd_soc_find_dai - Find a registered DAI 863fbb88b5cSMengdong Lin * 8644958471bSJeffy Chen * @dlc: name of the DAI or the DAI driver and optional component info to match 865fbb88b5cSMengdong Lin * 866ad61dd30SStephen Boyd * This function will search all registered components and their DAIs to 867fbb88b5cSMengdong Lin * find the DAI of the same name. The component's of_node and name 868fbb88b5cSMengdong Lin * should also match if being specified. 869fbb88b5cSMengdong Lin * 870fbb88b5cSMengdong Lin * Return: pointer of DAI, or NULL if not found. 871fbb88b5cSMengdong Lin */ 872305e9020SMengdong Lin struct snd_soc_dai *snd_soc_find_dai( 87314621c7eSLars-Peter Clausen const struct snd_soc_dai_link_component *dlc) 87412023a9aSMisael Lopez Cruz { 87514621c7eSLars-Peter Clausen struct snd_soc_component *component; 87614621c7eSLars-Peter Clausen struct snd_soc_dai *dai; 87712023a9aSMisael Lopez Cruz 87834e81ab4SLars-Peter Clausen lockdep_assert_held(&client_mutex); 87934e81ab4SLars-Peter Clausen 88014621c7eSLars-Peter Clausen /* Find CPU DAI from registered DAIs */ 881368dee94SKuninori Morimoto for_each_component(component) { 882be6ac0a9SKuninori Morimoto if (!snd_soc_is_matching_component(dlc, component)) 88312023a9aSMisael Lopez Cruz continue; 88415a0c645SKuninori Morimoto for_each_component_dais(component, dai) { 8854958471bSJeffy Chen if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) 8866a6dafdaSJeffy Chen && (!dai->driver->name 8876a6dafdaSJeffy Chen || strcmp(dai->driver->name, dlc->dai_name))) 88814621c7eSLars-Peter Clausen continue; 88912023a9aSMisael Lopez Cruz 89014621c7eSLars-Peter Clausen return dai; 89112023a9aSMisael Lopez Cruz } 89212023a9aSMisael Lopez Cruz } 89312023a9aSMisael Lopez Cruz 89412023a9aSMisael Lopez Cruz return NULL; 89512023a9aSMisael Lopez Cruz } 896305e9020SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai); 89712023a9aSMisael Lopez Cruz 898bfce78a5SKuninori Morimoto static int soc_dai_link_sanity_check(struct snd_soc_card *card, 89936794902SKuninori Morimoto struct snd_soc_dai_link *link) 90036794902SKuninori Morimoto { 90136794902SKuninori Morimoto int i; 90236794902SKuninori Morimoto struct snd_soc_dai_link_component *codec, *platform; 90336794902SKuninori Morimoto 90436794902SKuninori Morimoto for_each_link_codecs(link, i, codec) { 90536794902SKuninori Morimoto /* 90636794902SKuninori Morimoto * Codec must be specified by 1 of name or OF node, 90736794902SKuninori Morimoto * not both or neither. 90836794902SKuninori Morimoto */ 90936794902SKuninori Morimoto if (!!codec->name == !!codec->of_node) { 91036794902SKuninori Morimoto dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", 91136794902SKuninori Morimoto link->name); 91236794902SKuninori Morimoto return -EINVAL; 91336794902SKuninori Morimoto } 91436794902SKuninori Morimoto 91536794902SKuninori Morimoto /* Codec DAI name must be specified */ 91636794902SKuninori Morimoto if (!codec->dai_name) { 91736794902SKuninori Morimoto dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", 91836794902SKuninori Morimoto link->name); 91936794902SKuninori Morimoto return -EINVAL; 92036794902SKuninori Morimoto } 92136794902SKuninori Morimoto 92236794902SKuninori Morimoto /* 92336794902SKuninori Morimoto * Defer card registration if codec component is not added to 92436794902SKuninori Morimoto * component list. 92536794902SKuninori Morimoto */ 92636794902SKuninori Morimoto if (!soc_find_component(codec)) 92736794902SKuninori Morimoto return -EPROBE_DEFER; 92836794902SKuninori Morimoto } 92936794902SKuninori Morimoto 93036794902SKuninori Morimoto for_each_link_platforms(link, i, platform) { 93136794902SKuninori Morimoto /* 93236794902SKuninori Morimoto * Platform may be specified by either name or OF node, but it 93336794902SKuninori Morimoto * can be left unspecified, then no components will be inserted 93436794902SKuninori Morimoto * in the rtdcom list 93536794902SKuninori Morimoto */ 93636794902SKuninori Morimoto if (!!platform->name == !!platform->of_node) { 93736794902SKuninori Morimoto dev_err(card->dev, 93836794902SKuninori Morimoto "ASoC: Neither/both platform name/of_node are set for %s\n", 93936794902SKuninori Morimoto link->name); 94036794902SKuninori Morimoto return -EINVAL; 94136794902SKuninori Morimoto } 94236794902SKuninori Morimoto 94336794902SKuninori Morimoto /* 94436794902SKuninori Morimoto * Defer card registration if platform component is not added to 94536794902SKuninori Morimoto * component list. 94636794902SKuninori Morimoto */ 94736794902SKuninori Morimoto if (!soc_find_component(platform)) 94836794902SKuninori Morimoto return -EPROBE_DEFER; 94936794902SKuninori Morimoto } 95036794902SKuninori Morimoto 95136794902SKuninori Morimoto /* FIXME */ 95236794902SKuninori Morimoto if (link->num_cpus > 1) { 95336794902SKuninori Morimoto dev_err(card->dev, 95436794902SKuninori Morimoto "ASoC: multi cpu is not yet supported %s\n", 95536794902SKuninori Morimoto link->name); 95636794902SKuninori Morimoto return -EINVAL; 95736794902SKuninori Morimoto } 95836794902SKuninori Morimoto 95936794902SKuninori Morimoto /* 96036794902SKuninori Morimoto * CPU device may be specified by either name or OF node, but 96136794902SKuninori Morimoto * can be left unspecified, and will be matched based on DAI 96236794902SKuninori Morimoto * name alone.. 96336794902SKuninori Morimoto */ 96436794902SKuninori Morimoto if (link->cpus->name && link->cpus->of_node) { 96536794902SKuninori Morimoto dev_err(card->dev, 96636794902SKuninori Morimoto "ASoC: Neither/both cpu name/of_node are set for %s\n", 96736794902SKuninori Morimoto link->name); 96836794902SKuninori Morimoto return -EINVAL; 96936794902SKuninori Morimoto } 97036794902SKuninori Morimoto 97136794902SKuninori Morimoto /* 972cd3c5ad7SKuninori Morimoto * Defer card registration if cpu dai component is not added to 97336794902SKuninori Morimoto * component list. 97436794902SKuninori Morimoto */ 97536794902SKuninori Morimoto if ((link->cpus->of_node || link->cpus->name) && 97636794902SKuninori Morimoto !soc_find_component(link->cpus)) 97736794902SKuninori Morimoto return -EPROBE_DEFER; 97836794902SKuninori Morimoto 97936794902SKuninori Morimoto /* 98036794902SKuninori Morimoto * At least one of CPU DAI name or CPU device name/node must be 98136794902SKuninori Morimoto * specified 98236794902SKuninori Morimoto */ 98336794902SKuninori Morimoto if (!link->cpus->dai_name && 98436794902SKuninori Morimoto !(link->cpus->name || link->cpus->of_node)) { 98536794902SKuninori Morimoto dev_err(card->dev, 98636794902SKuninori Morimoto "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", 98736794902SKuninori Morimoto link->name); 98836794902SKuninori Morimoto return -EINVAL; 98936794902SKuninori Morimoto } 99036794902SKuninori Morimoto 99136794902SKuninori Morimoto return 0; 99236794902SKuninori Morimoto } 99336794902SKuninori Morimoto 994da704f26SKuninori Morimoto /** 99550cd9b53SKuninori Morimoto * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card 99650cd9b53SKuninori Morimoto * @card: The ASoC card to which the pcm_runtime has 99750cd9b53SKuninori Morimoto * @rtd: The pcm_runtime to remove 998da704f26SKuninori Morimoto * 99950cd9b53SKuninori Morimoto * This function removes a pcm_runtime from the ASoC card. 1000da704f26SKuninori Morimoto */ 100150cd9b53SKuninori Morimoto void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, 100250cd9b53SKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 1003bc7a9091SKuninori Morimoto { 1004da704f26SKuninori Morimoto lockdep_assert_held(&client_mutex); 1005da704f26SKuninori Morimoto 1006da704f26SKuninori Morimoto /* 1007da704f26SKuninori Morimoto * Notify the machine driver for extra destruction 1008da704f26SKuninori Morimoto */ 1009da704f26SKuninori Morimoto if (card->remove_dai_link) 101050cd9b53SKuninori Morimoto card->remove_dai_link(card, rtd->dai_link); 1011da704f26SKuninori Morimoto 1012bc7a9091SKuninori Morimoto soc_free_pcm_runtime(rtd); 1013bc7a9091SKuninori Morimoto } 101450cd9b53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_remove_pcm_runtime); 1015bc7a9091SKuninori Morimoto 101663dc47daSKuninori Morimoto /** 10170c048004SKuninori Morimoto * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link 10180c048004SKuninori Morimoto * @card: The ASoC card to which the pcm_runtime is added 10190c048004SKuninori Morimoto * @dai_link: The DAI link to find pcm_runtime 102063dc47daSKuninori Morimoto * 10210c048004SKuninori Morimoto * This function adds a pcm_runtime ASoC card by using dai_link. 102263dc47daSKuninori Morimoto * 10230c048004SKuninori Morimoto * Note: Topology can use this API to add pcm_runtime when probing the 102463dc47daSKuninori Morimoto * topology component. And machine drivers can still define static 102563dc47daSKuninori Morimoto * DAI links in dai_link array. 102663dc47daSKuninori Morimoto */ 10270c048004SKuninori Morimoto int snd_soc_add_pcm_runtime(struct snd_soc_card *card, 10286f2f1ff0SMengdong Lin struct snd_soc_dai_link *dai_link) 1029db2a4165SFrank Mandarino { 10301a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 103134614739SJerome Brunet struct snd_soc_dai_link_component *codec, *platform; 103290be711eSKuninori Morimoto struct snd_soc_component *component; 1033bfce78a5SKuninori Morimoto int i, ret; 1034db2a4165SFrank Mandarino 103563dc47daSKuninori Morimoto lockdep_assert_held(&client_mutex); 103663dc47daSKuninori Morimoto 103763dc47daSKuninori Morimoto /* 103863dc47daSKuninori Morimoto * Notify the machine driver for extra initialization 103963dc47daSKuninori Morimoto */ 104063dc47daSKuninori Morimoto if (card->add_dai_link) 104163dc47daSKuninori Morimoto card->add_dai_link(card, dai_link); 104263dc47daSKuninori Morimoto 1043a655de80SLiam Girdwood if (dai_link->ignore) 1044a655de80SLiam Girdwood return 0; 1045a655de80SLiam Girdwood 10466f2f1ff0SMengdong Lin dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); 10476308419aSMark Brown 1048bfce78a5SKuninori Morimoto ret = soc_dai_link_sanity_check(card, dai_link); 1049bfce78a5SKuninori Morimoto if (ret < 0) 1050bfce78a5SKuninori Morimoto return ret; 1051bfce78a5SKuninori Morimoto 1052513cb311SSudip Mukherjee rtd = soc_new_pcm_runtime(card, dai_link); 1053513cb311SSudip Mukherjee if (!rtd) 1054513cb311SSudip Mukherjee return -ENOMEM; 1055513cb311SSudip Mukherjee 105608a5841eSKuninori Morimoto /* FIXME: we need multi CPU support in the future */ 105708a5841eSKuninori Morimoto rtd->cpu_dai = snd_soc_find_dai(dai_link->cpus); 1058b19e6e7bSMark Brown if (!rtd->cpu_dai) { 10596b490879SMartin Hundebøll dev_info(card->dev, "ASoC: CPU DAI %s not registered\n", 106008a5841eSKuninori Morimoto dai_link->cpus->dai_name); 10611a497983SMengdong Lin goto _err_defer; 1062c5af3a2eSMark Brown } 106390be711eSKuninori Morimoto snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); 1064c5af3a2eSMark Brown 106588bd870fSBenoit Cousson /* Find CODEC from registered CODECs */ 1066e2b30edfSKuninori Morimoto rtd->num_codecs = dai_link->num_codecs; 106734614739SJerome Brunet for_each_link_codecs(dai_link, i, codec) { 106834614739SJerome Brunet rtd->codec_dais[i] = snd_soc_find_dai(codec); 10690a2cfcd9SKuninori Morimoto if (!rtd->codec_dais[i]) { 10707c7e2d6aSStefan Agner dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", 107134614739SJerome Brunet codec->dai_name); 10721a497983SMengdong Lin goto _err_defer; 107312023a9aSMisael Lopez Cruz } 107434614739SJerome Brunet 10750a2cfcd9SKuninori Morimoto snd_soc_rtdcom_add(rtd, rtd->codec_dais[i]->component); 107688bd870fSBenoit Cousson } 107788bd870fSBenoit Cousson 107888bd870fSBenoit Cousson /* Single codec links expect codec and codec_dai in runtime data */ 10790a2cfcd9SKuninori Morimoto rtd->codec_dai = rtd->codec_dais[0]; 108012023a9aSMisael Lopez Cruz 1081e2b30edfSKuninori Morimoto /* Find PLATFORM from registered PLATFORMs */ 108234614739SJerome Brunet for_each_link_platforms(dai_link, i, platform) { 1083368dee94SKuninori Morimoto for_each_component(component) { 108434614739SJerome Brunet if (!snd_soc_is_matching_component(platform, component)) 108590be711eSKuninori Morimoto continue; 108690be711eSKuninori Morimoto 108790be711eSKuninori Morimoto snd_soc_rtdcom_add(rtd, component); 108890be711eSKuninori Morimoto } 108934614739SJerome Brunet } 109090be711eSKuninori Morimoto 1091b19e6e7bSMark Brown return 0; 10921a497983SMengdong Lin 10931a497983SMengdong Lin _err_defer: 109450cd9b53SKuninori Morimoto snd_soc_remove_pcm_runtime(card, rtd); 10951a497983SMengdong Lin return -EPROBE_DEFER; 10966b05eda6SMark Brown } 10970c048004SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime); 10986b05eda6SMark Brown 1099bfa0dd89SKuninori Morimoto static int soc_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, 11009e9c70a5SKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 11019e9c70a5SKuninori Morimoto { 11029e9c70a5SKuninori Morimoto int i, ret = 0; 11039e9c70a5SKuninori Morimoto 11049e9c70a5SKuninori Morimoto for (i = 0; i < num_dais; ++i) { 11059e9c70a5SKuninori Morimoto struct snd_soc_dai_driver *drv = dais[i]->driver; 11069e9c70a5SKuninori Morimoto 11079e9c70a5SKuninori Morimoto if (drv->pcm_new) 11089e9c70a5SKuninori Morimoto ret = drv->pcm_new(rtd, dais[i]); 11099e9c70a5SKuninori Morimoto if (ret < 0) { 11109e9c70a5SKuninori Morimoto dev_err(dais[i]->dev, 11119e9c70a5SKuninori Morimoto "ASoC: Failed to bind %s with pcm device\n", 11129e9c70a5SKuninori Morimoto dais[i]->name); 11139e9c70a5SKuninori Morimoto return ret; 11149e9c70a5SKuninori Morimoto } 11159e9c70a5SKuninori Morimoto } 11169e9c70a5SKuninori Morimoto 11179e9c70a5SKuninori Morimoto return 0; 11189e9c70a5SKuninori Morimoto } 11199e9c70a5SKuninori Morimoto 1120eaffeefbSKuninori Morimoto static int soc_init_pcm_runtime(struct snd_soc_card *card, 112146496acbSKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 112246496acbSKuninori Morimoto { 112346496acbSKuninori Morimoto struct snd_soc_dai_link *dai_link = rtd->dai_link; 112446496acbSKuninori Morimoto struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 112546496acbSKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 112646496acbSKuninori Morimoto struct snd_soc_component *component; 112746496acbSKuninori Morimoto int ret, num; 112846496acbSKuninori Morimoto 112946496acbSKuninori Morimoto /* set default power off timeout */ 113046496acbSKuninori Morimoto rtd->pmdown_time = pmdown_time; 113146496acbSKuninori Morimoto 113246496acbSKuninori Morimoto /* do machine specific initialization */ 113346496acbSKuninori Morimoto if (dai_link->init) { 113446496acbSKuninori Morimoto ret = dai_link->init(rtd); 113546496acbSKuninori Morimoto if (ret < 0) { 113646496acbSKuninori Morimoto dev_err(card->dev, "ASoC: failed to init %s: %d\n", 113746496acbSKuninori Morimoto dai_link->name, ret); 113846496acbSKuninori Morimoto return ret; 113946496acbSKuninori Morimoto } 114046496acbSKuninori Morimoto } 114146496acbSKuninori Morimoto 114246496acbSKuninori Morimoto if (dai_link->dai_fmt) { 114346496acbSKuninori Morimoto ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); 114446496acbSKuninori Morimoto if (ret) 114546496acbSKuninori Morimoto return ret; 114646496acbSKuninori Morimoto } 114746496acbSKuninori Morimoto 114846496acbSKuninori Morimoto /* add DPCM sysfs entries */ 114946496acbSKuninori Morimoto soc_dpcm_debugfs_add(rtd); 115046496acbSKuninori Morimoto 115146496acbSKuninori Morimoto num = rtd->num; 115246496acbSKuninori Morimoto 115346496acbSKuninori Morimoto /* 115446496acbSKuninori Morimoto * most drivers will register their PCMs using DAI link ordering but 115546496acbSKuninori Morimoto * topology based drivers can use the DAI link id field to set PCM 115646496acbSKuninori Morimoto * device number and then use rtd + a base offset of the BEs. 115746496acbSKuninori Morimoto */ 115846496acbSKuninori Morimoto for_each_rtd_components(rtd, rtdcom, component) { 115946496acbSKuninori Morimoto if (!component->driver->use_dai_pcm_id) 116046496acbSKuninori Morimoto continue; 116146496acbSKuninori Morimoto 116246496acbSKuninori Morimoto if (rtd->dai_link->no_pcm) 116346496acbSKuninori Morimoto num += component->driver->be_pcm_base; 116446496acbSKuninori Morimoto else 116546496acbSKuninori Morimoto num = rtd->dai_link->id; 116646496acbSKuninori Morimoto } 116746496acbSKuninori Morimoto 116846496acbSKuninori Morimoto /* create compress_device if possible */ 116946496acbSKuninori Morimoto ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); 117046496acbSKuninori Morimoto if (ret != -ENOTSUPP) { 117146496acbSKuninori Morimoto if (ret < 0) 117246496acbSKuninori Morimoto dev_err(card->dev, "ASoC: can't create compress %s\n", 117346496acbSKuninori Morimoto dai_link->stream_name); 117446496acbSKuninori Morimoto return ret; 117546496acbSKuninori Morimoto } 117646496acbSKuninori Morimoto 117746496acbSKuninori Morimoto /* create the pcm */ 117846496acbSKuninori Morimoto ret = soc_new_pcm(rtd, num); 117946496acbSKuninori Morimoto if (ret < 0) { 118046496acbSKuninori Morimoto dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", 118146496acbSKuninori Morimoto dai_link->stream_name, ret); 118246496acbSKuninori Morimoto return ret; 118346496acbSKuninori Morimoto } 118446496acbSKuninori Morimoto ret = soc_dai_pcm_new(&cpu_dai, 1, rtd); 118546496acbSKuninori Morimoto if (ret < 0) 118646496acbSKuninori Morimoto return ret; 118746496acbSKuninori Morimoto ret = soc_dai_pcm_new(rtd->codec_dais, 118846496acbSKuninori Morimoto rtd->num_codecs, rtd); 118946496acbSKuninori Morimoto return ret; 119046496acbSKuninori Morimoto } 119146496acbSKuninori Morimoto 1192ffd60fbaSKuninori Morimoto static void soc_set_name_prefix(struct snd_soc_card *card, 1193ffd60fbaSKuninori Morimoto struct snd_soc_component *component) 1194ffd60fbaSKuninori Morimoto { 1195aec3ff99SKuninori Morimoto struct device_node *of_node = soc_component_to_node(component); 119629d9fc7aSKuninori Morimoto const char *str; 119729d9fc7aSKuninori Morimoto int ret, i; 1198ffd60fbaSKuninori Morimoto 11994702f991SKuninori Morimoto for (i = 0; i < card->num_configs; i++) { 1200ffd60fbaSKuninori Morimoto struct snd_soc_codec_conf *map = &card->codec_conf[i]; 1201ffd60fbaSKuninori Morimoto 1202ffd60fbaSKuninori Morimoto if (map->of_node && of_node != map->of_node) 1203ffd60fbaSKuninori Morimoto continue; 1204ffd60fbaSKuninori Morimoto if (map->dev_name && strcmp(component->name, map->dev_name)) 1205ffd60fbaSKuninori Morimoto continue; 1206ffd60fbaSKuninori Morimoto component->name_prefix = map->name_prefix; 1207ffd60fbaSKuninori Morimoto return; 1208ffd60fbaSKuninori Morimoto } 1209ffd60fbaSKuninori Morimoto 1210ffd60fbaSKuninori Morimoto /* 1211ffd60fbaSKuninori Morimoto * If there is no configuration table or no match in the table, 1212ffd60fbaSKuninori Morimoto * check if a prefix is provided in the node 1213ffd60fbaSKuninori Morimoto */ 121429d9fc7aSKuninori Morimoto ret = of_property_read_string(of_node, "sound-name-prefix", &str); 121529d9fc7aSKuninori Morimoto if (ret < 0) 121629d9fc7aSKuninori Morimoto return; 121729d9fc7aSKuninori Morimoto 121829d9fc7aSKuninori Morimoto component->name_prefix = str; 1219ffd60fbaSKuninori Morimoto } 1220ffd60fbaSKuninori Morimoto 1221c6619b72SKuninori Morimoto static void soc_remove_component(struct snd_soc_component *component, 1222c6619b72SKuninori Morimoto int probed) 122322d14231SKuninori Morimoto { 1224c6619b72SKuninori Morimoto 1225c6619b72SKuninori Morimoto if (!component->card) 1226c6619b72SKuninori Morimoto return; 1227c6619b72SKuninori Morimoto 1228c6619b72SKuninori Morimoto if (probed) 1229c6619b72SKuninori Morimoto snd_soc_component_remove(component); 1230c6619b72SKuninori Morimoto 123104f770d9SKuninori Morimoto /* For framework level robustness */ 12323bb936f5SAmadeusz Sławiński snd_soc_component_set_jack(component, NULL, NULL); 123304f770d9SKuninori Morimoto 12347a5d9815SBard liao list_del_init(&component->card_list); 123522d14231SKuninori Morimoto snd_soc_dapm_free(snd_soc_component_get_dapm(component)); 123622d14231SKuninori Morimoto soc_cleanup_component_debugfs(component); 123722d14231SKuninori Morimoto component->card = NULL; 12380e36f36bSPierre-Louis Bossart snd_soc_component_module_put_when_remove(component); 123922d14231SKuninori Morimoto } 124022d14231SKuninori Morimoto 1241ffd60fbaSKuninori Morimoto static int soc_probe_component(struct snd_soc_card *card, 1242ffd60fbaSKuninori Morimoto struct snd_soc_component *component) 1243ffd60fbaSKuninori Morimoto { 1244ffd60fbaSKuninori Morimoto struct snd_soc_dapm_context *dapm = 1245ffd60fbaSKuninori Morimoto snd_soc_component_get_dapm(component); 1246ffd60fbaSKuninori Morimoto struct snd_soc_dai *dai; 1247c6619b72SKuninori Morimoto int probed = 0; 1248ffd60fbaSKuninori Morimoto int ret; 1249ffd60fbaSKuninori Morimoto 1250ffd60fbaSKuninori Morimoto if (!strcmp(component->name, "snd-soc-dummy")) 1251ffd60fbaSKuninori Morimoto return 0; 1252ffd60fbaSKuninori Morimoto 1253ffd60fbaSKuninori Morimoto if (component->card) { 1254ffd60fbaSKuninori Morimoto if (component->card != card) { 1255ffd60fbaSKuninori Morimoto dev_err(component->dev, 1256ffd60fbaSKuninori Morimoto "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", 1257ffd60fbaSKuninori Morimoto card->name, component->card->name); 1258ffd60fbaSKuninori Morimoto return -ENODEV; 1259ffd60fbaSKuninori Morimoto } 1260ffd60fbaSKuninori Morimoto return 0; 1261ffd60fbaSKuninori Morimoto } 1262ffd60fbaSKuninori Morimoto 1263ffd60fbaSKuninori Morimoto ret = snd_soc_component_module_get_when_probe(component); 1264ffd60fbaSKuninori Morimoto if (ret < 0) 1265ffd60fbaSKuninori Morimoto return ret; 1266ffd60fbaSKuninori Morimoto 1267ffd60fbaSKuninori Morimoto component->card = card; 1268ffd60fbaSKuninori Morimoto soc_set_name_prefix(card, component); 1269ffd60fbaSKuninori Morimoto 1270ffd60fbaSKuninori Morimoto soc_init_component_debugfs(component); 1271ffd60fbaSKuninori Morimoto 127295c267ddSKuninori Morimoto snd_soc_dapm_init(dapm, card, component); 1273b614beafSKuninori Morimoto 1274ffd60fbaSKuninori Morimoto ret = snd_soc_dapm_new_controls(dapm, 1275ffd60fbaSKuninori Morimoto component->driver->dapm_widgets, 1276ffd60fbaSKuninori Morimoto component->driver->num_dapm_widgets); 1277ffd60fbaSKuninori Morimoto 1278ffd60fbaSKuninori Morimoto if (ret != 0) { 1279ffd60fbaSKuninori Morimoto dev_err(component->dev, 1280ffd60fbaSKuninori Morimoto "Failed to create new controls %d\n", ret); 1281ffd60fbaSKuninori Morimoto goto err_probe; 1282ffd60fbaSKuninori Morimoto } 1283ffd60fbaSKuninori Morimoto 1284ffd60fbaSKuninori Morimoto for_each_component_dais(component, dai) { 1285ffd60fbaSKuninori Morimoto ret = snd_soc_dapm_new_dai_widgets(dapm, dai); 1286ffd60fbaSKuninori Morimoto if (ret != 0) { 1287ffd60fbaSKuninori Morimoto dev_err(component->dev, 1288ffd60fbaSKuninori Morimoto "Failed to create DAI widgets %d\n", ret); 1289ffd60fbaSKuninori Morimoto goto err_probe; 1290ffd60fbaSKuninori Morimoto } 1291ffd60fbaSKuninori Morimoto } 1292ffd60fbaSKuninori Morimoto 1293ffd60fbaSKuninori Morimoto ret = snd_soc_component_probe(component); 1294ffd60fbaSKuninori Morimoto if (ret < 0) { 1295ffd60fbaSKuninori Morimoto dev_err(component->dev, 1296ffd60fbaSKuninori Morimoto "ASoC: failed to probe component %d\n", ret); 1297ffd60fbaSKuninori Morimoto goto err_probe; 1298ffd60fbaSKuninori Morimoto } 1299ffd60fbaSKuninori Morimoto WARN(dapm->idle_bias_off && 1300ffd60fbaSKuninori Morimoto dapm->bias_level != SND_SOC_BIAS_OFF, 1301ffd60fbaSKuninori Morimoto "codec %s can not start from non-off bias with idle_bias_off==1\n", 1302ffd60fbaSKuninori Morimoto component->name); 1303c6619b72SKuninori Morimoto probed = 1; 1304ffd60fbaSKuninori Morimoto 1305ffd60fbaSKuninori Morimoto /* machine specific init */ 1306ffd60fbaSKuninori Morimoto if (component->init) { 1307ffd60fbaSKuninori Morimoto ret = component->init(component); 1308ffd60fbaSKuninori Morimoto if (ret < 0) { 1309ffd60fbaSKuninori Morimoto dev_err(component->dev, 1310ffd60fbaSKuninori Morimoto "Failed to do machine specific init %d\n", ret); 1311ffd60fbaSKuninori Morimoto goto err_probe; 1312ffd60fbaSKuninori Morimoto } 1313ffd60fbaSKuninori Morimoto } 1314ffd60fbaSKuninori Morimoto 1315ffd60fbaSKuninori Morimoto ret = snd_soc_add_component_controls(component, 1316ffd60fbaSKuninori Morimoto component->driver->controls, 1317ffd60fbaSKuninori Morimoto component->driver->num_controls); 1318ffd60fbaSKuninori Morimoto if (ret < 0) 1319ffd60fbaSKuninori Morimoto goto err_probe; 1320ffd60fbaSKuninori Morimoto 1321ffd60fbaSKuninori Morimoto ret = snd_soc_dapm_add_routes(dapm, 1322ffd60fbaSKuninori Morimoto component->driver->dapm_routes, 1323ffd60fbaSKuninori Morimoto component->driver->num_dapm_routes); 1324ffd60fbaSKuninori Morimoto if (ret < 0) 1325ffd60fbaSKuninori Morimoto goto err_probe; 1326ffd60fbaSKuninori Morimoto 1327ffd60fbaSKuninori Morimoto /* see for_each_card_components */ 1328ffd60fbaSKuninori Morimoto list_add(&component->card_list, &card->component_dev_list); 1329ffd60fbaSKuninori Morimoto 1330ffd60fbaSKuninori Morimoto err_probe: 1331ffd60fbaSKuninori Morimoto if (ret < 0) 1332c6619b72SKuninori Morimoto soc_remove_component(component, probed); 1333ffd60fbaSKuninori Morimoto 1334ffd60fbaSKuninori Morimoto return ret; 1335ffd60fbaSKuninori Morimoto } 1336ffd60fbaSKuninori Morimoto 1337e60cd14fSLars-Peter Clausen static void soc_remove_dai(struct snd_soc_dai *dai, int order) 1338589c3563SJarkko Nikula { 1339589c3563SJarkko Nikula int err; 1340589c3563SJarkko Nikula 134152abe6ccSGuennadi Liakhovetski if (!dai || !dai->probed || !dai->driver || 13422eda3cb1SKuninori Morimoto dai->driver->remove_order != order) 13432eda3cb1SKuninori Morimoto return; 13442eda3cb1SKuninori Morimoto 1345dcdab582SKuninori Morimoto err = snd_soc_dai_remove(dai); 1346589c3563SJarkko Nikula if (err < 0) 1347e60cd14fSLars-Peter Clausen dev_err(dai->dev, 1348b0aa88afSMisael Lopez Cruz "ASoC: failed to remove %s: %d\n", 1349e60cd14fSLars-Peter Clausen dai->name, err); 1350dcdab582SKuninori Morimoto 1351e60cd14fSLars-Peter Clausen dai->probed = 0; 1352b0aa88afSMisael Lopez Cruz } 1353b0aa88afSMisael Lopez Cruz 1354a7d44f78SKuninori Morimoto static int soc_probe_dai(struct snd_soc_dai *dai, int order) 1355a7d44f78SKuninori Morimoto { 1356a7d44f78SKuninori Morimoto int ret; 1357a7d44f78SKuninori Morimoto 1358a7d44f78SKuninori Morimoto if (dai->probed || 1359a7d44f78SKuninori Morimoto dai->driver->probe_order != order) 1360a7d44f78SKuninori Morimoto return 0; 1361a7d44f78SKuninori Morimoto 1362a7d44f78SKuninori Morimoto ret = snd_soc_dai_probe(dai); 1363a7d44f78SKuninori Morimoto if (ret < 0) { 1364a7d44f78SKuninori Morimoto dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", 1365a7d44f78SKuninori Morimoto dai->name, ret); 1366a7d44f78SKuninori Morimoto return ret; 1367a7d44f78SKuninori Morimoto } 1368a7d44f78SKuninori Morimoto 1369a7d44f78SKuninori Morimoto dai->probed = 1; 1370a7d44f78SKuninori Morimoto 1371a7d44f78SKuninori Morimoto return 0; 1372a7d44f78SKuninori Morimoto } 1373a7d44f78SKuninori Morimoto 13744ca47d21SKuninori Morimoto static void soc_remove_link_dais(struct snd_soc_card *card) 1375f0fba2adSLiam Girdwood { 1376e60cd14fSLars-Peter Clausen int i; 13770b7990e3SKuninori Morimoto struct snd_soc_dai *codec_dai; 13784ca47d21SKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 13794ca47d21SKuninori Morimoto int order; 13804ca47d21SKuninori Morimoto 13814ca47d21SKuninori Morimoto for_each_comp_order(order) { 13824ca47d21SKuninori Morimoto for_each_card_rtds(card, rtd) { 1383f0fba2adSLiam Girdwood /* remove the CODEC DAI */ 13840b7990e3SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, codec_dai) 13850b7990e3SKuninori Morimoto soc_remove_dai(codec_dai, order); 1386f0fba2adSLiam Girdwood 1387e60cd14fSLars-Peter Clausen soc_remove_dai(rtd->cpu_dai, order); 1388f0fba2adSLiam Girdwood } 13894ca47d21SKuninori Morimoto } 13904ca47d21SKuninori Morimoto } 1391f0fba2adSLiam Girdwood 1392bc7c16c2SKuninori Morimoto static int soc_probe_link_dais(struct snd_soc_card *card) 1393bc7c16c2SKuninori Morimoto { 1394bc7c16c2SKuninori Morimoto struct snd_soc_dai *codec_dai; 1395bc7c16c2SKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 1396bc7c16c2SKuninori Morimoto int i, order, ret; 1397bc7c16c2SKuninori Morimoto 1398bc7c16c2SKuninori Morimoto for_each_comp_order(order) { 1399bc7c16c2SKuninori Morimoto for_each_card_rtds(card, rtd) { 1400bc7c16c2SKuninori Morimoto 1401bc7c16c2SKuninori Morimoto dev_dbg(card->dev, 1402bc7c16c2SKuninori Morimoto "ASoC: probe %s dai link %d late %d\n", 1403bc7c16c2SKuninori Morimoto card->name, rtd->num, order); 1404bc7c16c2SKuninori Morimoto 1405bc7c16c2SKuninori Morimoto ret = soc_probe_dai(rtd->cpu_dai, order); 1406bc7c16c2SKuninori Morimoto if (ret) 1407bc7c16c2SKuninori Morimoto return ret; 1408bc7c16c2SKuninori Morimoto 1409bc7c16c2SKuninori Morimoto /* probe the CODEC DAI */ 1410bc7c16c2SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, codec_dai) { 1411bc7c16c2SKuninori Morimoto ret = soc_probe_dai(codec_dai, order); 1412bc7c16c2SKuninori Morimoto if (ret) 1413bc7c16c2SKuninori Morimoto return ret; 1414bc7c16c2SKuninori Morimoto } 1415bc7c16c2SKuninori Morimoto } 1416bc7c16c2SKuninori Morimoto } 1417bc7c16c2SKuninori Morimoto 1418bc7c16c2SKuninori Morimoto return 0; 1419bc7c16c2SKuninori Morimoto } 1420bc7c16c2SKuninori Morimoto 1421b006c0c6SKuninori Morimoto static void soc_remove_link_components(struct snd_soc_card *card) 142262ae68faSStephen Warren { 142361aca564SLars-Peter Clausen struct snd_soc_component *component; 1424b006c0c6SKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 142590be711eSKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 1426b006c0c6SKuninori Morimoto int order; 142762ae68faSStephen Warren 1428b006c0c6SKuninori Morimoto for_each_comp_order(order) { 1429b006c0c6SKuninori Morimoto for_each_card_rtds(card, rtd) { 14302b544dd7SKuninori Morimoto for_each_rtd_components(rtd, rtdcom, component) { 1431b006c0c6SKuninori Morimoto if (component->driver->remove_order != order) 1432b006c0c6SKuninori Morimoto continue; 1433b006c0c6SKuninori Morimoto 1434c6619b72SKuninori Morimoto soc_remove_component(component, 1); 143562ae68faSStephen Warren } 143662ae68faSStephen Warren } 1437b006c0c6SKuninori Morimoto } 1438b006c0c6SKuninori Morimoto } 143962ae68faSStephen Warren 144062f07a6bSKuninori Morimoto static int soc_probe_link_components(struct snd_soc_card *card) 14416fb03550SKuninori Morimoto { 14426fb03550SKuninori Morimoto struct snd_soc_component *component; 144362f07a6bSKuninori Morimoto struct snd_soc_pcm_runtime *rtd; 14446fb03550SKuninori Morimoto struct snd_soc_rtdcom_list *rtdcom; 144562f07a6bSKuninori Morimoto int ret, order; 14466fb03550SKuninori Morimoto 144762f07a6bSKuninori Morimoto for_each_comp_order(order) { 144862f07a6bSKuninori Morimoto for_each_card_rtds(card, rtd) { 14492b544dd7SKuninori Morimoto for_each_rtd_components(rtd, rtdcom, component) { 145062f07a6bSKuninori Morimoto if (component->driver->probe_order != order) 145162f07a6bSKuninori Morimoto continue; 145262f07a6bSKuninori Morimoto 14536fb03550SKuninori Morimoto ret = soc_probe_component(card, component); 14546fb03550SKuninori Morimoto if (ret < 0) 14556fb03550SKuninori Morimoto return ret; 14566fb03550SKuninori Morimoto } 14576fb03550SKuninori Morimoto } 145862f07a6bSKuninori Morimoto } 14596fb03550SKuninori Morimoto 14606fb03550SKuninori Morimoto return 0; 14616fb03550SKuninori Morimoto } 14626fb03550SKuninori Morimoto 1463e8fbd250SKuninori Morimoto static void soc_unbind_aux_dev(struct snd_soc_card *card) 14644893a2ebSKuninori Morimoto { 1465e8fbd250SKuninori Morimoto struct snd_soc_component *component, *_component; 1466e8fbd250SKuninori Morimoto 1467e8fbd250SKuninori Morimoto for_each_card_auxs_safe(card, component, _component) { 14684893a2ebSKuninori Morimoto component->init = NULL; 14694893a2ebSKuninori Morimoto list_del(&component->card_aux_list); 14704893a2ebSKuninori Morimoto } 1471e8fbd250SKuninori Morimoto } 14724893a2ebSKuninori Morimoto 1473bee886f1SKuninori Morimoto static int soc_bind_aux_dev(struct snd_soc_card *card) 1474b19e6e7bSMark Brown { 1475f2ed6b07SMengdong Lin struct snd_soc_component *component; 1476bee886f1SKuninori Morimoto struct snd_soc_aux_dev *aux; 1477bee886f1SKuninori Morimoto int i; 14783ca041edSSebastian Reichel 1479bee886f1SKuninori Morimoto for_each_card_pre_auxs(card, i, aux) { 1480f2ed6b07SMengdong Lin /* codecs, usually analog devices */ 1481bee886f1SKuninori Morimoto component = soc_find_component(&aux->dlc); 1482f2ed6b07SMengdong Lin if (!component) 14833dc29b8bSKuninori Morimoto return -EPROBE_DEFER; 14843ca041edSSebastian Reichel 1485bee886f1SKuninori Morimoto component->init = aux->init; 1486c2b71c71SKuninori Morimoto /* see for_each_card_auxs */ 1487d2e3a135SSylwester Nawrocki list_add(&component->card_aux_list, &card->aux_comp_list); 1488bee886f1SKuninori Morimoto } 1489f2ed6b07SMengdong Lin return 0; 1490b19e6e7bSMark Brown } 1491b19e6e7bSMark Brown 1492f2ed6b07SMengdong Lin static int soc_probe_aux_devices(struct snd_soc_card *card) 1493f2ed6b07SMengdong Lin { 149474bd3f92SKuninori Morimoto struct snd_soc_component *component; 1495f2ed6b07SMengdong Lin int order; 1496f2ed6b07SMengdong Lin int ret; 1497f2ed6b07SMengdong Lin 14981a1035a9SKuninori Morimoto for_each_comp_order(order) { 149974bd3f92SKuninori Morimoto for_each_card_auxs(card, component) { 150074bd3f92SKuninori Morimoto if (component->driver->probe_order != order) 150174bd3f92SKuninori Morimoto continue; 150274bd3f92SKuninori Morimoto 150374bd3f92SKuninori Morimoto ret = soc_probe_component(card, component); 150474bd3f92SKuninori Morimoto if (ret < 0) 1505f2ed6b07SMengdong Lin return ret; 1506f2ed6b07SMengdong Lin } 1507f2ed6b07SMengdong Lin } 150865d9361fSLars-Peter Clausen 150944c69bb1SLars-Peter Clausen return 0; 15103ca041edSSebastian Reichel } 15112eea392dSJarkko Nikula 1512f2ed6b07SMengdong Lin static void soc_remove_aux_devices(struct snd_soc_card *card) 151344c69bb1SLars-Peter Clausen { 1514f2ed6b07SMengdong Lin struct snd_soc_component *comp, *_comp; 1515f2ed6b07SMengdong Lin int order; 151644c69bb1SLars-Peter Clausen 15171a1035a9SKuninori Morimoto for_each_comp_order(order) { 1518c2b71c71SKuninori Morimoto for_each_card_auxs_safe(card, comp, _comp) { 1519e8fbd250SKuninori Morimoto if (comp->driver->remove_order == order) 1520c6619b72SKuninori Morimoto soc_remove_component(comp, 1); 15215f3484acSLars-Peter Clausen } 15222eea392dSJarkko Nikula } 15232eea392dSJarkko Nikula } 15242eea392dSJarkko Nikula 1525ce64c8b9SLars-Peter Clausen /** 1526ce64c8b9SLars-Peter Clausen * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime 1527ce64c8b9SLars-Peter Clausen * @rtd: The runtime for which the DAI link format should be changed 1528ce64c8b9SLars-Peter Clausen * @dai_fmt: The new DAI link format 1529ce64c8b9SLars-Peter Clausen * 1530ce64c8b9SLars-Peter Clausen * This function updates the DAI link format for all DAIs connected to the DAI 1531ce64c8b9SLars-Peter Clausen * link for the specified runtime. 1532ce64c8b9SLars-Peter Clausen * 1533ce64c8b9SLars-Peter Clausen * Note: For setups with a static format set the dai_fmt field in the 1534ce64c8b9SLars-Peter Clausen * corresponding snd_dai_link struct instead of using this function. 1535ce64c8b9SLars-Peter Clausen * 1536ce64c8b9SLars-Peter Clausen * Returns 0 on success, otherwise a negative error code. 1537ce64c8b9SLars-Peter Clausen */ 1538ce64c8b9SLars-Peter Clausen int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, 1539ce64c8b9SLars-Peter Clausen unsigned int dai_fmt) 1540ce64c8b9SLars-Peter Clausen { 1541ce64c8b9SLars-Peter Clausen struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 15420b7990e3SKuninori Morimoto struct snd_soc_dai *codec_dai; 1543ce64c8b9SLars-Peter Clausen unsigned int i; 1544ce64c8b9SLars-Peter Clausen int ret; 1545ce64c8b9SLars-Peter Clausen 15460b7990e3SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, codec_dai) { 1547ce64c8b9SLars-Peter Clausen ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); 1548ce64c8b9SLars-Peter Clausen if (ret != 0 && ret != -ENOTSUPP) { 1549ce64c8b9SLars-Peter Clausen dev_warn(codec_dai->dev, 1550ce64c8b9SLars-Peter Clausen "ASoC: Failed to set DAI format: %d\n", ret); 1551ce64c8b9SLars-Peter Clausen return ret; 1552ce64c8b9SLars-Peter Clausen } 1553ce64c8b9SLars-Peter Clausen } 1554ce64c8b9SLars-Peter Clausen 15552c7b696aSMarcel Ziswiler /* 15562c7b696aSMarcel Ziswiler * Flip the polarity for the "CPU" end of a CODEC<->CODEC link 15572c7b696aSMarcel Ziswiler * the component which has non_legacy_dai_naming is Codec 15582c7b696aSMarcel Ziswiler */ 1559999f7f5aSKuninori Morimoto if (cpu_dai->component->driver->non_legacy_dai_naming) { 1560ce64c8b9SLars-Peter Clausen unsigned int inv_dai_fmt; 1561ce64c8b9SLars-Peter Clausen 1562ce64c8b9SLars-Peter Clausen inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; 1563ce64c8b9SLars-Peter Clausen switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { 1564ce64c8b9SLars-Peter Clausen case SND_SOC_DAIFMT_CBM_CFM: 1565ce64c8b9SLars-Peter Clausen inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; 1566ce64c8b9SLars-Peter Clausen break; 1567ce64c8b9SLars-Peter Clausen case SND_SOC_DAIFMT_CBM_CFS: 1568ce64c8b9SLars-Peter Clausen inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; 1569ce64c8b9SLars-Peter Clausen break; 1570ce64c8b9SLars-Peter Clausen case SND_SOC_DAIFMT_CBS_CFM: 1571ce64c8b9SLars-Peter Clausen inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; 1572ce64c8b9SLars-Peter Clausen break; 1573ce64c8b9SLars-Peter Clausen case SND_SOC_DAIFMT_CBS_CFS: 1574ce64c8b9SLars-Peter Clausen inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; 1575ce64c8b9SLars-Peter Clausen break; 1576ce64c8b9SLars-Peter Clausen } 1577ce64c8b9SLars-Peter Clausen 1578ce64c8b9SLars-Peter Clausen dai_fmt = inv_dai_fmt; 1579ce64c8b9SLars-Peter Clausen } 1580ce64c8b9SLars-Peter Clausen 1581ce64c8b9SLars-Peter Clausen ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); 1582ce64c8b9SLars-Peter Clausen if (ret != 0 && ret != -ENOTSUPP) { 1583ce64c8b9SLars-Peter Clausen dev_warn(cpu_dai->dev, 1584ce64c8b9SLars-Peter Clausen "ASoC: Failed to set DAI format: %d\n", ret); 1585ce64c8b9SLars-Peter Clausen return ret; 1586ce64c8b9SLars-Peter Clausen } 1587ce64c8b9SLars-Peter Clausen 1588ce64c8b9SLars-Peter Clausen return 0; 1589ce64c8b9SLars-Peter Clausen } 1590ddaca25aSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); 1591ce64c8b9SLars-Peter Clausen 15921f5a4535STakashi Iwai #ifdef CONFIG_DMI 15932c7b696aSMarcel Ziswiler /* 1594*8a6a6a38SKuninori Morimoto * If a DMI filed contain strings in this blacklist (e.g. 1595*8a6a6a38SKuninori Morimoto * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken 1596*8a6a6a38SKuninori Morimoto * as invalid and dropped when setting the card long name from DMI info. 1597*8a6a6a38SKuninori Morimoto */ 1598*8a6a6a38SKuninori Morimoto static const char * const dmi_blacklist[] = { 1599*8a6a6a38SKuninori Morimoto "To be filled by OEM", 1600*8a6a6a38SKuninori Morimoto "TBD by OEM", 1601*8a6a6a38SKuninori Morimoto "Default String", 1602*8a6a6a38SKuninori Morimoto "Board Manufacturer", 1603*8a6a6a38SKuninori Morimoto "Board Vendor Name", 1604*8a6a6a38SKuninori Morimoto "Board Product Name", 1605*8a6a6a38SKuninori Morimoto NULL, /* terminator */ 1606*8a6a6a38SKuninori Morimoto }; 1607*8a6a6a38SKuninori Morimoto 1608*8a6a6a38SKuninori Morimoto /* 16092c7b696aSMarcel Ziswiler * Trim special characters, and replace '-' with '_' since '-' is used to 1610345233d7SLiam Girdwood * separate different DMI fields in the card long name. Only number and 1611345233d7SLiam Girdwood * alphabet characters and a few separator characters are kept. 1612345233d7SLiam Girdwood */ 1613345233d7SLiam Girdwood static void cleanup_dmi_name(char *name) 1614345233d7SLiam Girdwood { 1615345233d7SLiam Girdwood int i, j = 0; 1616345233d7SLiam Girdwood 1617345233d7SLiam Girdwood for (i = 0; name[i]; i++) { 1618345233d7SLiam Girdwood if (isalnum(name[i]) || (name[i] == '.') 1619345233d7SLiam Girdwood || (name[i] == '_')) 1620345233d7SLiam Girdwood name[j++] = name[i]; 1621345233d7SLiam Girdwood else if (name[i] == '-') 1622345233d7SLiam Girdwood name[j++] = '_'; 1623345233d7SLiam Girdwood } 1624345233d7SLiam Girdwood 1625345233d7SLiam Girdwood name[j] = '\0'; 1626345233d7SLiam Girdwood } 1627345233d7SLiam Girdwood 16282c7b696aSMarcel Ziswiler /* 16292c7b696aSMarcel Ziswiler * Check if a DMI field is valid, i.e. not containing any string 163098faf436SMengdong Lin * in the black list. 163198faf436SMengdong Lin */ 163298faf436SMengdong Lin static int is_dmi_valid(const char *field) 163398faf436SMengdong Lin { 163498faf436SMengdong Lin int i = 0; 163598faf436SMengdong Lin 163698faf436SMengdong Lin while (dmi_blacklist[i]) { 163798faf436SMengdong Lin if (strstr(field, dmi_blacklist[i])) 163898faf436SMengdong Lin return 0; 163998faf436SMengdong Lin i++; 164046b5a4d2SWu Fengguang } 164198faf436SMengdong Lin 164298faf436SMengdong Lin return 1; 164398faf436SMengdong Lin } 164498faf436SMengdong Lin 16454e01e5dbSJaroslav Kysela /* 16464e01e5dbSJaroslav Kysela * Append a string to card->dmi_longname with character cleanups. 16474e01e5dbSJaroslav Kysela */ 16484e01e5dbSJaroslav Kysela static void append_dmi_string(struct snd_soc_card *card, const char *str) 16494e01e5dbSJaroslav Kysela { 16504e01e5dbSJaroslav Kysela char *dst = card->dmi_longname; 16514e01e5dbSJaroslav Kysela size_t dst_len = sizeof(card->dmi_longname); 16524e01e5dbSJaroslav Kysela size_t len; 16534e01e5dbSJaroslav Kysela 16544e01e5dbSJaroslav Kysela len = strlen(dst); 16554e01e5dbSJaroslav Kysela snprintf(dst + len, dst_len - len, "-%s", str); 16564e01e5dbSJaroslav Kysela 16574e01e5dbSJaroslav Kysela len++; /* skip the separator "-" */ 16584e01e5dbSJaroslav Kysela if (len < dst_len) 16594e01e5dbSJaroslav Kysela cleanup_dmi_name(dst + len); 16604e01e5dbSJaroslav Kysela } 16614e01e5dbSJaroslav Kysela 1662345233d7SLiam Girdwood /** 1663345233d7SLiam Girdwood * snd_soc_set_dmi_name() - Register DMI names to card 1664345233d7SLiam Girdwood * @card: The card to register DMI names 1665345233d7SLiam Girdwood * @flavour: The flavour "differentiator" for the card amongst its peers. 1666345233d7SLiam Girdwood * 1667345233d7SLiam Girdwood * An Intel machine driver may be used by many different devices but are 1668345233d7SLiam Girdwood * difficult for userspace to differentiate, since machine drivers ususally 1669345233d7SLiam Girdwood * use their own name as the card short name and leave the card long name 1670345233d7SLiam Girdwood * blank. To differentiate such devices and fix bugs due to lack of 1671345233d7SLiam Girdwood * device-specific configurations, this function allows DMI info to be used 1672345233d7SLiam Girdwood * as the sound card long name, in the format of 1673345233d7SLiam Girdwood * "vendor-product-version-board" 1674345233d7SLiam Girdwood * (Character '-' is used to separate different DMI fields here). 1675345233d7SLiam Girdwood * This will help the user space to load the device-specific Use Case Manager 1676345233d7SLiam Girdwood * (UCM) configurations for the card. 1677345233d7SLiam Girdwood * 1678345233d7SLiam Girdwood * Possible card long names may be: 1679345233d7SLiam Girdwood * DellInc.-XPS139343-01-0310JH 1680345233d7SLiam Girdwood * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA 1681345233d7SLiam Girdwood * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX 1682345233d7SLiam Girdwood * 1683345233d7SLiam Girdwood * This function also supports flavoring the card longname to provide 1684345233d7SLiam Girdwood * the extra differentiation, like "vendor-product-version-board-flavor". 1685345233d7SLiam Girdwood * 1686345233d7SLiam Girdwood * We only keep number and alphabet characters and a few separator characters 1687345233d7SLiam Girdwood * in the card long name since UCM in the user space uses the card long names 1688345233d7SLiam Girdwood * as card configuration directory names and AudoConf cannot support special 1689345233d7SLiam Girdwood * charactors like SPACE. 1690345233d7SLiam Girdwood * 1691345233d7SLiam Girdwood * Returns 0 on success, otherwise a negative error code. 1692345233d7SLiam Girdwood */ 1693345233d7SLiam Girdwood int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) 1694345233d7SLiam Girdwood { 1695345233d7SLiam Girdwood const char *vendor, *product, *product_version, *board; 1696345233d7SLiam Girdwood 1697345233d7SLiam Girdwood if (card->long_name) 1698345233d7SLiam Girdwood return 0; /* long name already set by driver or from DMI */ 1699345233d7SLiam Girdwood 17004e01e5dbSJaroslav Kysela /* make up dmi long name as: vendor-product-version-board */ 1701345233d7SLiam Girdwood vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 170298faf436SMengdong Lin if (!vendor || !is_dmi_valid(vendor)) { 1703345233d7SLiam Girdwood dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); 1704345233d7SLiam Girdwood return 0; 1705345233d7SLiam Girdwood } 1706345233d7SLiam Girdwood 17074e01e5dbSJaroslav Kysela snprintf(card->dmi_longname, sizeof(card->dmi_longname), "%s", vendor); 1708345233d7SLiam Girdwood cleanup_dmi_name(card->dmi_longname); 1709345233d7SLiam Girdwood 1710345233d7SLiam Girdwood product = dmi_get_system_info(DMI_PRODUCT_NAME); 171198faf436SMengdong Lin if (product && is_dmi_valid(product)) { 17124e01e5dbSJaroslav Kysela append_dmi_string(card, product); 1713345233d7SLiam Girdwood 17142c7b696aSMarcel Ziswiler /* 17152c7b696aSMarcel Ziswiler * some vendors like Lenovo may only put a self-explanatory 1716345233d7SLiam Girdwood * name in the product version field 1717345233d7SLiam Girdwood */ 1718345233d7SLiam Girdwood product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); 17194e01e5dbSJaroslav Kysela if (product_version && is_dmi_valid(product_version)) 17204e01e5dbSJaroslav Kysela append_dmi_string(card, product_version); 1721345233d7SLiam Girdwood } 1722345233d7SLiam Girdwood 1723345233d7SLiam Girdwood board = dmi_get_system_info(DMI_BOARD_NAME); 172498faf436SMengdong Lin if (board && is_dmi_valid(board)) { 172539870b0dSJaroslav Kysela if (!product || strcasecmp(board, product)) 17264e01e5dbSJaroslav Kysela append_dmi_string(card, board); 1727345233d7SLiam Girdwood } else if (!product) { 1728345233d7SLiam Girdwood /* fall back to using legacy name */ 1729345233d7SLiam Girdwood dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); 1730345233d7SLiam Girdwood return 0; 1731345233d7SLiam Girdwood } 1732345233d7SLiam Girdwood 1733345233d7SLiam Girdwood /* Add flavour to dmi long name */ 17344e01e5dbSJaroslav Kysela if (flavour) 17354e01e5dbSJaroslav Kysela append_dmi_string(card, flavour); 1736345233d7SLiam Girdwood 1737345233d7SLiam Girdwood /* set the card long name */ 1738345233d7SLiam Girdwood card->long_name = card->dmi_longname; 1739345233d7SLiam Girdwood 1740345233d7SLiam Girdwood return 0; 1741345233d7SLiam Girdwood } 1742345233d7SLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); 17431f5a4535STakashi Iwai #endif /* CONFIG_DMI */ 1744345233d7SLiam Girdwood 1745a655de80SLiam Girdwood static void soc_check_tplg_fes(struct snd_soc_card *card) 1746a655de80SLiam Girdwood { 1747a655de80SLiam Girdwood struct snd_soc_component *component; 1748a655de80SLiam Girdwood const struct snd_soc_component_driver *comp_drv; 1749a655de80SLiam Girdwood struct snd_soc_dai_link *dai_link; 1750a655de80SLiam Girdwood int i; 1751a655de80SLiam Girdwood 1752368dee94SKuninori Morimoto for_each_component(component) { 1753a655de80SLiam Girdwood 175449f9c4f2SDaniel Baluta /* does this component override BEs ? */ 1755a655de80SLiam Girdwood if (!component->driver->ignore_machine) 1756a655de80SLiam Girdwood continue; 1757a655de80SLiam Girdwood 1758a655de80SLiam Girdwood /* for this machine ? */ 1759e194098bSPierre-Louis Bossart if (!strcmp(component->driver->ignore_machine, 1760a655de80SLiam Girdwood card->dev->driver->name)) 1761e194098bSPierre-Louis Bossart goto match; 1762e194098bSPierre-Louis Bossart if (strcmp(component->driver->ignore_machine, 1763e194098bSPierre-Louis Bossart dev_name(card->dev))) 1764a655de80SLiam Girdwood continue; 1765e194098bSPierre-Louis Bossart match: 1766a655de80SLiam Girdwood /* machine matches, so override the rtd data */ 17677fe072b4SKuninori Morimoto for_each_card_prelinks(card, i, dai_link) { 1768a655de80SLiam Girdwood 1769a655de80SLiam Girdwood /* ignore this FE */ 1770a655de80SLiam Girdwood if (dai_link->dynamic) { 1771a655de80SLiam Girdwood dai_link->ignore = true; 1772a655de80SLiam Girdwood continue; 1773a655de80SLiam Girdwood } 1774a655de80SLiam Girdwood 177549f9c4f2SDaniel Baluta dev_info(card->dev, "info: override BE DAI link %s\n", 1776a655de80SLiam Girdwood card->dai_link[i].name); 1777a655de80SLiam Girdwood 1778a655de80SLiam Girdwood /* override platform component */ 1779adb76b5bSKuninori Morimoto if (!dai_link->platforms) { 1780daecf46eSKuninori Morimoto dev_err(card->dev, "init platform error"); 1781daecf46eSKuninori Morimoto continue; 1782daecf46eSKuninori Morimoto } 1783910fdcabSKuninori Morimoto dai_link->platforms->name = component->name; 1784a655de80SLiam Girdwood 1785a655de80SLiam Girdwood /* convert non BE into BE */ 1786a655de80SLiam Girdwood dai_link->no_pcm = 1; 1787a655de80SLiam Girdwood 1788a655de80SLiam Girdwood /* override any BE fixups */ 1789a655de80SLiam Girdwood dai_link->be_hw_params_fixup = 1790a655de80SLiam Girdwood component->driver->be_hw_params_fixup; 1791a655de80SLiam Girdwood 17922c7b696aSMarcel Ziswiler /* 17932c7b696aSMarcel Ziswiler * most BE links don't set stream name, so set it to 1794a655de80SLiam Girdwood * dai link name if it's NULL to help bind widgets. 1795a655de80SLiam Girdwood */ 1796a655de80SLiam Girdwood if (!dai_link->stream_name) 1797a655de80SLiam Girdwood dai_link->stream_name = dai_link->name; 1798a655de80SLiam Girdwood } 1799a655de80SLiam Girdwood 1800a655de80SLiam Girdwood /* Inform userspace we are using alternate topology */ 1801a655de80SLiam Girdwood if (component->driver->topology_name_prefix) { 1802a655de80SLiam Girdwood 1803a655de80SLiam Girdwood /* topology shortname created? */ 1804a655de80SLiam Girdwood if (!card->topology_shortname_created) { 1805a655de80SLiam Girdwood comp_drv = component->driver; 1806a655de80SLiam Girdwood 1807a655de80SLiam Girdwood snprintf(card->topology_shortname, 32, "%s-%s", 1808a655de80SLiam Girdwood comp_drv->topology_name_prefix, 1809a655de80SLiam Girdwood card->name); 1810a655de80SLiam Girdwood card->topology_shortname_created = true; 1811a655de80SLiam Girdwood } 1812a655de80SLiam Girdwood 1813a655de80SLiam Girdwood /* use topology shortname */ 1814a655de80SLiam Girdwood card->name = card->topology_shortname; 1815a655de80SLiam Girdwood } 1816a655de80SLiam Girdwood } 1817a655de80SLiam Girdwood } 1818a655de80SLiam Girdwood 18190f23f718SKuninori Morimoto #define soc_setup_card_name(name, name1, name2, norm) \ 18200f23f718SKuninori Morimoto __soc_setup_card_name(name, sizeof(name), name1, name2, norm) 18210f23f718SKuninori Morimoto static void __soc_setup_card_name(char *name, int len, 18220f23f718SKuninori Morimoto const char *name1, const char *name2, 18230f23f718SKuninori Morimoto int normalization) 18240f23f718SKuninori Morimoto { 18250f23f718SKuninori Morimoto int i; 18260f23f718SKuninori Morimoto 18270f23f718SKuninori Morimoto snprintf(name, len, "%s", name1 ? name1 : name2); 18280f23f718SKuninori Morimoto 18290f23f718SKuninori Morimoto if (!normalization) 18300f23f718SKuninori Morimoto return; 18310f23f718SKuninori Morimoto 18320f23f718SKuninori Morimoto /* 18330f23f718SKuninori Morimoto * Name normalization 18340f23f718SKuninori Morimoto * 18350f23f718SKuninori Morimoto * The driver name is somewhat special, as it's used as a key for 18360f23f718SKuninori Morimoto * searches in the user-space. 18370f23f718SKuninori Morimoto * 18380f23f718SKuninori Morimoto * ex) 18390f23f718SKuninori Morimoto * "abcd??efg" -> "abcd__efg" 18400f23f718SKuninori Morimoto */ 18410f23f718SKuninori Morimoto for (i = 0; i < len; i++) { 18420f23f718SKuninori Morimoto switch (name[i]) { 18430f23f718SKuninori Morimoto case '_': 18440f23f718SKuninori Morimoto case '-': 18450f23f718SKuninori Morimoto case '\0': 18460f23f718SKuninori Morimoto break; 18470f23f718SKuninori Morimoto default: 18480f23f718SKuninori Morimoto if (!isalnum(name[i])) 18490f23f718SKuninori Morimoto name[i] = '_'; 18500f23f718SKuninori Morimoto break; 18510f23f718SKuninori Morimoto } 18520f23f718SKuninori Morimoto } 18530f23f718SKuninori Morimoto } 18540f23f718SKuninori Morimoto 1855ce21401cSKuninori Morimoto static void soc_cleanup_card_resources(struct snd_soc_card *card, 1856ce21401cSKuninori Morimoto int card_probed) 185753e947a0SKuninori Morimoto { 1858cc733900SKuninori Morimoto struct snd_soc_pcm_runtime *rtd, *n; 18597ce6088fSKuninori Morimoto 18600ced7b05SKuninori Morimoto if (card->snd_card) 18610ced7b05SKuninori Morimoto snd_card_disconnect_sync(card->snd_card); 186253e947a0SKuninori Morimoto 18632a6f0892SKuninori Morimoto snd_soc_dapm_shutdown(card); 18642a6f0892SKuninori Morimoto 186553e947a0SKuninori Morimoto /* remove and free each DAI */ 18667ce6088fSKuninori Morimoto soc_remove_link_dais(card); 18670ced7b05SKuninori Morimoto soc_remove_link_components(card); 18687ce6088fSKuninori Morimoto 1869cc733900SKuninori Morimoto for_each_card_rtds_safe(card, rtd, n) 187050cd9b53SKuninori Morimoto snd_soc_remove_pcm_runtime(card, rtd); 18717ce6088fSKuninori Morimoto 187253e947a0SKuninori Morimoto /* remove auxiliary devices */ 187353e947a0SKuninori Morimoto soc_remove_aux_devices(card); 1874e8fbd250SKuninori Morimoto soc_unbind_aux_dev(card); 187553e947a0SKuninori Morimoto 187653e947a0SKuninori Morimoto snd_soc_dapm_free(&card->dapm); 187753e947a0SKuninori Morimoto soc_cleanup_card_debugfs(card); 187853e947a0SKuninori Morimoto 187953e947a0SKuninori Morimoto /* remove the card */ 1880ce21401cSKuninori Morimoto if (card_probed && card->remove) 188153e947a0SKuninori Morimoto card->remove(card); 18820ced7b05SKuninori Morimoto 18830ced7b05SKuninori Morimoto if (card->snd_card) { 18840ced7b05SKuninori Morimoto snd_card_free(card->snd_card); 18850ced7b05SKuninori Morimoto card->snd_card = NULL; 18860ced7b05SKuninori Morimoto } 188753e947a0SKuninori Morimoto } 188853e947a0SKuninori Morimoto 18892cc1afcfSKuninori Morimoto static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) 18902cc1afcfSKuninori Morimoto { 18912cc1afcfSKuninori Morimoto if (card->instantiated) { 1892ce21401cSKuninori Morimoto int card_probed = 1; 1893ce21401cSKuninori Morimoto 18942cc1afcfSKuninori Morimoto card->instantiated = false; 18952cc1afcfSKuninori Morimoto snd_soc_flush_all_delayed_work(card); 18962cc1afcfSKuninori Morimoto 1897ce21401cSKuninori Morimoto soc_cleanup_card_resources(card, card_probed); 18982cc1afcfSKuninori Morimoto if (!unregister) 18992cc1afcfSKuninori Morimoto list_add(&card->list, &unbind_card_list); 19002cc1afcfSKuninori Morimoto } else { 19012cc1afcfSKuninori Morimoto if (unregister) 19022cc1afcfSKuninori Morimoto list_del(&card->list); 19032cc1afcfSKuninori Morimoto } 19042cc1afcfSKuninori Morimoto } 19052cc1afcfSKuninori Morimoto 1906ed90c013SKuninori Morimoto static int snd_soc_bind_card(struct snd_soc_card *card) 1907f0fba2adSLiam Girdwood { 19081a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 190961b0088bSMengdong Lin struct snd_soc_dai_link *dai_link; 1910ce21401cSKuninori Morimoto int ret, i, card_probed = 0; 191196dd3622SMark Brown 191234e81ab4SLars-Peter Clausen mutex_lock(&client_mutex); 191301b9d99aSLiam Girdwood mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); 1914f0fba2adSLiam Girdwood 191595c267ddSKuninori Morimoto snd_soc_dapm_init(&card->dapm, card, NULL); 191653e947a0SKuninori Morimoto 1917a655de80SLiam Girdwood /* check whether any platform is ignore machine FE and using topology */ 1918a655de80SLiam Girdwood soc_check_tplg_fes(card); 1919a655de80SLiam Girdwood 192044c69bb1SLars-Peter Clausen /* bind aux_devs too */ 1921bee886f1SKuninori Morimoto ret = soc_bind_aux_dev(card); 1922bee886f1SKuninori Morimoto if (ret < 0) 192353e947a0SKuninori Morimoto goto probe_end; 1924db2a4165SFrank Mandarino 1925f8f80361SMengdong Lin /* add predefined DAI links to the list */ 1926d8145989SKuninori Morimoto card->num_rtd = 0; 19275b99a0aaSKuninori Morimoto for_each_card_prelinks(card, i, dai_link) { 19280c048004SKuninori Morimoto ret = snd_soc_add_pcm_runtime(card, dai_link); 19295b99a0aaSKuninori Morimoto if (ret < 0) 19305b99a0aaSKuninori Morimoto goto probe_end; 19315b99a0aaSKuninori Morimoto } 1932f8f80361SMengdong Lin 1933f0fba2adSLiam Girdwood /* card bind complete so register a sound card */ 1934102b5a8dSTakashi Iwai ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 1935f0fba2adSLiam Girdwood card->owner, 0, &card->snd_card); 1936f0fba2adSLiam Girdwood if (ret < 0) { 193710e8aa9aSMichał Mirosław dev_err(card->dev, 193810e8aa9aSMichał Mirosław "ASoC: can't create sound card for card %s: %d\n", 193910e8aa9aSMichał Mirosław card->name, ret); 194053e947a0SKuninori Morimoto goto probe_end; 1941db2a4165SFrank Mandarino } 1942db2a4165SFrank Mandarino 19430757d834SLars-Peter Clausen soc_init_card_debugfs(card); 19440757d834SLars-Peter Clausen 1945b3da4251SKuninori Morimoto soc_resume_init(card); 19466ed25978SAndy Green 1947b8ba3b57SKuninori Morimoto ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, 19489a841ebbSMark Brown card->num_dapm_widgets); 1949b8ba3b57SKuninori Morimoto if (ret < 0) 1950b8ba3b57SKuninori Morimoto goto probe_end; 19519a841ebbSMark Brown 1952b8ba3b57SKuninori Morimoto ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, 1953f23e860eSNicolin Chen card->num_of_dapm_widgets); 1954b8ba3b57SKuninori Morimoto if (ret < 0) 1955b8ba3b57SKuninori Morimoto goto probe_end; 1956f23e860eSNicolin Chen 1957f0fba2adSLiam Girdwood /* initialise the sound card only once */ 1958f0fba2adSLiam Girdwood if (card->probe) { 1959e7361ec4SMark Brown ret = card->probe(card); 1960f0fba2adSLiam Girdwood if (ret < 0) 196153e947a0SKuninori Morimoto goto probe_end; 1962ce21401cSKuninori Morimoto card_probed = 1; 1963f0fba2adSLiam Girdwood } 1964f0fba2adSLiam Girdwood 196562ae68faSStephen Warren /* probe all components used by DAI links on this card */ 196662f07a6bSKuninori Morimoto ret = soc_probe_link_components(card); 196762ae68faSStephen Warren if (ret < 0) { 1968f110bfc7SLiam Girdwood dev_err(card->dev, 196962f07a6bSKuninori Morimoto "ASoC: failed to instantiate card %d\n", ret); 197053e947a0SKuninori Morimoto goto probe_end; 197162ae68faSStephen Warren } 197262ae68faSStephen Warren 1973f2ed6b07SMengdong Lin /* probe auxiliary components */ 1974f2ed6b07SMengdong Lin ret = soc_probe_aux_devices(card); 197574bd3f92SKuninori Morimoto if (ret < 0) { 197674bd3f92SKuninori Morimoto dev_err(card->dev, 197774bd3f92SKuninori Morimoto "ASoC: failed to probe aux component %d\n", ret); 197853e947a0SKuninori Morimoto goto probe_end; 197974bd3f92SKuninori Morimoto } 1980f2ed6b07SMengdong Lin 198162ae68faSStephen Warren /* probe all DAI links on this card */ 1982c7e73774SKuninori Morimoto ret = soc_probe_link_dais(card); 1983fe3e78e0SMark Brown if (ret < 0) { 1984f110bfc7SLiam Girdwood dev_err(card->dev, 1985c7e73774SKuninori Morimoto "ASoC: failed to instantiate card %d\n", ret); 198653e947a0SKuninori Morimoto goto probe_end; 1987fe3e78e0SMark Brown } 1988fe3e78e0SMark Brown 1989626c2e57SKuninori Morimoto for_each_card_rtds(card, rtd) { 1990eaffeefbSKuninori Morimoto ret = soc_init_pcm_runtime(card, rtd); 1991626c2e57SKuninori Morimoto if (ret < 0) 1992626c2e57SKuninori Morimoto goto probe_end; 1993626c2e57SKuninori Morimoto } 1994c4b46982SKuninori Morimoto 1995888df395SMark Brown snd_soc_dapm_link_dai_widgets(card); 1996b893ea5fSLiam Girdwood snd_soc_dapm_connect_dai_link_widgets(card); 1997888df395SMark Brown 19989b98c7c2SKuninori Morimoto ret = snd_soc_add_card_controls(card, card->controls, 19992c7b696aSMarcel Ziswiler card->num_controls); 20009b98c7c2SKuninori Morimoto if (ret < 0) 20019b98c7c2SKuninori Morimoto goto probe_end; 2002b7af1dafSMark Brown 2003daa480bdSKuninori Morimoto ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, 2004b8ad29deSMark Brown card->num_dapm_routes); 2005daa480bdSKuninori Morimoto if (ret < 0) 2006daa480bdSKuninori Morimoto goto probe_end; 2007b8ad29deSMark Brown 2008daa480bdSKuninori Morimoto ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, 2009f23e860eSNicolin Chen card->num_of_dapm_routes); 2010daa480bdSKuninori Morimoto if (ret < 0) 2011daa480bdSKuninori Morimoto goto probe_end; 201275d9ac46SMark Brown 2013861886d3STakashi Iwai /* try to set some sane longname if DMI is available */ 2014861886d3STakashi Iwai snd_soc_set_dmi_name(card, NULL); 2015861886d3STakashi Iwai 20160f23f718SKuninori Morimoto soc_setup_card_name(card->snd_card->shortname, 20170f23f718SKuninori Morimoto card->name, NULL, 0); 20180f23f718SKuninori Morimoto soc_setup_card_name(card->snd_card->longname, 20190f23f718SKuninori Morimoto card->long_name, card->name, 0); 20200f23f718SKuninori Morimoto soc_setup_card_name(card->snd_card->driver, 20210f23f718SKuninori Morimoto card->driver_name, card->name, 1); 2022fe3e78e0SMark Brown 2023dc73d73aSJaroslav Kysela if (card->components) { 2024dc73d73aSJaroslav Kysela /* the current implementation of snd_component_add() accepts */ 2025dc73d73aSJaroslav Kysela /* multiple components in the string separated by space, */ 2026dc73d73aSJaroslav Kysela /* but the string collision (identical string) check might */ 2027dc73d73aSJaroslav Kysela /* not work correctly */ 2028dc73d73aSJaroslav Kysela ret = snd_component_add(card->snd_card, card->components); 2029dc73d73aSJaroslav Kysela if (ret < 0) { 2030dc73d73aSJaroslav Kysela dev_err(card->dev, "ASoC: %s snd_component_add() failed: %d\n", 2031dc73d73aSJaroslav Kysela card->name, ret); 2032dc73d73aSJaroslav Kysela goto probe_end; 2033dc73d73aSJaroslav Kysela } 2034dc73d73aSJaroslav Kysela } 2035dc73d73aSJaroslav Kysela 203628e9ad92SMark Brown if (card->late_probe) { 203728e9ad92SMark Brown ret = card->late_probe(card); 203828e9ad92SMark Brown if (ret < 0) { 2039f110bfc7SLiam Girdwood dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", 204028e9ad92SMark Brown card->name, ret); 204153e947a0SKuninori Morimoto goto probe_end; 204228e9ad92SMark Brown } 204328e9ad92SMark Brown } 2044ce21401cSKuninori Morimoto card_probed = 1; 204528e9ad92SMark Brown 2046824ef826SLars-Peter Clausen snd_soc_dapm_new_widgets(card); 20478c193b8dSLars-Peter Clausen 2048f0fba2adSLiam Girdwood ret = snd_card_register(card->snd_card); 2049fe3e78e0SMark Brown if (ret < 0) { 2050f110bfc7SLiam Girdwood dev_err(card->dev, "ASoC: failed to register soundcard %d\n", 2051f110bfc7SLiam Girdwood ret); 205253e947a0SKuninori Morimoto goto probe_end; 2053fe3e78e0SMark Brown } 2054fe3e78e0SMark Brown 2055435c5e25SMark Brown card->instantiated = 1; 2056882eab6cSTzung-Bi Shih dapm_mark_endpoints_dirty(card); 20574f4c0072SMark Brown snd_soc_dapm_sync(&card->dapm); 2058b19e6e7bSMark Brown 2059ed90c013SKuninori Morimoto /* deactivate pins to sleep state */ 2060ed90c013SKuninori Morimoto for_each_card_rtds(card, rtd) { 2061ed90c013SKuninori Morimoto struct snd_soc_dai *dai; 2062ed90c013SKuninori Morimoto 2063ed90c013SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, dai) { 2064ed90c013SKuninori Morimoto if (!dai->active) 2065ed90c013SKuninori Morimoto pinctrl_pm_select_sleep_state(dai->dev); 2066ed90c013SKuninori Morimoto } 2067ed90c013SKuninori Morimoto 2068ed90c013SKuninori Morimoto if (!rtd->cpu_dai->active) 2069ed90c013SKuninori Morimoto pinctrl_pm_select_sleep_state(rtd->cpu_dai->dev); 2070ed90c013SKuninori Morimoto } 2071ed90c013SKuninori Morimoto 207253e947a0SKuninori Morimoto probe_end: 207353e947a0SKuninori Morimoto if (ret < 0) 2074ce21401cSKuninori Morimoto soc_cleanup_card_resources(card, card_probed); 2075db2a4165SFrank Mandarino 2076f0fba2adSLiam Girdwood mutex_unlock(&card->mutex); 207734e81ab4SLars-Peter Clausen mutex_unlock(&client_mutex); 2078db2a4165SFrank Mandarino 2079b19e6e7bSMark Brown return ret; 2080435c5e25SMark Brown } 2081435c5e25SMark Brown 2082435c5e25SMark Brown /* probes a new socdev */ 2083435c5e25SMark Brown static int soc_probe(struct platform_device *pdev) 2084435c5e25SMark Brown { 2085f0fba2adSLiam Girdwood struct snd_soc_card *card = platform_get_drvdata(pdev); 2086435c5e25SMark Brown 208770a7ca34SVinod Koul /* 208870a7ca34SVinod Koul * no card, so machine driver should be registering card 208970a7ca34SVinod Koul * we should not be here in that case so ret error 209070a7ca34SVinod Koul */ 209170a7ca34SVinod Koul if (!card) 209270a7ca34SVinod Koul return -EINVAL; 209370a7ca34SVinod Koul 2094fe4085e8SMark Brown dev_warn(&pdev->dev, 2095f110bfc7SLiam Girdwood "ASoC: machine %s should use snd_soc_register_card()\n", 2096fe4085e8SMark Brown card->name); 2097fe4085e8SMark Brown 2098435c5e25SMark Brown /* Bodge while we unpick instantiation */ 2099435c5e25SMark Brown card->dev = &pdev->dev; 2100f0fba2adSLiam Girdwood 210128d528c8SMark Brown return snd_soc_register_card(card); 2102435c5e25SMark Brown } 2103435c5e25SMark Brown 2104b0e26485SVinod Koul /* removes a socdev */ 2105b0e26485SVinod Koul static int soc_remove(struct platform_device *pdev) 2106b0e26485SVinod Koul { 2107b0e26485SVinod Koul struct snd_soc_card *card = platform_get_drvdata(pdev); 2108b0e26485SVinod Koul 2109c5af3a2eSMark Brown snd_soc_unregister_card(card); 2110db2a4165SFrank Mandarino return 0; 2111db2a4165SFrank Mandarino } 2112db2a4165SFrank Mandarino 21136f8ab4acSMark Brown int snd_soc_poweroff(struct device *dev) 211451737470SMark Brown { 21156f8ab4acSMark Brown struct snd_soc_card *card = dev_get_drvdata(dev); 21161a497983SMengdong Lin struct snd_soc_pcm_runtime *rtd; 211751737470SMark Brown 211851737470SMark Brown if (!card->instantiated) 2119416356fcSMark Brown return 0; 212051737470SMark Brown 21212c7b696aSMarcel Ziswiler /* 21222c7b696aSMarcel Ziswiler * Flush out pmdown_time work - we actually do want to run it 21232c7b696aSMarcel Ziswiler * now, we're shutting down so no imminent restart. 21242c7b696aSMarcel Ziswiler */ 212565462e44SKuninori Morimoto snd_soc_flush_all_delayed_work(card); 212651737470SMark Brown 2127f0fba2adSLiam Girdwood snd_soc_dapm_shutdown(card); 2128416356fcSMark Brown 2129988e8cc4SNicolin Chen /* deactivate pins to sleep state */ 2130bcb1fd1fSKuninori Morimoto for_each_card_rtds(card, rtd) { 213188bd870fSBenoit Cousson struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 21320b7990e3SKuninori Morimoto struct snd_soc_dai *codec_dai; 21331a497983SMengdong Lin int i; 213488bd870fSBenoit Cousson 2135988e8cc4SNicolin Chen pinctrl_pm_select_sleep_state(cpu_dai->dev); 21360b7990e3SKuninori Morimoto for_each_rtd_codec_dai(rtd, i, codec_dai) { 213788bd870fSBenoit Cousson pinctrl_pm_select_sleep_state(codec_dai->dev); 213888bd870fSBenoit Cousson } 2139988e8cc4SNicolin Chen } 2140988e8cc4SNicolin Chen 2141416356fcSMark Brown return 0; 214251737470SMark Brown } 21436f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_poweroff); 214451737470SMark Brown 21456f8ab4acSMark Brown const struct dev_pm_ops snd_soc_pm_ops = { 2146b1dd5897SViresh Kumar .suspend = snd_soc_suspend, 2147b1dd5897SViresh Kumar .resume = snd_soc_resume, 2148b1dd5897SViresh Kumar .freeze = snd_soc_suspend, 2149b1dd5897SViresh Kumar .thaw = snd_soc_resume, 21506f8ab4acSMark Brown .poweroff = snd_soc_poweroff, 2151b1dd5897SViresh Kumar .restore = snd_soc_resume, 2152416356fcSMark Brown }; 2153deb2607eSStephen Warren EXPORT_SYMBOL_GPL(snd_soc_pm_ops); 2154416356fcSMark Brown 2155db2a4165SFrank Mandarino /* ASoC platform driver */ 2156db2a4165SFrank Mandarino static struct platform_driver soc_driver = { 2157db2a4165SFrank Mandarino .driver = { 2158db2a4165SFrank Mandarino .name = "soc-audio", 21596f8ab4acSMark Brown .pm = &snd_soc_pm_ops, 2160db2a4165SFrank Mandarino }, 2161db2a4165SFrank Mandarino .probe = soc_probe, 2162db2a4165SFrank Mandarino .remove = soc_remove, 2163db2a4165SFrank Mandarino }; 2164db2a4165SFrank Mandarino 2165096e49d5SMark Brown /** 2166db2a4165SFrank Mandarino * snd_soc_cnew - create new control 2167db2a4165SFrank Mandarino * @_template: control template 2168db2a4165SFrank Mandarino * @data: control private data 2169ac11a2b3SMark Brown * @long_name: control long name 2170efb7ac3fSMark Brown * @prefix: control name prefix 2171db2a4165SFrank Mandarino * 2172db2a4165SFrank Mandarino * Create a new mixer control from a template control. 2173db2a4165SFrank Mandarino * 2174db2a4165SFrank Mandarino * Returns 0 for success, else error. 2175db2a4165SFrank Mandarino */ 2176db2a4165SFrank Mandarino struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, 21773056557fSMark Brown void *data, const char *long_name, 2178efb7ac3fSMark Brown const char *prefix) 2179db2a4165SFrank Mandarino { 2180db2a4165SFrank Mandarino struct snd_kcontrol_new template; 2181efb7ac3fSMark Brown struct snd_kcontrol *kcontrol; 2182efb7ac3fSMark Brown char *name = NULL; 2183db2a4165SFrank Mandarino 2184db2a4165SFrank Mandarino memcpy(&template, _template, sizeof(template)); 2185db2a4165SFrank Mandarino template.index = 0; 2186db2a4165SFrank Mandarino 2187efb7ac3fSMark Brown if (!long_name) 2188efb7ac3fSMark Brown long_name = template.name; 2189efb7ac3fSMark Brown 2190efb7ac3fSMark Brown if (prefix) { 21912b581074SLars-Peter Clausen name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name); 2192efb7ac3fSMark Brown if (!name) 2193efb7ac3fSMark Brown return NULL; 2194efb7ac3fSMark Brown 2195efb7ac3fSMark Brown template.name = name; 2196efb7ac3fSMark Brown } else { 2197efb7ac3fSMark Brown template.name = long_name; 2198efb7ac3fSMark Brown } 2199efb7ac3fSMark Brown 2200efb7ac3fSMark Brown kcontrol = snd_ctl_new1(&template, data); 2201efb7ac3fSMark Brown 2202efb7ac3fSMark Brown kfree(name); 2203efb7ac3fSMark Brown 2204efb7ac3fSMark Brown return kcontrol; 2205db2a4165SFrank Mandarino } 2206db2a4165SFrank Mandarino EXPORT_SYMBOL_GPL(snd_soc_cnew); 2207db2a4165SFrank Mandarino 2208022658beSLiam Girdwood static int snd_soc_add_controls(struct snd_card *card, struct device *dev, 2209022658beSLiam Girdwood const struct snd_kcontrol_new *controls, int num_controls, 2210022658beSLiam Girdwood const char *prefix, void *data) 2211022658beSLiam Girdwood { 2212022658beSLiam Girdwood int err, i; 2213022658beSLiam Girdwood 2214022658beSLiam Girdwood for (i = 0; i < num_controls; i++) { 2215022658beSLiam Girdwood const struct snd_kcontrol_new *control = &controls[i]; 22162c7b696aSMarcel Ziswiler 2217022658beSLiam Girdwood err = snd_ctl_add(card, snd_soc_cnew(control, data, 2218022658beSLiam Girdwood control->name, prefix)); 2219022658beSLiam Girdwood if (err < 0) { 2220f110bfc7SLiam Girdwood dev_err(dev, "ASoC: Failed to add %s: %d\n", 2221f110bfc7SLiam Girdwood control->name, err); 2222022658beSLiam Girdwood return err; 2223022658beSLiam Girdwood } 2224022658beSLiam Girdwood } 2225022658beSLiam Girdwood 2226022658beSLiam Girdwood return 0; 2227022658beSLiam Girdwood } 2228022658beSLiam Girdwood 22294fefd698SDimitris Papastamos struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, 22304fefd698SDimitris Papastamos const char *name) 22314fefd698SDimitris Papastamos { 22324fefd698SDimitris Papastamos struct snd_card *card = soc_card->snd_card; 22334fefd698SDimitris Papastamos struct snd_kcontrol *kctl; 22344fefd698SDimitris Papastamos 22354fefd698SDimitris Papastamos if (unlikely(!name)) 22364fefd698SDimitris Papastamos return NULL; 22374fefd698SDimitris Papastamos 22384fefd698SDimitris Papastamos list_for_each_entry(kctl, &card->controls, list) 22394fefd698SDimitris Papastamos if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) 22404fefd698SDimitris Papastamos return kctl; 22414fefd698SDimitris Papastamos return NULL; 22424fefd698SDimitris Papastamos } 22434fefd698SDimitris Papastamos EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); 22444fefd698SDimitris Papastamos 2245db2a4165SFrank Mandarino /** 22460f2780adSLars-Peter Clausen * snd_soc_add_component_controls - Add an array of controls to a component. 22470f2780adSLars-Peter Clausen * 22480f2780adSLars-Peter Clausen * @component: Component to add controls to 22490f2780adSLars-Peter Clausen * @controls: Array of controls to add 22500f2780adSLars-Peter Clausen * @num_controls: Number of elements in the array 22510f2780adSLars-Peter Clausen * 22520f2780adSLars-Peter Clausen * Return: 0 for success, else error. 22530f2780adSLars-Peter Clausen */ 22540f2780adSLars-Peter Clausen int snd_soc_add_component_controls(struct snd_soc_component *component, 22550f2780adSLars-Peter Clausen const struct snd_kcontrol_new *controls, unsigned int num_controls) 22560f2780adSLars-Peter Clausen { 22570f2780adSLars-Peter Clausen struct snd_card *card = component->card->snd_card; 22580f2780adSLars-Peter Clausen 22590f2780adSLars-Peter Clausen return snd_soc_add_controls(card, component->dev, controls, 22600f2780adSLars-Peter Clausen num_controls, component->name_prefix, component); 22610f2780adSLars-Peter Clausen } 22620f2780adSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_add_component_controls); 22630f2780adSLars-Peter Clausen 22640f2780adSLars-Peter Clausen /** 2265022658beSLiam Girdwood * snd_soc_add_card_controls - add an array of controls to a SoC card. 2266022658beSLiam Girdwood * Convenience function to add a list of controls. 2267022658beSLiam Girdwood * 2268022658beSLiam Girdwood * @soc_card: SoC card to add controls to 2269022658beSLiam Girdwood * @controls: array of controls to add 2270022658beSLiam Girdwood * @num_controls: number of elements in the array 2271022658beSLiam Girdwood * 2272022658beSLiam Girdwood * Return 0 for success, else error. 2273022658beSLiam Girdwood */ 2274022658beSLiam Girdwood int snd_soc_add_card_controls(struct snd_soc_card *soc_card, 2275022658beSLiam Girdwood const struct snd_kcontrol_new *controls, int num_controls) 2276022658beSLiam Girdwood { 2277022658beSLiam Girdwood struct snd_card *card = soc_card->snd_card; 2278022658beSLiam Girdwood 2279022658beSLiam Girdwood return snd_soc_add_controls(card, soc_card->dev, controls, num_controls, 2280022658beSLiam Girdwood NULL, soc_card); 2281022658beSLiam Girdwood } 2282022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); 2283022658beSLiam Girdwood 2284022658beSLiam Girdwood /** 2285022658beSLiam Girdwood * snd_soc_add_dai_controls - add an array of controls to a DAI. 2286022658beSLiam Girdwood * Convienience function to add a list of controls. 2287022658beSLiam Girdwood * 2288022658beSLiam Girdwood * @dai: DAI to add controls to 2289022658beSLiam Girdwood * @controls: array of controls to add 2290022658beSLiam Girdwood * @num_controls: number of elements in the array 2291022658beSLiam Girdwood * 2292022658beSLiam Girdwood * Return 0 for success, else error. 2293022658beSLiam Girdwood */ 2294022658beSLiam Girdwood int snd_soc_add_dai_controls(struct snd_soc_dai *dai, 2295022658beSLiam Girdwood const struct snd_kcontrol_new *controls, int num_controls) 2296022658beSLiam Girdwood { 2297313665b9SLars-Peter Clausen struct snd_card *card = dai->component->card->snd_card; 2298022658beSLiam Girdwood 2299022658beSLiam Girdwood return snd_soc_add_controls(card, dai->dev, controls, num_controls, 2300022658beSLiam Girdwood NULL, dai); 2301022658beSLiam Girdwood } 2302022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); 2303022658beSLiam Girdwood 2304c5af3a2eSMark Brown /** 2305c5af3a2eSMark Brown * snd_soc_register_card - Register a card with the ASoC core 2306c5af3a2eSMark Brown * 2307ac11a2b3SMark Brown * @card: Card to register 2308c5af3a2eSMark Brown * 2309c5af3a2eSMark Brown */ 231070a7ca34SVinod Koul int snd_soc_register_card(struct snd_soc_card *card) 2311c5af3a2eSMark Brown { 2312c5af3a2eSMark Brown if (!card->name || !card->dev) 2313c5af3a2eSMark Brown return -EINVAL; 2314c5af3a2eSMark Brown 2315ed77cc12SMark Brown dev_set_drvdata(card->dev, card); 2316ed77cc12SMark Brown 2317b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->widgets); 2318b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->paths); 2319b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->dapm_list); 2320b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->aux_comp_list); 2321b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->component_dev_list); 2322b03bfaecSKuninori Morimoto INIT_LIST_HEAD(&card->list); 23231a497983SMengdong Lin INIT_LIST_HEAD(&card->rtd_list); 2324db432b41SMark Brown INIT_LIST_HEAD(&card->dapm_dirty); 23258a978234SLiam Girdwood INIT_LIST_HEAD(&card->dobj_list); 2326b03bfaecSKuninori Morimoto 2327c5af3a2eSMark Brown card->instantiated = 0; 2328f0fba2adSLiam Girdwood mutex_init(&card->mutex); 2329a73fb2dfSLiam Girdwood mutex_init(&card->dapm_mutex); 233072b745e3SPeter Ujfalusi mutex_init(&card->pcm_mutex); 2331a9764869SKaiChieh Chuang spin_lock_init(&card->dpcm_lock); 2332c5af3a2eSMark Brown 2333e894efefSSrinivas Kandagatla return snd_soc_bind_card(card); 2334c5af3a2eSMark Brown } 233570a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_register_card); 2336c5af3a2eSMark Brown 2337c5af3a2eSMark Brown /** 2338c5af3a2eSMark Brown * snd_soc_unregister_card - Unregister a card with the ASoC core 2339c5af3a2eSMark Brown * 2340ac11a2b3SMark Brown * @card: Card to unregister 2341c5af3a2eSMark Brown * 2342c5af3a2eSMark Brown */ 234370a7ca34SVinod Koul int snd_soc_unregister_card(struct snd_soc_card *card) 2344c5af3a2eSMark Brown { 2345b545542aSKuninori Morimoto mutex_lock(&client_mutex); 2346e894efefSSrinivas Kandagatla snd_soc_unbind_card(card, true); 2347b545542aSKuninori Morimoto mutex_unlock(&client_mutex); 2348f110bfc7SLiam Girdwood dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); 2349c5af3a2eSMark Brown 2350c5af3a2eSMark Brown return 0; 2351c5af3a2eSMark Brown } 235270a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_unregister_card); 2353c5af3a2eSMark Brown 2354f0fba2adSLiam Girdwood /* 2355f0fba2adSLiam Girdwood * Simplify DAI link configuration by removing ".-1" from device names 2356f0fba2adSLiam Girdwood * and sanitizing names. 2357f0fba2adSLiam Girdwood */ 23580b9a214aSDimitris Papastamos static char *fmt_single_name(struct device *dev, int *id) 2359f0fba2adSLiam Girdwood { 2360f0fba2adSLiam Girdwood char *found, name[NAME_SIZE]; 2361f0fba2adSLiam Girdwood int id1, id2; 2362f0fba2adSLiam Girdwood 2363f0fba2adSLiam Girdwood if (dev_name(dev) == NULL) 2364f0fba2adSLiam Girdwood return NULL; 2365f0fba2adSLiam Girdwood 236658818a77SDimitris Papastamos strlcpy(name, dev_name(dev), NAME_SIZE); 2367f0fba2adSLiam Girdwood 2368f0fba2adSLiam Girdwood /* are we a "%s.%d" name (platform and SPI components) */ 2369f0fba2adSLiam Girdwood found = strstr(name, dev->driver->name); 2370f0fba2adSLiam Girdwood if (found) { 2371f0fba2adSLiam Girdwood /* get ID */ 2372f0fba2adSLiam Girdwood if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { 2373f0fba2adSLiam Girdwood 2374f0fba2adSLiam Girdwood /* discard ID from name if ID == -1 */ 2375f0fba2adSLiam Girdwood if (*id == -1) 2376f0fba2adSLiam Girdwood found[strlen(dev->driver->name)] = '\0'; 2377f0fba2adSLiam Girdwood } 2378f0fba2adSLiam Girdwood 2379f0fba2adSLiam Girdwood } else { 2380f0fba2adSLiam Girdwood /* I2C component devices are named "bus-addr" */ 2381f0fba2adSLiam Girdwood if (sscanf(name, "%x-%x", &id1, &id2) == 2) { 2382f0fba2adSLiam Girdwood char tmp[NAME_SIZE]; 2383f0fba2adSLiam Girdwood 2384f0fba2adSLiam Girdwood /* create unique ID number from I2C addr and bus */ 238505899446SJarkko Nikula *id = ((id1 & 0xffff) << 16) + id2; 2386f0fba2adSLiam Girdwood 2387f0fba2adSLiam Girdwood /* sanitize component name for DAI link creation */ 23882c7b696aSMarcel Ziswiler snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, 23892c7b696aSMarcel Ziswiler name); 239058818a77SDimitris Papastamos strlcpy(name, tmp, NAME_SIZE); 2391f0fba2adSLiam Girdwood } else 2392f0fba2adSLiam Girdwood *id = 0; 2393f0fba2adSLiam Girdwood } 2394f0fba2adSLiam Girdwood 239550014499SKuninori Morimoto return devm_kstrdup(dev, name, GFP_KERNEL); 2396f0fba2adSLiam Girdwood } 2397f0fba2adSLiam Girdwood 2398f0fba2adSLiam Girdwood /* 2399f0fba2adSLiam Girdwood * Simplify DAI link naming for single devices with multiple DAIs by removing 2400f0fba2adSLiam Girdwood * any ".-1" and using the DAI name (instead of device name). 2401f0fba2adSLiam Girdwood */ 2402f0fba2adSLiam Girdwood static inline char *fmt_multiple_name(struct device *dev, 2403f0fba2adSLiam Girdwood struct snd_soc_dai_driver *dai_drv) 2404f0fba2adSLiam Girdwood { 2405f0fba2adSLiam Girdwood if (dai_drv->name == NULL) { 240610e8aa9aSMichał Mirosław dev_err(dev, 240710e8aa9aSMichał Mirosław "ASoC: error - multiple DAI %s registered with no name\n", 240810e8aa9aSMichał Mirosław dev_name(dev)); 2409f0fba2adSLiam Girdwood return NULL; 2410f0fba2adSLiam Girdwood } 2411f0fba2adSLiam Girdwood 241250014499SKuninori Morimoto return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); 2413f0fba2adSLiam Girdwood } 2414f0fba2adSLiam Girdwood 2415ffdbca0bSKuninori Morimoto void snd_soc_unregister_dai(struct snd_soc_dai *dai) 2416e11381f3SKuninori Morimoto { 2417e11381f3SKuninori Morimoto dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); 2418e11381f3SKuninori Morimoto list_del(&dai->list); 2419e11381f3SKuninori Morimoto } 2420ffdbca0bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); 2421e11381f3SKuninori Morimoto 24227ca24386SKuninori Morimoto /** 24237ca24386SKuninori Morimoto * snd_soc_register_dai - Register a DAI dynamically & create its widgets 24247ca24386SKuninori Morimoto * 24257ca24386SKuninori Morimoto * @component: The component the DAIs are registered for 24267ca24386SKuninori Morimoto * @dai_drv: DAI driver to use for the DAI 2427bc9a6655SRandy Dunlap * @legacy_dai_naming: if %true, use legacy single-name format; 2428bc9a6655SRandy Dunlap * if %false, use multiple-name format; 24297ca24386SKuninori Morimoto * 24307ca24386SKuninori Morimoto * Topology can use this API to register DAIs when probing a component. 24317ca24386SKuninori Morimoto * These DAIs's widgets will be freed in the card cleanup and the DAIs 24327ca24386SKuninori Morimoto * will be freed in the component cleanup. 24337ca24386SKuninori Morimoto */ 24347ca24386SKuninori Morimoto struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, 24355e4fb372SMengdong Lin struct snd_soc_dai_driver *dai_drv, 24365e4fb372SMengdong Lin bool legacy_dai_naming) 24375e4fb372SMengdong Lin { 24385e4fb372SMengdong Lin struct device *dev = component->dev; 24395e4fb372SMengdong Lin struct snd_soc_dai *dai; 24405e4fb372SMengdong Lin 24415e4fb372SMengdong Lin dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); 24425e4fb372SMengdong Lin 24437ca24386SKuninori Morimoto lockdep_assert_held(&client_mutex); 24447ca24386SKuninori Morimoto 244550014499SKuninori Morimoto dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL); 24465e4fb372SMengdong Lin if (dai == NULL) 24475e4fb372SMengdong Lin return NULL; 24485e4fb372SMengdong Lin 24495e4fb372SMengdong Lin /* 24505e4fb372SMengdong Lin * Back in the old days when we still had component-less DAIs, 24515e4fb372SMengdong Lin * instead of having a static name, component-less DAIs would 24525e4fb372SMengdong Lin * inherit the name of the parent device so it is possible to 24535e4fb372SMengdong Lin * register multiple instances of the DAI. We still need to keep 24545e4fb372SMengdong Lin * the same naming style even though those DAIs are not 24555e4fb372SMengdong Lin * component-less anymore. 24565e4fb372SMengdong Lin */ 24575e4fb372SMengdong Lin if (legacy_dai_naming && 24585e4fb372SMengdong Lin (dai_drv->id == 0 || dai_drv->name == NULL)) { 24595e4fb372SMengdong Lin dai->name = fmt_single_name(dev, &dai->id); 24605e4fb372SMengdong Lin } else { 24615e4fb372SMengdong Lin dai->name = fmt_multiple_name(dev, dai_drv); 24625e4fb372SMengdong Lin if (dai_drv->id) 24635e4fb372SMengdong Lin dai->id = dai_drv->id; 24645e4fb372SMengdong Lin else 24655e4fb372SMengdong Lin dai->id = component->num_dai; 24665e4fb372SMengdong Lin } 246750014499SKuninori Morimoto if (!dai->name) 24685e4fb372SMengdong Lin return NULL; 24695e4fb372SMengdong Lin 24705e4fb372SMengdong Lin dai->component = component; 24715e4fb372SMengdong Lin dai->dev = dev; 24725e4fb372SMengdong Lin dai->driver = dai_drv; 24735e4fb372SMengdong Lin if (!dai->driver->ops) 24745e4fb372SMengdong Lin dai->driver->ops = &null_dai_ops; 24755e4fb372SMengdong Lin 247615a0c645SKuninori Morimoto /* see for_each_component_dais */ 247758bf4179SKuninori Morimoto list_add_tail(&dai->list, &component->dai_list); 24785e4fb372SMengdong Lin component->num_dai++; 24795e4fb372SMengdong Lin 24805e4fb372SMengdong Lin dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); 24815e4fb372SMengdong Lin return dai; 24825e4fb372SMengdong Lin } 2483e11381f3SKuninori Morimoto 24849115171aSMark Brown /** 24853f6674aeSKuninori Morimoto * snd_soc_unregister_dai - Unregister DAIs from the ASoC core 24863f6674aeSKuninori Morimoto * 24873f6674aeSKuninori Morimoto * @component: The component for which the DAIs should be unregistered 24883f6674aeSKuninori Morimoto */ 24893f6674aeSKuninori Morimoto static void snd_soc_unregister_dais(struct snd_soc_component *component) 24903f6674aeSKuninori Morimoto { 24913f6674aeSKuninori Morimoto struct snd_soc_dai *dai, *_dai; 24923f6674aeSKuninori Morimoto 2493e11381f3SKuninori Morimoto for_each_component_dais_safe(component, dai, _dai) 2494e11381f3SKuninori Morimoto snd_soc_unregister_dai(dai); 24953f6674aeSKuninori Morimoto } 24963f6674aeSKuninori Morimoto 24973f6674aeSKuninori Morimoto /** 2498daf77373SKuninori Morimoto * snd_soc_register_dais - Register a DAI with the ASoC core 2499daf77373SKuninori Morimoto * 2500daf77373SKuninori Morimoto * @component: The component the DAIs are registered for 2501daf77373SKuninori Morimoto * @dai_drv: DAI driver to use for the DAIs 2502daf77373SKuninori Morimoto * @count: Number of DAIs 2503daf77373SKuninori Morimoto */ 2504daf77373SKuninori Morimoto static int snd_soc_register_dais(struct snd_soc_component *component, 2505daf77373SKuninori Morimoto struct snd_soc_dai_driver *dai_drv, 2506daf77373SKuninori Morimoto size_t count) 2507daf77373SKuninori Morimoto { 2508daf77373SKuninori Morimoto struct snd_soc_dai *dai; 2509daf77373SKuninori Morimoto unsigned int i; 2510daf77373SKuninori Morimoto int ret; 2511daf77373SKuninori Morimoto 2512daf77373SKuninori Morimoto for (i = 0; i < count; i++) { 251371cb85f5SKuninori Morimoto dai = snd_soc_register_dai(component, dai_drv + i, count == 1 && 2514daf77373SKuninori Morimoto !component->driver->non_legacy_dai_naming); 2515daf77373SKuninori Morimoto if (dai == NULL) { 2516daf77373SKuninori Morimoto ret = -ENOMEM; 2517daf77373SKuninori Morimoto goto err; 2518daf77373SKuninori Morimoto } 2519daf77373SKuninori Morimoto } 2520daf77373SKuninori Morimoto 2521daf77373SKuninori Morimoto return 0; 2522daf77373SKuninori Morimoto 2523daf77373SKuninori Morimoto err: 2524daf77373SKuninori Morimoto snd_soc_unregister_dais(component); 2525daf77373SKuninori Morimoto 2526daf77373SKuninori Morimoto return ret; 2527daf77373SKuninori Morimoto } 2528daf77373SKuninori Morimoto 2529bb13109dSLars-Peter Clausen static int snd_soc_component_initialize(struct snd_soc_component *component, 2530bb13109dSLars-Peter Clausen const struct snd_soc_component_driver *driver, struct device *dev) 2531d191bd8dSKuninori Morimoto { 25328d92bb51SKuninori Morimoto INIT_LIST_HEAD(&component->dai_list); 2533495efdb0SKuninori Morimoto INIT_LIST_HEAD(&component->dobj_list); 2534495efdb0SKuninori Morimoto INIT_LIST_HEAD(&component->card_list); 25358d92bb51SKuninori Morimoto mutex_init(&component->io_mutex); 25368d92bb51SKuninori Morimoto 2537bb13109dSLars-Peter Clausen component->name = fmt_single_name(dev, &component->id); 2538bb13109dSLars-Peter Clausen if (!component->name) { 2539bb13109dSLars-Peter Clausen dev_err(dev, "ASoC: Failed to allocate name\n"); 2540d191bd8dSKuninori Morimoto return -ENOMEM; 2541d191bd8dSKuninori Morimoto } 2542d191bd8dSKuninori Morimoto 2543bb13109dSLars-Peter Clausen component->dev = dev; 2544bb13109dSLars-Peter Clausen component->driver = driver; 2545e2c330b9SLars-Peter Clausen 2546bb13109dSLars-Peter Clausen return 0; 2547d191bd8dSKuninori Morimoto } 2548d191bd8dSKuninori Morimoto 254920feb881SLars-Peter Clausen static void snd_soc_component_setup_regmap(struct snd_soc_component *component) 2550886f5692SLars-Peter Clausen { 2551886f5692SLars-Peter Clausen int val_bytes = regmap_get_val_bytes(component->regmap); 255220feb881SLars-Peter Clausen 2553886f5692SLars-Peter Clausen /* Errors are legitimate for non-integer byte multiples */ 2554886f5692SLars-Peter Clausen if (val_bytes > 0) 2555886f5692SLars-Peter Clausen component->val_bytes = val_bytes; 2556886f5692SLars-Peter Clausen } 255720feb881SLars-Peter Clausen 2558e874bf5fSLars-Peter Clausen #ifdef CONFIG_REGMAP 2559e874bf5fSLars-Peter Clausen 256020feb881SLars-Peter Clausen /** 25612c7b696aSMarcel Ziswiler * snd_soc_component_init_regmap() - Initialize regmap instance for the 25622c7b696aSMarcel Ziswiler * component 256320feb881SLars-Peter Clausen * @component: The component for which to initialize the regmap instance 256420feb881SLars-Peter Clausen * @regmap: The regmap instance that should be used by the component 256520feb881SLars-Peter Clausen * 256620feb881SLars-Peter Clausen * This function allows deferred assignment of the regmap instance that is 256720feb881SLars-Peter Clausen * associated with the component. Only use this if the regmap instance is not 256820feb881SLars-Peter Clausen * yet ready when the component is registered. The function must also be called 256920feb881SLars-Peter Clausen * before the first IO attempt of the component. 257020feb881SLars-Peter Clausen */ 257120feb881SLars-Peter Clausen void snd_soc_component_init_regmap(struct snd_soc_component *component, 257220feb881SLars-Peter Clausen struct regmap *regmap) 257320feb881SLars-Peter Clausen { 257420feb881SLars-Peter Clausen component->regmap = regmap; 257520feb881SLars-Peter Clausen snd_soc_component_setup_regmap(component); 2576886f5692SLars-Peter Clausen } 257720feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); 257820feb881SLars-Peter Clausen 257920feb881SLars-Peter Clausen /** 25802c7b696aSMarcel Ziswiler * snd_soc_component_exit_regmap() - De-initialize regmap instance for the 25812c7b696aSMarcel Ziswiler * component 258220feb881SLars-Peter Clausen * @component: The component for which to de-initialize the regmap instance 258320feb881SLars-Peter Clausen * 258420feb881SLars-Peter Clausen * Calls regmap_exit() on the regmap instance associated to the component and 258520feb881SLars-Peter Clausen * removes the regmap instance from the component. 258620feb881SLars-Peter Clausen * 258720feb881SLars-Peter Clausen * This function should only be used if snd_soc_component_init_regmap() was used 258820feb881SLars-Peter Clausen * to initialize the regmap instance. 258920feb881SLars-Peter Clausen */ 259020feb881SLars-Peter Clausen void snd_soc_component_exit_regmap(struct snd_soc_component *component) 259120feb881SLars-Peter Clausen { 259220feb881SLars-Peter Clausen regmap_exit(component->regmap); 259320feb881SLars-Peter Clausen component->regmap = NULL; 259420feb881SLars-Peter Clausen } 259520feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); 2596886f5692SLars-Peter Clausen 2597e874bf5fSLars-Peter Clausen #endif 2598d191bd8dSKuninori Morimoto 2599273d778eSKuninori Morimoto #define ENDIANNESS_MAP(name) \ 2600273d778eSKuninori Morimoto (SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE) 2601273d778eSKuninori Morimoto static u64 endianness_format_map[] = { 2602273d778eSKuninori Morimoto ENDIANNESS_MAP(S16_), 2603273d778eSKuninori Morimoto ENDIANNESS_MAP(U16_), 2604273d778eSKuninori Morimoto ENDIANNESS_MAP(S24_), 2605273d778eSKuninori Morimoto ENDIANNESS_MAP(U24_), 2606273d778eSKuninori Morimoto ENDIANNESS_MAP(S32_), 2607273d778eSKuninori Morimoto ENDIANNESS_MAP(U32_), 2608273d778eSKuninori Morimoto ENDIANNESS_MAP(S24_3), 2609273d778eSKuninori Morimoto ENDIANNESS_MAP(U24_3), 2610273d778eSKuninori Morimoto ENDIANNESS_MAP(S20_3), 2611273d778eSKuninori Morimoto ENDIANNESS_MAP(U20_3), 2612273d778eSKuninori Morimoto ENDIANNESS_MAP(S18_3), 2613273d778eSKuninori Morimoto ENDIANNESS_MAP(U18_3), 2614273d778eSKuninori Morimoto ENDIANNESS_MAP(FLOAT_), 2615273d778eSKuninori Morimoto ENDIANNESS_MAP(FLOAT64_), 2616273d778eSKuninori Morimoto ENDIANNESS_MAP(IEC958_SUBFRAME_), 2617273d778eSKuninori Morimoto }; 2618273d778eSKuninori Morimoto 2619273d778eSKuninori Morimoto /* 2620273d778eSKuninori Morimoto * Fix up the DAI formats for endianness: codecs don't actually see 2621273d778eSKuninori Morimoto * the endianness of the data but we're using the CPU format 2622273d778eSKuninori Morimoto * definitions which do need to include endianness so we ensure that 2623273d778eSKuninori Morimoto * codec DAIs always have both big and little endian variants set. 2624273d778eSKuninori Morimoto */ 2625273d778eSKuninori Morimoto static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) 2626273d778eSKuninori Morimoto { 2627273d778eSKuninori Morimoto int i; 2628273d778eSKuninori Morimoto 2629273d778eSKuninori Morimoto for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++) 2630273d778eSKuninori Morimoto if (stream->formats & endianness_format_map[i]) 2631273d778eSKuninori Morimoto stream->formats |= endianness_format_map[i]; 2632273d778eSKuninori Morimoto } 2633273d778eSKuninori Morimoto 2634e894efefSSrinivas Kandagatla static void snd_soc_try_rebind_card(void) 2635e894efefSSrinivas Kandagatla { 2636e894efefSSrinivas Kandagatla struct snd_soc_card *card, *c; 2637e894efefSSrinivas Kandagatla 2638b245d273SKuninori Morimoto list_for_each_entry_safe(card, c, &unbind_card_list, list) 2639e894efefSSrinivas Kandagatla if (!snd_soc_bind_card(card)) 2640e894efefSSrinivas Kandagatla list_del(&card->list); 2641e894efefSSrinivas Kandagatla } 2642e894efefSSrinivas Kandagatla 2643486c7978SKuninori Morimoto static void snd_soc_del_component_unlocked(struct snd_soc_component *component) 2644486c7978SKuninori Morimoto { 2645b18768f5SKuninori Morimoto struct snd_soc_card *card = component->card; 2646b18768f5SKuninori Morimoto 2647486c7978SKuninori Morimoto snd_soc_unregister_dais(component); 2648b18768f5SKuninori Morimoto 2649b18768f5SKuninori Morimoto if (card) 2650b18768f5SKuninori Morimoto snd_soc_unbind_card(card, false); 2651b18768f5SKuninori Morimoto 2652b18768f5SKuninori Morimoto list_del(&component->list); 2653486c7978SKuninori Morimoto } 2654486c7978SKuninori Morimoto 2655e0dac41bSKuninori Morimoto int snd_soc_add_component(struct device *dev, 2656e0dac41bSKuninori Morimoto struct snd_soc_component *component, 2657cf9e829eSKuninori Morimoto const struct snd_soc_component_driver *component_driver, 2658d191bd8dSKuninori Morimoto struct snd_soc_dai_driver *dai_drv, 2659d191bd8dSKuninori Morimoto int num_dai) 2660d191bd8dSKuninori Morimoto { 2661bb13109dSLars-Peter Clausen int ret; 2662273d778eSKuninori Morimoto int i; 2663d191bd8dSKuninori Morimoto 2664b18768f5SKuninori Morimoto mutex_lock(&client_mutex); 2665b18768f5SKuninori Morimoto 2666cf9e829eSKuninori Morimoto ret = snd_soc_component_initialize(component, component_driver, dev); 2667bb13109dSLars-Peter Clausen if (ret) 2668bb13109dSLars-Peter Clausen goto err_free; 2669bb13109dSLars-Peter Clausen 2670273d778eSKuninori Morimoto if (component_driver->endianness) { 2671273d778eSKuninori Morimoto for (i = 0; i < num_dai; i++) { 2672273d778eSKuninori Morimoto convert_endianness_formats(&dai_drv[i].playback); 2673273d778eSKuninori Morimoto convert_endianness_formats(&dai_drv[i].capture); 2674273d778eSKuninori Morimoto } 2675273d778eSKuninori Morimoto } 2676273d778eSKuninori Morimoto 26770e7b25c6SKuninori Morimoto ret = snd_soc_register_dais(component, dai_drv, num_dai); 2678bb13109dSLars-Peter Clausen if (ret < 0) { 2679f42cf8d6SMasanari Iida dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret); 2680bb13109dSLars-Peter Clausen goto err_cleanup; 2681bb13109dSLars-Peter Clausen } 2682bb13109dSLars-Peter Clausen 2683b18768f5SKuninori Morimoto if (!component->driver->write && !component->driver->read) { 2684b18768f5SKuninori Morimoto if (!component->regmap) 2685b18768f5SKuninori Morimoto component->regmap = dev_get_regmap(component->dev, 2686b18768f5SKuninori Morimoto NULL); 2687b18768f5SKuninori Morimoto if (component->regmap) 2688b18768f5SKuninori Morimoto snd_soc_component_setup_regmap(component); 2689b18768f5SKuninori Morimoto } 2690bb13109dSLars-Peter Clausen 2691b18768f5SKuninori Morimoto /* see for_each_component */ 2692b18768f5SKuninori Morimoto list_add(&component->list, &component_list); 2693bb13109dSLars-Peter Clausen 2694bb13109dSLars-Peter Clausen err_cleanup: 2695b18768f5SKuninori Morimoto if (ret < 0) 2696486c7978SKuninori Morimoto snd_soc_del_component_unlocked(component); 2697bb13109dSLars-Peter Clausen err_free: 2698b18768f5SKuninori Morimoto mutex_unlock(&client_mutex); 2699b18768f5SKuninori Morimoto 2700b18768f5SKuninori Morimoto if (ret == 0) 2701b18768f5SKuninori Morimoto snd_soc_try_rebind_card(); 2702b18768f5SKuninori Morimoto 2703bb13109dSLars-Peter Clausen return ret; 2704d191bd8dSKuninori Morimoto } 2705e0dac41bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_component); 2706e0dac41bSKuninori Morimoto 2707e0dac41bSKuninori Morimoto int snd_soc_register_component(struct device *dev, 2708e0dac41bSKuninori Morimoto const struct snd_soc_component_driver *component_driver, 2709e0dac41bSKuninori Morimoto struct snd_soc_dai_driver *dai_drv, 2710e0dac41bSKuninori Morimoto int num_dai) 2711e0dac41bSKuninori Morimoto { 2712e0dac41bSKuninori Morimoto struct snd_soc_component *component; 2713e0dac41bSKuninori Morimoto 27147ecbd6a9SKuninori Morimoto component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); 271508e61d03SKuninori Morimoto if (!component) 2716e0dac41bSKuninori Morimoto return -ENOMEM; 2717e0dac41bSKuninori Morimoto 2718e0dac41bSKuninori Morimoto return snd_soc_add_component(dev, component, component_driver, 2719e0dac41bSKuninori Morimoto dai_drv, num_dai); 2720e0dac41bSKuninori Morimoto } 2721d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_register_component); 2722d191bd8dSKuninori Morimoto 2723d191bd8dSKuninori Morimoto /** 27242eccea8cSKuninori Morimoto * snd_soc_unregister_component - Unregister all related component 27252eccea8cSKuninori Morimoto * from the ASoC core 2726d191bd8dSKuninori Morimoto * 2727628536eaSJonathan Corbet * @dev: The device to unregister 2728d191bd8dSKuninori Morimoto */ 27292eccea8cSKuninori Morimoto void snd_soc_unregister_component(struct device *dev) 27302eccea8cSKuninori Morimoto { 2731ac6a4dd3SKuninori Morimoto struct snd_soc_component *component; 2732ac6a4dd3SKuninori Morimoto 2733ac6a4dd3SKuninori Morimoto mutex_lock(&client_mutex); 2734ac6a4dd3SKuninori Morimoto while (1) { 273518dd66eaSKuninori Morimoto component = snd_soc_lookup_component_nolocked(dev, NULL); 2736ac6a4dd3SKuninori Morimoto if (!component) 2737ac6a4dd3SKuninori Morimoto break; 2738ac6a4dd3SKuninori Morimoto 2739ac6a4dd3SKuninori Morimoto snd_soc_del_component_unlocked(component); 2740ac6a4dd3SKuninori Morimoto } 2741ac6a4dd3SKuninori Morimoto mutex_unlock(&client_mutex); 2742d191bd8dSKuninori Morimoto } 2743d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_component); 2744d191bd8dSKuninori Morimoto 2745bec4fa05SStephen Warren /* Retrieve a card's name from device tree */ 2746b07609ceSKuninori Morimoto int snd_soc_of_parse_card_name(struct snd_soc_card *card, 2747bec4fa05SStephen Warren const char *propname) 2748bec4fa05SStephen Warren { 2749b07609ceSKuninori Morimoto struct device_node *np; 2750bec4fa05SStephen Warren int ret; 2751bec4fa05SStephen Warren 27527e07e7c0STushar Behera if (!card->dev) { 27537e07e7c0STushar Behera pr_err("card->dev is not set before calling %s\n", __func__); 27547e07e7c0STushar Behera return -EINVAL; 27557e07e7c0STushar Behera } 27567e07e7c0STushar Behera 27577e07e7c0STushar Behera np = card->dev->of_node; 27587e07e7c0STushar Behera 2759bec4fa05SStephen Warren ret = of_property_read_string_index(np, propname, 0, &card->name); 2760bec4fa05SStephen Warren /* 2761bec4fa05SStephen Warren * EINVAL means the property does not exist. This is fine providing 2762bec4fa05SStephen Warren * card->name was previously set, which is checked later in 2763bec4fa05SStephen Warren * snd_soc_register_card. 2764bec4fa05SStephen Warren */ 2765bec4fa05SStephen Warren if (ret < 0 && ret != -EINVAL) { 2766bec4fa05SStephen Warren dev_err(card->dev, 2767f110bfc7SLiam Girdwood "ASoC: Property '%s' could not be read: %d\n", 2768bec4fa05SStephen Warren propname, ret); 2769bec4fa05SStephen Warren return ret; 2770bec4fa05SStephen Warren } 2771bec4fa05SStephen Warren 2772bec4fa05SStephen Warren return 0; 2773bec4fa05SStephen Warren } 2774b07609ceSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); 2775bec4fa05SStephen Warren 27769a6d4860SXiubo Li static const struct snd_soc_dapm_widget simple_widgets[] = { 27779a6d4860SXiubo Li SND_SOC_DAPM_MIC("Microphone", NULL), 27789a6d4860SXiubo Li SND_SOC_DAPM_LINE("Line", NULL), 27799a6d4860SXiubo Li SND_SOC_DAPM_HP("Headphone", NULL), 27809a6d4860SXiubo Li SND_SOC_DAPM_SPK("Speaker", NULL), 27819a6d4860SXiubo Li }; 27829a6d4860SXiubo Li 278321efde50SKuninori Morimoto int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, 27849a6d4860SXiubo Li const char *propname) 27859a6d4860SXiubo Li { 278621efde50SKuninori Morimoto struct device_node *np = card->dev->of_node; 27879a6d4860SXiubo Li struct snd_soc_dapm_widget *widgets; 27889a6d4860SXiubo Li const char *template, *wname; 27899a6d4860SXiubo Li int i, j, num_widgets, ret; 27909a6d4860SXiubo Li 27919a6d4860SXiubo Li num_widgets = of_property_count_strings(np, propname); 27929a6d4860SXiubo Li if (num_widgets < 0) { 27939a6d4860SXiubo Li dev_err(card->dev, 27949a6d4860SXiubo Li "ASoC: Property '%s' does not exist\n", propname); 27959a6d4860SXiubo Li return -EINVAL; 27969a6d4860SXiubo Li } 27979a6d4860SXiubo Li if (num_widgets & 1) { 27989a6d4860SXiubo Li dev_err(card->dev, 27999a6d4860SXiubo Li "ASoC: Property '%s' length is not even\n", propname); 28009a6d4860SXiubo Li return -EINVAL; 28019a6d4860SXiubo Li } 28029a6d4860SXiubo Li 28039a6d4860SXiubo Li num_widgets /= 2; 28049a6d4860SXiubo Li if (!num_widgets) { 28059a6d4860SXiubo Li dev_err(card->dev, "ASoC: Property '%s's length is zero\n", 28069a6d4860SXiubo Li propname); 28079a6d4860SXiubo Li return -EINVAL; 28089a6d4860SXiubo Li } 28099a6d4860SXiubo Li 28109a6d4860SXiubo Li widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), 28119a6d4860SXiubo Li GFP_KERNEL); 28129a6d4860SXiubo Li if (!widgets) { 28139a6d4860SXiubo Li dev_err(card->dev, 28149a6d4860SXiubo Li "ASoC: Could not allocate memory for widgets\n"); 28159a6d4860SXiubo Li return -ENOMEM; 28169a6d4860SXiubo Li } 28179a6d4860SXiubo Li 28189a6d4860SXiubo Li for (i = 0; i < num_widgets; i++) { 28199a6d4860SXiubo Li ret = of_property_read_string_index(np, propname, 28209a6d4860SXiubo Li 2 * i, &template); 28219a6d4860SXiubo Li if (ret) { 28229a6d4860SXiubo Li dev_err(card->dev, 28239a6d4860SXiubo Li "ASoC: Property '%s' index %d read error:%d\n", 28249a6d4860SXiubo Li propname, 2 * i, ret); 28259a6d4860SXiubo Li return -EINVAL; 28269a6d4860SXiubo Li } 28279a6d4860SXiubo Li 28289a6d4860SXiubo Li for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { 28299a6d4860SXiubo Li if (!strncmp(template, simple_widgets[j].name, 28309a6d4860SXiubo Li strlen(simple_widgets[j].name))) { 28319a6d4860SXiubo Li widgets[i] = simple_widgets[j]; 28329a6d4860SXiubo Li break; 28339a6d4860SXiubo Li } 28349a6d4860SXiubo Li } 28359a6d4860SXiubo Li 28369a6d4860SXiubo Li if (j >= ARRAY_SIZE(simple_widgets)) { 28379a6d4860SXiubo Li dev_err(card->dev, 28389a6d4860SXiubo Li "ASoC: DAPM widget '%s' is not supported\n", 28399a6d4860SXiubo Li template); 28409a6d4860SXiubo Li return -EINVAL; 28419a6d4860SXiubo Li } 28429a6d4860SXiubo Li 28439a6d4860SXiubo Li ret = of_property_read_string_index(np, propname, 28449a6d4860SXiubo Li (2 * i) + 1, 28459a6d4860SXiubo Li &wname); 28469a6d4860SXiubo Li if (ret) { 28479a6d4860SXiubo Li dev_err(card->dev, 28489a6d4860SXiubo Li "ASoC: Property '%s' index %d read error:%d\n", 28499a6d4860SXiubo Li propname, (2 * i) + 1, ret); 28509a6d4860SXiubo Li return -EINVAL; 28519a6d4860SXiubo Li } 28529a6d4860SXiubo Li 28539a6d4860SXiubo Li widgets[i].name = wname; 28549a6d4860SXiubo Li } 28559a6d4860SXiubo Li 2856f23e860eSNicolin Chen card->of_dapm_widgets = widgets; 2857f23e860eSNicolin Chen card->num_of_dapm_widgets = num_widgets; 28589a6d4860SXiubo Li 28599a6d4860SXiubo Li return 0; 28609a6d4860SXiubo Li } 286121efde50SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); 28629a6d4860SXiubo Li 2863cbdfab3bSJerome Brunet int snd_soc_of_get_slot_mask(struct device_node *np, 28646131084aSJyri Sarha const char *prop_name, 28656131084aSJyri Sarha unsigned int *mask) 28666131084aSJyri Sarha { 28676131084aSJyri Sarha u32 val; 28686c84e591SJyri Sarha const __be32 *of_slot_mask = of_get_property(np, prop_name, &val); 28696131084aSJyri Sarha int i; 28706131084aSJyri Sarha 28716131084aSJyri Sarha if (!of_slot_mask) 28726131084aSJyri Sarha return 0; 28736131084aSJyri Sarha val /= sizeof(u32); 28746131084aSJyri Sarha for (i = 0; i < val; i++) 28756131084aSJyri Sarha if (be32_to_cpup(&of_slot_mask[i])) 28766131084aSJyri Sarha *mask |= (1 << i); 28776131084aSJyri Sarha 28786131084aSJyri Sarha return val; 28796131084aSJyri Sarha } 2880cbdfab3bSJerome Brunet EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask); 28816131084aSJyri Sarha 288289c67857SXiubo Li int snd_soc_of_parse_tdm_slot(struct device_node *np, 28836131084aSJyri Sarha unsigned int *tx_mask, 28846131084aSJyri Sarha unsigned int *rx_mask, 288589c67857SXiubo Li unsigned int *slots, 288689c67857SXiubo Li unsigned int *slot_width) 288789c67857SXiubo Li { 288889c67857SXiubo Li u32 val; 288989c67857SXiubo Li int ret; 289089c67857SXiubo Li 28916131084aSJyri Sarha if (tx_mask) 28926131084aSJyri Sarha snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask); 28936131084aSJyri Sarha if (rx_mask) 28946131084aSJyri Sarha snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); 28956131084aSJyri Sarha 289689c67857SXiubo Li if (of_property_read_bool(np, "dai-tdm-slot-num")) { 289789c67857SXiubo Li ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); 289889c67857SXiubo Li if (ret) 289989c67857SXiubo Li return ret; 290089c67857SXiubo Li 290189c67857SXiubo Li if (slots) 290289c67857SXiubo Li *slots = val; 290389c67857SXiubo Li } 290489c67857SXiubo Li 290589c67857SXiubo Li if (of_property_read_bool(np, "dai-tdm-slot-width")) { 290689c67857SXiubo Li ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); 290789c67857SXiubo Li if (ret) 290889c67857SXiubo Li return ret; 290989c67857SXiubo Li 291089c67857SXiubo Li if (slot_width) 291189c67857SXiubo Li *slot_width = val; 291289c67857SXiubo Li } 291389c67857SXiubo Li 291489c67857SXiubo Li return 0; 291589c67857SXiubo Li } 291689c67857SXiubo Li EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); 291789c67857SXiubo Li 29183b710356SKuninori Morimoto void snd_soc_of_parse_node_prefix(struct device_node *np, 29195e3cdaa2SKuninori Morimoto struct snd_soc_codec_conf *codec_conf, 29205e3cdaa2SKuninori Morimoto struct device_node *of_node, 29215e3cdaa2SKuninori Morimoto const char *propname) 29225e3cdaa2SKuninori Morimoto { 29235e3cdaa2SKuninori Morimoto const char *str; 29245e3cdaa2SKuninori Morimoto int ret; 29255e3cdaa2SKuninori Morimoto 29265e3cdaa2SKuninori Morimoto ret = of_property_read_string(np, propname, &str); 29275e3cdaa2SKuninori Morimoto if (ret < 0) { 29285e3cdaa2SKuninori Morimoto /* no prefix is not error */ 29295e3cdaa2SKuninori Morimoto return; 29305e3cdaa2SKuninori Morimoto } 29315e3cdaa2SKuninori Morimoto 29325e3cdaa2SKuninori Morimoto codec_conf->of_node = of_node; 29335e3cdaa2SKuninori Morimoto codec_conf->name_prefix = str; 29345e3cdaa2SKuninori Morimoto } 29353b710356SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix); 29365e3cdaa2SKuninori Morimoto 29372bc644afSKuninori Morimoto int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, 2938a4a54dd5SStephen Warren const char *propname) 2939a4a54dd5SStephen Warren { 29402bc644afSKuninori Morimoto struct device_node *np = card->dev->of_node; 2941e3b1e6a1SMark Brown int num_routes; 2942a4a54dd5SStephen Warren struct snd_soc_dapm_route *routes; 2943a4a54dd5SStephen Warren int i, ret; 2944a4a54dd5SStephen Warren 2945a4a54dd5SStephen Warren num_routes = of_property_count_strings(np, propname); 2946c34ce320SRichard Zhao if (num_routes < 0 || num_routes & 1) { 294710e8aa9aSMichał Mirosław dev_err(card->dev, 294810e8aa9aSMichał Mirosław "ASoC: Property '%s' does not exist or its length is not even\n", 294910e8aa9aSMichał Mirosław propname); 2950a4a54dd5SStephen Warren return -EINVAL; 2951a4a54dd5SStephen Warren } 2952a4a54dd5SStephen Warren num_routes /= 2; 2953a4a54dd5SStephen Warren if (!num_routes) { 2954f110bfc7SLiam Girdwood dev_err(card->dev, "ASoC: Property '%s's length is zero\n", 2955a4a54dd5SStephen Warren propname); 2956a4a54dd5SStephen Warren return -EINVAL; 2957a4a54dd5SStephen Warren } 2958a4a54dd5SStephen Warren 2959a86854d0SKees Cook routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes), 2960a4a54dd5SStephen Warren GFP_KERNEL); 2961a4a54dd5SStephen Warren if (!routes) { 2962a4a54dd5SStephen Warren dev_err(card->dev, 2963f110bfc7SLiam Girdwood "ASoC: Could not allocate DAPM route table\n"); 2964a4a54dd5SStephen Warren return -EINVAL; 2965a4a54dd5SStephen Warren } 2966a4a54dd5SStephen Warren 2967a4a54dd5SStephen Warren for (i = 0; i < num_routes; i++) { 2968a4a54dd5SStephen Warren ret = of_property_read_string_index(np, propname, 2969e3b1e6a1SMark Brown 2 * i, &routes[i].sink); 2970a4a54dd5SStephen Warren if (ret) { 2971c871bd0bSMark Brown dev_err(card->dev, 2972c871bd0bSMark Brown "ASoC: Property '%s' index %d could not be read: %d\n", 2973c871bd0bSMark Brown propname, 2 * i, ret); 2974a4a54dd5SStephen Warren return -EINVAL; 2975a4a54dd5SStephen Warren } 2976a4a54dd5SStephen Warren ret = of_property_read_string_index(np, propname, 2977e3b1e6a1SMark Brown (2 * i) + 1, &routes[i].source); 2978a4a54dd5SStephen Warren if (ret) { 2979a4a54dd5SStephen Warren dev_err(card->dev, 2980c871bd0bSMark Brown "ASoC: Property '%s' index %d could not be read: %d\n", 2981c871bd0bSMark Brown propname, (2 * i) + 1, ret); 2982a4a54dd5SStephen Warren return -EINVAL; 2983a4a54dd5SStephen Warren } 2984a4a54dd5SStephen Warren } 2985a4a54dd5SStephen Warren 2986f23e860eSNicolin Chen card->num_of_dapm_routes = num_routes; 2987f23e860eSNicolin Chen card->of_dapm_routes = routes; 2988a4a54dd5SStephen Warren 2989a4a54dd5SStephen Warren return 0; 2990a4a54dd5SStephen Warren } 29912bc644afSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); 2992a4a54dd5SStephen Warren 2993a7930ed4SKuninori Morimoto unsigned int snd_soc_of_parse_daifmt(struct device_node *np, 2994389cb834SJyri Sarha const char *prefix, 2995389cb834SJyri Sarha struct device_node **bitclkmaster, 2996389cb834SJyri Sarha struct device_node **framemaster) 2997a7930ed4SKuninori Morimoto { 2998a7930ed4SKuninori Morimoto int ret, i; 2999a7930ed4SKuninori Morimoto char prop[128]; 3000a7930ed4SKuninori Morimoto unsigned int format = 0; 3001a7930ed4SKuninori Morimoto int bit, frame; 3002a7930ed4SKuninori Morimoto const char *str; 3003a7930ed4SKuninori Morimoto struct { 3004a7930ed4SKuninori Morimoto char *name; 3005a7930ed4SKuninori Morimoto unsigned int val; 3006a7930ed4SKuninori Morimoto } of_fmt_table[] = { 3007a7930ed4SKuninori Morimoto { "i2s", SND_SOC_DAIFMT_I2S }, 3008a7930ed4SKuninori Morimoto { "right_j", SND_SOC_DAIFMT_RIGHT_J }, 3009a7930ed4SKuninori Morimoto { "left_j", SND_SOC_DAIFMT_LEFT_J }, 3010a7930ed4SKuninori Morimoto { "dsp_a", SND_SOC_DAIFMT_DSP_A }, 3011a7930ed4SKuninori Morimoto { "dsp_b", SND_SOC_DAIFMT_DSP_B }, 3012a7930ed4SKuninori Morimoto { "ac97", SND_SOC_DAIFMT_AC97 }, 3013a7930ed4SKuninori Morimoto { "pdm", SND_SOC_DAIFMT_PDM}, 3014a7930ed4SKuninori Morimoto { "msb", SND_SOC_DAIFMT_MSB }, 3015a7930ed4SKuninori Morimoto { "lsb", SND_SOC_DAIFMT_LSB }, 3016a7930ed4SKuninori Morimoto }; 3017a7930ed4SKuninori Morimoto 3018a7930ed4SKuninori Morimoto if (!prefix) 3019a7930ed4SKuninori Morimoto prefix = ""; 3020a7930ed4SKuninori Morimoto 3021a7930ed4SKuninori Morimoto /* 30225711c979SKuninori Morimoto * check "dai-format = xxx" 30235711c979SKuninori Morimoto * or "[prefix]format = xxx" 3024a7930ed4SKuninori Morimoto * SND_SOC_DAIFMT_FORMAT_MASK area 3025a7930ed4SKuninori Morimoto */ 30265711c979SKuninori Morimoto ret = of_property_read_string(np, "dai-format", &str); 30275711c979SKuninori Morimoto if (ret < 0) { 3028a7930ed4SKuninori Morimoto snprintf(prop, sizeof(prop), "%sformat", prefix); 3029a7930ed4SKuninori Morimoto ret = of_property_read_string(np, prop, &str); 30305711c979SKuninori Morimoto } 3031a7930ed4SKuninori Morimoto if (ret == 0) { 3032a7930ed4SKuninori Morimoto for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { 3033a7930ed4SKuninori Morimoto if (strcmp(str, of_fmt_table[i].name) == 0) { 3034a7930ed4SKuninori Morimoto format |= of_fmt_table[i].val; 3035a7930ed4SKuninori Morimoto break; 3036a7930ed4SKuninori Morimoto } 3037a7930ed4SKuninori Morimoto } 3038a7930ed4SKuninori Morimoto } 3039a7930ed4SKuninori Morimoto 3040a7930ed4SKuninori Morimoto /* 30418c2d6a9fSKuninori Morimoto * check "[prefix]continuous-clock" 3042a7930ed4SKuninori Morimoto * SND_SOC_DAIFMT_CLOCK_MASK area 3043a7930ed4SKuninori Morimoto */ 30448c2d6a9fSKuninori Morimoto snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix); 304551930295SJulia Lawall if (of_property_read_bool(np, prop)) 30468c2d6a9fSKuninori Morimoto format |= SND_SOC_DAIFMT_CONT; 30478c2d6a9fSKuninori Morimoto else 30488c2d6a9fSKuninori Morimoto format |= SND_SOC_DAIFMT_GATED; 3049a7930ed4SKuninori Morimoto 3050a7930ed4SKuninori Morimoto /* 3051a7930ed4SKuninori Morimoto * check "[prefix]bitclock-inversion" 3052a7930ed4SKuninori Morimoto * check "[prefix]frame-inversion" 3053a7930ed4SKuninori Morimoto * SND_SOC_DAIFMT_INV_MASK area 3054a7930ed4SKuninori Morimoto */ 3055a7930ed4SKuninori Morimoto snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); 3056a7930ed4SKuninori Morimoto bit = !!of_get_property(np, prop, NULL); 3057a7930ed4SKuninori Morimoto 3058a7930ed4SKuninori Morimoto snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); 3059a7930ed4SKuninori Morimoto frame = !!of_get_property(np, prop, NULL); 3060a7930ed4SKuninori Morimoto 3061a7930ed4SKuninori Morimoto switch ((bit << 4) + frame) { 3062a7930ed4SKuninori Morimoto case 0x11: 3063a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_IB_IF; 3064a7930ed4SKuninori Morimoto break; 3065a7930ed4SKuninori Morimoto case 0x10: 3066a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_IB_NF; 3067a7930ed4SKuninori Morimoto break; 3068a7930ed4SKuninori Morimoto case 0x01: 3069a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_NB_IF; 3070a7930ed4SKuninori Morimoto break; 3071a7930ed4SKuninori Morimoto default: 3072a7930ed4SKuninori Morimoto /* SND_SOC_DAIFMT_NB_NF is default */ 3073a7930ed4SKuninori Morimoto break; 3074a7930ed4SKuninori Morimoto } 3075a7930ed4SKuninori Morimoto 3076a7930ed4SKuninori Morimoto /* 3077a7930ed4SKuninori Morimoto * check "[prefix]bitclock-master" 3078a7930ed4SKuninori Morimoto * check "[prefix]frame-master" 3079a7930ed4SKuninori Morimoto * SND_SOC_DAIFMT_MASTER_MASK area 3080a7930ed4SKuninori Morimoto */ 3081a7930ed4SKuninori Morimoto snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); 3082a7930ed4SKuninori Morimoto bit = !!of_get_property(np, prop, NULL); 3083389cb834SJyri Sarha if (bit && bitclkmaster) 3084389cb834SJyri Sarha *bitclkmaster = of_parse_phandle(np, prop, 0); 3085a7930ed4SKuninori Morimoto 3086a7930ed4SKuninori Morimoto snprintf(prop, sizeof(prop), "%sframe-master", prefix); 3087a7930ed4SKuninori Morimoto frame = !!of_get_property(np, prop, NULL); 3088389cb834SJyri Sarha if (frame && framemaster) 3089389cb834SJyri Sarha *framemaster = of_parse_phandle(np, prop, 0); 3090a7930ed4SKuninori Morimoto 3091a7930ed4SKuninori Morimoto switch ((bit << 4) + frame) { 3092a7930ed4SKuninori Morimoto case 0x11: 3093a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_CBM_CFM; 3094a7930ed4SKuninori Morimoto break; 3095a7930ed4SKuninori Morimoto case 0x10: 3096a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_CBM_CFS; 3097a7930ed4SKuninori Morimoto break; 3098a7930ed4SKuninori Morimoto case 0x01: 3099a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_CBS_CFM; 3100a7930ed4SKuninori Morimoto break; 3101a7930ed4SKuninori Morimoto default: 3102a7930ed4SKuninori Morimoto format |= SND_SOC_DAIFMT_CBS_CFS; 3103a7930ed4SKuninori Morimoto break; 3104a7930ed4SKuninori Morimoto } 3105a7930ed4SKuninori Morimoto 3106a7930ed4SKuninori Morimoto return format; 3107a7930ed4SKuninori Morimoto } 3108a7930ed4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); 3109a7930ed4SKuninori Morimoto 3110a180e8b9SKuninori Morimoto int snd_soc_get_dai_id(struct device_node *ep) 3111a180e8b9SKuninori Morimoto { 311209d4cc03SKuninori Morimoto struct snd_soc_component *component; 3113c1e230f0SKuninori Morimoto struct snd_soc_dai_link_component dlc; 3114a180e8b9SKuninori Morimoto int ret; 3115a180e8b9SKuninori Morimoto 3116c1e230f0SKuninori Morimoto dlc.of_node = of_graph_get_port_parent(ep); 3117c1e230f0SKuninori Morimoto dlc.name = NULL; 3118a180e8b9SKuninori Morimoto /* 3119a180e8b9SKuninori Morimoto * For example HDMI case, HDMI has video/sound port, 3120a180e8b9SKuninori Morimoto * but ALSA SoC needs sound port number only. 3121a180e8b9SKuninori Morimoto * Thus counting HDMI DT port/endpoint doesn't work. 3122a180e8b9SKuninori Morimoto * Then, it should have .of_xlate_dai_id 3123a180e8b9SKuninori Morimoto */ 3124a180e8b9SKuninori Morimoto ret = -ENOTSUPP; 3125a180e8b9SKuninori Morimoto mutex_lock(&client_mutex); 3126c1e230f0SKuninori Morimoto component = soc_find_component(&dlc); 31272c7b1704SKuninori Morimoto if (component) 31282c7b1704SKuninori Morimoto ret = snd_soc_component_of_xlate_dai_id(component, ep); 3129a180e8b9SKuninori Morimoto mutex_unlock(&client_mutex); 3130a180e8b9SKuninori Morimoto 3131c1e230f0SKuninori Morimoto of_node_put(dlc.of_node); 3132c0a480d1STony Lindgren 3133a180e8b9SKuninori Morimoto return ret; 3134a180e8b9SKuninori Morimoto } 3135a180e8b9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); 3136a180e8b9SKuninori Morimoto 31371ad8ec53SKuninori Morimoto int snd_soc_get_dai_name(struct of_phandle_args *args, 3138cb470087SKuninori Morimoto const char **dai_name) 3139cb470087SKuninori Morimoto { 3140cb470087SKuninori Morimoto struct snd_soc_component *pos; 31413e0aa8d8SJyri Sarha struct device_node *component_of_node; 314293b0f3eeSJean-Francois Moine int ret = -EPROBE_DEFER; 3143cb470087SKuninori Morimoto 3144cb470087SKuninori Morimoto mutex_lock(&client_mutex); 3145368dee94SKuninori Morimoto for_each_component(pos) { 3146c0834440SKuninori Morimoto component_of_node = soc_component_to_node(pos); 31473e0aa8d8SJyri Sarha 31483e0aa8d8SJyri Sarha if (component_of_node != args->np) 3149cb470087SKuninori Morimoto continue; 3150cb470087SKuninori Morimoto 3151a2a34175SKuninori Morimoto ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name); 3152a2a34175SKuninori Morimoto if (ret == -ENOTSUPP) { 315358bf4179SKuninori Morimoto struct snd_soc_dai *dai; 31546833c452SKuninori Morimoto int id = -1; 31556833c452SKuninori Morimoto 315693b0f3eeSJean-Francois Moine switch (args->args_count) { 31576833c452SKuninori Morimoto case 0: 31586833c452SKuninori Morimoto id = 0; /* same as dai_drv[0] */ 31596833c452SKuninori Morimoto break; 31606833c452SKuninori Morimoto case 1: 316193b0f3eeSJean-Francois Moine id = args->args[0]; 31626833c452SKuninori Morimoto break; 31636833c452SKuninori Morimoto default: 31646833c452SKuninori Morimoto /* not supported */ 3165cb470087SKuninori Morimoto break; 3166cb470087SKuninori Morimoto } 3167cb470087SKuninori Morimoto 31686833c452SKuninori Morimoto if (id < 0 || id >= pos->num_dai) { 31696833c452SKuninori Morimoto ret = -EINVAL; 31703dcba280SNicolin Chen continue; 31716833c452SKuninori Morimoto } 3172e41975edSXiubo Li 3173e41975edSXiubo Li ret = 0; 3174e41975edSXiubo Li 317558bf4179SKuninori Morimoto /* find target DAI */ 317615a0c645SKuninori Morimoto for_each_component_dais(pos, dai) { 317758bf4179SKuninori Morimoto if (id == 0) 317858bf4179SKuninori Morimoto break; 317958bf4179SKuninori Morimoto id--; 318058bf4179SKuninori Morimoto } 318158bf4179SKuninori Morimoto 318258bf4179SKuninori Morimoto *dai_name = dai->driver->name; 3183e41975edSXiubo Li if (!*dai_name) 3184e41975edSXiubo Li *dai_name = pos->name; 31856833c452SKuninori Morimoto } 31866833c452SKuninori Morimoto 3187cb470087SKuninori Morimoto break; 3188cb470087SKuninori Morimoto } 3189cb470087SKuninori Morimoto mutex_unlock(&client_mutex); 319093b0f3eeSJean-Francois Moine return ret; 319193b0f3eeSJean-Francois Moine } 31921ad8ec53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_name); 319393b0f3eeSJean-Francois Moine 319493b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_name(struct device_node *of_node, 319593b0f3eeSJean-Francois Moine const char **dai_name) 319693b0f3eeSJean-Francois Moine { 319793b0f3eeSJean-Francois Moine struct of_phandle_args args; 319893b0f3eeSJean-Francois Moine int ret; 319993b0f3eeSJean-Francois Moine 320093b0f3eeSJean-Francois Moine ret = of_parse_phandle_with_args(of_node, "sound-dai", 320193b0f3eeSJean-Francois Moine "#sound-dai-cells", 0, &args); 320293b0f3eeSJean-Francois Moine if (ret) 320393b0f3eeSJean-Francois Moine return ret; 320493b0f3eeSJean-Francois Moine 320593b0f3eeSJean-Francois Moine ret = snd_soc_get_dai_name(&args, dai_name); 3206cb470087SKuninori Morimoto 3207cb470087SKuninori Morimoto of_node_put(args.np); 3208cb470087SKuninori Morimoto 3209cb470087SKuninori Morimoto return ret; 3210cb470087SKuninori Morimoto } 3211cb470087SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); 3212cb470087SKuninori Morimoto 321393b0f3eeSJean-Francois Moine /* 321494685763SSylwester Nawrocki * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array 321594685763SSylwester Nawrocki * @dai_link: DAI link 321694685763SSylwester Nawrocki * 321794685763SSylwester Nawrocki * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs(). 321894685763SSylwester Nawrocki */ 321994685763SSylwester Nawrocki void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) 322094685763SSylwester Nawrocki { 32213db769f1SKuninori Morimoto struct snd_soc_dai_link_component *component; 322294685763SSylwester Nawrocki int index; 322394685763SSylwester Nawrocki 32243db769f1SKuninori Morimoto for_each_link_codecs(dai_link, index, component) { 322594685763SSylwester Nawrocki if (!component->of_node) 322694685763SSylwester Nawrocki break; 322794685763SSylwester Nawrocki of_node_put(component->of_node); 322894685763SSylwester Nawrocki component->of_node = NULL; 322994685763SSylwester Nawrocki } 323094685763SSylwester Nawrocki } 323194685763SSylwester Nawrocki EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs); 323294685763SSylwester Nawrocki 323394685763SSylwester Nawrocki /* 323493b0f3eeSJean-Francois Moine * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree 323593b0f3eeSJean-Francois Moine * @dev: Card device 323693b0f3eeSJean-Francois Moine * @of_node: Device node 323793b0f3eeSJean-Francois Moine * @dai_link: DAI link 323893b0f3eeSJean-Francois Moine * 323993b0f3eeSJean-Francois Moine * Builds an array of CODEC DAI components from the DAI link property 324093b0f3eeSJean-Francois Moine * 'sound-dai'. 324193b0f3eeSJean-Francois Moine * The array is set in the DAI link and the number of DAIs is set accordingly. 324294685763SSylwester Nawrocki * The device nodes in the array (of_node) must be dereferenced by calling 324394685763SSylwester Nawrocki * snd_soc_of_put_dai_link_codecs() on @dai_link. 324493b0f3eeSJean-Francois Moine * 324593b0f3eeSJean-Francois Moine * Returns 0 for success 324693b0f3eeSJean-Francois Moine */ 324793b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_link_codecs(struct device *dev, 324893b0f3eeSJean-Francois Moine struct device_node *of_node, 324993b0f3eeSJean-Francois Moine struct snd_soc_dai_link *dai_link) 325093b0f3eeSJean-Francois Moine { 325193b0f3eeSJean-Francois Moine struct of_phandle_args args; 325293b0f3eeSJean-Francois Moine struct snd_soc_dai_link_component *component; 325393b0f3eeSJean-Francois Moine char *name; 325493b0f3eeSJean-Francois Moine int index, num_codecs, ret; 325593b0f3eeSJean-Francois Moine 325693b0f3eeSJean-Francois Moine /* Count the number of CODECs */ 325793b0f3eeSJean-Francois Moine name = "sound-dai"; 325893b0f3eeSJean-Francois Moine num_codecs = of_count_phandle_with_args(of_node, name, 325993b0f3eeSJean-Francois Moine "#sound-dai-cells"); 326093b0f3eeSJean-Francois Moine if (num_codecs <= 0) { 326193b0f3eeSJean-Francois Moine if (num_codecs == -ENOENT) 326293b0f3eeSJean-Francois Moine dev_err(dev, "No 'sound-dai' property\n"); 326393b0f3eeSJean-Francois Moine else 326493b0f3eeSJean-Francois Moine dev_err(dev, "Bad phandle in 'sound-dai'\n"); 326593b0f3eeSJean-Francois Moine return num_codecs; 326693b0f3eeSJean-Francois Moine } 3267a86854d0SKees Cook component = devm_kcalloc(dev, 3268a86854d0SKees Cook num_codecs, sizeof(*component), 326993b0f3eeSJean-Francois Moine GFP_KERNEL); 327093b0f3eeSJean-Francois Moine if (!component) 327193b0f3eeSJean-Francois Moine return -ENOMEM; 327293b0f3eeSJean-Francois Moine dai_link->codecs = component; 327393b0f3eeSJean-Francois Moine dai_link->num_codecs = num_codecs; 327493b0f3eeSJean-Francois Moine 327593b0f3eeSJean-Francois Moine /* Parse the list */ 32763db769f1SKuninori Morimoto for_each_link_codecs(dai_link, index, component) { 327793b0f3eeSJean-Francois Moine ret = of_parse_phandle_with_args(of_node, name, 327893b0f3eeSJean-Francois Moine "#sound-dai-cells", 327993b0f3eeSJean-Francois Moine index, &args); 328093b0f3eeSJean-Francois Moine if (ret) 328193b0f3eeSJean-Francois Moine goto err; 328293b0f3eeSJean-Francois Moine component->of_node = args.np; 328393b0f3eeSJean-Francois Moine ret = snd_soc_get_dai_name(&args, &component->dai_name); 328493b0f3eeSJean-Francois Moine if (ret < 0) 328593b0f3eeSJean-Francois Moine goto err; 328693b0f3eeSJean-Francois Moine } 328793b0f3eeSJean-Francois Moine return 0; 328893b0f3eeSJean-Francois Moine err: 328994685763SSylwester Nawrocki snd_soc_of_put_dai_link_codecs(dai_link); 329093b0f3eeSJean-Francois Moine dai_link->codecs = NULL; 329193b0f3eeSJean-Francois Moine dai_link->num_codecs = 0; 329293b0f3eeSJean-Francois Moine return ret; 329393b0f3eeSJean-Francois Moine } 329493b0f3eeSJean-Francois Moine EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); 329593b0f3eeSJean-Francois Moine 3296c9b3a40fSTakashi Iwai static int __init snd_soc_init(void) 3297db2a4165SFrank Mandarino { 32986553bf06SLars-Peter Clausen snd_soc_debugfs_init(); 3299fb257897SMark Brown snd_soc_util_init(); 3300fb257897SMark Brown 3301db2a4165SFrank Mandarino return platform_driver_register(&soc_driver); 3302db2a4165SFrank Mandarino } 33034abe8e16SMark Brown module_init(snd_soc_init); 3304db2a4165SFrank Mandarino 33057d8c16a6SMark Brown static void __exit snd_soc_exit(void) 3306db2a4165SFrank Mandarino { 3307fb257897SMark Brown snd_soc_util_exit(); 33086553bf06SLars-Peter Clausen snd_soc_debugfs_exit(); 3309fb257897SMark Brown 3310db2a4165SFrank Mandarino platform_driver_unregister(&soc_driver); 3311db2a4165SFrank Mandarino } 3312db2a4165SFrank Mandarino module_exit(snd_soc_exit); 3313db2a4165SFrank Mandarino 3314db2a4165SFrank Mandarino /* Module information */ 3315d331124dSLiam Girdwood MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); 3316db2a4165SFrank Mandarino MODULE_DESCRIPTION("ALSA SoC Core"); 3317db2a4165SFrank Mandarino MODULE_LICENSE("GPL"); 33188b45a209SKay Sievers MODULE_ALIAS("platform:soc-audio"); 3319