linux/sound/soc/sof/topology.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2//
   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.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//
  10
  11#include <linux/firmware.h>
  12#include <sound/tlv.h>
  13#include <sound/pcm_params.h>
  14#include <uapi/sound/sof/tokens.h>
  15#include "sof-priv.h"
  16#include "sof-audio.h"
  17#include "ops.h"
  18
  19#define COMP_ID_UNASSIGNED              0xffffffff
  20/*
  21 * Constants used in the computation of linear volume gain
  22 * from dB gain 20th root of 10 in Q1.16 fixed-point notation
  23 */
  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
  27/*
  28 * Volume fractional word length define to 16 sets
  29 * the volume linear gain value to use Qx.16 format
  30 */
  31#define VOLUME_FWL      16
  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)
  36
  37/* TLV data items */
  38#define TLV_ITEMS       3
  39#define TLV_MIN         0
  40#define TLV_STEP        1
  41#define TLV_MUTE        2
  42
  43/* size of tplg abi in byte */
  44#define SOF_TPLG_ABI_SIZE 3
  45
  46struct sof_widget_data {
  47        int ctrl_type;
  48        int ipc_cmd;
  49        struct sof_abi_hdr *pdata;
  50        struct snd_sof_control *control;
  51};
  52
  53/* send pcm params ipc */
  54static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
  55{
  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;
  62        int ret = 0;
  63
  64        memset(&pcm, 0, sizeof(pcm));
  65
  66        /* get runtime PCM params using widget's stream name */
  67        spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
  68        if (!spcm) {
  69                dev_err(scomp->dev, "error: cannot find PCM for %s\n",
  70                        swidget->widget->name);
  71                return -EINVAL;
  72        }
  73
  74        params = &spcm->params[dir];
  75
  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);
  87
  88        /* set format */
  89        switch (params_format(params)) {
  90        case SNDRV_PCM_FORMAT_S16:
  91                pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
  92                break;
  93        case SNDRV_PCM_FORMAT_S24:
  94                pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
  95                break;
  96        case SNDRV_PCM_FORMAT_S32:
  97                pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
  98                break;
  99        default:
 100                return -EINVAL;
 101        }
 102
 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));
 106        if (ret < 0)
 107                dev_err(scomp->dev, "error: pcm params failed for %s\n",
 108                        swidget->widget->name);
 109
 110        return ret;
 111}
 112
 113 /* send stream trigger ipc */
 114static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
 115{
 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;
 120        int ret = 0;
 121
 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;
 126
 127        /* send IPC to the DSP */
 128        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
 129                                 sizeof(stream), &reply, sizeof(reply));
 130        if (ret < 0)
 131                dev_err(scomp->dev, "error: failed to trigger %s\n",
 132                        swidget->widget->name);
 133
 134        return ret;
 135}
 136
 137static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
 138                                  struct snd_kcontrol *k, int event)
 139{
 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;
 144        int ret = 0;
 145
 146        if (!swidget)
 147                return 0;
 148
 149        scomp = swidget->scomp;
 150
 151        dev_dbg(scomp->dev, "received event %d for widget %s\n",
 152                event, w->name);
 153
 154        /* get runtime PCM params using widget's stream name */
 155        spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
 156        if (!spcm) {
 157                dev_err(scomp->dev, "error: cannot find PCM for %s\n",
 158                        swidget->widget->name);
 159                return -EINVAL;
 160        }
 161
 162        /* process events */
 163        switch (event) {
 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");
 167                        return 0;
 168                }
 169
 170                /* set pcm params */
 171                ret = ipc_pcm_params(swidget, stream);
 172                if (ret < 0) {
 173                        dev_err(scomp->dev,
 174                                "error: failed to set pcm params for widget %s\n",
 175                                swidget->widget->name);
 176                        break;
 177                }
 178
 179                /* start trigger */
 180                ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
 181                if (ret < 0)
 182                        dev_err(scomp->dev,
 183                                "error: failed to trigger widget %s\n",
 184                                swidget->widget->name);
 185                break;
 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");
 189                        return 0;
 190                }
 191
 192                /* stop trigger */
 193                ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
 194                if (ret < 0)
 195                        dev_err(scomp->dev,
 196                                "error: failed to trigger widget %s\n",
 197                                swidget->widget->name);
 198
 199                /* pcm free */
 200                ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
 201                if (ret < 0)
 202                        dev_err(scomp->dev,
 203                                "error: failed to trigger widget %s\n",
 204                                swidget->widget->name);
 205                break;
 206        default:
 207                break;
 208        }
 209
 210        return ret;
 211}
 212
 213/* event handlers for keyword detect component */
 214static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
 215        {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event},
 216};
 217
 218static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
 219{
 220        /* we only support dB scale TLV type at the moment */
 221        if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
 222                return -EINVAL;
 223
 224        /* min value in topology tlv data is multiplied by 100 */
 225        tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100;
 226
 227        /* volume steps */
 228        tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
 229                                TLV_DB_SCALE_MASK);
 230
 231        /* mute ON/OFF */
 232        if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
 233                TLV_DB_SCALE_MUTE) == 0)
 234                tlv[TLV_MUTE] = 0;
 235        else
 236                tlv[TLV_MUTE] = 1;
 237
 238        return 0;
 239}
 240
 241/*
 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
 245 */
 246static inline u32 vol_shift_64(u64 i, u32 x)
 247{
 248        /* do not truncate more than 32 bits */
 249        if (x > 32)
 250                x = 32;
 251
 252        if (x == 0)
 253                return (u32)i;
 254
 255        return (u32)(((i >> (x - 1)) + 1) >> 1);
 256}
 257
 258/*
 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"
 262 * exp is an integer
 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"
 266 */
 267static u32 vol_pow32(u32 a, int exp, u32 fwl)
 268{
 269        int i, iter;
 270        u32 power = 1 << fwl;
 271        u64 numerator;
 272
 273        /* if exponent is 0, return 1 */
 274        if (exp == 0)
 275                return power;
 276
 277        /* determine the number of iterations based on the exponent */
 278        if (exp < 0)
 279                iter = exp * -1;
 280        else
 281                iter = exp;
 282
 283        /* mutiply a "iter" times to compute power */
 284        for (i = 0; i < iter; i++) {
 285                /*
 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
 288                 */
 289                power = vol_shift_64((u64)power * a, fwl);
 290        }
 291
 292        if (exp > 0) {
 293                /* if exp is positive, return the result */
 294                return power;
 295        }
 296
 297        /* if exp is negative, return the multiplicative inverse */
 298        numerator = (u64)1 << (fwl << 1);
 299        do_div(numerator, power);
 300
 301        return (u32)numerator;
 302}
 303
 304/*
 305 * Function to calculate volume gain from TLV data.
 306 * This function can only handle gain steps that are multiples of 0.5 dB
 307 */
 308static u32 vol_compute_gain(u32 value, int *tlv)
 309{
 310        int dB_gain;
 311        u32 linear_gain;
 312        int f_step;
 313
 314        /* mute volume */
 315        if (value == 0 && tlv[TLV_MUTE])
 316                return 0;
 317
 318        /*
 319         * compute dB gain from tlv. tlv_step
 320         * in topology is multiplied by 100
 321         */
 322        dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100;
 323
 324        /*
 325         * compute linear gain represented by fixed-point
 326         * int with VOLUME_FWL fractional bits
 327         */
 328        linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL);
 329
 330        /* extract the fractional part of volume step */
 331        f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100);
 332
 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,
 337                                                  VOLUME_FWL);
 338
 339        return linear_gain;
 340}
 341
 342/*
 343 * Set up volume table for kcontrols from tlv data
 344 * "size" specifies the number of entries in the table
 345 */
 346static int set_up_volume_table(struct snd_sof_control *scontrol,
 347                               int tlv[TLV_ITEMS], int size)
 348{
 349        int j;
 350
 351        /* init the volume table */
 352        scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
 353        if (!scontrol->volume_table)
 354                return -ENOMEM;
 355
 356        /* populate the volume table */
 357        for (j = 0; j < size ; j++)
 358                scontrol->volume_table[j] = vol_compute_gain(j, tlv);
 359
 360        return 0;
 361}
 362
 363struct sof_dai_types {
 364        const char *name;
 365        enum sof_ipc_dai_type type;
 366};
 367
 368static 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},
 375};
 376
 377static enum sof_ipc_dai_type find_dai(const char *name)
 378{
 379        int i;
 380
 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;
 384        }
 385
 386        return SOF_DAI_INTEL_NONE;
 387}
 388
 389/*
 390 * Supported Frame format types and lookup, add new ones to end of list.
 391 */
 392
 393struct sof_frame_types {
 394        const char *name;
 395        enum sof_ipc_frame frame;
 396};
 397
 398static 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},
 403};
 404
 405static enum sof_ipc_frame find_format(const char *name)
 406{
 407        int i;
 408
 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;
 412        }
 413
 414        /* use s32le if nothing is specified */
 415        return SOF_IPC_FRAME_S32_LE;
 416}
 417
 418struct sof_process_types {
 419        const char *name;
 420        enum sof_ipc_process_type type;
 421        enum sof_comp_type comp_type;
 422};
 423
 424static 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},
 432};
 433
 434static enum sof_ipc_process_type find_process(const char *name)
 435{
 436        int i;
 437
 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;
 441        }
 442
 443        return SOF_PROCESS_NONE;
 444}
 445
 446static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
 447{
 448        int i;
 449
 450        for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
 451                if (sof_process[i].type == type)
 452                        return sof_process[i].comp_type;
 453        }
 454
 455        return SOF_COMP_NONE;
 456}
 457
 458/*
 459 * Topology Token Parsing.
 460 * New tokens should be added to headers and parsing tables below.
 461 */
 462
 463struct sof_topology_token {
 464        u32 token;
 465        u32 type;
 466        int (*get_token)(void *elem, void *object, u32 offset, u32 size);
 467        u32 offset;
 468        u32 size;
 469};
 470
 471static int get_token_u32(void *elem, void *object, u32 offset, u32 size)
 472{
 473        struct snd_soc_tplg_vendor_value_elem *velem = elem;
 474        u32 *val = (u32 *)((u8 *)object + offset);
 475
 476        *val = le32_to_cpu(velem->value);
 477        return 0;
 478}
 479
 480static int get_token_u16(void *elem, void *object, u32 offset, u32 size)
 481{
 482        struct snd_soc_tplg_vendor_value_elem *velem = elem;
 483        u16 *val = (u16 *)((u8 *)object + offset);
 484
 485        *val = (u16)le32_to_cpu(velem->value);
 486        return 0;
 487}
 488
 489static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size)
 490{
 491        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 492        u32 *val = (u32 *)((u8 *)object + offset);
 493
 494        *val = find_format(velem->string);
 495        return 0;
 496}
 497
 498static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size)
 499{
 500        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 501        u32 *val = (u32 *)((u8 *)object + offset);
 502
 503        *val = find_dai(velem->string);
 504        return 0;
 505}
 506
 507static int get_token_process_type(void *elem, void *object, u32 offset,
 508                                  u32 size)
 509{
 510        struct snd_soc_tplg_vendor_string_elem *velem = elem;
 511        u32 *val = (u32 *)((u8 *)object + offset);
 512
 513        *val = find_process(velem->string);
 514        return 0;
 515}
 516
 517/* Buffers */
 518static 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},
 523};
 524
 525/* DAI */
 526static 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},
 533};
 534
 535/* BE DAI link */
 536static 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},
 541};
 542
 543/* scheduling */
 544static 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},
 557};
 558
 559/* volume */
 560static 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},
 566};
 567
 568/* SRC */
 569static 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},
 574};
 575
 576/* ASRC */
 577static 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,
 583                get_token_u32,
 584                offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0},
 585        {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 586                get_token_u32,
 587                offsetof(struct sof_ipc_comp_asrc, operation_mode), 0},
 588};
 589
 590/* Tone */
 591static const struct sof_topology_token tone_tokens[] = {
 592};
 593
 594/* EFFECT */
 595static 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},
 599};
 600
 601/* PCM */
 602static 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},
 605};
 606
 607/* PCM */
 608static 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},
 615};
 616
 617/* Generic components */
 618static 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},
 628};
 629
 630/* SSP */
 631static 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,
 639                get_token_u32,
 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,
 642                get_token_u16,
 643                offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width), 0},
 644        {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 645                get_token_u32,
 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,
 648                get_token_u16,
 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,
 652                get_token_u32,
 653                offsetof(struct sof_ipc_dai_ssp_params, bclk_delay), 0},
 654
 655};
 656
 657/* DMIC */
 658static 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),
 662                0},
 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,
 681                         num_pdm_active), 0},
 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},
 688
 689};
 690
 691/* ESAI */
 692static 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},
 696};
 697
 698/* SAI */
 699static 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},
 703};
 704
 705/*
 706 * DMIC PDM Tokens
 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
 710 */
 711static 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),
 715                0},
 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),
 719                0},
 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),
 723                0},
 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),
 727                0},
 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),
 731                0},
 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),
 735                0},
 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),
 739                0},
 740};
 741
 742/* HDA */
 743static const struct sof_topology_token hda_tokens[] = {
 744};
 745
 746/* Leds */
 747static 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},
 752};
 753
 754static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
 755                                  void *object,
 756                                  const struct sof_topology_token *tokens,
 757                                  int count,
 758                                  struct snd_soc_tplg_vendor_array *array)
 759{
 760        struct snd_soc_tplg_vendor_uuid_elem *elem;
 761        int i, j;
 762
 763        /* parse element by element */
 764        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 765                elem = &array->uuid[i];
 766
 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)
 771                                continue;
 772
 773                        /* match token id */
 774                        if (tokens[j].token != le32_to_cpu(elem->token))
 775                                continue;
 776
 777                        /* matched - now load token */
 778                        tokens[j].get_token(elem, object, tokens[j].offset,
 779                                            tokens[j].size);
 780                }
 781        }
 782}
 783
 784static void sof_parse_string_tokens(struct snd_soc_component *scomp,
 785                                    void *object,
 786                                    const struct sof_topology_token *tokens,
 787                                    int count,
 788                                    struct snd_soc_tplg_vendor_array *array)
 789{
 790        struct snd_soc_tplg_vendor_string_elem *elem;
 791        int i, j;
 792
 793        /* parse element by element */
 794        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 795                elem = &array->string[i];
 796
 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)
 801                                continue;
 802
 803                        /* match token id */
 804                        if (tokens[j].token != le32_to_cpu(elem->token))
 805                                continue;
 806
 807                        /* matched - now load token */
 808                        tokens[j].get_token(elem, object, tokens[j].offset,
 809                                            tokens[j].size);
 810                }
 811        }
 812}
 813
 814static void sof_parse_word_tokens(struct snd_soc_component *scomp,
 815                                  void *object,
 816                                  const struct sof_topology_token *tokens,
 817                                  int count,
 818                                  struct snd_soc_tplg_vendor_array *array)
 819{
 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);
 823        int i, j;
 824        u32 offset;
 825        u32 *index = NULL;
 826
 827        /* parse element by element */
 828        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
 829                elem = &array->value[i];
 830
 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))
 838                                continue;
 839
 840                        /* match token id */
 841                        if (tokens[j].token != le32_to_cpu(elem->token))
 842                                continue;
 843
 844                        /* pdm config array index */
 845                        if (sdev->private)
 846                                index = sdev->private;
 847
 848                        /* matched - determine offset */
 849                        switch (tokens[j].token) {
 850                        case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID:
 851
 852                                /* inc number of pdm array index */
 853                                if (index)
 854                                        (*index)++;
 855                                /* fallthrough */
 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:
 862
 863                                /* check if array index is valid */
 864                                if (!index || *index == 0) {
 865                                        dev_err(scomp->dev,
 866                                                "error: invalid array offset\n");
 867                                        continue;
 868                                } else {
 869                                        /* offset within the pdm config array */
 870                                        offset = size * (*index - 1);
 871                                }
 872                                break;
 873                        default:
 874                                offset = 0;
 875                                break;
 876                        }
 877
 878                        /* load token */
 879                        tokens[j].get_token(elem, object,
 880                                            offset + tokens[j].offset,
 881                                            tokens[j].size);
 882                }
 883        }
 884}
 885
 886static int sof_parse_tokens(struct snd_soc_component *scomp,
 887                            void *object,
 888                            const struct sof_topology_token *tokens,
 889                            int count,
 890                            struct snd_soc_tplg_vendor_array *array,
 891                            int priv_size)
 892{
 893        int asize;
 894
 895        while (priv_size > 0) {
 896                asize = le32_to_cpu(array->size);
 897
 898                /* validate asize */
 899                if (asize < 0) { /* FIXME: A zero-size array makes no sense */
 900                        dev_err(scomp->dev, "error: invalid array size 0x%x\n",
 901                                asize);
 902                        return -EINVAL;
 903                }
 904
 905                /* make sure there is enough data before parsing */
 906                priv_size -= asize;
 907                if (priv_size < 0) {
 908                        dev_err(scomp->dev, "error: invalid array size 0x%x\n",
 909                                asize);
 910                        return -EINVAL;
 911                }
 912
 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,
 917                                              array);
 918                        break;
 919                case SND_SOC_TPLG_TUPLE_TYPE_STRING:
 920                        sof_parse_string_tokens(scomp, object, tokens, count,
 921                                                array);
 922                        break;
 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,
 928                                              array);
 929                        break;
 930                default:
 931                        dev_err(scomp->dev, "error: unknown token type %d\n",
 932                                array->type);
 933                        return -EINVAL;
 934                }
 935
 936                /* next array */
 937                array = (struct snd_soc_tplg_vendor_array *)((u8 *)array
 938                        + asize);
 939        }
 940        return 0;
 941}
 942
 943static void sof_dbg_comp_config(struct snd_soc_component *scomp,
 944                                struct sof_ipc_comp_config *config)
 945{
 946        dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
 947                config->periods_sink, config->periods_source,
 948                config->frame_fmt);
 949}
 950
 951/*
 952 * Standard Kcontrols.
 953 */
 954
 955static 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)
 959{
 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;
 964        int tlv[TLV_ITEMS];
 965        unsigned int i;
 966        int ret = 0;
 967
 968        /* validate topology data */
 969        if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) {
 970                ret = -EINVAL;
 971                goto out;
 972        }
 973
 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) {
 979                ret = -ENOMEM;
 980                goto out;
 981        }
 982
 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);
 987
 988        /* set cmd for mixer control */
 989        if (le32_to_cpu(mc->max) == 1) {
 990                scontrol->cmd = SOF_CTRL_CMD_SWITCH;
 991                goto skip;
 992        }
 993
 994        scontrol->cmd = SOF_CTRL_CMD_VOLUME;
 995
 996        /* extract tlv data */
 997        if (get_tlv_data(kc->tlv.p, tlv) < 0) {
 998                dev_err(scomp->dev, "error: invalid TLV data\n");
 999                ret = -EINVAL;
1000                goto out_free;
1001        }
1002
1003        /* set up volume table */
1004        ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
1005        if (ret < 0) {
1006                dev_err(scomp->dev, "error: setting up volume table\n");
1007                goto out_free;
1008        }
1009
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;
1015        }
1016
1017skip:
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));
1022        if (ret != 0) {
1023                dev_err(scomp->dev, "error: parse led tokens failed %d\n",
1024                        le32_to_cpu(mc->priv.size));
1025                goto out_free_table;
1026        }
1027
1028        dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
1029                scontrol->comp_id, scontrol->num_channels);
1030
1031        return ret;
1032
1033out_free_table:
1034        if (le32_to_cpu(mc->max) > 1)
1035                kfree(scontrol->volume_table);
1036out_free:
1037        kfree(scontrol->control_data);
1038out:
1039        return ret;
1040}
1041
1042static 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)
1046{
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);
1050
1051        /* validate topology data */
1052        if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN)
1053                return -EINVAL;
1054
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)
1060                return -ENOMEM;
1061
1062        scontrol->comp_id = sdev->next_comp_id;
1063        scontrol->num_channels = le32_to_cpu(ec->num_channels);
1064
1065        scontrol->cmd = SOF_CTRL_CMD_ENUM;
1066
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);
1069
1070        return 0;
1071}
1072
1073static 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)
1077{
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;
1084        int ret = 0;
1085
1086        /* init the get/put bytes data */
1087        scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
1088                le32_to_cpu(control->priv.size);
1089
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);
1093                ret = -EINVAL;
1094                goto out;
1095        }
1096
1097        scontrol->control_data = kzalloc(max_size, GFP_KERNEL);
1098        cdata = scontrol->control_data;
1099        if (!scontrol->control_data) {
1100                ret = -ENOMEM;
1101                goto out;
1102        }
1103
1104        scontrol->comp_id = sdev->next_comp_id;
1105        scontrol->cmd = SOF_CTRL_CMD_BINARY;
1106
1107        dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
1108                scontrol->comp_id, scontrol->num_channels);
1109
1110        if (le32_to_cpu(control->priv.size) > 0) {
1111                memcpy(cdata->data, control->priv.data,
1112                       le32_to_cpu(control->priv.size));
1113
1114                if (cdata->data->magic != SOF_ABI_MAGIC) {
1115                        dev_err(scomp->dev, "error: Wrong ABI magic 0x%08x.\n",
1116                                cdata->data->magic);
1117                        ret = -EINVAL;
1118                        goto out_free;
1119                }
1120                if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION,
1121                                                 cdata->data->abi)) {
1122                        dev_err(scomp->dev,
1123                                "error: Incompatible ABI version 0x%08x.\n",
1124                                cdata->data->abi);
1125                        ret = -EINVAL;
1126                        goto out_free;
1127                }
1128                if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
1129                    le32_to_cpu(control->priv.size)) {
1130                        dev_err(scomp->dev,
1131                                "error: Conflict in bytes vs. priv size.\n");
1132                        ret = -EINVAL;
1133                        goto out_free;
1134                }
1135        }
1136
1137        return ret;
1138
1139out_free:
1140        kfree(scontrol->control_data);
1141out:
1142        return ret;
1143}
1144
1145/* external kcontrol init - used for any driver specific init */
1146static 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)
1149{
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;
1156        int ret = -EINVAL;
1157
1158        dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n",
1159                hdr->type, hdr->name);
1160
1161        scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1162        if (!scontrol)
1163                return -ENOMEM;
1164
1165        scontrol->scomp = scomp;
1166
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;
1172                dobj = &sm->dobj;
1173                ret = sof_control_load_volume(scomp, scontrol, kc, hdr);
1174                break;
1175        case SND_SOC_TPLG_CTL_BYTES:
1176                sbe = (struct soc_bytes_ext *)kc->private_value;
1177                dobj = &sbe->dobj;
1178                ret = sof_control_load_bytes(scomp, scontrol, kc, hdr);
1179                break;
1180        case SND_SOC_TPLG_CTL_ENUM:
1181        case SND_SOC_TPLG_CTL_ENUM_VALUE:
1182                se = (struct soc_enum *)kc->private_value;
1183                dobj = &se->dobj;
1184                ret = sof_control_load_enum(scomp, scontrol, kc, hdr);
1185                break;
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:
1193        default:
1194                dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1195                         hdr->ops.get, hdr->ops.put, hdr->ops.info);
1196                kfree(scontrol);
1197                return 0;
1198        }
1199
1200        if (ret < 0) {
1201                kfree(scontrol);
1202                return ret;
1203        }
1204
1205        dobj->private = scontrol;
1206        list_add(&scontrol->list, &sdev->kcontrol_list);
1207        return ret;
1208}
1209
1210static int sof_control_unload(struct snd_soc_component *scomp,
1211                              struct snd_soc_dobj *dobj)
1212{
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;
1216
1217        dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scomp->name);
1218
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;
1222
1223        kfree(scontrol->control_data);
1224        list_del(&scontrol->list);
1225        kfree(scontrol);
1226        /* send IPC to the DSP */
1227        return sof_ipc_tx_message(sdev->ipc,
1228                                  fcomp.hdr.cmd, &fcomp, sizeof(fcomp),
1229                                  NULL, 0);
1230}
1231
1232/*
1233 * DAI Topology
1234 */
1235
1236static 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)
1240{
1241        struct snd_soc_card *card = scomp->card;
1242        struct snd_soc_pcm_runtime *rtd;
1243
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);
1247
1248                if (!w->sname || !rtd->dai_link->stream_name)
1249                        continue;
1250
1251                /* does stream match DAI link ? */
1252                if (strcmp(w->sname, rtd->dai_link->stream_name))
1253                        continue;
1254
1255                switch (w->id) {
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);
1261                        break;
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);
1267                        break;
1268                default:
1269                        break;
1270                }
1271        }
1272
1273        /* check we have a connection */
1274        if (!dai->name) {
1275                dev_err(scomp->dev, "error: can't connect DAI %s stream %s\n",
1276                        w->name, w->sname);
1277                return -EINVAL;
1278        }
1279
1280        return 0;
1281}
1282
1283static 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)
1288{
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;
1292        int ret;
1293
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);
1302
1303        ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens,
1304                               ARRAY_SIZE(dai_tokens), private->array,
1305                               le32_to_cpu(private->size));
1306        if (ret != 0) {
1307                dev_err(scomp->dev, "error: parse dai tokens failed %d\n",
1308                        le32_to_cpu(private->size));
1309                return ret;
1310        }
1311
1312        ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens,
1313                               ARRAY_SIZE(comp_tokens), private->array,
1314                               le32_to_cpu(private->size));
1315        if (ret != 0) {
1316                dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n",
1317                        private->size);
1318                return ret;
1319        }
1320
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);
1324
1325        ret = sof_ipc_tx_message(sdev->ipc, comp_dai.comp.hdr.cmd,
1326                                 &comp_dai, sizeof(comp_dai), r, sizeof(*r));
1327
1328        if (ret == 0 && dai) {
1329                dai->scomp = scomp;
1330                memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai));
1331        }
1332
1333        return ret;
1334}
1335
1336/*
1337 * Buffer topology
1338 */
1339
1340static 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)
1344{
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;
1348        int ret;
1349
1350        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
1351        if (!buffer)
1352                return -ENOMEM;
1353
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;
1360
1361        ret = sof_parse_tokens(scomp, buffer, buffer_tokens,
1362                               ARRAY_SIZE(buffer_tokens), private->array,
1363                               le32_to_cpu(private->size));
1364        if (ret != 0) {
1365                dev_err(scomp->dev, "error: parse buffer tokens failed %d\n",
1366                        private->size);
1367                kfree(buffer);
1368                return ret;
1369        }
1370
1371        dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
1372                swidget->widget->name, buffer->size, buffer->caps);
1373
1374        swidget->private = buffer;
1375
1376        ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer,
1377                                 sizeof(*buffer), r, sizeof(*r));
1378        if (ret < 0) {
1379                dev_err(scomp->dev, "error: buffer %s load failed\n",
1380                        swidget->widget->name);
1381                kfree(buffer);
1382        }
1383
1384        return ret;
1385}
1386
1387/* bind PCM ID to host component ID */
1388static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
1389                     int dir)
1390{
1391        struct snd_sof_widget *host_widget;
1392
1393        host_widget = snd_sof_find_swidget_sname(scomp,
1394                                                 spcm->pcm.caps[dir].name,
1395                                                 dir);
1396        if (!host_widget) {
1397                dev_err(scomp->dev, "can't find host comp to bind pcm\n");
1398                return -EINVAL;
1399        }
1400
1401        spcm->stream[dir].comp_id = host_widget->comp_id;
1402
1403        return 0;
1404}
1405
1406/*
1407 * PCM Topology
1408 */
1409
1410static 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)
1415{
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;
1419        int ret;
1420
1421        host = kzalloc(sizeof(*host), GFP_KERNEL);
1422        if (!host)
1423                return -ENOMEM;
1424
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);
1433
1434        ret = sof_parse_tokens(scomp, host, pcm_tokens,
1435                               ARRAY_SIZE(pcm_tokens), private->array,
1436                               le32_to_cpu(private->size));
1437        if (ret != 0) {
1438                dev_err(scomp->dev, "error: parse host tokens failed %d\n",
1439                        private->size);
1440                goto err;
1441        }
1442
1443        ret = sof_parse_tokens(scomp, &host->config, comp_tokens,
1444                               ARRAY_SIZE(comp_tokens), private->array,
1445                               le32_to_cpu(private->size));
1446        if (ret != 0) {
1447                dev_err(scomp->dev, "error: parse host.cfg tokens failed %d\n",
1448                        le32_to_cpu(private->size));
1449                goto err;
1450        }
1451
1452        dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
1453        sof_dbg_comp_config(scomp, &host->config);
1454
1455        swidget->private = host;
1456
1457        ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host,
1458                                 sizeof(*host), r, sizeof(*r));
1459        if (ret >= 0)
1460                return ret;
1461err:
1462        kfree(host);
1463        return ret;
1464}
1465
1466/*
1467 * Pipeline Topology
1468 */
1469int sof_load_pipeline_ipc(struct device *dev,
1470                          struct sof_ipc_pipe_new *pipeline,
1471                          struct sof_ipc_comp_reply *r)
1472{
1473        struct snd_sof_dev *sdev = dev_get_drvdata(dev);
1474        struct sof_ipc_pm_core_config pm_core_config;
1475        int ret;
1476
1477        ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
1478                                 sizeof(*pipeline), r, sizeof(*r));
1479        if (ret < 0) {
1480                dev_err(dev, "error: load pipeline ipc failure\n");
1481                return ret;
1482        }
1483
1484        /* power up the core that this pipeline is scheduled on */
1485        ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core);
1486        if (ret < 0) {
1487                dev_err(dev, "error: powering up pipeline schedule core %d\n",
1488                        pipeline->core);
1489                return ret;
1490        }
1491
1492        /* update enabled cores mask */
1493        sdev->enabled_cores_mask |= 1 << pipeline->core;
1494
1495        /*
1496         * Now notify DSP that the core that this pipeline is scheduled on
1497         * has been powered up
1498         */
1499        memset(&pm_core_config, 0, sizeof(pm_core_config));
1500        pm_core_config.enable_mask = sdev->enabled_cores_mask;
1501
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;
1505
1506        /* send ipc */
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));
1510        if (ret < 0)
1511                dev_err(dev, "error: core enable ipc failure\n");
1512
1513        return ret;
1514}
1515
1516static 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)
1520{
1521        struct snd_soc_tplg_private *private = &tw->priv;
1522        struct sof_ipc_pipe_new *pipeline;
1523        struct snd_sof_widget *comp_swidget;
1524        int ret;
1525
1526        pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
1527        if (!pipeline)
1528                return -ENOMEM;
1529
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;
1535
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);
1541                ret = -EINVAL;
1542                goto err;
1543        }
1544
1545        pipeline->sched_id = comp_swidget->comp_id;
1546
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);
1549
1550        ret = sof_parse_tokens(scomp, pipeline, sched_tokens,
1551                               ARRAY_SIZE(sched_tokens), private->array,
1552                               le32_to_cpu(private->size));
1553        if (ret != 0) {
1554                dev_err(scomp->dev, "error: parse pipeline tokens failed %d\n",
1555                        private->size);
1556                goto err;
1557        }
1558
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);
1562
1563        swidget->private = pipeline;
1564
1565        /* send ipc's to create pipeline comp and power up schedule core */
1566        ret = sof_load_pipeline_ipc(scomp->dev, pipeline, r);
1567        if (ret >= 0)
1568                return ret;
1569err:
1570        kfree(pipeline);
1571        return ret;
1572}
1573
1574/*
1575 * Mixer topology
1576 */
1577
1578static 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)
1582{
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;
1586        int ret;
1587
1588        mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
1589        if (!mixer)
1590                return -ENOMEM;
1591
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);
1599
1600        ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens,
1601                               ARRAY_SIZE(comp_tokens), private->array,
1602                               le32_to_cpu(private->size));
1603        if (ret != 0) {
1604                dev_err(scomp->dev, "error: parse mixer.cfg tokens failed %d\n",
1605                        private->size);
1606                kfree(mixer);
1607                return ret;
1608        }
1609
1610        sof_dbg_comp_config(scomp, &mixer->config);
1611
1612        swidget->private = mixer;
1613
1614        ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer,
1615                                 sizeof(*mixer), r, sizeof(*r));
1616        if (ret < 0)
1617                kfree(mixer);
1618
1619        return ret;
1620}
1621
1622/*
1623 * Mux topology
1624 */
1625static 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)
1629{
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;
1633        int ret;
1634
1635        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
1636        if (!mux)
1637                return -ENOMEM;
1638
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);
1646
1647        ret = sof_parse_tokens(scomp, &mux->config, comp_tokens,
1648                               ARRAY_SIZE(comp_tokens), private->array,
1649                               le32_to_cpu(private->size));
1650        if (ret != 0) {
1651                dev_err(scomp->dev, "error: parse mux.cfg tokens failed %d\n",
1652                        private->size);
1653                kfree(mux);
1654                return ret;
1655        }
1656
1657        sof_dbg_comp_config(scomp, &mux->config);
1658
1659        swidget->private = mux;
1660
1661        ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux,
1662                                 sizeof(*mux), r, sizeof(*r));
1663        if (ret < 0)
1664                kfree(mux);
1665
1666        return ret;
1667}
1668
1669/*
1670 * PGA Topology
1671 */
1672
1673static 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)
1677{
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;
1682        int min_step;
1683        int max_step;
1684        int ret;
1685
1686        volume = kzalloc(sizeof(*volume), GFP_KERNEL);
1687        if (!volume)
1688                return -ENOMEM;
1689
1690        if (!le32_to_cpu(tw->num_kcontrols)) {
1691                dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n",
1692                        tw->num_kcontrols);
1693                ret = -EINVAL;
1694                goto err;
1695        }
1696
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);
1704
1705        ret = sof_parse_tokens(scomp, volume, volume_tokens,
1706                               ARRAY_SIZE(volume_tokens), private->array,
1707                               le32_to_cpu(private->size));
1708        if (ret != 0) {
1709                dev_err(scomp->dev, "error: parse volume tokens failed %d\n",
1710                        private->size);
1711                goto err;
1712        }
1713        ret = sof_parse_tokens(scomp, &volume->config, comp_tokens,
1714                               ARRAY_SIZE(comp_tokens), private->array,
1715                               le32_to_cpu(private->size));
1716        if (ret != 0) {
1717                dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n",
1718                        le32_to_cpu(private->size));
1719                goto err;
1720        }
1721
1722        sof_dbg_comp_config(scomp, &volume->config);
1723
1724        swidget->private = volume;
1725
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;
1734                        break;
1735                }
1736        }
1737
1738        ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume,
1739                                 sizeof(*volume), r, sizeof(*r));
1740        if (ret >= 0)
1741                return ret;
1742err:
1743        kfree(volume);
1744        return ret;
1745}
1746
1747/*
1748 * SRC Topology
1749 */
1750
1751static 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)
1755{
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;
1759        int ret;
1760
1761        src = kzalloc(sizeof(*src), GFP_KERNEL);
1762        if (!src)
1763                return -ENOMEM;
1764
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);
1772
1773        ret = sof_parse_tokens(scomp, src, src_tokens,
1774                               ARRAY_SIZE(src_tokens), private->array,
1775                               le32_to_cpu(private->size));
1776        if (ret != 0) {
1777                dev_err(scomp->dev, "error: parse src tokens failed %d\n",
1778                        private->size);
1779                goto err;
1780        }
1781
1782        ret = sof_parse_tokens(scomp, &src->config, comp_tokens,
1783                               ARRAY_SIZE(comp_tokens), private->array,
1784                               le32_to_cpu(private->size));
1785        if (ret != 0) {
1786                dev_err(scomp->dev, "error: parse src.cfg tokens failed %d\n",
1787                        le32_to_cpu(private->size));
1788                goto err;
1789        }
1790
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);
1794
1795        swidget->private = src;
1796
1797        ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src,
1798                                 sizeof(*src), r, sizeof(*r));
1799        if (ret >= 0)
1800                return ret;
1801err:
1802        kfree(src);
1803        return ret;
1804}
1805
1806/*
1807 * ASRC Topology
1808 */
1809
1810static 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)
1814{
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;
1818        int ret;
1819
1820        asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
1821        if (!asrc)
1822                return -ENOMEM;
1823
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);
1831
1832        ret = sof_parse_tokens(scomp, asrc, asrc_tokens,
1833                               ARRAY_SIZE(asrc_tokens), private->array,
1834                               le32_to_cpu(private->size));
1835        if (ret != 0) {
1836                dev_err(scomp->dev, "error: parse asrc tokens failed %d\n",
1837                        private->size);
1838                goto err;
1839        }
1840
1841        ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens,
1842                               ARRAY_SIZE(comp_tokens), private->array,
1843                               le32_to_cpu(private->size));
1844        if (ret != 0) {
1845                dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n",
1846                        le32_to_cpu(private->size));
1847                goto err;
1848        }
1849
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);
1855
1856        swidget->private = asrc;
1857
1858        ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc,
1859                                 sizeof(*asrc), r, sizeof(*r));
1860        if (ret >= 0)
1861                return ret;
1862err:
1863        kfree(asrc);
1864        return ret;
1865}
1866
1867/*
1868 * Signal Generator Topology
1869 */
1870
1871static 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)
1875{
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;
1879        int ret;
1880
1881        tone = kzalloc(sizeof(*tone), GFP_KERNEL);
1882        if (!tone)
1883                return -ENOMEM;
1884
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);
1892
1893        ret = sof_parse_tokens(scomp, tone, tone_tokens,
1894                               ARRAY_SIZE(tone_tokens), private->array,
1895                               le32_to_cpu(private->size));
1896        if (ret != 0) {
1897                dev_err(scomp->dev, "error: parse tone tokens failed %d\n",
1898                        le32_to_cpu(private->size));
1899                goto err;
1900        }
1901
1902        ret = sof_parse_tokens(scomp, &tone->config, comp_tokens,
1903                               ARRAY_SIZE(comp_tokens), private->array,
1904                               le32_to_cpu(private->size));
1905        if (ret != 0) {
1906                dev_err(scomp->dev, "error: parse tone.cfg tokens failed %d\n",
1907                        le32_to_cpu(private->size));
1908                goto err;
1909        }
1910
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);
1914
1915        swidget->private = tone;
1916
1917        ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone,
1918                                 sizeof(*tone), r, sizeof(*r));
1919        if (ret >= 0)
1920                return ret;
1921err:
1922        kfree(tone);
1923        return ret;
1924}
1925
1926static int sof_get_control_data(struct snd_soc_component *scomp,
1927                                struct snd_soc_dapm_widget *widget,
1928                                struct sof_widget_data *wdata,
1929                                size_t *size)
1930{
1931        const struct snd_kcontrol_new *kc;
1932        struct soc_mixer_control *sm;
1933        struct soc_bytes_ext *sbe;
1934        struct soc_enum *se;
1935        int i;
1936
1937        *size = 0;
1938
1939        for (i = 0; i < widget->num_kcontrols; i++) {
1940                kc = &widget->kcontrol_news[i];
1941
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;
1946                        break;
1947                case SND_SOC_TPLG_TYPE_BYTES:
1948                        sbe = (struct soc_bytes_ext *)kc->private_value;
1949                        wdata[i].control = sbe->dobj.private;
1950                        break;
1951                case SND_SOC_TPLG_TYPE_ENUM:
1952                        se = (struct soc_enum *)kc->private_value;
1953                        wdata[i].control = se->dobj.private;
1954                        break;
1955                default:
1956                        dev_err(scomp->dev, "error: unknown kcontrol type %d in widget %s\n",
1957                                widget->dobj.widget.kcontrol_type,
1958                                widget->name);
1959                        return -EINVAL;
1960                }
1961
1962                if (!wdata[i].control) {
1963                        dev_err(scomp->dev, "error: no scontrol for widget %s\n",
1964                                widget->name);
1965                        return -EINVAL;
1966                }
1967
1968                wdata[i].pdata = wdata[i].control->control_data->data;
1969                if (!wdata[i].pdata)
1970                        return -EINVAL;
1971
1972                /* make sure data is valid - data can be updated at runtime */
1973                if (wdata[i].pdata->magic != SOF_ABI_MAGIC)
1974                        return -EINVAL;
1975
1976                *size += wdata[i].pdata->size;
1977
1978                /* get data type */
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;
1985                        break;
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;
1989                        break;
1990                default:
1991                        break;
1992                }
1993        }
1994
1995        return 0;
1996}
1997
1998static 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,
2002                            int type)
2003{
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;
2010        size_t ipc_size;
2011        int offset = 0;
2012        int ret = 0;
2013        int i;
2014
2015        if (type == SOF_COMP_NONE) {
2016                dev_err(scomp->dev, "error: invalid process comp type %d\n",
2017                        type);
2018                return -EINVAL;
2019        }
2020
2021        /* allocate struct for widget control data sizes and types */
2022        if (widget->num_kcontrols) {
2023                wdata = kcalloc(widget->num_kcontrols,
2024                                sizeof(*wdata),
2025                                GFP_KERNEL);
2026
2027                if (!wdata)
2028                        return -ENOMEM;
2029
2030                /* get possible component controls and get size of all pdata */
2031                ret = sof_get_control_data(scomp, widget, wdata,
2032                                           &ipc_data_size);
2033
2034                if (ret < 0)
2035                        goto out;
2036        }
2037
2038        ipc_size = sizeof(struct sof_ipc_comp_process) +
2039                le32_to_cpu(private->size) +
2040                ipc_data_size;
2041
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;
2045                ipc_data_size = 0;
2046        }
2047
2048        process = kzalloc(ipc_size, GFP_KERNEL);
2049        if (!process) {
2050                ret = -ENOMEM;
2051                goto out;
2052        }
2053
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);
2061
2062        ret = sof_parse_tokens(scomp, &process->config, comp_tokens,
2063                               ARRAY_SIZE(comp_tokens), private->array,
2064                               le32_to_cpu(private->size));
2065        if (ret != 0) {
2066                dev_err(scomp->dev, "error: parse process.cfg tokens failed %d\n",
2067                        le32_to_cpu(private->size));
2068                goto err;
2069        }
2070
2071        sof_dbg_comp_config(scomp, &process->config);
2072
2073        /*
2074         * found private data in control, so copy it.
2075         * get possible component controls - get size of all pdata,
2076         * then memcpy with headers
2077         */
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;
2084                }
2085        }
2086
2087        process->size = ipc_data_size;
2088        swidget->private = process;
2089
2090        ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process,
2091                                 ipc_size, r, sizeof(*r));
2092
2093        if (ret < 0) {
2094                dev_err(scomp->dev, "error: create process failed\n");
2095                goto err;
2096        }
2097
2098        /* we sent the data in single message so return */
2099        if (ipc_data_size)
2100                goto out;
2101
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,
2106                                                    wdata[i].ipc_cmd,
2107                                                    wdata[i].ctrl_type,
2108                                                    wdata[i].control->cmd,
2109                                                    true);
2110                if (ret != 0) {
2111                        dev_err(scomp->dev, "error: send control failed\n");
2112                        break;
2113                }
2114        }
2115
2116err:
2117        if (ret < 0)
2118                kfree(process);
2119out:
2120        kfree(wdata);
2121        return ret;
2122}
2123
2124/*
2125 * Processing Component Topology - can be "effect", "codec", or general
2126 * "processing".
2127 */
2128
2129static 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)
2133{
2134        struct snd_soc_tplg_private *private = &tw->priv;
2135        struct sof_ipc_comp_process config;
2136        int ret;
2137
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");
2141                return -EINVAL;
2142        }
2143
2144        memset(&config, 0, sizeof(config));
2145
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));
2150        if (ret != 0) {
2151                dev_err(scomp->dev, "error: parse process tokens failed %d\n",
2152                        le32_to_cpu(private->size));
2153                return ret;
2154        }
2155
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));
2159        if (ret < 0) {
2160                dev_err(scomp->dev, "error: process loading failed\n");
2161                return ret;
2162        }
2163
2164        return 0;
2165}
2166
2167static int sof_widget_bind_event(struct snd_soc_component *scomp,
2168                                 struct snd_sof_widget *swidget,
2169                                 u16 event_type)
2170{
2171        struct sof_ipc_comp *ipc_comp;
2172
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)
2178                        break;
2179
2180                ipc_comp = swidget->private;
2181                if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
2182                        break;
2183
2184                /* bind event to keyword detect comp */
2185                return snd_soc_tplg_widget_bind_event(swidget->widget,
2186                                                      sof_kwd_events,
2187                                                      ARRAY_SIZE(sof_kwd_events),
2188                                                      event_type);
2189        default:
2190                break;
2191        }
2192
2193        dev_err(scomp->dev,
2194                "error: invalid event type %d for widget %s\n",
2195                event_type, swidget->widget->name);
2196        return -EINVAL;
2197}
2198
2199/* external widget init - used for any driver specific init */
2200static 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)
2203{
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;
2209        int ret = 0;
2210
2211        swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
2212        if (!swidget)
2213                return -ENOMEM;
2214
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));
2223
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");
2228
2229        /* handle any special case widgets */
2230        switch (w->id) {
2231        case snd_soc_dapm_dai_in:
2232        case snd_soc_dapm_dai_out:
2233                dai = kzalloc(sizeof(*dai), GFP_KERNEL);
2234                if (!dai) {
2235                        kfree(swidget);
2236                        return -ENOMEM;
2237                }
2238
2239                ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply,
2240                                          dai);
2241                if (ret == 0) {
2242                        sof_connect_dai_widget(scomp, w, tw, dai);
2243                        list_add(&dai->list, &sdev->dai_list);
2244                        swidget->private = dai;
2245                } else {
2246                        kfree(dai);
2247                }
2248                break;
2249        case snd_soc_dapm_mixer:
2250                ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply);
2251                break;
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;
2258                                break;
2259                        }
2260                }
2261                break;
2262        case snd_soc_dapm_buffer:
2263                ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply);
2264                break;
2265        case snd_soc_dapm_scheduler:
2266                ret = sof_widget_load_pipeline(scomp, index, swidget, tw,
2267                                               &reply);
2268                break;
2269        case snd_soc_dapm_aif_out:
2270                ret = sof_widget_load_pcm(scomp, index, swidget,
2271                                          SOF_IPC_STREAM_CAPTURE, tw, &reply);
2272                break;
2273        case snd_soc_dapm_aif_in:
2274                ret = sof_widget_load_pcm(scomp, index, swidget,
2275                                          SOF_IPC_STREAM_PLAYBACK, tw, &reply);
2276                break;
2277        case snd_soc_dapm_src:
2278                ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
2279                break;
2280        case snd_soc_dapm_asrc:
2281                ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply);
2282                break;
2283        case snd_soc_dapm_siggen:
2284                ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
2285                break;
2286        case snd_soc_dapm_effect:
2287                ret = sof_widget_load_process(scomp, index, swidget, tw,
2288                                              &reply);
2289                break;
2290        case snd_soc_dapm_mux:
2291        case snd_soc_dapm_demux:
2292                ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply);
2293                break;
2294        case snd_soc_dapm_switch:
2295        case snd_soc_dapm_dai_link:
2296        case snd_soc_dapm_kcontrol:
2297        default:
2298                dev_warn(scomp->dev, "warning: widget type %d name %s not handled\n",
2299                         swidget->id, tw->name);
2300                break;
2301        }
2302
2303        /* check IPC reply */
2304        if (ret < 0 || reply.rhdr.error < 0) {
2305                dev_err(scomp->dev,
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);
2310                kfree(swidget);
2311                return ret;
2312        }
2313
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));
2318                if (ret) {
2319                        dev_err(scomp->dev, "error: widget event binding failed\n");
2320                        kfree(swidget->private);
2321                        kfree(swidget);
2322                        return ret;
2323                }
2324        }
2325
2326        w->dobj.private = swidget;
2327        list_add(&swidget->list, &sdev->widget_list);
2328        return ret;
2329}
2330
2331static int sof_route_unload(struct snd_soc_component *scomp,
2332                            struct snd_soc_dobj *dobj)
2333{
2334        struct snd_sof_route *sroute;
2335
2336        sroute = dobj->private;
2337        if (!sroute)
2338                return 0;
2339
2340        /* free sroute and its private data */
2341        kfree(sroute->private);
2342        list_del(&sroute->list);
2343        kfree(sroute);
2344
2345        return 0;
2346}
2347
2348static int sof_widget_unload(struct snd_soc_component *scomp,
2349                             struct snd_soc_dobj *dobj)
2350{
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;
2361        int ret = 0;
2362        int i;
2363
2364        swidget = dobj->private;
2365        if (!swidget)
2366                return 0;
2367
2368        widget = swidget->widget;
2369
2370        switch (swidget->id) {
2371        case snd_soc_dapm_dai_in:
2372        case snd_soc_dapm_dai_out:
2373                dai = swidget->private;
2374
2375                if (dai) {
2376                        /* free dai config */
2377                        kfree(dai->dai_config);
2378                        list_del(&dai->list);
2379                }
2380                break;
2381        case snd_soc_dapm_scheduler:
2382
2383                /* power down the pipeline schedule core */
2384                pipeline = swidget->private;
2385                ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
2386                if (ret < 0)
2387                        dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
2388                                pipeline->core);
2389
2390                /* update enabled cores mask */
2391                sdev->enabled_cores_mask &= ~(1 << pipeline->core);
2392
2393                break;
2394        default:
2395                break;
2396        }
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;
2403                        if (sm->max > 1)
2404                                kfree(scontrol->volume_table);
2405                        break;
2406                case SND_SOC_TPLG_TYPE_ENUM:
2407                        se = (struct soc_enum *)kc->private_value;
2408                        scontrol = se->dobj.private;
2409                        break;
2410                case SND_SOC_TPLG_TYPE_BYTES:
2411                        sbe = (struct soc_bytes_ext *)kc->private_value;
2412                        scontrol = sbe->dobj.private;
2413                        break;
2414                default:
2415                        dev_warn(scomp->dev, "unsupported kcontrol_type\n");
2416                        goto out;
2417                }
2418                kfree(scontrol->control_data);
2419                list_del(&scontrol->list);
2420                kfree(scontrol);
2421        }
2422
2423out:
2424        /* free private value */
2425        kfree(swidget->private);
2426
2427        /* remove and free swidget object */
2428        list_del(&swidget->list);
2429        kfree(swidget);
2430
2431        return ret;
2432}
2433
2434/*
2435 * DAI HW configuration.
2436 */
2437
2438/* FE DAI - used for any driver specific init */
2439static 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)
2442{
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;
2448        int ret = 0;
2449
2450        /* nothing to do for BEs atm */
2451        if (!pcm)
2452                return 0;
2453
2454        spcm = kzalloc(sizeof(*spcm), GFP_KERNEL);
2455        if (!spcm)
2456                return -ENOMEM;
2457
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;
2461
2462        spcm->pcm = *pcm;
2463        dev_dbg(scomp->dev, "tplg: load pcm %s\n", pcm->dai_name);
2464
2465        dai_drv->dobj.private = spcm;
2466        list_add(&spcm->list, &sdev->pcm_list);
2467
2468        ret = sof_parse_tokens(scomp, spcm, stream_tokens,
2469                               ARRAY_SIZE(stream_tokens), private->array,
2470                               le32_to_cpu(private->size));
2471        if (ret) {
2472                dev_err(scomp->dev, "error: parse stream tokens failed %d\n",
2473                        le32_to_cpu(private->size));
2474                return ret;
2475        }
2476
2477        /* do we need to allocate playback PCM DMA pages */
2478        if (!spcm->pcm.playback)
2479                goto capture;
2480
2481        dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
2482                 spcm->pcm.pcm_name, spcm->stream[0].d0i3_compatible);
2483
2484        caps = &spcm->pcm.caps[stream];
2485
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);
2489        if (ret < 0) {
2490                dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
2491                        caps->name, ret);
2492
2493                return ret;
2494        }
2495
2496        /* bind pcm to host comp */
2497        ret = spcm_bind(scomp, spcm, stream);
2498        if (ret) {
2499                dev_err(scomp->dev,
2500                        "error: can't bind pcm to host\n");
2501                goto free_playback_tables;
2502        }
2503
2504capture:
2505        stream = SNDRV_PCM_STREAM_CAPTURE;
2506
2507        /* do we need to allocate capture PCM DMA pages */
2508        if (!spcm->pcm.capture)
2509                return ret;
2510
2511        dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
2512                 spcm->pcm.pcm_name, spcm->stream[1].d0i3_compatible);
2513
2514        caps = &spcm->pcm.caps[stream];
2515
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);
2519        if (ret < 0) {
2520                dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
2521                        caps->name, ret);
2522                goto free_playback_tables;
2523        }
2524
2525        /* bind pcm to host comp */
2526        ret = spcm_bind(scomp, spcm, stream);
2527        if (ret) {
2528                dev_err(scomp->dev,
2529                        "error: can't bind pcm to host\n");
2530                snd_dma_free_pages(&spcm->stream[stream].page_table);
2531                goto free_playback_tables;
2532        }
2533
2534        return ret;
2535
2536free_playback_tables:
2537        if (spcm->pcm.playback)
2538                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2539
2540        return ret;
2541}
2542
2543static int sof_dai_unload(struct snd_soc_component *scomp,
2544                          struct snd_soc_dobj *dobj)
2545{
2546        struct snd_sof_pcm *spcm = dobj->private;
2547
2548        /* free PCM DMA pages */
2549        if (spcm->pcm.playback)
2550                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2551
2552        if (spcm->pcm.capture)
2553                snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table);
2554
2555        /* remove from list and free spcm */
2556        list_del(&spcm->list);
2557        kfree(spcm);
2558
2559        return 0;
2560}
2561
2562static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
2563                               struct sof_ipc_dai_config *config)
2564{
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;
2570                else
2571                        config->format |= SOF_DAI_FMT_CBM_CFS;
2572        } else {
2573                /* codec is bclk slave */
2574                if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
2575                        config->format |= SOF_DAI_FMT_CBS_CFM;
2576                else
2577                        config->format |= SOF_DAI_FMT_CBS_CFS;
2578        }
2579
2580        /* inverted clocks ? */
2581        if (hw_config->invert_bclk) {
2582                if (hw_config->invert_fsync)
2583                        config->format |= SOF_DAI_FMT_IB_IF;
2584                else
2585                        config->format |= SOF_DAI_FMT_IB_NF;
2586        } else {
2587                if (hw_config->invert_fsync)
2588                        config->format |= SOF_DAI_FMT_NB_IF;
2589                else
2590                        config->format |= SOF_DAI_FMT_NB_NF;
2591        }
2592}
2593
2594/* set config for all DAI's with name matching the link name */
2595static 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)
2598{
2599        struct snd_sof_dai *dai;
2600        int found = 0;
2601
2602        list_for_each_entry(dai, &sdev->dai_list, list) {
2603                if (!dai->name)
2604                        continue;
2605
2606                if (strcmp(link->name, dai->name) == 0) {
2607                        dai->dai_config = kmemdup(config, size, GFP_KERNEL);
2608                        if (!dai->dai_config)
2609                                return -ENOMEM;
2610
2611                        /* set cpu_dai_name */
2612                        dai->cpu_dai_name = link->cpus->dai_name;
2613
2614                        found = 1;
2615                }
2616        }
2617
2618        /*
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
2622         */
2623        if (!found) {
2624                dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
2625                         link->name);
2626        }
2627
2628        return 0;
2629}
2630
2631static 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)
2636{
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);
2641        int ret;
2642
2643        /* handle master/slave and inverted clocks */
2644        sof_dai_set_format(hw_config, config);
2645
2646        /* init IPC */
2647        memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params));
2648        config->hdr.size = size;
2649
2650        ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens,
2651                               ARRAY_SIZE(ssp_tokens), private->array,
2652                               le32_to_cpu(private->size));
2653        if (ret != 0) {
2654                dev_err(scomp->dev, "error: parse ssp tokens failed %d\n",
2655                        le32_to_cpu(private->size));
2656                return ret;
2657        }
2658
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);
2667
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);
2674
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",
2678                        config->dai_index);
2679                return -EINVAL;
2680        }
2681
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",
2684                        config->dai_index);
2685                return -EINVAL;
2686        }
2687
2688        /* send message to DSP */
2689        ret = sof_ipc_tx_message(sdev->ipc,
2690                                 config->hdr.cmd, config, size, &reply,
2691                                 sizeof(reply));
2692
2693        if (ret < 0) {
2694                dev_err(scomp->dev, "error: failed to set DAI config for SSP%d\n",
2695                        config->dai_index);
2696                return ret;
2697        }
2698
2699        /* set config for all DAI's with name matching the link name */
2700        ret = sof_set_dai_config(sdev, size, link, config);
2701        if (ret < 0)
2702                dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n",
2703                        config->dai_index);
2704
2705        return ret;
2706}
2707
2708static 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)
2713{
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);
2718        int ret;
2719
2720        /* handle master/slave and inverted clocks */
2721        sof_dai_set_format(hw_config, config);
2722
2723        /* init IPC */
2724        memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params));
2725        config->hdr.size = size;
2726
2727        ret = sof_parse_tokens(scomp, &config->sai, sai_tokens,
2728                               ARRAY_SIZE(sai_tokens), private->array,
2729                               le32_to_cpu(private->size));
2730        if (ret != 0) {
2731                dev_err(scomp->dev, "error: parse sai tokens failed %d\n",
2732                        le32_to_cpu(private->size));
2733                return ret;
2734        }
2735
2736        config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
2737        config->sai.mclk_direction = hw_config->mclk_direction;
2738
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);
2743
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);
2749
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",
2752                        config->dai_index);
2753                return -EINVAL;
2754        }
2755
2756        /* send message to DSP */
2757        ret = sof_ipc_tx_message(sdev->ipc,
2758                                 config->hdr.cmd, config, size, &reply,
2759                                 sizeof(reply));
2760
2761        if (ret < 0) {
2762                dev_err(scomp->dev, "error: failed to set DAI config for SAI%d\n",
2763                        config->dai_index);
2764                return ret;
2765        }
2766
2767        /* set config for all DAI's with name matching the link name */
2768        ret = sof_set_dai_config(sdev, size, link, config);
2769        if (ret < 0)
2770                dev_err(scomp->dev, "error: failed to save DAI config for SAI%d\n",
2771                        config->dai_index);
2772
2773        return ret;
2774}
2775
2776static 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)
2781{
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);
2786        int ret;
2787
2788        /* handle master/slave and inverted clocks */
2789        sof_dai_set_format(hw_config, config);
2790
2791        /* init IPC */
2792        memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params));
2793        config->hdr.size = size;
2794
2795        ret = sof_parse_tokens(scomp, &config->esai, esai_tokens,
2796                               ARRAY_SIZE(esai_tokens), private->array,
2797                               le32_to_cpu(private->size));
2798        if (ret != 0) {
2799                dev_err(scomp->dev, "error: parse esai tokens failed %d\n",
2800                        le32_to_cpu(private->size));
2801                return ret;
2802        }
2803
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);
2812
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);
2818
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",
2821                        config->dai_index);
2822                return -EINVAL;
2823        }
2824
2825        /* send message to DSP */
2826        ret = sof_ipc_tx_message(sdev->ipc,
2827                                 config->hdr.cmd, config, size, &reply,
2828                                 sizeof(reply));
2829        if (ret < 0) {
2830                dev_err(scomp->dev, "error: failed to set DAI config for ESAI%d\n",
2831                        config->dai_index);
2832                return ret;
2833        }
2834
2835        /* set config for all DAI's with name matching the link name */
2836        ret = sof_set_dai_config(sdev, size, link, config);
2837        if (ret < 0)
2838                dev_err(scomp->dev, "error: failed to save DAI config for ESAI%d\n",
2839                        config->dai_index);
2840
2841        return ret;
2842}
2843
2844static 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)
2849{
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;
2856        u32 size;
2857        int ret, j;
2858
2859        /*
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.
2863         */
2864        memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params));
2865
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));
2870        if (ret != 0) {
2871                dev_err(scomp->dev, "error: parse dmic tokens failed %d\n",
2872                        le32_to_cpu(private->size));
2873                return ret;
2874        }
2875
2876        /*
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
2880         */
2881        size = sizeof(*config) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) *
2882                                        config->dmic.num_pdm_active;
2883
2884        ipc_config = kzalloc(size, GFP_KERNEL);
2885        if (!ipc_config)
2886                return -ENOMEM;
2887
2888        /* copy the common dai config and dmic params */
2889        memcpy(ipc_config, config, sizeof(*config));
2890
2891        /*
2892         * alloc memory for private member
2893         * Used to track the pdm config array index currently being parsed
2894         */
2895        sdev->private = kzalloc(sizeof(u32), GFP_KERNEL);
2896        if (!sdev->private) {
2897                kfree(ipc_config);
2898                return -ENOMEM;
2899        }
2900
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));
2905        if (ret != 0) {
2906                dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n",
2907                        le32_to_cpu(private->size));
2908                goto err;
2909        }
2910
2911        /* set IPC header size */
2912        ipc_config->hdr.size = size;
2913
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);
2925
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);
2939        }
2940
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;
2944        }
2945
2946        /* send message to DSP */
2947        ret = sof_ipc_tx_message(sdev->ipc,
2948                                 ipc_config->hdr.cmd, ipc_config, size, &reply,
2949                                 sizeof(reply));
2950
2951        if (ret < 0) {
2952                dev_err(scomp->dev,
2953                        "error: failed to set DAI config for DMIC%d\n",
2954                        config->dai_index);
2955                goto err;
2956        }
2957
2958        /* set config for all DAI's with name matching the link name */
2959        ret = sof_set_dai_config(sdev, size, link, ipc_config);
2960        if (ret < 0)
2961                dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n",
2962                        config->dai_index);
2963
2964err:
2965        kfree(sdev->private);
2966        kfree(ipc_config);
2967
2968        return ret;
2969}
2970
2971/*
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
2975 */
2976static int sof_link_hda_process(struct snd_sof_dev *sdev,
2977                                struct snd_soc_dai_link *link,
2978                                struct sof_ipc_dai_config *config)
2979{
2980        struct sof_ipc_reply reply;
2981        u32 size = sizeof(*config);
2982        struct snd_sof_dai *sof_dai;
2983        int found = 0;
2984        int ret;
2985
2986        list_for_each_entry(sof_dai, &sdev->dai_list, list) {
2987                if (!sof_dai->name)
2988                        continue;
2989
2990                if (strcmp(link->name, sof_dai->name) == 0) {
2991                        config->dai_index = sof_dai->comp_dai.dai_index;
2992                        found = 1;
2993
2994                        config->hda.link_dma_ch = DMA_CHAN_INVALID;
2995
2996                        /* save config in dai component */
2997                        sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
2998                        if (!sof_dai->dai_config)
2999                                return -ENOMEM;
3000
3001                        sof_dai->cpu_dai_name = link->cpus->dai_name;
3002
3003                        /* send message to DSP */
3004                        ret = sof_ipc_tx_message(sdev->ipc,
3005                                                 config->hdr.cmd, config, size,
3006                                                 &reply, sizeof(reply));
3007
3008                        if (ret < 0) {
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,
3011                                        config->dai_index);
3012
3013                                return ret;
3014                        }
3015                }
3016        }
3017
3018        /*
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
3022         */
3023        if (!found) {
3024                dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
3025                         link->name);
3026        }
3027
3028        return 0;
3029}
3030
3031static 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)
3036{
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);
3041        int ret;
3042
3043        /* init IPC */
3044        memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params));
3045        config->hdr.size = size;
3046
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));
3051        if (ret != 0) {
3052                dev_err(scomp->dev, "error: parse hda tokens failed %d\n",
3053                        le32_to_cpu(private->size));
3054                return ret;
3055        }
3056
3057        dai = snd_soc_find_dai(link->cpus);
3058        if (!dai) {
3059                dev_err(scomp->dev, "error: failed to find dai %s in %s",
3060                        link->cpus->dai_name, __func__);
3061                return -EINVAL;
3062        }
3063
3064        ret = sof_link_hda_process(sdev, link, config);
3065        if (ret < 0)
3066                dev_err(scomp->dev, "error: failed to process hda dai link %s",
3067                        link->name);
3068
3069        return ret;
3070}
3071
3072static 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)
3077{
3078        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3079        struct sof_ipc_reply reply;
3080        u32 size = sizeof(*config);
3081        int ret;
3082
3083        /* init IPC */
3084        config->hdr.size = size;
3085
3086        /* send message to DSP */
3087        ret = sof_ipc_tx_message(sdev->ipc,
3088                                 config->hdr.cmd, config, size, &reply,
3089                                 sizeof(reply));
3090
3091        if (ret < 0) {
3092                dev_err(scomp->dev, "error: failed to set DAI config for ALH %d\n",
3093                        config->dai_index);
3094                return ret;
3095        }
3096
3097        /* set config for all DAI's with name matching the link name */
3098        ret = sof_set_dai_config(sdev, size, link, config);
3099        if (ret < 0)
3100                dev_err(scomp->dev, "error: failed to save DAI config for ALH %d\n",
3101                        config->dai_index);
3102
3103        return ret;
3104}
3105
3106/* DAI link - used for any driver specific init */
3107static 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)
3110{
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;
3114        int num_hw_configs;
3115        int ret;
3116        int i = 0;
3117
3118        if (!link->platforms) {
3119                dev_err(scomp->dev, "error: no platforms\n");
3120                return -EINVAL;
3121        }
3122        link->platforms->name = dev_name(scomp->dev);
3123
3124        /*
3125         * Set nonatomic property for FE dai links as their trigger action
3126         * involves IPC's.
3127         */
3128        if (!link->no_pcm) {
3129                link->nonatomic = true;
3130
3131                /* set trigger order */
3132                link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST;
3133                link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST;
3134
3135                /* nothing more to do for FE dai links */
3136                return 0;
3137        }
3138
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");
3142                return -EINVAL;
3143        }
3144
3145        /* Send BE DAI link configurations to DSP */
3146        memset(&config, 0, sizeof(config));
3147
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));
3152        if (ret != 0) {
3153                dev_err(scomp->dev, "error: parse link tokens failed %d\n",
3154                        le32_to_cpu(private->size));
3155                return ret;
3156        }
3157
3158        /*
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.
3161         */
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));
3167                        return -EINVAL;
3168                }
3169        } else {
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));
3172
3173                for (i = 0; i < num_hw_configs; i++) {
3174                        if (cfg->hw_config[i].id == cfg->default_hw_config_id)
3175                                break;
3176                }
3177
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));
3181                        return -EINVAL;
3182                }
3183        }
3184
3185        /* configure dai IPC message */
3186        hw_config = &cfg->hw_config[i];
3187
3188        config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
3189        config.format = le32_to_cpu(hw_config->fmt);
3190
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,
3195                                        &config);
3196                break;
3197        case SOF_DAI_INTEL_DMIC:
3198                ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config,
3199                                         &config);
3200                break;
3201        case SOF_DAI_INTEL_HDA:
3202                ret = sof_link_hda_load(scomp, index, link, cfg, hw_config,
3203                                        &config);
3204                break;
3205        case SOF_DAI_INTEL_ALH:
3206                ret = sof_link_alh_load(scomp, index, link, cfg, hw_config,
3207                                        &config);
3208                break;
3209        case SOF_DAI_IMX_SAI:
3210                ret = sof_link_sai_load(scomp, index, link, cfg, hw_config,
3211                                        &config);
3212                break;
3213        case SOF_DAI_IMX_ESAI:
3214                ret = sof_link_esai_load(scomp, index, link, cfg, hw_config,
3215                                         &config);
3216                break;
3217        default:
3218                dev_err(scomp->dev, "error: invalid DAI type %d\n",
3219                        config.type);
3220                ret = -EINVAL;
3221                break;
3222        }
3223        if (ret < 0)
3224                return ret;
3225
3226        return 0;
3227}
3228
3229static int sof_link_hda_unload(struct snd_sof_dev *sdev,
3230                               struct snd_soc_dai_link *link)
3231{
3232        struct snd_soc_dai *dai;
3233        int ret = 0;
3234
3235        dai = snd_soc_find_dai(link->cpus);
3236        if (!dai) {
3237                dev_err(sdev->dev, "error: failed to find dai %s in %s",
3238                        link->cpus->dai_name, __func__);
3239                return -EINVAL;
3240        }
3241
3242        return ret;
3243}
3244
3245static int sof_link_unload(struct snd_soc_component *scomp,
3246                           struct snd_soc_dobj *dobj)
3247{
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);
3251
3252        struct snd_sof_dai *sof_dai;
3253        int ret = 0;
3254
3255        /* only BE link is loaded by sof */
3256        if (!link->no_pcm)
3257                return 0;
3258
3259        list_for_each_entry(sof_dai, &sdev->dai_list, list) {
3260                if (!sof_dai->name)
3261                        continue;
3262
3263                if (strcmp(link->name, sof_dai->name) == 0)
3264                        goto found;
3265        }
3266
3267        dev_err(scomp->dev, "error: failed to find dai %s in %s",
3268                link->name, __func__);
3269        return -EINVAL;
3270found:
3271
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 */
3279                break;
3280        case SOF_DAI_INTEL_HDA:
3281                ret = sof_link_hda_unload(sdev, link);
3282                break;
3283        default:
3284                dev_err(scomp->dev, "error: invalid DAI type %d\n",
3285                        sof_dai->dai_config->type);
3286                ret = -EINVAL;
3287                break;
3288        }
3289
3290        return ret;
3291}
3292
3293/* DAI link - used for any driver specific init */
3294static int sof_route_load(struct snd_soc_component *scomp, int index,
3295                          struct snd_soc_dapm_route *route)
3296{
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;
3303        int ret = 0;
3304
3305        /* allocate memory for sroute and connect */
3306        sroute = kzalloc(sizeof(*sroute), GFP_KERNEL);
3307        if (!sroute)
3308                return -ENOMEM;
3309
3310        sroute->scomp = scomp;
3311
3312        connect = kzalloc(sizeof(*connect), GFP_KERNEL);
3313        if (!connect) {
3314                kfree(sroute);
3315                return -ENOMEM;
3316        }
3317
3318        connect->hdr.size = sizeof(*connect);
3319        connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
3320
3321        dev_dbg(scomp->dev, "sink %s control %s source %s\n",
3322                route->sink, route->control ? route->control : "none",
3323                route->source);
3324
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",
3329                        route->source);
3330                ret = -EINVAL;
3331                goto err;
3332        }
3333
3334        /*
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
3338         * to the DSP.
3339         */
3340        if (source_swidget->id == snd_soc_dapm_out_drv ||
3341            source_swidget->id == snd_soc_dapm_output)
3342                goto err;
3343
3344        connect->source_id = source_swidget->comp_id;
3345
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",
3350                        route->sink);
3351                ret = -EINVAL;
3352                goto err;
3353        }
3354
3355        /*
3356         * Don't send routes whose sink widget is of type
3357         * output or out_drv to the DSP
3358         */
3359        if (sink_swidget->id == snd_soc_dapm_out_drv ||
3360            sink_swidget->id == snd_soc_dapm_output)
3361                goto err;
3362
3363        connect->sink_id = sink_swidget->comp_id;
3364
3365        /*
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
3370         */
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);
3375                ret = 0;
3376                goto err;
3377        } else {
3378                ret = sof_ipc_tx_message(sdev->ipc,
3379                                         connect->hdr.cmd,
3380                                         connect, sizeof(*connect),
3381                                         &reply, sizeof(reply));
3382
3383                /* check IPC return value */
3384                if (ret < 0) {
3385                        dev_err(scomp->dev, "error: failed to add route sink %s control %s source %s\n",
3386                                route->sink,
3387                                route->control ? route->control : "none",
3388                                route->source);
3389                        goto err;
3390                }
3391
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",
3395                                route->sink,
3396                                route->control ? route->control : "none",
3397                                route->source, reply.error);
3398                        ret = reply.error;
3399                        goto err;
3400                }
3401
3402                sroute->route = route;
3403                dobj->private = sroute;
3404                sroute->private = connect;
3405
3406                /* add route to route list */
3407                list_add(&sroute->list, &sdev->route_list);
3408
3409                return ret;
3410        }
3411
3412err:
3413        kfree(connect);
3414        kfree(sroute);
3415        return ret;
3416}
3417
3418/* Function to set the initial value of SOF kcontrols.
3419 * The value will be stored in scontrol->control_data
3420 */
3421static int snd_sof_cache_kcontrol_val(struct snd_soc_component *scomp)
3422{
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;
3426        int ret = 0;
3427
3428        list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
3429
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;
3437                        break;
3438                case SOF_CTRL_CMD_BINARY:
3439                        ipc_cmd = SOF_IPC_COMP_GET_DATA;
3440                        ctrl_type = SOF_CTRL_TYPE_DATA_GET;
3441                        break;
3442                default:
3443                        dev_err(scomp->dev,
3444                                "error: Invalid scontrol->cmd: %d\n",
3445                                scontrol->cmd);
3446                        return -EINVAL;
3447                }
3448                ret = snd_sof_ipc_set_get_comp_data(scontrol,
3449                                                    ipc_cmd, ctrl_type,
3450                                                    scontrol->cmd,
3451                                                    false);
3452                if (ret < 0) {
3453                        dev_warn(scomp->dev,
3454                                 "error: kcontrol value get for widget: %d\n",
3455                                 scontrol->comp_id);
3456                }
3457        }
3458
3459        return ret;
3460}
3461
3462int snd_sof_complete_pipeline(struct device *dev,
3463                              struct snd_sof_widget *swidget)
3464{
3465        struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3466        struct sof_ipc_pipe_ready ready;
3467        struct sof_ipc_reply reply;
3468        int ret;
3469
3470        dev_dbg(dev, "tplg: complete pipeline %s id %d\n",
3471                swidget->widget->name, swidget->comp_id);
3472
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;
3477
3478        ret = sof_ipc_tx_message(sdev->ipc,
3479                                 ready.hdr.cmd, &ready, sizeof(ready), &reply,
3480                                 sizeof(reply));
3481        if (ret < 0)
3482                return ret;
3483        return 1;
3484}
3485
3486/* completion - called at completion of firmware loading */
3487static void sof_complete(struct snd_soc_component *scomp)
3488{
3489        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3490        struct snd_sof_widget *swidget;
3491
3492        /* some widget types require completion notificattion */
3493        list_for_each_entry(swidget, &sdev->widget_list, list) {
3494                if (swidget->complete)
3495                        continue;
3496
3497                switch (swidget->id) {
3498                case snd_soc_dapm_scheduler:
3499                        swidget->complete =
3500                                snd_sof_complete_pipeline(scomp->dev, swidget);
3501                        break;
3502                default:
3503                        break;
3504                }
3505        }
3506        /*
3507         * cache initial values of SOF kcontrols by reading DSP value over
3508         * IPC. It may be overwritten by alsa-mixer after booting up
3509         */
3510        snd_sof_cache_kcontrol_val(scomp);
3511}
3512
3513/* manifest - optional to inform component of manifest */
3514static int sof_manifest(struct snd_soc_component *scomp, int index,
3515                        struct snd_soc_tplg_manifest *man)
3516{
3517        u32 size;
3518        u32 abi_version;
3519
3520        size = le32_to_cpu(man->priv.size);
3521
3522        /* backward compatible with tplg without ABI info */
3523        if (!size) {
3524                dev_dbg(scomp->dev, "No topology ABI info\n");
3525                return 0;
3526        }
3527
3528        if (size != SOF_TPLG_ABI_SIZE) {
3529                dev_err(scomp->dev, "error: invalid topology ABI size\n");
3530                return -EINVAL;
3531        }
3532
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,
3537                 SOF_ABI_PATCH);
3538
3539        abi_version = SOF_ABI_VER(man->priv.data[0],
3540                                  man->priv.data[1],
3541                                  man->priv.data[2]);
3542
3543        if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
3544                dev_err(scomp->dev, "error: incompatible topology ABI version\n");
3545                return -EINVAL;
3546        }
3547
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");
3551                } else {
3552                        dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
3553                        return -EINVAL;
3554                }
3555        }
3556
3557        return 0;
3558}
3559
3560/* vendor specific kcontrol handlers available for binding */
3561static 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},
3566};
3567
3568/* vendor specific bytes ext handlers available for binding */
3569static 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},
3571};
3572
3573static 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,
3577
3578        /* external kcontrol init - used for any driver specific init */
3579        .dapm_route_load        = sof_route_load,
3580        .dapm_route_unload      = sof_route_unload,
3581
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,
3586
3587        /* FE DAI - used for any driver specific init */
3588        .dai_load       = sof_dai_load,
3589        .dai_unload     = sof_dai_unload,
3590
3591        /* DAI link - used for any driver specific init */
3592        .link_load      = sof_link_load,
3593        .link_unload    = sof_link_unload,
3594
3595        /* completion - called at completion of firmware loading */
3596        .complete       = sof_complete,
3597
3598        /* manifest - optional to inform component of manifest */
3599        .manifest       = sof_manifest,
3600
3601        /* vendor specific kcontrol handlers available for binding */
3602        .io_ops         = sof_io_ops,
3603        .io_ops_count   = ARRAY_SIZE(sof_io_ops),
3604
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),
3608};
3609
3610int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
3611{
3612        const struct firmware *fw;
3613        int ret;
3614
3615        dev_dbg(scomp->dev, "loading topology:%s\n", file);
3616
3617        ret = request_firmware(&fw, file, scomp->dev);
3618        if (ret < 0) {
3619                dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
3620                        file, ret);
3621                return ret;
3622        }
3623
3624        ret = snd_soc_tplg_component_load(scomp,
3625                                          &sof_tplg_ops, fw,
3626                                          SND_SOC_TPLG_INDEX_ALL);
3627        if (ret < 0) {
3628                dev_err(scomp->dev, "error: tplg component load failed %d\n",
3629                        ret);
3630                ret = -EINVAL;
3631        }
3632
3633        release_firmware(fw);
3634        return ret;
3635}
3636EXPORT_SYMBOL(snd_sof_load_topology);
3637