From patchwork Fri Jun 13 12:34:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinod Koul X-Patchwork-Id: 4348931 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 4113FBEEAA for ; Fri, 13 Jun 2014 12:45:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 12A8C2022A for ; Fri, 13 Jun 2014 12:45:32 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 7ED672008F for ; Fri, 13 Jun 2014 12:45:30 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9F16A265274; Fri, 13 Jun 2014 14:45:24 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 6A3C8261A2F; Fri, 13 Jun 2014 14:37:30 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 892D92652C2; Fri, 13 Jun 2014 14:37:29 +0200 (CEST) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by alsa0.perex.cz (Postfix) with ESMTP id 3E9E2261A38 for ; Fri, 13 Jun 2014 14:33:23 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 13 Jun 2014 05:28:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,471,1400050800"; d="scan'208";a="528029568" Received: from vkoul-udesk3.iind.intel.com (HELO localhost.localdomain) ([10.223.96.65]) by orsmga001.jf.intel.com with ESMTP; 13 Jun 2014 05:33:19 -0700 From: Vinod Koul To: alsa-devel@alsa-project.org Date: Fri, 13 Jun 2014 18:04:06 +0530 Message-Id: <1402662848-24534-18-git-send-email-vinod.koul@intel.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1402662848-24534-1-git-send-email-vinod.koul@intel.com> References: <1402662848-24534-1-git-send-email-vinod.koul@intel.com> Cc: Vinod Koul , broonie@kernel.org, lgirdwood@gmail.com, Lars-Peter Clausen Subject: [alsa-devel] [PATCH 17/19] ASoC: InteL; mrfld: add the DSP DAPM widgets X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This patchs adds all DAPM widgets and the event handlers for DSP expect the mixers. Since we are still discussing mixer update and is dependent upon component series Signed-off-by: Vinod Koul --- sound/soc/intel/sst-atom-controls.c | 237 +++++++++++++++++++++++++++++++++++ sound/soc/intel/sst-mfld-platform.h | 4 + 2 files changed, 241 insertions(+), 0 deletions(-) diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c index 2938105..2e733f8 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/sst-atom-controls.c @@ -528,6 +528,161 @@ static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { [SST_IP_MEDIA2] = SST_SWM_IN_MEDIA2, [SST_IP_MEDIA3] = SST_SWM_IN_MEDIA3, }; + +/** + * fill_swm_input - fill in the SWM input ids given the register + * + * The register value is a bit-field inicated which mixer inputs are ON. Use the + * lookup table to get the input-id and fill it in the structure. + */ +static int fill_swm_input(struct swm_input_ids *swm_input, unsigned int reg) +{ + uint i, is_set, nb_inputs = 0; + u16 input_loc_id; + + pr_debug("%s: reg: %#x\n", __func__, reg); + for (i = 0; i < SST_SWM_INPUT_COUNT; i++) { + is_set = reg & BIT(i); + if (!is_set) + continue; + + input_loc_id = swm_mixer_input_ids[i]; + SST_FILL_DESTINATION(2, swm_input->input_id, + input_loc_id, SST_DEFAULT_MODULE_ID); + nb_inputs++; + swm_input++; + pr_debug("input id: %#x, nb_inputs: %d\n", input_loc_id, nb_inputs); + + if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) { + pr_warn("%s: SET_SWM cmd max inputs reached", __func__); + break; + } + } + return nb_inputs; +} + +static void sst_set_pipe_gain(struct sst_ids *ids, struct sst_data *drv, int mute) +{ + struct sst_gain_mixer_control *mc; + struct sst_gain_value *gv; + struct sst_module *gain = NULL; + + list_for_each_entry(gain, &ids->gain_list, node) { + struct snd_kcontrol *kctl = gain->kctl; + + pr_debug("control name=%s\n", kctl->id.name); + mc = (void *)kctl->private_value; + gv = mc->gain_val; + + sst_send_gain_cmd(drv, gv, mc->task_id, + mc->pipe_id | mc->instance_id, mc->module_id, mute); + } +} + +static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct sst_cmd_set_swm cmd; + struct sst_data *drv = snd_soc_platform_get_drvdata(w->platform); + struct sst_ids *ids = w->priv; + bool set_mixer = false; + int val = drv->widget[ids->reg]; + + pr_debug("%s: widget = %s\n", __func__, w->name); + pr_debug("%s: reg[%d] = %#x\n", __func__, ids->reg, val); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + set_mixer = true; + break; + case SND_SOC_DAPM_POST_REG: + if (w->power) + set_mixer = true; + break; + default: + set_mixer = false; + } + + if (set_mixer == false) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event) || + event == SND_SOC_DAPM_POST_REG) + cmd.switch_state = SST_SWM_ON; + else + cmd.switch_state = SST_SWM_OFF; + + SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); + /* MMX_SET_SWM == SBA_SET_SWM */ + cmd.header.command_id = SBA_SET_SWM; + + SST_FILL_DESTINATION(2, cmd.output_id, + ids->location_id, SST_DEFAULT_MODULE_ID); + cmd.nb_inputs = fill_swm_input(&cmd.input[0], val); + cmd.header.length = offsetof(struct sst_cmd_set_swm, input) - sizeof(struct sst_dsp_header) + + (cmd.nb_inputs * sizeof(cmd.input[0])); + + sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, + ids->task_id, 0, &cmd, + sizeof(cmd.header) + cmd.header.length); + return 0; +} + +/* SBA mixers - 16 inputs */ +#define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name, mixer_reg) \ + static const struct snd_kcontrol_new kctl_name[] = { \ + SOC_SINGLE_EXT("codec_in0", mixer_reg, SST_IP_CODEC0, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("codec_in1", mixer_reg, SST_IP_CODEC1, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("sprot_loop_in", mixer_reg, SST_IP_LOOP0, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("media_loop1_in", mixer_reg, SST_IP_LOOP1, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("media_loop2_in", mixer_reg, SST_IP_LOOP2, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("pcm0_in", mixer_reg, SST_IP_PCM0, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("pcm1_in", mixer_reg, SST_IP_PCM1, 1, 0, \ + sst_mix_get, sst_mix_put), \ + } + +#define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ + { mix_name, "codec_in0", "codec_in0" }, \ + { mix_name, "codec_in1", "codec_in1" }, \ + { mix_name, "sprot_loop_in", "sprot_loop_in" }, \ + { mix_name, "media_loop1_in", "media_loop1_in" }, \ + { mix_name, "media_loop2_in", "media_loop2_in" }, \ + { mix_name, "pcm0_in", "pcm0_in" }, \ + { mix_name, "pcm1_in", "pcm1_in" } + +#define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name, mixer_reg) \ + static const struct snd_kcontrol_new kctl_name[] = { \ + SOC_SINGLE_EXT("media0_in", mixer_reg, SST_IP_MEDIA0, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("media1_in", mixer_reg, SST_IP_MEDIA1, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("media2_in", mixer_reg, SST_IP_MEDIA2, 1, 0, \ + sst_mix_get, sst_mix_put), \ + SOC_SINGLE_EXT("media3_in", mixer_reg, SST_IP_MEDIA3, 1, 0, \ + sst_mix_get, sst_mix_put), \ + } + +SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls, SST_MIX_MEDIA0); +SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls, SST_MIX_MEDIA1); + +/* 18 SBA mixers */ +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls, SST_MIX_PCM0); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls, SST_MIX_PCM1); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls, SST_MIX_PCM2); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls, SST_MIX_LOOP0); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls, SST_MIX_LOOP1); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls, SST_MIX_LOOP2); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls, SST_MIX_VOIP); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls, SST_MIX_CODEC0); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls, SST_MIX_CODEC1); + void sst_handle_vb_timer(struct snd_soc_platform *p, bool enable) { struct sst_cmd_generic cmd; @@ -751,6 +906,83 @@ static int sst_set_media_loop(struct snd_soc_dapm_widget *w, return 0; } +static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { + SST_AIF_IN("codec_in0", sst_set_be_modules), + SST_AIF_IN("codec_in1", sst_set_be_modules), + SST_AIF_OUT("codec_out0", sst_set_be_modules), + SST_AIF_OUT("codec_out1", sst_set_be_modules), + + /* Media Paths */ + /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */ + SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event), + SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL), + SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path), + SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL), + SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path), + SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path), + + /* SBA PCM Paths */ + SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path), + SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path), + SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path), + SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path), + SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path), + + /* SBA Loops */ + SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL), + SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL), + SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL), + SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop), + SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop), + SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop), + + /* Media Mixers */ +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"media0_in", NULL, "Compress Playback"}, + {"media1_in", NULL, "Headset Playback"}, + {"media2_in", NULL, "pcm0_out"}, + + {"media0_out mix 0", "media0_in", "media0_in"}, + {"media0_out mix 0", "media1_in", "media1_in"}, + {"media0_out mix 0", "media2_in", "media2_in"}, + {"media0_out mix 0", "media3_in", "media3_in"}, + {"media1_out mix 0", "media0_in", "media0_in"}, + {"media1_out mix 0", "media1_in", "media1_in"}, + {"media1_out mix 0", "media2_in", "media2_in"}, + {"media1_out mix 0", "media3_in", "media3_in"}, + + {"media0_out", NULL, "media0_out mix 0"}, + {"media1_out", NULL, "media1_out mix 0"}, + {"pcm0_in", NULL, "media0_out"}, + {"pcm1_in", NULL, "media1_out"}, + + {"Headset Capture", NULL, "pcm1_out"}, + {"Headset Capture", NULL, "pcm2_out"}, + {"pcm0_out", NULL, "pcm0_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"), + {"pcm1_out", NULL, "pcm1_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"), + {"pcm2_out", NULL, "pcm2_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"), + + {"media_loop1_in", NULL, "media_loop1_out"}, + {"media_loop1_out", NULL, "media_loop1_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"), + {"media_loop2_in", NULL, "media_loop2_out"}, + {"media_loop2_out", NULL, "media_loop2_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"), + {"sprot_loop_in", NULL, "sprot_loop_out"}, + {"sprot_loop_out", NULL, "sprot_loop_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"), + + {"codec_out0", NULL, "codec_out0 mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), + {"codec_out1", NULL, "codec_out1 mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), + +}; static const char * const slot_names[] = { "none", "slot 0", "slot 1", "slot 2", "slot 3", @@ -1060,6 +1292,11 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) return -ENOMEM; } + snd_soc_dapm_new_controls(&platform->dapm, sst_dapm_widgets, + ARRAY_SIZE(sst_dapm_widgets)); + snd_soc_dapm_add_routes(&platform->dapm, intercon, + ARRAY_SIZE(intercon)); + snd_soc_dapm_new_widgets(platform->dapm.card); for (i = 0; i < SST_NUM_GAINS; i++) { sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 4acdd32..fee03df 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -158,6 +158,10 @@ struct sst_device { struct sst_data; int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); +int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute); +void send_ssp_cmd(struct snd_soc_platform *platform, const char *id, bool enable); +void sst_handle_vb_timer(struct snd_soc_platform *platform, bool enable); + unsigned int sst_soc_read(struct snd_soc_platform *platform, unsigned int reg); int sst_soc_write(struct snd_soc_platform *platform, unsigned int reg, unsigned int val); unsigned int sst_reg_read(struct sst_data *sst, unsigned int reg,