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