Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 230316
b: refs/heads/master
c: 2eea392
h: refs/heads/master
v: v3
  • Loading branch information
Jarkko Nikula authored and Mark Brown committed Nov 30, 2010
1 parent 4f8c6d4 commit 990b4f7
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 09c74a9d0b0bedff16d0881db8cc0054a5e34f47
refs/heads/master: 2eea392d0a28a0a07d36a9da544eb40f81bf4cb6
17 changes: 17 additions & 0 deletions trunk/include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,14 @@ struct snd_soc_prefix_map {
const char *name_prefix;
};

struct snd_soc_aux_dev {
const char *name; /* Codec name */
const char *codec_name; /* for multi-codec */

/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_dapm_context *dapm);
};

/* SoC card */
struct snd_soc_card {
const char *name;
Expand Down Expand Up @@ -624,6 +632,15 @@ struct snd_soc_card {
struct snd_soc_prefix_map *prefix_map;
int num_prefixes;

/*
* optional auxiliary devices such as amplifiers or codecs with DAI
* link unused
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;

struct work_struct deferred_resume_work;

/* lists of probed devices belonging to this card */
Expand Down
155 changes: 149 additions & 6 deletions trunk/sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,7 @@ static int soc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
int i;

/* If the initialization of this soc device failed, there is no codec
Expand Down Expand Up @@ -1064,8 +1065,7 @@ static int soc_suspend(struct device *dev)
}

/* suspend all CODECs */
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_codec *codec = card->rtd[i].codec;
list_for_each_entry(codec, &card->codec_dev_list, card_list) {
/* If there are paths active then the CODEC will be held with
* bias _ON and should not be suspended. */
if (!codec->suspended && codec->driver->suspend) {
Expand Down Expand Up @@ -1106,6 +1106,7 @@ static void soc_resume_deferred(struct work_struct *work)
struct snd_soc_card *card =
container_of(work, struct snd_soc_card, deferred_resume_work);
struct platform_device *pdev = to_platform_device(card->dev);
struct snd_soc_codec *codec;
int i;

/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
Expand All @@ -1131,8 +1132,7 @@ static void soc_resume_deferred(struct work_struct *work)
cpu_dai->driver->resume(cpu_dai);
}

for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_codec *codec = card->rtd[i].codec;
list_for_each_entry(codec, &card->codec_dev_list, card_list) {
/* If the CODEC was idle over suspend then it will have been
* left with bias OFF or STANDBY and suspended so we must now
* resume. Otherwise the suspend was suppressed.
Expand Down Expand Up @@ -1603,6 +1603,130 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
}
#endif

static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
struct snd_soc_codec *codec;
const char *temp;
int ret = 0;

/* find CODEC from registered CODECs*/
list_for_each_entry(codec, &codec_list, list) {
if (!strcmp(codec->name, aux_dev->codec_name)) {
if (codec->probed) {
dev_err(codec->dev,
"asoc: codec already probed");
ret = -EBUSY;
goto out;
}
break;
}
}

if (!try_module_get(codec->dev->driver->owner))
return -ENODEV;

codec->card = card;
codec->dapm.card = card;

soc_set_name_prefix(card, codec);
if (codec->driver->probe) {
ret = codec->driver->probe(codec);
if (ret < 0) {
dev_err(codec->dev, "asoc: failed to probe CODEC");
return ret;
}
}

soc_init_codec_debugfs(codec);

/* mark codec as probed and add to card codec list */
codec->probed = 1;
list_add(&codec->card_list, &card->codec_dev_list);
list_add(&codec->dapm.list, &card->dapm_list);

/* now that all clients have probed, initialise the DAI link */
if (aux_dev->init) {
/* machine controls, routes and widgets are not prefixed */
temp = codec->name_prefix;
codec->name_prefix = NULL;
ret = aux_dev->init(&codec->dapm);
if (ret < 0) {
dev_err(codec->dev,
"asoc: failed to init %s\n", aux_dev->name);
return ret;
}
codec->name_prefix = temp;
}

/* Make sure all DAPM widgets are instantiated */
snd_soc_dapm_new_widgets(&codec->dapm);
snd_soc_dapm_sync(&codec->dapm);

/* register the rtd device */
rtd->codec = codec;
rtd->card = card;
rtd->dev.parent = card->dev;
rtd->dev.release = rtd_release;
rtd->dev.init_name = aux_dev->name;
ret = device_register(&rtd->dev);
if (ret < 0) {
dev_err(codec->dev,
"asoc: failed to register aux runtime device %d\n",
ret);
return ret;
}
rtd->dev_registered = 1;

/* add DAPM sysfs entries for this codec */
ret = snd_soc_dapm_sys_add(&rtd->dev);
if (ret < 0)
dev_err(codec->dev,
"asoc: failed to add codec dapm sysfs entries\n");

/* add codec sysfs entries */
ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
if (ret < 0)
dev_err(codec->dev, "asoc: failed to add codec sysfs files\n");

out:
return ret;
}

static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
struct snd_soc_codec *codec = rtd->codec;
int err;

/* unregister the rtd device */
if (rtd->dev_registered) {
device_unregister(&rtd->dev);
rtd->dev_registered = 0;
}

/* remove the CODEC */
if (codec && codec->probed) {
if (codec->driver->remove) {
err = codec->driver->remove(codec);
if (err < 0)
dev_err(codec->dev,
"asoc: failed to remove %s\n",
codec->name);
}

/* Make sure all DAPM widgets are freed */
snd_soc_dapm_free(&codec->dapm);

soc_cleanup_codec_debugfs(codec);
device_remove_file(&rtd->dev, &dev_attr_codec_reg);
codec->probed = 0;
list_del(&codec->card_list);
module_put(codec->dev->driver->owner);
}
}

static void snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct platform_device *pdev = to_platform_device(card->dev);
Expand Down Expand Up @@ -1657,6 +1781,15 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
}

for (i = 0; i < card->num_aux_devs; i++) {
ret = soc_probe_aux_dev(card, i);
if (ret < 0) {
pr_err("asoc: failed to add auxiliary devices %s: %d\n",
card->name, ret);
goto probe_aux_dev_err;
}
}

snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
Expand All @@ -1683,6 +1816,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
mutex_unlock(&card->mutex);
return;

probe_aux_dev_err:
for (i = 0; i < card->num_aux_devs; i++)
soc_remove_aux_dev(card, i);

probe_dai_err:
for (i = 0; i < card->num_links; i++)
soc_remove_dai_link(card, i);
Expand Down Expand Up @@ -1744,6 +1881,10 @@ static int soc_remove(struct platform_device *pdev)
run_delayed_work(&rtd->delayed_work);
}

/* remove auxiliary devices */
for (i = 0; i < card->num_aux_devs; i++)
soc_remove_aux_dev(card, i);

/* remove and free each DAI */
for (i = 0; i < card->num_rtd; i++)
soc_remove_dai_link(card, i);
Expand Down Expand Up @@ -2946,10 +3087,12 @@ static int snd_soc_register_card(struct snd_soc_card *card)
if (!card->name || !card->dev)
return -EINVAL;

card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
GFP_KERNEL);
card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
(card->num_links + card->num_aux_devs),
GFP_KERNEL);
if (card->rtd == NULL)
return -ENOMEM;
card->rtd_aux = &card->rtd[card->num_links];

for (i = 0; i < card->num_links; i++)
card->rtd[i].dai_link = &card->dai_link[i];
Expand Down

0 comments on commit 990b4f7

Please sign in to comment.