blob: 4f85cb19a3091df9b0c3abf4379a04a515758553 [file] [log] [blame]
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +01001// 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>
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010014#include <uapi/sound/asound.h>
Srinivas Kandagatlaf2e6c6aa2018-11-15 18:13:23 +000015#include <uapi/sound/compress_params.h>
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +010016#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
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010024#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
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +010032#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
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010035#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
Srinivas Kandagatlaf2e6c6aa2018-11-15 18:13:23 +000040#define ASM_MEDIA_FMT_MP3 0x00010BE9
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010041#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
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +010048
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010049
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
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +010055#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 */
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +010059#define ASM_SHIFT_GAPLESS_MODE_FLAG 31
60#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
61
62struct avs_cmd_shared_mem_map_regions {
63 u16 mem_pool_id;
64 u16 num_regions;
65 u32 property_flag;
66} __packed;
67
68struct avs_shared_map_region_payload {
69 u32 shm_addr_lsw;
70 u32 shm_addr_msw;
71 u32 mem_size_bytes;
72} __packed;
73
74struct avs_cmd_shared_mem_unmap_regions {
75 u32 mem_map_handle;
76} __packed;
77
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +010078struct asm_data_cmd_media_fmt_update_v2 {
79 u32 fmt_blk_size;
80} __packed;
81
82struct 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
92struct asm_stream_cmd_set_encdec_param {
93 u32 param_id;
94 u32 param_size;
95} __packed;
96
97struct asm_enc_cfg_blk_param_v2 {
98 u32 frames_per_buf;
99 u32 enc_cfg_blk_size;
100} __packed;
101
102struct 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
113struct 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
121struct asm_data_cmd_read_v2_done {
122 u32 status;
123 u32 buf_addr_lsw;
124 u32 buf_addr_msw;
125};
126
127struct 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
136struct 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
147struct 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
155struct asm_session_cmd_run_v2 {
156 u32 flags;
157 u32 time_lsw;
158 u32 time_msw;
159} __packed;
160
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100161struct audio_buffer {
162 phys_addr_t phys;
163 uint32_t size; /* size of buffer */
164};
165
166struct 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};
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100172
173struct q6asm {
174 struct apr_device *adev;
175 struct device *dev;
176 struct q6core_svc_api_info ainfo;
177 wait_queue_head_t mem_wait;
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100178 spinlock_t slock;
179 struct audio_client *session[MAX_SESSIONS + 1];
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100180};
181
182struct 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;
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100191 /* idx:1 out port, 0: in port */
192 struct audio_port_data port[2];
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100193 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
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100201static 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
213static 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
245err:
246 mutex_unlock(&ac->cmd_lock);
247 return rc;
248}
249
250static 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
294static 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 */
314int 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
338err:
339 return rc;
340}
341EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
342
343static 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 */
422int 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}
468EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
469
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100470static 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 */
491void q6asm_audio_client_free(struct audio_client *ac)
492{
493 kref_put(&ac->refcount, q6asm_audio_client_release);
494}
495EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
496
497static 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);
517err:
518 spin_unlock_irqrestore(&a->slock, flags);
519 return ac;
520}
521
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +0100522static 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_DATA_CMD_EOS:
550 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
551 break;
552 case ASM_STREAM_CMD_FLUSH:
553 client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
554 break;
555 case ASM_SESSION_CMD_RUN_V2:
556 client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
557 break;
558 case ASM_STREAM_CMD_CLOSE:
559 client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
560 break;
561 case ASM_STREAM_CMD_FLUSH_READBUFS:
562 client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
563 break;
564 case ASM_STREAM_CMD_OPEN_WRITE_V3:
565 case ASM_STREAM_CMD_OPEN_READ_V3:
566 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
567 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
568 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
569 if (result->status != 0) {
570 dev_err(ac->dev,
571 "cmd = 0x%x returned error = 0x%x\n",
572 result->opcode, result->status);
573 ac->result = *result;
574 wake_up(&ac->cmd_wait);
575 ret = 0;
576 goto done;
577 }
578 break;
579 default:
580 dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
581 result->opcode);
582 break;
583 }
584
585 ac->result = *result;
586 wake_up(&ac->cmd_wait);
587
588 if (ac->cb)
589 ac->cb(client_event, hdr->token,
590 data->payload, ac->priv);
591
592 ret = 0;
593 goto done;
594
595 case ASM_DATA_EVENT_WRITE_DONE_V2:
596 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
597 if (ac->io_mode & ASM_SYNC_IO_MODE) {
598 phys_addr_t phys;
599 unsigned long flags;
600
601 spin_lock_irqsave(&ac->lock, flags);
602
603 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
604
605 if (!port->buf) {
606 spin_unlock_irqrestore(&ac->lock, flags);
607 ret = 0;
608 goto done;
609 }
610
611 phys = port->buf[hdr->token].phys;
612
613 if (lower_32_bits(phys) != result->opcode ||
614 upper_32_bits(phys) != result->status) {
615 dev_err(ac->dev, "Expected addr %pa\n",
616 &port->buf[hdr->token].phys);
617 spin_unlock_irqrestore(&ac->lock, flags);
618 ret = -EINVAL;
619 goto done;
620 }
621 spin_unlock_irqrestore(&ac->lock, flags);
622 }
623 break;
624 case ASM_DATA_EVENT_READ_DONE_V2:
625 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
626 if (ac->io_mode & ASM_SYNC_IO_MODE) {
627 struct asm_data_cmd_read_v2_done *done = data->payload;
628 unsigned long flags;
629 phys_addr_t phys;
630
631 spin_lock_irqsave(&ac->lock, flags);
632 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
633 if (!port->buf) {
634 spin_unlock_irqrestore(&ac->lock, flags);
635 ret = 0;
636 goto done;
637 }
638
639 phys = port->buf[hdr->token].phys;
640
641 if (upper_32_bits(phys) != done->buf_addr_msw ||
642 lower_32_bits(phys) != done->buf_addr_lsw) {
643 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
644 &port->buf[hdr->token].phys,
645 done->buf_addr_lsw,
646 done->buf_addr_msw);
647 spin_unlock_irqrestore(&ac->lock, flags);
648 ret = -EINVAL;
649 goto done;
650 }
651 spin_unlock_irqrestore(&ac->lock, flags);
652 }
653
654 break;
655 }
656
657 if (ac->cb)
658 ac->cb(client_event, hdr->token, data->payload, ac->priv);
659
660done:
661 kref_put(&ac->refcount, q6asm_audio_client_release);
662 return ret;
663}
664
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100665static int q6asm_srvc_callback(struct apr_device *adev,
666 struct apr_resp_pkt *data)
667{
668 struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100669 struct aprv2_ibasic_rsp_result_t *result;
670 struct audio_port_data *port;
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100671 struct audio_client *ac = NULL;
672 struct apr_hdr *hdr = &data->hdr;
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100673 struct q6asm *a;
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100674 uint32_t sid = 0;
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100675 uint32_t dir = 0;
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +0100676 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);
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100681
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
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100689 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
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100726 if (ac->cb)
727 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
728
Srinivas Kandagatlaa2a5d302018-05-18 13:56:02 +0100729done:
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +0100730 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 */
742int q6asm_get_session_id(struct audio_client *c)
743{
744 return c->session;
745}
746EXPORT_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 */
760struct 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}
799EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
800
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +0100801static 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
831err:
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 */
845int 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) {
Srinivas Kandagatlaf2e6c6aa2018-11-15 18:13:23 +0000873 case SND_AUDIOCODEC_MP3:
874 open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
875 break;
Srinivas Kandagatla68fd8482018-05-18 13:56:03 +0100876 case FORMAT_LINEAR_PCM:
877 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
878 break;
879 default:
880 dev_err(ac->dev, "Invalid format 0x%x\n", format);
881 rc = -EINVAL;
882 goto err;
883 }
884
885 rc = q6asm_ac_send_cmd_sync(ac, pkt);
886 if (rc < 0)
887 goto err;
888
889 ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
890
891err:
892 kfree(pkt);
893 return rc;
894}
895EXPORT_SYMBOL_GPL(q6asm_open_write);
896
897static int __q6asm_run(struct audio_client *ac, uint32_t flags,
898 uint32_t msw_ts, uint32_t lsw_ts, bool wait)
899{
900 struct asm_session_cmd_run_v2 *run;
901 struct apr_pkt *pkt;
902 int pkt_size, rc;
903 void *p;
904
905 pkt_size = APR_HDR_SIZE + sizeof(*run);
906 p = kzalloc(pkt_size, GFP_ATOMIC);
907 if (!p)
908 return -ENOMEM;
909
910 pkt = p;
911 run = p + APR_HDR_SIZE;
912
913 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
914
915 pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
916 run->flags = flags;
917 run->time_lsw = lsw_ts;
918 run->time_msw = msw_ts;
919 if (wait) {
920 rc = q6asm_ac_send_cmd_sync(ac, pkt);
921 } else {
922 rc = apr_send_pkt(ac->adev, pkt);
923 if (rc == pkt_size)
924 rc = 0;
925 }
926
927 kfree(pkt);
928 return rc;
929}
930
931/**
932 * q6asm_run() - start the audio client
933 *
934 * @ac: audio client pointer
935 * @flags: flags associated with write
936 * @msw_ts: timestamp msw
937 * @lsw_ts: timestamp lsw
938 *
939 * Return: Will be an negative value on error or zero on success
940 */
941int q6asm_run(struct audio_client *ac, uint32_t flags,
942 uint32_t msw_ts, uint32_t lsw_ts)
943{
944 return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
945}
946EXPORT_SYMBOL_GPL(q6asm_run);
947
948/**
949 * q6asm_run_nowait() - start the audio client withou blocking
950 *
951 * @ac: audio client pointer
952 * @flags: flags associated with write
953 * @msw_ts: timestamp msw
954 * @lsw_ts: timestamp lsw
955 *
956 * Return: Will be an negative value on error or zero on success
957 */
958int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
959 uint32_t msw_ts, uint32_t lsw_ts)
960{
961 return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
962}
963EXPORT_SYMBOL_GPL(q6asm_run_nowait);
964
965/**
966 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
967 *
968 * @ac: audio client pointer
969 * @rate: audio sample rate
970 * @channels: number of audio channels.
971 * @channel_map: channel map pointer
972 * @bits_per_sample: bits per sample
973 *
974 * Return: Will be an negative value on error or zero on success
975 */
976int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
977 uint32_t rate, uint32_t channels,
978 u8 channel_map[PCM_MAX_NUM_CHANNEL],
979 uint16_t bits_per_sample)
980{
981 struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
982 struct apr_pkt *pkt;
983 u8 *channel_mapping;
984 void *p;
985 int rc, pkt_size;
986
987 pkt_size = APR_HDR_SIZE + sizeof(*fmt);
988 p = kzalloc(pkt_size, GFP_KERNEL);
989 if (!p)
990 return -ENOMEM;
991
992 pkt = p;
993 fmt = p + APR_HDR_SIZE;
994
995 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
996
997 pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
998 fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
999 fmt->num_channels = channels;
1000 fmt->bits_per_sample = bits_per_sample;
1001 fmt->sample_rate = rate;
1002 fmt->is_signed = 1;
1003
1004 channel_mapping = fmt->channel_mapping;
1005
1006 if (channel_map) {
1007 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1008 } else {
1009 if (q6dsp_map_channels(channel_mapping, channels)) {
1010 dev_err(ac->dev, " map channels failed %d\n", channels);
1011 rc = -EINVAL;
1012 goto err;
1013 }
1014 }
1015
1016 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1017
1018err:
1019 kfree(pkt);
1020 return rc;
1021}
1022EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1023
1024/**
1025 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1026 *
1027 * @ac: audio client pointer
1028 * @rate: audio sample rate
1029 * @channels: number of audio channels.
1030 * @bits_per_sample: bits per sample
1031 *
1032 * Return: Will be an negative value on error or zero on success
1033 */
1034int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1035 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
1036{
1037 struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg;
1038 struct apr_pkt *pkt;
1039 u8 *channel_mapping;
1040 u32 frames_per_buf = 0;
1041 int pkt_size, rc;
1042 void *p;
1043
1044 pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1045 p = kzalloc(pkt_size, GFP_KERNEL);
1046 if (!p)
1047 return -ENOMEM;
1048
1049 pkt = p;
1050 enc_cfg = p + APR_HDR_SIZE;
1051 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1052
1053 pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1054 enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1055 enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1056 enc_cfg->encblk.frames_per_buf = frames_per_buf;
1057 enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size -
1058 sizeof(struct asm_enc_cfg_blk_param_v2);
1059
1060 enc_cfg->num_channels = channels;
1061 enc_cfg->bits_per_sample = bits_per_sample;
1062 enc_cfg->sample_rate = rate;
1063 enc_cfg->is_signed = 1;
1064 channel_mapping = enc_cfg->channel_mapping;
1065
1066 if (q6dsp_map_channels(channel_mapping, channels)) {
1067 rc = -EINVAL;
1068 goto err;
1069 }
1070
1071 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1072err:
1073 kfree(pkt);
1074 return rc;
1075}
1076EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1077
1078/**
1079 * q6asm_read() - read data of period size from audio client
1080 *
1081 * @ac: audio client pointer
1082 *
1083 * Return: Will be an negative value on error or zero on success
1084 */
1085int q6asm_read(struct audio_client *ac)
1086{
1087 struct asm_data_cmd_read_v2 *read;
1088 struct audio_port_data *port;
1089 struct audio_buffer *ab;
1090 struct apr_pkt *pkt;
1091 unsigned long flags;
1092 int pkt_size;
1093 int rc = 0;
1094 void *p;
1095
1096 pkt_size = APR_HDR_SIZE + sizeof(*read);
1097 p = kzalloc(pkt_size, GFP_ATOMIC);
1098 if (!p)
1099 return -ENOMEM;
1100
1101 pkt = p;
1102 read = p + APR_HDR_SIZE;
1103
1104 spin_lock_irqsave(&ac->lock, flags);
1105 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1106 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1107 ab = &port->buf[port->dsp_buf];
1108 pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1109 read->buf_addr_lsw = lower_32_bits(ab->phys);
1110 read->buf_addr_msw = upper_32_bits(ab->phys);
1111 read->mem_map_handle = port->mem_map_handle;
1112
1113 read->buf_size = ab->size;
1114 read->seq_id = port->dsp_buf;
1115 pkt->hdr.token = port->dsp_buf;
1116
1117 port->dsp_buf++;
1118
1119 if (port->dsp_buf >= port->num_periods)
1120 port->dsp_buf = 0;
1121
1122 spin_unlock_irqrestore(&ac->lock, flags);
1123 rc = apr_send_pkt(ac->adev, pkt);
1124 if (rc == pkt_size)
1125 rc = 0;
1126 else
1127 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1128
1129 kfree(pkt);
1130 return rc;
1131}
1132EXPORT_SYMBOL_GPL(q6asm_read);
1133
1134static int __q6asm_open_read(struct audio_client *ac,
1135 uint32_t format, uint16_t bits_per_sample)
1136{
1137 struct asm_stream_cmd_open_read_v3 *open;
1138 struct apr_pkt *pkt;
1139 int pkt_size, rc;
1140 void *p;
1141
1142 pkt_size = APR_HDR_SIZE + sizeof(*open);
1143 p = kzalloc(pkt_size, GFP_KERNEL);
1144 if (!p)
1145 return -ENOMEM;
1146
1147 pkt = p;
1148 open = p + APR_HDR_SIZE;
1149
1150 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1151 pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1152 /* Stream prio : High, provide meta info with encoded frames */
1153 open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1154
1155 open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1156 open->bits_per_sample = bits_per_sample;
1157 open->mode_flags = 0x0;
1158
1159 open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1160 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1161
1162 switch (format) {
1163 case FORMAT_LINEAR_PCM:
1164 open->mode_flags |= 0x00;
1165 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1166 break;
1167 default:
1168 pr_err("Invalid format[%d]\n", format);
1169 }
1170
1171 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1172
1173 kfree(pkt);
1174 return rc;
1175}
1176
1177/**
1178 * q6asm_open_read() - Open audio client for reading
1179 *
1180 * @ac: audio client pointer
1181 * @format: audio sample format
1182 * @bits_per_sample: bits per sample
1183 *
1184 * Return: Will be an negative value on error or zero on success
1185 */
1186int q6asm_open_read(struct audio_client *ac, uint32_t format,
1187 uint16_t bits_per_sample)
1188{
1189 return __q6asm_open_read(ac, format, bits_per_sample);
1190}
1191EXPORT_SYMBOL_GPL(q6asm_open_read);
1192
1193/**
1194 * q6asm_write_async() - non blocking write
1195 *
1196 * @ac: audio client pointer
1197 * @len: lenght in bytes
1198 * @msw_ts: timestamp msw
1199 * @lsw_ts: timestamp lsw
1200 * @wflags: flags associated with write
1201 *
1202 * Return: Will be an negative value on error or zero on success
1203 */
1204int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
1205 uint32_t lsw_ts, uint32_t wflags)
1206{
1207 struct asm_data_cmd_write_v2 *write;
1208 struct audio_port_data *port;
1209 struct audio_buffer *ab;
1210 unsigned long flags;
1211 struct apr_pkt *pkt;
1212 int pkt_size;
1213 int rc = 0;
1214 void *p;
1215
1216 pkt_size = APR_HDR_SIZE + sizeof(*write);
1217 p = kzalloc(pkt_size, GFP_ATOMIC);
1218 if (!p)
1219 return -ENOMEM;
1220
1221 pkt = p;
1222 write = p + APR_HDR_SIZE;
1223
1224 spin_lock_irqsave(&ac->lock, flags);
1225 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1226 q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1227
1228 ab = &port->buf[port->dsp_buf];
1229 pkt->hdr.token = port->dsp_buf;
1230 pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1231 write->buf_addr_lsw = lower_32_bits(ab->phys);
1232 write->buf_addr_msw = upper_32_bits(ab->phys);
1233 write->buf_size = len;
1234 write->seq_id = port->dsp_buf;
1235 write->timestamp_lsw = lsw_ts;
1236 write->timestamp_msw = msw_ts;
1237 write->mem_map_handle =
1238 ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1239
1240 if (wflags == NO_TIMESTAMP)
1241 write->flags = (wflags & 0x800000FF);
1242 else
1243 write->flags = (0x80000000 | wflags);
1244
1245 port->dsp_buf++;
1246
1247 if (port->dsp_buf >= port->num_periods)
1248 port->dsp_buf = 0;
1249
1250 spin_unlock_irqrestore(&ac->lock, flags);
1251 rc = apr_send_pkt(ac->adev, pkt);
1252 if (rc == pkt_size)
1253 rc = 0;
1254
1255 kfree(pkt);
1256 return rc;
1257}
1258EXPORT_SYMBOL_GPL(q6asm_write_async);
1259
1260static void q6asm_reset_buf_state(struct audio_client *ac)
1261{
1262 struct audio_port_data *port = NULL;
1263 unsigned long flags;
1264
1265 spin_lock_irqsave(&ac->lock, flags);
1266 port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1267 port->dsp_buf = 0;
1268 port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1269 port->dsp_buf = 0;
1270 spin_unlock_irqrestore(&ac->lock, flags);
1271}
1272
1273static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
1274{
1275 int stream_id = ac->stream_id;
1276 struct apr_pkt pkt;
1277 int rc;
1278
1279 q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1280
1281 switch (cmd) {
1282 case CMD_PAUSE:
1283 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1284 break;
1285 case CMD_SUSPEND:
1286 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1287 break;
1288 case CMD_FLUSH:
1289 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1290 break;
1291 case CMD_OUT_FLUSH:
1292 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1293 break;
1294 case CMD_EOS:
1295 pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1296 break;
1297 case CMD_CLOSE:
1298 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1299 break;
1300 default:
1301 return -EINVAL;
1302 }
1303
1304 if (wait)
1305 rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1306 else
1307 return apr_send_pkt(ac->adev, &pkt);
1308
1309 if (rc < 0)
1310 return rc;
1311
1312 if (cmd == CMD_FLUSH)
1313 q6asm_reset_buf_state(ac);
1314
1315 return 0;
1316}
1317
1318/**
1319 * q6asm_cmd() - run cmd on audio client
1320 *
1321 * @ac: audio client pointer
1322 * @cmd: command to run on audio client.
1323 *
1324 * Return: Will be an negative value on error or zero on success
1325 */
1326int q6asm_cmd(struct audio_client *ac, int cmd)
1327{
1328 return __q6asm_cmd(ac, cmd, true);
1329}
1330EXPORT_SYMBOL_GPL(q6asm_cmd);
1331
1332/**
1333 * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1334 *
1335 * @ac: audio client pointer
1336 * @cmd: command to run on audio client.
1337 *
1338 * Return: Will be an negative value on error or zero on success
1339 */
1340int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
1341{
1342 return __q6asm_cmd(ac, cmd, false);
1343}
1344EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +01001345
1346static int q6asm_probe(struct apr_device *adev)
1347{
1348 struct device *dev = &adev->dev;
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +01001349 struct q6asm *q6asm;
1350
1351 q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1352 if (!q6asm)
1353 return -ENOMEM;
1354
1355 q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1356
1357 q6asm->dev = dev;
1358 q6asm->adev = adev;
1359 init_waitqueue_head(&q6asm->mem_wait);
1360 spin_lock_init(&q6asm->slock);
1361 dev_set_drvdata(dev, q6asm);
1362
Srinivas Kandagatla4aac7e22018-06-26 10:20:09 +01001363 return of_platform_populate(dev->of_node, NULL, NULL, dev);
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +01001364}
1365
1366static int q6asm_remove(struct apr_device *adev)
1367{
Srinivas Kandagatla4aac7e22018-06-26 10:20:09 +01001368 of_platform_depopulate(&adev->dev);
Srinivas Kandagatlaa13e8722018-05-18 13:56:01 +01001369
1370 return 0;
1371}
1372static const struct of_device_id q6asm_device_id[] = {
1373 { .compatible = "qcom,q6asm" },
1374 {},
1375};
1376MODULE_DEVICE_TABLE(of, q6asm_device_id);
1377
1378static struct apr_driver qcom_q6asm_driver = {
1379 .probe = q6asm_probe,
1380 .remove = q6asm_remove,
1381 .callback = q6asm_srvc_callback,
1382 .driver = {
1383 .name = "qcom-q6asm",
1384 .of_match_table = of_match_ptr(q6asm_device_id),
1385 },
1386};
1387
1388module_apr_driver(qcom_q6asm_driver);
1389MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1390MODULE_LICENSE("GPL v2");