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