18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// soc-card.c 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2019 Renesas Electronics Corp. 68c2ecf20Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci#include <sound/soc.h> 98c2ecf20Sopenharmony_ci#include <sound/jack.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define soc_card_ret(dai, ret) _soc_card_ret(dai, __func__, ret) 128c2ecf20Sopenharmony_cistatic inline int _soc_card_ret(struct snd_soc_card *card, 138c2ecf20Sopenharmony_ci const char *func, int ret) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci switch (ret) { 168c2ecf20Sopenharmony_ci case -EPROBE_DEFER: 178c2ecf20Sopenharmony_ci case -ENOTSUPP: 188c2ecf20Sopenharmony_ci case 0: 198c2ecf20Sopenharmony_ci break; 208c2ecf20Sopenharmony_ci default: 218c2ecf20Sopenharmony_ci dev_err(card->dev, 228c2ecf20Sopenharmony_ci "ASoC: error at %s on %s: %d\n", 238c2ecf20Sopenharmony_ci func, card->name, ret); 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return ret; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, 308c2ecf20Sopenharmony_ci const char *name) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct snd_card *card = soc_card->snd_card; 338c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (unlikely(!name)) 368c2ecf20Sopenharmony_ci return NULL; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci list_for_each_entry(kctl, &card->controls, list) 398c2ecf20Sopenharmony_ci if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) 408c2ecf20Sopenharmony_ci return kctl; 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * snd_soc_card_jack_new - Create a new jack 478c2ecf20Sopenharmony_ci * @card: ASoC card 488c2ecf20Sopenharmony_ci * @id: an identifying string for this jack 498c2ecf20Sopenharmony_ci * @type: a bitmask of enum snd_jack_type values that can be detected by 508c2ecf20Sopenharmony_ci * this jack 518c2ecf20Sopenharmony_ci * @jack: structure to use for the jack 528c2ecf20Sopenharmony_ci * @pins: Array of jack pins to be added to the jack or NULL 538c2ecf20Sopenharmony_ci * @num_pins: Number of elements in the @pins array 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * Creates a new jack object. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Returns zero if successful, or a negative error code on failure. 588c2ecf20Sopenharmony_ci * On success jack will be initialised. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ciint snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, 618c2ecf20Sopenharmony_ci struct snd_soc_jack *jack, 628c2ecf20Sopenharmony_ci struct snd_soc_jack_pin *pins, unsigned int num_pins) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mutex_init(&jack->mutex); 678c2ecf20Sopenharmony_ci jack->card = card; 688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&jack->pins); 698c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&jack->jack_zones); 708c2ecf20Sopenharmony_ci BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci ret = snd_jack_new(card->snd_card, id, type, &jack->jack, false, false); 738c2ecf20Sopenharmony_ci if (ret) 748c2ecf20Sopenharmony_ci goto end; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (num_pins) 778c2ecf20Sopenharmony_ci ret = snd_soc_jack_add_pins(jack, num_pins, pins); 788c2ecf20Sopenharmony_ciend: 798c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_card_jack_new); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint snd_soc_card_suspend_pre(struct snd_soc_card *card) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci int ret = 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (card->suspend_pre) 888c2ecf20Sopenharmony_ci ret = card->suspend_pre(card); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciint snd_soc_card_suspend_post(struct snd_soc_card *card) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int ret = 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (card->suspend_post) 988c2ecf20Sopenharmony_ci ret = card->suspend_post(card); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint snd_soc_card_resume_pre(struct snd_soc_card *card) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int ret = 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (card->resume_pre) 1088c2ecf20Sopenharmony_ci ret = card->resume_pre(card); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint snd_soc_card_resume_post(struct snd_soc_card *card) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int ret = 0; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (card->resume_post) 1188c2ecf20Sopenharmony_ci ret = card->resume_post(card); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciint snd_soc_card_probe(struct snd_soc_card *card) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci if (card->probe) { 1268c2ecf20Sopenharmony_ci int ret = card->probe(card); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (ret < 0) 1298c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * It has "card->probe" and "card->late_probe" callbacks. 1338c2ecf20Sopenharmony_ci * So, set "probed" flag here, because it needs to care 1348c2ecf20Sopenharmony_ci * about "late_probe". 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * see 1378c2ecf20Sopenharmony_ci * snd_soc_bind_card() 1388c2ecf20Sopenharmony_ci * snd_soc_card_late_probe() 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci card->probed = 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciint snd_soc_card_late_probe(struct snd_soc_card *card) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci if (card->late_probe) { 1498c2ecf20Sopenharmony_ci int ret = card->late_probe(card); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (ret < 0) 1528c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * It has "card->probe" and "card->late_probe" callbacks, 1578c2ecf20Sopenharmony_ci * and "late_probe" callback is called after "probe". 1588c2ecf20Sopenharmony_ci * This means, we can set "card->probed" flag afer "late_probe" 1598c2ecf20Sopenharmony_ci * for all cases. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * see 1628c2ecf20Sopenharmony_ci * snd_soc_bind_card() 1638c2ecf20Sopenharmony_ci * snd_soc_card_probe() 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci card->probed = 1; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint snd_soc_card_remove(struct snd_soc_card *card) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int ret = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (card->probed && 1758c2ecf20Sopenharmony_ci card->remove) 1768c2ecf20Sopenharmony_ci ret = card->remove(card); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci card->probed = 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ciint snd_soc_card_set_bias_level(struct snd_soc_card *card, 1848c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm, 1858c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int ret = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (card && card->set_bias_level) 1908c2ecf20Sopenharmony_ci ret = card->set_bias_level(card, dapm, level); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciint snd_soc_card_set_bias_level_post(struct snd_soc_card *card, 1968c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm, 1978c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int ret = 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (card && card->set_bias_level_post) 2028c2ecf20Sopenharmony_ci ret = card->set_bias_level_post(card, dapm, level); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ciint snd_soc_card_add_dai_link(struct snd_soc_card *card, 2088c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai_link) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int ret = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (card->add_dai_link) 2138c2ecf20Sopenharmony_ci ret = card->add_dai_link(card, dai_link); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return soc_card_ret(card, ret); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_civoid snd_soc_card_remove_dai_link(struct snd_soc_card *card, 2208c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai_link) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci if (card->remove_dai_link) 2238c2ecf20Sopenharmony_ci card->remove_dai_link(card, dai_link); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link); 226