1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
4
5 #include <linux/mutex.h>
6 #include <linux/wait.h>
7 #include <linux/module.h>
8 #include <linux/soc/qcom/apr.h>
9 #include <linux/device.h>
10 #include <linux/of_platform.h>
11 #include <linux/spinlock.h>
12 #include <linux/kref.h>
13 #include <linux/of.h>
14 #include <uapi/sound/asound.h>
15 #include <uapi/sound/compress_params.h>
16 #include <linux/delay.h>
17 #include <linux/slab.h>
18 #include <linux/mm.h>
19 #include "q6asm.h"
20 #include "q6core.h"
21 #include "q6dsp-errno.h"
22 #include "q6dsp-common.h"
23
24 #define ASM_STREAM_CMD_CLOSE 0x00010BCD
25 #define ASM_STREAM_CMD_FLUSH 0x00010BCE
26 #define ASM_SESSION_CMD_PAUSE 0x00010BD3
27 #define ASM_DATA_CMD_EOS 0x00010BDB
28 #define ASM_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_MEDIA_FMT_MP3 0x00010BE9
42 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB
43 #define ASM_DATA_CMD_READ_V2 0x00010DAC
44 #define ASM_SESSION_CMD_SUSPEND 0x00010DEC
45 #define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3
46 #define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4
47 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
48 #define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
49
50
51 #define ASM_LEGACY_STREAM_SESSION 0
52 /* Bit shift for the stream_perf_mode subfield. */
53 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29
54 #define ASM_END_POINT_DEVICE_MATRIX 0
55 #define ASM_DEFAULT_APP_TYPE 0
56 #define ASM_SYNC_IO_MODE 0x0001
57 #define ASM_ASYNC_IO_MODE 0x0002
58 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
59 #define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
60 #define ASM_SHIFT_GAPLESS_MODE_FLAG 31
61 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
62
63 struct avs_cmd_shared_mem_map_regions {
64 u16 mem_pool_id;
65 u16 num_regions;
66 u32 property_flag;
67 } __packed;
68
69 struct avs_shared_map_region_payload {
70 u32 shm_addr_lsw;
71 u32 shm_addr_msw;
72 u32 mem_size_bytes;
73 } __packed;
74
75 struct avs_cmd_shared_mem_unmap_regions {
76 u32 mem_map_handle;
77 } __packed;
78
79 struct asm_data_cmd_media_fmt_update_v2 {
80 u32 fmt_blk_size;
81 } __packed;
82
83 struct asm_multi_channel_pcm_fmt_blk_v2 {
84 struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
85 u16 num_channels;
86 u16 bits_per_sample;
87 u32 sample_rate;
88 u16 is_signed;
89 u16 reserved;
90 u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
91 } __packed;
92
93 struct asm_stream_cmd_set_encdec_param {
94 u32 param_id;
95 u32 param_size;
96 } __packed;
97
98 struct asm_enc_cfg_blk_param_v2 {
99 u32 frames_per_buf;
100 u32 enc_cfg_blk_size;
101 } __packed;
102
103 struct asm_multi_channel_pcm_enc_cfg_v2 {
104 struct asm_stream_cmd_set_encdec_param encdec;
105 struct asm_enc_cfg_blk_param_v2 encblk;
106 uint16_t num_channels;
107 uint16_t bits_per_sample;
108 uint32_t sample_rate;
109 uint16_t is_signed;
110 uint16_t reserved;
111 uint8_t channel_mapping[8];
112 } __packed;
113
114 struct asm_data_cmd_read_v2 {
115 u32 buf_addr_lsw;
116 u32 buf_addr_msw;
117 u32 mem_map_handle;
118 u32 buf_size;
119 u32 seq_id;
120 } __packed;
121
122 struct asm_data_cmd_read_v2_done {
123 u32 status;
124 u32 buf_addr_lsw;
125 u32 buf_addr_msw;
126 };
127
128 struct asm_stream_cmd_open_read_v3 {
129 u32 mode_flags;
130 u32 src_endpointype;
131 u32 preprocopo_id;
132 u32 enc_cfg_id;
133 u16 bits_per_sample;
134 u16 reserved;
135 } __packed;
136
137 struct asm_data_cmd_write_v2 {
138 u32 buf_addr_lsw;
139 u32 buf_addr_msw;
140 u32 mem_map_handle;
141 u32 buf_size;
142 u32 seq_id;
143 u32 timestamp_lsw;
144 u32 timestamp_msw;
145 u32 flags;
146 } __packed;
147
148 struct asm_stream_cmd_open_write_v3 {
149 uint32_t mode_flags;
150 uint16_t sink_endpointype;
151 uint16_t bits_per_sample;
152 uint32_t postprocopo_id;
153 uint32_t dec_fmt_id;
154 } __packed;
155
156 struct asm_session_cmd_run_v2 {
157 u32 flags;
158 u32 time_lsw;
159 u32 time_msw;
160 } __packed;
161
162 struct audio_buffer {
163 phys_addr_t phys;
164 uint32_t size; /* size of buffer */
165 };
166
167 struct audio_port_data {
168 struct audio_buffer *buf;
169 uint32_t num_periods;
170 uint32_t dsp_buf;
171 uint32_t mem_map_handle;
172 };
173
174 struct q6asm {
175 struct apr_device *adev;
176 struct device *dev;
177 struct q6core_svc_api_info ainfo;
178 wait_queue_head_t mem_wait;
179 spinlock_t slock;
180 struct audio_client *session[MAX_SESSIONS + 1];
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
q6asm_add_hdr(struct audio_client * ac,struct apr_hdr * hdr,uint32_t pkt_size,bool cmd_flg,uint32_t stream_id)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
q6asm_apr_send_session_pkt(struct q6asm * a,struct audio_client * ac,struct apr_pkt * pkt,uint32_t rsp_opcode)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
__q6asm_memory_unmap(struct audio_client * ac,phys_addr_t buf_add,int dir)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
q6asm_audio_client_free_buf(struct audio_client * ac,struct audio_port_data * port)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 */
q6asm_unmap_memory_regions(unsigned int dir,struct audio_client * ac)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
__q6asm_memory_map_regions(struct audio_client * ac,int dir,size_t period_sz,unsigned int periods,bool is_contiguous)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 */
q6asm_map_memory_regions(unsigned int dir,struct audio_client * ac,phys_addr_t phys,size_t period_sz,unsigned int periods)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
q6asm_audio_client_release(struct kref * ref)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 */
q6asm_audio_client_free(struct audio_client * ac)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
q6asm_get_audio_client(struct q6asm * a,int session_id)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
q6asm_stream_callback(struct apr_device * adev,struct apr_resp_pkt * data,int session_id)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_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 case ASM_DATA_EVENT_RENDERED_EOS:
654 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
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
q6asm_srvc_callback(struct apr_device * adev,struct apr_resp_pkt * data)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 */
q6asm_get_session_id(struct audio_client * c)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 */
q6asm_audio_client_alloc(struct device * dev,q6asm_cb cb,void * priv,int stream_id,int perf_mode)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
q6asm_ac_send_cmd_sync(struct audio_client * ac,struct apr_pkt * pkt)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 */
q6asm_open_write(struct audio_client * ac,uint32_t format,uint16_t bits_per_sample)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 SND_AUDIOCODEC_MP3:
875 open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
876 break;
877 case FORMAT_LINEAR_PCM:
878 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
879 break;
880 default:
881 dev_err(ac->dev, "Invalid format 0x%x\n", format);
882 rc = -EINVAL;
883 goto err;
884 }
885
886 rc = q6asm_ac_send_cmd_sync(ac, pkt);
887 if (rc < 0)
888 goto err;
889
890 ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
891
892 err:
893 kfree(pkt);
894 return rc;
895 }
896 EXPORT_SYMBOL_GPL(q6asm_open_write);
897
__q6asm_run(struct audio_client * ac,uint32_t flags,uint32_t msw_ts,uint32_t lsw_ts,bool wait)898 static int __q6asm_run(struct audio_client *ac, uint32_t flags,
899 uint32_t msw_ts, uint32_t lsw_ts, bool wait)
900 {
901 struct asm_session_cmd_run_v2 *run;
902 struct apr_pkt *pkt;
903 int pkt_size, rc;
904 void *p;
905
906 pkt_size = APR_HDR_SIZE + sizeof(*run);
907 p = kzalloc(pkt_size, GFP_ATOMIC);
908 if (!p)
909 return -ENOMEM;
910
911 pkt = p;
912 run = p + APR_HDR_SIZE;
913
914 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
915
916 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
917 run->flags = flags;
918 run->time_lsw = lsw_ts;
919 run->time_msw = msw_ts;
920 if (wait) {
921 rc = q6asm_ac_send_cmd_sync(ac, pkt);
922 } else {
923 rc = apr_send_pkt(ac->adev, pkt);
924 if (rc == pkt_size)
925 rc = 0;
926 }
927
928 kfree(pkt);
929 return rc;
930 }
931
932 /**
933 * q6asm_run() - start the audio client
934 *
935 * @ac: audio client pointer
936 * @flags: flags associated with write
937 * @msw_ts: timestamp msw
938 * @lsw_ts: timestamp lsw
939 *
940 * Return: Will be an negative value on error or zero on success
941 */
q6asm_run(struct audio_client * ac,uint32_t flags,uint32_t msw_ts,uint32_t lsw_ts)942 int q6asm_run(struct audio_client *ac, uint32_t flags,
943 uint32_t msw_ts, uint32_t lsw_ts)
944 {
945 return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
946 }
947 EXPORT_SYMBOL_GPL(q6asm_run);
948
949 /**
950 * q6asm_run_nowait() - start the audio client withou blocking
951 *
952 * @ac: audio client pointer
953 * @flags: flags associated with write
954 * @msw_ts: timestamp msw
955 * @lsw_ts: timestamp lsw
956 *
957 * Return: Will be an negative value on error or zero on success
958 */
q6asm_run_nowait(struct audio_client * ac,uint32_t flags,uint32_t msw_ts,uint32_t lsw_ts)959 int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
960 uint32_t msw_ts, uint32_t lsw_ts)
961 {
962 return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
963 }
964 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
965
966 /**
967 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
968 *
969 * @ac: audio client pointer
970 * @rate: audio sample rate
971 * @channels: number of audio channels.
972 * @channel_map: channel map pointer
973 * @bits_per_sample: bits per sample
974 *
975 * Return: Will be an negative value on error or zero on success
976 */
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)977 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
978 uint32_t rate, uint32_t channels,
979 u8 channel_map[PCM_MAX_NUM_CHANNEL],
980 uint16_t bits_per_sample)
981 {
982 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
983 struct apr_pkt *pkt;
984 u8 *channel_mapping;
985 void *p;
986 int rc, pkt_size;
987
988 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
989 p = kzalloc(pkt_size, GFP_KERNEL);
990 if (!p)
991 return -ENOMEM;
992
993 pkt = p;
994 fmt = p + APR_HDR_SIZE;
995
996 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
997
998 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
999 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1000 fmt->num_channels = channels;
1001 fmt->bits_per_sample = bits_per_sample;
1002 fmt->sample_rate = rate;
1003 fmt->is_signed = 1;
1004
1005 channel_mapping = fmt->channel_mapping;
1006
1007 if (channel_map) {
1008 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1009 } else {
1010 if (q6dsp_map_channels(channel_mapping, channels)) {
1011 dev_err(ac->dev, " map channels failed %d\n", channels);
1012 rc = -EINVAL;
1013 goto err;
1014 }
1015 }
1016
1017 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1018
1019 err:
1020 kfree(pkt);
1021 return rc;
1022 }
1023 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1024
1025 /**
1026 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1027 *
1028 * @ac: audio client pointer
1029 * @rate: audio sample rate
1030 * @channels: number of audio channels.
1031 * @bits_per_sample: bits per sample
1032 *
1033 * Return: Will be an negative value on error or zero on success
1034 */
q6asm_enc_cfg_blk_pcm_format_support(struct audio_client * ac,uint32_t rate,uint32_t channels,uint16_t bits_per_sample)1035 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1036 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
1037 {
1038 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg;
1039 struct apr_pkt *pkt;
1040 u8 *channel_mapping;
1041 u32 frames_per_buf = 0;
1042 int pkt_size, rc;
1043 void *p;
1044
1045 pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1046 p = kzalloc(pkt_size, GFP_KERNEL);
1047 if (!p)
1048 return -ENOMEM;
1049
1050 pkt = p;
1051 enc_cfg = p + APR_HDR_SIZE;
1052 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1053
1054 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1055 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1056 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1057 enc_cfg->encblk.frames_per_buf = frames_per_buf;
1058 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size -
1059 sizeof(struct asm_enc_cfg_blk_param_v2);
1060
1061 enc_cfg->num_channels = channels;
1062 enc_cfg->bits_per_sample = bits_per_sample;
1063 enc_cfg->sample_rate = rate;
1064 enc_cfg->is_signed = 1;
1065 channel_mapping = enc_cfg->channel_mapping;
1066
1067 if (q6dsp_map_channels(channel_mapping, channels)) {
1068 rc = -EINVAL;
1069 goto err;
1070 }
1071
1072 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1073 err:
1074 kfree(pkt);
1075 return rc;
1076 }
1077 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1078
1079 /**
1080 * q6asm_read() - read data of period size from audio client
1081 *
1082 * @ac: audio client pointer
1083 *
1084 * Return: Will be an negative value on error or zero on success
1085 */
q6asm_read(struct audio_client * ac)1086 int q6asm_read(struct audio_client *ac)
1087 {
1088 struct asm_data_cmd_read_v2 *read;
1089 struct audio_port_data *port;
1090 struct audio_buffer *ab;
1091 struct apr_pkt *pkt;
1092 unsigned long flags;
1093 int pkt_size;
1094 int rc = 0;
1095 void *p;
1096
1097 pkt_size = APR_HDR_SIZE + sizeof(*read);
1098 p = kzalloc(pkt_size, GFP_ATOMIC);
1099 if (!p)
1100 return -ENOMEM;
1101
1102 pkt = p;
1103 read = p + APR_HDR_SIZE;
1104
1105 spin_lock_irqsave(&ac->lock, flags);
1106 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1107 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1108 ab = &port->buf[port->dsp_buf];
1109 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1110 read->buf_addr_lsw = lower_32_bits(ab->phys);
1111 read->buf_addr_msw = upper_32_bits(ab->phys);
1112 read->mem_map_handle = port->mem_map_handle;
1113
1114 read->buf_size = ab->size;
1115 read->seq_id = port->dsp_buf;
1116 pkt->hdr.token = port->dsp_buf;
1117
1118 port->dsp_buf++;
1119
1120 if (port->dsp_buf >= port->num_periods)
1121 port->dsp_buf = 0;
1122
1123 spin_unlock_irqrestore(&ac->lock, flags);
1124 rc = apr_send_pkt(ac->adev, pkt);
1125 if (rc == pkt_size)
1126 rc = 0;
1127 else
1128 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1129
1130 kfree(pkt);
1131 return rc;
1132 }
1133 EXPORT_SYMBOL_GPL(q6asm_read);
1134
__q6asm_open_read(struct audio_client * ac,uint32_t format,uint16_t bits_per_sample)1135 static int __q6asm_open_read(struct audio_client *ac,
1136 uint32_t format, uint16_t bits_per_sample)
1137 {
1138 struct asm_stream_cmd_open_read_v3 *open;
1139 struct apr_pkt *pkt;
1140 int pkt_size, rc;
1141 void *p;
1142
1143 pkt_size = APR_HDR_SIZE + sizeof(*open);
1144 p = kzalloc(pkt_size, GFP_KERNEL);
1145 if (!p)
1146 return -ENOMEM;
1147
1148 pkt = p;
1149 open = p + APR_HDR_SIZE;
1150
1151 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1152 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1153 /* Stream prio : High, provide meta info with encoded frames */
1154 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1155
1156 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1157 open->bits_per_sample = bits_per_sample;
1158 open->mode_flags = 0x0;
1159
1160 open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1161 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1162
1163 switch (format) {
1164 case FORMAT_LINEAR_PCM:
1165 open->mode_flags |= 0x00;
1166 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1167 break;
1168 default:
1169 pr_err("Invalid format[%d]\n", format);
1170 }
1171
1172 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1173
1174 kfree(pkt);
1175 return rc;
1176 }
1177
1178 /**
1179 * q6asm_open_read() - Open audio client for reading
1180 *
1181 * @ac: audio client pointer
1182 * @format: audio sample format
1183 * @bits_per_sample: bits per sample
1184 *
1185 * Return: Will be an negative value on error or zero on success
1186 */
q6asm_open_read(struct audio_client * ac,uint32_t format,uint16_t bits_per_sample)1187 int q6asm_open_read(struct audio_client *ac, uint32_t format,
1188 uint16_t bits_per_sample)
1189 {
1190 return __q6asm_open_read(ac, format, bits_per_sample);
1191 }
1192 EXPORT_SYMBOL_GPL(q6asm_open_read);
1193
1194 /**
1195 * q6asm_write_async() - non blocking write
1196 *
1197 * @ac: audio client pointer
1198 * @len: length in bytes
1199 * @msw_ts: timestamp msw
1200 * @lsw_ts: timestamp lsw
1201 * @wflags: flags associated with write
1202 *
1203 * Return: Will be an negative value on error or zero on success
1204 */
q6asm_write_async(struct audio_client * ac,uint32_t len,uint32_t msw_ts,uint32_t lsw_ts,uint32_t wflags)1205 int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
1206 uint32_t lsw_ts, uint32_t wflags)
1207 {
1208 struct asm_data_cmd_write_v2 *write;
1209 struct audio_port_data *port;
1210 struct audio_buffer *ab;
1211 unsigned long flags;
1212 struct apr_pkt *pkt;
1213 int pkt_size;
1214 int rc = 0;
1215 void *p;
1216
1217 pkt_size = APR_HDR_SIZE + sizeof(*write);
1218 p = kzalloc(pkt_size, GFP_ATOMIC);
1219 if (!p)
1220 return -ENOMEM;
1221
1222 pkt = p;
1223 write = p + APR_HDR_SIZE;
1224
1225 spin_lock_irqsave(&ac->lock, flags);
1226 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1227 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1228
1229 ab = &port->buf[port->dsp_buf];
1230 pkt->hdr.token = port->dsp_buf;
1231 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1232 write->buf_addr_lsw = lower_32_bits(ab->phys);
1233 write->buf_addr_msw = upper_32_bits(ab->phys);
1234 write->buf_size = len;
1235 write->seq_id = port->dsp_buf;
1236 write->timestamp_lsw = lsw_ts;
1237 write->timestamp_msw = msw_ts;
1238 write->mem_map_handle =
1239 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1240
1241 if (wflags == NO_TIMESTAMP)
1242 write->flags = (wflags & 0x800000FF);
1243 else
1244 write->flags = (0x80000000 | wflags);
1245
1246 port->dsp_buf++;
1247
1248 if (port->dsp_buf >= port->num_periods)
1249 port->dsp_buf = 0;
1250
1251 spin_unlock_irqrestore(&ac->lock, flags);
1252 rc = apr_send_pkt(ac->adev, pkt);
1253 if (rc == pkt_size)
1254 rc = 0;
1255
1256 kfree(pkt);
1257 return rc;
1258 }
1259 EXPORT_SYMBOL_GPL(q6asm_write_async);
1260
q6asm_reset_buf_state(struct audio_client * ac)1261 static void q6asm_reset_buf_state(struct audio_client *ac)
1262 {
1263 struct audio_port_data *port = NULL;
1264 unsigned long flags;
1265
1266 spin_lock_irqsave(&ac->lock, flags);
1267 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1268 port->dsp_buf = 0;
1269 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1270 port->dsp_buf = 0;
1271 spin_unlock_irqrestore(&ac->lock, flags);
1272 }
1273
__q6asm_cmd(struct audio_client * ac,int cmd,bool wait)1274 static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
1275 {
1276 int stream_id = ac->stream_id;
1277 struct apr_pkt pkt;
1278 int rc;
1279
1280 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1281
1282 switch (cmd) {
1283 case CMD_PAUSE:
1284 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1285 break;
1286 case CMD_SUSPEND:
1287 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1288 break;
1289 case CMD_FLUSH:
1290 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1291 break;
1292 case CMD_OUT_FLUSH:
1293 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1294 break;
1295 case CMD_EOS:
1296 pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1297 break;
1298 case CMD_CLOSE:
1299 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1300 break;
1301 default:
1302 return -EINVAL;
1303 }
1304
1305 if (wait)
1306 rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1307 else
1308 return apr_send_pkt(ac->adev, &pkt);
1309
1310 if (rc < 0)
1311 return rc;
1312
1313 if (cmd == CMD_FLUSH)
1314 q6asm_reset_buf_state(ac);
1315
1316 return 0;
1317 }
1318
1319 /**
1320 * q6asm_cmd() - run cmd on audio client
1321 *
1322 * @ac: audio client pointer
1323 * @cmd: command to run on audio client.
1324 *
1325 * Return: Will be an negative value on error or zero on success
1326 */
q6asm_cmd(struct audio_client * ac,int cmd)1327 int q6asm_cmd(struct audio_client *ac, int cmd)
1328 {
1329 return __q6asm_cmd(ac, cmd, true);
1330 }
1331 EXPORT_SYMBOL_GPL(q6asm_cmd);
1332
1333 /**
1334 * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1335 *
1336 * @ac: audio client pointer
1337 * @cmd: command to run on audio client.
1338 *
1339 * Return: Will be an negative value on error or zero on success
1340 */
q6asm_cmd_nowait(struct audio_client * ac,int cmd)1341 int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
1342 {
1343 return __q6asm_cmd(ac, cmd, false);
1344 }
1345 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1346
q6asm_probe(struct apr_device * adev)1347 static int q6asm_probe(struct apr_device *adev)
1348 {
1349 struct device *dev = &adev->dev;
1350 struct q6asm *q6asm;
1351
1352 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1353 if (!q6asm)
1354 return -ENOMEM;
1355
1356 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1357
1358 q6asm->dev = dev;
1359 q6asm->adev = adev;
1360 init_waitqueue_head(&q6asm->mem_wait);
1361 spin_lock_init(&q6asm->slock);
1362 dev_set_drvdata(dev, q6asm);
1363
1364 return of_platform_populate(dev->of_node, NULL, NULL, dev);
1365 }
1366
q6asm_remove(struct apr_device * adev)1367 static int q6asm_remove(struct apr_device *adev)
1368 {
1369 of_platform_depopulate(&adev->dev);
1370
1371 return 0;
1372 }
1373 static const struct of_device_id q6asm_device_id[] = {
1374 { .compatible = "qcom,q6asm" },
1375 {},
1376 };
1377 MODULE_DEVICE_TABLE(of, q6asm_device_id);
1378
1379 static struct apr_driver qcom_q6asm_driver = {
1380 .probe = q6asm_probe,
1381 .remove = q6asm_remove,
1382 .callback = q6asm_srvc_callback,
1383 .driver = {
1384 .name = "qcom-q6asm",
1385 .of_match_table = of_match_ptr(q6asm_device_id),
1386 },
1387 };
1388
1389 module_apr_driver(qcom_q6asm_driver);
1390 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1391 MODULE_LICENSE("GPL v2");
1392