ASoC: q6asm: add support to remove intial and trailing silence
[linux-2.6-microblaze.git] / sound / soc / qcom / qdsp6 / q6asm.c
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_MEDIA_FMT_FLAC                      0x00010C16
43 #define ASM_MEDIA_FMT_WMA_V9                    0x00010DA8
44 #define ASM_MEDIA_FMT_WMA_V10                   0x00010DA7
45 #define ASM_DATA_CMD_WRITE_V2                   0x00010DAB
46 #define ASM_DATA_CMD_READ_V2                    0x00010DAC
47 #define ASM_SESSION_CMD_SUSPEND                 0x00010DEC
48 #define ASM_STREAM_CMD_OPEN_WRITE_V3            0x00010DB3
49 #define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
50 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
51 #define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
52 #define ASM_MEDIA_FMT_ALAC                      0x00012f31
53 #define ASM_MEDIA_FMT_APE                       0x00012f32
54 #define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE     0x00010D67
55 #define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE    0x00010D68
56
57
58 #define ASM_LEGACY_STREAM_SESSION       0
59 /* Bit shift for the stream_perf_mode subfield. */
60 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
61 #define ASM_END_POINT_DEVICE_MATRIX     0
62 #define ASM_DEFAULT_APP_TYPE            0
63 #define ASM_SYNC_IO_MODE                0x0001
64 #define ASM_ASYNC_IO_MODE               0x0002
65 #define ASM_TUN_READ_IO_MODE            0x0004  /* tunnel read write mode */
66 #define ASM_TUN_WRITE_IO_MODE           0x0008  /* tunnel read write mode */
67 #define ASM_SHIFT_GAPLESS_MODE_FLAG     31
68 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL  3
69
70 struct avs_cmd_shared_mem_map_regions {
71         u16 mem_pool_id;
72         u16 num_regions;
73         u32 property_flag;
74 } __packed;
75
76 struct avs_shared_map_region_payload {
77         u32 shm_addr_lsw;
78         u32 shm_addr_msw;
79         u32 mem_size_bytes;
80 } __packed;
81
82 struct avs_cmd_shared_mem_unmap_regions {
83         u32 mem_map_handle;
84 } __packed;
85
86 struct asm_data_cmd_media_fmt_update_v2 {
87         u32 fmt_blk_size;
88 } __packed;
89
90 struct asm_multi_channel_pcm_fmt_blk_v2 {
91         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
92         u16 num_channels;
93         u16 bits_per_sample;
94         u32 sample_rate;
95         u16 is_signed;
96         u16 reserved;
97         u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
98 } __packed;
99
100 struct asm_flac_fmt_blk_v2 {
101         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
102         u16 is_stream_info_present;
103         u16 num_channels;
104         u16 min_blk_size;
105         u16 max_blk_size;
106         u16 md5_sum[8];
107         u32 sample_rate;
108         u32 min_frame_size;
109         u32 max_frame_size;
110         u16 sample_size;
111         u16 reserved;
112 } __packed;
113
114 struct asm_wmastdv9_fmt_blk_v2 {
115         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
116         u16          fmtag;
117         u16          num_channels;
118         u32          sample_rate;
119         u32          bytes_per_sec;
120         u16          blk_align;
121         u16          bits_per_sample;
122         u32          channel_mask;
123         u16          enc_options;
124         u16          reserved;
125 } __packed;
126
127 struct asm_wmaprov10_fmt_blk_v2 {
128         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
129         u16          fmtag;
130         u16          num_channels;
131         u32          sample_rate;
132         u32          bytes_per_sec;
133         u16          blk_align;
134         u16          bits_per_sample;
135         u32          channel_mask;
136         u16          enc_options;
137         u16          advanced_enc_options1;
138         u32          advanced_enc_options2;
139 } __packed;
140
141 struct asm_alac_fmt_blk_v2 {
142         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
143         u32 frame_length;
144         u8 compatible_version;
145         u8 bit_depth;
146         u8 pb;
147         u8 mb;
148         u8 kb;
149         u8 num_channels;
150         u16 max_run;
151         u32 max_frame_bytes;
152         u32 avg_bit_rate;
153         u32 sample_rate;
154         u32 channel_layout_tag;
155 } __packed;
156
157 struct asm_ape_fmt_blk_v2 {
158         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
159         u16 compatible_version;
160         u16 compression_level;
161         u32 format_flags;
162         u32 blocks_per_frame;
163         u32 final_frame_blocks;
164         u32 total_frames;
165         u16 bits_per_sample;
166         u16 num_channels;
167         u32 sample_rate;
168         u32 seek_table_present;
169 } __packed;
170
171 struct asm_stream_cmd_set_encdec_param {
172         u32                  param_id;
173         u32                  param_size;
174 } __packed;
175
176 struct asm_enc_cfg_blk_param_v2 {
177         u32                  frames_per_buf;
178         u32                  enc_cfg_blk_size;
179 } __packed;
180
181 struct asm_multi_channel_pcm_enc_cfg_v2 {
182         struct asm_stream_cmd_set_encdec_param  encdec;
183         struct asm_enc_cfg_blk_param_v2 encblk;
184         uint16_t  num_channels;
185         uint16_t  bits_per_sample;
186         uint32_t  sample_rate;
187         uint16_t  is_signed;
188         uint16_t  reserved;
189         uint8_t   channel_mapping[8];
190 } __packed;
191
192 struct asm_data_cmd_read_v2 {
193         u32                  buf_addr_lsw;
194         u32                  buf_addr_msw;
195         u32                  mem_map_handle;
196         u32                  buf_size;
197         u32                  seq_id;
198 } __packed;
199
200 struct asm_data_cmd_read_v2_done {
201         u32     status;
202         u32     buf_addr_lsw;
203         u32     buf_addr_msw;
204 };
205
206 struct asm_stream_cmd_open_read_v3 {
207         u32                    mode_flags;
208         u32                    src_endpointype;
209         u32                    preprocopo_id;
210         u32                    enc_cfg_id;
211         u16                    bits_per_sample;
212         u16                    reserved;
213 } __packed;
214
215 struct asm_data_cmd_write_v2 {
216         u32 buf_addr_lsw;
217         u32 buf_addr_msw;
218         u32 mem_map_handle;
219         u32 buf_size;
220         u32 seq_id;
221         u32 timestamp_lsw;
222         u32 timestamp_msw;
223         u32 flags;
224 } __packed;
225
226 struct asm_stream_cmd_open_write_v3 {
227         uint32_t mode_flags;
228         uint16_t sink_endpointype;
229         uint16_t bits_per_sample;
230         uint32_t postprocopo_id;
231         uint32_t dec_fmt_id;
232 } __packed;
233
234 struct asm_session_cmd_run_v2 {
235         u32 flags;
236         u32 time_lsw;
237         u32 time_msw;
238 } __packed;
239
240 struct audio_buffer {
241         phys_addr_t phys;
242         uint32_t size;          /* size of buffer */
243 };
244
245 struct audio_port_data {
246         struct audio_buffer *buf;
247         uint32_t num_periods;
248         uint32_t dsp_buf;
249         uint32_t mem_map_handle;
250 };
251
252 struct q6asm {
253         struct apr_device *adev;
254         struct device *dev;
255         struct q6core_svc_api_info ainfo;
256         wait_queue_head_t mem_wait;
257         spinlock_t slock;
258         struct audio_client *session[MAX_SESSIONS + 1];
259 };
260
261 struct audio_client {
262         int session;
263         q6asm_cb cb;
264         void *priv;
265         uint32_t io_mode;
266         struct apr_device *adev;
267         struct mutex cmd_lock;
268         spinlock_t lock;
269         struct kref refcount;
270         /* idx:1 out port, 0: in port */
271         struct audio_port_data port[2];
272         wait_queue_head_t cmd_wait;
273         struct aprv2_ibasic_rsp_result_t result;
274         int perf_mode;
275         struct q6asm *q6asm;
276         struct device *dev;
277 };
278
279 static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
280                                  uint32_t pkt_size, bool cmd_flg,
281                                  uint32_t stream_id)
282 {
283         hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
284         hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
285         hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
286         hdr->pkt_size = pkt_size;
287         if (cmd_flg)
288                 hdr->token = ac->session;
289 }
290
291 static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
292                                       struct apr_pkt *pkt, uint32_t rsp_opcode)
293 {
294         struct apr_hdr *hdr = &pkt->hdr;
295         int rc;
296
297         mutex_lock(&ac->cmd_lock);
298         ac->result.opcode = 0;
299         ac->result.status = 0;
300         rc = apr_send_pkt(a->adev, pkt);
301         if (rc < 0)
302                 goto err;
303
304         if (rsp_opcode)
305                 rc = wait_event_timeout(a->mem_wait,
306                                         (ac->result.opcode == hdr->opcode) ||
307                                         (ac->result.opcode == rsp_opcode),
308                                         5 * HZ);
309         else
310                 rc = wait_event_timeout(a->mem_wait,
311                                         (ac->result.opcode == hdr->opcode),
312                                         5 * HZ);
313
314         if (!rc) {
315                 dev_err(a->dev, "CMD %x timeout\n", hdr->opcode);
316                 rc = -ETIMEDOUT;
317         } else if (ac->result.status > 0) {
318                 dev_err(a->dev, "DSP returned error[%x]\n",
319                         ac->result.status);
320                 rc = -EINVAL;
321         }
322
323 err:
324         mutex_unlock(&ac->cmd_lock);
325         return rc;
326 }
327
328 static int __q6asm_memory_unmap(struct audio_client *ac,
329                                 phys_addr_t buf_add, int dir)
330 {
331         struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
332         struct q6asm *a = dev_get_drvdata(ac->dev->parent);
333         struct apr_pkt *pkt;
334         int rc, pkt_size;
335         void *p;
336
337         if (ac->port[dir].mem_map_handle == 0) {
338                 dev_err(ac->dev, "invalid mem handle\n");
339                 return -EINVAL;
340         }
341
342         pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
343         p = kzalloc(pkt_size, GFP_KERNEL);
344         if (!p)
345                 return -ENOMEM;
346
347         pkt = p;
348         mem_unmap = p + APR_HDR_SIZE;
349
350         pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
351         pkt->hdr.src_port = 0;
352         pkt->hdr.dest_port = 0;
353         pkt->hdr.pkt_size = pkt_size;
354         pkt->hdr.token = ((ac->session << 8) | dir);
355
356         pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
357         mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
358
359         rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
360         if (rc < 0) {
361                 kfree(pkt);
362                 return rc;
363         }
364
365         ac->port[dir].mem_map_handle = 0;
366
367         kfree(pkt);
368         return 0;
369 }
370
371
372 static void q6asm_audio_client_free_buf(struct audio_client *ac,
373                                         struct audio_port_data *port)
374 {
375         unsigned long flags;
376
377         spin_lock_irqsave(&ac->lock, flags);
378         port->num_periods = 0;
379         kfree(port->buf);
380         port->buf = NULL;
381         spin_unlock_irqrestore(&ac->lock, flags);
382 }
383
384 /**
385  * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
386  *
387  * @dir: direction of audio stream
388  * @ac: audio client instanace
389  *
390  * Return: Will be an negative value on failure or zero on success
391  */
392 int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
393 {
394         struct audio_port_data *port;
395         int cnt = 0;
396         int rc = 0;
397
398         port = &ac->port[dir];
399         if (!port->buf) {
400                 rc = -EINVAL;
401                 goto err;
402         }
403
404         cnt = port->num_periods - 1;
405         if (cnt >= 0) {
406                 rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
407                 if (rc < 0) {
408                         dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
409                                 __func__, rc);
410                         goto err;
411                 }
412         }
413
414         q6asm_audio_client_free_buf(ac, port);
415
416 err:
417         return rc;
418 }
419 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
420
421 static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
422                                       size_t period_sz, unsigned int periods,
423                                       bool is_contiguous)
424 {
425         struct avs_cmd_shared_mem_map_regions *cmd = NULL;
426         struct avs_shared_map_region_payload *mregions = NULL;
427         struct q6asm *a = dev_get_drvdata(ac->dev->parent);
428         struct audio_port_data *port = NULL;
429         struct audio_buffer *ab = NULL;
430         struct apr_pkt *pkt;
431         void *p;
432         unsigned long flags;
433         uint32_t num_regions, buf_sz;
434         int rc, i, pkt_size;
435
436         if (is_contiguous) {
437                 num_regions = 1;
438                 buf_sz = period_sz * periods;
439         } else {
440                 buf_sz = period_sz;
441                 num_regions = periods;
442         }
443
444         /* DSP expects size should be aligned to 4K */
445         buf_sz = ALIGN(buf_sz, 4096);
446
447         pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
448                    (sizeof(*mregions) * num_regions);
449
450         p = kzalloc(pkt_size, GFP_KERNEL);
451         if (!p)
452                 return -ENOMEM;
453
454         pkt = p;
455         cmd = p + APR_HDR_SIZE;
456         mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
457
458         pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
459         pkt->hdr.src_port = 0;
460         pkt->hdr.dest_port = 0;
461         pkt->hdr.pkt_size = pkt_size;
462         pkt->hdr.token = ((ac->session << 8) | dir);
463         pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
464
465         cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
466         cmd->num_regions = num_regions;
467         cmd->property_flag = 0x00;
468
469         spin_lock_irqsave(&ac->lock, flags);
470         port = &ac->port[dir];
471
472         for (i = 0; i < num_regions; i++) {
473                 ab = &port->buf[i];
474                 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
475                 mregions->shm_addr_msw = upper_32_bits(ab->phys);
476                 mregions->mem_size_bytes = buf_sz;
477                 ++mregions;
478         }
479         spin_unlock_irqrestore(&ac->lock, flags);
480
481         rc = q6asm_apr_send_session_pkt(a, ac, pkt,
482                                         ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
483
484         kfree(pkt);
485
486         return rc;
487 }
488
489 /**
490  * q6asm_map_memory_regions() - map memory regions in the dsp.
491  *
492  * @dir: direction of audio stream
493  * @ac: audio client instanace
494  * @phys: physcial address that needs mapping.
495  * @period_sz: audio period size
496  * @periods: number of periods
497  *
498  * Return: Will be an negative value on failure or zero on success
499  */
500 int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
501                              phys_addr_t phys,
502                              size_t period_sz, unsigned int periods)
503 {
504         struct audio_buffer *buf;
505         unsigned long flags;
506         int cnt;
507         int rc;
508
509         spin_lock_irqsave(&ac->lock, flags);
510         if (ac->port[dir].buf) {
511                 dev_err(ac->dev, "Buffer already allocated\n");
512                 spin_unlock_irqrestore(&ac->lock, flags);
513                 return 0;
514         }
515
516         buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
517         if (!buf) {
518                 spin_unlock_irqrestore(&ac->lock, flags);
519                 return -ENOMEM;
520         }
521
522
523         ac->port[dir].buf = buf;
524
525         buf[0].phys = phys;
526         buf[0].size = period_sz;
527
528         for (cnt = 1; cnt < periods; cnt++) {
529                 if (period_sz > 0) {
530                         buf[cnt].phys = buf[0].phys + (cnt * period_sz);
531                         buf[cnt].size = period_sz;
532                 }
533         }
534         ac->port[dir].num_periods = periods;
535
536         spin_unlock_irqrestore(&ac->lock, flags);
537
538         rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
539         if (rc < 0) {
540                 dev_err(ac->dev, "Memory_map_regions failed\n");
541                 q6asm_audio_client_free_buf(ac, &ac->port[dir]);
542         }
543
544         return rc;
545 }
546 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
547
548 static void q6asm_audio_client_release(struct kref *ref)
549 {
550         struct audio_client *ac;
551         struct q6asm *a;
552         unsigned long flags;
553
554         ac = container_of(ref, struct audio_client, refcount);
555         a = ac->q6asm;
556
557         spin_lock_irqsave(&a->slock, flags);
558         a->session[ac->session] = NULL;
559         spin_unlock_irqrestore(&a->slock, flags);
560
561         kfree(ac);
562 }
563
564 /**
565  * q6asm_audio_client_free() - Freee allocated audio client
566  *
567  * @ac: audio client to free
568  */
569 void q6asm_audio_client_free(struct audio_client *ac)
570 {
571         kref_put(&ac->refcount, q6asm_audio_client_release);
572 }
573 EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
574
575 static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
576                                                    int session_id)
577 {
578         struct audio_client *ac = NULL;
579         unsigned long flags;
580
581         spin_lock_irqsave(&a->slock, flags);
582         if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
583                 dev_err(a->dev, "invalid session: %d\n", session_id);
584                 goto err;
585         }
586
587         /* check for valid session */
588         if (!a->session[session_id])
589                 goto err;
590         else if (a->session[session_id]->session != session_id)
591                 goto err;
592
593         ac = a->session[session_id];
594         kref_get(&ac->refcount);
595 err:
596         spin_unlock_irqrestore(&a->slock, flags);
597         return ac;
598 }
599
600 static int32_t q6asm_stream_callback(struct apr_device *adev,
601                                      struct apr_resp_pkt *data,
602                                      int session_id)
603 {
604         struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
605         struct aprv2_ibasic_rsp_result_t *result;
606         struct apr_hdr *hdr = &data->hdr;
607         struct audio_port_data *port;
608         struct audio_client *ac;
609         uint32_t client_event = 0;
610         int ret = 0;
611
612         ac = q6asm_get_audio_client(q6asm, session_id);
613         if (!ac)/* Audio client might already be freed by now */
614                 return 0;
615
616         result = data->payload;
617
618         switch (hdr->opcode) {
619         case APR_BASIC_RSP_RESULT:
620                 switch (result->opcode) {
621                 case ASM_SESSION_CMD_PAUSE:
622                         client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
623                         break;
624                 case ASM_SESSION_CMD_SUSPEND:
625                         client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
626                         break;
627                 case ASM_STREAM_CMD_FLUSH:
628                         client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
629                         break;
630                 case ASM_SESSION_CMD_RUN_V2:
631                         client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
632                         break;
633                 case ASM_STREAM_CMD_CLOSE:
634                         client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
635                         break;
636                 case ASM_STREAM_CMD_FLUSH_READBUFS:
637                         client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
638                         break;
639                 case ASM_STREAM_CMD_OPEN_WRITE_V3:
640                 case ASM_STREAM_CMD_OPEN_READ_V3:
641                 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
642                 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
643                 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
644                 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
645                 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
646                         if (result->status != 0) {
647                                 dev_err(ac->dev,
648                                         "cmd = 0x%x returned error = 0x%x\n",
649                                         result->opcode, result->status);
650                                 ac->result = *result;
651                                 wake_up(&ac->cmd_wait);
652                                 ret = 0;
653                                 goto done;
654                         }
655                         break;
656                 default:
657                         dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
658                                 result->opcode);
659                         break;
660                 }
661
662                 ac->result = *result;
663                 wake_up(&ac->cmd_wait);
664
665                 if (ac->cb)
666                         ac->cb(client_event, hdr->token,
667                                data->payload, ac->priv);
668
669                 ret = 0;
670                 goto done;
671
672         case ASM_DATA_EVENT_WRITE_DONE_V2:
673                 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
674                 if (ac->io_mode & ASM_SYNC_IO_MODE) {
675                         phys_addr_t phys;
676                         unsigned long flags;
677                         int token = hdr->token & ASM_WRITE_TOKEN_MASK;
678
679                         spin_lock_irqsave(&ac->lock, flags);
680
681                         port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
682
683                         if (!port->buf) {
684                                 spin_unlock_irqrestore(&ac->lock, flags);
685                                 ret = 0;
686                                 goto done;
687                         }
688
689                         phys = port->buf[token].phys;
690
691                         if (lower_32_bits(phys) != result->opcode ||
692                             upper_32_bits(phys) != result->status) {
693                                 dev_err(ac->dev, "Expected addr %pa\n",
694                                         &port->buf[token].phys);
695                                 spin_unlock_irqrestore(&ac->lock, flags);
696                                 ret = -EINVAL;
697                                 goto done;
698                         }
699                         spin_unlock_irqrestore(&ac->lock, flags);
700                 }
701                 break;
702         case ASM_DATA_EVENT_READ_DONE_V2:
703                 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
704                 if (ac->io_mode & ASM_SYNC_IO_MODE) {
705                         struct asm_data_cmd_read_v2_done *done = data->payload;
706                         unsigned long flags;
707                         phys_addr_t phys;
708
709                         spin_lock_irqsave(&ac->lock, flags);
710                         port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
711                         if (!port->buf) {
712                                 spin_unlock_irqrestore(&ac->lock, flags);
713                                 ret = 0;
714                                 goto done;
715                         }
716
717                         phys = port->buf[hdr->token].phys;
718
719                         if (upper_32_bits(phys) != done->buf_addr_msw ||
720                             lower_32_bits(phys) != done->buf_addr_lsw) {
721                                 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
722                                         &port->buf[hdr->token].phys,
723                                         done->buf_addr_lsw,
724                                         done->buf_addr_msw);
725                                 spin_unlock_irqrestore(&ac->lock, flags);
726                                 ret = -EINVAL;
727                                 goto done;
728                         }
729                         spin_unlock_irqrestore(&ac->lock, flags);
730                 }
731
732                 break;
733         case ASM_DATA_EVENT_RENDERED_EOS:
734                 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
735                 break;
736         }
737
738         if (ac->cb)
739                 ac->cb(client_event, hdr->token, data->payload, ac->priv);
740
741 done:
742         kref_put(&ac->refcount, q6asm_audio_client_release);
743         return ret;
744 }
745
746 static int q6asm_srvc_callback(struct apr_device *adev,
747                                struct apr_resp_pkt *data)
748 {
749         struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
750         struct aprv2_ibasic_rsp_result_t *result;
751         struct audio_port_data *port;
752         struct audio_client *ac = NULL;
753         struct apr_hdr *hdr = &data->hdr;
754         struct q6asm *a;
755         uint32_t sid = 0;
756         uint32_t dir = 0;
757         int session_id;
758
759         session_id = (hdr->dest_port >> 8) & 0xFF;
760         if (session_id)
761                 return q6asm_stream_callback(adev, data, session_id);
762
763         sid = (hdr->token >> 8) & 0x0F;
764         ac = q6asm_get_audio_client(q6asm, sid);
765         if (!ac) {
766                 dev_err(&adev->dev, "Audio Client not active\n");
767                 return 0;
768         }
769
770         a = dev_get_drvdata(ac->dev->parent);
771         dir = (hdr->token & 0x0F);
772         port = &ac->port[dir];
773         result = data->payload;
774
775         switch (hdr->opcode) {
776         case APR_BASIC_RSP_RESULT:
777                 switch (result->opcode) {
778                 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
779                 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
780                         ac->result = *result;
781                         wake_up(&a->mem_wait);
782                         break;
783                 default:
784                         dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
785                                  result->opcode);
786                         break;
787                 }
788                 goto done;
789         case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
790                 ac->result.status = 0;
791                 ac->result.opcode = hdr->opcode;
792                 port->mem_map_handle = result->opcode;
793                 wake_up(&a->mem_wait);
794                 break;
795         case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
796                 ac->result.opcode = hdr->opcode;
797                 ac->result.status = 0;
798                 port->mem_map_handle = 0;
799                 wake_up(&a->mem_wait);
800                 break;
801         default:
802                 dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
803                         result->opcode, result->status);
804                 break;
805         }
806
807         if (ac->cb)
808                 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
809
810 done:
811         kref_put(&ac->refcount, q6asm_audio_client_release);
812
813         return 0;
814 }
815
816 /**
817  * q6asm_get_session_id() - get session id for audio client
818  *
819  * @c: audio client pointer
820  *
821  * Return: Will be an session id of the audio client.
822  */
823 int q6asm_get_session_id(struct audio_client *c)
824 {
825         return c->session;
826 }
827 EXPORT_SYMBOL_GPL(q6asm_get_session_id);
828
829 /**
830  * q6asm_audio_client_alloc() - Allocate a new audio client
831  *
832  * @dev: Pointer to asm child device.
833  * @cb: event callback.
834  * @priv: private data associated with this client.
835  * @session_id: session id
836  * @perf_mode: performace mode for this client
837  *
838  * Return: Will be an error pointer on error or a valid audio client
839  * on success.
840  */
841 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
842                                               void *priv, int session_id,
843                                               int perf_mode)
844 {
845         struct q6asm *a = dev_get_drvdata(dev->parent);
846         struct audio_client *ac;
847         unsigned long flags;
848
849         ac = q6asm_get_audio_client(a, session_id + 1);
850         if (ac) {
851                 dev_err(dev, "Audio Client already active\n");
852                 return ac;
853         }
854
855         ac = kzalloc(sizeof(*ac), GFP_KERNEL);
856         if (!ac)
857                 return ERR_PTR(-ENOMEM);
858
859         spin_lock_irqsave(&a->slock, flags);
860         a->session[session_id + 1] = ac;
861         spin_unlock_irqrestore(&a->slock, flags);
862         ac->session = session_id + 1;
863         ac->cb = cb;
864         ac->dev = dev;
865         ac->q6asm = a;
866         ac->priv = priv;
867         ac->io_mode = ASM_SYNC_IO_MODE;
868         ac->perf_mode = perf_mode;
869         ac->adev = a->adev;
870         kref_init(&ac->refcount);
871
872         init_waitqueue_head(&ac->cmd_wait);
873         mutex_init(&ac->cmd_lock);
874         spin_lock_init(&ac->lock);
875
876         return ac;
877 }
878 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
879
880 static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
881 {
882         struct apr_hdr *hdr = &pkt->hdr;
883         int rc;
884
885         mutex_lock(&ac->cmd_lock);
886         ac->result.opcode = 0;
887         ac->result.status = 0;
888
889         rc = apr_send_pkt(ac->adev, pkt);
890         if (rc < 0)
891                 goto err;
892
893         rc = wait_event_timeout(ac->cmd_wait,
894                                 (ac->result.opcode == hdr->opcode), 5 * HZ);
895         if (!rc) {
896                 dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode);
897                 rc =  -ETIMEDOUT;
898                 goto err;
899         }
900
901         if (ac->result.status > 0) {
902                 dev_err(ac->dev, "DSP returned error[%x]\n",
903                         ac->result.status);
904                 rc = -EINVAL;
905         } else {
906                 rc = 0;
907         }
908
909
910 err:
911         mutex_unlock(&ac->cmd_lock);
912         return rc;
913 }
914
915 /**
916  * q6asm_open_write() - Open audio client for writing
917  * @ac: audio client pointer
918  * @format: audio sample format
919  * @codec_profile: compressed format profile
920  * @bits_per_sample: bits per sample
921  *
922  * Return: Will be an negative value on error or zero on success
923  */
924 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
925                      uint32_t format, u32 codec_profile,
926                      uint16_t bits_per_sample)
927 {
928         struct asm_stream_cmd_open_write_v3 *open;
929         struct apr_pkt *pkt;
930         void *p;
931         int rc, pkt_size;
932
933         pkt_size = APR_HDR_SIZE + sizeof(*open);
934
935         p = kzalloc(pkt_size, GFP_KERNEL);
936         if (!p)
937                 return -ENOMEM;
938
939         pkt = p;
940         open = p + APR_HDR_SIZE;
941         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
942
943         pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
944         open->mode_flags = 0x00;
945         open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
946
947         /* source endpoint : matrix */
948         open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
949         open->bits_per_sample = bits_per_sample;
950         open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
951
952         switch (format) {
953         case SND_AUDIOCODEC_MP3:
954                 open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
955                 break;
956         case FORMAT_LINEAR_PCM:
957                 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
958                 break;
959         case SND_AUDIOCODEC_FLAC:
960                 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
961                 break;
962         case SND_AUDIOCODEC_WMA:
963                 switch (codec_profile) {
964                 case SND_AUDIOPROFILE_WMA9:
965                         open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9;
966                         break;
967                 case SND_AUDIOPROFILE_WMA10:
968                 case SND_AUDIOPROFILE_WMA9_PRO:
969                 case SND_AUDIOPROFILE_WMA9_LOSSLESS:
970                 case SND_AUDIOPROFILE_WMA10_LOSSLESS:
971                         open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10;
972                         break;
973                 default:
974                         dev_err(ac->dev, "Invalid codec profile 0x%x\n",
975                                 codec_profile);
976                         rc = -EINVAL;
977                         goto err;
978                 }
979                 break;
980         case SND_AUDIOCODEC_ALAC:
981                 open->dec_fmt_id = ASM_MEDIA_FMT_ALAC;
982                 break;
983         case SND_AUDIOCODEC_APE:
984                 open->dec_fmt_id = ASM_MEDIA_FMT_APE;
985                 break;
986         default:
987                 dev_err(ac->dev, "Invalid format 0x%x\n", format);
988                 rc = -EINVAL;
989                 goto err;
990         }
991
992         rc = q6asm_ac_send_cmd_sync(ac, pkt);
993         if (rc < 0)
994                 goto err;
995
996         ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
997
998 err:
999         kfree(pkt);
1000         return rc;
1001 }
1002 EXPORT_SYMBOL_GPL(q6asm_open_write);
1003
1004 static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
1005                        uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
1006                        bool wait)
1007 {
1008         struct asm_session_cmd_run_v2 *run;
1009         struct apr_pkt *pkt;
1010         int pkt_size, rc;
1011         void *p;
1012
1013         pkt_size = APR_HDR_SIZE + sizeof(*run);
1014         p = kzalloc(pkt_size, GFP_ATOMIC);
1015         if (!p)
1016                 return -ENOMEM;
1017
1018         pkt = p;
1019         run = p + APR_HDR_SIZE;
1020
1021         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1022
1023         pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
1024         run->flags = flags;
1025         run->time_lsw = lsw_ts;
1026         run->time_msw = msw_ts;
1027         if (wait) {
1028                 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1029         } else {
1030                 rc = apr_send_pkt(ac->adev, pkt);
1031                 if (rc == pkt_size)
1032                         rc = 0;
1033         }
1034
1035         kfree(pkt);
1036         return rc;
1037 }
1038
1039 /**
1040  * q6asm_run() - start the audio client
1041  *
1042  * @ac: audio client pointer
1043  * @flags: flags associated with write
1044  * @msw_ts: timestamp msw
1045  * @lsw_ts: timestamp lsw
1046  *
1047  * Return: Will be an negative value on error or zero on success
1048  */
1049 int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
1050               uint32_t msw_ts, uint32_t lsw_ts)
1051 {
1052         return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
1053 }
1054 EXPORT_SYMBOL_GPL(q6asm_run);
1055
1056 /**
1057  * q6asm_run_nowait() - start the audio client withou blocking
1058  *
1059  * @ac: audio client pointer
1060  * @stream_id: stream id
1061  * @flags: flags associated with write
1062  * @msw_ts: timestamp msw
1063  * @lsw_ts: timestamp lsw
1064  *
1065  * Return: Will be an negative value on error or zero on success
1066  */
1067 int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
1068                      uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
1069 {
1070         return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
1071 }
1072 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
1073
1074 /**
1075  * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
1076  *
1077  * @ac: audio client pointer
1078  * @stream_id: stream id
1079  * @rate: audio sample rate
1080  * @channels: number of audio channels.
1081  * @channel_map: channel map pointer
1082  * @bits_per_sample: bits per sample
1083  *
1084  * Return: Will be an negative value on error or zero on success
1085  */
1086 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
1087                                           uint32_t stream_id,
1088                                           uint32_t rate, uint32_t channels,
1089                                           u8 channel_map[PCM_MAX_NUM_CHANNEL],
1090                                           uint16_t bits_per_sample)
1091 {
1092         struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
1093         struct apr_pkt *pkt;
1094         u8 *channel_mapping;
1095         void *p;
1096         int rc, pkt_size;
1097
1098         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1099         p = kzalloc(pkt_size, GFP_KERNEL);
1100         if (!p)
1101                 return -ENOMEM;
1102
1103         pkt = p;
1104         fmt = p + APR_HDR_SIZE;
1105
1106         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1107
1108         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1109         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1110         fmt->num_channels = channels;
1111         fmt->bits_per_sample = bits_per_sample;
1112         fmt->sample_rate = rate;
1113         fmt->is_signed = 1;
1114
1115         channel_mapping = fmt->channel_mapping;
1116
1117         if (channel_map) {
1118                 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1119         } else {
1120                 if (q6dsp_map_channels(channel_mapping, channels)) {
1121                         dev_err(ac->dev, " map channels failed %d\n", channels);
1122                         rc = -EINVAL;
1123                         goto err;
1124                 }
1125         }
1126
1127         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1128
1129 err:
1130         kfree(pkt);
1131         return rc;
1132 }
1133 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1134
1135 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
1136                                          uint32_t stream_id,
1137                                          struct q6asm_flac_cfg *cfg)
1138 {
1139         struct asm_flac_fmt_blk_v2 *fmt;
1140         struct apr_pkt *pkt;
1141         void *p;
1142         int rc, pkt_size;
1143
1144         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1145         p = kzalloc(pkt_size, GFP_KERNEL);
1146         if (!p)
1147                 return -ENOMEM;
1148
1149         pkt = p;
1150         fmt = p + APR_HDR_SIZE;
1151
1152         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1153
1154         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1155         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1156         fmt->is_stream_info_present = cfg->stream_info_present;
1157         fmt->num_channels = cfg->ch_cfg;
1158         fmt->min_blk_size = cfg->min_blk_size;
1159         fmt->max_blk_size = cfg->max_blk_size;
1160         fmt->sample_rate = cfg->sample_rate;
1161         fmt->min_frame_size = cfg->min_frame_size;
1162         fmt->max_frame_size = cfg->max_frame_size;
1163         fmt->sample_size = cfg->sample_size;
1164
1165         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1166         kfree(pkt);
1167
1168         return rc;
1169 }
1170 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
1171
1172 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
1173                                            uint32_t stream_id,
1174                                            struct q6asm_wma_cfg *cfg)
1175 {
1176         struct asm_wmastdv9_fmt_blk_v2 *fmt;
1177         struct apr_pkt *pkt;
1178         void *p;
1179         int rc, pkt_size;
1180
1181         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1182         p = kzalloc(pkt_size, GFP_KERNEL);
1183         if (!p)
1184                 return -ENOMEM;
1185
1186         pkt = p;
1187         fmt = p + APR_HDR_SIZE;
1188
1189         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1190
1191         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1192         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1193         fmt->fmtag = cfg->fmtag;
1194         fmt->num_channels = cfg->num_channels;
1195         fmt->sample_rate = cfg->sample_rate;
1196         fmt->bytes_per_sec = cfg->bytes_per_sec;
1197         fmt->blk_align = cfg->block_align;
1198         fmt->bits_per_sample = cfg->bits_per_sample;
1199         fmt->channel_mask = cfg->channel_mask;
1200         fmt->enc_options = cfg->enc_options;
1201         fmt->reserved = 0;
1202
1203         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1204         kfree(pkt);
1205
1206         return rc;
1207 }
1208 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
1209
1210 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
1211                                             uint32_t stream_id,
1212                                             struct q6asm_wma_cfg *cfg)
1213 {
1214         struct asm_wmaprov10_fmt_blk_v2 *fmt;
1215         struct apr_pkt *pkt;
1216         void *p;
1217         int rc, pkt_size;
1218
1219         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1220         p = kzalloc(pkt_size, GFP_KERNEL);
1221         if (!p)
1222                 return -ENOMEM;
1223
1224         pkt = p;
1225         fmt = p + APR_HDR_SIZE;
1226
1227         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1228
1229         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1230         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1231         fmt->fmtag = cfg->fmtag;
1232         fmt->num_channels = cfg->num_channels;
1233         fmt->sample_rate = cfg->sample_rate;
1234         fmt->bytes_per_sec = cfg->bytes_per_sec;
1235         fmt->blk_align = cfg->block_align;
1236         fmt->bits_per_sample = cfg->bits_per_sample;
1237         fmt->channel_mask = cfg->channel_mask;
1238         fmt->enc_options = cfg->enc_options;
1239         fmt->advanced_enc_options1 = cfg->adv_enc_options;
1240         fmt->advanced_enc_options2 = cfg->adv_enc_options2;
1241
1242         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1243         kfree(pkt);
1244
1245         return rc;
1246 }
1247 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
1248
1249 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
1250                                          uint32_t stream_id,
1251                                          struct q6asm_alac_cfg *cfg)
1252 {
1253         struct asm_alac_fmt_blk_v2 *fmt;
1254         struct apr_pkt *pkt;
1255         void *p;
1256         int rc, pkt_size;
1257
1258         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1259         p = kzalloc(pkt_size, GFP_KERNEL);
1260         if (!p)
1261                 return -ENOMEM;
1262
1263         pkt = p;
1264         fmt = p + APR_HDR_SIZE;
1265
1266         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1267
1268         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1269         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1270
1271         fmt->frame_length = cfg->frame_length;
1272         fmt->compatible_version = cfg->compatible_version;
1273         fmt->bit_depth =  cfg->bit_depth;
1274         fmt->num_channels = cfg->num_channels;
1275         fmt->max_run = cfg->max_run;
1276         fmt->max_frame_bytes = cfg->max_frame_bytes;
1277         fmt->avg_bit_rate = cfg->avg_bit_rate;
1278         fmt->sample_rate = cfg->sample_rate;
1279         fmt->channel_layout_tag = cfg->channel_layout_tag;
1280         fmt->pb = cfg->pb;
1281         fmt->mb = cfg->mb;
1282         fmt->kb = cfg->kb;
1283
1284         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1285         kfree(pkt);
1286
1287         return rc;
1288 }
1289 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
1290
1291 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
1292                                         uint32_t stream_id,
1293                                         struct q6asm_ape_cfg *cfg)
1294 {
1295         struct asm_ape_fmt_blk_v2 *fmt;
1296         struct apr_pkt *pkt;
1297         void *p;
1298         int rc, pkt_size;
1299
1300         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1301         p = kzalloc(pkt_size, GFP_KERNEL);
1302         if (!p)
1303                 return -ENOMEM;
1304
1305         pkt = p;
1306         fmt = p + APR_HDR_SIZE;
1307
1308         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1309
1310         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1311         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1312
1313         fmt->compatible_version = cfg->compatible_version;
1314         fmt->compression_level = cfg->compression_level;
1315         fmt->format_flags = cfg->format_flags;
1316         fmt->blocks_per_frame = cfg->blocks_per_frame;
1317         fmt->final_frame_blocks = cfg->final_frame_blocks;
1318         fmt->total_frames = cfg->total_frames;
1319         fmt->bits_per_sample = cfg->bits_per_sample;
1320         fmt->num_channels = cfg->num_channels;
1321         fmt->sample_rate = cfg->sample_rate;
1322         fmt->seek_table_present = cfg->seek_table_present;
1323
1324         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1325         kfree(pkt);
1326
1327         return rc;
1328 }
1329 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
1330
1331 static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
1332                                        uint32_t cmd,
1333                                        uint32_t num_samples)
1334 {
1335         uint32_t *samples;
1336         struct apr_pkt *pkt;
1337         void *p;
1338         int rc, pkt_size;
1339
1340         pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
1341         p = kzalloc(pkt_size, GFP_ATOMIC);
1342         if (!p)
1343                 return -ENOMEM;
1344
1345         pkt = p;
1346         samples = p + APR_HDR_SIZE;
1347
1348         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1349
1350         pkt->hdr.opcode = cmd;
1351         *samples = num_samples;
1352         rc = apr_send_pkt(ac->adev, pkt);
1353         if (rc == pkt_size)
1354                 rc = 0;
1355
1356         kfree(pkt);
1357
1358         return rc;
1359 }
1360
1361 int q6asm_stream_remove_initial_silence(struct audio_client *ac,
1362                                         uint32_t stream_id,
1363                                         uint32_t initial_samples)
1364 {
1365         return q6asm_stream_remove_silence(ac, stream_id,
1366                                            ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
1367                                            initial_samples);
1368 }
1369 EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
1370
1371 int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
1372                                          uint32_t trailing_samples)
1373 {
1374         return q6asm_stream_remove_silence(ac, stream_id,
1375                                    ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
1376                                    trailing_samples);
1377 }
1378 EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
1379
1380 /**
1381  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1382  *
1383  * @ac: audio client pointer
1384  * @stream_id: stream id
1385  * @rate: audio sample rate
1386  * @channels: number of audio channels.
1387  * @bits_per_sample: bits per sample
1388  *
1389  * Return: Will be an negative value on error or zero on success
1390  */
1391 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1392                                          uint32_t stream_id, uint32_t rate,
1393                                          uint32_t channels,
1394                                          uint16_t bits_per_sample)
1395 {
1396         struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
1397         struct apr_pkt *pkt;
1398         u8 *channel_mapping;
1399         u32 frames_per_buf = 0;
1400         int pkt_size, rc;
1401         void *p;
1402
1403         pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1404         p = kzalloc(pkt_size, GFP_KERNEL);
1405         if (!p)
1406                 return -ENOMEM;
1407
1408         pkt = p;
1409         enc_cfg = p + APR_HDR_SIZE;
1410         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1411
1412         pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1413         enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1414         enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1415         enc_cfg->encblk.frames_per_buf = frames_per_buf;
1416         enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
1417                                         sizeof(struct asm_enc_cfg_blk_param_v2);
1418
1419         enc_cfg->num_channels = channels;
1420         enc_cfg->bits_per_sample = bits_per_sample;
1421         enc_cfg->sample_rate = rate;
1422         enc_cfg->is_signed = 1;
1423         channel_mapping = enc_cfg->channel_mapping;
1424
1425         if (q6dsp_map_channels(channel_mapping, channels)) {
1426                 rc = -EINVAL;
1427                 goto err;
1428         }
1429
1430         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1431 err:
1432         kfree(pkt);
1433         return rc;
1434 }
1435 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1436
1437
1438 /**
1439  * q6asm_read() - read data of period size from audio client
1440  *
1441  * @ac: audio client pointer
1442  * @stream_id: stream id
1443  *
1444  * Return: Will be an negative value on error or zero on success
1445  */
1446 int q6asm_read(struct audio_client *ac, uint32_t stream_id)
1447 {
1448         struct asm_data_cmd_read_v2 *read;
1449         struct audio_port_data *port;
1450         struct audio_buffer *ab;
1451         struct apr_pkt *pkt;
1452         unsigned long flags;
1453         int pkt_size;
1454         int rc = 0;
1455         void *p;
1456
1457         pkt_size = APR_HDR_SIZE + sizeof(*read);
1458         p = kzalloc(pkt_size, GFP_ATOMIC);
1459         if (!p)
1460                 return -ENOMEM;
1461
1462         pkt = p;
1463         read = p + APR_HDR_SIZE;
1464
1465         spin_lock_irqsave(&ac->lock, flags);
1466         port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1467         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1468         ab = &port->buf[port->dsp_buf];
1469         pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1470         read->buf_addr_lsw = lower_32_bits(ab->phys);
1471         read->buf_addr_msw = upper_32_bits(ab->phys);
1472         read->mem_map_handle = port->mem_map_handle;
1473
1474         read->buf_size = ab->size;
1475         read->seq_id = port->dsp_buf;
1476         pkt->hdr.token = port->dsp_buf;
1477
1478         port->dsp_buf++;
1479
1480         if (port->dsp_buf >= port->num_periods)
1481                 port->dsp_buf = 0;
1482
1483         spin_unlock_irqrestore(&ac->lock, flags);
1484         rc = apr_send_pkt(ac->adev, pkt);
1485         if (rc == pkt_size)
1486                 rc = 0;
1487         else
1488                 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1489
1490         kfree(pkt);
1491         return rc;
1492 }
1493 EXPORT_SYMBOL_GPL(q6asm_read);
1494
1495 static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1496                 uint32_t format, uint16_t bits_per_sample)
1497 {
1498         struct asm_stream_cmd_open_read_v3 *open;
1499         struct apr_pkt *pkt;
1500         int pkt_size, rc;
1501         void *p;
1502
1503         pkt_size = APR_HDR_SIZE + sizeof(*open);
1504         p = kzalloc(pkt_size, GFP_KERNEL);
1505         if (!p)
1506                 return -ENOMEM;
1507
1508         pkt = p;
1509         open = p + APR_HDR_SIZE;
1510
1511         q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, stream_id);
1512         pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1513         /* Stream prio : High, provide meta info with encoded frames */
1514         open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1515
1516         open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1517         open->bits_per_sample = bits_per_sample;
1518         open->mode_flags = 0x0;
1519
1520         open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1521                                 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1522
1523         switch (format) {
1524         case FORMAT_LINEAR_PCM:
1525                 open->mode_flags |= 0x00;
1526                 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1527                 break;
1528         default:
1529                 pr_err("Invalid format[%d]\n", format);
1530         }
1531
1532         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1533
1534         kfree(pkt);
1535         return rc;
1536 }
1537
1538 /**
1539  * q6asm_open_read() - Open audio client for reading
1540  *
1541  * @ac: audio client pointer
1542  * @stream_id: stream id
1543  * @format: audio sample format
1544  * @bits_per_sample: bits per sample
1545  *
1546  * Return: Will be an negative value on error or zero on success
1547  */
1548 int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1549                     uint32_t format, uint16_t bits_per_sample)
1550 {
1551         return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
1552 }
1553 EXPORT_SYMBOL_GPL(q6asm_open_read);
1554
1555 /**
1556  * q6asm_write_async() - non blocking write
1557  *
1558  * @ac: audio client pointer
1559  * @stream_id: stream id
1560  * @len: length in bytes
1561  * @msw_ts: timestamp msw
1562  * @lsw_ts: timestamp lsw
1563  * @wflags: flags associated with write
1564  *
1565  * Return: Will be an negative value on error or zero on success
1566  */
1567 int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
1568                       uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
1569 {
1570         struct asm_data_cmd_write_v2 *write;
1571         struct audio_port_data *port;
1572         struct audio_buffer *ab;
1573         unsigned long flags;
1574         struct apr_pkt *pkt;
1575         int pkt_size;
1576         int rc = 0;
1577         void *p;
1578
1579         pkt_size = APR_HDR_SIZE + sizeof(*write);
1580         p = kzalloc(pkt_size, GFP_ATOMIC);
1581         if (!p)
1582                 return -ENOMEM;
1583
1584         pkt = p;
1585         write = p + APR_HDR_SIZE;
1586
1587         spin_lock_irqsave(&ac->lock, flags);
1588         port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1589         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1590
1591         ab = &port->buf[port->dsp_buf];
1592         pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
1593         pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1594         write->buf_addr_lsw = lower_32_bits(ab->phys);
1595         write->buf_addr_msw = upper_32_bits(ab->phys);
1596         write->buf_size = len;
1597         write->seq_id = port->dsp_buf;
1598         write->timestamp_lsw = lsw_ts;
1599         write->timestamp_msw = msw_ts;
1600         write->mem_map_handle =
1601             ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1602
1603         write->flags = wflags;
1604
1605         port->dsp_buf++;
1606
1607         if (port->dsp_buf >= port->num_periods)
1608                 port->dsp_buf = 0;
1609
1610         spin_unlock_irqrestore(&ac->lock, flags);
1611         rc = apr_send_pkt(ac->adev, pkt);
1612         if (rc == pkt_size)
1613                 rc = 0;
1614
1615         kfree(pkt);
1616         return rc;
1617 }
1618 EXPORT_SYMBOL_GPL(q6asm_write_async);
1619
1620 static void q6asm_reset_buf_state(struct audio_client *ac)
1621 {
1622         struct audio_port_data *port = NULL;
1623         unsigned long flags;
1624
1625         spin_lock_irqsave(&ac->lock, flags);
1626         port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1627         port->dsp_buf = 0;
1628         port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1629         port->dsp_buf = 0;
1630         spin_unlock_irqrestore(&ac->lock, flags);
1631 }
1632
1633 static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
1634                        bool wait)
1635 {
1636         struct apr_pkt pkt;
1637         int rc;
1638
1639         q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1640
1641         switch (cmd) {
1642         case CMD_PAUSE:
1643                 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1644                 break;
1645         case CMD_SUSPEND:
1646                 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1647                 break;
1648         case CMD_FLUSH:
1649                 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1650                 break;
1651         case CMD_OUT_FLUSH:
1652                 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1653                 break;
1654         case CMD_EOS:
1655                 pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1656                 break;
1657         case CMD_CLOSE:
1658                 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1659                 break;
1660         default:
1661                 return -EINVAL;
1662         }
1663
1664         if (wait)
1665                 rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1666         else
1667                 return apr_send_pkt(ac->adev, &pkt);
1668
1669         if (rc < 0)
1670                 return rc;
1671
1672         if (cmd == CMD_FLUSH)
1673                 q6asm_reset_buf_state(ac);
1674
1675         return 0;
1676 }
1677
1678 /**
1679  * q6asm_cmd() - run cmd on audio client
1680  *
1681  * @ac: audio client pointer
1682  * @stream_id: stream id
1683  * @cmd: command to run on audio client.
1684  *
1685  * Return: Will be an negative value on error or zero on success
1686  */
1687 int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
1688 {
1689         return __q6asm_cmd(ac, stream_id, cmd, true);
1690 }
1691 EXPORT_SYMBOL_GPL(q6asm_cmd);
1692
1693 /**
1694  * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1695  *
1696  * @ac: audio client pointer
1697  * @stream_id: stream id
1698  * @cmd: command to run on audio client.
1699  *
1700  * Return: Will be an negative value on error or zero on success
1701  */
1702 int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
1703 {
1704         return __q6asm_cmd(ac, stream_id, cmd, false);
1705 }
1706 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1707
1708 static int q6asm_probe(struct apr_device *adev)
1709 {
1710         struct device *dev = &adev->dev;
1711         struct q6asm *q6asm;
1712
1713         q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1714         if (!q6asm)
1715                 return -ENOMEM;
1716
1717         q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1718
1719         q6asm->dev = dev;
1720         q6asm->adev = adev;
1721         init_waitqueue_head(&q6asm->mem_wait);
1722         spin_lock_init(&q6asm->slock);
1723         dev_set_drvdata(dev, q6asm);
1724
1725         return of_platform_populate(dev->of_node, NULL, NULL, dev);
1726 }
1727
1728 static int q6asm_remove(struct apr_device *adev)
1729 {
1730         of_platform_depopulate(&adev->dev);
1731
1732         return 0;
1733 }
1734 static const struct of_device_id q6asm_device_id[]  = {
1735         { .compatible = "qcom,q6asm" },
1736         {},
1737 };
1738 MODULE_DEVICE_TABLE(of, q6asm_device_id);
1739
1740 static struct apr_driver qcom_q6asm_driver = {
1741         .probe = q6asm_probe,
1742         .remove = q6asm_remove,
1743         .callback = q6asm_srvc_callback,
1744         .driver = {
1745                 .name = "qcom-q6asm",
1746                 .of_match_table = of_match_ptr(q6asm_device_id),
1747         },
1748 };
1749
1750 module_apr_driver(qcom_q6asm_driver);
1751 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1752 MODULE_LICENSE("GPL v2");