return 0;
 }
 
+static int
+sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
+{
+       int i;
+
+       /* init the volume table */
+       scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
+       if (!scontrol->volume_table)
+               return -ENOMEM;
+
+       /* populate the volume table */
+       for (i = 0; i < size ; i++)
+               scontrol->volume_table[i] = vol_compute_gain(i, tlv);
+
+       return 0;
+}
+
 const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
        .volume_put = sof_ipc3_volume_put,
        .volume_get = sof_ipc3_volume_get,
        .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
        .update = sof_ipc3_control_update,
        .widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
+       .set_up_volume_table = sof_ipc3_set_up_volume_table,
 };
 
  */
 #define VOLUME_FWL     16
 
+#define SOF_TLV_ITEMS 3
+
 struct snd_sof_widget;
 struct snd_sof_route;
 struct snd_sof_control;
        void (*update)(struct snd_sof_dev *sdev, void *ipc_control_message);
        /* Optional callback to setup kcontrols associated with an swidget */
        int (*widget_kcontrol_setup)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
+       /* mandatory callback to set up volume table for volume kcontrols */
+       int (*set_up_volume_table)(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS],
+                                  int size);
 };
 
 /**
                          size_t object_size, int token_instance_num);
 int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd,
                                    struct snd_sof_pcm *spcm, int dir);
+u32 vol_compute_gain(u32 value, int *tlv);
 #endif
 
 #define VOL_HALF_DB_STEP       50
 
 /* TLV data items */
-#define TLV_ITEMS      3
 #define TLV_MIN                0
 #define TLV_STEP       1
 #define TLV_MUTE       2
        return 0;
 }
 
-static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
+static inline int get_tlv_data(const int *p, int tlv[SOF_TLV_ITEMS])
 {
        /* we only support dB scale TLV type at the moment */
        if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
  * Function to calculate volume gain from TLV data.
  * This function can only handle gain steps that are multiples of 0.5 dB
  */
-static u32 vol_compute_gain(u32 value, int *tlv)
+u32 vol_compute_gain(u32 value, int *tlv)
 {
        int dB_gain;
        u32 linear_gain;
  * "size" specifies the number of entries in the table
  */
 static int set_up_volume_table(struct snd_sof_control *scontrol,
-                              int tlv[TLV_ITEMS], int size)
+                              int tlv[SOF_TLV_ITEMS], int size)
 {
-       int j;
-
-       /* init the volume table */
-       scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
-       if (!scontrol->volume_table)
-               return -ENOMEM;
+       struct snd_soc_component *scomp = scontrol->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 
-       /* populate the volume table */
-       for (j = 0; j < size ; j++)
-               scontrol->volume_table[j] = vol_compute_gain(j, tlv);
+       if (tplg_ops->control->set_up_volume_table)
+               return tplg_ops->control->set_up_volume_table(scontrol, tlv, size);
 
-       return 0;
+       dev_err(scomp->dev, "Mandatory op %s not set\n", __func__);
+       return -EINVAL;
 }
 
 struct sof_dai_types {
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
        struct snd_soc_tplg_mixer_control *mc =
                container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
-       int tlv[TLV_ITEMS];
+       int tlv[SOF_TLV_ITEMS];
        unsigned int mask;
        int ret;