forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
4.8 KiB
225 lines
4.8 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
// |
|
// soc-card.c |
|
// |
|
// Copyright (C) 2019 Renesas Electronics Corp. |
|
// Kuninori Morimoto <[email protected]> |
|
// |
|
#include <sound/soc.h> |
|
#include <sound/jack.h> |
|
|
|
#define soc_card_ret(dai, ret) _soc_card_ret(dai, __func__, ret) |
|
static inline int _soc_card_ret(struct snd_soc_card *card, |
|
const char *func, int ret) |
|
{ |
|
switch (ret) { |
|
case -EPROBE_DEFER: |
|
case -ENOTSUPP: |
|
case 0: |
|
break; |
|
default: |
|
dev_err(card->dev, |
|
"ASoC: error at %s on %s: %d\n", |
|
func, card->name, ret); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, |
|
const char *name) |
|
{ |
|
struct snd_card *card = soc_card->snd_card; |
|
struct snd_kcontrol *kctl; |
|
|
|
if (unlikely(!name)) |
|
return NULL; |
|
|
|
list_for_each_entry(kctl, &card->controls, list) |
|
if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) |
|
return kctl; |
|
return NULL; |
|
} |
|
EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); |
|
|
|
/** |
|
* snd_soc_card_jack_new - Create a new jack |
|
* @card: ASoC card |
|
* @id: an identifying string for this jack |
|
* @type: a bitmask of enum snd_jack_type values that can be detected by |
|
* this jack |
|
* @jack: structure to use for the jack |
|
* @pins: Array of jack pins to be added to the jack or NULL |
|
* @num_pins: Number of elements in the @pins array |
|
* |
|
* Creates a new jack object. |
|
* |
|
* Returns zero if successful, or a negative error code on failure. |
|
* On success jack will be initialised. |
|
*/ |
|
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, |
|
struct snd_soc_jack *jack, |
|
struct snd_soc_jack_pin *pins, unsigned int num_pins) |
|
{ |
|
int ret; |
|
|
|
mutex_init(&jack->mutex); |
|
jack->card = card; |
|
INIT_LIST_HEAD(&jack->pins); |
|
INIT_LIST_HEAD(&jack->jack_zones); |
|
BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); |
|
|
|
ret = snd_jack_new(card->snd_card, id, type, &jack->jack, false, false); |
|
if (ret) |
|
goto end; |
|
|
|
if (num_pins) |
|
ret = snd_soc_jack_add_pins(jack, num_pins, pins); |
|
end: |
|
return soc_card_ret(card, ret); |
|
} |
|
EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); |
|
|
|
int snd_soc_card_suspend_pre(struct snd_soc_card *card) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->suspend_pre) |
|
ret = card->suspend_pre(card); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_suspend_post(struct snd_soc_card *card) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->suspend_post) |
|
ret = card->suspend_post(card); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_resume_pre(struct snd_soc_card *card) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->resume_pre) |
|
ret = card->resume_pre(card); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_resume_post(struct snd_soc_card *card) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->resume_post) |
|
ret = card->resume_post(card); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_probe(struct snd_soc_card *card) |
|
{ |
|
if (card->probe) { |
|
int ret = card->probe(card); |
|
|
|
if (ret < 0) |
|
return soc_card_ret(card, ret); |
|
|
|
/* |
|
* It has "card->probe" and "card->late_probe" callbacks. |
|
* So, set "probed" flag here, because it needs to care |
|
* about "late_probe". |
|
* |
|
* see |
|
* snd_soc_bind_card() |
|
* snd_soc_card_late_probe() |
|
*/ |
|
card->probed = 1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int snd_soc_card_late_probe(struct snd_soc_card *card) |
|
{ |
|
if (card->late_probe) { |
|
int ret = card->late_probe(card); |
|
|
|
if (ret < 0) |
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
/* |
|
* It has "card->probe" and "card->late_probe" callbacks, |
|
* and "late_probe" callback is called after "probe". |
|
* This means, we can set "card->probed" flag afer "late_probe" |
|
* for all cases. |
|
* |
|
* see |
|
* snd_soc_bind_card() |
|
* snd_soc_card_probe() |
|
*/ |
|
card->probed = 1; |
|
|
|
return 0; |
|
} |
|
|
|
int snd_soc_card_remove(struct snd_soc_card *card) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->probed && |
|
card->remove) |
|
ret = card->remove(card); |
|
|
|
card->probed = 0; |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_set_bias_level(struct snd_soc_card *card, |
|
struct snd_soc_dapm_context *dapm, |
|
enum snd_soc_bias_level level) |
|
{ |
|
int ret = 0; |
|
|
|
if (card && card->set_bias_level) |
|
ret = card->set_bias_level(card, dapm, level); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_set_bias_level_post(struct snd_soc_card *card, |
|
struct snd_soc_dapm_context *dapm, |
|
enum snd_soc_bias_level level) |
|
{ |
|
int ret = 0; |
|
|
|
if (card && card->set_bias_level_post) |
|
ret = card->set_bias_level_post(card, dapm, level); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
|
|
int snd_soc_card_add_dai_link(struct snd_soc_card *card, |
|
struct snd_soc_dai_link *dai_link) |
|
{ |
|
int ret = 0; |
|
|
|
if (card->add_dai_link) |
|
ret = card->add_dai_link(card, dai_link); |
|
|
|
return soc_card_ret(card, ret); |
|
} |
|
EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link); |
|
|
|
void snd_soc_card_remove_dai_link(struct snd_soc_card *card, |
|
struct snd_soc_dai_link *dai_link) |
|
{ |
|
if (card->remove_dai_link) |
|
card->remove_dai_link(card, dai_link); |
|
} |
|
EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link);
|
|
|