*/
 #define SOF_WIDGET_MAX_NUM_PINS        8
 
+/* The type of a widget pin is either sink or source */
+#define SOF_PIN_TYPE_SINK      0
+#define SOF_PIN_TYPE_SOURCE    1
+
 /* max number of FE PCMs before BEs */
 #define SOF_BE_PCM_BASE                16
 
        u32 num_sink_pins;
        u32 num_source_pins;
 
+       /*
+        * The sink/source pin binding array, it takes the form of
+        * [widget_name_connected_to_pin0, widget_name_connected_to_pin1, ...],
+        * with the index as the queue ID.
+        *
+        * The array is used for special pin binding. Note that even if there
+        * is only one sink/source pin requires special pin binding, pin binding
+        * should be defined for all sink/source pins in topology, for pin(s) that
+        * are not used, give the value "NotConnected".
+        *
+        * If pin binding is not defined in topology, nothing to parse in the kernel,
+        * sink_pin_binding and src_pin_binding shall be NULL.
+        */
+       char **sink_pin_binding;
+       char **src_pin_binding;
+
        void *private;          /* core does not touch this */
 };
 
 int get_token_comp_format(void *elem, void *object, u32 offset);
 int get_token_dai_type(void *elem, void *object, u32 offset);
 int get_token_uuid(void *elem, void *object, u32 offset);
+int get_token_string(void *elem, void *object, u32 offset);
 int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id,
                          struct snd_sof_tuple *tuples, int num_tuples,
                          size_t object_size, int token_instance_num);
 
        return 0;
 }
 
+/*
+ * The string gets from topology will be stored in heap, the owner only
+ * holds a char* member point to the heap.
+ */
+int get_token_string(void *elem, void *object, u32 offset)
+{
+       /* "dst" here points to the char* member of the owner */
+       char **dst = (char **)((u8 *)object + offset);
+
+       *dst = kstrdup(elem, GFP_KERNEL);
+       if (!*dst)
+               return -ENOMEM;
+       return 0;
+};
+
 int get_token_comp_format(void *elem, void *object, u32 offset)
 {
        u32 *val = (u32 *)((u8 *)object + offset);
                offsetof(struct snd_sof_widget, num_source_pins)},
 };
 
+static const struct sof_topology_token comp_sink_pin_binding_tokens[] = {
+       {SOF_TKN_COMP_SINK_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+               get_token_string, 0},
+};
+
+static const struct sof_topology_token comp_src_pin_binding_tokens[] = {
+       {SOF_TKN_COMP_SRC_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+               get_token_string, 0},
+};
+
 /**
  * sof_parse_uuid_tokens - Parse multiple sets of UUID tokens
  * @scomp: pointer to soc component
 {
        struct snd_soc_tplg_vendor_string_elem *elem;
        int found = 0;
-       int i, j;
+       int i, j, ret;
 
        /* parse element by element */
        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
                                continue;
 
                        /* matched - now load token */
-                       tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+                       ret = tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+                       if (ret < 0)
+                               return ret;
 
                        found++;
                }
        int found = 0;
        int total = 0;
        int asize;
+       int ret;
 
        while (array_size > 0 && total < count * token_instance_num) {
                asize = le32_to_cpu(array->size);
                                                       array);
                        break;
                case SND_SOC_TPLG_TUPLE_TYPE_STRING:
-                       found += sof_parse_string_tokens(scomp, object, offset, tokens, count,
-                                                        array);
+
+                       ret = sof_parse_string_tokens(scomp, object, offset, tokens, count,
+                                                     array);
+                       if (ret < 0) {
+                               dev_err(scomp->dev, "error: no memory to copy string token\n");
+                               return ret;
+                       }
+
+                       found += ret;
                        break;
                case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
                case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
        return ret;
 }
 
+static void sof_free_pin_binding(struct snd_sof_widget *swidget,
+                                bool pin_type)
+{
+       char **pin_binding;
+       u32 num_pins;
+       int i;
+
+       if (pin_type == SOF_PIN_TYPE_SINK) {
+               pin_binding = swidget->sink_pin_binding;
+               num_pins = swidget->num_sink_pins;
+       } else {
+               pin_binding = swidget->src_pin_binding;
+               num_pins = swidget->num_source_pins;
+       }
+
+       if (pin_binding) {
+               for (i = 0; i < num_pins; i++)
+                       kfree(pin_binding[i]);
+       }
+
+       kfree(pin_binding);
+}
+
+static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
+                                struct snd_soc_tplg_private *priv, bool pin_type)
+{
+       const struct sof_topology_token *pin_binding_token;
+       char *pin_binding[SOF_WIDGET_MAX_NUM_PINS];
+       int token_count;
+       u32 num_pins;
+       char **pb;
+       int ret;
+       int i;
+
+       if (pin_type == SOF_PIN_TYPE_SINK) {
+               num_pins = swidget->num_sink_pins;
+               pin_binding_token = comp_sink_pin_binding_tokens;
+               token_count = ARRAY_SIZE(comp_sink_pin_binding_tokens);
+       } else {
+               num_pins = swidget->num_source_pins;
+               pin_binding_token = comp_src_pin_binding_tokens;
+               token_count = ARRAY_SIZE(comp_src_pin_binding_tokens);
+       }
+
+       memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *));
+       ret = sof_parse_token_sets(swidget->scomp, pin_binding, pin_binding_token,
+                                  token_count, priv->array, le32_to_cpu(priv->size),
+                                  num_pins, sizeof(char *));
+       if (ret < 0)
+               goto err;
+
+       /* copy pin binding array to swidget only if it is defined in topology */
+       if (pin_binding[0]) {
+               pb = kmemdup(pin_binding, num_pins * sizeof(char *), GFP_KERNEL);
+               if (!pb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               if (pin_type == SOF_PIN_TYPE_SINK)
+                       swidget->sink_pin_binding = pb;
+               else
+                       swidget->src_pin_binding = pb;
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < num_pins; i++)
+               kfree(pin_binding[i]);
+
+       return ret;
+}
+
 /* external widget init - used for any driver specific init */
 static int sof_widget_ready(struct snd_soc_component *scomp, int index,
                            struct snd_soc_dapm_widget *w,
                return -EINVAL;
        }
 
+       if (swidget->num_sink_pins > 1) {
+               ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK);
+               /* on parsing error, pin binding is not allocated, nothing to free. */
+               if (ret < 0) {
+                       dev_err(scomp->dev, "failed to parse sink pin binding for %s\n",
+                               w->name);
+                       return ret;
+               }
+       }
+
+       if (swidget->num_source_pins > 1) {
+               ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE);
+               /* on parsing error, pin binding is not allocated, nothing to free. */
+               if (ret < 0) {
+                       dev_err(scomp->dev, "failed to parse source pin binding for %s\n",
+                               w->name);
+                       return ret;
+               }
+       }
+
        dev_dbg(scomp->dev,
                "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n",
                swidget->comp_id, w->name, swidget->id, index,
        if (widget_ops[swidget->id].ipc_free)
                widget_ops[swidget->id].ipc_free(swidget);
 
+       sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK);
+       sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE);
+
        kfree(swidget->tuples);
 
        /* remove and free swidget object */