[v4,10/12] ASoC: Intel: mrfld: add the DSP DAPM widgets
diff mbox

Message ID 1407145563-1303-11-git-send-email-subhransu.s.prusty@intel.com
State New, archived
Headers show

Commit Message

Subhransu S. Prusty Aug. 4, 2014, 9:46 a.m. UTC
From: Vinod Koul <vinod.koul@intel.com>

This patch 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 <vinod.koul@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
---
 sound/soc/intel/sst-atom-controls.c | 220 ++++++++++++++++++++++++++++++++++++
 sound/soc/intel/sst-mfld-platform.h |   4 +
 2 files changed, 224 insertions(+)

Comments

Mark Brown Aug. 13, 2014, 8:14 p.m. UTC | #1
On Mon, Aug 04, 2014 at 03:16:01PM +0530, Subhransu S. Prusty wrote:

> +	pr_debug("%s: widget = %s\n", __func__, w->name);
> +	for (i = 0; i < w->num_kcontrols; i++) {
> +		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> +			mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
> +			val |= 1 << mc->shift;
> +		}
> +	}

All my concerns about this still stand - using something called
_get_value() to do something other than read the control value (which
this does - it uses it as a boolean then does something else to read the
value) which doesn't seem good.
Subhransu S. Prusty Aug. 14, 2014, 10:21 a.m. UTC | #2
On Wed, Aug 13, 2014 at 09:14:54PM +0100, Mark Brown wrote:
> On Mon, Aug 04, 2014 at 03:16:01PM +0530, Subhransu S. Prusty wrote:
> 
> > +	pr_debug("%s: widget = %s\n", __func__, w->name);
> > +	for (i = 0; i < w->num_kcontrols; i++) {
> > +		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > +			mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
> > +			val |= 1 << mc->shift;
> > +		}
> > +	}
> 
> All my concerns about this still stand - using something called
> _get_value() to do something other than read the control value (which
> this does - it uses it as a boolean then does something else to read the
> value) which doesn't seem good.

I think this can be optimized. This need a bit of rework in the code, but
need to check. But this would need an assumption that the controls are
created in order.

for (i = 0; i < w->num_kcontrols; i++) {
	if (dapm_kcontrol_get_value(w->kcontrols[i])) {
		val |= 1 << i;
}

Is this ok?
Mark Brown Aug. 14, 2014, 1:07 p.m. UTC | #3
On Thu, Aug 14, 2014 at 03:51:56PM +0530, Subhransu S. Prusty wrote:
> On Wed, Aug 13, 2014 at 09:14:54PM +0100, Mark Brown wrote:
> > On Mon, Aug 04, 2014 at 03:16:01PM +0530, Subhransu S. Prusty wrote:

> > > +	pr_debug("%s: widget = %s\n", __func__, w->name);
> > > +	for (i = 0; i < w->num_kcontrols; i++) {
> > > +		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > > +			mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
> > > +			val |= 1 << mc->shift;
> > > +		}
> > > +	}

> > All my concerns about this still stand - using something called
> > _get_value() to do something other than read the control value (which
> > this does - it uses it as a boolean then does something else to read the
> > value) which doesn't seem good.

> I think this can be optimized. This need a bit of rework in the code, but
> need to check. But this would need an assumption that the controls are
> created in order.

> for (i = 0; i < w->num_kcontrols; i++) {
> 	if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> 		val |= 1 << i;
> }

> Is this ok?

No, that doesn't seem safe.  Why not read the data from the control - if
we were calling a function which returned the value that'd be much
clearer.
Subhransu S. Prusty Aug. 18, 2014, 4:28 a.m. UTC | #4
On Thu, Aug 14, 2014 at 02:07:08PM +0100, Mark Brown wrote:
> On Thu, Aug 14, 2014 at 03:51:56PM +0530, Subhransu S. Prusty wrote:
> > On Wed, Aug 13, 2014 at 09:14:54PM +0100, Mark Brown wrote:
> > > On Mon, Aug 04, 2014 at 03:16:01PM +0530, Subhransu S. Prusty wrote:
> 
> > > > +	pr_debug("%s: widget = %s\n", __func__, w->name);
> > > > +	for (i = 0; i < w->num_kcontrols; i++) {
> > > > +		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > > > +			mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
> > > > +			val |= 1 << mc->shift;
> > > > +		}
> > > > +	}
> 
> > > All my concerns about this still stand - using something called
> > > _get_value() to do something other than read the control value (which
> > > this does - it uses it as a boolean then does something else to read the
> > > value) which doesn't seem good.
> 
> > I think this can be optimized. This need a bit of rework in the code, but
> > need to check. But this would need an assumption that the controls are
> > created in order.
> 
> > for (i = 0; i < w->num_kcontrols; i++) {
> > 	if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > 		val |= 1 << i;
> > }
> 
> > Is this ok?
> 
> No, that doesn't seem safe.  Why not read the data from the control - if
> we were calling a function which returned the value that'd be much
> clearer.
So lets step back and see what is required here.

I get a mixer update for one of the inputs of the mixer. This needs to be
communicated to the DSP via the IPC. But the IPC expects that we send all
the values of all the inputs of a mixer to the DSP.

That is why here we are reading the all mixer inputs to find the values and
send the bitmap of all inputs.

So from the driver if I have to find out what is the value of the inputs in
mixer, how do I do that, is there a simpler way? Or should we push
this/<something else> into framework to query

--
Mark Brown Aug. 18, 2014, 1:56 p.m. UTC | #5
On Mon, Aug 18, 2014 at 09:58:11AM +0530, Subhransu S. Prusty wrote:
> On Thu, Aug 14, 2014 at 02:07:08PM +0100, Mark Brown wrote:

> > > for (i = 0; i < w->num_kcontrols; i++) {
> > > 	if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > > 		val |= 1 << i;
> > > }

> > > Is this ok?

> > No, that doesn't seem safe.  Why not read the data from the control - if
> > we were calling a function which returned the value that'd be much
> > clearer.

> So lets step back and see what is required here.

> I get a mixer update for one of the inputs of the mixer. This needs to be
> communicated to the DSP via the IPC. But the IPC expects that we send all
> the values of all the inputs of a mixer to the DSP.

> That is why here we are reading the all mixer inputs to find the values and
> send the bitmap of all inputs.

> So from the driver if I have to find out what is the value of the inputs in
> mixer, how do I do that, is there a simpler way? Or should we push
> this/<something else> into framework to query

The problem is that it looks like you are reading the value from the
control, treating it as a boolean and discarding it.
Subhransu S. Prusty Aug. 19, 2014, 4:27 a.m. UTC | #6
On Mon, Aug 18, 2014 at 08:56:33AM -0500, Mark Brown wrote:
> On Mon, Aug 18, 2014 at 09:58:11AM +0530, Subhransu S. Prusty wrote:
> > On Thu, Aug 14, 2014 at 02:07:08PM +0100, Mark Brown wrote:
> 
> > > > for (i = 0; i < w->num_kcontrols; i++) {
> > > > 	if (dapm_kcontrol_get_value(w->kcontrols[i])) {
> > > > 		val |= 1 << i;
> > > > }
> 
> > > > Is this ok?
> 
> > > No, that doesn't seem safe.  Why not read the data from the control - if
> > > we were calling a function which returned the value that'd be much
> > > clearer.
> 
> > So lets step back and see what is required here.
> 
> > I get a mixer update for one of the inputs of the mixer. This needs to be
> > communicated to the DSP via the IPC. But the IPC expects that we send all
> > the values of all the inputs of a mixer to the DSP.
> 
> > That is why here we are reading the all mixer inputs to find the values and
> > send the bitmap of all inputs.
> 
> > So from the driver if I have to find out what is the value of the inputs in
> > mixer, how do I do that, is there a simpler way? Or should we push
> > this/<something else> into framework to query
> 
> The problem is that it looks like you are reading the value from the
> control, treating it as a boolean and discarding it.
Well the mixer input is on/off, so it should be treated as boolean. How will
it have any other value.

Btw I am thinking to create an API dapm_kcontrol_get_mixer_values() which can
give me bit map of all the mixer inputs, so I can use it and send IPCs to
the DSP.
Mark Brown Aug. 19, 2014, 4:03 p.m. UTC | #7
On Tue, Aug 19, 2014 at 09:57:11AM +0530, Subhransu S. Prusty wrote:
> On Mon, Aug 18, 2014 at 08:56:33AM -0500, Mark Brown wrote:

> > The problem is that it looks like you are reading the value from the
> > control, treating it as a boolean and discarding it.

> Well the mixer input is on/off, so it should be treated as boolean. How will
> it have any other value.

OK, so you're trying to read a boolean value.  Perhaps what you need
here is some comments then - the way you fiddle about with the bitmasks
afterwards doesn't make it sufficient obvious.

Patch
diff mbox

diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
index 5a181b32c247..029e6960ca73 100644
--- a/sound/soc/intel/sst-atom-controls.c
+++ b/sound/soc/intel/sst-atom-controls.c
@@ -492,6 +492,39 @@  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;
@@ -509,6 +542,109 @@  static void sst_set_pipe_gain(struct sst_ids *ids, struct sst_data *drv, int mut
 				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 snd_soc_platform *platform = snd_soc_dapm_to_platform(w->dapm);
+	struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+	struct sst_ids *ids = w->priv;
+	bool set_mixer = false;
+	struct soc_mixer_control *mc;
+	int val = 0;
+	int i = 0;
+
+	pr_debug("%s: widget = %s\n", __func__, w->name);
+	for (i = 0; i < w->num_kcontrols; i++) {
+		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
+			mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
+			val |= 1 << mc->shift;
+		}
+	}
+	pr_debug("%s: val = %#x\n", __func__, 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)						\
+	static const struct snd_kcontrol_new kctl_name[] = {				\
+		SOC_DAPM_SINGLE("codec_in0", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0),	\
+		SOC_DAPM_SINGLE("codec_in1", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0),	\
+		SOC_DAPM_SINGLE("sprot_loop_in", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0),	\
+		SOC_DAPM_SINGLE("media_loop1_in", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0),	\
+		SOC_DAPM_SINGLE("media_loop2_in", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0),	\
+		SOC_DAPM_SINGLE("pcm0_in", SND_SOC_NOPM, SST_IP_PCM0, 1, 0),		\
+		SOC_DAPM_SINGLE("pcm1_in", SND_SOC_NOPM, SST_IP_PCM1, 1, 0),		\
+	}
+
+#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)			\
+	static const struct snd_kcontrol_new kctl_name[] = {			\
+		SOC_DAPM_SINGLE("media0_in", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0),	\
+		SOC_DAPM_SINGLE("media1_in", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0),	\
+		SOC_DAPM_SINGLE("media2_in", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0),	\
+		SOC_DAPM_SINGLE("media3_in", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0),	\
+	}
+
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls);
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls);
+
+/* 18 SBA mixers */
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls);
+
 void sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
 {
 	struct sst_cmd_generic cmd;
@@ -688,6 +824,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",
@@ -981,6 +1194,8 @@  static int sst_map_modules_to_pipe(struct snd_soc_platform *platform)
 int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
 {
 	int i, ret = 0;
+	struct snd_soc_dapm_context *dapm =
+			snd_soc_component_get_dapm(&platform->component);
 	struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
 
 	drv->byte_stream = devm_kzalloc(platform->dev,
@@ -988,6 +1203,11 @@  int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
 	if (!drv->byte_stream)
 		return -ENOMEM;
 
+	snd_soc_dapm_new_controls(dapm, sst_dapm_widgets,
+			ARRAY_SIZE(sst_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, intercon,
+			ARRAY_SIZE(intercon));
+	snd_soc_dapm_new_widgets(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 1f42b9ce5554..09ecf44f33fb 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -146,6 +146,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_dai *dai, const char *id, bool enable);
+void sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable);
+
 void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
 int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
 			   struct snd_sst_params *str_params, bool is_compress);