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