670 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// soc-compress.c -- ALSA SoC Compress4//5// Copyright (C) 2012 Intel Corp.6//7// Authors: Namarta Kohli <namartax.kohli@intel.com>8// Ramesh Babu K V <ramesh.babu@linux.intel.com>9// Vinod Koul <vinod.koul@linux.intel.com>10 11#include <linux/kernel.h>12#include <linux/init.h>13#include <linux/delay.h>14#include <linux/slab.h>15#include <linux/workqueue.h>16#include <sound/core.h>17#include <sound/compress_params.h>18#include <sound/compress_driver.h>19#include <sound/soc.h>20#include <sound/initval.h>21#include <sound/soc-dpcm.h>22#include <sound/soc-link.h>23 24static int snd_soc_compr_components_open(struct snd_compr_stream *cstream)25{26 struct snd_soc_pcm_runtime *rtd = cstream->private_data;27 struct snd_soc_component *component;28 int ret = 0;29 int i;30 31 for_each_rtd_components(rtd, i, component) {32 ret = snd_soc_component_module_get_when_open(component, cstream);33 if (ret < 0)34 break;35 36 ret = snd_soc_component_compr_open(component, cstream);37 if (ret < 0)38 break;39 }40 41 return ret;42}43 44static void snd_soc_compr_components_free(struct snd_compr_stream *cstream,45 int rollback)46{47 struct snd_soc_pcm_runtime *rtd = cstream->private_data;48 struct snd_soc_component *component;49 int i;50 51 for_each_rtd_components(rtd, i, component) {52 snd_soc_component_compr_free(component, cstream, rollback);53 snd_soc_component_module_put_when_close(component, cstream, rollback);54 }55}56 57static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)58{59 struct snd_soc_pcm_runtime *rtd = cstream->private_data;60 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);61 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);62 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */63 64 snd_soc_dpcm_mutex_lock(rtd);65 66 if (!rollback)67 snd_soc_runtime_deactivate(rtd, stream);68 69 snd_soc_dai_digital_mute(codec_dai, 1, stream);70 71 if (!snd_soc_dai_active(cpu_dai))72 cpu_dai->rate = 0;73 74 if (!snd_soc_dai_active(codec_dai))75 codec_dai->rate = 0;76 77 snd_soc_link_compr_shutdown(cstream, rollback);78 79 snd_soc_compr_components_free(cstream, rollback);80 81 snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback);82 83 if (!rollback)84 snd_soc_dapm_stream_stop(rtd, stream);85 86 snd_soc_dpcm_mutex_unlock(rtd);87 88 snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback);89 90 return 0;91}92 93static int soc_compr_free(struct snd_compr_stream *cstream)94{95 return soc_compr_clean(cstream, 0);96}97 98static int soc_compr_open(struct snd_compr_stream *cstream)99{100 struct snd_soc_pcm_runtime *rtd = cstream->private_data;101 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);102 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */103 int ret;104 105 ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream);106 if (ret < 0)107 goto err_no_lock;108 109 snd_soc_dpcm_mutex_lock(rtd);110 111 ret = snd_soc_dai_compr_startup(cpu_dai, cstream);112 if (ret < 0)113 goto err;114 115 ret = snd_soc_compr_components_open(cstream);116 if (ret < 0)117 goto err;118 119 ret = snd_soc_link_compr_startup(cstream);120 if (ret < 0)121 goto err;122 123 snd_soc_runtime_activate(rtd, stream);124err:125 snd_soc_dpcm_mutex_unlock(rtd);126err_no_lock:127 if (ret < 0)128 soc_compr_clean(cstream, 1);129 130 return ret;131}132 133static int soc_compr_open_fe(struct snd_compr_stream *cstream)134{135 struct snd_soc_pcm_runtime *fe = cstream->private_data;136 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);137 struct snd_soc_dpcm *dpcm;138 struct snd_soc_dapm_widget_list *list;139 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */140 int ret;141 142 snd_soc_card_mutex_lock(fe->card);143 144 ret = dpcm_path_get(fe, stream, &list);145 if (ret < 0)146 goto be_err;147 148 snd_soc_dpcm_mutex_lock(fe);149 150 /* calculate valid and active FE <-> BE dpcms */151 dpcm_process_paths(fe, stream, &list, 1);152 153 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;154 155 ret = dpcm_be_dai_startup(fe, stream);156 if (ret < 0) {157 /* clean up all links */158 for_each_dpcm_be(fe, stream, dpcm)159 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;160 161 dpcm_be_disconnect(fe, stream);162 goto out;163 }164 165 ret = snd_soc_dai_compr_startup(cpu_dai, cstream);166 if (ret < 0)167 goto out;168 169 ret = snd_soc_compr_components_open(cstream);170 if (ret < 0)171 goto open_err;172 173 ret = snd_soc_link_compr_startup(cstream);174 if (ret < 0)175 goto machine_err;176 177 dpcm_clear_pending_state(fe, stream);178 dpcm_path_put(&list);179 180 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;181 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;182 183 snd_soc_runtime_activate(fe, stream);184 snd_soc_dpcm_mutex_unlock(fe);185 186 snd_soc_card_mutex_unlock(fe->card);187 188 return 0;189 190machine_err:191 snd_soc_compr_components_free(cstream, 1);192open_err:193 snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);194out:195 dpcm_path_put(&list);196 snd_soc_dpcm_mutex_unlock(fe);197be_err:198 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;199 snd_soc_card_mutex_unlock(fe->card);200 return ret;201}202 203static int soc_compr_free_fe(struct snd_compr_stream *cstream)204{205 struct snd_soc_pcm_runtime *fe = cstream->private_data;206 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);207 struct snd_soc_dpcm *dpcm;208 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */209 210 snd_soc_card_mutex_lock(fe->card);211 212 snd_soc_dpcm_mutex_lock(fe);213 snd_soc_runtime_deactivate(fe, stream);214 215 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;216 217 dpcm_be_dai_hw_free(fe, stream);218 219 dpcm_be_dai_shutdown(fe, stream);220 221 /* mark FE's links ready to prune */222 for_each_dpcm_be(fe, stream, dpcm)223 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;224 225 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);226 227 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;228 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;229 230 dpcm_be_disconnect(fe, stream);231 232 snd_soc_dpcm_mutex_unlock(fe);233 234 snd_soc_link_compr_shutdown(cstream, 0);235 236 snd_soc_compr_components_free(cstream, 0);237 238 snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);239 240 snd_soc_card_mutex_unlock(fe->card);241 return 0;242}243 244static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)245{246 struct snd_soc_pcm_runtime *rtd = cstream->private_data;247 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);248 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);249 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */250 int ret;251 252 snd_soc_dpcm_mutex_lock(rtd);253 254 ret = snd_soc_component_compr_trigger(cstream, cmd);255 if (ret < 0)256 goto out;257 258 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);259 if (ret < 0)260 goto out;261 262 switch (cmd) {263 case SNDRV_PCM_TRIGGER_START:264 snd_soc_dai_digital_mute(codec_dai, 0, stream);265 break;266 case SNDRV_PCM_TRIGGER_STOP:267 snd_soc_dai_digital_mute(codec_dai, 1, stream);268 break;269 }270 271out:272 snd_soc_dpcm_mutex_unlock(rtd);273 return ret;274}275 276static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)277{278 struct snd_soc_pcm_runtime *fe = cstream->private_data;279 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);280 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */281 int ret;282 283 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||284 cmd == SND_COMPR_TRIGGER_DRAIN)285 return snd_soc_component_compr_trigger(cstream, cmd);286 287 snd_soc_card_mutex_lock(fe->card);288 289 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);290 if (ret < 0)291 goto out;292 293 ret = snd_soc_component_compr_trigger(cstream, cmd);294 if (ret < 0)295 goto out;296 297 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;298 299 ret = dpcm_be_dai_trigger(fe, stream, cmd);300 301 switch (cmd) {302 case SNDRV_PCM_TRIGGER_START:303 case SNDRV_PCM_TRIGGER_RESUME:304 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:305 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;306 break;307 case SNDRV_PCM_TRIGGER_STOP:308 case SNDRV_PCM_TRIGGER_SUSPEND:309 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;310 break;311 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:312 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;313 break;314 }315 316out:317 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;318 snd_soc_card_mutex_unlock(fe->card);319 return ret;320}321 322static int soc_compr_set_params(struct snd_compr_stream *cstream,323 struct snd_compr_params *params)324{325 struct snd_soc_pcm_runtime *rtd = cstream->private_data;326 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);327 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */328 int ret;329 330 snd_soc_dpcm_mutex_lock(rtd);331 332 /*333 * First we call set_params for the CPU DAI, then the component334 * driver this should configure the SoC side. If the machine has335 * compressed ops then we call that as well. The expectation is336 * that these callbacks will configure everything for this compress337 * path, like configuring a PCM port for a CODEC.338 */339 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);340 if (ret < 0)341 goto err;342 343 ret = snd_soc_component_compr_set_params(cstream, params);344 if (ret < 0)345 goto err;346 347 ret = snd_soc_link_compr_set_params(cstream);348 if (ret < 0)349 goto err;350 351 snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START);352 353 /* cancel any delayed stream shutdown that is pending */354 rtd->pop_wait = 0;355 snd_soc_dpcm_mutex_unlock(rtd);356 357 cancel_delayed_work_sync(&rtd->delayed_work);358 359 return 0;360 361err:362 snd_soc_dpcm_mutex_unlock(rtd);363 return ret;364}365 366static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,367 struct snd_compr_params *params)368{369 struct snd_soc_pcm_runtime *fe = cstream->private_data;370 struct snd_pcm_substream *fe_substream =371 fe->pcm->streams[cstream->direction].substream;372 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);373 int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */374 int ret;375 376 snd_soc_card_mutex_lock(fe->card);377 378 /*379 * Create an empty hw_params for the BE as the machine driver must380 * fix this up to match DSP decoder and ASRC configuration.381 * I.e. machine driver fixup for compressed BE is mandatory.382 */383 memset(&fe->dpcm[fe_substream->stream].hw_params, 0,384 sizeof(struct snd_pcm_hw_params));385 386 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;387 388 snd_soc_dpcm_mutex_lock(fe);389 ret = dpcm_be_dai_hw_params(fe, stream);390 snd_soc_dpcm_mutex_unlock(fe);391 if (ret < 0)392 goto out;393 394 snd_soc_dpcm_mutex_lock(fe);395 ret = dpcm_be_dai_prepare(fe, stream);396 snd_soc_dpcm_mutex_unlock(fe);397 if (ret < 0)398 goto out;399 400 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);401 if (ret < 0)402 goto out;403 404 ret = snd_soc_component_compr_set_params(cstream, params);405 if (ret < 0)406 goto out;407 408 ret = snd_soc_link_compr_set_params(cstream);409 if (ret < 0)410 goto out;411 snd_soc_dpcm_mutex_lock(fe);412 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);413 snd_soc_dpcm_mutex_unlock(fe);414 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;415 416out:417 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;418 snd_soc_card_mutex_unlock(fe->card);419 return ret;420}421 422static int soc_compr_get_params(struct snd_compr_stream *cstream,423 struct snd_codec *params)424{425 struct snd_soc_pcm_runtime *rtd = cstream->private_data;426 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);427 int ret = 0;428 429 snd_soc_dpcm_mutex_lock(rtd);430 431 ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params);432 if (ret < 0)433 goto err;434 435 ret = snd_soc_component_compr_get_params(cstream, params);436err:437 snd_soc_dpcm_mutex_unlock(rtd);438 return ret;439}440 441static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)442{443 struct snd_soc_pcm_runtime *rtd = cstream->private_data;444 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);445 int ret;446 447 snd_soc_dpcm_mutex_lock(rtd);448 449 ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes);450 if (ret < 0)451 goto err;452 453 ret = snd_soc_component_compr_ack(cstream, bytes);454err:455 snd_soc_dpcm_mutex_unlock(rtd);456 return ret;457}458 459static int soc_compr_pointer(struct snd_compr_stream *cstream,460 struct snd_compr_tstamp *tstamp)461{462 struct snd_soc_pcm_runtime *rtd = cstream->private_data;463 int ret;464 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);465 466 snd_soc_dpcm_mutex_lock(rtd);467 468 ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp);469 if (ret < 0)470 goto out;471 472 ret = snd_soc_component_compr_pointer(cstream, tstamp);473out:474 snd_soc_dpcm_mutex_unlock(rtd);475 return ret;476}477 478static int soc_compr_set_metadata(struct snd_compr_stream *cstream,479 struct snd_compr_metadata *metadata)480{481 struct snd_soc_pcm_runtime *rtd = cstream->private_data;482 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);483 int ret;484 485 ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);486 if (ret < 0)487 return ret;488 489 return snd_soc_component_compr_set_metadata(cstream, metadata);490}491 492static int soc_compr_get_metadata(struct snd_compr_stream *cstream,493 struct snd_compr_metadata *metadata)494{495 struct snd_soc_pcm_runtime *rtd = cstream->private_data;496 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);497 int ret;498 499 ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);500 if (ret < 0)501 return ret;502 503 return snd_soc_component_compr_get_metadata(cstream, metadata);504}505 506/* ASoC Compress operations */507static struct snd_compr_ops soc_compr_ops = {508 .open = soc_compr_open,509 .free = soc_compr_free,510 .set_params = soc_compr_set_params,511 .set_metadata = soc_compr_set_metadata,512 .get_metadata = soc_compr_get_metadata,513 .get_params = soc_compr_get_params,514 .trigger = soc_compr_trigger,515 .pointer = soc_compr_pointer,516 .ack = soc_compr_ack,517 .get_caps = snd_soc_component_compr_get_caps,518 .get_codec_caps = snd_soc_component_compr_get_codec_caps,519};520 521/* ASoC Dynamic Compress operations */522static struct snd_compr_ops soc_compr_dyn_ops = {523 .open = soc_compr_open_fe,524 .free = soc_compr_free_fe,525 .set_params = soc_compr_set_params_fe,526 .get_params = soc_compr_get_params,527 .set_metadata = soc_compr_set_metadata,528 .get_metadata = soc_compr_get_metadata,529 .trigger = soc_compr_trigger_fe,530 .pointer = soc_compr_pointer,531 .ack = soc_compr_ack,532 .get_caps = snd_soc_component_compr_get_caps,533 .get_codec_caps = snd_soc_component_compr_get_codec_caps,534};535 536/**537 * snd_soc_new_compress - create a new compress.538 *539 * @rtd: The runtime for which we will create compress540 * @num: the device index number (zero based - shared with normal PCMs)541 *542 * Return: 0 for success, else error.543 */544int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)545{546 struct snd_soc_component *component;547 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);548 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);549 struct snd_compr *compr;550 struct snd_pcm *be_pcm;551 char new_name[64];552 int ret = 0, direction = 0;553 int playback = 0, capture = 0;554 int i;555 556 /*557 * make sure these are same value,558 * and then use these as equally559 */560 BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK);561 BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE != (int)SND_COMPRESS_CAPTURE);562 563 if (rtd->dai_link->num_cpus > 1 ||564 rtd->dai_link->num_codecs > 1) {565 dev_err(rtd->card->dev,566 "Compress ASoC: Multi CPU/Codec not supported\n");567 return -EINVAL;568 }569 570 if (!codec_dai) {571 dev_err(rtd->card->dev, "Missing codec\n");572 return -EINVAL;573 }574 575 /* check client and interface hw capabilities */576 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&577 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK))578 playback = 1;579 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&580 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE))581 capture = 1;582 583 /*584 * Compress devices are unidirectional so only one of the directions585 * should be set, check for that (xor)586 */587 if (playback + capture != 1) {588 dev_err(rtd->card->dev,589 "Compress ASoC: Invalid direction for P %d, C %d\n",590 playback, capture);591 return -EINVAL;592 }593 594 if (playback)595 direction = SND_COMPRESS_PLAYBACK;596 else597 direction = SND_COMPRESS_CAPTURE;598 599 compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);600 if (!compr)601 return -ENOMEM;602 603 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),604 GFP_KERNEL);605 if (!compr->ops)606 return -ENOMEM;607 608 if (rtd->dai_link->dynamic) {609 snprintf(new_name, sizeof(new_name), "(%s)",610 rtd->dai_link->stream_name);611 612 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,613 rtd->dai_link->dpcm_playback,614 rtd->dai_link->dpcm_capture, &be_pcm);615 if (ret < 0) {616 dev_err(rtd->card->dev,617 "Compress ASoC: can't create compressed for %s: %d\n",618 rtd->dai_link->name, ret);619 return ret;620 }621 622 /* inherit atomicity from DAI link */623 be_pcm->nonatomic = rtd->dai_link->nonatomic;624 625 rtd->pcm = be_pcm;626 rtd->fe_compr = 1;627 if (rtd->dai_link->dpcm_playback)628 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;629 if (rtd->dai_link->dpcm_capture)630 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;631 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));632 } else {633 snprintf(new_name, sizeof(new_name), "%s %s-%d",634 rtd->dai_link->stream_name, codec_dai->name, num);635 636 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));637 }638 639 for_each_rtd_components(rtd, i, component) {640 if (!component->driver->compress_ops ||641 !component->driver->compress_ops->copy)642 continue;643 644 compr->ops->copy = snd_soc_component_compr_copy;645 break;646 }647 648 ret = snd_compress_new(rtd->card->snd_card, num, direction,649 new_name, compr);650 if (ret < 0) {651 component = snd_soc_rtd_to_codec(rtd, 0)->component;652 dev_err(component->dev,653 "Compress ASoC: can't create compress for codec %s: %d\n",654 component->name, ret);655 return ret;656 }657 658 /* DAPM dai link stream work */659 rtd->close_delayed_work_func = snd_soc_close_delayed_work;660 661 rtd->compr = compr;662 compr->private_data = rtd;663 664 dev_dbg(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",665 codec_dai->name, cpu_dai->name);666 667 return 0;668}669EXPORT_SYMBOL_GPL(snd_soc_new_compress);670