1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
11 #include <linux/firmware.h>
12 #include <sound/tlv.h>
13 #include <sound/pcm_params.h>
14 #include <uapi/sound/sof/tokens.h>
16 #include "sof-audio.h"
19 #define COMP_ID_UNASSIGNED 0xffffffff
21 * Constants used in the computation of linear volume gain
22 * from dB gain 20th root of 10 in Q1.16 fixed-point notation
24 #define VOL_TWENTIETH_ROOT_OF_TEN 73533
25 /* 40th root of 10 in Q1.16 fixed-point notation*/
26 #define VOL_FORTIETH_ROOT_OF_TEN 69419
28 * Volume fractional word length define to 16 sets
29 * the volume linear gain value to use Qx.16 format
32 /* 0.5 dB step value in topology TLV */
33 #define VOL_HALF_DB_STEP 50
34 /* Full volume for default values */
35 #define VOL_ZERO_DB BIT(VOLUME_FWL)
43 /* size of tplg abi in byte */
44 #define SOF_TPLG_ABI_SIZE 3
46 struct sof_widget_data
{
49 struct sof_abi_hdr
*pdata
;
50 struct snd_sof_control
*control
;
53 /* send pcm params ipc */
54 static int ipc_pcm_params(struct snd_sof_widget
*swidget
, int dir
)
56 struct sof_ipc_pcm_params_reply ipc_params_reply
;
57 struct snd_soc_component
*scomp
= swidget
->scomp
;
58 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
59 struct sof_ipc_pcm_params pcm
;
60 struct snd_pcm_hw_params
*params
;
61 struct snd_sof_pcm
*spcm
;
64 memset(&pcm
, 0, sizeof(pcm
));
66 /* get runtime PCM params using widget's stream name */
67 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
69 dev_err(scomp
->dev
, "error: cannot find PCM for %s\n",
70 swidget
->widget
->name
);
74 params
= &spcm
->params
[dir
];
76 /* set IPC PCM params */
77 pcm
.hdr
.size
= sizeof(pcm
);
78 pcm
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_PARAMS
;
79 pcm
.comp_id
= swidget
->comp_id
;
80 pcm
.params
.hdr
.size
= sizeof(pcm
.params
);
81 pcm
.params
.direction
= dir
;
82 pcm
.params
.sample_valid_bytes
= params_width(params
) >> 3;
83 pcm
.params
.buffer_fmt
= SOF_IPC_BUFFER_INTERLEAVED
;
84 pcm
.params
.rate
= params_rate(params
);
85 pcm
.params
.channels
= params_channels(params
);
86 pcm
.params
.host_period_bytes
= params_period_bytes(params
);
89 switch (params_format(params
)) {
90 case SNDRV_PCM_FORMAT_S16
:
91 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S16_LE
;
93 case SNDRV_PCM_FORMAT_S24
:
94 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S24_4LE
;
96 case SNDRV_PCM_FORMAT_S32
:
97 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S32_LE
;
103 /* send IPC to the DSP */
104 ret
= sof_ipc_tx_message(sdev
->ipc
, pcm
.hdr
.cmd
, &pcm
, sizeof(pcm
),
105 &ipc_params_reply
, sizeof(ipc_params_reply
));
107 dev_err(scomp
->dev
, "error: pcm params failed for %s\n",
108 swidget
->widget
->name
);
113 /* send stream trigger ipc */
114 static int ipc_trigger(struct snd_sof_widget
*swidget
, int cmd
)
116 struct snd_soc_component
*scomp
= swidget
->scomp
;
117 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
118 struct sof_ipc_stream stream
;
119 struct sof_ipc_reply reply
;
122 /* set IPC stream params */
123 stream
.hdr
.size
= sizeof(stream
);
124 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| cmd
;
125 stream
.comp_id
= swidget
->comp_id
;
127 /* send IPC to the DSP */
128 ret
= sof_ipc_tx_message(sdev
->ipc
, stream
.hdr
.cmd
, &stream
,
129 sizeof(stream
), &reply
, sizeof(reply
));
131 dev_err(scomp
->dev
, "error: failed to trigger %s\n",
132 swidget
->widget
->name
);
137 static int sof_keyword_dapm_event(struct snd_soc_dapm_widget
*w
,
138 struct snd_kcontrol
*k
, int event
)
140 struct snd_sof_widget
*swidget
= w
->dobj
.private;
141 struct snd_soc_component
*scomp
;
142 int stream
= SNDRV_PCM_STREAM_CAPTURE
;
143 struct snd_sof_pcm
*spcm
;
149 scomp
= swidget
->scomp
;
151 dev_dbg(scomp
->dev
, "received event %d for widget %s\n",
154 /* get runtime PCM params using widget's stream name */
155 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
157 dev_err(scomp
->dev
, "error: cannot find PCM for %s\n",
158 swidget
->widget
->name
);
164 case SND_SOC_DAPM_PRE_PMU
:
165 if (spcm
->stream
[stream
].suspend_ignored
) {
166 dev_dbg(scomp
->dev
, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
171 ret
= ipc_pcm_params(swidget
, stream
);
174 "error: failed to set pcm params for widget %s\n",
175 swidget
->widget
->name
);
180 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_TRIG_START
);
183 "error: failed to trigger widget %s\n",
184 swidget
->widget
->name
);
186 case SND_SOC_DAPM_POST_PMD
:
187 if (spcm
->stream
[stream
].suspend_ignored
) {
188 dev_dbg(scomp
->dev
, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
193 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_TRIG_STOP
);
196 "error: failed to trigger widget %s\n",
197 swidget
->widget
->name
);
200 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_PCM_FREE
);
203 "error: failed to trigger widget %s\n",
204 swidget
->widget
->name
);
213 /* event handlers for keyword detect component */
214 static const struct snd_soc_tplg_widget_events sof_kwd_events
[] = {
215 {SOF_KEYWORD_DETECT_DAPM_EVENT
, sof_keyword_dapm_event
},
218 static inline int get_tlv_data(const int *p
, int tlv
[TLV_ITEMS
])
220 /* we only support dB scale TLV type at the moment */
221 if ((int)p
[SNDRV_CTL_TLVO_TYPE
] != SNDRV_CTL_TLVT_DB_SCALE
)
224 /* min value in topology tlv data is multiplied by 100 */
225 tlv
[TLV_MIN
] = (int)p
[SNDRV_CTL_TLVO_DB_SCALE_MIN
] / 100;
228 tlv
[TLV_STEP
] = (int)(p
[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP
] &
232 if ((p
[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP
] &
233 TLV_DB_SCALE_MUTE
) == 0)
242 * Function to truncate an unsigned 64-bit number
243 * by x bits and return 32-bit unsigned number. This
244 * function also takes care of rounding while truncating
246 static inline u32
vol_shift_64(u64 i
, u32 x
)
248 /* do not truncate more than 32 bits */
255 return (u32
)(((i
>> (x
- 1)) + 1) >> 1);
259 * Function to compute a ^ exp where,
260 * a is a fractional number represented by a fixed-point
261 * integer with a fractional world length of "fwl"
263 * fwl is the fractional word length
264 * Return value is a fractional number represented by a
265 * fixed-point integer with a fractional word length of "fwl"
267 static u32
vol_pow32(u32 a
, int exp
, u32 fwl
)
270 u32 power
= 1 << fwl
;
273 /* if exponent is 0, return 1 */
277 /* determine the number of iterations based on the exponent */
283 /* mutiply a "iter" times to compute power */
284 for (i
= 0; i
< iter
; i
++) {
286 * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl
287 * Truncate product back to fwl fractional bits with rounding
289 power
= vol_shift_64((u64
)power
* a
, fwl
);
293 /* if exp is positive, return the result */
297 /* if exp is negative, return the multiplicative inverse */
298 numerator
= (u64
)1 << (fwl
<< 1);
299 do_div(numerator
, power
);
301 return (u32
)numerator
;
305 * Function to calculate volume gain from TLV data.
306 * This function can only handle gain steps that are multiples of 0.5 dB
308 static u32
vol_compute_gain(u32 value
, int *tlv
)
315 if (value
== 0 && tlv
[TLV_MUTE
])
319 * compute dB gain from tlv. tlv_step
320 * in topology is multiplied by 100
322 dB_gain
= tlv
[TLV_MIN
] + (value
* tlv
[TLV_STEP
]) / 100;
325 * compute linear gain represented by fixed-point
326 * int with VOLUME_FWL fractional bits
328 linear_gain
= vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN
, dB_gain
, VOLUME_FWL
);
330 /* extract the fractional part of volume step */
331 f_step
= tlv
[TLV_STEP
] - (tlv
[TLV_STEP
] / 100);
333 /* if volume step is an odd multiple of 0.5 dB */
334 if (f_step
== VOL_HALF_DB_STEP
&& (value
& 1))
335 linear_gain
= vol_shift_64((u64
)linear_gain
*
336 VOL_FORTIETH_ROOT_OF_TEN
,
343 * Set up volume table for kcontrols from tlv data
344 * "size" specifies the number of entries in the table
346 static int set_up_volume_table(struct snd_sof_control
*scontrol
,
347 int tlv
[TLV_ITEMS
], int size
)
351 /* init the volume table */
352 scontrol
->volume_table
= kcalloc(size
, sizeof(u32
), GFP_KERNEL
);
353 if (!scontrol
->volume_table
)
356 /* populate the volume table */
357 for (j
= 0; j
< size
; j
++)
358 scontrol
->volume_table
[j
] = vol_compute_gain(j
, tlv
);
363 struct sof_dai_types
{
365 enum sof_ipc_dai_type type
;
368 static const struct sof_dai_types sof_dais
[] = {
369 {"SSP", SOF_DAI_INTEL_SSP
},
370 {"HDA", SOF_DAI_INTEL_HDA
},
371 {"DMIC", SOF_DAI_INTEL_DMIC
},
372 {"ALH", SOF_DAI_INTEL_ALH
},
373 {"SAI", SOF_DAI_IMX_SAI
},
374 {"ESAI", SOF_DAI_IMX_ESAI
},
377 static enum sof_ipc_dai_type
find_dai(const char *name
)
381 for (i
= 0; i
< ARRAY_SIZE(sof_dais
); i
++) {
382 if (strcmp(name
, sof_dais
[i
].name
) == 0)
383 return sof_dais
[i
].type
;
386 return SOF_DAI_INTEL_NONE
;
390 * Supported Frame format types and lookup, add new ones to end of list.
393 struct sof_frame_types
{
395 enum sof_ipc_frame frame
;
398 static const struct sof_frame_types sof_frames
[] = {
399 {"s16le", SOF_IPC_FRAME_S16_LE
},
400 {"s24le", SOF_IPC_FRAME_S24_4LE
},
401 {"s32le", SOF_IPC_FRAME_S32_LE
},
402 {"float", SOF_IPC_FRAME_FLOAT
},
405 static enum sof_ipc_frame
find_format(const char *name
)
409 for (i
= 0; i
< ARRAY_SIZE(sof_frames
); i
++) {
410 if (strcmp(name
, sof_frames
[i
].name
) == 0)
411 return sof_frames
[i
].frame
;
414 /* use s32le if nothing is specified */
415 return SOF_IPC_FRAME_S32_LE
;
418 struct sof_process_types
{
420 enum sof_ipc_process_type type
;
421 enum sof_comp_type comp_type
;
424 static const struct sof_process_types sof_process
[] = {
425 {"EQFIR", SOF_PROCESS_EQFIR
, SOF_COMP_EQ_FIR
},
426 {"EQIIR", SOF_PROCESS_EQIIR
, SOF_COMP_EQ_IIR
},
427 {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT
, SOF_COMP_KEYWORD_DETECT
},
428 {"KPB", SOF_PROCESS_KPB
, SOF_COMP_KPB
},
429 {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR
, SOF_COMP_SELECTOR
},
430 {"MUX", SOF_PROCESS_MUX
, SOF_COMP_MUX
},
431 {"DEMUX", SOF_PROCESS_DEMUX
, SOF_COMP_DEMUX
},
434 static enum sof_ipc_process_type
find_process(const char *name
)
438 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
439 if (strcmp(name
, sof_process
[i
].name
) == 0)
440 return sof_process
[i
].type
;
443 return SOF_PROCESS_NONE
;
446 static enum sof_comp_type
find_process_comp_type(enum sof_ipc_process_type type
)
450 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
451 if (sof_process
[i
].type
== type
)
452 return sof_process
[i
].comp_type
;
455 return SOF_COMP_NONE
;
459 * Topology Token Parsing.
460 * New tokens should be added to headers and parsing tables below.
463 struct sof_topology_token
{
466 int (*get_token
)(void *elem
, void *object
, u32 offset
, u32 size
);
471 static int get_token_u32(void *elem
, void *object
, u32 offset
, u32 size
)
473 struct snd_soc_tplg_vendor_value_elem
*velem
= elem
;
474 u32
*val
= (u32
*)((u8
*)object
+ offset
);
476 *val
= le32_to_cpu(velem
->value
);
480 static int get_token_u16(void *elem
, void *object
, u32 offset
, u32 size
)
482 struct snd_soc_tplg_vendor_value_elem
*velem
= elem
;
483 u16
*val
= (u16
*)((u8
*)object
+ offset
);
485 *val
= (u16
)le32_to_cpu(velem
->value
);
489 static int get_token_comp_format(void *elem
, void *object
, u32 offset
, u32 size
)
491 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
492 u32
*val
= (u32
*)((u8
*)object
+ offset
);
494 *val
= find_format(velem
->string
);
498 static int get_token_dai_type(void *elem
, void *object
, u32 offset
, u32 size
)
500 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
501 u32
*val
= (u32
*)((u8
*)object
+ offset
);
503 *val
= find_dai(velem
->string
);
507 static int get_token_process_type(void *elem
, void *object
, u32 offset
,
510 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
511 u32
*val
= (u32
*)((u8
*)object
+ offset
);
513 *val
= find_process(velem
->string
);
518 static const struct sof_topology_token buffer_tokens
[] = {
519 {SOF_TKN_BUF_SIZE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
520 offsetof(struct sof_ipc_buffer
, size
), 0},
521 {SOF_TKN_BUF_CAPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
522 offsetof(struct sof_ipc_buffer
, caps
), 0},
526 static const struct sof_topology_token dai_tokens
[] = {
527 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
528 offsetof(struct sof_ipc_comp_dai
, type
), 0},
529 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
530 offsetof(struct sof_ipc_comp_dai
, dai_index
), 0},
531 {SOF_TKN_DAI_DIRECTION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
532 offsetof(struct sof_ipc_comp_dai
, direction
), 0},
536 static const struct sof_topology_token dai_link_tokens
[] = {
537 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
538 offsetof(struct sof_ipc_dai_config
, type
), 0},
539 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
540 offsetof(struct sof_ipc_dai_config
, dai_index
), 0},
544 static const struct sof_topology_token sched_tokens
[] = {
545 {SOF_TKN_SCHED_PERIOD
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
546 offsetof(struct sof_ipc_pipe_new
, period
), 0},
547 {SOF_TKN_SCHED_PRIORITY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
548 offsetof(struct sof_ipc_pipe_new
, priority
), 0},
549 {SOF_TKN_SCHED_MIPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
550 offsetof(struct sof_ipc_pipe_new
, period_mips
), 0},
551 {SOF_TKN_SCHED_CORE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
552 offsetof(struct sof_ipc_pipe_new
, core
), 0},
553 {SOF_TKN_SCHED_FRAMES
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
554 offsetof(struct sof_ipc_pipe_new
, frames_per_sched
), 0},
555 {SOF_TKN_SCHED_TIME_DOMAIN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
556 offsetof(struct sof_ipc_pipe_new
, time_domain
), 0},
560 static const struct sof_topology_token volume_tokens
[] = {
561 {SOF_TKN_VOLUME_RAMP_STEP_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
562 get_token_u32
, offsetof(struct sof_ipc_comp_volume
, ramp
), 0},
563 {SOF_TKN_VOLUME_RAMP_STEP_MS
,
564 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
565 offsetof(struct sof_ipc_comp_volume
, initial_ramp
), 0},
569 static const struct sof_topology_token src_tokens
[] = {
570 {SOF_TKN_SRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
571 offsetof(struct sof_ipc_comp_src
, source_rate
), 0},
572 {SOF_TKN_SRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
573 offsetof(struct sof_ipc_comp_src
, sink_rate
), 0},
577 static const struct sof_topology_token asrc_tokens
[] = {
578 {SOF_TKN_ASRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
579 offsetof(struct sof_ipc_comp_asrc
, source_rate
), 0},
580 {SOF_TKN_ASRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
581 offsetof(struct sof_ipc_comp_asrc
, sink_rate
), 0},
582 {SOF_TKN_ASRC_ASYNCHRONOUS_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
584 offsetof(struct sof_ipc_comp_asrc
, asynchronous_mode
), 0},
585 {SOF_TKN_ASRC_OPERATION_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
587 offsetof(struct sof_ipc_comp_asrc
, operation_mode
), 0},
591 static const struct sof_topology_token tone_tokens
[] = {
595 static const struct sof_topology_token process_tokens
[] = {
596 {SOF_TKN_PROCESS_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
,
597 get_token_process_type
,
598 offsetof(struct sof_ipc_comp_process
, type
), 0},
602 static const struct sof_topology_token pcm_tokens
[] = {
603 {SOF_TKN_PCM_DMAC_CONFIG
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
604 offsetof(struct sof_ipc_comp_host
, dmac_config
), 0},
608 static const struct sof_topology_token stream_tokens
[] = {
609 {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3
,
610 SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
611 offsetof(struct snd_sof_pcm
, stream
[0].d0i3_compatible
), 0},
612 {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3
,
613 SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
614 offsetof(struct snd_sof_pcm
, stream
[1].d0i3_compatible
), 0},
617 /* Generic components */
618 static const struct sof_topology_token comp_tokens
[] = {
619 {SOF_TKN_COMP_PERIOD_SINK_COUNT
,
620 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
621 offsetof(struct sof_ipc_comp_config
, periods_sink
), 0},
622 {SOF_TKN_COMP_PERIOD_SOURCE_COUNT
,
623 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
624 offsetof(struct sof_ipc_comp_config
, periods_source
), 0},
625 {SOF_TKN_COMP_FORMAT
,
626 SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_comp_format
,
627 offsetof(struct sof_ipc_comp_config
, frame_fmt
), 0},
631 static const struct sof_topology_token ssp_tokens
[] = {
632 {SOF_TKN_INTEL_SSP_CLKS_CONTROL
,
633 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
634 offsetof(struct sof_ipc_dai_ssp_params
, clks_control
), 0},
635 {SOF_TKN_INTEL_SSP_MCLK_ID
,
636 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
637 offsetof(struct sof_ipc_dai_ssp_params
, mclk_id
), 0},
638 {SOF_TKN_INTEL_SSP_SAMPLE_BITS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
640 offsetof(struct sof_ipc_dai_ssp_params
, sample_valid_bits
), 0},
641 {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
,
643 offsetof(struct sof_ipc_dai_ssp_params
, frame_pulse_width
), 0},
644 {SOF_TKN_INTEL_SSP_QUIRKS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
646 offsetof(struct sof_ipc_dai_ssp_params
, quirks
), 0},
647 {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT
, SND_SOC_TPLG_TUPLE_TYPE_BOOL
,
649 offsetof(struct sof_ipc_dai_ssp_params
,
650 tdm_per_slot_padding_flag
), 0},
651 {SOF_TKN_INTEL_SSP_BCLK_DELAY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
653 offsetof(struct sof_ipc_dai_ssp_params
, bclk_delay
), 0},
658 static const struct sof_topology_token dmic_tokens
[] = {
659 {SOF_TKN_INTEL_DMIC_DRIVER_VERSION
,
660 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
661 offsetof(struct sof_ipc_dai_dmic_params
, driver_ipc_version
),
663 {SOF_TKN_INTEL_DMIC_CLK_MIN
,
664 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
665 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_min
), 0},
666 {SOF_TKN_INTEL_DMIC_CLK_MAX
,
667 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
668 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_max
), 0},
669 {SOF_TKN_INTEL_DMIC_SAMPLE_RATE
,
670 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
671 offsetof(struct sof_ipc_dai_dmic_params
, fifo_fs
), 0},
672 {SOF_TKN_INTEL_DMIC_DUTY_MIN
,
673 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
674 offsetof(struct sof_ipc_dai_dmic_params
, duty_min
), 0},
675 {SOF_TKN_INTEL_DMIC_DUTY_MAX
,
676 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
677 offsetof(struct sof_ipc_dai_dmic_params
, duty_max
), 0},
678 {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE
,
679 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
680 offsetof(struct sof_ipc_dai_dmic_params
,
682 {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH
,
683 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
684 offsetof(struct sof_ipc_dai_dmic_params
, fifo_bits
), 0},
685 {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS
,
686 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
687 offsetof(struct sof_ipc_dai_dmic_params
, unmute_ramp_time
), 0},
692 static const struct sof_topology_token esai_tokens
[] = {
693 {SOF_TKN_IMX_ESAI_MCLK_ID
,
694 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
695 offsetof(struct sof_ipc_dai_esai_params
, mclk_id
), 0},
699 static const struct sof_topology_token sai_tokens
[] = {
700 {SOF_TKN_IMX_SAI_MCLK_ID
,
701 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
702 offsetof(struct sof_ipc_dai_sai_params
, mclk_id
), 0},
707 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
708 * as it increments the index while parsing the array of pdm tokens
709 * and determines the correct offset
711 static const struct sof_topology_token dmic_pdm_tokens
[] = {
712 {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID
,
713 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
714 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, id
),
716 {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable
,
717 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
718 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_a
),
720 {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable
,
721 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
722 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_b
),
724 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A
,
725 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
726 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_a
),
728 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B
,
729 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
730 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_b
),
732 {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE
,
733 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
734 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, clk_edge
),
736 {SOF_TKN_INTEL_DMIC_PDM_SKEW
,
737 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
738 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, skew
),
743 static const struct sof_topology_token hda_tokens
[] = {
747 static const struct sof_topology_token led_tokens
[] = {
748 {SOF_TKN_MUTE_LED_USE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
749 offsetof(struct snd_sof_led_control
, use_led
), 0},
750 {SOF_TKN_MUTE_LED_DIRECTION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
751 get_token_u32
, offsetof(struct snd_sof_led_control
, direction
), 0},
754 static void sof_parse_uuid_tokens(struct snd_soc_component
*scomp
,
756 const struct sof_topology_token
*tokens
,
758 struct snd_soc_tplg_vendor_array
*array
)
760 struct snd_soc_tplg_vendor_uuid_elem
*elem
;
763 /* parse element by element */
764 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
765 elem
= &array
->uuid
[i
];
767 /* search for token */
768 for (j
= 0; j
< count
; j
++) {
769 /* match token type */
770 if (tokens
[j
].type
!= SND_SOC_TPLG_TUPLE_TYPE_UUID
)
774 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
777 /* matched - now load token */
778 tokens
[j
].get_token(elem
, object
, tokens
[j
].offset
,
784 static void sof_parse_string_tokens(struct snd_soc_component
*scomp
,
786 const struct sof_topology_token
*tokens
,
788 struct snd_soc_tplg_vendor_array
*array
)
790 struct snd_soc_tplg_vendor_string_elem
*elem
;
793 /* parse element by element */
794 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
795 elem
= &array
->string
[i
];
797 /* search for token */
798 for (j
= 0; j
< count
; j
++) {
799 /* match token type */
800 if (tokens
[j
].type
!= SND_SOC_TPLG_TUPLE_TYPE_STRING
)
804 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
807 /* matched - now load token */
808 tokens
[j
].get_token(elem
, object
, tokens
[j
].offset
,
814 static void sof_parse_word_tokens(struct snd_soc_component
*scomp
,
816 const struct sof_topology_token
*tokens
,
818 struct snd_soc_tplg_vendor_array
*array
)
820 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
821 struct snd_soc_tplg_vendor_value_elem
*elem
;
822 size_t size
= sizeof(struct sof_ipc_dai_dmic_pdm_ctrl
);
827 /* parse element by element */
828 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
829 elem
= &array
->value
[i
];
831 /* search for token */
832 for (j
= 0; j
< count
; j
++) {
833 /* match token type */
834 if (!(tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_WORD
||
835 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_SHORT
||
836 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_BYTE
||
837 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_BOOL
))
841 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
844 /* pdm config array index */
846 index
= sdev
->private;
848 /* matched - determine offset */
849 switch (tokens
[j
].token
) {
850 case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID
:
852 /* inc number of pdm array index */
856 case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable
:
857 case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable
:
858 case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A
:
859 case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B
:
860 case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE
:
861 case SOF_TKN_INTEL_DMIC_PDM_SKEW
:
863 /* check if array index is valid */
864 if (!index
|| *index
== 0) {
866 "error: invalid array offset\n");
869 /* offset within the pdm config array */
870 offset
= size
* (*index
- 1);
879 tokens
[j
].get_token(elem
, object
,
880 offset
+ tokens
[j
].offset
,
886 static int sof_parse_tokens(struct snd_soc_component
*scomp
,
888 const struct sof_topology_token
*tokens
,
890 struct snd_soc_tplg_vendor_array
*array
,
895 while (priv_size
> 0) {
896 asize
= le32_to_cpu(array
->size
);
899 if (asize
< 0) { /* FIXME: A zero-size array makes no sense */
900 dev_err(scomp
->dev
, "error: invalid array size 0x%x\n",
905 /* make sure there is enough data before parsing */
908 dev_err(scomp
->dev
, "error: invalid array size 0x%x\n",
913 /* call correct parser depending on type */
914 switch (le32_to_cpu(array
->type
)) {
915 case SND_SOC_TPLG_TUPLE_TYPE_UUID
:
916 sof_parse_uuid_tokens(scomp
, object
, tokens
, count
,
919 case SND_SOC_TPLG_TUPLE_TYPE_STRING
:
920 sof_parse_string_tokens(scomp
, object
, tokens
, count
,
923 case SND_SOC_TPLG_TUPLE_TYPE_BOOL
:
924 case SND_SOC_TPLG_TUPLE_TYPE_BYTE
:
925 case SND_SOC_TPLG_TUPLE_TYPE_WORD
:
926 case SND_SOC_TPLG_TUPLE_TYPE_SHORT
:
927 sof_parse_word_tokens(scomp
, object
, tokens
, count
,
931 dev_err(scomp
->dev
, "error: unknown token type %d\n",
937 array
= (struct snd_soc_tplg_vendor_array
*)((u8
*)array
943 static void sof_dbg_comp_config(struct snd_soc_component
*scomp
,
944 struct sof_ipc_comp_config
*config
)
946 dev_dbg(scomp
->dev
, " config: periods snk %d src %d fmt %d\n",
947 config
->periods_sink
, config
->periods_source
,
952 * Standard Kcontrols.
955 static int sof_control_load_volume(struct snd_soc_component
*scomp
,
956 struct snd_sof_control
*scontrol
,
957 struct snd_kcontrol_new
*kc
,
958 struct snd_soc_tplg_ctl_hdr
*hdr
)
960 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
961 struct snd_soc_tplg_mixer_control
*mc
=
962 container_of(hdr
, struct snd_soc_tplg_mixer_control
, hdr
);
963 struct sof_ipc_ctrl_data
*cdata
;
968 /* validate topology data */
969 if (le32_to_cpu(mc
->num_channels
) > SND_SOC_TPLG_MAX_CHAN
) {
974 /* init the volume get/put data */
975 scontrol
->size
= struct_size(scontrol
->control_data
, chanv
,
976 le32_to_cpu(mc
->num_channels
));
977 scontrol
->control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
978 if (!scontrol
->control_data
) {
983 scontrol
->comp_id
= sdev
->next_comp_id
;
984 scontrol
->min_volume_step
= le32_to_cpu(mc
->min
);
985 scontrol
->max_volume_step
= le32_to_cpu(mc
->max
);
986 scontrol
->num_channels
= le32_to_cpu(mc
->num_channels
);
988 /* set cmd for mixer control */
989 if (le32_to_cpu(mc
->max
) == 1) {
990 scontrol
->cmd
= SOF_CTRL_CMD_SWITCH
;
994 scontrol
->cmd
= SOF_CTRL_CMD_VOLUME
;
996 /* extract tlv data */
997 if (get_tlv_data(kc
->tlv
.p
, tlv
) < 0) {
998 dev_err(scomp
->dev
, "error: invalid TLV data\n");
1003 /* set up volume table */
1004 ret
= set_up_volume_table(scontrol
, tlv
, le32_to_cpu(mc
->max
) + 1);
1006 dev_err(scomp
->dev
, "error: setting up volume table\n");
1010 /* set default volume values to 0dB in control */
1011 cdata
= scontrol
->control_data
;
1012 for (i
= 0; i
< scontrol
->num_channels
; i
++) {
1013 cdata
->chanv
[i
].channel
= i
;
1014 cdata
->chanv
[i
].value
= VOL_ZERO_DB
;
1018 /* set up possible led control from mixer private data */
1019 ret
= sof_parse_tokens(scomp
, &scontrol
->led_ctl
, led_tokens
,
1020 ARRAY_SIZE(led_tokens
), mc
->priv
.array
,
1021 le32_to_cpu(mc
->priv
.size
));
1023 dev_err(scomp
->dev
, "error: parse led tokens failed %d\n",
1024 le32_to_cpu(mc
->priv
.size
));
1025 goto out_free_table
;
1028 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d\n",
1029 scontrol
->comp_id
, scontrol
->num_channels
);
1034 if (le32_to_cpu(mc
->max
) > 1)
1035 kfree(scontrol
->volume_table
);
1037 kfree(scontrol
->control_data
);
1042 static int sof_control_load_enum(struct snd_soc_component
*scomp
,
1043 struct snd_sof_control
*scontrol
,
1044 struct snd_kcontrol_new
*kc
,
1045 struct snd_soc_tplg_ctl_hdr
*hdr
)
1047 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1048 struct snd_soc_tplg_enum_control
*ec
=
1049 container_of(hdr
, struct snd_soc_tplg_enum_control
, hdr
);
1051 /* validate topology data */
1052 if (le32_to_cpu(ec
->num_channels
) > SND_SOC_TPLG_MAX_CHAN
)
1055 /* init the enum get/put data */
1056 scontrol
->size
= struct_size(scontrol
->control_data
, chanv
,
1057 le32_to_cpu(ec
->num_channels
));
1058 scontrol
->control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
1059 if (!scontrol
->control_data
)
1062 scontrol
->comp_id
= sdev
->next_comp_id
;
1063 scontrol
->num_channels
= le32_to_cpu(ec
->num_channels
);
1065 scontrol
->cmd
= SOF_CTRL_CMD_ENUM
;
1067 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d comp_id %d\n",
1068 scontrol
->comp_id
, scontrol
->num_channels
, scontrol
->comp_id
);
1073 static int sof_control_load_bytes(struct snd_soc_component
*scomp
,
1074 struct snd_sof_control
*scontrol
,
1075 struct snd_kcontrol_new
*kc
,
1076 struct snd_soc_tplg_ctl_hdr
*hdr
)
1078 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1079 struct sof_ipc_ctrl_data
*cdata
;
1080 struct snd_soc_tplg_bytes_control
*control
=
1081 container_of(hdr
, struct snd_soc_tplg_bytes_control
, hdr
);
1082 struct soc_bytes_ext
*sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
1083 int max_size
= sbe
->max
;
1086 /* init the get/put bytes data */
1087 scontrol
->size
= sizeof(struct sof_ipc_ctrl_data
) +
1088 le32_to_cpu(control
->priv
.size
);
1090 if (scontrol
->size
> max_size
) {
1091 dev_err(scomp
->dev
, "err: bytes data size %d exceeds max %d.\n",
1092 scontrol
->size
, max_size
);
1097 scontrol
->control_data
= kzalloc(max_size
, GFP_KERNEL
);
1098 cdata
= scontrol
->control_data
;
1099 if (!scontrol
->control_data
) {
1104 scontrol
->comp_id
= sdev
->next_comp_id
;
1105 scontrol
->cmd
= SOF_CTRL_CMD_BINARY
;
1107 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d\n",
1108 scontrol
->comp_id
, scontrol
->num_channels
);
1110 if (le32_to_cpu(control
->priv
.size
) > 0) {
1111 memcpy(cdata
->data
, control
->priv
.data
,
1112 le32_to_cpu(control
->priv
.size
));
1114 if (cdata
->data
->magic
!= SOF_ABI_MAGIC
) {
1115 dev_err(scomp
->dev
, "error: Wrong ABI magic 0x%08x.\n",
1116 cdata
->data
->magic
);
1120 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
,
1121 cdata
->data
->abi
)) {
1123 "error: Incompatible ABI version 0x%08x.\n",
1128 if (cdata
->data
->size
+ sizeof(const struct sof_abi_hdr
) !=
1129 le32_to_cpu(control
->priv
.size
)) {
1131 "error: Conflict in bytes vs. priv size.\n");
1140 kfree(scontrol
->control_data
);
1145 /* external kcontrol init - used for any driver specific init */
1146 static int sof_control_load(struct snd_soc_component
*scomp
, int index
,
1147 struct snd_kcontrol_new
*kc
,
1148 struct snd_soc_tplg_ctl_hdr
*hdr
)
1150 struct soc_mixer_control
*sm
;
1151 struct soc_bytes_ext
*sbe
;
1152 struct soc_enum
*se
;
1153 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1154 struct snd_soc_dobj
*dobj
;
1155 struct snd_sof_control
*scontrol
;
1158 dev_dbg(scomp
->dev
, "tplg: load control type %d name : %s\n",
1159 hdr
->type
, hdr
->name
);
1161 scontrol
= kzalloc(sizeof(*scontrol
), GFP_KERNEL
);
1165 scontrol
->scomp
= scomp
;
1167 switch (le32_to_cpu(hdr
->ops
.info
)) {
1168 case SND_SOC_TPLG_CTL_VOLSW
:
1169 case SND_SOC_TPLG_CTL_VOLSW_SX
:
1170 case SND_SOC_TPLG_CTL_VOLSW_XR_SX
:
1171 sm
= (struct soc_mixer_control
*)kc
->private_value
;
1173 ret
= sof_control_load_volume(scomp
, scontrol
, kc
, hdr
);
1175 case SND_SOC_TPLG_CTL_BYTES
:
1176 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
1178 ret
= sof_control_load_bytes(scomp
, scontrol
, kc
, hdr
);
1180 case SND_SOC_TPLG_CTL_ENUM
:
1181 case SND_SOC_TPLG_CTL_ENUM_VALUE
:
1182 se
= (struct soc_enum
*)kc
->private_value
;
1184 ret
= sof_control_load_enum(scomp
, scontrol
, kc
, hdr
);
1186 case SND_SOC_TPLG_CTL_RANGE
:
1187 case SND_SOC_TPLG_CTL_STROBE
:
1188 case SND_SOC_TPLG_DAPM_CTL_VOLSW
:
1189 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE
:
1190 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT
:
1191 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE
:
1192 case SND_SOC_TPLG_DAPM_CTL_PIN
:
1194 dev_warn(scomp
->dev
, "control type not supported %d:%d:%d\n",
1195 hdr
->ops
.get
, hdr
->ops
.put
, hdr
->ops
.info
);
1205 dobj
->private = scontrol
;
1206 list_add(&scontrol
->list
, &sdev
->kcontrol_list
);
1210 static int sof_control_unload(struct snd_soc_component
*scomp
,
1211 struct snd_soc_dobj
*dobj
)
1213 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1214 struct sof_ipc_free fcomp
;
1215 struct snd_sof_control
*scontrol
= dobj
->private;
1217 dev_dbg(scomp
->dev
, "tplg: unload control name : %s\n", scomp
->name
);
1219 fcomp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_FREE
;
1220 fcomp
.hdr
.size
= sizeof(fcomp
);
1221 fcomp
.id
= scontrol
->comp_id
;
1223 kfree(scontrol
->control_data
);
1224 list_del(&scontrol
->list
);
1226 /* send IPC to the DSP */
1227 return sof_ipc_tx_message(sdev
->ipc
,
1228 fcomp
.hdr
.cmd
, &fcomp
, sizeof(fcomp
),
1236 static int sof_connect_dai_widget(struct snd_soc_component
*scomp
,
1237 struct snd_soc_dapm_widget
*w
,
1238 struct snd_soc_tplg_dapm_widget
*tw
,
1239 struct snd_sof_dai
*dai
)
1241 struct snd_soc_card
*card
= scomp
->card
;
1242 struct snd_soc_pcm_runtime
*rtd
;
1244 list_for_each_entry(rtd
, &card
->rtd_list
, list
) {
1245 dev_vdbg(scomp
->dev
, "tplg: check widget: %s stream: %s dai stream: %s\n",
1246 w
->name
, w
->sname
, rtd
->dai_link
->stream_name
);
1248 if (!w
->sname
|| !rtd
->dai_link
->stream_name
)
1251 /* does stream match DAI link ? */
1252 if (strcmp(w
->sname
, rtd
->dai_link
->stream_name
))
1256 case snd_soc_dapm_dai_out
:
1257 rtd
->cpu_dai
->capture_widget
= w
;
1258 dai
->name
= rtd
->dai_link
->name
;
1259 dev_dbg(scomp
->dev
, "tplg: connected widget %s -> DAI link %s\n",
1260 w
->name
, rtd
->dai_link
->name
);
1262 case snd_soc_dapm_dai_in
:
1263 rtd
->cpu_dai
->playback_widget
= w
;
1264 dai
->name
= rtd
->dai_link
->name
;
1265 dev_dbg(scomp
->dev
, "tplg: connected widget %s -> DAI link %s\n",
1266 w
->name
, rtd
->dai_link
->name
);
1273 /* check we have a connection */
1275 dev_err(scomp
->dev
, "error: can't connect DAI %s stream %s\n",
1283 static int sof_widget_load_dai(struct snd_soc_component
*scomp
, int index
,
1284 struct snd_sof_widget
*swidget
,
1285 struct snd_soc_tplg_dapm_widget
*tw
,
1286 struct sof_ipc_comp_reply
*r
,
1287 struct snd_sof_dai
*dai
)
1289 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1290 struct snd_soc_tplg_private
*private = &tw
->priv
;
1291 struct sof_ipc_comp_dai comp_dai
;
1294 /* configure dai IPC message */
1295 memset(&comp_dai
, 0, sizeof(comp_dai
));
1296 comp_dai
.comp
.hdr
.size
= sizeof(comp_dai
);
1297 comp_dai
.comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1298 comp_dai
.comp
.id
= swidget
->comp_id
;
1299 comp_dai
.comp
.type
= SOF_COMP_DAI
;
1300 comp_dai
.comp
.pipeline_id
= index
;
1301 comp_dai
.config
.hdr
.size
= sizeof(comp_dai
.config
);
1303 ret
= sof_parse_tokens(scomp
, &comp_dai
, dai_tokens
,
1304 ARRAY_SIZE(dai_tokens
), private->array
,
1305 le32_to_cpu(private->size
));
1307 dev_err(scomp
->dev
, "error: parse dai tokens failed %d\n",
1308 le32_to_cpu(private->size
));
1312 ret
= sof_parse_tokens(scomp
, &comp_dai
.config
, comp_tokens
,
1313 ARRAY_SIZE(comp_tokens
), private->array
,
1314 le32_to_cpu(private->size
));
1316 dev_err(scomp
->dev
, "error: parse dai.cfg tokens failed %d\n",
1321 dev_dbg(scomp
->dev
, "dai %s: type %d index %d\n",
1322 swidget
->widget
->name
, comp_dai
.type
, comp_dai
.dai_index
);
1323 sof_dbg_comp_config(scomp
, &comp_dai
.config
);
1325 ret
= sof_ipc_tx_message(sdev
->ipc
, comp_dai
.comp
.hdr
.cmd
,
1326 &comp_dai
, sizeof(comp_dai
), r
, sizeof(*r
));
1328 if (ret
== 0 && dai
) {
1330 memcpy(&dai
->comp_dai
, &comp_dai
, sizeof(comp_dai
));
1340 static int sof_widget_load_buffer(struct snd_soc_component
*scomp
, int index
,
1341 struct snd_sof_widget
*swidget
,
1342 struct snd_soc_tplg_dapm_widget
*tw
,
1343 struct sof_ipc_comp_reply
*r
)
1345 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1346 struct snd_soc_tplg_private
*private = &tw
->priv
;
1347 struct sof_ipc_buffer
*buffer
;
1350 buffer
= kzalloc(sizeof(*buffer
), GFP_KERNEL
);
1354 /* configure dai IPC message */
1355 buffer
->comp
.hdr
.size
= sizeof(*buffer
);
1356 buffer
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_BUFFER_NEW
;
1357 buffer
->comp
.id
= swidget
->comp_id
;
1358 buffer
->comp
.type
= SOF_COMP_BUFFER
;
1359 buffer
->comp
.pipeline_id
= index
;
1361 ret
= sof_parse_tokens(scomp
, buffer
, buffer_tokens
,
1362 ARRAY_SIZE(buffer_tokens
), private->array
,
1363 le32_to_cpu(private->size
));
1365 dev_err(scomp
->dev
, "error: parse buffer tokens failed %d\n",
1371 dev_dbg(scomp
->dev
, "buffer %s: size %d caps 0x%x\n",
1372 swidget
->widget
->name
, buffer
->size
, buffer
->caps
);
1374 swidget
->private = buffer
;
1376 ret
= sof_ipc_tx_message(sdev
->ipc
, buffer
->comp
.hdr
.cmd
, buffer
,
1377 sizeof(*buffer
), r
, sizeof(*r
));
1379 dev_err(scomp
->dev
, "error: buffer %s load failed\n",
1380 swidget
->widget
->name
);
1387 /* bind PCM ID to host component ID */
1388 static int spcm_bind(struct snd_soc_component
*scomp
, struct snd_sof_pcm
*spcm
,
1391 struct snd_sof_widget
*host_widget
;
1393 host_widget
= snd_sof_find_swidget_sname(scomp
,
1394 spcm
->pcm
.caps
[dir
].name
,
1397 dev_err(scomp
->dev
, "can't find host comp to bind pcm\n");
1401 spcm
->stream
[dir
].comp_id
= host_widget
->comp_id
;
1410 static int sof_widget_load_pcm(struct snd_soc_component
*scomp
, int index
,
1411 struct snd_sof_widget
*swidget
,
1412 enum sof_ipc_stream_direction dir
,
1413 struct snd_soc_tplg_dapm_widget
*tw
,
1414 struct sof_ipc_comp_reply
*r
)
1416 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1417 struct snd_soc_tplg_private
*private = &tw
->priv
;
1418 struct sof_ipc_comp_host
*host
;
1421 host
= kzalloc(sizeof(*host
), GFP_KERNEL
);
1425 /* configure host comp IPC message */
1426 host
->comp
.hdr
.size
= sizeof(*host
);
1427 host
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1428 host
->comp
.id
= swidget
->comp_id
;
1429 host
->comp
.type
= SOF_COMP_HOST
;
1430 host
->comp
.pipeline_id
= index
;
1431 host
->direction
= dir
;
1432 host
->config
.hdr
.size
= sizeof(host
->config
);
1434 ret
= sof_parse_tokens(scomp
, host
, pcm_tokens
,
1435 ARRAY_SIZE(pcm_tokens
), private->array
,
1436 le32_to_cpu(private->size
));
1438 dev_err(scomp
->dev
, "error: parse host tokens failed %d\n",
1443 ret
= sof_parse_tokens(scomp
, &host
->config
, comp_tokens
,
1444 ARRAY_SIZE(comp_tokens
), private->array
,
1445 le32_to_cpu(private->size
));
1447 dev_err(scomp
->dev
, "error: parse host.cfg tokens failed %d\n",
1448 le32_to_cpu(private->size
));
1452 dev_dbg(scomp
->dev
, "loaded host %s\n", swidget
->widget
->name
);
1453 sof_dbg_comp_config(scomp
, &host
->config
);
1455 swidget
->private = host
;
1457 ret
= sof_ipc_tx_message(sdev
->ipc
, host
->comp
.hdr
.cmd
, host
,
1458 sizeof(*host
), r
, sizeof(*r
));
1469 int sof_load_pipeline_ipc(struct device
*dev
,
1470 struct sof_ipc_pipe_new
*pipeline
,
1471 struct sof_ipc_comp_reply
*r
)
1473 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
1474 struct sof_ipc_pm_core_config pm_core_config
;
1477 ret
= sof_ipc_tx_message(sdev
->ipc
, pipeline
->hdr
.cmd
, pipeline
,
1478 sizeof(*pipeline
), r
, sizeof(*r
));
1480 dev_err(dev
, "error: load pipeline ipc failure\n");
1484 /* power up the core that this pipeline is scheduled on */
1485 ret
= snd_sof_dsp_core_power_up(sdev
, 1 << pipeline
->core
);
1487 dev_err(dev
, "error: powering up pipeline schedule core %d\n",
1492 /* update enabled cores mask */
1493 sdev
->enabled_cores_mask
|= 1 << pipeline
->core
;
1496 * Now notify DSP that the core that this pipeline is scheduled on
1497 * has been powered up
1499 memset(&pm_core_config
, 0, sizeof(pm_core_config
));
1500 pm_core_config
.enable_mask
= sdev
->enabled_cores_mask
;
1502 /* configure CORE_ENABLE ipc message */
1503 pm_core_config
.hdr
.size
= sizeof(pm_core_config
);
1504 pm_core_config
.hdr
.cmd
= SOF_IPC_GLB_PM_MSG
| SOF_IPC_PM_CORE_ENABLE
;
1507 ret
= sof_ipc_tx_message(sdev
->ipc
, pm_core_config
.hdr
.cmd
,
1508 &pm_core_config
, sizeof(pm_core_config
),
1509 &pm_core_config
, sizeof(pm_core_config
));
1511 dev_err(dev
, "error: core enable ipc failure\n");
1516 static int sof_widget_load_pipeline(struct snd_soc_component
*scomp
,
1517 int index
, struct snd_sof_widget
*swidget
,
1518 struct snd_soc_tplg_dapm_widget
*tw
,
1519 struct sof_ipc_comp_reply
*r
)
1521 struct snd_soc_tplg_private
*private = &tw
->priv
;
1522 struct sof_ipc_pipe_new
*pipeline
;
1523 struct snd_sof_widget
*comp_swidget
;
1526 pipeline
= kzalloc(sizeof(*pipeline
), GFP_KERNEL
);
1530 /* configure dai IPC message */
1531 pipeline
->hdr
.size
= sizeof(*pipeline
);
1532 pipeline
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_NEW
;
1533 pipeline
->pipeline_id
= index
;
1534 pipeline
->comp_id
= swidget
->comp_id
;
1536 /* component at start of pipeline is our stream id */
1537 comp_swidget
= snd_sof_find_swidget(scomp
, tw
->sname
);
1538 if (!comp_swidget
) {
1539 dev_err(scomp
->dev
, "error: widget %s refers to non existent widget %s\n",
1540 tw
->name
, tw
->sname
);
1545 pipeline
->sched_id
= comp_swidget
->comp_id
;
1547 dev_dbg(scomp
->dev
, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
1548 pipeline
->pipeline_id
, pipeline
->comp_id
, pipeline
->sched_id
);
1550 ret
= sof_parse_tokens(scomp
, pipeline
, sched_tokens
,
1551 ARRAY_SIZE(sched_tokens
), private->array
,
1552 le32_to_cpu(private->size
));
1554 dev_err(scomp
->dev
, "error: parse pipeline tokens failed %d\n",
1559 dev_dbg(scomp
->dev
, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
1560 swidget
->widget
->name
, pipeline
->period
, pipeline
->priority
,
1561 pipeline
->period_mips
, pipeline
->core
, pipeline
->frames_per_sched
);
1563 swidget
->private = pipeline
;
1565 /* send ipc's to create pipeline comp and power up schedule core */
1566 ret
= sof_load_pipeline_ipc(scomp
->dev
, pipeline
, r
);
1578 static int sof_widget_load_mixer(struct snd_soc_component
*scomp
, int index
,
1579 struct snd_sof_widget
*swidget
,
1580 struct snd_soc_tplg_dapm_widget
*tw
,
1581 struct sof_ipc_comp_reply
*r
)
1583 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1584 struct snd_soc_tplg_private
*private = &tw
->priv
;
1585 struct sof_ipc_comp_mixer
*mixer
;
1588 mixer
= kzalloc(sizeof(*mixer
), GFP_KERNEL
);
1592 /* configure mixer IPC message */
1593 mixer
->comp
.hdr
.size
= sizeof(*mixer
);
1594 mixer
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1595 mixer
->comp
.id
= swidget
->comp_id
;
1596 mixer
->comp
.type
= SOF_COMP_MIXER
;
1597 mixer
->comp
.pipeline_id
= index
;
1598 mixer
->config
.hdr
.size
= sizeof(mixer
->config
);
1600 ret
= sof_parse_tokens(scomp
, &mixer
->config
, comp_tokens
,
1601 ARRAY_SIZE(comp_tokens
), private->array
,
1602 le32_to_cpu(private->size
));
1604 dev_err(scomp
->dev
, "error: parse mixer.cfg tokens failed %d\n",
1610 sof_dbg_comp_config(scomp
, &mixer
->config
);
1612 swidget
->private = mixer
;
1614 ret
= sof_ipc_tx_message(sdev
->ipc
, mixer
->comp
.hdr
.cmd
, mixer
,
1615 sizeof(*mixer
), r
, sizeof(*r
));
1625 static int sof_widget_load_mux(struct snd_soc_component
*scomp
, int index
,
1626 struct snd_sof_widget
*swidget
,
1627 struct snd_soc_tplg_dapm_widget
*tw
,
1628 struct sof_ipc_comp_reply
*r
)
1630 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1631 struct snd_soc_tplg_private
*private = &tw
->priv
;
1632 struct sof_ipc_comp_mux
*mux
;
1635 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
1639 /* configure mux IPC message */
1640 mux
->comp
.hdr
.size
= sizeof(*mux
);
1641 mux
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1642 mux
->comp
.id
= swidget
->comp_id
;
1643 mux
->comp
.type
= SOF_COMP_MUX
;
1644 mux
->comp
.pipeline_id
= index
;
1645 mux
->config
.hdr
.size
= sizeof(mux
->config
);
1647 ret
= sof_parse_tokens(scomp
, &mux
->config
, comp_tokens
,
1648 ARRAY_SIZE(comp_tokens
), private->array
,
1649 le32_to_cpu(private->size
));
1651 dev_err(scomp
->dev
, "error: parse mux.cfg tokens failed %d\n",
1657 sof_dbg_comp_config(scomp
, &mux
->config
);
1659 swidget
->private = mux
;
1661 ret
= sof_ipc_tx_message(sdev
->ipc
, mux
->comp
.hdr
.cmd
, mux
,
1662 sizeof(*mux
), r
, sizeof(*r
));
1673 static int sof_widget_load_pga(struct snd_soc_component
*scomp
, int index
,
1674 struct snd_sof_widget
*swidget
,
1675 struct snd_soc_tplg_dapm_widget
*tw
,
1676 struct sof_ipc_comp_reply
*r
)
1678 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1679 struct snd_soc_tplg_private
*private = &tw
->priv
;
1680 struct sof_ipc_comp_volume
*volume
;
1681 struct snd_sof_control
*scontrol
;
1686 volume
= kzalloc(sizeof(*volume
), GFP_KERNEL
);
1690 if (!le32_to_cpu(tw
->num_kcontrols
)) {
1691 dev_err(scomp
->dev
, "error: invalid kcontrol count %d for volume\n",
1697 /* configure volume IPC message */
1698 volume
->comp
.hdr
.size
= sizeof(*volume
);
1699 volume
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1700 volume
->comp
.id
= swidget
->comp_id
;
1701 volume
->comp
.type
= SOF_COMP_VOLUME
;
1702 volume
->comp
.pipeline_id
= index
;
1703 volume
->config
.hdr
.size
= sizeof(volume
->config
);
1705 ret
= sof_parse_tokens(scomp
, volume
, volume_tokens
,
1706 ARRAY_SIZE(volume_tokens
), private->array
,
1707 le32_to_cpu(private->size
));
1709 dev_err(scomp
->dev
, "error: parse volume tokens failed %d\n",
1713 ret
= sof_parse_tokens(scomp
, &volume
->config
, comp_tokens
,
1714 ARRAY_SIZE(comp_tokens
), private->array
,
1715 le32_to_cpu(private->size
));
1717 dev_err(scomp
->dev
, "error: parse volume.cfg tokens failed %d\n",
1718 le32_to_cpu(private->size
));
1722 sof_dbg_comp_config(scomp
, &volume
->config
);
1724 swidget
->private = volume
;
1726 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
1727 if (scontrol
->comp_id
== swidget
->comp_id
&&
1728 scontrol
->volume_table
) {
1729 min_step
= scontrol
->min_volume_step
;
1730 max_step
= scontrol
->max_volume_step
;
1731 volume
->min_value
= scontrol
->volume_table
[min_step
];
1732 volume
->max_value
= scontrol
->volume_table
[max_step
];
1733 volume
->channels
= scontrol
->num_channels
;
1738 ret
= sof_ipc_tx_message(sdev
->ipc
, volume
->comp
.hdr
.cmd
, volume
,
1739 sizeof(*volume
), r
, sizeof(*r
));
1751 static int sof_widget_load_src(struct snd_soc_component
*scomp
, int index
,
1752 struct snd_sof_widget
*swidget
,
1753 struct snd_soc_tplg_dapm_widget
*tw
,
1754 struct sof_ipc_comp_reply
*r
)
1756 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1757 struct snd_soc_tplg_private
*private = &tw
->priv
;
1758 struct sof_ipc_comp_src
*src
;
1761 src
= kzalloc(sizeof(*src
), GFP_KERNEL
);
1765 /* configure src IPC message */
1766 src
->comp
.hdr
.size
= sizeof(*src
);
1767 src
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1768 src
->comp
.id
= swidget
->comp_id
;
1769 src
->comp
.type
= SOF_COMP_SRC
;
1770 src
->comp
.pipeline_id
= index
;
1771 src
->config
.hdr
.size
= sizeof(src
->config
);
1773 ret
= sof_parse_tokens(scomp
, src
, src_tokens
,
1774 ARRAY_SIZE(src_tokens
), private->array
,
1775 le32_to_cpu(private->size
));
1777 dev_err(scomp
->dev
, "error: parse src tokens failed %d\n",
1782 ret
= sof_parse_tokens(scomp
, &src
->config
, comp_tokens
,
1783 ARRAY_SIZE(comp_tokens
), private->array
,
1784 le32_to_cpu(private->size
));
1786 dev_err(scomp
->dev
, "error: parse src.cfg tokens failed %d\n",
1787 le32_to_cpu(private->size
));
1791 dev_dbg(scomp
->dev
, "src %s: source rate %d sink rate %d\n",
1792 swidget
->widget
->name
, src
->source_rate
, src
->sink_rate
);
1793 sof_dbg_comp_config(scomp
, &src
->config
);
1795 swidget
->private = src
;
1797 ret
= sof_ipc_tx_message(sdev
->ipc
, src
->comp
.hdr
.cmd
, src
,
1798 sizeof(*src
), r
, sizeof(*r
));
1810 static int sof_widget_load_asrc(struct snd_soc_component
*scomp
, int index
,
1811 struct snd_sof_widget
*swidget
,
1812 struct snd_soc_tplg_dapm_widget
*tw
,
1813 struct sof_ipc_comp_reply
*r
)
1815 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1816 struct snd_soc_tplg_private
*private = &tw
->priv
;
1817 struct sof_ipc_comp_asrc
*asrc
;
1820 asrc
= kzalloc(sizeof(*asrc
), GFP_KERNEL
);
1824 /* configure ASRC IPC message */
1825 asrc
->comp
.hdr
.size
= sizeof(*asrc
);
1826 asrc
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1827 asrc
->comp
.id
= swidget
->comp_id
;
1828 asrc
->comp
.type
= SOF_COMP_ASRC
;
1829 asrc
->comp
.pipeline_id
= index
;
1830 asrc
->config
.hdr
.size
= sizeof(asrc
->config
);
1832 ret
= sof_parse_tokens(scomp
, asrc
, asrc_tokens
,
1833 ARRAY_SIZE(asrc_tokens
), private->array
,
1834 le32_to_cpu(private->size
));
1836 dev_err(scomp
->dev
, "error: parse asrc tokens failed %d\n",
1841 ret
= sof_parse_tokens(scomp
, &asrc
->config
, comp_tokens
,
1842 ARRAY_SIZE(comp_tokens
), private->array
,
1843 le32_to_cpu(private->size
));
1845 dev_err(scomp
->dev
, "error: parse asrc.cfg tokens failed %d\n",
1846 le32_to_cpu(private->size
));
1850 dev_dbg(scomp
->dev
, "asrc %s: source rate %d sink rate %d "
1851 "asynch %d operation %d\n",
1852 swidget
->widget
->name
, asrc
->source_rate
, asrc
->sink_rate
,
1853 asrc
->asynchronous_mode
, asrc
->operation_mode
);
1854 sof_dbg_comp_config(scomp
, &asrc
->config
);
1856 swidget
->private = asrc
;
1858 ret
= sof_ipc_tx_message(sdev
->ipc
, asrc
->comp
.hdr
.cmd
, asrc
,
1859 sizeof(*asrc
), r
, sizeof(*r
));
1868 * Signal Generator Topology
1871 static int sof_widget_load_siggen(struct snd_soc_component
*scomp
, int index
,
1872 struct snd_sof_widget
*swidget
,
1873 struct snd_soc_tplg_dapm_widget
*tw
,
1874 struct sof_ipc_comp_reply
*r
)
1876 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1877 struct snd_soc_tplg_private
*private = &tw
->priv
;
1878 struct sof_ipc_comp_tone
*tone
;
1881 tone
= kzalloc(sizeof(*tone
), GFP_KERNEL
);
1885 /* configure siggen IPC message */
1886 tone
->comp
.hdr
.size
= sizeof(*tone
);
1887 tone
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1888 tone
->comp
.id
= swidget
->comp_id
;
1889 tone
->comp
.type
= SOF_COMP_TONE
;
1890 tone
->comp
.pipeline_id
= index
;
1891 tone
->config
.hdr
.size
= sizeof(tone
->config
);
1893 ret
= sof_parse_tokens(scomp
, tone
, tone_tokens
,
1894 ARRAY_SIZE(tone_tokens
), private->array
,
1895 le32_to_cpu(private->size
));
1897 dev_err(scomp
->dev
, "error: parse tone tokens failed %d\n",
1898 le32_to_cpu(private->size
));
1902 ret
= sof_parse_tokens(scomp
, &tone
->config
, comp_tokens
,
1903 ARRAY_SIZE(comp_tokens
), private->array
,
1904 le32_to_cpu(private->size
));
1906 dev_err(scomp
->dev
, "error: parse tone.cfg tokens failed %d\n",
1907 le32_to_cpu(private->size
));
1911 dev_dbg(scomp
->dev
, "tone %s: frequency %d amplitude %d\n",
1912 swidget
->widget
->name
, tone
->frequency
, tone
->amplitude
);
1913 sof_dbg_comp_config(scomp
, &tone
->config
);
1915 swidget
->private = tone
;
1917 ret
= sof_ipc_tx_message(sdev
->ipc
, tone
->comp
.hdr
.cmd
, tone
,
1918 sizeof(*tone
), r
, sizeof(*r
));
1926 static int sof_get_control_data(struct snd_soc_component
*scomp
,
1927 struct snd_soc_dapm_widget
*widget
,
1928 struct sof_widget_data
*wdata
,
1931 const struct snd_kcontrol_new
*kc
;
1932 struct soc_mixer_control
*sm
;
1933 struct soc_bytes_ext
*sbe
;
1934 struct soc_enum
*se
;
1939 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
1940 kc
= &widget
->kcontrol_news
[i
];
1942 switch (widget
->dobj
.widget
.kcontrol_type
) {
1943 case SND_SOC_TPLG_TYPE_MIXER
:
1944 sm
= (struct soc_mixer_control
*)kc
->private_value
;
1945 wdata
[i
].control
= sm
->dobj
.private;
1947 case SND_SOC_TPLG_TYPE_BYTES
:
1948 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
1949 wdata
[i
].control
= sbe
->dobj
.private;
1951 case SND_SOC_TPLG_TYPE_ENUM
:
1952 se
= (struct soc_enum
*)kc
->private_value
;
1953 wdata
[i
].control
= se
->dobj
.private;
1956 dev_err(scomp
->dev
, "error: unknown kcontrol type %d in widget %s\n",
1957 widget
->dobj
.widget
.kcontrol_type
,
1962 if (!wdata
[i
].control
) {
1963 dev_err(scomp
->dev
, "error: no scontrol for widget %s\n",
1968 wdata
[i
].pdata
= wdata
[i
].control
->control_data
->data
;
1969 if (!wdata
[i
].pdata
)
1972 /* make sure data is valid - data can be updated at runtime */
1973 if (wdata
[i
].pdata
->magic
!= SOF_ABI_MAGIC
)
1976 *size
+= wdata
[i
].pdata
->size
;
1979 switch (wdata
[i
].control
->cmd
) {
1980 case SOF_CTRL_CMD_VOLUME
:
1981 case SOF_CTRL_CMD_ENUM
:
1982 case SOF_CTRL_CMD_SWITCH
:
1983 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_VALUE
;
1984 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_VALUE_CHAN_SET
;
1986 case SOF_CTRL_CMD_BINARY
:
1987 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_DATA
;
1988 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_DATA_SET
;
1998 static int sof_process_load(struct snd_soc_component
*scomp
, int index
,
1999 struct snd_sof_widget
*swidget
,
2000 struct snd_soc_tplg_dapm_widget
*tw
,
2001 struct sof_ipc_comp_reply
*r
,
2004 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2005 struct snd_soc_dapm_widget
*widget
= swidget
->widget
;
2006 struct snd_soc_tplg_private
*private = &tw
->priv
;
2007 struct sof_ipc_comp_process
*process
= NULL
;
2008 struct sof_widget_data
*wdata
= NULL
;
2009 size_t ipc_data_size
= 0;
2015 if (type
== SOF_COMP_NONE
) {
2016 dev_err(scomp
->dev
, "error: invalid process comp type %d\n",
2021 /* allocate struct for widget control data sizes and types */
2022 if (widget
->num_kcontrols
) {
2023 wdata
= kcalloc(widget
->num_kcontrols
,
2030 /* get possible component controls and get size of all pdata */
2031 ret
= sof_get_control_data(scomp
, widget
, wdata
,
2038 ipc_size
= sizeof(struct sof_ipc_comp_process
) +
2039 le32_to_cpu(private->size
) +
2042 /* we are exceeding max ipc size, config needs to be sent separately */
2043 if (ipc_size
> SOF_IPC_MSG_MAX_SIZE
) {
2044 ipc_size
-= ipc_data_size
;
2048 process
= kzalloc(ipc_size
, GFP_KERNEL
);
2054 /* configure iir IPC message */
2055 process
->comp
.hdr
.size
= ipc_size
;
2056 process
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
2057 process
->comp
.id
= swidget
->comp_id
;
2058 process
->comp
.type
= type
;
2059 process
->comp
.pipeline_id
= index
;
2060 process
->config
.hdr
.size
= sizeof(process
->config
);
2062 ret
= sof_parse_tokens(scomp
, &process
->config
, comp_tokens
,
2063 ARRAY_SIZE(comp_tokens
), private->array
,
2064 le32_to_cpu(private->size
));
2066 dev_err(scomp
->dev
, "error: parse process.cfg tokens failed %d\n",
2067 le32_to_cpu(private->size
));
2071 sof_dbg_comp_config(scomp
, &process
->config
);
2074 * found private data in control, so copy it.
2075 * get possible component controls - get size of all pdata,
2076 * then memcpy with headers
2078 if (ipc_data_size
) {
2079 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2080 memcpy(&process
->data
+ offset
,
2081 wdata
[i
].pdata
->data
,
2082 wdata
[i
].pdata
->size
);
2083 offset
+= wdata
[i
].pdata
->size
;
2087 process
->size
= ipc_data_size
;
2088 swidget
->private = process
;
2090 ret
= sof_ipc_tx_message(sdev
->ipc
, process
->comp
.hdr
.cmd
, process
,
2091 ipc_size
, r
, sizeof(*r
));
2094 dev_err(scomp
->dev
, "error: create process failed\n");
2098 /* we sent the data in single message so return */
2102 /* send control data with large message supported method */
2103 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2104 wdata
[i
].control
->readback_offset
= 0;
2105 ret
= snd_sof_ipc_set_get_comp_data(wdata
[i
].control
,
2108 wdata
[i
].control
->cmd
,
2111 dev_err(scomp
->dev
, "error: send control failed\n");
2125 * Processing Component Topology - can be "effect", "codec", or general
2129 static int sof_widget_load_process(struct snd_soc_component
*scomp
, int index
,
2130 struct snd_sof_widget
*swidget
,
2131 struct snd_soc_tplg_dapm_widget
*tw
,
2132 struct sof_ipc_comp_reply
*r
)
2134 struct snd_soc_tplg_private
*private = &tw
->priv
;
2135 struct sof_ipc_comp_process config
;
2138 /* check we have some tokens - we need at least process type */
2139 if (le32_to_cpu(private->size
) == 0) {
2140 dev_err(scomp
->dev
, "error: process tokens not found\n");
2144 memset(&config
, 0, sizeof(config
));
2146 /* get the process token */
2147 ret
= sof_parse_tokens(scomp
, &config
, process_tokens
,
2148 ARRAY_SIZE(process_tokens
), private->array
,
2149 le32_to_cpu(private->size
));
2151 dev_err(scomp
->dev
, "error: parse process tokens failed %d\n",
2152 le32_to_cpu(private->size
));
2156 /* now load process specific data and send IPC */
2157 ret
= sof_process_load(scomp
, index
, swidget
, tw
, r
,
2158 find_process_comp_type(config
.type
));
2160 dev_err(scomp
->dev
, "error: process loading failed\n");
2167 static int sof_widget_bind_event(struct snd_soc_component
*scomp
,
2168 struct snd_sof_widget
*swidget
,
2171 struct sof_ipc_comp
*ipc_comp
;
2173 /* validate widget event type */
2174 switch (event_type
) {
2175 case SOF_KEYWORD_DETECT_DAPM_EVENT
:
2176 /* only KEYWORD_DETECT comps should handle this */
2177 if (swidget
->id
!= snd_soc_dapm_effect
)
2180 ipc_comp
= swidget
->private;
2181 if (ipc_comp
&& ipc_comp
->type
!= SOF_COMP_KEYWORD_DETECT
)
2184 /* bind event to keyword detect comp */
2185 return snd_soc_tplg_widget_bind_event(swidget
->widget
,
2187 ARRAY_SIZE(sof_kwd_events
),
2194 "error: invalid event type %d for widget %s\n",
2195 event_type
, swidget
->widget
->name
);
2199 /* external widget init - used for any driver specific init */
2200 static int sof_widget_ready(struct snd_soc_component
*scomp
, int index
,
2201 struct snd_soc_dapm_widget
*w
,
2202 struct snd_soc_tplg_dapm_widget
*tw
)
2204 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2205 struct snd_sof_widget
*swidget
;
2206 struct snd_sof_dai
*dai
;
2207 struct sof_ipc_comp_reply reply
;
2208 struct snd_sof_control
*scontrol
;
2211 swidget
= kzalloc(sizeof(*swidget
), GFP_KERNEL
);
2215 swidget
->scomp
= scomp
;
2216 swidget
->widget
= w
;
2217 swidget
->comp_id
= sdev
->next_comp_id
++;
2218 swidget
->complete
= 0;
2219 swidget
->id
= w
->id
;
2220 swidget
->pipeline_id
= index
;
2221 swidget
->private = NULL
;
2222 memset(&reply
, 0, sizeof(reply
));
2224 dev_dbg(scomp
->dev
, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
2225 swidget
->comp_id
, index
, swidget
->id
, tw
->name
,
2226 strnlen(tw
->sname
, SNDRV_CTL_ELEM_ID_NAME_MAXLEN
) > 0
2227 ? tw
->sname
: "none");
2229 /* handle any special case widgets */
2231 case snd_soc_dapm_dai_in
:
2232 case snd_soc_dapm_dai_out
:
2233 dai
= kzalloc(sizeof(*dai
), GFP_KERNEL
);
2239 ret
= sof_widget_load_dai(scomp
, index
, swidget
, tw
, &reply
,
2242 sof_connect_dai_widget(scomp
, w
, tw
, dai
);
2243 list_add(&dai
->list
, &sdev
->dai_list
);
2244 swidget
->private = dai
;
2249 case snd_soc_dapm_mixer
:
2250 ret
= sof_widget_load_mixer(scomp
, index
, swidget
, tw
, &reply
);
2252 case snd_soc_dapm_pga
:
2253 ret
= sof_widget_load_pga(scomp
, index
, swidget
, tw
, &reply
);
2254 /* Find scontrol for this pga and set readback offset*/
2255 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
2256 if (scontrol
->comp_id
== swidget
->comp_id
) {
2257 scontrol
->readback_offset
= reply
.offset
;
2262 case snd_soc_dapm_buffer
:
2263 ret
= sof_widget_load_buffer(scomp
, index
, swidget
, tw
, &reply
);
2265 case snd_soc_dapm_scheduler
:
2266 ret
= sof_widget_load_pipeline(scomp
, index
, swidget
, tw
,
2269 case snd_soc_dapm_aif_out
:
2270 ret
= sof_widget_load_pcm(scomp
, index
, swidget
,
2271 SOF_IPC_STREAM_CAPTURE
, tw
, &reply
);
2273 case snd_soc_dapm_aif_in
:
2274 ret
= sof_widget_load_pcm(scomp
, index
, swidget
,
2275 SOF_IPC_STREAM_PLAYBACK
, tw
, &reply
);
2277 case snd_soc_dapm_src
:
2278 ret
= sof_widget_load_src(scomp
, index
, swidget
, tw
, &reply
);
2280 case snd_soc_dapm_asrc
:
2281 ret
= sof_widget_load_asrc(scomp
, index
, swidget
, tw
, &reply
);
2283 case snd_soc_dapm_siggen
:
2284 ret
= sof_widget_load_siggen(scomp
, index
, swidget
, tw
, &reply
);
2286 case snd_soc_dapm_effect
:
2287 ret
= sof_widget_load_process(scomp
, index
, swidget
, tw
,
2290 case snd_soc_dapm_mux
:
2291 case snd_soc_dapm_demux
:
2292 ret
= sof_widget_load_mux(scomp
, index
, swidget
, tw
, &reply
);
2294 case snd_soc_dapm_switch
:
2295 case snd_soc_dapm_dai_link
:
2296 case snd_soc_dapm_kcontrol
:
2298 dev_warn(scomp
->dev
, "warning: widget type %d name %s not handled\n",
2299 swidget
->id
, tw
->name
);
2303 /* check IPC reply */
2304 if (ret
< 0 || reply
.rhdr
.error
< 0) {
2306 "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
2307 tw
->shift
, swidget
->id
, tw
->name
,
2308 strnlen(tw
->sname
, SNDRV_CTL_ELEM_ID_NAME_MAXLEN
) > 0
2309 ? tw
->sname
: "none", reply
.rhdr
.error
);
2314 /* bind widget to external event */
2315 if (tw
->event_type
) {
2316 ret
= sof_widget_bind_event(scomp
, swidget
,
2317 le16_to_cpu(tw
->event_type
));
2319 dev_err(scomp
->dev
, "error: widget event binding failed\n");
2320 kfree(swidget
->private);
2326 w
->dobj
.private = swidget
;
2327 list_add(&swidget
->list
, &sdev
->widget_list
);
2331 static int sof_route_unload(struct snd_soc_component
*scomp
,
2332 struct snd_soc_dobj
*dobj
)
2334 struct snd_sof_route
*sroute
;
2336 sroute
= dobj
->private;
2340 /* free sroute and its private data */
2341 kfree(sroute
->private);
2342 list_del(&sroute
->list
);
2348 static int sof_widget_unload(struct snd_soc_component
*scomp
,
2349 struct snd_soc_dobj
*dobj
)
2351 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2352 const struct snd_kcontrol_new
*kc
;
2353 struct snd_soc_dapm_widget
*widget
;
2354 struct sof_ipc_pipe_new
*pipeline
;
2355 struct snd_sof_control
*scontrol
;
2356 struct snd_sof_widget
*swidget
;
2357 struct soc_mixer_control
*sm
;
2358 struct soc_bytes_ext
*sbe
;
2359 struct snd_sof_dai
*dai
;
2360 struct soc_enum
*se
;
2364 swidget
= dobj
->private;
2368 widget
= swidget
->widget
;
2370 switch (swidget
->id
) {
2371 case snd_soc_dapm_dai_in
:
2372 case snd_soc_dapm_dai_out
:
2373 dai
= swidget
->private;
2376 /* free dai config */
2377 kfree(dai
->dai_config
);
2378 list_del(&dai
->list
);
2381 case snd_soc_dapm_scheduler
:
2383 /* power down the pipeline schedule core */
2384 pipeline
= swidget
->private;
2385 ret
= snd_sof_dsp_core_power_down(sdev
, 1 << pipeline
->core
);
2387 dev_err(scomp
->dev
, "error: powering down pipeline schedule core %d\n",
2390 /* update enabled cores mask */
2391 sdev
->enabled_cores_mask
&= ~(1 << pipeline
->core
);
2397 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2398 kc
= &widget
->kcontrol_news
[i
];
2399 switch (dobj
->widget
.kcontrol_type
) {
2400 case SND_SOC_TPLG_TYPE_MIXER
:
2401 sm
= (struct soc_mixer_control
*)kc
->private_value
;
2402 scontrol
= sm
->dobj
.private;
2404 kfree(scontrol
->volume_table
);
2406 case SND_SOC_TPLG_TYPE_ENUM
:
2407 se
= (struct soc_enum
*)kc
->private_value
;
2408 scontrol
= se
->dobj
.private;
2410 case SND_SOC_TPLG_TYPE_BYTES
:
2411 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
2412 scontrol
= sbe
->dobj
.private;
2415 dev_warn(scomp
->dev
, "unsupported kcontrol_type\n");
2418 kfree(scontrol
->control_data
);
2419 list_del(&scontrol
->list
);
2424 /* free private value */
2425 kfree(swidget
->private);
2427 /* remove and free swidget object */
2428 list_del(&swidget
->list
);
2435 * DAI HW configuration.
2438 /* FE DAI - used for any driver specific init */
2439 static int sof_dai_load(struct snd_soc_component
*scomp
, int index
,
2440 struct snd_soc_dai_driver
*dai_drv
,
2441 struct snd_soc_tplg_pcm
*pcm
, struct snd_soc_dai
*dai
)
2443 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2444 struct snd_soc_tplg_stream_caps
*caps
;
2445 struct snd_soc_tplg_private
*private = &pcm
->priv
;
2446 struct snd_sof_pcm
*spcm
;
2447 int stream
= SNDRV_PCM_STREAM_PLAYBACK
;
2450 /* nothing to do for BEs atm */
2454 spcm
= kzalloc(sizeof(*spcm
), GFP_KERNEL
);
2458 spcm
->scomp
= scomp
;
2459 spcm
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].comp_id
= COMP_ID_UNASSIGNED
;
2460 spcm
->stream
[SNDRV_PCM_STREAM_CAPTURE
].comp_id
= COMP_ID_UNASSIGNED
;
2463 dev_dbg(scomp
->dev
, "tplg: load pcm %s\n", pcm
->dai_name
);
2465 dai_drv
->dobj
.private = spcm
;
2466 list_add(&spcm
->list
, &sdev
->pcm_list
);
2468 ret
= sof_parse_tokens(scomp
, spcm
, stream_tokens
,
2469 ARRAY_SIZE(stream_tokens
), private->array
,
2470 le32_to_cpu(private->size
));
2472 dev_err(scomp
->dev
, "error: parse stream tokens failed %d\n",
2473 le32_to_cpu(private->size
));
2477 /* do we need to allocate playback PCM DMA pages */
2478 if (!spcm
->pcm
.playback
)
2481 dev_vdbg(scomp
->dev
, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
2482 spcm
->pcm
.pcm_name
, spcm
->stream
[0].d0i3_compatible
);
2484 caps
= &spcm
->pcm
.caps
[stream
];
2486 /* allocate playback page table buffer */
2487 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, sdev
->dev
,
2488 PAGE_SIZE
, &spcm
->stream
[stream
].page_table
);
2490 dev_err(scomp
->dev
, "error: can't alloc page table for %s %d\n",
2496 /* bind pcm to host comp */
2497 ret
= spcm_bind(scomp
, spcm
, stream
);
2500 "error: can't bind pcm to host\n");
2501 goto free_playback_tables
;
2505 stream
= SNDRV_PCM_STREAM_CAPTURE
;
2507 /* do we need to allocate capture PCM DMA pages */
2508 if (!spcm
->pcm
.capture
)
2511 dev_vdbg(scomp
->dev
, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
2512 spcm
->pcm
.pcm_name
, spcm
->stream
[1].d0i3_compatible
);
2514 caps
= &spcm
->pcm
.caps
[stream
];
2516 /* allocate capture page table buffer */
2517 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, sdev
->dev
,
2518 PAGE_SIZE
, &spcm
->stream
[stream
].page_table
);
2520 dev_err(scomp
->dev
, "error: can't alloc page table for %s %d\n",
2522 goto free_playback_tables
;
2525 /* bind pcm to host comp */
2526 ret
= spcm_bind(scomp
, spcm
, stream
);
2529 "error: can't bind pcm to host\n");
2530 snd_dma_free_pages(&spcm
->stream
[stream
].page_table
);
2531 goto free_playback_tables
;
2536 free_playback_tables
:
2537 if (spcm
->pcm
.playback
)
2538 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].page_table
);
2543 static int sof_dai_unload(struct snd_soc_component
*scomp
,
2544 struct snd_soc_dobj
*dobj
)
2546 struct snd_sof_pcm
*spcm
= dobj
->private;
2548 /* free PCM DMA pages */
2549 if (spcm
->pcm
.playback
)
2550 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].page_table
);
2552 if (spcm
->pcm
.capture
)
2553 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_CAPTURE
].page_table
);
2555 /* remove from list and free spcm */
2556 list_del(&spcm
->list
);
2562 static void sof_dai_set_format(struct snd_soc_tplg_hw_config
*hw_config
,
2563 struct sof_ipc_dai_config
*config
)
2565 /* clock directions wrt codec */
2566 if (hw_config
->bclk_master
== SND_SOC_TPLG_BCLK_CM
) {
2567 /* codec is bclk master */
2568 if (hw_config
->fsync_master
== SND_SOC_TPLG_FSYNC_CM
)
2569 config
->format
|= SOF_DAI_FMT_CBM_CFM
;
2571 config
->format
|= SOF_DAI_FMT_CBM_CFS
;
2573 /* codec is bclk slave */
2574 if (hw_config
->fsync_master
== SND_SOC_TPLG_FSYNC_CM
)
2575 config
->format
|= SOF_DAI_FMT_CBS_CFM
;
2577 config
->format
|= SOF_DAI_FMT_CBS_CFS
;
2580 /* inverted clocks ? */
2581 if (hw_config
->invert_bclk
) {
2582 if (hw_config
->invert_fsync
)
2583 config
->format
|= SOF_DAI_FMT_IB_IF
;
2585 config
->format
|= SOF_DAI_FMT_IB_NF
;
2587 if (hw_config
->invert_fsync
)
2588 config
->format
|= SOF_DAI_FMT_NB_IF
;
2590 config
->format
|= SOF_DAI_FMT_NB_NF
;
2594 /* set config for all DAI's with name matching the link name */
2595 static int sof_set_dai_config(struct snd_sof_dev
*sdev
, u32 size
,
2596 struct snd_soc_dai_link
*link
,
2597 struct sof_ipc_dai_config
*config
)
2599 struct snd_sof_dai
*dai
;
2602 list_for_each_entry(dai
, &sdev
->dai_list
, list
) {
2606 if (strcmp(link
->name
, dai
->name
) == 0) {
2607 dai
->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
2608 if (!dai
->dai_config
)
2611 /* set cpu_dai_name */
2612 dai
->cpu_dai_name
= link
->cpus
->dai_name
;
2619 * machine driver may define a dai link with playback and capture
2620 * dai enabled, but the dai link in topology would support both, one
2621 * or none of them. Here print a warning message to notify user
2624 dev_warn(sdev
->dev
, "warning: failed to find dai for dai link %s",
2631 static int sof_link_ssp_load(struct snd_soc_component
*scomp
, int index
,
2632 struct snd_soc_dai_link
*link
,
2633 struct snd_soc_tplg_link_config
*cfg
,
2634 struct snd_soc_tplg_hw_config
*hw_config
,
2635 struct sof_ipc_dai_config
*config
)
2637 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2638 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2639 struct sof_ipc_reply reply
;
2640 u32 size
= sizeof(*config
);
2643 /* handle master/slave and inverted clocks */
2644 sof_dai_set_format(hw_config
, config
);
2647 memset(&config
->ssp
, 0, sizeof(struct sof_ipc_dai_ssp_params
));
2648 config
->hdr
.size
= size
;
2650 ret
= sof_parse_tokens(scomp
, &config
->ssp
, ssp_tokens
,
2651 ARRAY_SIZE(ssp_tokens
), private->array
,
2652 le32_to_cpu(private->size
));
2654 dev_err(scomp
->dev
, "error: parse ssp tokens failed %d\n",
2655 le32_to_cpu(private->size
));
2659 config
->ssp
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
2660 config
->ssp
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
2661 config
->ssp
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
2662 config
->ssp
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
2663 config
->ssp
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
2664 config
->ssp
.mclk_direction
= hw_config
->mclk_direction
;
2665 config
->ssp
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
2666 config
->ssp
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
2668 dev_dbg(scomp
->dev
, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
2669 config
->dai_index
, config
->format
,
2670 config
->ssp
.mclk_rate
, config
->ssp
.bclk_rate
,
2671 config
->ssp
.fsync_rate
, config
->ssp
.sample_valid_bits
,
2672 config
->ssp
.tdm_slot_width
, config
->ssp
.tdm_slots
,
2673 config
->ssp
.mclk_id
, config
->ssp
.quirks
);
2675 /* validate SSP fsync rate and channel count */
2676 if (config
->ssp
.fsync_rate
< 8000 || config
->ssp
.fsync_rate
> 192000) {
2677 dev_err(scomp
->dev
, "error: invalid fsync rate for SSP%d\n",
2682 if (config
->ssp
.tdm_slots
< 1 || config
->ssp
.tdm_slots
> 8) {
2683 dev_err(scomp
->dev
, "error: invalid channel count for SSP%d\n",
2688 /* send message to DSP */
2689 ret
= sof_ipc_tx_message(sdev
->ipc
,
2690 config
->hdr
.cmd
, config
, size
, &reply
,
2694 dev_err(scomp
->dev
, "error: failed to set DAI config for SSP%d\n",
2699 /* set config for all DAI's with name matching the link name */
2700 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
2702 dev_err(scomp
->dev
, "error: failed to save DAI config for SSP%d\n",
2708 static int sof_link_sai_load(struct snd_soc_component
*scomp
, int index
,
2709 struct snd_soc_dai_link
*link
,
2710 struct snd_soc_tplg_link_config
*cfg
,
2711 struct snd_soc_tplg_hw_config
*hw_config
,
2712 struct sof_ipc_dai_config
*config
)
2714 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2715 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2716 struct sof_ipc_reply reply
;
2717 u32 size
= sizeof(*config
);
2720 /* handle master/slave and inverted clocks */
2721 sof_dai_set_format(hw_config
, config
);
2724 memset(&config
->sai
, 0, sizeof(struct sof_ipc_dai_sai_params
));
2725 config
->hdr
.size
= size
;
2727 ret
= sof_parse_tokens(scomp
, &config
->sai
, sai_tokens
,
2728 ARRAY_SIZE(sai_tokens
), private->array
,
2729 le32_to_cpu(private->size
));
2731 dev_err(scomp
->dev
, "error: parse sai tokens failed %d\n",
2732 le32_to_cpu(private->size
));
2736 config
->sai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
2737 config
->sai
.mclk_direction
= hw_config
->mclk_direction
;
2739 config
->sai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
2740 config
->sai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
2741 config
->sai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
2742 config
->sai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
2744 dev_info(scomp
->dev
,
2745 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
2746 config
->dai_index
, config
->format
,
2747 config
->sai
.mclk_rate
, config
->sai
.tdm_slot_width
,
2748 config
->sai
.tdm_slots
, config
->sai
.mclk_id
);
2750 if (config
->sai
.tdm_slots
< 1 || config
->sai
.tdm_slots
> 8) {
2751 dev_err(scomp
->dev
, "error: invalid channel count for SAI%d\n",
2756 /* send message to DSP */
2757 ret
= sof_ipc_tx_message(sdev
->ipc
,
2758 config
->hdr
.cmd
, config
, size
, &reply
,
2762 dev_err(scomp
->dev
, "error: failed to set DAI config for SAI%d\n",
2767 /* set config for all DAI's with name matching the link name */
2768 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
2770 dev_err(scomp
->dev
, "error: failed to save DAI config for SAI%d\n",
2776 static int sof_link_esai_load(struct snd_soc_component
*scomp
, int index
,
2777 struct snd_soc_dai_link
*link
,
2778 struct snd_soc_tplg_link_config
*cfg
,
2779 struct snd_soc_tplg_hw_config
*hw_config
,
2780 struct sof_ipc_dai_config
*config
)
2782 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2783 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2784 struct sof_ipc_reply reply
;
2785 u32 size
= sizeof(*config
);
2788 /* handle master/slave and inverted clocks */
2789 sof_dai_set_format(hw_config
, config
);
2792 memset(&config
->esai
, 0, sizeof(struct sof_ipc_dai_esai_params
));
2793 config
->hdr
.size
= size
;
2795 ret
= sof_parse_tokens(scomp
, &config
->esai
, esai_tokens
,
2796 ARRAY_SIZE(esai_tokens
), private->array
,
2797 le32_to_cpu(private->size
));
2799 dev_err(scomp
->dev
, "error: parse esai tokens failed %d\n",
2800 le32_to_cpu(private->size
));
2804 config
->esai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
2805 config
->esai
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
2806 config
->esai
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
2807 config
->esai
.mclk_direction
= hw_config
->mclk_direction
;
2808 config
->esai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
2809 config
->esai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
2810 config
->esai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
2811 config
->esai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
2813 dev_info(scomp
->dev
,
2814 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
2815 config
->dai_index
, config
->format
,
2816 config
->esai
.mclk_rate
, config
->esai
.tdm_slot_width
,
2817 config
->esai
.tdm_slots
, config
->esai
.mclk_id
);
2819 if (config
->esai
.tdm_slots
< 1 || config
->esai
.tdm_slots
> 8) {
2820 dev_err(scomp
->dev
, "error: invalid channel count for ESAI%d\n",
2825 /* send message to DSP */
2826 ret
= sof_ipc_tx_message(sdev
->ipc
,
2827 config
->hdr
.cmd
, config
, size
, &reply
,
2830 dev_err(scomp
->dev
, "error: failed to set DAI config for ESAI%d\n",
2835 /* set config for all DAI's with name matching the link name */
2836 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
2838 dev_err(scomp
->dev
, "error: failed to save DAI config for ESAI%d\n",
2844 static int sof_link_dmic_load(struct snd_soc_component
*scomp
, int index
,
2845 struct snd_soc_dai_link
*link
,
2846 struct snd_soc_tplg_link_config
*cfg
,
2847 struct snd_soc_tplg_hw_config
*hw_config
,
2848 struct sof_ipc_dai_config
*config
)
2850 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2851 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2852 struct sof_ipc_dai_config
*ipc_config
;
2853 struct sof_ipc_reply reply
;
2854 struct sof_ipc_fw_ready
*ready
= &sdev
->fw_ready
;
2855 struct sof_ipc_fw_version
*v
= &ready
->version
;
2860 * config is only used for the common params in dmic_params structure
2861 * that does not include the PDM controller config array
2862 * Set the common params to 0.
2864 memset(&config
->dmic
, 0, sizeof(struct sof_ipc_dai_dmic_params
));
2866 /* get DMIC tokens */
2867 ret
= sof_parse_tokens(scomp
, &config
->dmic
, dmic_tokens
,
2868 ARRAY_SIZE(dmic_tokens
), private->array
,
2869 le32_to_cpu(private->size
));
2871 dev_err(scomp
->dev
, "error: parse dmic tokens failed %d\n",
2872 le32_to_cpu(private->size
));
2877 * allocate memory for dmic dai config accounting for the
2878 * variable number of active pdm controllers
2879 * This will be the ipc payload for setting dai config
2881 size
= sizeof(*config
) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl
) *
2882 config
->dmic
.num_pdm_active
;
2884 ipc_config
= kzalloc(size
, GFP_KERNEL
);
2888 /* copy the common dai config and dmic params */
2889 memcpy(ipc_config
, config
, sizeof(*config
));
2892 * alloc memory for private member
2893 * Used to track the pdm config array index currently being parsed
2895 sdev
->private = kzalloc(sizeof(u32
), GFP_KERNEL
);
2896 if (!sdev
->private) {
2901 /* get DMIC PDM tokens */
2902 ret
= sof_parse_tokens(scomp
, &ipc_config
->dmic
.pdm
[0], dmic_pdm_tokens
,
2903 ARRAY_SIZE(dmic_pdm_tokens
), private->array
,
2904 le32_to_cpu(private->size
));
2906 dev_err(scomp
->dev
, "error: parse dmic pdm tokens failed %d\n",
2907 le32_to_cpu(private->size
));
2911 /* set IPC header size */
2912 ipc_config
->hdr
.size
= size
;
2914 /* debug messages */
2915 dev_dbg(scomp
->dev
, "tplg: config DMIC%d driver version %d\n",
2916 ipc_config
->dai_index
, ipc_config
->dmic
.driver_ipc_version
);
2917 dev_dbg(scomp
->dev
, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
2918 ipc_config
->dmic
.pdmclk_min
, ipc_config
->dmic
.pdmclk_max
,
2919 ipc_config
->dmic
.duty_min
);
2920 dev_dbg(scomp
->dev
, "duty_max %hd fifo_fs %d num_pdms active %d\n",
2921 ipc_config
->dmic
.duty_max
, ipc_config
->dmic
.fifo_fs
,
2922 ipc_config
->dmic
.num_pdm_active
);
2923 dev_dbg(scomp
->dev
, "fifo word length %hd\n",
2924 ipc_config
->dmic
.fifo_bits
);
2926 for (j
= 0; j
< ipc_config
->dmic
.num_pdm_active
; j
++) {
2927 dev_dbg(scomp
->dev
, "pdm %hd mic a %hd mic b %hd\n",
2928 ipc_config
->dmic
.pdm
[j
].id
,
2929 ipc_config
->dmic
.pdm
[j
].enable_mic_a
,
2930 ipc_config
->dmic
.pdm
[j
].enable_mic_b
);
2931 dev_dbg(scomp
->dev
, "pdm %hd polarity a %hd polarity b %hd\n",
2932 ipc_config
->dmic
.pdm
[j
].id
,
2933 ipc_config
->dmic
.pdm
[j
].polarity_mic_a
,
2934 ipc_config
->dmic
.pdm
[j
].polarity_mic_b
);
2935 dev_dbg(scomp
->dev
, "pdm %hd clk_edge %hd skew %hd\n",
2936 ipc_config
->dmic
.pdm
[j
].id
,
2937 ipc_config
->dmic
.pdm
[j
].clk_edge
,
2938 ipc_config
->dmic
.pdm
[j
].skew
);
2941 if (SOF_ABI_VER(v
->major
, v
->minor
, v
->micro
) < SOF_ABI_VER(3, 0, 1)) {
2942 /* this takes care of backwards compatible handling of fifo_bits_b */
2943 ipc_config
->dmic
.reserved_2
= ipc_config
->dmic
.fifo_bits
;
2946 /* send message to DSP */
2947 ret
= sof_ipc_tx_message(sdev
->ipc
,
2948 ipc_config
->hdr
.cmd
, ipc_config
, size
, &reply
,
2953 "error: failed to set DAI config for DMIC%d\n",
2958 /* set config for all DAI's with name matching the link name */
2959 ret
= sof_set_dai_config(sdev
, size
, link
, ipc_config
);
2961 dev_err(scomp
->dev
, "error: failed to save DAI config for DMIC%d\n",
2965 kfree(sdev
->private);
2972 * for hda link, playback and capture are supported by different dai
2973 * in FW. Here get the dai_index, set dma channel of each dai
2974 * and send config to FW. In FW, each dai sets config by dai_index
2976 static int sof_link_hda_process(struct snd_sof_dev
*sdev
,
2977 struct snd_soc_dai_link
*link
,
2978 struct sof_ipc_dai_config
*config
)
2980 struct sof_ipc_reply reply
;
2981 u32 size
= sizeof(*config
);
2982 struct snd_sof_dai
*sof_dai
;
2986 list_for_each_entry(sof_dai
, &sdev
->dai_list
, list
) {
2990 if (strcmp(link
->name
, sof_dai
->name
) == 0) {
2991 config
->dai_index
= sof_dai
->comp_dai
.dai_index
;
2994 config
->hda
.link_dma_ch
= DMA_CHAN_INVALID
;
2996 /* save config in dai component */
2997 sof_dai
->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
2998 if (!sof_dai
->dai_config
)
3001 sof_dai
->cpu_dai_name
= link
->cpus
->dai_name
;
3003 /* send message to DSP */
3004 ret
= sof_ipc_tx_message(sdev
->ipc
,
3005 config
->hdr
.cmd
, config
, size
,
3006 &reply
, sizeof(reply
));
3009 dev_err(sdev
->dev
, "error: failed to set DAI config for direction:%d of HDA dai %d\n",
3010 sof_dai
->comp_dai
.direction
,
3019 * machine driver may define a dai link with playback and capture
3020 * dai enabled, but the dai link in topology would support both, one
3021 * or none of them. Here print a warning message to notify user
3024 dev_warn(sdev
->dev
, "warning: failed to find dai for dai link %s",
3031 static int sof_link_hda_load(struct snd_soc_component
*scomp
, int index
,
3032 struct snd_soc_dai_link
*link
,
3033 struct snd_soc_tplg_link_config
*cfg
,
3034 struct snd_soc_tplg_hw_config
*hw_config
,
3035 struct sof_ipc_dai_config
*config
)
3037 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3038 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3039 struct snd_soc_dai
*dai
;
3040 u32 size
= sizeof(*config
);
3044 memset(&config
->hda
, 0, sizeof(struct sof_ipc_dai_hda_params
));
3045 config
->hdr
.size
= size
;
3047 /* get any bespoke DAI tokens */
3048 ret
= sof_parse_tokens(scomp
, config
, hda_tokens
,
3049 ARRAY_SIZE(hda_tokens
), private->array
,
3050 le32_to_cpu(private->size
));
3052 dev_err(scomp
->dev
, "error: parse hda tokens failed %d\n",
3053 le32_to_cpu(private->size
));
3057 dai
= snd_soc_find_dai(link
->cpus
);
3059 dev_err(scomp
->dev
, "error: failed to find dai %s in %s",
3060 link
->cpus
->dai_name
, __func__
);
3064 ret
= sof_link_hda_process(sdev
, link
, config
);
3066 dev_err(scomp
->dev
, "error: failed to process hda dai link %s",
3072 static int sof_link_alh_load(struct snd_soc_component
*scomp
, int index
,
3073 struct snd_soc_dai_link
*link
,
3074 struct snd_soc_tplg_link_config
*cfg
,
3075 struct snd_soc_tplg_hw_config
*hw_config
,
3076 struct sof_ipc_dai_config
*config
)
3078 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3079 struct sof_ipc_reply reply
;
3080 u32 size
= sizeof(*config
);
3084 config
->hdr
.size
= size
;
3086 /* send message to DSP */
3087 ret
= sof_ipc_tx_message(sdev
->ipc
,
3088 config
->hdr
.cmd
, config
, size
, &reply
,
3092 dev_err(scomp
->dev
, "error: failed to set DAI config for ALH %d\n",
3097 /* set config for all DAI's with name matching the link name */
3098 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
3100 dev_err(scomp
->dev
, "error: failed to save DAI config for ALH %d\n",
3106 /* DAI link - used for any driver specific init */
3107 static int sof_link_load(struct snd_soc_component
*scomp
, int index
,
3108 struct snd_soc_dai_link
*link
,
3109 struct snd_soc_tplg_link_config
*cfg
)
3111 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3112 struct sof_ipc_dai_config config
;
3113 struct snd_soc_tplg_hw_config
*hw_config
;
3118 if (!link
->platforms
) {
3119 dev_err(scomp
->dev
, "error: no platforms\n");
3122 link
->platforms
->name
= dev_name(scomp
->dev
);
3125 * Set nonatomic property for FE dai links as their trigger action
3128 if (!link
->no_pcm
) {
3129 link
->nonatomic
= true;
3131 /* set trigger order */
3132 link
->trigger
[0] = SND_SOC_DPCM_TRIGGER_POST
;
3133 link
->trigger
[1] = SND_SOC_DPCM_TRIGGER_POST
;
3135 /* nothing more to do for FE dai links */
3139 /* check we have some tokens - we need at least DAI type */
3140 if (le32_to_cpu(private->size
) == 0) {
3141 dev_err(scomp
->dev
, "error: expected tokens for DAI, none found\n");
3145 /* Send BE DAI link configurations to DSP */
3146 memset(&config
, 0, sizeof(config
));
3148 /* get any common DAI tokens */
3149 ret
= sof_parse_tokens(scomp
, &config
, dai_link_tokens
,
3150 ARRAY_SIZE(dai_link_tokens
), private->array
,
3151 le32_to_cpu(private->size
));
3153 dev_err(scomp
->dev
, "error: parse link tokens failed %d\n",
3154 le32_to_cpu(private->size
));
3159 * DAI links are expected to have at least 1 hw_config.
3160 * But some older topologies might have no hw_config for HDA dai links.
3162 num_hw_configs
= le32_to_cpu(cfg
->num_hw_configs
);
3163 if (!num_hw_configs
) {
3164 if (config
.type
!= SOF_DAI_INTEL_HDA
) {
3165 dev_err(scomp
->dev
, "error: unexpected DAI config count %d!\n",
3166 le32_to_cpu(cfg
->num_hw_configs
));
3170 dev_dbg(scomp
->dev
, "tplg: %d hw_configs found, default id: %d!\n",
3171 cfg
->num_hw_configs
, le32_to_cpu(cfg
->default_hw_config_id
));
3173 for (i
= 0; i
< num_hw_configs
; i
++) {
3174 if (cfg
->hw_config
[i
].id
== cfg
->default_hw_config_id
)
3178 if (i
== num_hw_configs
) {
3179 dev_err(scomp
->dev
, "error: default hw_config id: %d not found!\n",
3180 le32_to_cpu(cfg
->default_hw_config_id
));
3185 /* configure dai IPC message */
3186 hw_config
= &cfg
->hw_config
[i
];
3188 config
.hdr
.cmd
= SOF_IPC_GLB_DAI_MSG
| SOF_IPC_DAI_CONFIG
;
3189 config
.format
= le32_to_cpu(hw_config
->fmt
);
3191 /* now load DAI specific data and send IPC - type comes from token */
3192 switch (config
.type
) {
3193 case SOF_DAI_INTEL_SSP
:
3194 ret
= sof_link_ssp_load(scomp
, index
, link
, cfg
, hw_config
,
3197 case SOF_DAI_INTEL_DMIC
:
3198 ret
= sof_link_dmic_load(scomp
, index
, link
, cfg
, hw_config
,
3201 case SOF_DAI_INTEL_HDA
:
3202 ret
= sof_link_hda_load(scomp
, index
, link
, cfg
, hw_config
,
3205 case SOF_DAI_INTEL_ALH
:
3206 ret
= sof_link_alh_load(scomp
, index
, link
, cfg
, hw_config
,
3209 case SOF_DAI_IMX_SAI
:
3210 ret
= sof_link_sai_load(scomp
, index
, link
, cfg
, hw_config
,
3213 case SOF_DAI_IMX_ESAI
:
3214 ret
= sof_link_esai_load(scomp
, index
, link
, cfg
, hw_config
,
3218 dev_err(scomp
->dev
, "error: invalid DAI type %d\n",
3229 static int sof_link_hda_unload(struct snd_sof_dev
*sdev
,
3230 struct snd_soc_dai_link
*link
)
3232 struct snd_soc_dai
*dai
;
3235 dai
= snd_soc_find_dai(link
->cpus
);
3237 dev_err(sdev
->dev
, "error: failed to find dai %s in %s",
3238 link
->cpus
->dai_name
, __func__
);
3245 static int sof_link_unload(struct snd_soc_component
*scomp
,
3246 struct snd_soc_dobj
*dobj
)
3248 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3249 struct snd_soc_dai_link
*link
=
3250 container_of(dobj
, struct snd_soc_dai_link
, dobj
);
3252 struct snd_sof_dai
*sof_dai
;
3255 /* only BE link is loaded by sof */
3259 list_for_each_entry(sof_dai
, &sdev
->dai_list
, list
) {
3263 if (strcmp(link
->name
, sof_dai
->name
) == 0)
3267 dev_err(scomp
->dev
, "error: failed to find dai %s in %s",
3268 link
->name
, __func__
);
3272 switch (sof_dai
->dai_config
->type
) {
3273 case SOF_DAI_INTEL_SSP
:
3274 case SOF_DAI_INTEL_DMIC
:
3275 case SOF_DAI_INTEL_ALH
:
3276 case SOF_DAI_IMX_SAI
:
3277 case SOF_DAI_IMX_ESAI
:
3278 /* no resource needs to be released for all cases above */
3280 case SOF_DAI_INTEL_HDA
:
3281 ret
= sof_link_hda_unload(sdev
, link
);
3284 dev_err(scomp
->dev
, "error: invalid DAI type %d\n",
3285 sof_dai
->dai_config
->type
);
3293 /* DAI link - used for any driver specific init */
3294 static int sof_route_load(struct snd_soc_component
*scomp
, int index
,
3295 struct snd_soc_dapm_route
*route
)
3297 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3298 struct sof_ipc_pipe_comp_connect
*connect
;
3299 struct snd_sof_widget
*source_swidget
, *sink_swidget
;
3300 struct snd_soc_dobj
*dobj
= &route
->dobj
;
3301 struct snd_sof_route
*sroute
;
3302 struct sof_ipc_reply reply
;
3305 /* allocate memory for sroute and connect */
3306 sroute
= kzalloc(sizeof(*sroute
), GFP_KERNEL
);
3310 sroute
->scomp
= scomp
;
3312 connect
= kzalloc(sizeof(*connect
), GFP_KERNEL
);
3318 connect
->hdr
.size
= sizeof(*connect
);
3319 connect
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_CONNECT
;
3321 dev_dbg(scomp
->dev
, "sink %s control %s source %s\n",
3322 route
->sink
, route
->control
? route
->control
: "none",
3325 /* source component */
3326 source_swidget
= snd_sof_find_swidget(scomp
, (char *)route
->source
);
3327 if (!source_swidget
) {
3328 dev_err(scomp
->dev
, "error: source %s not found\n",
3335 * Virtual widgets of type output/out_drv may be added in topology
3336 * for compatibility. These are not handled by the FW.
3337 * So, don't send routes whose source/sink widget is of such types
3340 if (source_swidget
->id
== snd_soc_dapm_out_drv
||
3341 source_swidget
->id
== snd_soc_dapm_output
)
3344 connect
->source_id
= source_swidget
->comp_id
;
3346 /* sink component */
3347 sink_swidget
= snd_sof_find_swidget(scomp
, (char *)route
->sink
);
3348 if (!sink_swidget
) {
3349 dev_err(scomp
->dev
, "error: sink %s not found\n",
3356 * Don't send routes whose sink widget is of type
3357 * output or out_drv to the DSP
3359 if (sink_swidget
->id
== snd_soc_dapm_out_drv
||
3360 sink_swidget
->id
== snd_soc_dapm_output
)
3363 connect
->sink_id
= sink_swidget
->comp_id
;
3366 * For virtual routes, both sink and source are not
3367 * buffer. Since only buffer linked to component is supported by
3368 * FW, others are reported as error, add check in route function,
3369 * do not send it to FW when both source and sink are not buffer
3371 if (source_swidget
->id
!= snd_soc_dapm_buffer
&&
3372 sink_swidget
->id
!= snd_soc_dapm_buffer
) {
3373 dev_dbg(scomp
->dev
, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
3374 route
->source
, route
->sink
);
3378 ret
= sof_ipc_tx_message(sdev
->ipc
,
3380 connect
, sizeof(*connect
),
3381 &reply
, sizeof(reply
));
3383 /* check IPC return value */
3385 dev_err(scomp
->dev
, "error: failed to add route sink %s control %s source %s\n",
3387 route
->control
? route
->control
: "none",
3392 /* check IPC reply */
3393 if (reply
.error
< 0) {
3394 dev_err(scomp
->dev
, "error: DSP failed to add route sink %s control %s source %s result %d\n",
3396 route
->control
? route
->control
: "none",
3397 route
->source
, reply
.error
);
3402 sroute
->route
= route
;
3403 dobj
->private = sroute
;
3404 sroute
->private = connect
;
3406 /* add route to route list */
3407 list_add(&sroute
->list
, &sdev
->route_list
);
3418 /* Function to set the initial value of SOF kcontrols.
3419 * The value will be stored in scontrol->control_data
3421 static int snd_sof_cache_kcontrol_val(struct snd_soc_component
*scomp
)
3423 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3424 struct snd_sof_control
*scontrol
= NULL
;
3425 int ipc_cmd
, ctrl_type
;
3428 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
3430 /* notify DSP of kcontrol values */
3431 switch (scontrol
->cmd
) {
3432 case SOF_CTRL_CMD_VOLUME
:
3433 case SOF_CTRL_CMD_ENUM
:
3434 case SOF_CTRL_CMD_SWITCH
:
3435 ipc_cmd
= SOF_IPC_COMP_GET_VALUE
;
3436 ctrl_type
= SOF_CTRL_TYPE_VALUE_CHAN_GET
;
3438 case SOF_CTRL_CMD_BINARY
:
3439 ipc_cmd
= SOF_IPC_COMP_GET_DATA
;
3440 ctrl_type
= SOF_CTRL_TYPE_DATA_GET
;
3444 "error: Invalid scontrol->cmd: %d\n",
3448 ret
= snd_sof_ipc_set_get_comp_data(scontrol
,
3453 dev_warn(scomp
->dev
,
3454 "error: kcontrol value get for widget: %d\n",
3462 int snd_sof_complete_pipeline(struct device
*dev
,
3463 struct snd_sof_widget
*swidget
)
3465 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
3466 struct sof_ipc_pipe_ready ready
;
3467 struct sof_ipc_reply reply
;
3470 dev_dbg(dev
, "tplg: complete pipeline %s id %d\n",
3471 swidget
->widget
->name
, swidget
->comp_id
);
3473 memset(&ready
, 0, sizeof(ready
));
3474 ready
.hdr
.size
= sizeof(ready
);
3475 ready
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_COMPLETE
;
3476 ready
.comp_id
= swidget
->comp_id
;
3478 ret
= sof_ipc_tx_message(sdev
->ipc
,
3479 ready
.hdr
.cmd
, &ready
, sizeof(ready
), &reply
,
3486 /* completion - called at completion of firmware loading */
3487 static void sof_complete(struct snd_soc_component
*scomp
)
3489 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3490 struct snd_sof_widget
*swidget
;
3492 /* some widget types require completion notificattion */
3493 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
3494 if (swidget
->complete
)
3497 switch (swidget
->id
) {
3498 case snd_soc_dapm_scheduler
:
3500 snd_sof_complete_pipeline(scomp
->dev
, swidget
);
3507 * cache initial values of SOF kcontrols by reading DSP value over
3508 * IPC. It may be overwritten by alsa-mixer after booting up
3510 snd_sof_cache_kcontrol_val(scomp
);
3513 /* manifest - optional to inform component of manifest */
3514 static int sof_manifest(struct snd_soc_component
*scomp
, int index
,
3515 struct snd_soc_tplg_manifest
*man
)
3520 size
= le32_to_cpu(man
->priv
.size
);
3522 /* backward compatible with tplg without ABI info */
3524 dev_dbg(scomp
->dev
, "No topology ABI info\n");
3528 if (size
!= SOF_TPLG_ABI_SIZE
) {
3529 dev_err(scomp
->dev
, "error: invalid topology ABI size\n");
3533 dev_info(scomp
->dev
,
3534 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
3535 man
->priv
.data
[0], man
->priv
.data
[1],
3536 man
->priv
.data
[2], SOF_ABI_MAJOR
, SOF_ABI_MINOR
,
3539 abi_version
= SOF_ABI_VER(man
->priv
.data
[0],
3543 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
, abi_version
)) {
3544 dev_err(scomp
->dev
, "error: incompatible topology ABI version\n");
3548 if (abi_version
> SOF_ABI_VERSION
) {
3549 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS
)) {
3550 dev_warn(scomp
->dev
, "warn: topology ABI is more recent than kernel\n");
3552 dev_err(scomp
->dev
, "error: topology ABI is more recent than kernel\n");
3560 /* vendor specific kcontrol handlers available for binding */
3561 static const struct snd_soc_tplg_kcontrol_ops sof_io_ops
[] = {
3562 {SOF_TPLG_KCTL_VOL_ID
, snd_sof_volume_get
, snd_sof_volume_put
},
3563 {SOF_TPLG_KCTL_BYTES_ID
, snd_sof_bytes_get
, snd_sof_bytes_put
},
3564 {SOF_TPLG_KCTL_ENUM_ID
, snd_sof_enum_get
, snd_sof_enum_put
},
3565 {SOF_TPLG_KCTL_SWITCH_ID
, snd_sof_switch_get
, snd_sof_switch_put
},
3568 /* vendor specific bytes ext handlers available for binding */
3569 static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops
[] = {
3570 {SOF_TPLG_KCTL_BYTES_ID
, snd_sof_bytes_ext_get
, snd_sof_bytes_ext_put
},
3573 static struct snd_soc_tplg_ops sof_tplg_ops
= {
3574 /* external kcontrol init - used for any driver specific init */
3575 .control_load
= sof_control_load
,
3576 .control_unload
= sof_control_unload
,
3578 /* external kcontrol init - used for any driver specific init */
3579 .dapm_route_load
= sof_route_load
,
3580 .dapm_route_unload
= sof_route_unload
,
3582 /* external widget init - used for any driver specific init */
3583 /* .widget_load is not currently used */
3584 .widget_ready
= sof_widget_ready
,
3585 .widget_unload
= sof_widget_unload
,
3587 /* FE DAI - used for any driver specific init */
3588 .dai_load
= sof_dai_load
,
3589 .dai_unload
= sof_dai_unload
,
3591 /* DAI link - used for any driver specific init */
3592 .link_load
= sof_link_load
,
3593 .link_unload
= sof_link_unload
,
3595 /* completion - called at completion of firmware loading */
3596 .complete
= sof_complete
,
3598 /* manifest - optional to inform component of manifest */
3599 .manifest
= sof_manifest
,
3601 /* vendor specific kcontrol handlers available for binding */
3602 .io_ops
= sof_io_ops
,
3603 .io_ops_count
= ARRAY_SIZE(sof_io_ops
),
3605 /* vendor specific bytes ext handlers available for binding */
3606 .bytes_ext_ops
= sof_bytes_ext_ops
,
3607 .bytes_ext_ops_count
= ARRAY_SIZE(sof_bytes_ext_ops
),
3610 int snd_sof_load_topology(struct snd_soc_component
*scomp
, const char *file
)
3612 const struct firmware
*fw
;
3615 dev_dbg(scomp
->dev
, "loading topology:%s\n", file
);
3617 ret
= request_firmware(&fw
, file
, scomp
->dev
);
3619 dev_err(scomp
->dev
, "error: tplg request firmware %s failed err: %d\n",
3624 ret
= snd_soc_tplg_component_load(scomp
,
3626 SND_SOC_TPLG_INDEX_ALL
);
3628 dev_err(scomp
->dev
, "error: tplg component load failed %d\n",
3633 release_firmware(fw
);
3636 EXPORT_SYMBOL(snd_sof_load_topology
);