/* size of tplg abi in byte */
 #define SOF_TPLG_ABI_SIZE 3
 
+struct sof_widget_data {
+       int ctrl_type;
+       int ipc_cmd;
+       struct sof_abi_hdr *pdata;
+       struct snd_sof_control *control;
+};
+
 /* send pcm params ipc */
 static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
 {
        return ret;
 }
 
-static int sof_process_load(struct snd_soc_component *scomp, int index,
-                           struct snd_sof_widget *swidget,
-                           struct snd_soc_tplg_dapm_widget *tw,
-                           struct sof_ipc_comp_reply *r,
-                           int type)
+static size_t sof_get_control_data(struct snd_sof_dev *sdev,
+                                  struct snd_soc_dapm_widget *widget,
+                                  struct sof_widget_data *wdata)
 {
-       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-       struct snd_soc_tplg_private *private = &tw->priv;
-       struct snd_soc_dapm_widget *widget = swidget->widget;
        const struct snd_kcontrol_new *kc;
-       struct soc_bytes_ext *sbe;
        struct soc_mixer_control *sm;
+       struct soc_bytes_ext *sbe;
        struct soc_enum *se;
-       struct snd_sof_control *scontrol = NULL;
-       struct sof_abi_hdr *pdata = NULL;
-       struct sof_ipc_comp_process *process;
-       size_t ipc_size, ipc_data_size = 0;
-       int ret, i, offset = 0;
-
-       if (type == SOF_COMP_NONE) {
-               dev_err(sdev->dev, "error: invalid process comp type %d\n",
-                       type);
-               return -EINVAL;
-       }
+       size_t size = 0;
+       int i;
 
-       /*
-        * get possible component controls - get size of all pdata,
-        * then memcpy with headers
-        */
        for (i = 0; i < widget->num_kcontrols; i++) {
-
                kc = &widget->kcontrol_news[i];
 
                switch (widget->dobj.widget.kcontrol_type) {
                case SND_SOC_TPLG_TYPE_MIXER:
                        sm = (struct soc_mixer_control *)kc->private_value;
-                       scontrol = sm->dobj.private;
+                       wdata[i].control = sm->dobj.private;
                        break;
                case SND_SOC_TPLG_TYPE_BYTES:
                        sbe = (struct soc_bytes_ext *)kc->private_value;
-                       scontrol = sbe->dobj.private;
+                       wdata[i].control = sbe->dobj.private;
                        break;
                case SND_SOC_TPLG_TYPE_ENUM:
                        se = (struct soc_enum *)kc->private_value;
-                       scontrol = se->dobj.private;
+                       wdata[i].control = se->dobj.private;
                        break;
                default:
                        dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n",
                        return -EINVAL;
                }
 
-               if (!scontrol) {
+               if (!wdata[i].control) {
                        dev_err(sdev->dev, "error: no scontrol for widget %s\n",
                                widget->name);
                        return -EINVAL;
                }
 
-               /* don't include if no private data */
-               pdata = scontrol->control_data->data;
-               if (!pdata)
-                       continue;
+               wdata[i].pdata = wdata[i].control->control_data->data;
+               if (!wdata[i].pdata)
+                       return -EINVAL;
 
                /* make sure data is valid - data can be updated at runtime */
-               if (pdata->magic != SOF_ABI_MAGIC)
-                       continue;
+               if (wdata[i].pdata->magic != SOF_ABI_MAGIC)
+                       return -EINVAL;
+
+               size += wdata[i].pdata->size;
+
+               /* get data type */
+               switch (wdata[i].control->cmd) {
+               case SOF_CTRL_CMD_VOLUME:
+               case SOF_CTRL_CMD_ENUM:
+               case SOF_CTRL_CMD_SWITCH:
+                       wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
+                       wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
+                       break;
+               case SOF_CTRL_CMD_BINARY:
+                       wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
+                       wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return size;
+}
+
+static int sof_process_load(struct snd_soc_component *scomp, int index,
+                           struct snd_sof_widget *swidget,
+                           struct snd_soc_tplg_dapm_widget *tw,
+                           struct sof_ipc_comp_reply *r,
+                           int type)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct snd_soc_dapm_widget *widget = swidget->widget;
+       struct snd_soc_tplg_private *private = &tw->priv;
+       struct sof_ipc_comp_process *process = NULL;
+       struct sof_widget_data *wdata = NULL;
+       size_t ipc_data_size = 0;
+       size_t ipc_size;
+       int offset = 0;
+       int ret = 0;
+       int i;
+
+       if (type == SOF_COMP_NONE) {
+               dev_err(sdev->dev, "error: invalid process comp type %d\n",
+                       type);
+               return -EINVAL;
+       }
+
+       /* allocate struct for widget control data sizes and types */
+       if (widget->num_kcontrols) {
+               wdata = kcalloc(widget->num_kcontrols,
+                               sizeof(*wdata),
+                               GFP_KERNEL);
+
+               if (!wdata)
+                       return -ENOMEM;
 
-               ipc_data_size += pdata->size;
+               /* get possible component controls and get size of all pdata */
+               ipc_data_size = sof_get_control_data(sdev, widget, wdata);
+
+               if (ipc_data_size <= 0) {
+                       ret = ipc_data_size;
+                       goto out;
+               }
        }
 
        ipc_size = sizeof(struct sof_ipc_comp_process) +
                le32_to_cpu(private->size) +
                ipc_data_size;
 
+       /* we are exceeding max ipc size, config needs to be sent separately */
+       if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
+               ipc_size -= ipc_data_size;
+               ipc_data_size = 0;
+       }
+
        process = kzalloc(ipc_size, GFP_KERNEL);
-       if (!process)
-               return -ENOMEM;
+       if (!process) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* configure iir IPC message */
        process->comp.hdr.size = ipc_size;
         * get possible component controls - get size of all pdata,
         * then memcpy with headers
         */
-       for (i = 0; i < widget->num_kcontrols; i++) {
-               kc = &widget->kcontrol_news[i];
-
-               switch (widget->dobj.widget.kcontrol_type) {
-               case SND_SOC_TPLG_TYPE_MIXER:
-                       sm = (struct soc_mixer_control *)kc->private_value;
-                       scontrol = sm->dobj.private;
-                       break;
-               case SND_SOC_TPLG_TYPE_BYTES:
-                       sbe = (struct soc_bytes_ext *)kc->private_value;
-                       scontrol = sbe->dobj.private;
-                       break;
-               case SND_SOC_TPLG_TYPE_ENUM:
-                       se = (struct soc_enum *)kc->private_value;
-                       scontrol = se->dobj.private;
-                       break;
-               default:
-                       dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n",
-                               widget->dobj.widget.kcontrol_type,
-                               widget->name);
-                       return -EINVAL;
+       if (ipc_data_size) {
+               for (i = 0; i < widget->num_kcontrols; i++) {
+                       memcpy(&process->data + offset,
+                              wdata[i].pdata->data,
+                              wdata[i].pdata->size);
+                       offset += wdata[i].pdata->size;
                }
-
-               /* don't include if no private data */
-               pdata = scontrol->control_data->data;
-               if (!pdata)
-                       continue;
-
-               /* make sure data is valid - data can be updated at runtime */
-               if (pdata->magic != SOF_ABI_MAGIC)
-                       continue;
-
-               memcpy(&process->data + offset, pdata->data, pdata->size);
-               offset += pdata->size;
        }
 
        process->size = ipc_data_size;
 
        ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process,
                                 ipc_size, r, sizeof(*r));
-       if (ret >= 0)
-               return ret;
+
+       if (ret < 0) {
+               dev_err(sdev->dev, "error: create process failed\n");
+               goto err;
+       }
+
+       /* we sent the data in single message so return */
+       if (ipc_data_size)
+               goto out;
+
+       /* send control data with large message supported method */
+       for (i = 0; i < widget->num_kcontrols; i++) {
+               wdata[i].control->readback_offset = 0;
+               ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control,
+                                                   wdata[i].ipc_cmd,
+                                                   wdata[i].ctrl_type,
+                                                   wdata[i].control->cmd,
+                                                   true);
+               if (ret != 0) {
+                       dev_err(sdev->dev, "error: send control failed\n");
+                       break;
+               }
+       }
+
 err:
-       kfree(process);
+       if (ret < 0)
+               kfree(process);
+out:
+       kfree(wdata);
        return ret;
 }