162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci// Copyright (c) 2018, Linaro Limited
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/mutex.h>
662306a36Sopenharmony_ci#include <linux/wait.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/soc/qcom/apr.h>
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/of_platform.h>
1162306a36Sopenharmony_ci#include <linux/spinlock.h>
1262306a36Sopenharmony_ci#include <linux/kref.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <uapi/sound/asound.h>
1562306a36Sopenharmony_ci#include <uapi/sound/compress_params.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/mm.h>
1962306a36Sopenharmony_ci#include "q6asm.h"
2062306a36Sopenharmony_ci#include "q6core.h"
2162306a36Sopenharmony_ci#include "q6dsp-errno.h"
2262306a36Sopenharmony_ci#include "q6dsp-common.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define ASM_STREAM_CMD_CLOSE			0x00010BCD
2562306a36Sopenharmony_ci#define ASM_STREAM_CMD_FLUSH			0x00010BCE
2662306a36Sopenharmony_ci#define ASM_SESSION_CMD_PAUSE			0x00010BD3
2762306a36Sopenharmony_ci#define ASM_DATA_CMD_EOS			0x00010BDB
2862306a36Sopenharmony_ci#define ASM_DATA_EVENT_RENDERED_EOS		0x00010C1C
2962306a36Sopenharmony_ci#define ASM_NULL_POPP_TOPOLOGY			0x00010C68
3062306a36Sopenharmony_ci#define ASM_STREAM_CMD_FLUSH_READBUFS		0x00010C09
3162306a36Sopenharmony_ci#define ASM_STREAM_CMD_SET_ENCDEC_PARAM		0x00010C10
3262306a36Sopenharmony_ci#define ASM_STREAM_POSTPROC_TOPO_ID_NONE	0x00010C68
3362306a36Sopenharmony_ci#define ASM_CMD_SHARED_MEM_MAP_REGIONS		0x00010D92
3462306a36Sopenharmony_ci#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS	0x00010D93
3562306a36Sopenharmony_ci#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS	0x00010D94
3662306a36Sopenharmony_ci#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2	0x00010D98
3762306a36Sopenharmony_ci#define ASM_DATA_EVENT_WRITE_DONE_V2		0x00010D99
3862306a36Sopenharmony_ci#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2	0x00010DA3
3962306a36Sopenharmony_ci#define ASM_SESSION_CMD_RUN_V2			0x00010DAA
4062306a36Sopenharmony_ci#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2	0x00010DA5
4162306a36Sopenharmony_ci#define ASM_MEDIA_FMT_MP3			0x00010BE9
4262306a36Sopenharmony_ci#define ASM_MEDIA_FMT_FLAC			0x00010C16
4362306a36Sopenharmony_ci#define ASM_MEDIA_FMT_WMA_V9			0x00010DA8
4462306a36Sopenharmony_ci#define ASM_MEDIA_FMT_WMA_V10			0x00010DA7
4562306a36Sopenharmony_ci#define ASM_DATA_CMD_WRITE_V2			0x00010DAB
4662306a36Sopenharmony_ci#define ASM_DATA_CMD_READ_V2			0x00010DAC
4762306a36Sopenharmony_ci#define ASM_SESSION_CMD_SUSPEND			0x00010DEC
4862306a36Sopenharmony_ci#define ASM_STREAM_CMD_OPEN_WRITE_V3		0x00010DB3
4962306a36Sopenharmony_ci#define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
5062306a36Sopenharmony_ci#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
5162306a36Sopenharmony_ci#define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
5262306a36Sopenharmony_ci#define ASM_MEDIA_FMT_ALAC			0x00012f31
5362306a36Sopenharmony_ci#define ASM_MEDIA_FMT_APE			0x00012f32
5462306a36Sopenharmony_ci#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE	0x00010D67
5562306a36Sopenharmony_ci#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE	0x00010D68
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define ASM_LEGACY_STREAM_SESSION	0
5962306a36Sopenharmony_ci/* Bit shift for the stream_perf_mode subfield. */
6062306a36Sopenharmony_ci#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
6162306a36Sopenharmony_ci#define ASM_END_POINT_DEVICE_MATRIX	0
6262306a36Sopenharmony_ci#define ASM_DEFAULT_APP_TYPE		0
6362306a36Sopenharmony_ci#define ASM_SYNC_IO_MODE		0x0001
6462306a36Sopenharmony_ci#define ASM_ASYNC_IO_MODE		0x0002
6562306a36Sopenharmony_ci#define ASM_TUN_READ_IO_MODE		0x0004	/* tunnel read write mode */
6662306a36Sopenharmony_ci#define ASM_TUN_WRITE_IO_MODE		0x0008	/* tunnel read write mode */
6762306a36Sopenharmony_ci#define ASM_SHIFT_GAPLESS_MODE_FLAG	31
6862306a36Sopenharmony_ci#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL	3
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct avs_cmd_shared_mem_map_regions {
7162306a36Sopenharmony_ci	u16 mem_pool_id;
7262306a36Sopenharmony_ci	u16 num_regions;
7362306a36Sopenharmony_ci	u32 property_flag;
7462306a36Sopenharmony_ci} __packed;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistruct avs_shared_map_region_payload {
7762306a36Sopenharmony_ci	u32 shm_addr_lsw;
7862306a36Sopenharmony_ci	u32 shm_addr_msw;
7962306a36Sopenharmony_ci	u32 mem_size_bytes;
8062306a36Sopenharmony_ci} __packed;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct avs_cmd_shared_mem_unmap_regions {
8362306a36Sopenharmony_ci	u32 mem_map_handle;
8462306a36Sopenharmony_ci} __packed;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct asm_data_cmd_media_fmt_update_v2 {
8762306a36Sopenharmony_ci	u32 fmt_blk_size;
8862306a36Sopenharmony_ci} __packed;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct asm_multi_channel_pcm_fmt_blk_v2 {
9162306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
9262306a36Sopenharmony_ci	u16 num_channels;
9362306a36Sopenharmony_ci	u16 bits_per_sample;
9462306a36Sopenharmony_ci	u32 sample_rate;
9562306a36Sopenharmony_ci	u16 is_signed;
9662306a36Sopenharmony_ci	u16 reserved;
9762306a36Sopenharmony_ci	u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
9862306a36Sopenharmony_ci} __packed;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct asm_flac_fmt_blk_v2 {
10162306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
10262306a36Sopenharmony_ci	u16 is_stream_info_present;
10362306a36Sopenharmony_ci	u16 num_channels;
10462306a36Sopenharmony_ci	u16 min_blk_size;
10562306a36Sopenharmony_ci	u16 max_blk_size;
10662306a36Sopenharmony_ci	u16 md5_sum[8];
10762306a36Sopenharmony_ci	u32 sample_rate;
10862306a36Sopenharmony_ci	u32 min_frame_size;
10962306a36Sopenharmony_ci	u32 max_frame_size;
11062306a36Sopenharmony_ci	u16 sample_size;
11162306a36Sopenharmony_ci	u16 reserved;
11262306a36Sopenharmony_ci} __packed;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistruct asm_wmastdv9_fmt_blk_v2 {
11562306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
11662306a36Sopenharmony_ci	u16          fmtag;
11762306a36Sopenharmony_ci	u16          num_channels;
11862306a36Sopenharmony_ci	u32          sample_rate;
11962306a36Sopenharmony_ci	u32          bytes_per_sec;
12062306a36Sopenharmony_ci	u16          blk_align;
12162306a36Sopenharmony_ci	u16          bits_per_sample;
12262306a36Sopenharmony_ci	u32          channel_mask;
12362306a36Sopenharmony_ci	u16          enc_options;
12462306a36Sopenharmony_ci	u16          reserved;
12562306a36Sopenharmony_ci} __packed;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct asm_wmaprov10_fmt_blk_v2 {
12862306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
12962306a36Sopenharmony_ci	u16          fmtag;
13062306a36Sopenharmony_ci	u16          num_channels;
13162306a36Sopenharmony_ci	u32          sample_rate;
13262306a36Sopenharmony_ci	u32          bytes_per_sec;
13362306a36Sopenharmony_ci	u16          blk_align;
13462306a36Sopenharmony_ci	u16          bits_per_sample;
13562306a36Sopenharmony_ci	u32          channel_mask;
13662306a36Sopenharmony_ci	u16          enc_options;
13762306a36Sopenharmony_ci	u16          advanced_enc_options1;
13862306a36Sopenharmony_ci	u32          advanced_enc_options2;
13962306a36Sopenharmony_ci} __packed;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistruct asm_alac_fmt_blk_v2 {
14262306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
14362306a36Sopenharmony_ci	u32 frame_length;
14462306a36Sopenharmony_ci	u8 compatible_version;
14562306a36Sopenharmony_ci	u8 bit_depth;
14662306a36Sopenharmony_ci	u8 pb;
14762306a36Sopenharmony_ci	u8 mb;
14862306a36Sopenharmony_ci	u8 kb;
14962306a36Sopenharmony_ci	u8 num_channels;
15062306a36Sopenharmony_ci	u16 max_run;
15162306a36Sopenharmony_ci	u32 max_frame_bytes;
15262306a36Sopenharmony_ci	u32 avg_bit_rate;
15362306a36Sopenharmony_ci	u32 sample_rate;
15462306a36Sopenharmony_ci	u32 channel_layout_tag;
15562306a36Sopenharmony_ci} __packed;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct asm_ape_fmt_blk_v2 {
15862306a36Sopenharmony_ci	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
15962306a36Sopenharmony_ci	u16 compatible_version;
16062306a36Sopenharmony_ci	u16 compression_level;
16162306a36Sopenharmony_ci	u32 format_flags;
16262306a36Sopenharmony_ci	u32 blocks_per_frame;
16362306a36Sopenharmony_ci	u32 final_frame_blocks;
16462306a36Sopenharmony_ci	u32 total_frames;
16562306a36Sopenharmony_ci	u16 bits_per_sample;
16662306a36Sopenharmony_ci	u16 num_channels;
16762306a36Sopenharmony_ci	u32 sample_rate;
16862306a36Sopenharmony_ci	u32 seek_table_present;
16962306a36Sopenharmony_ci} __packed;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistruct asm_stream_cmd_set_encdec_param {
17262306a36Sopenharmony_ci	u32                  param_id;
17362306a36Sopenharmony_ci	u32                  param_size;
17462306a36Sopenharmony_ci} __packed;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistruct asm_enc_cfg_blk_param_v2 {
17762306a36Sopenharmony_ci	u32                  frames_per_buf;
17862306a36Sopenharmony_ci	u32                  enc_cfg_blk_size;
17962306a36Sopenharmony_ci} __packed;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistruct asm_multi_channel_pcm_enc_cfg_v2 {
18262306a36Sopenharmony_ci	struct asm_stream_cmd_set_encdec_param  encdec;
18362306a36Sopenharmony_ci	struct asm_enc_cfg_blk_param_v2	encblk;
18462306a36Sopenharmony_ci	uint16_t  num_channels;
18562306a36Sopenharmony_ci	uint16_t  bits_per_sample;
18662306a36Sopenharmony_ci	uint32_t  sample_rate;
18762306a36Sopenharmony_ci	uint16_t  is_signed;
18862306a36Sopenharmony_ci	uint16_t  reserved;
18962306a36Sopenharmony_ci	uint8_t   channel_mapping[8];
19062306a36Sopenharmony_ci} __packed;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct asm_data_cmd_read_v2 {
19362306a36Sopenharmony_ci	u32                  buf_addr_lsw;
19462306a36Sopenharmony_ci	u32                  buf_addr_msw;
19562306a36Sopenharmony_ci	u32                  mem_map_handle;
19662306a36Sopenharmony_ci	u32                  buf_size;
19762306a36Sopenharmony_ci	u32                  seq_id;
19862306a36Sopenharmony_ci} __packed;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistruct asm_data_cmd_read_v2_done {
20162306a36Sopenharmony_ci	u32	status;
20262306a36Sopenharmony_ci	u32	buf_addr_lsw;
20362306a36Sopenharmony_ci	u32	buf_addr_msw;
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistruct asm_stream_cmd_open_read_v3 {
20762306a36Sopenharmony_ci	u32                    mode_flags;
20862306a36Sopenharmony_ci	u32                    src_endpointype;
20962306a36Sopenharmony_ci	u32                    preprocopo_id;
21062306a36Sopenharmony_ci	u32                    enc_cfg_id;
21162306a36Sopenharmony_ci	u16                    bits_per_sample;
21262306a36Sopenharmony_ci	u16                    reserved;
21362306a36Sopenharmony_ci} __packed;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistruct asm_data_cmd_write_v2 {
21662306a36Sopenharmony_ci	u32 buf_addr_lsw;
21762306a36Sopenharmony_ci	u32 buf_addr_msw;
21862306a36Sopenharmony_ci	u32 mem_map_handle;
21962306a36Sopenharmony_ci	u32 buf_size;
22062306a36Sopenharmony_ci	u32 seq_id;
22162306a36Sopenharmony_ci	u32 timestamp_lsw;
22262306a36Sopenharmony_ci	u32 timestamp_msw;
22362306a36Sopenharmony_ci	u32 flags;
22462306a36Sopenharmony_ci} __packed;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct asm_stream_cmd_open_write_v3 {
22762306a36Sopenharmony_ci	uint32_t mode_flags;
22862306a36Sopenharmony_ci	uint16_t sink_endpointype;
22962306a36Sopenharmony_ci	uint16_t bits_per_sample;
23062306a36Sopenharmony_ci	uint32_t postprocopo_id;
23162306a36Sopenharmony_ci	uint32_t dec_fmt_id;
23262306a36Sopenharmony_ci} __packed;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistruct asm_session_cmd_run_v2 {
23562306a36Sopenharmony_ci	u32 flags;
23662306a36Sopenharmony_ci	u32 time_lsw;
23762306a36Sopenharmony_ci	u32 time_msw;
23862306a36Sopenharmony_ci} __packed;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistruct audio_buffer {
24162306a36Sopenharmony_ci	phys_addr_t phys;
24262306a36Sopenharmony_ci	uint32_t size;		/* size of buffer */
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistruct audio_port_data {
24662306a36Sopenharmony_ci	struct audio_buffer *buf;
24762306a36Sopenharmony_ci	uint32_t num_periods;
24862306a36Sopenharmony_ci	uint32_t dsp_buf;
24962306a36Sopenharmony_ci	uint32_t mem_map_handle;
25062306a36Sopenharmony_ci};
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistruct q6asm {
25362306a36Sopenharmony_ci	struct apr_device *adev;
25462306a36Sopenharmony_ci	struct device *dev;
25562306a36Sopenharmony_ci	struct q6core_svc_api_info ainfo;
25662306a36Sopenharmony_ci	wait_queue_head_t mem_wait;
25762306a36Sopenharmony_ci	spinlock_t slock;
25862306a36Sopenharmony_ci	struct audio_client *session[MAX_SESSIONS + 1];
25962306a36Sopenharmony_ci};
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistruct audio_client {
26262306a36Sopenharmony_ci	int session;
26362306a36Sopenharmony_ci	q6asm_cb cb;
26462306a36Sopenharmony_ci	void *priv;
26562306a36Sopenharmony_ci	uint32_t io_mode;
26662306a36Sopenharmony_ci	struct apr_device *adev;
26762306a36Sopenharmony_ci	struct mutex cmd_lock;
26862306a36Sopenharmony_ci	spinlock_t lock;
26962306a36Sopenharmony_ci	struct kref refcount;
27062306a36Sopenharmony_ci	/* idx:1 out port, 0: in port */
27162306a36Sopenharmony_ci	struct audio_port_data port[2];
27262306a36Sopenharmony_ci	wait_queue_head_t cmd_wait;
27362306a36Sopenharmony_ci	struct aprv2_ibasic_rsp_result_t result;
27462306a36Sopenharmony_ci	int perf_mode;
27562306a36Sopenharmony_ci	struct q6asm *q6asm;
27662306a36Sopenharmony_ci	struct device *dev;
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
28062306a36Sopenharmony_ci				 uint32_t pkt_size, bool cmd_flg,
28162306a36Sopenharmony_ci				 uint32_t stream_id)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
28462306a36Sopenharmony_ci	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
28562306a36Sopenharmony_ci	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
28662306a36Sopenharmony_ci	hdr->pkt_size = pkt_size;
28762306a36Sopenharmony_ci	if (cmd_flg)
28862306a36Sopenharmony_ci		hdr->token = ac->session;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
29262306a36Sopenharmony_ci				      struct apr_pkt *pkt, uint32_t rsp_opcode)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct apr_hdr *hdr = &pkt->hdr;
29562306a36Sopenharmony_ci	int rc;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	mutex_lock(&ac->cmd_lock);
29862306a36Sopenharmony_ci	ac->result.opcode = 0;
29962306a36Sopenharmony_ci	ac->result.status = 0;
30062306a36Sopenharmony_ci	rc = apr_send_pkt(a->adev, pkt);
30162306a36Sopenharmony_ci	if (rc < 0)
30262306a36Sopenharmony_ci		goto err;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (rsp_opcode)
30562306a36Sopenharmony_ci		rc = wait_event_timeout(a->mem_wait,
30662306a36Sopenharmony_ci					(ac->result.opcode == hdr->opcode) ||
30762306a36Sopenharmony_ci					(ac->result.opcode == rsp_opcode),
30862306a36Sopenharmony_ci					5 * HZ);
30962306a36Sopenharmony_ci	else
31062306a36Sopenharmony_ci		rc = wait_event_timeout(a->mem_wait,
31162306a36Sopenharmony_ci					(ac->result.opcode == hdr->opcode),
31262306a36Sopenharmony_ci					5 * HZ);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (!rc) {
31562306a36Sopenharmony_ci		dev_err(a->dev, "CMD %x timeout\n", hdr->opcode);
31662306a36Sopenharmony_ci		rc = -ETIMEDOUT;
31762306a36Sopenharmony_ci	} else if (ac->result.status > 0) {
31862306a36Sopenharmony_ci		dev_err(a->dev, "DSP returned error[%x]\n",
31962306a36Sopenharmony_ci			ac->result.status);
32062306a36Sopenharmony_ci		rc = -EINVAL;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cierr:
32462306a36Sopenharmony_ci	mutex_unlock(&ac->cmd_lock);
32562306a36Sopenharmony_ci	return rc;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int __q6asm_memory_unmap(struct audio_client *ac,
32962306a36Sopenharmony_ci				phys_addr_t buf_add, int dir)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
33262306a36Sopenharmony_ci	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
33362306a36Sopenharmony_ci	struct apr_pkt *pkt;
33462306a36Sopenharmony_ci	int rc, pkt_size;
33562306a36Sopenharmony_ci	void *p;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (ac->port[dir].mem_map_handle == 0) {
33862306a36Sopenharmony_ci		dev_err(ac->dev, "invalid mem handle\n");
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
34362306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
34462306a36Sopenharmony_ci	if (!p)
34562306a36Sopenharmony_ci		return -ENOMEM;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	pkt = p;
34862306a36Sopenharmony_ci	mem_unmap = p + APR_HDR_SIZE;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
35162306a36Sopenharmony_ci	pkt->hdr.src_port = 0;
35262306a36Sopenharmony_ci	pkt->hdr.dest_port = 0;
35362306a36Sopenharmony_ci	pkt->hdr.pkt_size = pkt_size;
35462306a36Sopenharmony_ci	pkt->hdr.token = ((ac->session << 8) | dir);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
35762306a36Sopenharmony_ci	mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
36062306a36Sopenharmony_ci	if (rc < 0) {
36162306a36Sopenharmony_ci		kfree(pkt);
36262306a36Sopenharmony_ci		return rc;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	ac->port[dir].mem_map_handle = 0;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	kfree(pkt);
36862306a36Sopenharmony_ci	return 0;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void q6asm_audio_client_free_buf(struct audio_client *ac,
37362306a36Sopenharmony_ci					struct audio_port_data *port)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	unsigned long flags;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
37862306a36Sopenharmony_ci	port->num_periods = 0;
37962306a36Sopenharmony_ci	kfree(port->buf);
38062306a36Sopenharmony_ci	port->buf = NULL;
38162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/**
38562306a36Sopenharmony_ci * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * @dir: direction of audio stream
38862306a36Sopenharmony_ci * @ac: audio client instanace
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * Return: Will be an negative value on failure or zero on success
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_ciint q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct audio_port_data *port;
39562306a36Sopenharmony_ci	int cnt = 0;
39662306a36Sopenharmony_ci	int rc = 0;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	port = &ac->port[dir];
39962306a36Sopenharmony_ci	if (!port->buf) {
40062306a36Sopenharmony_ci		rc = -EINVAL;
40162306a36Sopenharmony_ci		goto err;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	cnt = port->num_periods - 1;
40562306a36Sopenharmony_ci	if (cnt >= 0) {
40662306a36Sopenharmony_ci		rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
40762306a36Sopenharmony_ci		if (rc < 0) {
40862306a36Sopenharmony_ci			dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
40962306a36Sopenharmony_ci				__func__, rc);
41062306a36Sopenharmony_ci			goto err;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	q6asm_audio_client_free_buf(ac, port);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cierr:
41762306a36Sopenharmony_ci	return rc;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
42262306a36Sopenharmony_ci				      size_t period_sz, unsigned int periods,
42362306a36Sopenharmony_ci				      bool is_contiguous)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct avs_cmd_shared_mem_map_regions *cmd = NULL;
42662306a36Sopenharmony_ci	struct avs_shared_map_region_payload *mregions = NULL;
42762306a36Sopenharmony_ci	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
42862306a36Sopenharmony_ci	struct audio_port_data *port = NULL;
42962306a36Sopenharmony_ci	struct audio_buffer *ab = NULL;
43062306a36Sopenharmony_ci	struct apr_pkt *pkt;
43162306a36Sopenharmony_ci	void *p;
43262306a36Sopenharmony_ci	unsigned long flags;
43362306a36Sopenharmony_ci	uint32_t num_regions, buf_sz;
43462306a36Sopenharmony_ci	int rc, i, pkt_size;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (is_contiguous) {
43762306a36Sopenharmony_ci		num_regions = 1;
43862306a36Sopenharmony_ci		buf_sz = period_sz * periods;
43962306a36Sopenharmony_ci	} else {
44062306a36Sopenharmony_ci		buf_sz = period_sz;
44162306a36Sopenharmony_ci		num_regions = periods;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/* DSP expects size should be aligned to 4K */
44562306a36Sopenharmony_ci	buf_sz = ALIGN(buf_sz, 4096);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
44862306a36Sopenharmony_ci		   (sizeof(*mregions) * num_regions);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
45162306a36Sopenharmony_ci	if (!p)
45262306a36Sopenharmony_ci		return -ENOMEM;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	pkt = p;
45562306a36Sopenharmony_ci	cmd = p + APR_HDR_SIZE;
45662306a36Sopenharmony_ci	mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
45962306a36Sopenharmony_ci	pkt->hdr.src_port = 0;
46062306a36Sopenharmony_ci	pkt->hdr.dest_port = 0;
46162306a36Sopenharmony_ci	pkt->hdr.pkt_size = pkt_size;
46262306a36Sopenharmony_ci	pkt->hdr.token = ((ac->session << 8) | dir);
46362306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
46662306a36Sopenharmony_ci	cmd->num_regions = num_regions;
46762306a36Sopenharmony_ci	cmd->property_flag = 0x00;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
47062306a36Sopenharmony_ci	port = &ac->port[dir];
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	for (i = 0; i < num_regions; i++) {
47362306a36Sopenharmony_ci		ab = &port->buf[i];
47462306a36Sopenharmony_ci		mregions->shm_addr_lsw = lower_32_bits(ab->phys);
47562306a36Sopenharmony_ci		mregions->shm_addr_msw = upper_32_bits(ab->phys);
47662306a36Sopenharmony_ci		mregions->mem_size_bytes = buf_sz;
47762306a36Sopenharmony_ci		++mregions;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	rc = q6asm_apr_send_session_pkt(a, ac, pkt,
48262306a36Sopenharmony_ci					ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	kfree(pkt);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return rc;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * q6asm_map_memory_regions() - map memory regions in the dsp.
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci * @dir: direction of audio stream
49362306a36Sopenharmony_ci * @ac: audio client instanace
49462306a36Sopenharmony_ci * @phys: physical address that needs mapping.
49562306a36Sopenharmony_ci * @period_sz: audio period size
49662306a36Sopenharmony_ci * @periods: number of periods
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Return: Will be an negative value on failure or zero on success
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_ciint q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
50162306a36Sopenharmony_ci			     phys_addr_t phys,
50262306a36Sopenharmony_ci			     size_t period_sz, unsigned int periods)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct audio_buffer *buf;
50562306a36Sopenharmony_ci	unsigned long flags;
50662306a36Sopenharmony_ci	int cnt;
50762306a36Sopenharmony_ci	int rc;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
51062306a36Sopenharmony_ci	if (ac->port[dir].buf) {
51162306a36Sopenharmony_ci		dev_err(ac->dev, "Buffer already allocated\n");
51262306a36Sopenharmony_ci		spin_unlock_irqrestore(&ac->lock, flags);
51362306a36Sopenharmony_ci		return 0;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
51762306a36Sopenharmony_ci	if (!buf) {
51862306a36Sopenharmony_ci		spin_unlock_irqrestore(&ac->lock, flags);
51962306a36Sopenharmony_ci		return -ENOMEM;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	ac->port[dir].buf = buf;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	buf[0].phys = phys;
52662306a36Sopenharmony_ci	buf[0].size = period_sz;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (cnt = 1; cnt < periods; cnt++) {
52962306a36Sopenharmony_ci		if (period_sz > 0) {
53062306a36Sopenharmony_ci			buf[cnt].phys = buf[0].phys + (cnt * period_sz);
53162306a36Sopenharmony_ci			buf[cnt].size = period_sz;
53262306a36Sopenharmony_ci		}
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	ac->port[dir].num_periods = periods;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
53962306a36Sopenharmony_ci	if (rc < 0) {
54062306a36Sopenharmony_ci		dev_err(ac->dev, "Memory_map_regions failed\n");
54162306a36Sopenharmony_ci		q6asm_audio_client_free_buf(ac, &ac->port[dir]);
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return rc;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic void q6asm_audio_client_release(struct kref *ref)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct audio_client *ac;
55162306a36Sopenharmony_ci	struct q6asm *a;
55262306a36Sopenharmony_ci	unsigned long flags;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	ac = container_of(ref, struct audio_client, refcount);
55562306a36Sopenharmony_ci	a = ac->q6asm;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	spin_lock_irqsave(&a->slock, flags);
55862306a36Sopenharmony_ci	a->session[ac->session] = NULL;
55962306a36Sopenharmony_ci	spin_unlock_irqrestore(&a->slock, flags);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	kfree(ac);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/**
56562306a36Sopenharmony_ci * q6asm_audio_client_free() - Freee allocated audio client
56662306a36Sopenharmony_ci *
56762306a36Sopenharmony_ci * @ac: audio client to free
56862306a36Sopenharmony_ci */
56962306a36Sopenharmony_civoid q6asm_audio_client_free(struct audio_client *ac)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	kref_put(&ac->refcount, q6asm_audio_client_release);
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_audio_client_free);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic struct audio_client *q6asm_get_audio_client(struct q6asm *a,
57662306a36Sopenharmony_ci						   int session_id)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct audio_client *ac = NULL;
57962306a36Sopenharmony_ci	unsigned long flags;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	spin_lock_irqsave(&a->slock, flags);
58262306a36Sopenharmony_ci	if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
58362306a36Sopenharmony_ci		dev_err(a->dev, "invalid session: %d\n", session_id);
58462306a36Sopenharmony_ci		goto err;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* check for valid session */
58862306a36Sopenharmony_ci	if (!a->session[session_id])
58962306a36Sopenharmony_ci		goto err;
59062306a36Sopenharmony_ci	else if (a->session[session_id]->session != session_id)
59162306a36Sopenharmony_ci		goto err;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	ac = a->session[session_id];
59462306a36Sopenharmony_ci	kref_get(&ac->refcount);
59562306a36Sopenharmony_cierr:
59662306a36Sopenharmony_ci	spin_unlock_irqrestore(&a->slock, flags);
59762306a36Sopenharmony_ci	return ac;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int32_t q6asm_stream_callback(struct apr_device *adev,
60162306a36Sopenharmony_ci				     struct apr_resp_pkt *data,
60262306a36Sopenharmony_ci				     int session_id)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
60562306a36Sopenharmony_ci	struct aprv2_ibasic_rsp_result_t *result;
60662306a36Sopenharmony_ci	struct apr_hdr *hdr = &data->hdr;
60762306a36Sopenharmony_ci	struct audio_port_data *port;
60862306a36Sopenharmony_ci	struct audio_client *ac;
60962306a36Sopenharmony_ci	uint32_t client_event = 0;
61062306a36Sopenharmony_ci	int ret = 0;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ac = q6asm_get_audio_client(q6asm, session_id);
61362306a36Sopenharmony_ci	if (!ac)/* Audio client might already be freed by now */
61462306a36Sopenharmony_ci		return 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	result = data->payload;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	switch (hdr->opcode) {
61962306a36Sopenharmony_ci	case APR_BASIC_RSP_RESULT:
62062306a36Sopenharmony_ci		switch (result->opcode) {
62162306a36Sopenharmony_ci		case ASM_SESSION_CMD_PAUSE:
62262306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
62362306a36Sopenharmony_ci			break;
62462306a36Sopenharmony_ci		case ASM_SESSION_CMD_SUSPEND:
62562306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
62662306a36Sopenharmony_ci			break;
62762306a36Sopenharmony_ci		case ASM_STREAM_CMD_FLUSH:
62862306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
62962306a36Sopenharmony_ci			break;
63062306a36Sopenharmony_ci		case ASM_SESSION_CMD_RUN_V2:
63162306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		case ASM_STREAM_CMD_CLOSE:
63462306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
63562306a36Sopenharmony_ci			break;
63662306a36Sopenharmony_ci		case ASM_STREAM_CMD_FLUSH_READBUFS:
63762306a36Sopenharmony_ci			client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
63862306a36Sopenharmony_ci			break;
63962306a36Sopenharmony_ci		case ASM_STREAM_CMD_OPEN_WRITE_V3:
64062306a36Sopenharmony_ci		case ASM_STREAM_CMD_OPEN_READ_V3:
64162306a36Sopenharmony_ci		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
64262306a36Sopenharmony_ci		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
64362306a36Sopenharmony_ci		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
64462306a36Sopenharmony_ci		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
64562306a36Sopenharmony_ci		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
64662306a36Sopenharmony_ci			if (result->status != 0) {
64762306a36Sopenharmony_ci				dev_err(ac->dev,
64862306a36Sopenharmony_ci					"cmd = 0x%x returned error = 0x%x\n",
64962306a36Sopenharmony_ci					result->opcode, result->status);
65062306a36Sopenharmony_ci				ac->result = *result;
65162306a36Sopenharmony_ci				wake_up(&ac->cmd_wait);
65262306a36Sopenharmony_ci				ret = 0;
65362306a36Sopenharmony_ci				goto done;
65462306a36Sopenharmony_ci			}
65562306a36Sopenharmony_ci			break;
65662306a36Sopenharmony_ci		default:
65762306a36Sopenharmony_ci			dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
65862306a36Sopenharmony_ci				result->opcode);
65962306a36Sopenharmony_ci			break;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		ac->result = *result;
66362306a36Sopenharmony_ci		wake_up(&ac->cmd_wait);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		if (ac->cb)
66662306a36Sopenharmony_ci			ac->cb(client_event, hdr->token,
66762306a36Sopenharmony_ci			       data->payload, ac->priv);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		ret = 0;
67062306a36Sopenharmony_ci		goto done;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	case ASM_DATA_EVENT_WRITE_DONE_V2:
67362306a36Sopenharmony_ci		client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
67462306a36Sopenharmony_ci		if (ac->io_mode & ASM_SYNC_IO_MODE) {
67562306a36Sopenharmony_ci			phys_addr_t phys;
67662306a36Sopenharmony_ci			unsigned long flags;
67762306a36Sopenharmony_ci			int token = hdr->token & ASM_WRITE_TOKEN_MASK;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci			spin_lock_irqsave(&ac->lock, flags);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci			port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci			if (!port->buf) {
68462306a36Sopenharmony_ci				spin_unlock_irqrestore(&ac->lock, flags);
68562306a36Sopenharmony_ci				ret = 0;
68662306a36Sopenharmony_ci				goto done;
68762306a36Sopenharmony_ci			}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci			phys = port->buf[token].phys;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci			if (lower_32_bits(phys) != result->opcode ||
69262306a36Sopenharmony_ci			    upper_32_bits(phys) != result->status) {
69362306a36Sopenharmony_ci				dev_err(ac->dev, "Expected addr %pa\n",
69462306a36Sopenharmony_ci					&port->buf[token].phys);
69562306a36Sopenharmony_ci				spin_unlock_irqrestore(&ac->lock, flags);
69662306a36Sopenharmony_ci				ret = -EINVAL;
69762306a36Sopenharmony_ci				goto done;
69862306a36Sopenharmony_ci			}
69962306a36Sopenharmony_ci			spin_unlock_irqrestore(&ac->lock, flags);
70062306a36Sopenharmony_ci		}
70162306a36Sopenharmony_ci		break;
70262306a36Sopenharmony_ci	case ASM_DATA_EVENT_READ_DONE_V2:
70362306a36Sopenharmony_ci		client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
70462306a36Sopenharmony_ci		if (ac->io_mode & ASM_SYNC_IO_MODE) {
70562306a36Sopenharmony_ci			struct asm_data_cmd_read_v2_done *done = data->payload;
70662306a36Sopenharmony_ci			unsigned long flags;
70762306a36Sopenharmony_ci			phys_addr_t phys;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci			spin_lock_irqsave(&ac->lock, flags);
71062306a36Sopenharmony_ci			port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
71162306a36Sopenharmony_ci			if (!port->buf) {
71262306a36Sopenharmony_ci				spin_unlock_irqrestore(&ac->lock, flags);
71362306a36Sopenharmony_ci				ret = 0;
71462306a36Sopenharmony_ci				goto done;
71562306a36Sopenharmony_ci			}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci			phys = port->buf[hdr->token].phys;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci			if (upper_32_bits(phys) != done->buf_addr_msw ||
72062306a36Sopenharmony_ci			    lower_32_bits(phys) != done->buf_addr_lsw) {
72162306a36Sopenharmony_ci				dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
72262306a36Sopenharmony_ci					&port->buf[hdr->token].phys,
72362306a36Sopenharmony_ci					done->buf_addr_lsw,
72462306a36Sopenharmony_ci					done->buf_addr_msw);
72562306a36Sopenharmony_ci				spin_unlock_irqrestore(&ac->lock, flags);
72662306a36Sopenharmony_ci				ret = -EINVAL;
72762306a36Sopenharmony_ci				goto done;
72862306a36Sopenharmony_ci			}
72962306a36Sopenharmony_ci			spin_unlock_irqrestore(&ac->lock, flags);
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		break;
73362306a36Sopenharmony_ci	case ASM_DATA_EVENT_RENDERED_EOS:
73462306a36Sopenharmony_ci		client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
73562306a36Sopenharmony_ci		break;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (ac->cb)
73962306a36Sopenharmony_ci		ac->cb(client_event, hdr->token, data->payload, ac->priv);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cidone:
74262306a36Sopenharmony_ci	kref_put(&ac->refcount, q6asm_audio_client_release);
74362306a36Sopenharmony_ci	return ret;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int q6asm_srvc_callback(struct apr_device *adev,
74762306a36Sopenharmony_ci			       struct apr_resp_pkt *data)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
75062306a36Sopenharmony_ci	struct aprv2_ibasic_rsp_result_t *result;
75162306a36Sopenharmony_ci	struct audio_port_data *port;
75262306a36Sopenharmony_ci	struct audio_client *ac = NULL;
75362306a36Sopenharmony_ci	struct apr_hdr *hdr = &data->hdr;
75462306a36Sopenharmony_ci	struct q6asm *a;
75562306a36Sopenharmony_ci	uint32_t sid = 0;
75662306a36Sopenharmony_ci	uint32_t dir = 0;
75762306a36Sopenharmony_ci	int session_id;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	session_id = (hdr->dest_port >> 8) & 0xFF;
76062306a36Sopenharmony_ci	if (session_id)
76162306a36Sopenharmony_ci		return q6asm_stream_callback(adev, data, session_id);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	sid = (hdr->token >> 8) & 0x0F;
76462306a36Sopenharmony_ci	ac = q6asm_get_audio_client(q6asm, sid);
76562306a36Sopenharmony_ci	if (!ac) {
76662306a36Sopenharmony_ci		dev_err(&adev->dev, "Audio Client not active\n");
76762306a36Sopenharmony_ci		return 0;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	a = dev_get_drvdata(ac->dev->parent);
77162306a36Sopenharmony_ci	dir = (hdr->token & 0x0F);
77262306a36Sopenharmony_ci	port = &ac->port[dir];
77362306a36Sopenharmony_ci	result = data->payload;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	switch (hdr->opcode) {
77662306a36Sopenharmony_ci	case APR_BASIC_RSP_RESULT:
77762306a36Sopenharmony_ci		switch (result->opcode) {
77862306a36Sopenharmony_ci		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
77962306a36Sopenharmony_ci		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
78062306a36Sopenharmony_ci			ac->result = *result;
78162306a36Sopenharmony_ci			wake_up(&a->mem_wait);
78262306a36Sopenharmony_ci			break;
78362306a36Sopenharmony_ci		default:
78462306a36Sopenharmony_ci			dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
78562306a36Sopenharmony_ci				 result->opcode);
78662306a36Sopenharmony_ci			break;
78762306a36Sopenharmony_ci		}
78862306a36Sopenharmony_ci		goto done;
78962306a36Sopenharmony_ci	case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
79062306a36Sopenharmony_ci		ac->result.status = 0;
79162306a36Sopenharmony_ci		ac->result.opcode = hdr->opcode;
79262306a36Sopenharmony_ci		port->mem_map_handle = result->opcode;
79362306a36Sopenharmony_ci		wake_up(&a->mem_wait);
79462306a36Sopenharmony_ci		break;
79562306a36Sopenharmony_ci	case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
79662306a36Sopenharmony_ci		ac->result.opcode = hdr->opcode;
79762306a36Sopenharmony_ci		ac->result.status = 0;
79862306a36Sopenharmony_ci		port->mem_map_handle = 0;
79962306a36Sopenharmony_ci		wake_up(&a->mem_wait);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	default:
80262306a36Sopenharmony_ci		dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
80362306a36Sopenharmony_ci			result->opcode, result->status);
80462306a36Sopenharmony_ci		break;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	if (ac->cb)
80862306a36Sopenharmony_ci		ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cidone:
81162306a36Sopenharmony_ci	kref_put(&ac->refcount, q6asm_audio_client_release);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return 0;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * q6asm_get_session_id() - get session id for audio client
81862306a36Sopenharmony_ci *
81962306a36Sopenharmony_ci * @c: audio client pointer
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * Return: Will be an session id of the audio client.
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_ciint q6asm_get_session_id(struct audio_client *c)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	return c->session;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_get_session_id);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci/**
83062306a36Sopenharmony_ci * q6asm_audio_client_alloc() - Allocate a new audio client
83162306a36Sopenharmony_ci *
83262306a36Sopenharmony_ci * @dev: Pointer to asm child device.
83362306a36Sopenharmony_ci * @cb: event callback.
83462306a36Sopenharmony_ci * @priv: private data associated with this client.
83562306a36Sopenharmony_ci * @session_id: session id
83662306a36Sopenharmony_ci * @perf_mode: performace mode for this client
83762306a36Sopenharmony_ci *
83862306a36Sopenharmony_ci * Return: Will be an error pointer on error or a valid audio client
83962306a36Sopenharmony_ci * on success.
84062306a36Sopenharmony_ci */
84162306a36Sopenharmony_cistruct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
84262306a36Sopenharmony_ci					      void *priv, int session_id,
84362306a36Sopenharmony_ci					      int perf_mode)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct q6asm *a = dev_get_drvdata(dev->parent);
84662306a36Sopenharmony_ci	struct audio_client *ac;
84762306a36Sopenharmony_ci	unsigned long flags;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	ac = q6asm_get_audio_client(a, session_id + 1);
85062306a36Sopenharmony_ci	if (ac) {
85162306a36Sopenharmony_ci		dev_err(dev, "Audio Client already active\n");
85262306a36Sopenharmony_ci		return ac;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
85662306a36Sopenharmony_ci	if (!ac)
85762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	spin_lock_irqsave(&a->slock, flags);
86062306a36Sopenharmony_ci	a->session[session_id + 1] = ac;
86162306a36Sopenharmony_ci	spin_unlock_irqrestore(&a->slock, flags);
86262306a36Sopenharmony_ci	ac->session = session_id + 1;
86362306a36Sopenharmony_ci	ac->cb = cb;
86462306a36Sopenharmony_ci	ac->dev = dev;
86562306a36Sopenharmony_ci	ac->q6asm = a;
86662306a36Sopenharmony_ci	ac->priv = priv;
86762306a36Sopenharmony_ci	ac->io_mode = ASM_SYNC_IO_MODE;
86862306a36Sopenharmony_ci	ac->perf_mode = perf_mode;
86962306a36Sopenharmony_ci	ac->adev = a->adev;
87062306a36Sopenharmony_ci	kref_init(&ac->refcount);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	init_waitqueue_head(&ac->cmd_wait);
87362306a36Sopenharmony_ci	mutex_init(&ac->cmd_lock);
87462306a36Sopenharmony_ci	spin_lock_init(&ac->lock);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	return ac;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct apr_hdr *hdr = &pkt->hdr;
88362306a36Sopenharmony_ci	int rc;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	mutex_lock(&ac->cmd_lock);
88662306a36Sopenharmony_ci	ac->result.opcode = 0;
88762306a36Sopenharmony_ci	ac->result.status = 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	rc = apr_send_pkt(ac->adev, pkt);
89062306a36Sopenharmony_ci	if (rc < 0)
89162306a36Sopenharmony_ci		goto err;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	rc = wait_event_timeout(ac->cmd_wait,
89462306a36Sopenharmony_ci				(ac->result.opcode == hdr->opcode), 5 * HZ);
89562306a36Sopenharmony_ci	if (!rc) {
89662306a36Sopenharmony_ci		dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode);
89762306a36Sopenharmony_ci		rc =  -ETIMEDOUT;
89862306a36Sopenharmony_ci		goto err;
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (ac->result.status > 0) {
90262306a36Sopenharmony_ci		dev_err(ac->dev, "DSP returned error[%x]\n",
90362306a36Sopenharmony_ci			ac->result.status);
90462306a36Sopenharmony_ci		rc = -EINVAL;
90562306a36Sopenharmony_ci	} else {
90662306a36Sopenharmony_ci		rc = 0;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cierr:
91162306a36Sopenharmony_ci	mutex_unlock(&ac->cmd_lock);
91262306a36Sopenharmony_ci	return rc;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci/**
91662306a36Sopenharmony_ci * q6asm_open_write() - Open audio client for writing
91762306a36Sopenharmony_ci * @ac: audio client pointer
91862306a36Sopenharmony_ci * @stream_id: stream id of q6asm session
91962306a36Sopenharmony_ci * @format: audio sample format
92062306a36Sopenharmony_ci * @codec_profile: compressed format profile
92162306a36Sopenharmony_ci * @bits_per_sample: bits per sample
92262306a36Sopenharmony_ci * @is_gapless: flag to indicate if this is a gapless stream
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_ciint q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
92762306a36Sopenharmony_ci		     uint32_t format, u32 codec_profile,
92862306a36Sopenharmony_ci		     uint16_t bits_per_sample, bool is_gapless)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct asm_stream_cmd_open_write_v3 *open;
93162306a36Sopenharmony_ci	struct apr_pkt *pkt;
93262306a36Sopenharmony_ci	void *p;
93362306a36Sopenharmony_ci	int rc, pkt_size;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*open);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
93862306a36Sopenharmony_ci	if (!p)
93962306a36Sopenharmony_ci		return -ENOMEM;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	pkt = p;
94262306a36Sopenharmony_ci	open = p + APR_HDR_SIZE;
94362306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
94662306a36Sopenharmony_ci	open->mode_flags = 0x00;
94762306a36Sopenharmony_ci	open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
94862306a36Sopenharmony_ci	if (is_gapless)
94962306a36Sopenharmony_ci		open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* source endpoint : matrix */
95262306a36Sopenharmony_ci	open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
95362306a36Sopenharmony_ci	open->bits_per_sample = bits_per_sample;
95462306a36Sopenharmony_ci	open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	switch (format) {
95762306a36Sopenharmony_ci	case SND_AUDIOCODEC_MP3:
95862306a36Sopenharmony_ci		open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
95962306a36Sopenharmony_ci		break;
96062306a36Sopenharmony_ci	case FORMAT_LINEAR_PCM:
96162306a36Sopenharmony_ci		open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
96262306a36Sopenharmony_ci		break;
96362306a36Sopenharmony_ci	case SND_AUDIOCODEC_FLAC:
96462306a36Sopenharmony_ci		open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
96562306a36Sopenharmony_ci		break;
96662306a36Sopenharmony_ci	case SND_AUDIOCODEC_WMA:
96762306a36Sopenharmony_ci		switch (codec_profile) {
96862306a36Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9:
96962306a36Sopenharmony_ci			open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9;
97062306a36Sopenharmony_ci			break;
97162306a36Sopenharmony_ci		case SND_AUDIOPROFILE_WMA10:
97262306a36Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9_PRO:
97362306a36Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9_LOSSLESS:
97462306a36Sopenharmony_ci		case SND_AUDIOPROFILE_WMA10_LOSSLESS:
97562306a36Sopenharmony_ci			open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10;
97662306a36Sopenharmony_ci			break;
97762306a36Sopenharmony_ci		default:
97862306a36Sopenharmony_ci			dev_err(ac->dev, "Invalid codec profile 0x%x\n",
97962306a36Sopenharmony_ci				codec_profile);
98062306a36Sopenharmony_ci			rc = -EINVAL;
98162306a36Sopenharmony_ci			goto err;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci		break;
98462306a36Sopenharmony_ci	case SND_AUDIOCODEC_ALAC:
98562306a36Sopenharmony_ci		open->dec_fmt_id = ASM_MEDIA_FMT_ALAC;
98662306a36Sopenharmony_ci		break;
98762306a36Sopenharmony_ci	case SND_AUDIOCODEC_APE:
98862306a36Sopenharmony_ci		open->dec_fmt_id = ASM_MEDIA_FMT_APE;
98962306a36Sopenharmony_ci		break;
99062306a36Sopenharmony_ci	default:
99162306a36Sopenharmony_ci		dev_err(ac->dev, "Invalid format 0x%x\n", format);
99262306a36Sopenharmony_ci		rc = -EINVAL;
99362306a36Sopenharmony_ci		goto err;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
99762306a36Sopenharmony_ci	if (rc < 0)
99862306a36Sopenharmony_ci		goto err;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cierr:
100362306a36Sopenharmony_ci	kfree(pkt);
100462306a36Sopenharmony_ci	return rc;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_open_write);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_cistatic int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
100962306a36Sopenharmony_ci		       uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
101062306a36Sopenharmony_ci		       bool wait)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct asm_session_cmd_run_v2 *run;
101362306a36Sopenharmony_ci	struct apr_pkt *pkt;
101462306a36Sopenharmony_ci	int pkt_size, rc;
101562306a36Sopenharmony_ci	void *p;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*run);
101862306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_ATOMIC);
101962306a36Sopenharmony_ci	if (!p)
102062306a36Sopenharmony_ci		return -ENOMEM;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	pkt = p;
102362306a36Sopenharmony_ci	run = p + APR_HDR_SIZE;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
102862306a36Sopenharmony_ci	run->flags = flags;
102962306a36Sopenharmony_ci	run->time_lsw = lsw_ts;
103062306a36Sopenharmony_ci	run->time_msw = msw_ts;
103162306a36Sopenharmony_ci	if (wait) {
103262306a36Sopenharmony_ci		rc = q6asm_ac_send_cmd_sync(ac, pkt);
103362306a36Sopenharmony_ci	} else {
103462306a36Sopenharmony_ci		rc = apr_send_pkt(ac->adev, pkt);
103562306a36Sopenharmony_ci		if (rc == pkt_size)
103662306a36Sopenharmony_ci			rc = 0;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	kfree(pkt);
104062306a36Sopenharmony_ci	return rc;
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci/**
104462306a36Sopenharmony_ci * q6asm_run() - start the audio client
104562306a36Sopenharmony_ci *
104662306a36Sopenharmony_ci * @ac: audio client pointer
104762306a36Sopenharmony_ci * @stream_id: stream id of q6asm session
104862306a36Sopenharmony_ci * @flags: flags associated with write
104962306a36Sopenharmony_ci * @msw_ts: timestamp msw
105062306a36Sopenharmony_ci * @lsw_ts: timestamp lsw
105162306a36Sopenharmony_ci *
105262306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
105362306a36Sopenharmony_ci */
105462306a36Sopenharmony_ciint q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
105562306a36Sopenharmony_ci	      uint32_t msw_ts, uint32_t lsw_ts)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_run);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci/**
106262306a36Sopenharmony_ci * q6asm_run_nowait() - start the audio client withou blocking
106362306a36Sopenharmony_ci *
106462306a36Sopenharmony_ci * @ac: audio client pointer
106562306a36Sopenharmony_ci * @stream_id: stream id
106662306a36Sopenharmony_ci * @flags: flags associated with write
106762306a36Sopenharmony_ci * @msw_ts: timestamp msw
106862306a36Sopenharmony_ci * @lsw_ts: timestamp lsw
106962306a36Sopenharmony_ci *
107062306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
107162306a36Sopenharmony_ci */
107262306a36Sopenharmony_ciint q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
107362306a36Sopenharmony_ci		     uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_run_nowait);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/**
108062306a36Sopenharmony_ci * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
108162306a36Sopenharmony_ci *
108262306a36Sopenharmony_ci * @ac: audio client pointer
108362306a36Sopenharmony_ci * @stream_id: stream id
108462306a36Sopenharmony_ci * @rate: audio sample rate
108562306a36Sopenharmony_ci * @channels: number of audio channels.
108662306a36Sopenharmony_ci * @channel_map: channel map pointer
108762306a36Sopenharmony_ci * @bits_per_sample: bits per sample
108862306a36Sopenharmony_ci *
108962306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
109062306a36Sopenharmony_ci */
109162306a36Sopenharmony_ciint q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
109262306a36Sopenharmony_ci					  uint32_t stream_id,
109362306a36Sopenharmony_ci					  uint32_t rate, uint32_t channels,
109462306a36Sopenharmony_ci					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
109562306a36Sopenharmony_ci					  uint16_t bits_per_sample)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
109862306a36Sopenharmony_ci	struct apr_pkt *pkt;
109962306a36Sopenharmony_ci	u8 *channel_mapping;
110062306a36Sopenharmony_ci	void *p;
110162306a36Sopenharmony_ci	int rc, pkt_size;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
110462306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
110562306a36Sopenharmony_ci	if (!p)
110662306a36Sopenharmony_ci		return -ENOMEM;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	pkt = p;
110962306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
111462306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
111562306a36Sopenharmony_ci	fmt->num_channels = channels;
111662306a36Sopenharmony_ci	fmt->bits_per_sample = bits_per_sample;
111762306a36Sopenharmony_ci	fmt->sample_rate = rate;
111862306a36Sopenharmony_ci	fmt->is_signed = 1;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	channel_mapping = fmt->channel_mapping;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (channel_map) {
112362306a36Sopenharmony_ci		memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
112462306a36Sopenharmony_ci	} else {
112562306a36Sopenharmony_ci		if (q6dsp_map_channels(channel_mapping, channels)) {
112662306a36Sopenharmony_ci			dev_err(ac->dev, " map channels failed %d\n", channels);
112762306a36Sopenharmony_ci			rc = -EINVAL;
112862306a36Sopenharmony_ci			goto err;
112962306a36Sopenharmony_ci		}
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cierr:
113562306a36Sopenharmony_ci	kfree(pkt);
113662306a36Sopenharmony_ci	return rc;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ciint q6asm_stream_media_format_block_flac(struct audio_client *ac,
114162306a36Sopenharmony_ci					 uint32_t stream_id,
114262306a36Sopenharmony_ci					 struct q6asm_flac_cfg *cfg)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct asm_flac_fmt_blk_v2 *fmt;
114562306a36Sopenharmony_ci	struct apr_pkt *pkt;
114662306a36Sopenharmony_ci	void *p;
114762306a36Sopenharmony_ci	int rc, pkt_size;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
115062306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
115162306a36Sopenharmony_ci	if (!p)
115262306a36Sopenharmony_ci		return -ENOMEM;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	pkt = p;
115562306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
116062306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
116162306a36Sopenharmony_ci	fmt->is_stream_info_present = cfg->stream_info_present;
116262306a36Sopenharmony_ci	fmt->num_channels = cfg->ch_cfg;
116362306a36Sopenharmony_ci	fmt->min_blk_size = cfg->min_blk_size;
116462306a36Sopenharmony_ci	fmt->max_blk_size = cfg->max_blk_size;
116562306a36Sopenharmony_ci	fmt->sample_rate = cfg->sample_rate;
116662306a36Sopenharmony_ci	fmt->min_frame_size = cfg->min_frame_size;
116762306a36Sopenharmony_ci	fmt->max_frame_size = cfg->max_frame_size;
116862306a36Sopenharmony_ci	fmt->sample_size = cfg->sample_size;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
117162306a36Sopenharmony_ci	kfree(pkt);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	return rc;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ciint q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
117862306a36Sopenharmony_ci					   uint32_t stream_id,
117962306a36Sopenharmony_ci					   struct q6asm_wma_cfg *cfg)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct asm_wmastdv9_fmt_blk_v2 *fmt;
118262306a36Sopenharmony_ci	struct apr_pkt *pkt;
118362306a36Sopenharmony_ci	void *p;
118462306a36Sopenharmony_ci	int rc, pkt_size;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
118762306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
118862306a36Sopenharmony_ci	if (!p)
118962306a36Sopenharmony_ci		return -ENOMEM;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	pkt = p;
119262306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
119762306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
119862306a36Sopenharmony_ci	fmt->fmtag = cfg->fmtag;
119962306a36Sopenharmony_ci	fmt->num_channels = cfg->num_channels;
120062306a36Sopenharmony_ci	fmt->sample_rate = cfg->sample_rate;
120162306a36Sopenharmony_ci	fmt->bytes_per_sec = cfg->bytes_per_sec;
120262306a36Sopenharmony_ci	fmt->blk_align = cfg->block_align;
120362306a36Sopenharmony_ci	fmt->bits_per_sample = cfg->bits_per_sample;
120462306a36Sopenharmony_ci	fmt->channel_mask = cfg->channel_mask;
120562306a36Sopenharmony_ci	fmt->enc_options = cfg->enc_options;
120662306a36Sopenharmony_ci	fmt->reserved = 0;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
120962306a36Sopenharmony_ci	kfree(pkt);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	return rc;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ciint q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
121662306a36Sopenharmony_ci					    uint32_t stream_id,
121762306a36Sopenharmony_ci					    struct q6asm_wma_cfg *cfg)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct asm_wmaprov10_fmt_blk_v2 *fmt;
122062306a36Sopenharmony_ci	struct apr_pkt *pkt;
122162306a36Sopenharmony_ci	void *p;
122262306a36Sopenharmony_ci	int rc, pkt_size;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
122562306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
122662306a36Sopenharmony_ci	if (!p)
122762306a36Sopenharmony_ci		return -ENOMEM;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	pkt = p;
123062306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
123562306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
123662306a36Sopenharmony_ci	fmt->fmtag = cfg->fmtag;
123762306a36Sopenharmony_ci	fmt->num_channels = cfg->num_channels;
123862306a36Sopenharmony_ci	fmt->sample_rate = cfg->sample_rate;
123962306a36Sopenharmony_ci	fmt->bytes_per_sec = cfg->bytes_per_sec;
124062306a36Sopenharmony_ci	fmt->blk_align = cfg->block_align;
124162306a36Sopenharmony_ci	fmt->bits_per_sample = cfg->bits_per_sample;
124262306a36Sopenharmony_ci	fmt->channel_mask = cfg->channel_mask;
124362306a36Sopenharmony_ci	fmt->enc_options = cfg->enc_options;
124462306a36Sopenharmony_ci	fmt->advanced_enc_options1 = cfg->adv_enc_options;
124562306a36Sopenharmony_ci	fmt->advanced_enc_options2 = cfg->adv_enc_options2;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
124862306a36Sopenharmony_ci	kfree(pkt);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return rc;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ciint q6asm_stream_media_format_block_alac(struct audio_client *ac,
125562306a36Sopenharmony_ci					 uint32_t stream_id,
125662306a36Sopenharmony_ci					 struct q6asm_alac_cfg *cfg)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct asm_alac_fmt_blk_v2 *fmt;
125962306a36Sopenharmony_ci	struct apr_pkt *pkt;
126062306a36Sopenharmony_ci	void *p;
126162306a36Sopenharmony_ci	int rc, pkt_size;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
126462306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
126562306a36Sopenharmony_ci	if (!p)
126662306a36Sopenharmony_ci		return -ENOMEM;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	pkt = p;
126962306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
127462306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	fmt->frame_length = cfg->frame_length;
127762306a36Sopenharmony_ci	fmt->compatible_version = cfg->compatible_version;
127862306a36Sopenharmony_ci	fmt->bit_depth =  cfg->bit_depth;
127962306a36Sopenharmony_ci	fmt->num_channels = cfg->num_channels;
128062306a36Sopenharmony_ci	fmt->max_run = cfg->max_run;
128162306a36Sopenharmony_ci	fmt->max_frame_bytes = cfg->max_frame_bytes;
128262306a36Sopenharmony_ci	fmt->avg_bit_rate = cfg->avg_bit_rate;
128362306a36Sopenharmony_ci	fmt->sample_rate = cfg->sample_rate;
128462306a36Sopenharmony_ci	fmt->channel_layout_tag = cfg->channel_layout_tag;
128562306a36Sopenharmony_ci	fmt->pb = cfg->pb;
128662306a36Sopenharmony_ci	fmt->mb = cfg->mb;
128762306a36Sopenharmony_ci	fmt->kb = cfg->kb;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
129062306a36Sopenharmony_ci	kfree(pkt);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return rc;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ciint q6asm_stream_media_format_block_ape(struct audio_client *ac,
129762306a36Sopenharmony_ci					uint32_t stream_id,
129862306a36Sopenharmony_ci					struct q6asm_ape_cfg *cfg)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct asm_ape_fmt_blk_v2 *fmt;
130162306a36Sopenharmony_ci	struct apr_pkt *pkt;
130262306a36Sopenharmony_ci	void *p;
130362306a36Sopenharmony_ci	int rc, pkt_size;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
130662306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
130762306a36Sopenharmony_ci	if (!p)
130862306a36Sopenharmony_ci		return -ENOMEM;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	pkt = p;
131162306a36Sopenharmony_ci	fmt = p + APR_HDR_SIZE;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
131662306a36Sopenharmony_ci	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	fmt->compatible_version = cfg->compatible_version;
131962306a36Sopenharmony_ci	fmt->compression_level = cfg->compression_level;
132062306a36Sopenharmony_ci	fmt->format_flags = cfg->format_flags;
132162306a36Sopenharmony_ci	fmt->blocks_per_frame = cfg->blocks_per_frame;
132262306a36Sopenharmony_ci	fmt->final_frame_blocks = cfg->final_frame_blocks;
132362306a36Sopenharmony_ci	fmt->total_frames = cfg->total_frames;
132462306a36Sopenharmony_ci	fmt->bits_per_sample = cfg->bits_per_sample;
132562306a36Sopenharmony_ci	fmt->num_channels = cfg->num_channels;
132662306a36Sopenharmony_ci	fmt->sample_rate = cfg->sample_rate;
132762306a36Sopenharmony_ci	fmt->seek_table_present = cfg->seek_table_present;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
133062306a36Sopenharmony_ci	kfree(pkt);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	return rc;
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
133762306a36Sopenharmony_ci				       uint32_t cmd,
133862306a36Sopenharmony_ci				       uint32_t num_samples)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	uint32_t *samples;
134162306a36Sopenharmony_ci	struct apr_pkt *pkt;
134262306a36Sopenharmony_ci	void *p;
134362306a36Sopenharmony_ci	int rc, pkt_size;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
134662306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_ATOMIC);
134762306a36Sopenharmony_ci	if (!p)
134862306a36Sopenharmony_ci		return -ENOMEM;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	pkt = p;
135162306a36Sopenharmony_ci	samples = p + APR_HDR_SIZE;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	pkt->hdr.opcode = cmd;
135662306a36Sopenharmony_ci	*samples = num_samples;
135762306a36Sopenharmony_ci	rc = apr_send_pkt(ac->adev, pkt);
135862306a36Sopenharmony_ci	if (rc == pkt_size)
135962306a36Sopenharmony_ci		rc = 0;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	kfree(pkt);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	return rc;
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ciint q6asm_stream_remove_initial_silence(struct audio_client *ac,
136762306a36Sopenharmony_ci					uint32_t stream_id,
136862306a36Sopenharmony_ci					uint32_t initial_samples)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	return q6asm_stream_remove_silence(ac, stream_id,
137162306a36Sopenharmony_ci					   ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
137262306a36Sopenharmony_ci					   initial_samples);
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ciint q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
137762306a36Sopenharmony_ci					 uint32_t trailing_samples)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	return q6asm_stream_remove_silence(ac, stream_id,
138062306a36Sopenharmony_ci				   ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
138162306a36Sopenharmony_ci				   trailing_samples);
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci/**
138662306a36Sopenharmony_ci * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
138762306a36Sopenharmony_ci *
138862306a36Sopenharmony_ci * @ac: audio client pointer
138962306a36Sopenharmony_ci * @stream_id: stream id
139062306a36Sopenharmony_ci * @rate: audio sample rate
139162306a36Sopenharmony_ci * @channels: number of audio channels.
139262306a36Sopenharmony_ci * @bits_per_sample: bits per sample
139362306a36Sopenharmony_ci *
139462306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
139562306a36Sopenharmony_ci */
139662306a36Sopenharmony_ciint q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
139762306a36Sopenharmony_ci					 uint32_t stream_id, uint32_t rate,
139862306a36Sopenharmony_ci					 uint32_t channels,
139962306a36Sopenharmony_ci					 uint16_t bits_per_sample)
140062306a36Sopenharmony_ci{
140162306a36Sopenharmony_ci	struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
140262306a36Sopenharmony_ci	struct apr_pkt *pkt;
140362306a36Sopenharmony_ci	u8 *channel_mapping;
140462306a36Sopenharmony_ci	u32 frames_per_buf = 0;
140562306a36Sopenharmony_ci	int pkt_size, rc;
140662306a36Sopenharmony_ci	void *p;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
140962306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
141062306a36Sopenharmony_ci	if (!p)
141162306a36Sopenharmony_ci		return -ENOMEM;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	pkt = p;
141462306a36Sopenharmony_ci	enc_cfg = p + APR_HDR_SIZE;
141562306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
141862306a36Sopenharmony_ci	enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
141962306a36Sopenharmony_ci	enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
142062306a36Sopenharmony_ci	enc_cfg->encblk.frames_per_buf = frames_per_buf;
142162306a36Sopenharmony_ci	enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
142262306a36Sopenharmony_ci					sizeof(struct asm_enc_cfg_blk_param_v2);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	enc_cfg->num_channels = channels;
142562306a36Sopenharmony_ci	enc_cfg->bits_per_sample = bits_per_sample;
142662306a36Sopenharmony_ci	enc_cfg->sample_rate = rate;
142762306a36Sopenharmony_ci	enc_cfg->is_signed = 1;
142862306a36Sopenharmony_ci	channel_mapping = enc_cfg->channel_mapping;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (q6dsp_map_channels(channel_mapping, channels)) {
143162306a36Sopenharmony_ci		rc = -EINVAL;
143262306a36Sopenharmony_ci		goto err;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
143662306a36Sopenharmony_cierr:
143762306a36Sopenharmony_ci	kfree(pkt);
143862306a36Sopenharmony_ci	return rc;
143962306a36Sopenharmony_ci}
144062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci/**
144462306a36Sopenharmony_ci * q6asm_read() - read data of period size from audio client
144562306a36Sopenharmony_ci *
144662306a36Sopenharmony_ci * @ac: audio client pointer
144762306a36Sopenharmony_ci * @stream_id: stream id
144862306a36Sopenharmony_ci *
144962306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
145062306a36Sopenharmony_ci */
145162306a36Sopenharmony_ciint q6asm_read(struct audio_client *ac, uint32_t stream_id)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	struct asm_data_cmd_read_v2 *read;
145462306a36Sopenharmony_ci	struct audio_port_data *port;
145562306a36Sopenharmony_ci	struct audio_buffer *ab;
145662306a36Sopenharmony_ci	struct apr_pkt *pkt;
145762306a36Sopenharmony_ci	unsigned long flags;
145862306a36Sopenharmony_ci	int pkt_size;
145962306a36Sopenharmony_ci	int rc = 0;
146062306a36Sopenharmony_ci	void *p;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*read);
146362306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_ATOMIC);
146462306a36Sopenharmony_ci	if (!p)
146562306a36Sopenharmony_ci		return -ENOMEM;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	pkt = p;
146862306a36Sopenharmony_ci	read = p + APR_HDR_SIZE;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
147162306a36Sopenharmony_ci	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
147262306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
147362306a36Sopenharmony_ci	ab = &port->buf[port->dsp_buf];
147462306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
147562306a36Sopenharmony_ci	read->buf_addr_lsw = lower_32_bits(ab->phys);
147662306a36Sopenharmony_ci	read->buf_addr_msw = upper_32_bits(ab->phys);
147762306a36Sopenharmony_ci	read->mem_map_handle = port->mem_map_handle;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	read->buf_size = ab->size;
148062306a36Sopenharmony_ci	read->seq_id = port->dsp_buf;
148162306a36Sopenharmony_ci	pkt->hdr.token = port->dsp_buf;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	port->dsp_buf++;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (port->dsp_buf >= port->num_periods)
148662306a36Sopenharmony_ci		port->dsp_buf = 0;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
148962306a36Sopenharmony_ci	rc = apr_send_pkt(ac->adev, pkt);
149062306a36Sopenharmony_ci	if (rc == pkt_size)
149162306a36Sopenharmony_ci		rc = 0;
149262306a36Sopenharmony_ci	else
149362306a36Sopenharmony_ci		pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	kfree(pkt);
149662306a36Sopenharmony_ci	return rc;
149762306a36Sopenharmony_ci}
149862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_read);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
150162306a36Sopenharmony_ci		uint32_t format, uint16_t bits_per_sample)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	struct asm_stream_cmd_open_read_v3 *open;
150462306a36Sopenharmony_ci	struct apr_pkt *pkt;
150562306a36Sopenharmony_ci	int pkt_size, rc;
150662306a36Sopenharmony_ci	void *p;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*open);
150962306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_KERNEL);
151062306a36Sopenharmony_ci	if (!p)
151162306a36Sopenharmony_ci		return -ENOMEM;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	pkt = p;
151462306a36Sopenharmony_ci	open = p + APR_HDR_SIZE;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, stream_id);
151762306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
151862306a36Sopenharmony_ci	/* Stream prio : High, provide meta info with encoded frames */
151962306a36Sopenharmony_ci	open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
152262306a36Sopenharmony_ci	open->bits_per_sample = bits_per_sample;
152362306a36Sopenharmony_ci	open->mode_flags = 0x0;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
152662306a36Sopenharmony_ci				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	switch (format) {
152962306a36Sopenharmony_ci	case FORMAT_LINEAR_PCM:
153062306a36Sopenharmony_ci		open->mode_flags |= 0x00;
153162306a36Sopenharmony_ci		open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
153262306a36Sopenharmony_ci		break;
153362306a36Sopenharmony_ci	default:
153462306a36Sopenharmony_ci		pr_err("Invalid format[%d]\n", format);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	rc = q6asm_ac_send_cmd_sync(ac, pkt);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	kfree(pkt);
154062306a36Sopenharmony_ci	return rc;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci/**
154462306a36Sopenharmony_ci * q6asm_open_read() - Open audio client for reading
154562306a36Sopenharmony_ci *
154662306a36Sopenharmony_ci * @ac: audio client pointer
154762306a36Sopenharmony_ci * @stream_id: stream id
154862306a36Sopenharmony_ci * @format: audio sample format
154962306a36Sopenharmony_ci * @bits_per_sample: bits per sample
155062306a36Sopenharmony_ci *
155162306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
155262306a36Sopenharmony_ci */
155362306a36Sopenharmony_ciint q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
155462306a36Sopenharmony_ci		    uint32_t format, uint16_t bits_per_sample)
155562306a36Sopenharmony_ci{
155662306a36Sopenharmony_ci	return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_open_read);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci/**
156162306a36Sopenharmony_ci * q6asm_write_async() - non blocking write
156262306a36Sopenharmony_ci *
156362306a36Sopenharmony_ci * @ac: audio client pointer
156462306a36Sopenharmony_ci * @stream_id: stream id
156562306a36Sopenharmony_ci * @len: length in bytes
156662306a36Sopenharmony_ci * @msw_ts: timestamp msw
156762306a36Sopenharmony_ci * @lsw_ts: timestamp lsw
156862306a36Sopenharmony_ci * @wflags: flags associated with write
156962306a36Sopenharmony_ci *
157062306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
157162306a36Sopenharmony_ci */
157262306a36Sopenharmony_ciint q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
157362306a36Sopenharmony_ci		      uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	struct asm_data_cmd_write_v2 *write;
157662306a36Sopenharmony_ci	struct audio_port_data *port;
157762306a36Sopenharmony_ci	struct audio_buffer *ab;
157862306a36Sopenharmony_ci	unsigned long flags;
157962306a36Sopenharmony_ci	struct apr_pkt *pkt;
158062306a36Sopenharmony_ci	int pkt_size;
158162306a36Sopenharmony_ci	int rc = 0;
158262306a36Sopenharmony_ci	void *p;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	pkt_size = APR_HDR_SIZE + sizeof(*write);
158562306a36Sopenharmony_ci	p = kzalloc(pkt_size, GFP_ATOMIC);
158662306a36Sopenharmony_ci	if (!p)
158762306a36Sopenharmony_ci		return -ENOMEM;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	pkt = p;
159062306a36Sopenharmony_ci	write = p + APR_HDR_SIZE;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
159362306a36Sopenharmony_ci	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
159462306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	ab = &port->buf[port->dsp_buf];
159762306a36Sopenharmony_ci	pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
159862306a36Sopenharmony_ci	pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
159962306a36Sopenharmony_ci	write->buf_addr_lsw = lower_32_bits(ab->phys);
160062306a36Sopenharmony_ci	write->buf_addr_msw = upper_32_bits(ab->phys);
160162306a36Sopenharmony_ci	write->buf_size = len;
160262306a36Sopenharmony_ci	write->seq_id = port->dsp_buf;
160362306a36Sopenharmony_ci	write->timestamp_lsw = lsw_ts;
160462306a36Sopenharmony_ci	write->timestamp_msw = msw_ts;
160562306a36Sopenharmony_ci	write->mem_map_handle =
160662306a36Sopenharmony_ci	    ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	write->flags = wflags;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	port->dsp_buf++;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if (port->dsp_buf >= port->num_periods)
161362306a36Sopenharmony_ci		port->dsp_buf = 0;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
161662306a36Sopenharmony_ci	rc = apr_send_pkt(ac->adev, pkt);
161762306a36Sopenharmony_ci	if (rc == pkt_size)
161862306a36Sopenharmony_ci		rc = 0;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	kfree(pkt);
162162306a36Sopenharmony_ci	return rc;
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_write_async);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_cistatic void q6asm_reset_buf_state(struct audio_client *ac)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	struct audio_port_data *port;
162862306a36Sopenharmony_ci	unsigned long flags;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	spin_lock_irqsave(&ac->lock, flags);
163162306a36Sopenharmony_ci	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
163262306a36Sopenharmony_ci	port->dsp_buf = 0;
163362306a36Sopenharmony_ci	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
163462306a36Sopenharmony_ci	port->dsp_buf = 0;
163562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ac->lock, flags);
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cistatic int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
163962306a36Sopenharmony_ci		       bool wait)
164062306a36Sopenharmony_ci{
164162306a36Sopenharmony_ci	struct apr_pkt pkt;
164262306a36Sopenharmony_ci	int rc;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	switch (cmd) {
164762306a36Sopenharmony_ci	case CMD_PAUSE:
164862306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
164962306a36Sopenharmony_ci		break;
165062306a36Sopenharmony_ci	case CMD_SUSPEND:
165162306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
165262306a36Sopenharmony_ci		break;
165362306a36Sopenharmony_ci	case CMD_FLUSH:
165462306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
165562306a36Sopenharmony_ci		break;
165662306a36Sopenharmony_ci	case CMD_OUT_FLUSH:
165762306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
165862306a36Sopenharmony_ci		break;
165962306a36Sopenharmony_ci	case CMD_EOS:
166062306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_DATA_CMD_EOS;
166162306a36Sopenharmony_ci		break;
166262306a36Sopenharmony_ci	case CMD_CLOSE:
166362306a36Sopenharmony_ci		pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
166462306a36Sopenharmony_ci		break;
166562306a36Sopenharmony_ci	default:
166662306a36Sopenharmony_ci		return -EINVAL;
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (wait)
167062306a36Sopenharmony_ci		rc = q6asm_ac_send_cmd_sync(ac, &pkt);
167162306a36Sopenharmony_ci	else
167262306a36Sopenharmony_ci		return apr_send_pkt(ac->adev, &pkt);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	if (rc < 0)
167562306a36Sopenharmony_ci		return rc;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (cmd == CMD_FLUSH)
167862306a36Sopenharmony_ci		q6asm_reset_buf_state(ac);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	return 0;
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci/**
168462306a36Sopenharmony_ci * q6asm_cmd() - run cmd on audio client
168562306a36Sopenharmony_ci *
168662306a36Sopenharmony_ci * @ac: audio client pointer
168762306a36Sopenharmony_ci * @stream_id: stream id
168862306a36Sopenharmony_ci * @cmd: command to run on audio client.
168962306a36Sopenharmony_ci *
169062306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
169162306a36Sopenharmony_ci */
169262306a36Sopenharmony_ciint q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	return __q6asm_cmd(ac, stream_id, cmd, true);
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_cmd);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci/**
169962306a36Sopenharmony_ci * q6asm_cmd_nowait() - non blocking, run cmd on audio client
170062306a36Sopenharmony_ci *
170162306a36Sopenharmony_ci * @ac: audio client pointer
170262306a36Sopenharmony_ci * @stream_id: stream id
170362306a36Sopenharmony_ci * @cmd: command to run on audio client.
170462306a36Sopenharmony_ci *
170562306a36Sopenharmony_ci * Return: Will be an negative value on error or zero on success
170662306a36Sopenharmony_ci */
170762306a36Sopenharmony_ciint q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	return __q6asm_cmd(ac, stream_id, cmd, false);
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_cistatic int q6asm_probe(struct apr_device *adev)
171462306a36Sopenharmony_ci{
171562306a36Sopenharmony_ci	struct device *dev = &adev->dev;
171662306a36Sopenharmony_ci	struct q6asm *q6asm;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
171962306a36Sopenharmony_ci	if (!q6asm)
172062306a36Sopenharmony_ci		return -ENOMEM;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	q6asm->dev = dev;
172562306a36Sopenharmony_ci	q6asm->adev = adev;
172662306a36Sopenharmony_ci	init_waitqueue_head(&q6asm->mem_wait);
172762306a36Sopenharmony_ci	spin_lock_init(&q6asm->slock);
172862306a36Sopenharmony_ci	dev_set_drvdata(dev, q6asm);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	return devm_of_platform_populate(dev);
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci#ifdef CONFIG_OF
173462306a36Sopenharmony_cistatic const struct of_device_id q6asm_device_id[]  = {
173562306a36Sopenharmony_ci	{ .compatible = "qcom,q6asm" },
173662306a36Sopenharmony_ci	{},
173762306a36Sopenharmony_ci};
173862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, q6asm_device_id);
173962306a36Sopenharmony_ci#endif
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_cistatic struct apr_driver qcom_q6asm_driver = {
174262306a36Sopenharmony_ci	.probe = q6asm_probe,
174362306a36Sopenharmony_ci	.callback = q6asm_srvc_callback,
174462306a36Sopenharmony_ci	.driver = {
174562306a36Sopenharmony_ci		.name = "qcom-q6asm",
174662306a36Sopenharmony_ci		.of_match_table = of_match_ptr(q6asm_device_id),
174762306a36Sopenharmony_ci	},
174862306a36Sopenharmony_ci};
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_cimodule_apr_driver(qcom_q6asm_driver);
175162306a36Sopenharmony_ciMODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
175262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1753