diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c
index 7a113f5d7128d9c2d9a181916906f8a3c251c94c..37d3292f08618af0d970b1598b3b4af879c7f5de 100644
--- a/sound/soc/fsl/fsl_hifi4.c
+++ b/sound/soc/fsl/fsl_hifi4.c
@@ -60,11 +60,13 @@ struct decode_info_compat32 {
 	__s32 out_buf_off;
 	__u32 cycles;
 	__u32 input_over;
+	__u32 process_id;
 };
 
 struct binary_info_compat32 {
 	__s32 type;
 	compat_long_t file;
+	__u32 process_id;
 };
 
 static int get_binary_info_compat32(struct binary_info *kp,
@@ -75,7 +77,8 @@ static int get_binary_info_compat32(struct binary_info *kp,
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct binary_info_compat32)) ||
 		get_user(kp->type, &up->type) ||
-		get_user(p, &up->file)
+		get_user(p, &up->file) ||
+		get_user(kp->process_id, &up->process_id)
 	   ) {
 		return -EFAULT;
 	}
@@ -86,6 +89,19 @@ static int get_binary_info_compat32(struct binary_info *kp,
 	return 0;
 }
 
+static int put_binary_info_compat32(struct binary_info *kp,
+				struct binary_info_compat32 *up)
+{
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(struct binary_info_compat32)) ||
+		put_user(kp->process_id, &up->process_id)
+	   ) {
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
 static int get_decode_info_compat32(struct decode_info *kp,
 				struct decode_info_compat32 *up)
 {
@@ -102,7 +118,8 @@ static int get_decode_info_compat32(struct decode_info *kp,
 		get_user(kp->out_buf_size, &up->out_buf_size) ||
 		get_user(kp->out_buf_off, &up->out_buf_off) ||
 		get_user(kp->cycles, &up->cycles) ||
-		get_user(kp->input_over, &up->input_over)
+		get_user(kp->input_over, &up->input_over) ||
+		get_user(kp->process_id, &up->process_id)
 	   ) {
 		return -EFAULT;
 	}
@@ -133,6 +150,66 @@ static int put_decode_info_compat32(struct decode_info *kp,
 }
 #endif
 
+long switch_codec(struct fsl_hifi4 *hifi4_priv, int id)
+{
+	union icm_header_t apu_icm;
+	struct hifi4_ext_msg ext_msg;
+	struct icm_switch_info_t switch_info;
+	int i;
+	long ret = 0;
+
+	switch_info.proc_id = id;
+	switch_info.status  = 0;
+
+	init_completion(&hifi4_priv->cmd_complete);
+	hifi4_priv->is_done = 0;
+
+	apu_icm.allbits = 0;	/* clear all bits; */
+
+	apu_icm.ack = 0;
+	apu_icm.intr = 1;
+	apu_icm.msg = ICM_SWITCH_CODEC;
+	apu_icm.size = 8;
+
+	ext_msg.phys = hifi4_priv->msg_buf_phys;
+	ext_msg.size = sizeof(struct icm_switch_info_t);
+	memcpy(hifi4_priv->msg_buf_virt, &switch_info,
+				sizeof(struct icm_switch_info_t));
+
+	icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
+
+	/* wait for response here */
+	ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
+	if (ret)
+		return ret;
+
+	/* check whether the dsp framework switches successfully or not */
+	ret = hifi4_priv->ret_status;
+	if (ret)
+		return ret;
+
+	/* Because this variables are shared for every codec, so when
+	 * switching, need to recover it value for current codec.
+	 */
+	for (i = 0; i < MULTI_CODEC_NUM; i++) {
+		if (hifi4_priv->process_info[i].process_id == id) {
+			if (hifi4_priv->process_info[i].status) {
+				hifi4_priv->cur_res_id = i;
+				hifi4_priv->pil_info =
+				  hifi4_priv->process_info[i].pil_info_info;
+				hifi4_priv->objtype =
+				  hifi4_priv->process_info[i].codec_id;
+				hifi4_priv->codec_iobuf_info.proc_id =
+				  hifi4_priv->process_info[i].proc_id;
+				break;
+			}
+		}
+	}
+	/* update the current process id to the new process id */
+	hifi4_priv->process_id = id;
+
+	return ret;
+}
 
 long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv)
 {
@@ -140,8 +217,11 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv)
 	unsigned char *srambuf = NULL;
 	struct lib_dnld_info_t dpulib;
 	int filesize = 0;
+	unsigned int id;
 	long ret_val = 0;
 
+	id = hifi4_priv->cur_res_id;
+
 	/* Load DPU's main program to System memory */
 	fpInfile = file_open_name(hifi4_priv->objfile, O_RDONLY, 0);
 	if (IS_ERR(fpInfile))
@@ -164,8 +244,12 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv)
 	if (ret_val != XTLIB_NO_ERR)
 		return ret_val;
 
+	hifi4_priv->size_code = dpulib.size_code;
+	hifi4_priv->size_data = dpulib.size_data;
+
 	dpulib.pbuf_code =  (unsigned long)hifi4_priv->code_buf_phys;
-	dpulib.pbuf_data =  (unsigned long)hifi4_priv->data_buf_phys;
+	dpulib.pbuf_data =
+		(unsigned long)hifi4_priv->process_info[id].data_buf_phys;
 
 	dpulib.ppil_inf = &hifi4_priv->pil_info;
 	xtlib_host_load_split_pi_library(
@@ -537,13 +621,14 @@ static xt_ptr xtlib_load_split_pi_library_common(
 	struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals;
 	Elf32_Ehdr *header = (Elf32_Ehdr *) library;
 	Elf32_Phdr *pheader;
-	unsigned int align;
+	unsigned int align, id;
 	int err = validate_dynamic_splitload(header, hifi4_priv);
 
 	if (err != XTLIB_NO_ERR) {
 		xtlib_globals->err = err;
 		return 0;
 	}
+	id = hifi4_priv->cur_res_id;
 
 	align = find_align(header, hifi4_priv);
 
@@ -585,7 +670,7 @@ static xt_ptr xtlib_load_split_pi_library_common(
 	xtlib_load_seg(&pheader[1],
 		  (char *)library + xtlib_host_word(pheader[1].p_offset,
 						xtlib_globals->byteswap),
-		  (xt_ptr)hifi4_priv->data_buf_virt +
+		  (xt_ptr)hifi4_priv->process_info[id].data_buf_virt +
 		  xtlib_host_word(pheader[1].p_paddr,
 						xtlib_globals->byteswap),
 		  mcpy_fn, mset_fn, hifi4_priv);
@@ -618,36 +703,28 @@ xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library,
 }
 
 
-static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv)
+static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv,
+							void __user *user)
 {
+	struct device *dev = hifi4_priv->dev;
 	union icm_header_t apu_icm;
 	struct hifi4_ext_msg ext_msg;
-	struct icm_pilib_size_t lib_alloc_mem;
+	int id;
 	long ret = 0;
 
-	init_completion(&hifi4_priv->cmd_complete);
-	hifi4_priv->is_done = 0;
-
-	apu_icm.allbits = 0;	/* clear all bits; */
-	apu_icm.ack = 0;
-	apu_icm.intr = 1;
-	apu_icm.msg = ICM_PI_LIB_MEM_ALLOC;
-	apu_icm.size = 8;
-
-	ext_msg.phys = hifi4_priv->msg_buf_phys;
-	ext_msg.size = sizeof(struct icm_pilib_size_t);
-
-	lib_alloc_mem.codec_type = hifi4_priv->objtype;
-
-	memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem,
-					sizeof(struct icm_pilib_size_t));
-	icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
-	/* wait for response here */
-	ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
-	if (ret)
-		return ret;
+	ret = copy_from_user(&id, user, sizeof(int));
+	if (ret) {
+		dev_err(dev, "failed to get para from user space\n");
+		return -EFAULT;
+	}
 
+	if (hifi4_priv->process_id != id) {
+		ret = switch_codec(hifi4_priv, id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec init\n");
+			return ret;
+		}
+	}
 
 	init_completion(&hifi4_priv->cmd_complete);
 	hifi4_priv->is_done = 0;
@@ -687,7 +764,15 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv,
 	ret = copy_from_user(&decode_info, user, sizeof(decode_info));
 	if (ret) {
 		dev_err(dev, "failed to get para from user space\n");
-		return ret;
+		return -EFAULT;
+	}
+
+	if (hifi4_priv->process_id != decode_info.process_id) {
+		ret = switch_codec(hifi4_priv, decode_info.process_id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec decode frame\n");
+			return ret;
+		}
 	}
 
 	if (decode_info.in_buf_size > INPUT_BUF_SIZE ||
@@ -709,6 +794,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv,
 
 	codec_iobuf_info->inp_addr_sysram  = hifi4_priv->in_buf_phys;
 	codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size;
+	codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off;
 
 	codec_iobuf_info->out_addr_sysram  = hifi4_priv->out_buf_phys;
 	codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size;
@@ -749,7 +835,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv,
 	ret = copy_to_user(user, &decode_info, sizeof(decode_info));
 	if (ret) {
 		dev_err(dev, "failed to send para to user space\n");
-		return ret;
+		return -EFAULT;
 	}
 
 	ret = hifi4_priv->ret_status;
@@ -774,6 +860,14 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv,
 		return ret;
 	}
 
+	if (hifi4_priv->process_id != decode_info.process_id) {
+		ret = switch_codec(hifi4_priv, decode_info.process_id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec decode frame in compat32 mode\n");
+			return ret;
+		}
+	}
+
 	if (decode_info.in_buf_size > INPUT_BUF_SIZE ||
 		decode_info.out_buf_size != OUTPUT_BUF_SIZE) {
 		dev_err(dev, "param error\n");
@@ -793,6 +887,7 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv,
 
 	codec_iobuf_info->inp_addr_sysram  = hifi4_priv->in_buf_phys;
 	codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size;
+	codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off;
 
 	codec_iobuf_info->out_addr_sysram  = hifi4_priv->out_buf_phys;
 	codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size;
@@ -831,7 +926,6 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv,
 	decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset;
 	decode_info.out_buf_off = codec_iobuf_info->out_cur_offset;
 	decode_info.cycles = codec_iobuf_info->cycles;
-	decode_info.input_over = codec_iobuf_info->input_over;
 
 	ret = put_decode_info_compat32(&decode_info, user);
 	if (ret) {
@@ -856,7 +950,15 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv,
 	ret = copy_from_user(&prop_info, user, sizeof(prop_info));
 	if (ret) {
 		dev_err(dev, "failed to get para from user space\n");
-		return ret;
+		return -EFAULT;
+	}
+
+	if (hifi4_priv->process_id != prop_info.process_id) {
+		ret = switch_codec(hifi4_priv, prop_info.process_id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec get param\n");
+			return ret;
+		}
 	}
 
 	init_completion(&hifi4_priv->cmd_complete);
@@ -883,7 +985,7 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv,
 	ret = copy_to_user(user, &prop_info, sizeof(prop_info));
 	if (ret) {
 		dev_err(dev, "failed to send para to user space\n");
-		return ret;
+		return -EFAULT;
 	}
 
 	ret = hifi4_priv->ret_status;
@@ -901,7 +1003,15 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user)
 	ret = copy_from_user(&prop_config, user, sizeof(prop_config));
 	if (ret) {
 		dev_err(dev, "failed to get para from user space: %d\n", ret);
-		return ret;
+		return -EFAULT;
+	}
+
+	if (hifi4_priv->process_id != prop_config.process_id) {
+		ret = switch_codec(hifi4_priv, prop_config.process_id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec set param\n");
+			return ret;
+		}
 	}
 
 	init_completion(&hifi4_priv->cmd_complete);
@@ -922,6 +1032,7 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user)
 	icm_ack_wait(hifi4_priv, apu_icm.allbits);
 	if (ret)
 		return ret;
+
 	ret = hifi4_priv->ret_status;
 
 	return ret;
@@ -932,13 +1043,17 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv,
 {
 	struct device *dev = hifi4_priv->dev;
 	struct filename *fpInfile;
+	union icm_header_t apu_icm;
 	struct binary_info binary_info;
+	struct icm_pilib_size_t lib_alloc_mem;
+	struct hifi4_ext_msg ext_msg;
 	long ret = 0;
+	long i;
 
 	ret = copy_from_user(&binary_info, user, sizeof(binary_info));
 	if (ret) {
 		dev_err(dev, "failed to get para from user space\n");
-		return ret;
+		return -EFAULT;
 	}
 
 	fpInfile = getname(binary_info.file);
@@ -948,13 +1063,75 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv,
 		return PTR_ERR(fpInfile);
 	}
 
+	/* check whether the dsp driver has available resource or not */
+	for (i = 0; i < MULTI_CODEC_NUM; i++) {
+		if (!(hifi4_priv->process_info[i].status)) {
+			hifi4_priv->process_info[i].status = 1;
+			hifi4_priv->available_resource--;
+			break;
+		}
+	}
+	if (i >= MULTI_CODEC_NUM) {
+		dev_err(dev, "out of range of multi codec max number\n");
+		return -EINVAL;
+	}
+
+	/* If dsp driver has available resource, produce a new process
+	 * for the new codec.
+	 */
+	hifi4_priv->process_id_count++;
+
+	ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count);
+	if (ret) {
+		dev_err(dev, "failed to switch codec in codec load\n");
+		return ret;
+	}
+
 	hifi4_priv->objfile = fpInfile;
 	hifi4_priv->objtype = binary_info.type;
 
+	hifi4_priv->cur_res_id = i;
 	ret = load_dpu_with_library(hifi4_priv);
 	if (ret) {
 		dev_err(dev, "failed to load code binary, err = %ld\n", ret);
+	}
+
+	init_completion(&hifi4_priv->cmd_complete);
+	hifi4_priv->is_done = 0;
+
+	apu_icm.allbits = 0;	/* clear all bits; */
+	apu_icm.ack = 0;
+	apu_icm.intr = 1;
+	apu_icm.msg = ICM_PI_LIB_MEM_ALLOC;
+	apu_icm.size = 8;
+
+	ext_msg.phys = hifi4_priv->msg_buf_phys;
+	ext_msg.size = sizeof(struct icm_pilib_size_t);
+
+	lib_alloc_mem.codec_type = hifi4_priv->objtype;
+	lib_alloc_mem.text_size = hifi4_priv->size_code;
+	lib_alloc_mem.data_size = hifi4_priv->size_data;
+
+	memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem,
+					sizeof(struct icm_pilib_size_t));
+	icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
+
+	/* wait for response here */
+	ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
+	if (ret)
 		return ret;
+
+	/* save current codec information */
+	hifi4_priv->process_info[i].process_id = hifi4_priv->process_id;
+	hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype;
+	hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info;
+
+	/* return process id of this codec to user space */
+	binary_info.process_id = hifi4_priv->process_id;
+	ret = copy_to_user(user, &binary_info, sizeof(struct binary_info));
+	if (ret) {
+		dev_err(dev, "failed to send para to user space\n");
+		return -EFAULT;
 	}
 
 	hifi4_priv->ret_status = 0;
@@ -970,8 +1147,12 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv,
 {
 	struct device *dev = hifi4_priv->dev;
 	struct filename *fpInfile;
+	union icm_header_t apu_icm;
 	struct binary_info binary_info;
+	struct icm_pilib_size_t lib_alloc_mem;
+	struct hifi4_ext_msg ext_msg;
 	long ret = 0;
+	long i;
 
 	ret = get_binary_info_compat32(&binary_info, user);
 	if (ret) {
@@ -986,15 +1167,78 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv,
 		return PTR_ERR(fpInfile);
 	}
 
+	/* check whether the dsp driver has available resource or not */
+	for (i = 0; i < MULTI_CODEC_NUM; i++) {
+		if (!(hifi4_priv->process_info[i].status)) {
+			hifi4_priv->process_info[i].status = 1;
+			hifi4_priv->available_resource--;
+			break;
+		}
+	}
+	if (i >= MULTI_CODEC_NUM) {
+		dev_err(dev, "out of range of multi codec max number\n");
+		return -EINVAL;
+	}
+
+	/* If dsp driver has available resource, produce a new process
+	 * for the new codec.
+	 */
+	hifi4_priv->process_id_count++;
+
+	ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count);
+	if (ret) {
+		dev_err(dev, "failed to switch codec in codec load\n");
+		return ret;
+	}
+
 	hifi4_priv->objfile = fpInfile;
 	hifi4_priv->objtype = binary_info.type;
 
+	hifi4_priv->cur_res_id = i;
 	ret = load_dpu_with_library(hifi4_priv);
 	if (ret) {
 		dev_err(dev, "failed to load code binary, err = %ld\n", ret);
 		return ret;
 	}
 
+	init_completion(&hifi4_priv->cmd_complete);
+	hifi4_priv->is_done = 0;
+
+	apu_icm.allbits = 0;	/* clear all bits; */
+	apu_icm.ack = 0;
+	apu_icm.intr = 1;
+	apu_icm.msg = ICM_PI_LIB_MEM_ALLOC;
+	apu_icm.size = 8;
+
+	ext_msg.phys = hifi4_priv->msg_buf_phys;
+	ext_msg.size = sizeof(struct icm_pilib_size_t);
+
+	lib_alloc_mem.codec_type = hifi4_priv->objtype;
+	lib_alloc_mem.text_size = hifi4_priv->size_code;
+	lib_alloc_mem.data_size = hifi4_priv->size_data;
+
+	memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem,
+					sizeof(struct icm_pilib_size_t));
+	icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
+
+	/* wait for response here */
+	ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
+	if (ret)
+		return ret;
+
+	/* save current codec information */
+	hifi4_priv->process_info[i].process_id = hifi4_priv->process_id;
+	hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype;
+	hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info;
+
+	/* return process id of this codec to user space */
+	binary_info.process_id = hifi4_priv->process_id;
+	ret = put_binary_info_compat32(&binary_info, user);
+	if (ret) {
+		dev_err(dev, "failed to send para to user space\n");
+		return ret;
+	}
+
 	hifi4_priv->ret_status = 0;
 
 	dev_dbg(dev, "code binary is loaded\n");
@@ -1003,17 +1247,32 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv,
 }
 #endif
 
-static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv)
+static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv,
+							void __user *user)
 {
+	struct device *dev = hifi4_priv->dev;
 	union icm_header_t apu_icm;
 	struct icm_cdc_uinp_t cdc_user_inp;
 	struct hifi4_ext_msg ext_msg;
+	int id;
 	long ret = 0;
 
+	ret = copy_from_user(&id, user, sizeof(int));
+	if (ret) {
+		dev_err(dev, "failed to get para from user space\n");
+		return -EFAULT;
+	}
+
+	if (hifi4_priv->process_id != id) {
+		ret = switch_codec(hifi4_priv, id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec open\n");
+			return ret;
+		}
+	}
+
 	cdc_user_inp.proc_id   = 0;
 	cdc_user_inp.codec_id  = hifi4_priv->objtype;
-	cdc_user_inp.crc_check = 0;
-	cdc_user_inp.pcm_wd_sz = 16;
 
 	init_completion(&hifi4_priv->cmd_complete);
 	hifi4_priv->is_done = 0;
@@ -1037,15 +1296,36 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv)
 	if (ret)
 		return ret;
 
+	/* save current codec information */
+	hifi4_priv->process_info[hifi4_priv->cur_res_id].proc_id =
+					hifi4_priv->codec_iobuf_info.proc_id;
+
 	ret = hifi4_priv->ret_status;
 	return ret;
 }
 
-static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv)
+static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv,
+							void __user *user)
 {
+	struct device *dev = hifi4_priv->dev;
 	union icm_header_t apu_icm;
+	int id;
 	long ret = 0;
 
+	ret = copy_from_user(&id, user, sizeof(int));
+	if (ret) {
+		dev_err(dev, "failed to get para from user space\n");
+		return -EFAULT;
+	}
+
+	if (hifi4_priv->process_id != id) {
+		ret = switch_codec(hifi4_priv, id);
+		if (ret) {
+			dev_err(dev, "failed to switch codec in codec close\n");
+			return ret;
+		}
+	}
+
 	init_completion(&hifi4_priv->cmd_complete);
 	hifi4_priv->is_done = 0;
 
@@ -1058,6 +1338,18 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv)
 
 	/* wait for response here */
 	ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
+	if (ret)
+		return ret;
+
+	/* Making status to 0 means releasing the resource that
+	 * current codec occupies.
+	 */
+	hifi4_priv->process_info[hifi4_priv->cur_res_id].status = 0;
+	hifi4_priv->available_resource++;
+
+	/* If no codec occupies the resource, zero the process id count */
+	if (hifi4_priv->available_resource >= MULTI_CODEC_NUM)
+		hifi4_priv->process_id_count = 0;
 
 	return ret;
 }
@@ -1070,26 +1362,32 @@ static struct miscdevice hifi4_miscdev = {
 static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd,
 						unsigned long arg)
 {
-	struct fsl_hifi4_engine *hifi4_engine = file->private_data;
-	struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv;
-	void __user *user = (void __user *)arg;
+	struct fsl_hifi4_engine *hifi4_engine;
+	struct fsl_hifi4 *hifi4_priv;
+	void __user *user;
 	long ret = 0;
 
+	hifi4_engine = file->private_data;
+	hifi4_priv = hifi4_engine->hifi4_priv;
+	user = (void __user *)arg;
+
+	mutex_lock(&hifi4_priv->hifi4_mutex);
+
 	switch (cmd) {
 	case HIFI4_LOAD_CODEC:
 		ret = fsl_hifi4_load_codec(hifi4_priv, user);
 		break;
 	case HIFI4_INIT_CODEC:
-		ret = fsl_hifi4_init_codec(hifi4_priv);
+		ret = fsl_hifi4_init_codec(hifi4_priv, user);
 		break;
 	case HIFI4_CODEC_OPEN:
-		ret = fsl_hifi4_codec_open(hifi4_priv);
+		ret = fsl_hifi4_codec_open(hifi4_priv, user);
 		break;
 	case HIFI4_DECODE_ONE_FRAME:
 		ret = fsl_hifi4_decode_frame(hifi4_priv, user);
 		break;
 	case HIFI4_CODEC_CLOSE:
-		ret = fsl_hifi4_codec_close(hifi4_priv);
+		ret = fsl_hifi4_codec_close(hifi4_priv, user);
 		break;
 	case HIFI4_UNLOAD_CODEC:
 		break;
@@ -1103,6 +1401,8 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd,
 		break;
 	}
 
+	mutex_unlock(&hifi4_priv->hifi4_mutex);
+
 	return ret;
 }
 
@@ -1110,26 +1410,32 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd,
 static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd,
 							unsigned long arg)
 {
-	struct fsl_hifi4_engine *hifi4_engine = file->private_data;
-	struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv;
-	void __user *user = compat_ptr(arg);
+	struct fsl_hifi4_engine *hifi4_engine;
+	struct fsl_hifi4 *hifi4_priv;
+	void __user *user;
 	long ret = 0;
 
+	hifi4_engine = file->private_data;
+	hifi4_priv = hifi4_engine->hifi4_priv;
+	user = compat_ptr(arg);
+
+	mutex_lock(&hifi4_priv->hifi4_mutex);
+
 	switch (cmd) {
 	case HIFI4_LOAD_CODEC:
 		ret = fsl_hifi4_load_codec_compat32(hifi4_priv, user);
 		break;
 	case HIFI4_INIT_CODEC:
-		ret = fsl_hifi4_init_codec(hifi4_priv);
+		ret = fsl_hifi4_init_codec(hifi4_priv, user);
 		break;
 	case HIFI4_CODEC_OPEN:
-		ret = fsl_hifi4_codec_open(hifi4_priv);
+		ret = fsl_hifi4_codec_open(hifi4_priv, user);
 		break;
 	case HIFI4_DECODE_ONE_FRAME:
 		ret = fsl_hifi4_decode_frame_compat32(hifi4_priv, user);
 		break;
 	case HIFI4_CODEC_CLOSE:
-		ret = fsl_hifi4_codec_close(hifi4_priv);
+		ret = fsl_hifi4_codec_close(hifi4_priv, user);
 		break;
 	case HIFI4_UNLOAD_CODEC:
 		break;
@@ -1143,17 +1449,24 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd,
 		break;
 	}
 
+	mutex_unlock(&hifi4_priv->hifi4_mutex);
+
 	return ret;
 }
 #endif
 
 static int fsl_hifi4_open(struct inode *inode, struct file *file)
 {
-	struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
-	struct device *dev = hifi4_priv->dev;
+	struct fsl_hifi4 *hifi4_priv;
+	struct device *dev;
 	struct fsl_hifi4_engine *hifi4_engine;
 	int ret = 0;
 
+	hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
+	dev = hifi4_priv->dev;
+
+	mutex_lock(&hifi4_priv->hifi4_mutex);
+
 	hifi4_engine = devm_kzalloc(dev,
 				sizeof(struct fsl_hifi4_engine), GFP_KERNEL);
 	if (!hifi4_engine)
@@ -1181,19 +1494,26 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file)
 			return ret;
 		dev_info(dev, "hifi driver registered\n");
 	}
+	mutex_unlock(&hifi4_priv->hifi4_mutex);
 
 	return ret;
 }
 
 static int fsl_hifi4_close(struct inode *inode, struct file *file)
 {
-	struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
-	struct device *dev = hifi4_priv->dev;
+	struct fsl_hifi4 *hifi4_priv;
+	struct device *dev;
 	struct fsl_hifi4_engine *hifi4_engine;
 
+	hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
+	mutex_lock(&hifi4_priv->hifi4_mutex);
+
+	dev = hifi4_priv->dev;
 	hifi4_engine = file->private_data;
 	devm_kfree(dev, hifi4_engine);
 
+	mutex_unlock(&hifi4_priv->hifi4_mutex);
+
 	return 0;
 }
 
@@ -1298,8 +1618,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
 
 	switch (recd_msg.sub_msg) {
 	case ICM_PI_LIB_MEM_ALLOC:
-		hifi4_priv->is_done = 1;
-		complete(&hifi4_priv->cmd_complete);
+		{
+			hifi4_priv->is_done = 1;
+			complete(&hifi4_priv->cmd_complete);
+		}
 		break;
 
 	case ICM_OPEN:
@@ -1307,10 +1629,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
 			struct icm_open_resp_info_t *pext_msg =
 			    (struct icm_open_resp_info_t *)pmsg_apu;
 			codec_iobuf_info->proc_id = pext_msg->proc_id;
-			hifi4_priv->is_done = 1;
 			hifi4_priv->dpu_tstamp =
 			    (struct timestamp_info_t *)pext_msg->dtstamp;
 			hifi4_priv->ret_status = pext_msg->ret;
+			hifi4_priv->is_done = 1;
 			complete(&hifi4_priv->cmd_complete);
 		}
 		break;
@@ -1326,9 +1648,9 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
 				codec_iobuf_info->cycles =
 						ext_msg->cycles;
 			}
-			complete(&hifi4_priv->cmd_complete);
-			hifi4_priv->is_done = 1;
 			hifi4_priv->ret_status = ext_msg->ret;
+			hifi4_priv->is_done = 1;
+			complete(&hifi4_priv->cmd_complete);
 		}
 		break;
 
@@ -1343,10 +1665,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
 			pcm_prop_info->bits     = ext_msg->bits;
 			pcm_prop_info->consumed_bytes =
 					ext_msg->consumed_bytes;
+			hifi4_priv->ret_status = ext_msg->ret;
 
-			complete(&hifi4_priv->cmd_complete);
 			hifi4_priv->is_done = 1;
-			hifi4_priv->ret_status = ext_msg->ret;
+			complete(&hifi4_priv->cmd_complete);
 		}
 		break;
 
@@ -1354,20 +1676,30 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
 		{
 			struct prop_config *ext_msg =
 				(struct prop_config *)pmsg_apu;
-			complete(&hifi4_priv->cmd_complete);
-			hifi4_priv->is_done = 1;
 			hifi4_priv->ret_status = ext_msg->ret;
+			hifi4_priv->is_done = 1;
+			complete(&hifi4_priv->cmd_complete);
 		}
 		break;
 
 	case ICM_PI_LIB_INIT:
-		complete(&hifi4_priv->cmd_complete);
 		hifi4_priv->is_done = 1;
+		complete(&hifi4_priv->cmd_complete);
 		break;
 
 	case ICM_CLOSE:
-		complete(&hifi4_priv->cmd_complete);
 		hifi4_priv->is_done = 1;
+		complete(&hifi4_priv->cmd_complete);
+		break;
+
+	case ICM_SWITCH_CODEC:
+		{
+			struct icm_switch_info_t *ext_msg =
+				(struct icm_switch_info_t *)pmsg_apu;
+			hifi4_priv->ret_status = ext_msg->status;
+			hifi4_priv->is_done = 1;
+			complete(&hifi4_priv->cmd_complete);
+		}
 		break;
 
 	default:
@@ -1391,7 +1723,8 @@ int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv)
 	apu_icm.msg  = ICM_EXT_MSG_ADDR;
 	apu_icm.size = 8;
 	ext_msg.phys = hifi4_priv->msg_buf_phys;
-	ext_msg.size = 8*4;
+	/* 10 means variable numbers that need to be transferred */
+	ext_msg.size = 10*4;	/* 10 * sizeof(int) */
 	dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048;
 	dpu_ext_msg->ext_msg_size = 2048;
 	dpu_ext_msg->code_phys =  hifi4_priv->code_buf_phys;
@@ -1400,6 +1733,8 @@ int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv)
 	dpu_ext_msg->data_size =  hifi4_priv->data_buf_size;
 	dpu_ext_msg->scratch_phys =  hifi4_priv->scratch_buf_phys;
 	dpu_ext_msg->scratch_size =  hifi4_priv->scratch_buf_size;
+	dpu_ext_msg->system_input_buf_phys =  hifi4_priv->in_buf_phys;
+	dpu_ext_msg->system_input_buf_size =  hifi4_priv->in_buf_size;
 
 	icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
 
@@ -1592,7 +1927,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev)
 	sc_err_t sciErr;
 	void *buf_virt;
 	dma_addr_t buf_phys;
-	int size, offset;
+	int size, offset, i;
 	int ret;
 
 	hifi4_priv = devm_kzalloc(&pdev->dev, sizeof(*hifi4_priv), GFP_KERNEL);
@@ -1730,6 +2065,30 @@ static int fsl_hifi4_probe(struct platform_device *pdev)
 	hifi4_priv->scratch_buf_phys = buf_phys + offset;
 	hifi4_priv->scratch_buf_size = SCRATCH_DATA_BUF_SIZE;
 
+	/* process_id_count is a counter to produce new id
+	 * process_id is current codec's id
+	 */
+	hifi4_priv->process_id_count = 0;
+	hifi4_priv->process_id = 0;
+
+	/* initialize the resources of multi codec
+	 * MULTI_CODEC_NUM is the max codec number that dsp
+	 * driver and framework can support.
+	 */
+	hifi4_priv->available_resource = MULTI_CODEC_NUM;
+	for (i = 0; i < MULTI_CODEC_NUM; i++) {
+		hifi4_priv->process_info[i].data_buf_virt =
+				hifi4_priv->data_buf_virt +
+				i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM;
+		hifi4_priv->process_info[i].data_buf_phys =
+				hifi4_priv->data_buf_phys +
+				i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM;
+
+		hifi4_priv->process_info[i].status = 0;
+	}
+
+	mutex_init(&hifi4_priv->hifi4_mutex);
+
 	return 0;
 }
 
diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h
index 3cb835654f06204ceb4b3ea4472499bb6479a195..d28666b311711514395d3f5e216399457b1d5842 100644
--- a/sound/soc/fsl/fsl_hifi4.h
+++ b/sound/soc/fsl/fsl_hifi4.h
@@ -21,6 +21,7 @@ typedef void (*memcpy_func) (void *dest, const void *src, size_t n);
 typedef void (*memset_func) (void *s, int c, size_t n);
 struct xtlib_packaged_library;
 
+#define MULTI_CODEC_NUM		5
 
 enum {
 	XTLIB_NO_ERR = 0,
@@ -61,8 +62,6 @@ struct icm_cdc_iobuf_t {
 struct icm_cdc_uinp_t {
 	u32 proc_id;			/* audio id */
 	u32 codec_id;			/* codec identifier */
-	u32 pcm_wd_sz;			/* pcm word size; only 16 or 24 */
-	u32 crc_check;			/* 0: disable, 1: enable */
 };
 
 struct icm_pcm_prop_t {
@@ -134,6 +133,8 @@ enum icm_action_t {
 
 	ICM_CORE_EXIT,
 	ICM_EXT_MSG_ADDR,
+
+	ICM_SWITCH_CODEC,
 };
 
 enum aud_status_t {
@@ -150,6 +151,11 @@ struct icm_open_resp_info_t {
 	s32 ret;
 };
 
+struct icm_switch_info_t {
+	u32 proc_id;    /* audio id */
+	u32 status;     /* codec status */
+};
+
 struct lib_dnld_info_t {
 	unsigned long pbuf_code;
 	unsigned long pbuf_data;
@@ -166,6 +172,18 @@ struct icm_pilib_size_t {
 	u32 data_size;
 };
 
+struct icm_process_info {
+	unsigned int process_id;
+	unsigned int codec_id;
+	unsigned int proc_id;
+
+	void *data_buf_virt;
+	dma_addr_t data_buf_phys;
+
+	struct xtlib_pil_info pil_info_info;
+	unsigned int status;
+};
+
 struct fsl_hifi4 {
 	struct device			*dev;
 	const char			*fw_name;
@@ -214,6 +232,18 @@ struct fsl_hifi4 {
 	struct xtlib_pil_info		pil_info;
 	struct xtlib_loader_globals	xtlib_globals;
 	struct timestamp_info_t		*dpu_tstamp;
+
+	struct mutex hifi4_mutex;
+
+	unsigned int process_id;
+	unsigned int process_id_count;
+
+	unsigned int size_code;
+	unsigned int size_data;
+
+	struct icm_process_info process_info[MULTI_CODEC_NUM];
+	unsigned int available_resource;
+	unsigned int cur_res_id;
 };
 
 struct fsl_hifi4_engine {
@@ -234,6 +264,8 @@ struct hifi4_mem_msg {
 	u32	data_size;
 	u32	scratch_phys;
 	u32	scratch_size;
+	u32	system_input_buf_phys;
+	u32	system_input_buf_size;
 };
 
 #define IRAM_OFFSET		0x10000
@@ -257,8 +289,8 @@ struct hifi4_mem_msg {
 #define MSG_BUF_SIZE		4096
 #define INPUT_BUF_SIZE		4096
 #define OUTPUT_BUF_SIZE		16384
-#define FIRMWARE_DATA_BUF_SIZE	0x100000
-#define SCRATCH_DATA_BUF_SIZE	0x100000
+#define FIRMWARE_DATA_BUF_SIZE	(MULTI_CODEC_NUM * 0x80000)
+#define SCRATCH_DATA_BUF_SIZE	(MULTI_CODEC_NUM * 0x80000)
 
 #define MEMORY_REMAP_OFFSET	0x39000000