static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* first we call set_params for the platform driver * this should configure the soc side * if the machine has compressed ops then we call that as well * expectation is that platform and machine will configure everything * for this compress path, like configuring pcm port for codec */ if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); if (ret < 0) goto err; } if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) goto err; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) goto err; } if (cstream->direction == SND_COMPRESS_PLAYBACK) snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_START); else snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_START); /* cancel any delayed stream shutdown that is pending */ rtd->pop_wait = 0; mutex_unlock(&rtd->pcm_mutex); cancel_delayed_work_sync(&rtd->delayed_work); return ret; err: mutex_unlock(&rtd->pcm_mutex); return ret; }
static int soc_compr_free(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; int stream; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; else stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_runtime_deactivate(rtd, stream); snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); if (!cpu_dai->active) cpu_dai->rate = 0; if (!codec_dai->active) codec_dai->rate = 0; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) rtd->dai_link->compr_ops->shutdown(cstream); if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } else { rtd->pop_wait = 1; queue_delayed_work(system_power_efficient_wq, &rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } } else { /* capture streams can be powered down now */ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); return 0; }
static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* first we call set_params for the platform driver * this should configure the soc side * if the machine has compressed ops then we call that as well * expectation is that platform and machine will configure everything * for this compress path, like configuring pcm port for codec */ if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) goto out; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) goto out; } snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_START); out: mutex_unlock(&rtd->pcm_mutex); return ret; }
/* * Called by ALSA when a PCM substream is closed. Private data can be * freed here. The cpu DAI, codec DAI, machine and platform are also * shutdown. */ static int soc_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; codec_dai->playback_active--; } else { cpu_dai->capture_active--; codec_dai->capture_active--; } cpu_dai->active--; codec_dai->active--; codec->active--; if (!cpu_dai->active && !codec_dai->active) rtd->rate = 0; /* Muting the DAC suppresses artifacts caused during digital * shutdown, for example from stopping clocks. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } else { /* capture streams can be powered down now */ snd_soc_dapm_stream_event(rtd, codec_dai->driver->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); return 0; }
/* pay attention: application should lock the route set period. */ static int bb_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned short reg; struct snd_soc_codec *codec = wm9713_dai[WM9713_DAI_PCM_VOICE].codec; if (bb_enable == 1 && ucontrol->value.integer.value[0] == 0) printk(KERN_INFO "Disable BB!!\n"); if (bb_enable == 0 && ucontrol->value.integer.value[0] == 1) { printk(KERN_INFO "Enable BB!!\n"); snd_soc_dapm_stream_event(codec, "Voice Playback", SND_SOC_DAPM_STREAM_START); snd_soc_dapm_stream_event(codec, "Voice Capture", SND_SOC_DAPM_STREAM_START); /*enable VRA mode*/ codec->write(codec, AC97_EXTENDED_STATUS, 0x1); codec->write(codec, AC97_PCM_LR_ADC_RATE, 0x1F40); codec->write(codec, AC97_EXTENDED_MID, codec->read(codec, AC97_EXTENDED_MID)&0xffc3); codec->write(codec, AC97_EXTENDED_MSTATUS, codec->read(codec, AC97_EXTENDED_MSTATUS)&0xf9f5); codec->write(codec, AC97_POWERDOWN, 0); codec->write(codec, AC97_HANDSET_RATE, 0x0f80); schedule_timeout_interruptible(msecs_to_jiffies(10)); codec->write(codec, AC97_CENTER_LFE_MASTER, 0xa8b3); reg = codec->read(codec, AC97_GPIO_CFG); reg |= (0x1<<1); reg |= (0x1<<3); reg |= (0x1<<4); reg &= ~(0x1<<5); codec->write(codec, AC97_GPIO_CFG, reg); schedule_timeout_interruptible(msecs_to_jiffies(10)); } bb_enable = ucontrol->value.integer.value[0]; return 0; }
static int zoom2_set_capture_state(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; if (zoom2_capture_state == ucontrol->value.integer.value[0]) return 0; if (ucontrol->value.integer.value[0]) { ret = snd_soc_dapm_stream_event(g_rtd, 1, "Capture", SND_SOC_DAPM_STREAM_START); } else { ret = snd_soc_dapm_stream_event(g_rtd, 1, "Capture", SND_SOC_DAPM_STREAM_STOP); } if (ret != 0) { printk(KERN_ERR "failed to set capture state\n"); return 0; } zoom2_capture_state = ucontrol->value.integer.value[0]; return 1; }
/* * Power down the audio subsystem pmdown_time msecs after close is called. * This is to ensure there are no pops or clicks in between any music tracks * due to DAPM power cycling. */ static void close_delayed_work(struct work_struct *work) { struct snd_soc_pcm_runtime *rtd = container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, codec_dai->playback_active ? "active" : "inactive", rtd->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ if (rtd->pop_wait == 1) { rtd->pop_wait = 0; snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); }
static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) goto err; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) goto err; } snd_soc_dapm_stream_event(rtd, codec_dai->driver->playback.stream_name, SND_SOC_DAPM_STREAM_START); codec_dai->pop_wait = 0; mutex_unlock(&rtd->pcm_mutex); cancel_delayed_work_sync(&rtd->delayed_work); return ret; err: mutex_unlock(&rtd->pcm_mutex); return ret; }
/* * Called by ALSA when the PCM substream is prepared, can set format, sample * rate, etc. This function is non atomic and can be called multiple times, * it can refer to the runtime info. */ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { pr_err("asoc: machine prepare error: %d\n", ret); goto out; } } if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { dev_err(platform->dev, "platform prepare error: %d\n", ret); goto out; } } if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { dev_err(codec_dai->dev, "DAI prepare error: %d\n", ret); goto out; } } if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "DAI prepare error: %d\n", ret); goto out; } } /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && codec_dai->pop_wait) { codec_dai->pop_wait = 0; cancel_delayed_work(&rtd->delayed_work); } snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai, SND_SOC_DAPM_STREAM_START); snd_soc_dai_digital_mute(codec_dai, 0); out: mutex_unlock(&rtd->pcm_mutex); return ret; }
static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; unsigned short reg; int ret = 0; /* Enable voice interface */ reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF); reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg); /* hifi state */ ret = snd_soc_dapm_stream_event(rtd, 1, "Capture", SND_SOC_DAPM_STREAM_START); /* voice state */ /* this is not dynamic, so ignore dir */ ret = snd_soc_dapm_stream_event(rtd, 1, "TWL4030 Voice", SND_SOC_DAPM_STREAM_START); /* Enable voice digital filters */ snd_soc_update_bits(codec, TWL4030_REG_OPTION, TWL4030_ARXL1_VRX_EN, 0x10); ret = snd_soc_dapm_stream_event(rtd, 1, "TWL4030 Voice", SND_SOC_DAPM_STREAM_START); /* reinit defaults */ snd_soc_update_bits(codec, 1, 1, 0); snd_soc_update_bits(codec, 17, 63, 50); snd_soc_update_bits(codec, 16, 63, 50); snd_soc_update_bits(codec, 19, 63, 45); snd_soc_update_bits(codec, 18, 63, 45); snd_soc_update_bits(codec, 17, 192, 128); snd_soc_update_bits(codec, 16, 192, 128); snd_soc_update_bits(codec, 19, 192, 128); snd_soc_update_bits(codec, 18, 192, 128); snd_soc_update_bits(codec, 25, 248, 0); snd_soc_update_bits(codec, 26, 248, 0); snd_soc_update_bits(codec, 27, 248, 32); snd_soc_update_bits(codec, 28, 248, 32); snd_soc_update_bits(codec, 25, 2, 0); snd_soc_update_bits(codec, 26, 2, 0); snd_soc_update_bits(codec, 27, 2, 2); snd_soc_update_bits(codec, 28, 2, 2); snd_soc_update_bits(codec, 20, 63, 36); snd_soc_update_bits(codec, 68, 2, 0); snd_soc_update_bits(codec, 37, 48, 16); snd_soc_update_bits(codec, 37, 48, 16); snd_soc_update_bits(codec, 38, 48, 16); snd_soc_update_bits(codec, 35, 15, 5); snd_soc_update_bits(codec, 39, 48, 16); snd_soc_update_bits(codec, 40, 48, 16); snd_soc_update_bits(codec, 33, 48, 16); snd_soc_update_bits(codec, 10, 31, 23); snd_soc_update_bits(codec, 11, 31, 23); snd_soc_update_bits(codec, 12, 31, 23); snd_soc_update_bits(codec, 13, 31, 23); snd_soc_update_bits(codec, 72, 63, 27); snd_soc_update_bits(codec, 7, 4, 0); snd_soc_update_bits(codec, 36, 28, 12); snd_soc_update_bits(codec, 69, 32, 0); snd_soc_update_bits(codec, 69, 2, 0); return 0; }
/* * Called by ALSA when a PCM substream is closed. Private data can be * freed here. The cpu DAI, codec DAI, machine and platform are also * shutdown. */ static int soc_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; codec_dai->playback_active--; } else { cpu_dai->capture_active--; codec_dai->capture_active--; } cpu_dai->active--; codec_dai->active--; codec->active--; /* clear the corresponding DAIs rate when inactive */ if (!cpu_dai->active) cpu_dai->rate = 0; if (!codec_dai->active) codec_dai->rate = 0; /* Muting the DAC suppresses artifacts caused during digital * shutdown, for example from stopping clocks. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !codec_dai->playback_active) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); if (codec_dai->driver->ops->shutdown && !codec_dai->playback_active) codec_dai->driver->ops->shutdown(substream, codec_dai); if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !codec_dai->playback_active) { if (!rtd->pmdown_time || codec->ignore_pmdown_time || rtd->dai_link->ignore_pmdown_time) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, codec_dai, SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; queue_delayed_work(system_power_efficient_wq, &rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } } else { /* capture streams can be powered down now */ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, codec_dai, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); pm_runtime_put(platform->dev); pm_runtime_put(codec_dai->dev); pm_runtime_put(cpu_dai->dev); return 0; }