2 * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
4 * Copyright (C) 2013-14 Intel Corp
5 * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
6 * Vinod Koul <vinod.koul@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active
19 * we forward the settings and parameters, rest we keep the values in
20 * driver and forward when DAPM enables them
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #include <linux/slab.h>
26 #include <sound/soc.h>
27 #include <sound/tlv.h>
28 #include "sst-mfld-platform.h"
29 #include "sst-atom-controls.h"
31 static int sst_fill_byte_control(struct sst_data
*drv
,
33 u8 task_id
, u8 pipe_id
,
34 u16 len
, void *cmd_data
)
36 struct snd_sst_bytes_v2
*byte_data
= drv
->byte_stream
;
38 byte_data
->type
= SST_CMD_BYTES_SET
;
39 byte_data
->ipc_msg
= ipc_msg
;
40 byte_data
->block
= block
;
41 byte_data
->task_id
= task_id
;
42 byte_data
->pipe_id
= pipe_id
;
44 if (len
> SST_MAX_BIN_BYTES
- sizeof(*byte_data
)) {
45 dev_err(&drv
->pdev
->dev
, "command length too big (%u)", len
);
49 memcpy(byte_data
->bytes
, cmd_data
, len
);
50 print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET
,
51 byte_data
, len
+ sizeof(*byte_data
));
55 static int sst_fill_and_send_cmd_unlocked(struct sst_data
*drv
,
56 u8 ipc_msg
, u8 block
, u8 task_id
, u8 pipe_id
,
57 void *cmd_data
, u16 len
)
61 ret
= sst_fill_byte_control(drv
, ipc_msg
,
62 block
, task_id
, pipe_id
, len
, cmd_data
);
65 return sst
->ops
->send_byte_stream(sst
->dev
, drv
->byte_stream
);
69 * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
70 * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS)
71 * @cmd_data: the IPC payload
73 static int sst_fill_and_send_cmd(struct sst_data
*drv
,
74 u8 ipc_msg
, u8 block
, u8 task_id
, u8 pipe_id
,
75 void *cmd_data
, u16 len
)
79 mutex_lock(&drv
->lock
);
80 ret
= sst_fill_and_send_cmd_unlocked(drv
, ipc_msg
, block
,
81 task_id
, pipe_id
, cmd_data
, len
);
82 mutex_unlock(&drv
->lock
);
88 * tx map value is a bitfield where each bit represents a FW channel
90 * 3 2 1 0 # 0 = codec0, 1 = codec1
91 * RLRLRLRL # 3, 4 = reserved
93 * e.g. slot 0 rx map = 00001100b -> data from slot 0 goes into codec_in1 L,R
95 static u8 sst_ssp_tx_map
[SST_MAX_TDM_SLOTS
] = {
96 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */
100 * rx map value is a bitfield where each bit represents a slot
102 * 76543210 # 0 = slot 0, 1 = slot 1
104 * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2
106 static u8 sst_ssp_rx_map
[SST_MAX_TDM_SLOTS
] = {
107 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */
111 * NOTE: this is invoked with lock held
113 static int sst_send_slot_map(struct sst_data
*drv
)
115 struct sst_param_sba_ssp_slot_map cmd
;
117 SST_FILL_DEFAULT_DESTINATION(cmd
.header
.dst
);
118 cmd
.header
.command_id
= SBA_SET_SSP_SLOT_MAP
;
119 cmd
.header
.length
= sizeof(struct sst_param_sba_ssp_slot_map
)
120 - sizeof(struct sst_dsp_header
);
122 cmd
.param_id
= SBA_SET_SSP_SLOT_MAP
;
123 cmd
.param_len
= sizeof(cmd
.rx_slot_map
) + sizeof(cmd
.tx_slot_map
)
124 + sizeof(cmd
.ssp_index
);
125 cmd
.ssp_index
= SSP_CODEC
;
127 memcpy(cmd
.rx_slot_map
, &sst_ssp_tx_map
[0], sizeof(cmd
.rx_slot_map
));
128 memcpy(cmd
.tx_slot_map
, &sst_ssp_rx_map
[0], sizeof(cmd
.tx_slot_map
));
130 return sst_fill_and_send_cmd_unlocked(drv
, SST_IPC_IA_SET_PARAMS
,
131 SST_FLAG_BLOCKED
, SST_TASK_SBA
, 0, &cmd
,
132 sizeof(cmd
.header
) + cmd
.header
.length
);
135 int sst_slot_enum_info(struct snd_kcontrol
*kcontrol
,
136 struct snd_ctl_elem_info
*uinfo
)
138 struct sst_enum
*e
= (struct sst_enum
*)kcontrol
->private_value
;
140 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_ENUMERATED
;
142 uinfo
->value
.enumerated
.items
= e
->max
;
144 if (uinfo
->value
.enumerated
.item
> e
->max
- 1)
145 uinfo
->value
.enumerated
.item
= e
->max
- 1;
146 strcpy(uinfo
->value
.enumerated
.name
,
147 e
->texts
[uinfo
->value
.enumerated
.item
]);
153 * sst_slot_get - get the status of the interleaver/deinterleaver control
155 * Searches the map where the control status is stored, and gets the
156 * channel/slot which is currently set for this enumerated control. Since it is
157 * an enumerated control, there is only one possible value.
159 static int sst_slot_get(struct snd_kcontrol
*kcontrol
,
160 struct snd_ctl_elem_value
*ucontrol
)
162 struct sst_enum
*e
= (void *)kcontrol
->private_value
;
163 struct snd_soc_component
*c
= snd_kcontrol_chip(kcontrol
);
164 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
165 unsigned int ctl_no
= e
->reg
;
166 unsigned int is_tx
= e
->tx
;
167 unsigned int val
, mux
;
168 u8
*map
= is_tx
? sst_ssp_rx_map
: sst_ssp_tx_map
;
170 mutex_lock(&drv
->lock
);
172 /* search which slot/channel has this bit set - there should be only one */
173 for (mux
= e
->max
; mux
> 0; mux
--)
174 if (map
[mux
- 1] & val
)
177 ucontrol
->value
.enumerated
.item
[0] = mux
;
178 mutex_unlock(&drv
->lock
);
180 dev_dbg(c
->dev
, "%s - %s map = %#x\n",
181 is_tx
? "tx channel" : "rx slot",
182 e
->texts
[mux
], mux
? map
[mux
- 1] : -1);
186 /* sst_check_and_send_slot_map - helper for checking power state and sending
189 * called with lock held
191 static int sst_check_and_send_slot_map(struct sst_data
*drv
, struct snd_kcontrol
*kcontrol
)
193 struct sst_enum
*e
= (void *)kcontrol
->private_value
;
196 if (e
->w
&& e
->w
->power
)
197 ret
= sst_send_slot_map(drv
);
199 dev_err(&drv
->pdev
->dev
, "Slot control: %s doesn't have DAPM widget!!!\n",
205 * sst_slot_put - set the status of interleaver/deinterleaver control
207 * (de)interleaver controls are defined in opposite sense to be user-friendly
209 * Instead of the enum value being the value written to the register, it is the
210 * register address; and the kcontrol number (register num) is the value written
211 * to the register. This is so that there can be only one value for each
212 * slot/channel since there is only one control for each slot/channel.
214 * This means that whenever an enum is set, we need to clear the bit
215 * for that kcontrol_no for all the interleaver OR deinterleaver registers
217 static int sst_slot_put(struct snd_kcontrol
*kcontrol
,
218 struct snd_ctl_elem_value
*ucontrol
)
220 struct snd_soc_component
*c
= snd_soc_kcontrol_component(kcontrol
);
221 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
222 struct sst_enum
*e
= (void *)kcontrol
->private_value
;
224 unsigned int ctl_no
= e
->reg
;
225 unsigned int is_tx
= e
->tx
;
226 unsigned int slot_channel_no
;
227 unsigned int val
, mux
;
230 map
= is_tx
? sst_ssp_rx_map
: sst_ssp_tx_map
;
233 mux
= ucontrol
->value
.enumerated
.item
[0];
234 if (mux
> e
->max
- 1)
237 mutex_lock(&drv
->lock
);
238 /* first clear all registers of this bit */
239 for (i
= 0; i
< e
->max
; i
++)
243 /* kctl set to 'none' and we reset the bits so send IPC */
244 ret
= sst_check_and_send_slot_map(drv
, kcontrol
);
246 mutex_unlock(&drv
->lock
);
250 /* offset by one to take "None" into account */
251 slot_channel_no
= mux
- 1;
252 map
[slot_channel_no
] |= val
;
254 dev_dbg(c
->dev
, "%s %s map = %#x\n",
255 is_tx
? "tx channel" : "rx slot",
256 e
->texts
[mux
], map
[slot_channel_no
]);
258 ret
= sst_check_and_send_slot_map(drv
, kcontrol
);
260 mutex_unlock(&drv
->lock
);
264 static int sst_send_algo_cmd(struct sst_data
*drv
,
265 struct sst_algo_control
*bc
)
268 struct sst_cmd_set_params
*cmd
;
270 /*bc->max includes sizeof algos + length field*/
271 len
= sizeof(cmd
->dst
) + sizeof(cmd
->command_id
) + bc
->max
;
273 cmd
= kzalloc(len
, GFP_KERNEL
);
277 SST_FILL_DESTINATION(2, cmd
->dst
, bc
->pipe_id
, bc
->module_id
);
278 cmd
->command_id
= bc
->cmd_id
;
279 memcpy(cmd
->params
, bc
->params
, bc
->max
);
281 ret
= sst_fill_and_send_cmd_unlocked(drv
, SST_IPC_IA_SET_PARAMS
,
282 SST_FLAG_BLOCKED
, bc
->task_id
, 0, cmd
, len
);
288 * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe
290 * The algos which are in each pipeline are sent to the firmware one by one
292 * Called with lock held
294 static int sst_find_and_send_pipe_algo(struct sst_data
*drv
,
295 const char *pipe
, struct sst_ids
*ids
)
298 struct sst_algo_control
*bc
;
299 struct sst_module
*algo
= NULL
;
301 dev_dbg(&drv
->pdev
->dev
, "Enter: widget=%s\n", pipe
);
303 list_for_each_entry(algo
, &ids
->algo_list
, node
) {
304 bc
= (void *)algo
->kctl
->private_value
;
306 dev_dbg(&drv
->pdev
->dev
, "Found algo control name=%s pipe=%s\n",
307 algo
->kctl
->id
.name
, pipe
);
308 ret
= sst_send_algo_cmd(drv
, bc
);
315 static int sst_algo_bytes_ctl_info(struct snd_kcontrol
*kcontrol
,
316 struct snd_ctl_elem_info
*uinfo
)
318 struct sst_algo_control
*bc
= (void *)kcontrol
->private_value
;
320 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BYTES
;
321 uinfo
->count
= bc
->max
;
326 static int sst_algo_control_get(struct snd_kcontrol
*kcontrol
,
327 struct snd_ctl_elem_value
*ucontrol
)
329 struct sst_algo_control
*bc
= (void *)kcontrol
->private_value
;
330 struct snd_soc_component
*component
= snd_kcontrol_chip(kcontrol
);
333 case SST_ALGO_PARAMS
:
334 memcpy(ucontrol
->value
.bytes
.data
, bc
->params
, bc
->max
);
337 dev_err(component
->dev
, "Invalid Input- algo type:%d\n",
345 static int sst_algo_control_set(struct snd_kcontrol
*kcontrol
,
346 struct snd_ctl_elem_value
*ucontrol
)
349 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
350 struct sst_data
*drv
= snd_soc_component_get_drvdata(cmpnt
);
351 struct sst_algo_control
*bc
= (void *)kcontrol
->private_value
;
353 dev_dbg(cmpnt
->dev
, "control_name=%s\n", kcontrol
->id
.name
);
354 mutex_lock(&drv
->lock
);
356 case SST_ALGO_PARAMS
:
357 memcpy(bc
->params
, ucontrol
->value
.bytes
.data
, bc
->max
);
360 mutex_unlock(&drv
->lock
);
361 dev_err(cmpnt
->dev
, "Invalid Input- algo type:%d\n",
365 /*if pipe is enabled, need to send the algo params from here*/
366 if (bc
->w
&& bc
->w
->power
)
367 ret
= sst_send_algo_cmd(drv
, bc
);
368 mutex_unlock(&drv
->lock
);
373 static int sst_gain_ctl_info(struct snd_kcontrol
*kcontrol
,
374 struct snd_ctl_elem_info
*uinfo
)
376 struct sst_gain_mixer_control
*mc
= (void *)kcontrol
->private_value
;
378 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
379 uinfo
->count
= mc
->stereo
? 2 : 1;
380 uinfo
->value
.integer
.min
= mc
->min
;
381 uinfo
->value
.integer
.max
= mc
->max
;
387 * sst_send_gain_cmd - send the gain algorithm IPC to the FW
388 * @gv: the stored value of gain (also contains rampduration)
389 * @mute: flag that indicates whether this was called from the
390 * digital_mute callback or directly. If called from the
391 * digital_mute callback, module will be muted/unmuted based on this
392 * flag. The flag is always 0 if called directly.
394 * Called with sst_data.lock held
396 * The user-set gain value is sent only if the user-controllable 'mute' control
397 * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is
400 static int sst_send_gain_cmd(struct sst_data
*drv
, struct sst_gain_value
*gv
,
401 u16 task_id
, u16 loc_id
, u16 module_id
, int mute
)
403 struct sst_cmd_set_gain_dual cmd
;
405 dev_dbg(&drv
->pdev
->dev
, "Enter\n");
407 cmd
.header
.command_id
= MMX_SET_GAIN
;
408 SST_FILL_DEFAULT_DESTINATION(cmd
.header
.dst
);
409 cmd
.gain_cell_num
= 1;
411 if (mute
|| gv
->mute
) {
412 cmd
.cell_gains
[0].cell_gain_left
= SST_GAIN_MIN_VALUE
;
413 cmd
.cell_gains
[0].cell_gain_right
= SST_GAIN_MIN_VALUE
;
415 cmd
.cell_gains
[0].cell_gain_left
= gv
->l_gain
;
416 cmd
.cell_gains
[0].cell_gain_right
= gv
->r_gain
;
419 SST_FILL_DESTINATION(2, cmd
.cell_gains
[0].dest
,
421 cmd
.cell_gains
[0].gain_time_constant
= gv
->ramp_duration
;
423 cmd
.header
.length
= sizeof(struct sst_cmd_set_gain_dual
)
424 - sizeof(struct sst_dsp_header
);
426 /* we are with lock held, so call the unlocked api to send */
427 return sst_fill_and_send_cmd_unlocked(drv
, SST_IPC_IA_SET_PARAMS
,
428 SST_FLAG_BLOCKED
, task_id
, 0, &cmd
,
429 sizeof(cmd
.header
) + cmd
.header
.length
);
432 static int sst_gain_get(struct snd_kcontrol
*kcontrol
,
433 struct snd_ctl_elem_value
*ucontrol
)
435 struct snd_soc_component
*component
= snd_kcontrol_chip(kcontrol
);
436 struct sst_gain_mixer_control
*mc
= (void *)kcontrol
->private_value
;
437 struct sst_gain_value
*gv
= mc
->gain_val
;
441 ucontrol
->value
.integer
.value
[0] = gv
->l_gain
;
442 ucontrol
->value
.integer
.value
[1] = gv
->r_gain
;
446 ucontrol
->value
.integer
.value
[0] = gv
->mute
? 1 : 0;
449 case SST_GAIN_RAMP_DURATION
:
450 ucontrol
->value
.integer
.value
[0] = gv
->ramp_duration
;
454 dev_err(component
->dev
, "Invalid Input- gain type:%d\n",
462 static int sst_gain_put(struct snd_kcontrol
*kcontrol
,
463 struct snd_ctl_elem_value
*ucontrol
)
466 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
467 struct sst_data
*drv
= snd_soc_component_get_drvdata(cmpnt
);
468 struct sst_gain_mixer_control
*mc
= (void *)kcontrol
->private_value
;
469 struct sst_gain_value
*gv
= mc
->gain_val
;
471 mutex_lock(&drv
->lock
);
475 gv
->l_gain
= ucontrol
->value
.integer
.value
[0];
476 gv
->r_gain
= ucontrol
->value
.integer
.value
[1];
477 dev_dbg(cmpnt
->dev
, "%s: Volume %d, %d\n",
478 mc
->pname
, gv
->l_gain
, gv
->r_gain
);
482 gv
->mute
= !!ucontrol
->value
.integer
.value
[0];
483 dev_dbg(cmpnt
->dev
, "%s: Mute %d\n", mc
->pname
, gv
->mute
);
486 case SST_GAIN_RAMP_DURATION
:
487 gv
->ramp_duration
= ucontrol
->value
.integer
.value
[0];
488 dev_dbg(cmpnt
->dev
, "%s: Ramp Delay%d\n",
489 mc
->pname
, gv
->ramp_duration
);
493 mutex_unlock(&drv
->lock
);
494 dev_err(cmpnt
->dev
, "Invalid Input- gain type:%d\n",
499 if (mc
->w
&& mc
->w
->power
)
500 ret
= sst_send_gain_cmd(drv
, gv
, mc
->task_id
,
501 mc
->pipe_id
| mc
->instance_id
, mc
->module_id
, 0);
502 mutex_unlock(&drv
->lock
);
507 static int sst_set_pipe_gain(struct sst_ids
*ids
,
508 struct sst_data
*drv
, int mute
);
510 static int sst_send_pipe_module_params(struct snd_soc_dapm_widget
*w
,
511 struct snd_kcontrol
*kcontrol
)
513 struct snd_soc_component
*c
= snd_soc_dapm_to_component(w
->dapm
);
514 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
515 struct sst_ids
*ids
= w
->priv
;
517 mutex_lock(&drv
->lock
);
518 sst_find_and_send_pipe_algo(drv
, w
->name
, ids
);
519 sst_set_pipe_gain(ids
, drv
, 0);
520 mutex_unlock(&drv
->lock
);
525 static int sst_generic_modules_event(struct snd_soc_dapm_widget
*w
,
526 struct snd_kcontrol
*k
, int event
)
528 if (SND_SOC_DAPM_EVENT_ON(event
))
529 return sst_send_pipe_module_params(w
, k
);
533 static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common
, SST_GAIN_MIN_VALUE
* 10, 10, 0);
535 /* Look up table to convert MIXER SW bit regs to SWM inputs */
536 static const uint swm_mixer_input_ids
[SST_SWM_INPUT_COUNT
] = {
537 [SST_IP_CODEC0
] = SST_SWM_IN_CODEC0
,
538 [SST_IP_CODEC1
] = SST_SWM_IN_CODEC1
,
539 [SST_IP_LOOP0
] = SST_SWM_IN_SPROT_LOOP
,
540 [SST_IP_LOOP1
] = SST_SWM_IN_MEDIA_LOOP1
,
541 [SST_IP_LOOP2
] = SST_SWM_IN_MEDIA_LOOP2
,
542 [SST_IP_PCM0
] = SST_SWM_IN_PCM0
,
543 [SST_IP_PCM1
] = SST_SWM_IN_PCM1
,
544 [SST_IP_MEDIA0
] = SST_SWM_IN_MEDIA0
,
545 [SST_IP_MEDIA1
] = SST_SWM_IN_MEDIA1
,
546 [SST_IP_MEDIA2
] = SST_SWM_IN_MEDIA2
,
547 [SST_IP_MEDIA3
] = SST_SWM_IN_MEDIA3
,
551 * fill_swm_input - fill in the SWM input ids given the register
553 * The register value is a bit-field inicated which mixer inputs are ON. Use the
554 * lookup table to get the input-id and fill it in the structure.
556 static int fill_swm_input(struct snd_soc_component
*cmpnt
,
557 struct swm_input_ids
*swm_input
, unsigned int reg
)
559 uint i
, is_set
, nb_inputs
= 0;
562 dev_dbg(cmpnt
->dev
, "reg: %#x\n", reg
);
563 for (i
= 0; i
< SST_SWM_INPUT_COUNT
; i
++) {
564 is_set
= reg
& BIT(i
);
568 input_loc_id
= swm_mixer_input_ids
[i
];
569 SST_FILL_DESTINATION(2, swm_input
->input_id
,
570 input_loc_id
, SST_DEFAULT_MODULE_ID
);
573 dev_dbg(cmpnt
->dev
, "input id: %#x, nb_inputs: %d\n",
574 input_loc_id
, nb_inputs
);
576 if (nb_inputs
== SST_CMD_SWM_MAX_INPUTS
) {
577 dev_warn(cmpnt
->dev
, "SET_SWM cmd max inputs reached");
586 * called with lock held
588 static int sst_set_pipe_gain(struct sst_ids
*ids
,
589 struct sst_data
*drv
, int mute
)
592 struct sst_gain_mixer_control
*mc
;
593 struct sst_gain_value
*gv
;
594 struct sst_module
*gain
= NULL
;
596 list_for_each_entry(gain
, &ids
->gain_list
, node
) {
597 struct snd_kcontrol
*kctl
= gain
->kctl
;
599 dev_dbg(&drv
->pdev
->dev
, "control name=%s\n", kctl
->id
.name
);
600 mc
= (void *)kctl
->private_value
;
603 ret
= sst_send_gain_cmd(drv
, gv
, mc
->task_id
,
604 mc
->pipe_id
| mc
->instance_id
, mc
->module_id
, mute
);
611 static int sst_swm_mixer_event(struct snd_soc_dapm_widget
*w
,
612 struct snd_kcontrol
*k
, int event
)
614 struct sst_cmd_set_swm cmd
;
615 struct snd_soc_component
*cmpnt
= snd_soc_dapm_to_component(w
->dapm
);
616 struct sst_data
*drv
= snd_soc_component_get_drvdata(cmpnt
);
617 struct sst_ids
*ids
= w
->priv
;
618 bool set_mixer
= false;
619 struct soc_mixer_control
*mc
;
623 dev_dbg(cmpnt
->dev
, "widget = %s\n", w
->name
);
625 * Identify which mixer input is on and send the bitmap of the
626 * inputs as an IPC to the DSP.
628 for (i
= 0; i
< w
->num_kcontrols
; i
++) {
629 if (dapm_kcontrol_get_value(w
->kcontrols
[i
])) {
630 mc
= (struct soc_mixer_control
*)(w
->kcontrols
[i
])->private_value
;
631 val
|= 1 << mc
->shift
;
634 dev_dbg(cmpnt
->dev
, "val = %#x\n", val
);
637 case SND_SOC_DAPM_PRE_PMU
:
638 case SND_SOC_DAPM_POST_PMD
:
641 case SND_SOC_DAPM_POST_REG
:
649 if (set_mixer
== false)
652 if (SND_SOC_DAPM_EVENT_ON(event
) ||
653 event
== SND_SOC_DAPM_POST_REG
)
654 cmd
.switch_state
= SST_SWM_ON
;
656 cmd
.switch_state
= SST_SWM_OFF
;
658 SST_FILL_DEFAULT_DESTINATION(cmd
.header
.dst
);
659 /* MMX_SET_SWM == SBA_SET_SWM */
660 cmd
.header
.command_id
= SBA_SET_SWM
;
662 SST_FILL_DESTINATION(2, cmd
.output_id
,
663 ids
->location_id
, SST_DEFAULT_MODULE_ID
);
664 cmd
.nb_inputs
= fill_swm_input(cmpnt
, &cmd
.input
[0], val
);
665 cmd
.header
.length
= offsetof(struct sst_cmd_set_swm
, input
)
666 - sizeof(struct sst_dsp_header
)
667 + (cmd
.nb_inputs
* sizeof(cmd
.input
[0]));
669 return sst_fill_and_send_cmd(drv
, SST_IPC_IA_CMD
, SST_FLAG_BLOCKED
,
670 ids
->task_id
, 0, &cmd
,
671 sizeof(cmd
.header
) + cmd
.header
.length
);
674 /* SBA mixers - 16 inputs */
675 #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \
676 static const struct snd_kcontrol_new kctl_name[] = { \
677 SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \
678 SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \
679 SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \
680 SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0), \
681 SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0), \
682 SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0), \
683 SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0), \
686 #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \
687 { mix_name, "codec_in0 Switch", "codec_in0" }, \
688 { mix_name, "codec_in1 Switch", "codec_in1" }, \
689 { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \
690 { mix_name, "media_loop1_in Switch", "media_loop1_in" }, \
691 { mix_name, "media_loop2_in Switch", "media_loop2_in" }, \
692 { mix_name, "pcm0_in Switch", "pcm0_in" }, \
693 { mix_name, "pcm1_in Switch", "pcm1_in" }
695 #define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name) \
696 static const struct snd_kcontrol_new kctl_name[] = { \
697 SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \
698 SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \
699 SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \
700 SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \
703 SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls
);
704 SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls
);
707 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls
);
708 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls
);
709 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls
);
710 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls
);
711 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls
);
712 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls
);
713 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls
);
714 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls
);
715 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls
);
718 * sst_handle_vb_timer - Start/Stop the DSP scheduler
720 * The DSP expects first cmd to be SBA_VB_START, so at first startup send
722 * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that.
724 * Do refcount internally so that we send command only at first start
725 * and last end. Since SST driver does its own ref count, invoke sst's
728 int sst_handle_vb_timer(struct snd_soc_dai
*dai
, bool enable
)
731 struct sst_cmd_generic cmd
;
732 struct sst_data
*drv
= snd_soc_dai_get_drvdata(dai
);
733 static int timer_usage
;
736 cmd
.header
.command_id
= SBA_VB_START
;
738 cmd
.header
.command_id
= SBA_IDLE
;
739 dev_dbg(dai
->dev
, "enable=%u, usage=%d\n", enable
, timer_usage
);
741 SST_FILL_DEFAULT_DESTINATION(cmd
.header
.dst
);
742 cmd
.header
.length
= 0;
745 ret
= sst
->ops
->power(sst
->dev
, true);
750 mutex_lock(&drv
->lock
);
757 * Send the command only if this call is the first enable or last
760 if ((enable
&& (timer_usage
== 1)) ||
761 (!enable
&& (timer_usage
== 0))) {
762 ret
= sst_fill_and_send_cmd_unlocked(drv
, SST_IPC_IA_CMD
,
763 SST_FLAG_BLOCKED
, SST_TASK_SBA
, 0, &cmd
,
764 sizeof(cmd
.header
) + cmd
.header
.length
);
770 mutex_unlock(&drv
->lock
);
773 sst
->ops
->power(sst
->dev
, false);
778 * sst_ssp_config - contains SSP configuration for media UC
780 static const struct sst_ssp_config sst_ssp_configs
= {
784 .ssp_mode
= SSP_MODE_MASTER
,
785 .pcm_mode
= SSP_PCM_MODE_NETWORK
,
786 .duplex
= SSP_DUPLEX
,
787 .ssp_protocol
= SSP_MODE_PCM
,
789 .fs_frequency
= SSP_FS_48_KHZ
,
790 .active_slot_map
= 0xF,
794 int send_ssp_cmd(struct snd_soc_dai
*dai
, const char *id
, bool enable
)
796 struct sst_cmd_sba_hw_set_ssp cmd
;
797 struct sst_data
*drv
= snd_soc_dai_get_drvdata(dai
);
798 const struct sst_ssp_config
*config
;
800 dev_info(dai
->dev
, "Enter: enable=%d port_name=%s\n", enable
, id
);
802 SST_FILL_DEFAULT_DESTINATION(cmd
.header
.dst
);
803 cmd
.header
.command_id
= SBA_HW_SET_SSP
;
804 cmd
.header
.length
= sizeof(struct sst_cmd_sba_hw_set_ssp
)
805 - sizeof(struct sst_dsp_header
);
807 config
= &sst_ssp_configs
;
808 dev_dbg(dai
->dev
, "ssp_id: %u\n", config
->ssp_id
);
811 cmd
.switch_state
= SST_SWITCH_ON
;
813 cmd
.switch_state
= SST_SWITCH_OFF
;
815 cmd
.selection
= config
->ssp_id
;
816 cmd
.nb_bits_per_slots
= config
->bits_per_slot
;
817 cmd
.nb_slots
= config
->slots
;
818 cmd
.mode
= config
->ssp_mode
| (config
->pcm_mode
<< 1);
819 cmd
.duplex
= config
->duplex
;
820 cmd
.active_tx_slot_map
= config
->active_slot_map
;
821 cmd
.active_rx_slot_map
= config
->active_slot_map
;
822 cmd
.frame_sync_frequency
= config
->fs_frequency
;
823 cmd
.frame_sync_polarity
= SSP_FS_ACTIVE_HIGH
;
824 cmd
.data_polarity
= 1;
825 cmd
.frame_sync_width
= config
->fs_width
;
826 cmd
.ssp_protocol
= config
->ssp_protocol
;
827 cmd
.start_delay
= config
->start_delay
;
828 cmd
.reserved1
= cmd
.reserved2
= 0xFF;
830 return sst_fill_and_send_cmd(drv
, SST_IPC_IA_CMD
, SST_FLAG_BLOCKED
,
831 SST_TASK_SBA
, 0, &cmd
,
832 sizeof(cmd
.header
) + cmd
.header
.length
);
835 static int sst_set_be_modules(struct snd_soc_dapm_widget
*w
,
836 struct snd_kcontrol
*k
, int event
)
839 struct snd_soc_component
*c
= snd_soc_dapm_to_component(w
->dapm
);
840 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
842 dev_dbg(c
->dev
, "Enter: widget=%s\n", w
->name
);
844 if (SND_SOC_DAPM_EVENT_ON(event
)) {
845 ret
= sst_send_slot_map(drv
);
848 ret
= sst_send_pipe_module_params(w
, k
);
853 static int sst_set_media_path(struct snd_soc_dapm_widget
*w
,
854 struct snd_kcontrol
*k
, int event
)
857 struct sst_cmd_set_media_path cmd
;
858 struct snd_soc_component
*c
= snd_soc_dapm_to_component(w
->dapm
);
859 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
860 struct sst_ids
*ids
= w
->priv
;
862 dev_dbg(c
->dev
, "widget=%s\n", w
->name
);
863 dev_dbg(c
->dev
, "task=%u, location=%#x\n",
864 ids
->task_id
, ids
->location_id
);
866 if (SND_SOC_DAPM_EVENT_ON(event
))
867 cmd
.switch_state
= SST_PATH_ON
;
869 cmd
.switch_state
= SST_PATH_OFF
;
871 SST_FILL_DESTINATION(2, cmd
.header
.dst
,
872 ids
->location_id
, SST_DEFAULT_MODULE_ID
);
874 /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */
875 cmd
.header
.command_id
= MMX_SET_MEDIA_PATH
;
876 cmd
.header
.length
= sizeof(struct sst_cmd_set_media_path
)
877 - sizeof(struct sst_dsp_header
);
879 ret
= sst_fill_and_send_cmd(drv
, SST_IPC_IA_CMD
, SST_FLAG_BLOCKED
,
880 ids
->task_id
, 0, &cmd
,
881 sizeof(cmd
.header
) + cmd
.header
.length
);
885 if (SND_SOC_DAPM_EVENT_ON(event
))
886 ret
= sst_send_pipe_module_params(w
, k
);
890 static int sst_set_media_loop(struct snd_soc_dapm_widget
*w
,
891 struct snd_kcontrol
*k
, int event
)
894 struct sst_cmd_sba_set_media_loop_map cmd
;
895 struct snd_soc_component
*c
= snd_soc_dapm_to_component(w
->dapm
);
896 struct sst_data
*drv
= snd_soc_component_get_drvdata(c
);
897 struct sst_ids
*ids
= w
->priv
;
899 dev_dbg(c
->dev
, "Enter:widget=%s\n", w
->name
);
900 if (SND_SOC_DAPM_EVENT_ON(event
))
901 cmd
.switch_state
= SST_SWITCH_ON
;
903 cmd
.switch_state
= SST_SWITCH_OFF
;
905 SST_FILL_DESTINATION(2, cmd
.header
.dst
,
906 ids
->location_id
, SST_DEFAULT_MODULE_ID
);
908 cmd
.header
.command_id
= SBA_SET_MEDIA_LOOP_MAP
;
909 cmd
.header
.length
= sizeof(struct sst_cmd_sba_set_media_loop_map
)
910 - sizeof(struct sst_dsp_header
);
911 cmd
.param
.part
.cfg
.rate
= 2; /* 48khz */
913 cmd
.param
.part
.cfg
.format
= ids
->format
; /* stereo/Mono */
914 cmd
.param
.part
.cfg
.s_length
= 1; /* 24bit left justified */
915 cmd
.map
= 0; /* Algo sequence: Gain - DRP - FIR - IIR */
917 ret
= sst_fill_and_send_cmd(drv
, SST_IPC_IA_CMD
, SST_FLAG_BLOCKED
,
918 SST_TASK_SBA
, 0, &cmd
,
919 sizeof(cmd
.header
) + cmd
.header
.length
);
923 if (SND_SOC_DAPM_EVENT_ON(event
))
924 ret
= sst_send_pipe_module_params(w
, k
);
928 static const struct snd_soc_dapm_widget sst_dapm_widgets
[] = {
929 SST_AIF_IN("codec_in0", sst_set_be_modules
),
930 SST_AIF_IN("codec_in1", sst_set_be_modules
),
931 SST_AIF_OUT("codec_out0", sst_set_be_modules
),
932 SST_AIF_OUT("codec_out1", sst_set_be_modules
),
935 /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */
936 SST_PATH_INPUT("media0_in", SST_TASK_MMX
, SST_SWM_IN_MEDIA0
, sst_generic_modules_event
),
937 SST_PATH_INPUT("media1_in", SST_TASK_MMX
, SST_SWM_IN_MEDIA1
, NULL
),
938 SST_PATH_INPUT("media2_in", SST_TASK_MMX
, SST_SWM_IN_MEDIA2
, sst_set_media_path
),
939 SST_PATH_INPUT("media3_in", SST_TASK_MMX
, SST_SWM_IN_MEDIA3
, NULL
),
940 SST_PATH_OUTPUT("media0_out", SST_TASK_MMX
, SST_SWM_OUT_MEDIA0
, sst_set_media_path
),
941 SST_PATH_OUTPUT("media1_out", SST_TASK_MMX
, SST_SWM_OUT_MEDIA1
, sst_set_media_path
),
944 SST_PATH_INPUT("pcm0_in", SST_TASK_SBA
, SST_SWM_IN_PCM0
, sst_set_media_path
),
945 SST_PATH_INPUT("pcm1_in", SST_TASK_SBA
, SST_SWM_IN_PCM1
, sst_set_media_path
),
946 SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA
, SST_SWM_OUT_PCM0
, sst_set_media_path
),
947 SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA
, SST_SWM_OUT_PCM1
, sst_set_media_path
),
948 SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA
, SST_SWM_OUT_PCM2
, sst_set_media_path
),
951 SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA
, SST_SWM_IN_SPROT_LOOP
, NULL
),
952 SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA
, SST_SWM_IN_MEDIA_LOOP1
, NULL
),
953 SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA
, SST_SWM_IN_MEDIA_LOOP2
, NULL
),
954 SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA
, SST_SWM_OUT_SPROT_LOOP
, SST_FMT_MONO
, sst_set_media_loop
),
955 SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA
, SST_SWM_OUT_MEDIA_LOOP1
, SST_FMT_MONO
, sst_set_media_loop
),
956 SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA
, SST_SWM_OUT_MEDIA_LOOP2
, SST_FMT_STEREO
, sst_set_media_loop
),
959 SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM
, SST_TASK_MMX
, SST_SWM_OUT_MEDIA0
,
960 sst_mix_media0_controls
, sst_swm_mixer_event
),
961 SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM
, SST_TASK_MMX
, SST_SWM_OUT_MEDIA1
,
962 sst_mix_media1_controls
, sst_swm_mixer_event
),
965 SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_PCM0
,
966 sst_mix_pcm0_controls
, sst_swm_mixer_event
),
967 SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_PCM1
,
968 sst_mix_pcm1_controls
, sst_swm_mixer_event
),
969 SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_PCM2
,
970 sst_mix_pcm2_controls
, sst_swm_mixer_event
),
972 /* SBA Loop mixers */
973 SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_SPROT_LOOP
,
974 sst_mix_sprot_l0_controls
, sst_swm_mixer_event
),
975 SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_MEDIA_LOOP1
,
976 sst_mix_media_l1_controls
, sst_swm_mixer_event
),
977 SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_MEDIA_LOOP2
,
978 sst_mix_media_l2_controls
, sst_swm_mixer_event
),
980 /* SBA Backend mixers */
981 SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_CODEC0
,
982 sst_mix_codec0_controls
, sst_swm_mixer_event
),
983 SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM
, SST_TASK_SBA
, SST_SWM_OUT_CODEC1
,
984 sst_mix_codec1_controls
, sst_swm_mixer_event
),
987 static const struct snd_soc_dapm_route intercon
[] = {
988 {"media0_in", NULL
, "Compress Playback"},
989 {"media1_in", NULL
, "Headset Playback"},
990 {"media2_in", NULL
, "pcm0_out"},
992 {"media0_out mix 0", "media0_in Switch", "media0_in"},
993 {"media0_out mix 0", "media1_in Switch", "media1_in"},
994 {"media0_out mix 0", "media2_in Switch", "media2_in"},
995 {"media0_out mix 0", "media3_in Switch", "media3_in"},
996 {"media1_out mix 0", "media0_in Switch", "media0_in"},
997 {"media1_out mix 0", "media1_in Switch", "media1_in"},
998 {"media1_out mix 0", "media2_in Switch", "media2_in"},
999 {"media1_out mix 0", "media3_in Switch", "media3_in"},
1001 {"media0_out", NULL
, "media0_out mix 0"},
1002 {"media1_out", NULL
, "media1_out mix 0"},
1003 {"pcm0_in", NULL
, "media0_out"},
1004 {"pcm1_in", NULL
, "media1_out"},
1006 {"Headset Capture", NULL
, "pcm1_out"},
1007 {"Headset Capture", NULL
, "pcm2_out"},
1008 {"pcm0_out", NULL
, "pcm0_out mix 0"},
1009 SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"),
1010 {"pcm1_out", NULL
, "pcm1_out mix 0"},
1011 SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"),
1012 {"pcm2_out", NULL
, "pcm2_out mix 0"},
1013 SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"),
1015 {"media_loop1_in", NULL
, "media_loop1_out"},
1016 {"media_loop1_out", NULL
, "media_loop1_out mix 0"},
1017 SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"),
1018 {"media_loop2_in", NULL
, "media_loop2_out"},
1019 {"media_loop2_out", NULL
, "media_loop2_out mix 0"},
1020 SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"),
1021 {"sprot_loop_in", NULL
, "sprot_loop_out"},
1022 {"sprot_loop_out", NULL
, "sprot_loop_out mix 0"},
1023 SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"),
1025 {"codec_out0", NULL
, "codec_out0 mix 0"},
1026 SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"),
1027 {"codec_out1", NULL
, "codec_out1 mix 0"},
1028 SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"),
1031 static const char * const slot_names
[] = {
1033 "slot 0", "slot 1", "slot 2", "slot 3",
1034 "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */
1037 static const char * const channel_names
[] = {
1039 "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1",
1040 "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */
1043 #define SST_INTERLEAVER(xpname, slot_name, slotno) \
1044 SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \
1045 channel_names, sst_slot_get, sst_slot_put)
1047 #define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \
1048 SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \
1049 slot_names, sst_slot_get, sst_slot_put)
1051 static const struct snd_kcontrol_new sst_slot_controls
[] = {
1052 SST_INTERLEAVER("codec_out", "slot 0", 0),
1053 SST_INTERLEAVER("codec_out", "slot 1", 1),
1054 SST_INTERLEAVER("codec_out", "slot 2", 2),
1055 SST_INTERLEAVER("codec_out", "slot 3", 3),
1056 SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0),
1057 SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1),
1058 SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2),
1059 SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3),
1062 /* Gain helper with min/max set */
1063 #define SST_GAIN(name, path_id, task_id, instance, gain_var) \
1064 SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \
1065 SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \
1066 sst_gain_get, sst_gain_put, \
1067 SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id, \
1068 sst_gain_tlv_common, gain_var)
1070 #define SST_VOLUME(name, path_id, task_id, instance, gain_var) \
1071 SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \
1072 SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \
1073 sst_gain_get, sst_gain_put, \
1074 SST_MODULE_ID_VOLUME, path_id, instance, task_id, \
1075 sst_gain_tlv_common, gain_var)
1077 static struct sst_gain_value sst_gains
[];
1079 static const struct snd_kcontrol_new sst_gain_controls
[] = {
1080 SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN
, SST_TASK_MMX
, 0, &sst_gains
[0]),
1081 SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN
, SST_TASK_MMX
, 0, &sst_gains
[1]),
1082 SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN
, SST_TASK_MMX
, 0, &sst_gains
[2]),
1083 SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN
, SST_TASK_MMX
, 0, &sst_gains
[3]),
1085 SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN
, SST_TASK_SBA
, 0, &sst_gains
[4]),
1086 SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN
, SST_TASK_SBA
, 0, &sst_gains
[5]),
1087 SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT
, SST_TASK_SBA
, 0, &sst_gains
[6]),
1088 SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT
, SST_TASK_SBA
, 0, &sst_gains
[7]),
1090 SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0
, SST_TASK_SBA
, 0, &sst_gains
[8]),
1091 SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1
, SST_TASK_SBA
, 0, &sst_gains
[9]),
1092 SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0
, SST_TASK_SBA
, 0, &sst_gains
[10]),
1093 SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1
, SST_TASK_SBA
, 0, &sst_gains
[11]),
1094 SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT
, SST_TASK_SBA
, 0, &sst_gains
[12]),
1095 SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT
, SST_TASK_SBA
, 0, &sst_gains
[13]),
1096 SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT
, SST_TASK_SBA
, 0, &sst_gains
[14]),
1097 SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN
, SST_TASK_MMX
, 0, &sst_gains
[15]),
1100 #define SST_GAIN_NUM_CONTROLS 3
1101 /* the SST_GAIN macro above will create three alsa controls for each
1102 * instance invoked, gain, mute and ramp duration, which use the same gain
1103 * cell sst_gain to keep track of data
1104 * To calculate number of gain cell instances we need to device by 3 in
1105 * below caulcation for gain cell memory.
1106 * This gets rid of static number and issues while adding new controls
1108 static struct sst_gain_value sst_gains
[ARRAY_SIZE(sst_gain_controls
)/SST_GAIN_NUM_CONTROLS
];
1110 static const struct snd_kcontrol_new sst_algo_controls
[] = {
1111 SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24
,
1112 SST_PATH_INDEX_MEDIA_LOOP1_OUT
, 0, SST_TASK_SBA
, SBA_VB_SET_FIR
),
1113 SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24
,
1114 SST_PATH_INDEX_MEDIA_LOOP1_OUT
, 0, SST_TASK_SBA
, SBA_VB_SET_IIR
),
1115 SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP
,
1116 SST_PATH_INDEX_MEDIA_LOOP1_OUT
, 0, SST_TASK_SBA
, SBA_SET_MDRP
),
1117 SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24
,
1118 SST_PATH_INDEX_MEDIA_LOOP2_OUT
, 0, SST_TASK_SBA
, SBA_VB_SET_FIR
),
1119 SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24
,
1120 SST_PATH_INDEX_MEDIA_LOOP2_OUT
, 0, SST_TASK_SBA
, SBA_VB_SET_IIR
),
1121 SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP
,
1122 SST_PATH_INDEX_MEDIA_LOOP2_OUT
, 0, SST_TASK_SBA
, SBA_SET_MDRP
),
1123 SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT
,
1124 SST_PATH_INDEX_SPROT_LOOP_OUT
, 0, SST_TASK_SBA
, SBA_VB_LPRO
),
1125 SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR
,
1126 SST_PATH_INDEX_CODEC_IN0
, 0, SST_TASK_SBA
, SBA_VB_SET_IIR
),
1127 SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR
,
1128 SST_PATH_INDEX_CODEC_IN1
, 0, SST_TASK_SBA
, SBA_VB_SET_IIR
),
1132 static int sst_algo_control_init(struct device
*dev
)
1135 struct sst_algo_control
*bc
;
1136 /*allocate space to cache the algo parameters in the driver*/
1137 for (i
= 0; i
< ARRAY_SIZE(sst_algo_controls
); i
++) {
1138 bc
= (struct sst_algo_control
*)sst_algo_controls
[i
].private_value
;
1139 bc
->params
= devm_kzalloc(dev
, bc
->max
, GFP_KERNEL
);
1140 if (bc
->params
== NULL
)
1146 static bool is_sst_dapm_widget(struct snd_soc_dapm_widget
*w
)
1149 case snd_soc_dapm_pga
:
1150 case snd_soc_dapm_aif_in
:
1151 case snd_soc_dapm_aif_out
:
1152 case snd_soc_dapm_input
:
1153 case snd_soc_dapm_output
:
1154 case snd_soc_dapm_mixer
:
1162 * sst_send_pipe_gains - send gains for the front-end DAIs
1164 * The gains in the pipes connected to the front-ends are muted/unmuted
1165 * automatically via the digital_mute() DAPM callback. This function sends the
1166 * gains for the front-end pipes.
1168 int sst_send_pipe_gains(struct snd_soc_dai
*dai
, int stream
, int mute
)
1170 struct sst_data
*drv
= snd_soc_dai_get_drvdata(dai
);
1171 struct snd_soc_dapm_widget
*w
;
1172 struct snd_soc_dapm_path
*p
= NULL
;
1174 dev_dbg(dai
->dev
, "enter, dai-name=%s dir=%d\n", dai
->name
, stream
);
1176 if (stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
1177 dev_dbg(dai
->dev
, "Stream name=%s\n",
1178 dai
->playback_widget
->name
);
1179 w
= dai
->playback_widget
;
1180 list_for_each_entry(p
, &w
->sinks
, list_source
) {
1181 if (p
->connected
&& !p
->connected(w
, p
->sink
))
1184 if (p
->connect
&& p
->sink
->power
&&
1185 is_sst_dapm_widget(p
->sink
)) {
1186 struct sst_ids
*ids
= p
->sink
->priv
;
1188 dev_dbg(dai
->dev
, "send gains for widget=%s\n",
1190 mutex_lock(&drv
->lock
);
1191 sst_set_pipe_gain(ids
, drv
, mute
);
1192 mutex_unlock(&drv
->lock
);
1196 dev_dbg(dai
->dev
, "Stream name=%s\n",
1197 dai
->capture_widget
->name
);
1198 w
= dai
->capture_widget
;
1199 list_for_each_entry(p
, &w
->sources
, list_sink
) {
1200 if (p
->connected
&& !p
->connected(w
, p
->sink
))
1203 if (p
->connect
&& p
->source
->power
&&
1204 is_sst_dapm_widget(p
->source
)) {
1205 struct sst_ids
*ids
= p
->source
->priv
;
1207 dev_dbg(dai
->dev
, "send gain for widget=%s\n",
1209 mutex_lock(&drv
->lock
);
1210 sst_set_pipe_gain(ids
, drv
, mute
);
1211 mutex_unlock(&drv
->lock
);
1219 * sst_fill_module_list - populate the list of modules/gains for a pipe
1222 * Fills the widget pointer in the kcontrol private data, and also fills the
1223 * kcontrol pointer in the widget private data.
1225 * Widget pointer is used to send the algo/gain in the .put() handler if the
1226 * widget is powerd on.
1228 * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF
1229 * event handler. Each widget (pipe) has multiple algos stored in the algo_list.
1231 static int sst_fill_module_list(struct snd_kcontrol
*kctl
,
1232 struct snd_soc_dapm_widget
*w
, int type
)
1234 struct sst_module
*module
= NULL
;
1235 struct snd_soc_component
*c
= snd_soc_dapm_to_component(w
->dapm
);
1236 struct sst_ids
*ids
= w
->priv
;
1239 module
= devm_kzalloc(c
->dev
, sizeof(*module
), GFP_KERNEL
);
1243 if (type
== SST_MODULE_GAIN
) {
1244 struct sst_gain_mixer_control
*mc
= (void *)kctl
->private_value
;
1247 module
->kctl
= kctl
;
1248 list_add_tail(&module
->node
, &ids
->gain_list
);
1249 } else if (type
== SST_MODULE_ALGO
) {
1250 struct sst_algo_control
*bc
= (void *)kctl
->private_value
;
1253 module
->kctl
= kctl
;
1254 list_add_tail(&module
->node
, &ids
->algo_list
);
1256 dev_err(c
->dev
, "invoked for unknown type %d module %s",
1257 type
, kctl
->id
.name
);
1265 * sst_fill_widget_module_info - fill list of gains/algos for the pipe
1266 * @widget: pipe modelled as a DAPM widget
1268 * Fill the list of gains/algos for the widget by looking at all the card
1269 * controls and comparing the name of the widget with the first part of control
1270 * name. First part of control name contains the pipe name (widget name).
1272 static int sst_fill_widget_module_info(struct snd_soc_dapm_widget
*w
,
1273 struct snd_soc_platform
*platform
)
1275 struct snd_kcontrol
*kctl
;
1277 struct snd_card
*card
= platform
->component
.card
->snd_card
;
1280 down_read(&card
->controls_rwsem
);
1282 list_for_each_entry(kctl
, &card
->controls
, list
) {
1283 idx
= strstr(kctl
->id
.name
, " ");
1286 index
= strlen(kctl
->id
.name
) - strlen(idx
);
1288 if (strstr(kctl
->id
.name
, "Volume") &&
1289 !strncmp(kctl
->id
.name
, w
->name
, index
))
1290 ret
= sst_fill_module_list(kctl
, w
, SST_MODULE_GAIN
);
1292 else if (strstr(kctl
->id
.name
, "params") &&
1293 !strncmp(kctl
->id
.name
, w
->name
, index
))
1294 ret
= sst_fill_module_list(kctl
, w
, SST_MODULE_ALGO
);
1296 else if (strstr(kctl
->id
.name
, "Switch") &&
1297 !strncmp(kctl
->id
.name
, w
->name
, index
) &&
1298 strstr(kctl
->id
.name
, "Gain")) {
1299 struct sst_gain_mixer_control
*mc
=
1300 (void *)kctl
->private_value
;
1304 } else if (strstr(kctl
->id
.name
, "interleaver") &&
1305 !strncmp(kctl
->id
.name
, w
->name
, index
)) {
1306 struct sst_enum
*e
= (void *)kctl
->private_value
;
1310 } else if (strstr(kctl
->id
.name
, "deinterleaver") &&
1311 !strncmp(kctl
->id
.name
, w
->name
, index
)) {
1313 struct sst_enum
*e
= (void *)kctl
->private_value
;
1319 up_read(&card
->controls_rwsem
);
1324 up_read(&card
->controls_rwsem
);
1329 * sst_fill_linked_widgets - fill the parent pointer for the linked widget
1331 static void sst_fill_linked_widgets(struct snd_soc_platform
*platform
,
1332 struct sst_ids
*ids
)
1334 struct snd_soc_dapm_widget
*w
;
1335 unsigned int len
= strlen(ids
->parent_wname
);
1337 list_for_each_entry(w
, &platform
->component
.card
->widgets
, list
) {
1338 if (!strncmp(ids
->parent_wname
, w
->name
, len
)) {
1346 * sst_map_modules_to_pipe - fill algo/gains list for all pipes
1348 static int sst_map_modules_to_pipe(struct snd_soc_platform
*platform
)
1350 struct snd_soc_dapm_widget
*w
;
1353 list_for_each_entry(w
, &platform
->component
.card
->widgets
, list
) {
1354 if (is_sst_dapm_widget(w
) && (w
->priv
)) {
1355 struct sst_ids
*ids
= w
->priv
;
1357 dev_dbg(platform
->dev
, "widget type=%d name=%s\n",
1359 INIT_LIST_HEAD(&ids
->algo_list
);
1360 INIT_LIST_HEAD(&ids
->gain_list
);
1361 ret
= sst_fill_widget_module_info(w
, platform
);
1366 /* fill linked widgets */
1367 if (ids
->parent_wname
!= NULL
)
1368 sst_fill_linked_widgets(platform
, ids
);
1374 int sst_dsp_init_v2_dpcm(struct snd_soc_platform
*platform
)
1377 struct snd_soc_dapm_context
*dapm
=
1378 snd_soc_component_get_dapm(&platform
->component
);
1379 struct sst_data
*drv
= snd_soc_platform_get_drvdata(platform
);
1380 unsigned int gains
= ARRAY_SIZE(sst_gain_controls
)/3;
1382 drv
->byte_stream
= devm_kzalloc(platform
->dev
,
1383 SST_MAX_BIN_BYTES
, GFP_KERNEL
);
1384 if (!drv
->byte_stream
)
1387 snd_soc_dapm_new_controls(dapm
, sst_dapm_widgets
,
1388 ARRAY_SIZE(sst_dapm_widgets
));
1389 snd_soc_dapm_add_routes(dapm
, intercon
,
1390 ARRAY_SIZE(intercon
));
1391 snd_soc_dapm_new_widgets(dapm
->card
);
1393 for (i
= 0; i
< gains
; i
++) {
1394 sst_gains
[i
].mute
= SST_GAIN_MUTE_DEFAULT
;
1395 sst_gains
[i
].l_gain
= SST_GAIN_VOLUME_DEFAULT
;
1396 sst_gains
[i
].r_gain
= SST_GAIN_VOLUME_DEFAULT
;
1397 sst_gains
[i
].ramp_duration
= SST_GAIN_RAMP_DURATION_DEFAULT
;
1400 ret
= snd_soc_add_platform_controls(platform
, sst_gain_controls
,
1401 ARRAY_SIZE(sst_gain_controls
));
1405 /* Initialize algo control params */
1406 ret
= sst_algo_control_init(platform
->dev
);
1409 ret
= snd_soc_add_platform_controls(platform
, sst_algo_controls
,
1410 ARRAY_SIZE(sst_algo_controls
));
1414 ret
= snd_soc_add_platform_controls(platform
, sst_slot_controls
,
1415 ARRAY_SIZE(sst_slot_controls
));
1419 ret
= sst_map_modules_to_pipe(platform
);