#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <sound/soc-dapm.h>
#include <sound/initval.h>
#define CREATE_TRACE_POINTS
}
}
- /* Check that the codec and cpu DAI's are compatible */
+ /* Check that the codec and cpu DAIs are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
max(codec_dai_drv->playback.rate_min,
}
/*
- * Free's resources allocated by hw_params, can be called multiple times
+ * Frees resources allocated by hw_params, can be called multiple times
*/
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
if (platform->driver->ops->hw_free)
platform->driver->ops->hw_free(substream);
- /* now free hw params for the DAI's */
+ /* now free hw params for the DAIs */
if (codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
{
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
/* we're going to block userspace touching us until resume completes */
snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
- /* mute any active DAC's */
+ /* mute any active DACs */
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *dai = card->rtd[i].codec_dai;
struct snd_soc_dai_driver *drv = dai->driver;
}
/* 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) {
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,
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.
}
#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 = -ENODEV;
+
+ /* 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;
+ }
+ goto found;
+ }
+ }
+ /* codec not found */
+ dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
+ goto out;
+
+found:
+ 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);
+
+ /* 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);
}
}
+ 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),
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);
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);
{
unsigned int ret;
- ret = codec->driver->read(codec, reg);
+ ret = codec->read(codec, reg);
dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
trace_snd_soc_reg_read(codec, reg, ret);
{
dev_dbg(codec->dev, "write %x = %x\n", reg, val);
trace_snd_soc_reg_write(codec, reg, val);
- return codec->driver->write(codec, reg, val);
+ return codec->write(codec, reg, val);
}
EXPORT_SYMBOL_GPL(snd_soc_write);
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];
return -ENOMEM;
}
+ if (codec_drv->compress_type)
+ codec->compress_type = codec_drv->compress_type;
+ else
+ codec->compress_type = SND_SOC_FLAT_COMPRESSION;
+
INIT_LIST_HEAD(&codec->dapm.widgets);
INIT_LIST_HEAD(&codec->dapm.paths);
+ codec->write = codec_drv->write;
+ codec->read = codec_drv->read;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;