1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. 3 // Copyright (c) 2018, Linaro Limited 4 5 #include <linux/mutex.h> 6 #include <linux/wait.h> 7 #include <linux/module.h> 8 #include <linux/soc/qcom/apr.h> 9 #include <linux/device.h> 10 #include <linux/of_platform.h> 11 #include <linux/spinlock.h> 12 #include <linux/kref.h> 13 #include <linux/of.h> 14 #include <uapi/sound/asound.h> 15 #include <uapi/sound/compress_params.h> 16 #include <linux/delay.h> 17 #include <linux/slab.h> 18 #include <linux/mm.h> 19 #include "q6asm.h" 20 #include "q6core.h" 21 #include "q6dsp-errno.h" 22 #include "q6dsp-common.h" 23 24 #define ASM_STREAM_CMD_CLOSE 0x00010BCD 25 #define ASM_STREAM_CMD_FLUSH 0x00010BCE 26 #define ASM_SESSION_CMD_PAUSE 0x00010BD3 27 #define ASM_DATA_CMD_EOS 0x00010BDB 28 #define ASM_NULL_POPP_TOPOLOGY 0x00010C68 29 #define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09 30 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10 31 #define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68 32 #define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92 33 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93 34 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94 35 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98 36 #define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99 37 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 38 #define ASM_SESSION_CMD_RUN_V2 0x00010DAA 39 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 40 #define ASM_MEDIA_FMT_MP3 0x00010BE9 41 #define ASM_MEDIA_FMT_FLAC 0x00010C16 42 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB 43 #define ASM_DATA_CMD_READ_V2 0x00010DAC 44 #define ASM_SESSION_CMD_SUSPEND 0x00010DEC 45 #define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3 46 #define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4 47 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A 48 #define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D 49 50 51 #define ASM_LEGACY_STREAM_SESSION 0 52 /* Bit shift for the stream_perf_mode subfield. */ 53 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29 54 #define ASM_END_POINT_DEVICE_MATRIX 0 55 #define ASM_DEFAULT_APP_TYPE 0 56 #define ASM_SYNC_IO_MODE 0x0001 57 #define ASM_ASYNC_IO_MODE 0x0002 58 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ 59 #define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */ 60 #define ASM_SHIFT_GAPLESS_MODE_FLAG 31 61 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3 62 63 struct avs_cmd_shared_mem_map_regions { 64 u16 mem_pool_id; 65 u16 num_regions; 66 u32 property_flag; 67 } __packed; 68 69 struct avs_shared_map_region_payload { 70 u32 shm_addr_lsw; 71 u32 shm_addr_msw; 72 u32 mem_size_bytes; 73 } __packed; 74 75 struct avs_cmd_shared_mem_unmap_regions { 76 u32 mem_map_handle; 77 } __packed; 78 79 struct asm_data_cmd_media_fmt_update_v2 { 80 u32 fmt_blk_size; 81 } __packed; 82 83 struct asm_multi_channel_pcm_fmt_blk_v2 { 84 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 85 u16 num_channels; 86 u16 bits_per_sample; 87 u32 sample_rate; 88 u16 is_signed; 89 u16 reserved; 90 u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; 91 } __packed; 92 93 struct asm_flac_fmt_blk_v2 { 94 struct asm_data_cmd_media_fmt_update_v2 fmt_blk; 95 u16 is_stream_info_present; 96 u16 num_channels; 97 u16 min_blk_size; 98 u16 max_blk_size; 99 u16 md5_sum[8]; 100 u32 sample_rate; 101 u32 min_frame_size; 102 u32 max_frame_size; 103 u16 sample_size; 104 u16 reserved; 105 } __packed; 106 107 struct asm_stream_cmd_set_encdec_param { 108 u32 param_id; 109 u32 param_size; 110 } __packed; 111 112 struct asm_enc_cfg_blk_param_v2 { 113 u32 frames_per_buf; 114 u32 enc_cfg_blk_size; 115 } __packed; 116 117 struct asm_multi_channel_pcm_enc_cfg_v2 { 118 struct asm_stream_cmd_set_encdec_param encdec; 119 struct asm_enc_cfg_blk_param_v2 encblk; 120 uint16_t num_channels; 121 uint16_t bits_per_sample; 122 uint32_t sample_rate; 123 uint16_t is_signed; 124 uint16_t reserved; 125 uint8_t channel_mapping[8]; 126 } __packed; 127 128 struct asm_data_cmd_read_v2 { 129 u32 buf_addr_lsw; 130 u32 buf_addr_msw; 131 u32 mem_map_handle; 132 u32 buf_size; 133 u32 seq_id; 134 } __packed; 135 136 struct asm_data_cmd_read_v2_done { 137 u32 status; 138 u32 buf_addr_lsw; 139 u32 buf_addr_msw; 140 }; 141 142 struct asm_stream_cmd_open_read_v3 { 143 u32 mode_flags; 144 u32 src_endpointype; 145 u32 preprocopo_id; 146 u32 enc_cfg_id; 147 u16 bits_per_sample; 148 u16 reserved; 149 } __packed; 150 151 struct asm_data_cmd_write_v2 { 152 u32 buf_addr_lsw; 153 u32 buf_addr_msw; 154 u32 mem_map_handle; 155 u32 buf_size; 156 u32 seq_id; 157 u32 timestamp_lsw; 158 u32 timestamp_msw; 159 u32 flags; 160 } __packed; 161 162 struct asm_stream_cmd_open_write_v3 { 163 uint32_t mode_flags; 164 uint16_t sink_endpointype; 165 uint16_t bits_per_sample; 166 uint32_t postprocopo_id; 167 uint32_t dec_fmt_id; 168 } __packed; 169 170 struct asm_session_cmd_run_v2 { 171 u32 flags; 172 u32 time_lsw; 173 u32 time_msw; 174 } __packed; 175 176 struct audio_buffer { 177 phys_addr_t phys; 178 uint32_t size; /* size of buffer */ 179 }; 180 181 struct audio_port_data { 182 struct audio_buffer *buf; 183 uint32_t num_periods; 184 uint32_t dsp_buf; 185 uint32_t mem_map_handle; 186 }; 187 188 struct q6asm { 189 struct apr_device *adev; 190 struct device *dev; 191 struct q6core_svc_api_info ainfo; 192 wait_queue_head_t mem_wait; 193 spinlock_t slock; 194 struct audio_client *session[MAX_SESSIONS + 1]; 195 }; 196 197 struct audio_client { 198 int session; 199 q6asm_cb cb; 200 void *priv; 201 uint32_t io_mode; 202 struct apr_device *adev; 203 struct mutex cmd_lock; 204 spinlock_t lock; 205 struct kref refcount; 206 /* idx:1 out port, 0: in port */ 207 struct audio_port_data port[2]; 208 wait_queue_head_t cmd_wait; 209 struct aprv2_ibasic_rsp_result_t result; 210 int perf_mode; 211 int stream_id; 212 struct q6asm *q6asm; 213 struct device *dev; 214 }; 215 216 static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, 217 uint32_t pkt_size, bool cmd_flg, 218 uint32_t stream_id) 219 { 220 hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD; 221 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id); 222 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id); 223 hdr->pkt_size = pkt_size; 224 if (cmd_flg) 225 hdr->token = ac->session; 226 } 227 228 static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac, 229 struct apr_pkt *pkt, uint32_t rsp_opcode) 230 { 231 struct apr_hdr *hdr = &pkt->hdr; 232 int rc; 233 234 mutex_lock(&ac->cmd_lock); 235 ac->result.opcode = 0; 236 ac->result.status = 0; 237 rc = apr_send_pkt(a->adev, pkt); 238 if (rc < 0) 239 goto err; 240 241 if (rsp_opcode) 242 rc = wait_event_timeout(a->mem_wait, 243 (ac->result.opcode == hdr->opcode) || 244 (ac->result.opcode == rsp_opcode), 245 5 * HZ); 246 else 247 rc = wait_event_timeout(a->mem_wait, 248 (ac->result.opcode == hdr->opcode), 249 5 * HZ); 250 251 if (!rc) { 252 dev_err(a->dev, "CMD timeout\n"); 253 rc = -ETIMEDOUT; 254 } else if (ac->result.status > 0) { 255 dev_err(a->dev, "DSP returned error[%x]\n", 256 ac->result.status); 257 rc = -EINVAL; 258 } 259 260 err: 261 mutex_unlock(&ac->cmd_lock); 262 return rc; 263 } 264 265 static int __q6asm_memory_unmap(struct audio_client *ac, 266 phys_addr_t buf_add, int dir) 267 { 268 struct avs_cmd_shared_mem_unmap_regions *mem_unmap; 269 struct q6asm *a = dev_get_drvdata(ac->dev->parent); 270 struct apr_pkt *pkt; 271 int rc, pkt_size; 272 void *p; 273 274 if (ac->port[dir].mem_map_handle == 0) { 275 dev_err(ac->dev, "invalid mem handle\n"); 276 return -EINVAL; 277 } 278 279 pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap); 280 p = kzalloc(pkt_size, GFP_KERNEL); 281 if (!p) 282 return -ENOMEM; 283 284 pkt = p; 285 mem_unmap = p + APR_HDR_SIZE; 286 287 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; 288 pkt->hdr.src_port = 0; 289 pkt->hdr.dest_port = 0; 290 pkt->hdr.pkt_size = pkt_size; 291 pkt->hdr.token = ((ac->session << 8) | dir); 292 293 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS; 294 mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle; 295 296 rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0); 297 if (rc < 0) { 298 kfree(pkt); 299 return rc; 300 } 301 302 ac->port[dir].mem_map_handle = 0; 303 304 kfree(pkt); 305 return 0; 306 } 307 308 309 static void q6asm_audio_client_free_buf(struct audio_client *ac, 310 struct audio_port_data *port) 311 { 312 unsigned long flags; 313 314 spin_lock_irqsave(&ac->lock, flags); 315 port->num_periods = 0; 316 kfree(port->buf); 317 port->buf = NULL; 318 spin_unlock_irqrestore(&ac->lock, flags); 319 } 320 321 /** 322 * q6asm_unmap_memory_regions() - unmap memory regions in the dsp. 323 * 324 * @dir: direction of audio stream 325 * @ac: audio client instanace 326 * 327 * Return: Will be an negative value on failure or zero on success 328 */ 329 int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac) 330 { 331 struct audio_port_data *port; 332 int cnt = 0; 333 int rc = 0; 334 335 port = &ac->port[dir]; 336 if (!port->buf) { 337 rc = -EINVAL; 338 goto err; 339 } 340 341 cnt = port->num_periods - 1; 342 if (cnt >= 0) { 343 rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir); 344 if (rc < 0) { 345 dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n", 346 __func__, rc); 347 goto err; 348 } 349 } 350 351 q6asm_audio_client_free_buf(ac, port); 352 353 err: 354 return rc; 355 } 356 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions); 357 358 static int __q6asm_memory_map_regions(struct audio_client *ac, int dir, 359 size_t period_sz, unsigned int periods, 360 bool is_contiguous) 361 { 362 struct avs_cmd_shared_mem_map_regions *cmd = NULL; 363 struct avs_shared_map_region_payload *mregions = NULL; 364 struct q6asm *a = dev_get_drvdata(ac->dev->parent); 365 struct audio_port_data *port = NULL; 366 struct audio_buffer *ab = NULL; 367 struct apr_pkt *pkt; 368 void *p; 369 unsigned long flags; 370 uint32_t num_regions, buf_sz; 371 int rc, i, pkt_size; 372 373 if (is_contiguous) { 374 num_regions = 1; 375 buf_sz = period_sz * periods; 376 } else { 377 buf_sz = period_sz; 378 num_regions = periods; 379 } 380 381 /* DSP expects size should be aligned to 4K */ 382 buf_sz = ALIGN(buf_sz, 4096); 383 384 pkt_size = APR_HDR_SIZE + sizeof(*cmd) + 385 (sizeof(*mregions) * num_regions); 386 387 p = kzalloc(pkt_size, GFP_KERNEL); 388 if (!p) 389 return -ENOMEM; 390 391 pkt = p; 392 cmd = p + APR_HDR_SIZE; 393 mregions = p + APR_HDR_SIZE + sizeof(*cmd); 394 395 pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; 396 pkt->hdr.src_port = 0; 397 pkt->hdr.dest_port = 0; 398 pkt->hdr.pkt_size = pkt_size; 399 pkt->hdr.token = ((ac->session << 8) | dir); 400 pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS; 401 402 cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL; 403 cmd->num_regions = num_regions; 404 cmd->property_flag = 0x00; 405 406 spin_lock_irqsave(&ac->lock, flags); 407 port = &ac->port[dir]; 408 409 for (i = 0; i < num_regions; i++) { 410 ab = &port->buf[i]; 411 mregions->shm_addr_lsw = lower_32_bits(ab->phys); 412 mregions->shm_addr_msw = upper_32_bits(ab->phys); 413 mregions->mem_size_bytes = buf_sz; 414 ++mregions; 415 } 416 spin_unlock_irqrestore(&ac->lock, flags); 417 418 rc = q6asm_apr_send_session_pkt(a, ac, pkt, 419 ASM_CMDRSP_SHARED_MEM_MAP_REGIONS); 420 421 kfree(pkt); 422 423 return rc; 424 } 425 426 /** 427 * q6asm_map_memory_regions() - map memory regions in the dsp. 428 * 429 * @dir: direction of audio stream 430 * @ac: audio client instanace 431 * @phys: physcial address that needs mapping. 432 * @period_sz: audio period size 433 * @periods: number of periods 434 * 435 * Return: Will be an negative value on failure or zero on success 436 */ 437 int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, 438 phys_addr_t phys, 439 size_t period_sz, unsigned int periods) 440 { 441 struct audio_buffer *buf; 442 unsigned long flags; 443 int cnt; 444 int rc; 445 446 spin_lock_irqsave(&ac->lock, flags); 447 if (ac->port[dir].buf) { 448 dev_err(ac->dev, "Buffer already allocated\n"); 449 spin_unlock_irqrestore(&ac->lock, flags); 450 return 0; 451 } 452 453 buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC); 454 if (!buf) { 455 spin_unlock_irqrestore(&ac->lock, flags); 456 return -ENOMEM; 457 } 458 459 460 ac->port[dir].buf = buf; 461 462 buf[0].phys = phys; 463 buf[0].size = period_sz; 464 465 for (cnt = 1; cnt < periods; cnt++) { 466 if (period_sz > 0) { 467 buf[cnt].phys = buf[0].phys + (cnt * period_sz); 468 buf[cnt].size = period_sz; 469 } 470 } 471 ac->port[dir].num_periods = periods; 472 473 spin_unlock_irqrestore(&ac->lock, flags); 474 475 rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1); 476 if (rc < 0) { 477 dev_err(ac->dev, "Memory_map_regions failed\n"); 478 q6asm_audio_client_free_buf(ac, &ac->port[dir]); 479 } 480 481 return rc; 482 } 483 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions); 484 485 static void q6asm_audio_client_release(struct kref *ref) 486 { 487 struct audio_client *ac; 488 struct q6asm *a; 489 unsigned long flags; 490 491 ac = container_of(ref, struct audio_client, refcount); 492 a = ac->q6asm; 493 494 spin_lock_irqsave(&a->slock, flags); 495 a->session[ac->session] = NULL; 496 spin_unlock_irqrestore(&a->slock, flags); 497 498 kfree(ac); 499 } 500 501 /** 502 * q6asm_audio_client_free() - Freee allocated audio client 503 * 504 * @ac: audio client to free 505 */ 506 void q6asm_audio_client_free(struct audio_client *ac) 507 { 508 kref_put(&ac->refcount, q6asm_audio_client_release); 509 } 510 EXPORT_SYMBOL_GPL(q6asm_audio_client_free); 511 512 static struct audio_client *q6asm_get_audio_client(struct q6asm *a, 513 int session_id) 514 { 515 struct audio_client *ac = NULL; 516 unsigned long flags; 517 518 spin_lock_irqsave(&a->slock, flags); 519 if ((session_id <= 0) || (session_id > MAX_SESSIONS)) { 520 dev_err(a->dev, "invalid session: %d\n", session_id); 521 goto err; 522 } 523 524 /* check for valid session */ 525 if (!a->session[session_id]) 526 goto err; 527 else if (a->session[session_id]->session != session_id) 528 goto err; 529 530 ac = a->session[session_id]; 531 kref_get(&ac->refcount); 532 err: 533 spin_unlock_irqrestore(&a->slock, flags); 534 return ac; 535 } 536 537 static int32_t q6asm_stream_callback(struct apr_device *adev, 538 struct apr_resp_pkt *data, 539 int session_id) 540 { 541 struct q6asm *q6asm = dev_get_drvdata(&adev->dev); 542 struct aprv2_ibasic_rsp_result_t *result; 543 struct apr_hdr *hdr = &data->hdr; 544 struct audio_port_data *port; 545 struct audio_client *ac; 546 uint32_t client_event = 0; 547 int ret = 0; 548 549 ac = q6asm_get_audio_client(q6asm, session_id); 550 if (!ac)/* Audio client might already be freed by now */ 551 return 0; 552 553 result = data->payload; 554 555 switch (hdr->opcode) { 556 case APR_BASIC_RSP_RESULT: 557 switch (result->opcode) { 558 case ASM_SESSION_CMD_PAUSE: 559 client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE; 560 break; 561 case ASM_SESSION_CMD_SUSPEND: 562 client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE; 563 break; 564 case ASM_DATA_CMD_EOS: 565 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE; 566 break; 567 case ASM_STREAM_CMD_FLUSH: 568 client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE; 569 break; 570 case ASM_SESSION_CMD_RUN_V2: 571 client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE; 572 break; 573 case ASM_STREAM_CMD_CLOSE: 574 client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE; 575 break; 576 case ASM_STREAM_CMD_FLUSH_READBUFS: 577 client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE; 578 break; 579 case ASM_STREAM_CMD_OPEN_WRITE_V3: 580 case ASM_STREAM_CMD_OPEN_READ_V3: 581 case ASM_STREAM_CMD_OPEN_READWRITE_V2: 582 case ASM_STREAM_CMD_SET_ENCDEC_PARAM: 583 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: 584 if (result->status != 0) { 585 dev_err(ac->dev, 586 "cmd = 0x%x returned error = 0x%x\n", 587 result->opcode, result->status); 588 ac->result = *result; 589 wake_up(&ac->cmd_wait); 590 ret = 0; 591 goto done; 592 } 593 break; 594 default: 595 dev_err(ac->dev, "command[0x%x] not expecting rsp\n", 596 result->opcode); 597 break; 598 } 599 600 ac->result = *result; 601 wake_up(&ac->cmd_wait); 602 603 if (ac->cb) 604 ac->cb(client_event, hdr->token, 605 data->payload, ac->priv); 606 607 ret = 0; 608 goto done; 609 610 case ASM_DATA_EVENT_WRITE_DONE_V2: 611 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE; 612 if (ac->io_mode & ASM_SYNC_IO_MODE) { 613 phys_addr_t phys; 614 unsigned long flags; 615 616 spin_lock_irqsave(&ac->lock, flags); 617 618 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 619 620 if (!port->buf) { 621 spin_unlock_irqrestore(&ac->lock, flags); 622 ret = 0; 623 goto done; 624 } 625 626 phys = port->buf[hdr->token].phys; 627 628 if (lower_32_bits(phys) != result->opcode || 629 upper_32_bits(phys) != result->status) { 630 dev_err(ac->dev, "Expected addr %pa\n", 631 &port->buf[hdr->token].phys); 632 spin_unlock_irqrestore(&ac->lock, flags); 633 ret = -EINVAL; 634 goto done; 635 } 636 spin_unlock_irqrestore(&ac->lock, flags); 637 } 638 break; 639 case ASM_DATA_EVENT_READ_DONE_V2: 640 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE; 641 if (ac->io_mode & ASM_SYNC_IO_MODE) { 642 struct asm_data_cmd_read_v2_done *done = data->payload; 643 unsigned long flags; 644 phys_addr_t phys; 645 646 spin_lock_irqsave(&ac->lock, flags); 647 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 648 if (!port->buf) { 649 spin_unlock_irqrestore(&ac->lock, flags); 650 ret = 0; 651 goto done; 652 } 653 654 phys = port->buf[hdr->token].phys; 655 656 if (upper_32_bits(phys) != done->buf_addr_msw || 657 lower_32_bits(phys) != done->buf_addr_lsw) { 658 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n", 659 &port->buf[hdr->token].phys, 660 done->buf_addr_lsw, 661 done->buf_addr_msw); 662 spin_unlock_irqrestore(&ac->lock, flags); 663 ret = -EINVAL; 664 goto done; 665 } 666 spin_unlock_irqrestore(&ac->lock, flags); 667 } 668 669 break; 670 } 671 672 if (ac->cb) 673 ac->cb(client_event, hdr->token, data->payload, ac->priv); 674 675 done: 676 kref_put(&ac->refcount, q6asm_audio_client_release); 677 return ret; 678 } 679 680 static int q6asm_srvc_callback(struct apr_device *adev, 681 struct apr_resp_pkt *data) 682 { 683 struct q6asm *q6asm = dev_get_drvdata(&adev->dev); 684 struct aprv2_ibasic_rsp_result_t *result; 685 struct audio_port_data *port; 686 struct audio_client *ac = NULL; 687 struct apr_hdr *hdr = &data->hdr; 688 struct q6asm *a; 689 uint32_t sid = 0; 690 uint32_t dir = 0; 691 int session_id; 692 693 session_id = (hdr->dest_port >> 8) & 0xFF; 694 if (session_id) 695 return q6asm_stream_callback(adev, data, session_id); 696 697 sid = (hdr->token >> 8) & 0x0F; 698 ac = q6asm_get_audio_client(q6asm, sid); 699 if (!ac) { 700 dev_err(&adev->dev, "Audio Client not active\n"); 701 return 0; 702 } 703 704 a = dev_get_drvdata(ac->dev->parent); 705 dir = (hdr->token & 0x0F); 706 port = &ac->port[dir]; 707 result = data->payload; 708 709 switch (hdr->opcode) { 710 case APR_BASIC_RSP_RESULT: 711 switch (result->opcode) { 712 case ASM_CMD_SHARED_MEM_MAP_REGIONS: 713 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: 714 ac->result = *result; 715 wake_up(&a->mem_wait); 716 break; 717 default: 718 dev_err(&adev->dev, "command[0x%x] not expecting rsp\n", 719 result->opcode); 720 break; 721 } 722 goto done; 723 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS: 724 ac->result.status = 0; 725 ac->result.opcode = hdr->opcode; 726 port->mem_map_handle = result->opcode; 727 wake_up(&a->mem_wait); 728 break; 729 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: 730 ac->result.opcode = hdr->opcode; 731 ac->result.status = 0; 732 port->mem_map_handle = 0; 733 wake_up(&a->mem_wait); 734 break; 735 default: 736 dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n", 737 result->opcode, result->status); 738 break; 739 } 740 741 if (ac->cb) 742 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv); 743 744 done: 745 kref_put(&ac->refcount, q6asm_audio_client_release); 746 747 return 0; 748 } 749 750 /** 751 * q6asm_get_session_id() - get session id for audio client 752 * 753 * @c: audio client pointer 754 * 755 * Return: Will be an session id of the audio client. 756 */ 757 int q6asm_get_session_id(struct audio_client *c) 758 { 759 return c->session; 760 } 761 EXPORT_SYMBOL_GPL(q6asm_get_session_id); 762 763 /** 764 * q6asm_audio_client_alloc() - Allocate a new audio client 765 * 766 * @dev: Pointer to asm child device. 767 * @cb: event callback. 768 * @priv: private data associated with this client. 769 * @stream_id: stream id 770 * @perf_mode: performace mode for this client 771 * 772 * Return: Will be an error pointer on error or a valid audio client 773 * on success. 774 */ 775 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, 776 void *priv, int stream_id, 777 int perf_mode) 778 { 779 struct q6asm *a = dev_get_drvdata(dev->parent); 780 struct audio_client *ac; 781 unsigned long flags; 782 783 ac = q6asm_get_audio_client(a, stream_id + 1); 784 if (ac) { 785 dev_err(dev, "Audio Client already active\n"); 786 return ac; 787 } 788 789 ac = kzalloc(sizeof(*ac), GFP_KERNEL); 790 if (!ac) 791 return ERR_PTR(-ENOMEM); 792 793 spin_lock_irqsave(&a->slock, flags); 794 a->session[stream_id + 1] = ac; 795 spin_unlock_irqrestore(&a->slock, flags); 796 ac->session = stream_id + 1; 797 ac->cb = cb; 798 ac->dev = dev; 799 ac->q6asm = a; 800 ac->priv = priv; 801 ac->io_mode = ASM_SYNC_IO_MODE; 802 ac->perf_mode = perf_mode; 803 /* DSP expects stream id from 1 */ 804 ac->stream_id = 1; 805 ac->adev = a->adev; 806 kref_init(&ac->refcount); 807 808 init_waitqueue_head(&ac->cmd_wait); 809 mutex_init(&ac->cmd_lock); 810 spin_lock_init(&ac->lock); 811 812 return ac; 813 } 814 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); 815 816 static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt) 817 { 818 struct apr_hdr *hdr = &pkt->hdr; 819 int rc; 820 821 mutex_lock(&ac->cmd_lock); 822 ac->result.opcode = 0; 823 ac->result.status = 0; 824 825 rc = apr_send_pkt(ac->adev, pkt); 826 if (rc < 0) 827 goto err; 828 829 rc = wait_event_timeout(ac->cmd_wait, 830 (ac->result.opcode == hdr->opcode), 5 * HZ); 831 if (!rc) { 832 dev_err(ac->dev, "CMD timeout\n"); 833 rc = -ETIMEDOUT; 834 goto err; 835 } 836 837 if (ac->result.status > 0) { 838 dev_err(ac->dev, "DSP returned error[%x]\n", 839 ac->result.status); 840 rc = -EINVAL; 841 } else { 842 rc = 0; 843 } 844 845 846 err: 847 mutex_unlock(&ac->cmd_lock); 848 return rc; 849 } 850 851 /** 852 * q6asm_open_write() - Open audio client for writing 853 * 854 * @ac: audio client pointer 855 * @format: audio sample format 856 * @bits_per_sample: bits per sample 857 * 858 * Return: Will be an negative value on error or zero on success 859 */ 860 int q6asm_open_write(struct audio_client *ac, uint32_t format, 861 uint16_t bits_per_sample) 862 { 863 struct asm_stream_cmd_open_write_v3 *open; 864 struct apr_pkt *pkt; 865 void *p; 866 int rc, pkt_size; 867 868 pkt_size = APR_HDR_SIZE + sizeof(*open); 869 870 p = kzalloc(pkt_size, GFP_KERNEL); 871 if (!p) 872 return -ENOMEM; 873 874 pkt = p; 875 open = p + APR_HDR_SIZE; 876 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 877 878 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; 879 open->mode_flags = 0x00; 880 open->mode_flags |= ASM_LEGACY_STREAM_SESSION; 881 882 /* source endpoint : matrix */ 883 open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; 884 open->bits_per_sample = bits_per_sample; 885 open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; 886 887 switch (format) { 888 case SND_AUDIOCODEC_MP3: 889 open->dec_fmt_id = ASM_MEDIA_FMT_MP3; 890 break; 891 case FORMAT_LINEAR_PCM: 892 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 893 break; 894 case SND_AUDIOCODEC_FLAC: 895 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC; 896 break; 897 default: 898 dev_err(ac->dev, "Invalid format 0x%x\n", format); 899 rc = -EINVAL; 900 goto err; 901 } 902 903 rc = q6asm_ac_send_cmd_sync(ac, pkt); 904 if (rc < 0) 905 goto err; 906 907 ac->io_mode |= ASM_TUN_WRITE_IO_MODE; 908 909 err: 910 kfree(pkt); 911 return rc; 912 } 913 EXPORT_SYMBOL_GPL(q6asm_open_write); 914 915 static int __q6asm_run(struct audio_client *ac, uint32_t flags, 916 uint32_t msw_ts, uint32_t lsw_ts, bool wait) 917 { 918 struct asm_session_cmd_run_v2 *run; 919 struct apr_pkt *pkt; 920 int pkt_size, rc; 921 void *p; 922 923 pkt_size = APR_HDR_SIZE + sizeof(*run); 924 p = kzalloc(pkt_size, GFP_ATOMIC); 925 if (!p) 926 return -ENOMEM; 927 928 pkt = p; 929 run = p + APR_HDR_SIZE; 930 931 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 932 933 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; 934 run->flags = flags; 935 run->time_lsw = lsw_ts; 936 run->time_msw = msw_ts; 937 if (wait) { 938 rc = q6asm_ac_send_cmd_sync(ac, pkt); 939 } else { 940 rc = apr_send_pkt(ac->adev, pkt); 941 if (rc == pkt_size) 942 rc = 0; 943 } 944 945 kfree(pkt); 946 return rc; 947 } 948 949 /** 950 * q6asm_run() - start the audio client 951 * 952 * @ac: audio client pointer 953 * @flags: flags associated with write 954 * @msw_ts: timestamp msw 955 * @lsw_ts: timestamp lsw 956 * 957 * Return: Will be an negative value on error or zero on success 958 */ 959 int q6asm_run(struct audio_client *ac, uint32_t flags, 960 uint32_t msw_ts, uint32_t lsw_ts) 961 { 962 return __q6asm_run(ac, flags, msw_ts, lsw_ts, true); 963 } 964 EXPORT_SYMBOL_GPL(q6asm_run); 965 966 /** 967 * q6asm_run_nowait() - start the audio client withou blocking 968 * 969 * @ac: audio client pointer 970 * @flags: flags associated with write 971 * @msw_ts: timestamp msw 972 * @lsw_ts: timestamp lsw 973 * 974 * Return: Will be an negative value on error or zero on success 975 */ 976 int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, 977 uint32_t msw_ts, uint32_t lsw_ts) 978 { 979 return __q6asm_run(ac, flags, msw_ts, lsw_ts, false); 980 } 981 EXPORT_SYMBOL_GPL(q6asm_run_nowait); 982 983 /** 984 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration 985 * 986 * @ac: audio client pointer 987 * @rate: audio sample rate 988 * @channels: number of audio channels. 989 * @channel_map: channel map pointer 990 * @bits_per_sample: bits per sample 991 * 992 * Return: Will be an negative value on error or zero on success 993 */ 994 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, 995 uint32_t rate, uint32_t channels, 996 u8 channel_map[PCM_MAX_NUM_CHANNEL], 997 uint16_t bits_per_sample) 998 { 999 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt; 1000 struct apr_pkt *pkt; 1001 u8 *channel_mapping; 1002 void *p; 1003 int rc, pkt_size; 1004 1005 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1006 p = kzalloc(pkt_size, GFP_KERNEL); 1007 if (!p) 1008 return -ENOMEM; 1009 1010 pkt = p; 1011 fmt = p + APR_HDR_SIZE; 1012 1013 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 1014 1015 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1016 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1017 fmt->num_channels = channels; 1018 fmt->bits_per_sample = bits_per_sample; 1019 fmt->sample_rate = rate; 1020 fmt->is_signed = 1; 1021 1022 channel_mapping = fmt->channel_mapping; 1023 1024 if (channel_map) { 1025 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL); 1026 } else { 1027 if (q6dsp_map_channels(channel_mapping, channels)) { 1028 dev_err(ac->dev, " map channels failed %d\n", channels); 1029 rc = -EINVAL; 1030 goto err; 1031 } 1032 } 1033 1034 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1035 1036 err: 1037 kfree(pkt); 1038 return rc; 1039 } 1040 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); 1041 1042 1043 int q6asm_stream_media_format_block_flac(struct audio_client *ac, 1044 struct q6asm_flac_cfg *cfg) 1045 { 1046 struct asm_flac_fmt_blk_v2 *fmt; 1047 struct apr_pkt *pkt; 1048 void *p; 1049 int rc, pkt_size; 1050 1051 pkt_size = APR_HDR_SIZE + sizeof(*fmt); 1052 p = kzalloc(pkt_size, GFP_KERNEL); 1053 if (!p) 1054 return -ENOMEM; 1055 1056 pkt = p; 1057 fmt = p + APR_HDR_SIZE; 1058 1059 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 1060 1061 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; 1062 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); 1063 fmt->is_stream_info_present = cfg->stream_info_present; 1064 fmt->num_channels = cfg->ch_cfg; 1065 fmt->min_blk_size = cfg->min_blk_size; 1066 fmt->max_blk_size = cfg->max_blk_size; 1067 fmt->sample_rate = cfg->sample_rate; 1068 fmt->min_frame_size = cfg->min_frame_size; 1069 fmt->max_frame_size = cfg->max_frame_size; 1070 fmt->sample_size = cfg->sample_size; 1071 1072 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1073 kfree(pkt); 1074 1075 return rc; 1076 } 1077 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); 1078 /** 1079 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture 1080 * 1081 * @ac: audio client pointer 1082 * @rate: audio sample rate 1083 * @channels: number of audio channels. 1084 * @bits_per_sample: bits per sample 1085 * 1086 * Return: Will be an negative value on error or zero on success 1087 */ 1088 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, 1089 uint32_t rate, uint32_t channels, uint16_t bits_per_sample) 1090 { 1091 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; 1092 struct apr_pkt *pkt; 1093 u8 *channel_mapping; 1094 u32 frames_per_buf = 0; 1095 int pkt_size, rc; 1096 void *p; 1097 1098 pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg); 1099 p = kzalloc(pkt_size, GFP_KERNEL); 1100 if (!p) 1101 return -ENOMEM; 1102 1103 pkt = p; 1104 enc_cfg = p + APR_HDR_SIZE; 1105 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 1106 1107 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; 1108 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; 1109 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec); 1110 enc_cfg->encblk.frames_per_buf = frames_per_buf; 1111 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size - 1112 sizeof(struct asm_enc_cfg_blk_param_v2); 1113 1114 enc_cfg->num_channels = channels; 1115 enc_cfg->bits_per_sample = bits_per_sample; 1116 enc_cfg->sample_rate = rate; 1117 enc_cfg->is_signed = 1; 1118 channel_mapping = enc_cfg->channel_mapping; 1119 1120 if (q6dsp_map_channels(channel_mapping, channels)) { 1121 rc = -EINVAL; 1122 goto err; 1123 } 1124 1125 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1126 err: 1127 kfree(pkt); 1128 return rc; 1129 } 1130 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); 1131 1132 1133 /** 1134 * q6asm_read() - read data of period size from audio client 1135 * 1136 * @ac: audio client pointer 1137 * 1138 * Return: Will be an negative value on error or zero on success 1139 */ 1140 int q6asm_read(struct audio_client *ac) 1141 { 1142 struct asm_data_cmd_read_v2 *read; 1143 struct audio_port_data *port; 1144 struct audio_buffer *ab; 1145 struct apr_pkt *pkt; 1146 unsigned long flags; 1147 int pkt_size; 1148 int rc = 0; 1149 void *p; 1150 1151 pkt_size = APR_HDR_SIZE + sizeof(*read); 1152 p = kzalloc(pkt_size, GFP_ATOMIC); 1153 if (!p) 1154 return -ENOMEM; 1155 1156 pkt = p; 1157 read = p + APR_HDR_SIZE; 1158 1159 spin_lock_irqsave(&ac->lock, flags); 1160 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1161 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); 1162 ab = &port->buf[port->dsp_buf]; 1163 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; 1164 read->buf_addr_lsw = lower_32_bits(ab->phys); 1165 read->buf_addr_msw = upper_32_bits(ab->phys); 1166 read->mem_map_handle = port->mem_map_handle; 1167 1168 read->buf_size = ab->size; 1169 read->seq_id = port->dsp_buf; 1170 pkt->hdr.token = port->dsp_buf; 1171 1172 port->dsp_buf++; 1173 1174 if (port->dsp_buf >= port->num_periods) 1175 port->dsp_buf = 0; 1176 1177 spin_unlock_irqrestore(&ac->lock, flags); 1178 rc = apr_send_pkt(ac->adev, pkt); 1179 if (rc == pkt_size) 1180 rc = 0; 1181 else 1182 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc); 1183 1184 kfree(pkt); 1185 return rc; 1186 } 1187 EXPORT_SYMBOL_GPL(q6asm_read); 1188 1189 static int __q6asm_open_read(struct audio_client *ac, 1190 uint32_t format, uint16_t bits_per_sample) 1191 { 1192 struct asm_stream_cmd_open_read_v3 *open; 1193 struct apr_pkt *pkt; 1194 int pkt_size, rc; 1195 void *p; 1196 1197 pkt_size = APR_HDR_SIZE + sizeof(*open); 1198 p = kzalloc(pkt_size, GFP_KERNEL); 1199 if (!p) 1200 return -ENOMEM; 1201 1202 pkt = p; 1203 open = p + APR_HDR_SIZE; 1204 1205 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); 1206 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; 1207 /* Stream prio : High, provide meta info with encoded frames */ 1208 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; 1209 1210 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE; 1211 open->bits_per_sample = bits_per_sample; 1212 open->mode_flags = 0x0; 1213 1214 open->mode_flags |= ASM_LEGACY_STREAM_SESSION << 1215 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ; 1216 1217 switch (format) { 1218 case FORMAT_LINEAR_PCM: 1219 open->mode_flags |= 0x00; 1220 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; 1221 break; 1222 default: 1223 pr_err("Invalid format[%d]\n", format); 1224 } 1225 1226 rc = q6asm_ac_send_cmd_sync(ac, pkt); 1227 1228 kfree(pkt); 1229 return rc; 1230 } 1231 1232 /** 1233 * q6asm_open_read() - Open audio client for reading 1234 * 1235 * @ac: audio client pointer 1236 * @format: audio sample format 1237 * @bits_per_sample: bits per sample 1238 * 1239 * Return: Will be an negative value on error or zero on success 1240 */ 1241 int q6asm_open_read(struct audio_client *ac, uint32_t format, 1242 uint16_t bits_per_sample) 1243 { 1244 return __q6asm_open_read(ac, format, bits_per_sample); 1245 } 1246 EXPORT_SYMBOL_GPL(q6asm_open_read); 1247 1248 /** 1249 * q6asm_write_async() - non blocking write 1250 * 1251 * @ac: audio client pointer 1252 * @len: length in bytes 1253 * @msw_ts: timestamp msw 1254 * @lsw_ts: timestamp lsw 1255 * @wflags: flags associated with write 1256 * 1257 * Return: Will be an negative value on error or zero on success 1258 */ 1259 int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, 1260 uint32_t lsw_ts, uint32_t wflags) 1261 { 1262 struct asm_data_cmd_write_v2 *write; 1263 struct audio_port_data *port; 1264 struct audio_buffer *ab; 1265 unsigned long flags; 1266 struct apr_pkt *pkt; 1267 int pkt_size; 1268 int rc = 0; 1269 void *p; 1270 1271 pkt_size = APR_HDR_SIZE + sizeof(*write); 1272 p = kzalloc(pkt_size, GFP_ATOMIC); 1273 if (!p) 1274 return -ENOMEM; 1275 1276 pkt = p; 1277 write = p + APR_HDR_SIZE; 1278 1279 spin_lock_irqsave(&ac->lock, flags); 1280 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1281 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); 1282 1283 ab = &port->buf[port->dsp_buf]; 1284 pkt->hdr.token = port->dsp_buf; 1285 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; 1286 write->buf_addr_lsw = lower_32_bits(ab->phys); 1287 write->buf_addr_msw = upper_32_bits(ab->phys); 1288 write->buf_size = len; 1289 write->seq_id = port->dsp_buf; 1290 write->timestamp_lsw = lsw_ts; 1291 write->timestamp_msw = msw_ts; 1292 write->mem_map_handle = 1293 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; 1294 1295 if (wflags == NO_TIMESTAMP) 1296 write->flags = (wflags & 0x800000FF); 1297 else 1298 write->flags = (0x80000000 | wflags); 1299 1300 port->dsp_buf++; 1301 1302 if (port->dsp_buf >= port->num_periods) 1303 port->dsp_buf = 0; 1304 1305 spin_unlock_irqrestore(&ac->lock, flags); 1306 rc = apr_send_pkt(ac->adev, pkt); 1307 if (rc == pkt_size) 1308 rc = 0; 1309 1310 kfree(pkt); 1311 return rc; 1312 } 1313 EXPORT_SYMBOL_GPL(q6asm_write_async); 1314 1315 static void q6asm_reset_buf_state(struct audio_client *ac) 1316 { 1317 struct audio_port_data *port = NULL; 1318 unsigned long flags; 1319 1320 spin_lock_irqsave(&ac->lock, flags); 1321 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; 1322 port->dsp_buf = 0; 1323 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; 1324 port->dsp_buf = 0; 1325 spin_unlock_irqrestore(&ac->lock, flags); 1326 } 1327 1328 static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait) 1329 { 1330 int stream_id = ac->stream_id; 1331 struct apr_pkt pkt; 1332 int rc; 1333 1334 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id); 1335 1336 switch (cmd) { 1337 case CMD_PAUSE: 1338 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE; 1339 break; 1340 case CMD_SUSPEND: 1341 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND; 1342 break; 1343 case CMD_FLUSH: 1344 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH; 1345 break; 1346 case CMD_OUT_FLUSH: 1347 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS; 1348 break; 1349 case CMD_EOS: 1350 pkt.hdr.opcode = ASM_DATA_CMD_EOS; 1351 break; 1352 case CMD_CLOSE: 1353 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE; 1354 break; 1355 default: 1356 return -EINVAL; 1357 } 1358 1359 if (wait) 1360 rc = q6asm_ac_send_cmd_sync(ac, &pkt); 1361 else 1362 return apr_send_pkt(ac->adev, &pkt); 1363 1364 if (rc < 0) 1365 return rc; 1366 1367 if (cmd == CMD_FLUSH) 1368 q6asm_reset_buf_state(ac); 1369 1370 return 0; 1371 } 1372 1373 /** 1374 * q6asm_cmd() - run cmd on audio client 1375 * 1376 * @ac: audio client pointer 1377 * @cmd: command to run on audio client. 1378 * 1379 * Return: Will be an negative value on error or zero on success 1380 */ 1381 int q6asm_cmd(struct audio_client *ac, int cmd) 1382 { 1383 return __q6asm_cmd(ac, cmd, true); 1384 } 1385 EXPORT_SYMBOL_GPL(q6asm_cmd); 1386 1387 /** 1388 * q6asm_cmd_nowait() - non blocking, run cmd on audio client 1389 * 1390 * @ac: audio client pointer 1391 * @cmd: command to run on audio client. 1392 * 1393 * Return: Will be an negative value on error or zero on success 1394 */ 1395 int q6asm_cmd_nowait(struct audio_client *ac, int cmd) 1396 { 1397 return __q6asm_cmd(ac, cmd, false); 1398 } 1399 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); 1400 1401 static int q6asm_probe(struct apr_device *adev) 1402 { 1403 struct device *dev = &adev->dev; 1404 struct q6asm *q6asm; 1405 1406 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL); 1407 if (!q6asm) 1408 return -ENOMEM; 1409 1410 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo); 1411 1412 q6asm->dev = dev; 1413 q6asm->adev = adev; 1414 init_waitqueue_head(&q6asm->mem_wait); 1415 spin_lock_init(&q6asm->slock); 1416 dev_set_drvdata(dev, q6asm); 1417 1418 return of_platform_populate(dev->of_node, NULL, NULL, dev); 1419 } 1420 1421 static int q6asm_remove(struct apr_device *adev) 1422 { 1423 of_platform_depopulate(&adev->dev); 1424 1425 return 0; 1426 } 1427 static const struct of_device_id q6asm_device_id[] = { 1428 { .compatible = "qcom,q6asm" }, 1429 {}, 1430 }; 1431 MODULE_DEVICE_TABLE(of, q6asm_device_id); 1432 1433 static struct apr_driver qcom_q6asm_driver = { 1434 .probe = q6asm_probe, 1435 .remove = q6asm_remove, 1436 .callback = q6asm_srvc_callback, 1437 .driver = { 1438 .name = "qcom-q6asm", 1439 .of_match_table = of_match_ptr(q6asm_device_id), 1440 }, 1441 }; 1442 1443 module_apr_driver(qcom_q6asm_driver); 1444 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver"); 1445 MODULE_LICENSE("GPL v2"); 1446