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