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