1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * sst_drv_interface.c - Intel SST Driver for audio engine 4 * 5 * Copyright (C) 2008-14 Intel Corp 6 * Authors: Vinod Koul <vinod.koul@intel.com> 7 * Harsha Priya <priya.harsha@intel.com> 8 * Dharageswari R <dharageswari.r@intel.com) 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 * 11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 */ 13 #include <linux/delay.h> 14 #include <linux/pci.h> 15 #include <linux/fs.h> 16 #include <linux/firmware.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/pm_qos.h> 19 #include <linux/math64.h> 20 #include <sound/core.h> 21 #include <sound/pcm.h> 22 #include <sound/soc.h> 23 #include <sound/compress_driver.h> 24 #include <asm/platform_sst_audio.h> 25 #include "../sst-mfld-platform.h" 26 #include "sst.h" 27 28 #define NUM_CODEC 2 29 #define MIN_FRAGMENT 2 30 #define MAX_FRAGMENT 4 31 #define MIN_FRAGMENT_SIZE (50 * 1024) 32 #define MAX_FRAGMENT_SIZE (1024 * 1024) 33 #define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz) (((pcm_wd_sz + 15) >> 4) << 1) 34 #ifdef CONFIG_PM 35 #define GET_USAGE_COUNT(dev) (atomic_read(&dev->power.usage_count)) 36 #else 37 #define GET_USAGE_COUNT(dev) 1 38 #endif 39 40 int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) 41 { 42 struct stream_info *stream; 43 int ret = 0; 44 45 stream = get_stream_info(ctx, str_id); 46 if (stream) { 47 /* str_id is valid, so stream is alloacted */ 48 ret = sst_free_stream(ctx, str_id); 49 if (ret) 50 sst_clean_stream(&ctx->streams[str_id]); 51 return ret; 52 } else { 53 dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id); 54 } 55 return ret; 56 } 57 58 /* 59 * sst_get_sfreq - this function returns the frequency of the stream 60 * 61 * @str_param : stream params 62 */ 63 int sst_get_sfreq(struct snd_sst_params *str_param) 64 { 65 switch (str_param->codec) { 66 case SST_CODEC_TYPE_PCM: 67 return str_param->sparams.uc.pcm_params.sfreq; 68 case SST_CODEC_TYPE_AAC: 69 return str_param->sparams.uc.aac_params.externalsr; 70 case SST_CODEC_TYPE_MP3: 71 return 0; 72 default: 73 return -EINVAL; 74 } 75 } 76 77 /* 78 * sst_get_num_channel - get number of channels for the stream 79 * 80 * @str_param : stream params 81 */ 82 int sst_get_num_channel(struct snd_sst_params *str_param) 83 { 84 switch (str_param->codec) { 85 case SST_CODEC_TYPE_PCM: 86 return str_param->sparams.uc.pcm_params.num_chan; 87 case SST_CODEC_TYPE_MP3: 88 return str_param->sparams.uc.mp3_params.num_chan; 89 case SST_CODEC_TYPE_AAC: 90 return str_param->sparams.uc.aac_params.num_chan; 91 default: 92 return -EINVAL; 93 } 94 } 95 96 /* 97 * sst_get_stream - this function prepares for stream allocation 98 * 99 * @str_param : stream param 100 */ 101 int sst_get_stream(struct intel_sst_drv *ctx, 102 struct snd_sst_params *str_param) 103 { 104 int retval; 105 struct stream_info *str_info; 106 107 /* stream is not allocated, we are allocating */ 108 retval = ctx->ops->alloc_stream(ctx, str_param); 109 if (retval <= 0) { 110 return -EIO; 111 } 112 /* store sampling freq */ 113 str_info = &ctx->streams[retval]; 114 str_info->sfreq = sst_get_sfreq(str_param); 115 116 return retval; 117 } 118 119 static int sst_power_control(struct device *dev, bool state) 120 { 121 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 122 int ret = 0; 123 int usage_count = 0; 124 125 if (state) { 126 ret = pm_runtime_resume_and_get(dev); 127 usage_count = GET_USAGE_COUNT(dev); 128 dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); 129 if (ret < 0) { 130 dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); 131 return ret; 132 } 133 if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) { 134 ret = sst_load_fw(ctx); 135 if (ret) { 136 dev_err(dev, "FW download fail %d\n", ret); 137 sst_set_fw_state_locked(ctx, SST_RESET); 138 ret = sst_pm_runtime_put(ctx); 139 } 140 } 141 } else { 142 usage_count = GET_USAGE_COUNT(dev); 143 dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count); 144 return sst_pm_runtime_put(ctx); 145 } 146 return ret; 147 } 148 149 /* 150 * sst_open_pcm_stream - Open PCM interface 151 * 152 * @str_param: parameters of pcm stream 153 * 154 * This function is called by MID sound card driver to open 155 * a new pcm interface 156 */ 157 static int sst_open_pcm_stream(struct device *dev, 158 struct snd_sst_params *str_param) 159 { 160 int retval; 161 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 162 163 if (!str_param) 164 return -EINVAL; 165 166 retval = sst_get_stream(ctx, str_param); 167 if (retval > 0) 168 ctx->stream_cnt++; 169 else 170 dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval); 171 172 return retval; 173 } 174 175 static int sst_cdev_open(struct device *dev, 176 struct snd_sst_params *str_params, struct sst_compress_cb *cb) 177 { 178 int str_id, retval; 179 struct stream_info *stream; 180 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 181 182 retval = pm_runtime_resume_and_get(ctx->dev); 183 if (retval < 0) 184 return retval; 185 186 str_id = sst_get_stream(ctx, str_params); 187 if (str_id > 0) { 188 dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id); 189 stream = &ctx->streams[str_id]; 190 stream->compr_cb = cb->compr_cb; 191 stream->compr_cb_param = cb->param; 192 stream->drain_notify = cb->drain_notify; 193 stream->drain_cb_param = cb->drain_cb_param; 194 } else { 195 dev_err(dev, "stream encountered error during alloc %d\n", str_id); 196 str_id = -EINVAL; 197 sst_pm_runtime_put(ctx); 198 } 199 return str_id; 200 } 201 202 static int sst_cdev_close(struct device *dev, unsigned int str_id) 203 { 204 int retval; 205 struct stream_info *stream; 206 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 207 208 stream = get_stream_info(ctx, str_id); 209 if (!stream) { 210 dev_err(dev, "stream info is NULL for str %d!!!\n", str_id); 211 return -EINVAL; 212 } 213 214 retval = sst_free_stream(ctx, str_id); 215 stream->compr_cb_param = NULL; 216 stream->compr_cb = NULL; 217 218 if (retval) 219 dev_err(dev, "free stream returned err %d\n", retval); 220 221 dev_dbg(dev, "End\n"); 222 return retval; 223 } 224 225 static int sst_cdev_ack(struct device *dev, unsigned int str_id, 226 unsigned long bytes) 227 { 228 struct stream_info *stream; 229 struct snd_sst_tstamp fw_tstamp = {0,}; 230 int offset; 231 void __iomem *addr; 232 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 233 234 stream = get_stream_info(ctx, str_id); 235 if (!stream) 236 return -EINVAL; 237 238 /* update bytes sent */ 239 stream->cumm_bytes += bytes; 240 dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes); 241 242 addr = ((void __iomem *)(ctx->mailbox + ctx->tstamp)) + 243 (str_id * sizeof(fw_tstamp)); 244 245 memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp)); 246 247 fw_tstamp.bytes_copied = stream->cumm_bytes; 248 dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n", 249 fw_tstamp.bytes_copied, bytes); 250 251 offset = offsetof(struct snd_sst_tstamp, bytes_copied); 252 sst_shim_write(addr, offset, fw_tstamp.bytes_copied); 253 return 0; 254 } 255 256 static int sst_cdev_set_metadata(struct device *dev, 257 unsigned int str_id, struct snd_compr_metadata *metadata) 258 { 259 int retval = 0; 260 struct stream_info *str_info; 261 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 262 263 dev_dbg(dev, "set metadata for stream %d\n", str_id); 264 265 str_info = get_stream_info(ctx, str_id); 266 if (!str_info) 267 return -EINVAL; 268 269 dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id); 270 retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD, 271 IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id, 272 sizeof(*metadata), metadata, NULL, 273 true, true, true, false); 274 275 return retval; 276 } 277 278 static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id) 279 { 280 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 281 282 return sst_pause_stream(ctx, str_id); 283 } 284 285 static int sst_cdev_stream_pause_release(struct device *dev, 286 unsigned int str_id) 287 { 288 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 289 290 return sst_resume_stream(ctx, str_id); 291 } 292 293 static int sst_cdev_stream_start(struct device *dev, unsigned int str_id) 294 { 295 struct stream_info *str_info; 296 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 297 298 str_info = get_stream_info(ctx, str_id); 299 if (!str_info) 300 return -EINVAL; 301 str_info->prev = str_info->status; 302 str_info->status = STREAM_RUNNING; 303 return sst_start_stream(ctx, str_id); 304 } 305 306 static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id) 307 { 308 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 309 310 return sst_drop_stream(ctx, str_id); 311 } 312 313 static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id) 314 { 315 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 316 317 return sst_drain_stream(ctx, str_id, false); 318 } 319 320 static int sst_cdev_stream_partial_drain(struct device *dev, 321 unsigned int str_id) 322 { 323 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 324 325 return sst_drain_stream(ctx, str_id, true); 326 } 327 328 static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, 329 struct snd_compr_tstamp64 *tstamp) 330 { 331 struct snd_sst_tstamp fw_tstamp = {0,}; 332 struct stream_info *stream; 333 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 334 void __iomem *addr; 335 336 addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) + 337 (str_id * sizeof(fw_tstamp)); 338 339 memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp)); 340 341 stream = get_stream_info(ctx, str_id); 342 if (!stream) 343 return -EINVAL; 344 dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter); 345 346 tstamp->copied_total = fw_tstamp.ring_buffer_counter; 347 tstamp->pcm_frames = fw_tstamp.frames_decoded; 348 tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, 349 (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24)); 350 tstamp->sampling_rate = fw_tstamp.sampling_frequency; 351 352 dev_dbg(dev, "PCM = %llu\n", tstamp->pcm_io_frames); 353 dev_dbg(dev, 354 "Ptr Query on strid = %d copied_total %llu, decodec %llu\n", 355 str_id, tstamp->copied_total, tstamp->pcm_frames); 356 dev_dbg(dev, "rendered %llu\n", tstamp->pcm_io_frames); 357 358 return 0; 359 } 360 361 static int sst_cdev_caps(struct snd_compr_caps *caps) 362 { 363 caps->num_codecs = NUM_CODEC; 364 caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */ 365 caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */ 366 caps->min_fragments = MIN_FRAGMENT; 367 caps->max_fragments = MAX_FRAGMENT; 368 caps->codecs[0] = SND_AUDIOCODEC_MP3; 369 caps->codecs[1] = SND_AUDIOCODEC_AAC; 370 return 0; 371 } 372 373 static const struct snd_compr_codec_caps caps_mp3 = { 374 .num_descriptors = 1, 375 .descriptor[0].max_ch = 2, 376 .descriptor[0].sample_rates[0] = 48000, 377 .descriptor[0].sample_rates[1] = 44100, 378 .descriptor[0].sample_rates[2] = 32000, 379 .descriptor[0].sample_rates[3] = 16000, 380 .descriptor[0].sample_rates[4] = 8000, 381 .descriptor[0].num_sample_rates = 5, 382 .descriptor[0].bit_rate[0] = 320, 383 .descriptor[0].bit_rate[1] = 192, 384 .descriptor[0].num_bitrates = 2, 385 .descriptor[0].profiles = 0, 386 .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, 387 .descriptor[0].formats = 0, 388 }; 389 390 static const struct snd_compr_codec_caps caps_aac = { 391 .num_descriptors = 2, 392 .descriptor[1].max_ch = 2, 393 .descriptor[0].sample_rates[0] = 48000, 394 .descriptor[0].sample_rates[1] = 44100, 395 .descriptor[0].sample_rates[2] = 32000, 396 .descriptor[0].sample_rates[3] = 16000, 397 .descriptor[0].sample_rates[4] = 8000, 398 .descriptor[0].num_sample_rates = 5, 399 .descriptor[1].bit_rate[0] = 320, 400 .descriptor[1].bit_rate[1] = 192, 401 .descriptor[1].num_bitrates = 2, 402 .descriptor[1].profiles = 0, 403 .descriptor[1].modes = 0, 404 .descriptor[1].formats = 405 (SND_AUDIOSTREAMFORMAT_MP4ADTS | 406 SND_AUDIOSTREAMFORMAT_RAW), 407 }; 408 409 static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec) 410 { 411 if (codec->codec == SND_AUDIOCODEC_MP3) 412 *codec = caps_mp3; 413 else if (codec->codec == SND_AUDIOCODEC_AAC) 414 *codec = caps_aac; 415 else 416 return -EINVAL; 417 418 return 0; 419 } 420 421 /* 422 * sst_close_pcm_stream - Close PCM interface 423 * 424 * @str_id: stream id to be closed 425 * 426 * This function is called by MID sound card driver to close 427 * an existing pcm interface 428 */ 429 static int sst_close_pcm_stream(struct device *dev, unsigned int str_id) 430 { 431 struct stream_info *stream; 432 int retval = 0; 433 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 434 435 stream = get_stream_info(ctx, str_id); 436 if (!stream) { 437 dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id); 438 return -EINVAL; 439 } 440 441 retval = free_stream_context(ctx, str_id); 442 stream->pcm_substream = NULL; 443 stream->status = STREAM_UN_INIT; 444 stream->period_elapsed = NULL; 445 ctx->stream_cnt--; 446 447 if (retval) 448 dev_err(ctx->dev, "free stream returned err %d\n", retval); 449 450 dev_dbg(ctx->dev, "Exit\n"); 451 return 0; 452 } 453 454 static inline int sst_calc_tstamp(struct intel_sst_drv *ctx, 455 struct pcm_stream_info *info, 456 struct snd_pcm_substream *substream, 457 struct snd_sst_tstamp *fw_tstamp) 458 { 459 size_t delay_bytes, delay_frames; 460 size_t buffer_sz; 461 u32 pointer_bytes, pointer_samples; 462 463 dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n", 464 fw_tstamp->ring_buffer_counter); 465 dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n", 466 fw_tstamp->hardware_counter); 467 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 468 delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter - 469 fw_tstamp->hardware_counter); 470 else 471 delay_bytes = (size_t) (fw_tstamp->hardware_counter - 472 fw_tstamp->ring_buffer_counter); 473 delay_frames = bytes_to_frames(substream->runtime, delay_bytes); 474 buffer_sz = snd_pcm_lib_buffer_bytes(substream); 475 div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes); 476 pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes); 477 478 dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes); 479 480 info->buffer_ptr = pointer_samples / substream->runtime->channels; 481 482 info->pcm_delay = delay_frames; 483 dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", 484 info->buffer_ptr, info->pcm_delay); 485 return 0; 486 } 487 488 static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info) 489 { 490 struct stream_info *stream; 491 struct snd_pcm_substream *substream; 492 struct snd_sst_tstamp fw_tstamp; 493 unsigned int str_id; 494 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 495 void __iomem *addr; 496 497 str_id = info->str_id; 498 stream = get_stream_info(ctx, str_id); 499 if (!stream) 500 return -EINVAL; 501 502 if (!stream->pcm_substream) 503 return -EINVAL; 504 substream = stream->pcm_substream; 505 506 addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) + 507 (str_id * sizeof(fw_tstamp)); 508 509 memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp)); 510 511 return sst_calc_tstamp(ctx, info, substream, &fw_tstamp); 512 } 513 514 static int sst_stream_start(struct device *dev, int str_id) 515 { 516 struct stream_info *str_info; 517 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 518 519 if (ctx->sst_state != SST_FW_RUNNING) 520 return 0; 521 str_info = get_stream_info(ctx, str_id); 522 if (!str_info) 523 return -EINVAL; 524 str_info->prev = str_info->status; 525 str_info->status = STREAM_RUNNING; 526 sst_start_stream(ctx, str_id); 527 528 return 0; 529 } 530 531 static int sst_stream_drop(struct device *dev, int str_id) 532 { 533 struct stream_info *str_info; 534 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 535 536 if (ctx->sst_state != SST_FW_RUNNING) 537 return 0; 538 539 str_info = get_stream_info(ctx, str_id); 540 if (!str_info) 541 return -EINVAL; 542 str_info->prev = STREAM_UN_INIT; 543 str_info->status = STREAM_INIT; 544 return sst_drop_stream(ctx, str_id); 545 } 546 547 static int sst_stream_pause(struct device *dev, int str_id) 548 { 549 struct stream_info *str_info; 550 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 551 552 if (ctx->sst_state != SST_FW_RUNNING) 553 return 0; 554 555 str_info = get_stream_info(ctx, str_id); 556 if (!str_info) 557 return -EINVAL; 558 559 return sst_pause_stream(ctx, str_id); 560 } 561 562 static int sst_stream_resume(struct device *dev, int str_id) 563 { 564 struct stream_info *str_info; 565 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 566 567 if (ctx->sst_state != SST_FW_RUNNING) 568 return 0; 569 570 str_info = get_stream_info(ctx, str_id); 571 if (!str_info) 572 return -EINVAL; 573 return sst_resume_stream(ctx, str_id); 574 } 575 576 static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) 577 { 578 int str_id = 0; 579 struct stream_info *stream; 580 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 581 582 str_id = str_info->str_id; 583 584 if (ctx->sst_state != SST_FW_RUNNING) 585 return 0; 586 587 stream = get_stream_info(ctx, str_id); 588 if (!stream) 589 return -EINVAL; 590 591 dev_dbg(ctx->dev, "setting the period ptrs\n"); 592 stream->pcm_substream = str_info->arg; 593 stream->period_elapsed = str_info->period_elapsed; 594 stream->sfreq = str_info->sfreq; 595 stream->prev = stream->status; 596 stream->status = STREAM_INIT; 597 dev_dbg(ctx->dev, 598 "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n", 599 stream->pcm_substream, stream->period_elapsed, 600 stream->sfreq, stream->status); 601 602 return 0; 603 } 604 605 /* 606 * sst_set_byte_stream - Set generic params 607 * 608 * @cmd: control cmd to be set 609 * @arg: command argument 610 * 611 * This function is called by MID sound card driver to configure 612 * SST runtime params. 613 */ 614 static int sst_send_byte_stream(struct device *dev, 615 struct snd_sst_bytes_v2 *bytes) 616 { 617 int ret_val = 0; 618 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 619 620 if (NULL == bytes) 621 return -EINVAL; 622 ret_val = pm_runtime_resume_and_get(ctx->dev); 623 if (ret_val < 0) 624 return ret_val; 625 626 ret_val = sst_send_byte_stream_mrfld(ctx, bytes); 627 sst_pm_runtime_put(ctx); 628 629 return ret_val; 630 } 631 632 static struct sst_ops pcm_ops = { 633 .open = sst_open_pcm_stream, 634 .stream_init = sst_stream_init, 635 .stream_start = sst_stream_start, 636 .stream_drop = sst_stream_drop, 637 .stream_pause = sst_stream_pause, 638 .stream_pause_release = sst_stream_resume, 639 .stream_read_tstamp = sst_read_timestamp, 640 .send_byte_stream = sst_send_byte_stream, 641 .close = sst_close_pcm_stream, 642 .power = sst_power_control, 643 }; 644 645 static struct compress_sst_ops compr_ops = { 646 .open = sst_cdev_open, 647 .close = sst_cdev_close, 648 .stream_pause = sst_cdev_stream_pause, 649 .stream_pause_release = sst_cdev_stream_pause_release, 650 .stream_start = sst_cdev_stream_start, 651 .stream_drop = sst_cdev_stream_drop, 652 .stream_drain = sst_cdev_stream_drain, 653 .stream_partial_drain = sst_cdev_stream_partial_drain, 654 .tstamp = sst_cdev_tstamp, 655 .ack = sst_cdev_ack, 656 .get_caps = sst_cdev_caps, 657 .get_codec_caps = sst_cdev_codec_caps, 658 .set_metadata = sst_cdev_set_metadata, 659 .power = sst_power_control, 660 }; 661 662 static struct sst_device sst_dsp_device = { 663 .name = "Intel(R) SST LPE", 664 .dev = NULL, 665 .ops = &pcm_ops, 666 .compr_ops = &compr_ops, 667 }; 668 669 /* 670 * sst_register - function to register DSP 671 * 672 * This functions registers DSP with the platform driver 673 */ 674 int sst_register(struct device *dev) 675 { 676 int ret_val; 677 678 sst_dsp_device.dev = dev; 679 ret_val = sst_register_dsp(&sst_dsp_device); 680 if (ret_val) 681 dev_err(dev, "Unable to register DSP with platform driver\n"); 682 683 return ret_val; 684 } 685 686 int sst_unregister(struct device *dev) 687 { 688 return sst_unregister_dsp(&sst_dsp_device); 689 } 690