greybus: audio: Use single codec driver registration
authorVaibhav Agarwal <vaibhav.agarwal@linaro.org>
Tue, 29 Mar 2016 18:01:41 +0000 (23:31 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 29 Mar 2016 18:15:14 +0000 (11:15 -0700)
We have single I2S port via APB1 for communication with all
audio modules. Thus, we should register single codec driver
and manage all individual audio modules internally within
this driver.

Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org>
Reviewed-by: Mark Greer <mark.greer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/audio_codec.c
drivers/staging/greybus/audio_codec.h
drivers/staging/greybus/audio_topology.c

index 30b381ab8a1f07a50a0088a6c2d15d40ff3d4906..ab24ec8c5ab88a549d0847ee298b4bc1b4c6d876 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Greybus audio driver
- * Copyright 2015 Google Inc.
- * Copyright 2015 Linaro Ltd.
+ * audio codec driver
+ * Copyright 2016 Google Inc.
+ * Copyright 2016 Linaro Ltd.
  *
  * Released under the GPLv2 only.
  */
 #include <linux/module.h>
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
-#include <sound/msm-dynamic-dailink.h>
 
 #include "audio_codec.h"
 #include "audio_apbridgea.h"
 #include "audio_manager.h"
 
-static DEFINE_MUTEX(gb_codec_list_lock);
-static LIST_HEAD(gb_codec_list);
+static struct gbaudio_codec_info *gbcodec;
 
-struct gbaudio_dai *gbaudio_find_dai(struct gbaudio_codec_info *gbcodec,
-                                    int data_cport, const char *name)
+struct gbaudio_data_connection *find_data(struct gbaudio_module_info *module,
+                                         const char *name)
 {
-       struct gbaudio_dai *dai;
+       struct gbaudio_data_connection *data;
 
-       list_for_each_entry(dai, &gbcodec->dai_list, list) {
-               if (name && !strncmp(dai->name, name, NAME_SIZE))
-                       return dai;
-               if ((data_cport != -1) && (dai->data_cport == data_cport))
-                       return dai;
+       list_for_each_entry(data, &module->data_list, list) {
+               if (name && !strncmp(data->name, name, NAME_SIZE))
+                       return data;
        }
        return NULL;
 }
 
-/*
- * codec DAI ops
- */
-static int gbcodec_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int find_stream(const char *name)
 {
-       int ret;
-       __u16 i2s_port, cportid;
+       int stream = 0;
+
+       if (strnstr(name, "SPK Amp", NAME_SIZE))
+               stream |= GB_PLAYBACK;
+
+       return stream;
+}
+
+static int gbaudio_module_disable(struct gbaudio_codec_info *codec,
+                                 struct gbaudio_module_info *module,
+                                 int dir)
+{
+       int ret = 0;
+       uint16_t data_cport, cportid, i2s_port;
+       int codec_state, module_state;
+       struct gbaudio_data_connection *data;
+       const char *dai_name;
+
+       mutex_lock(&codec->lock);
+
+       codec_state = codec->stream[dir].state;
+       if (codec_state == GBAUDIO_CODEC_SHUTDOWN) {
+               mutex_unlock(&codec->lock);
+               return 0;
+       }
+
+       dai_name = codec->stream[dir].dai_name;
 
-       struct gbaudio_dai *gb_dai;
-       struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev);
+       mutex_lock(&module->lock);
+       module_state = module->ctrlstate[dir];
+       if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
+               dev_dbg(codec->dev, "%s: module already configured\n",
+                       module->name);
+               goto func_exit;
+       }
 
-       if (!atomic_read(&gb->is_connected))
+       /* find the dai */
+       data = find_data(module, dai_name);
+       if (!data) {
+               dev_err(codec->dev, "%s:%s DATA connection missing\n",
+                       dai_name, module->name);
+               mutex_unlock(&module->lock);
+               mutex_unlock(&codec->lock);
                return -ENODEV;
+       }
+       if (codec_state > GBAUDIO_CODEC_HWPARAMS) {
+               data_cport = data->connection->intf_cport_id;
+               ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
+                                               data_cport);
+               if (ret) {
+                       dev_err(codec->dev, "deactivate_tx for %s failed:%d\n",
+                               module->name, ret);
+                       goto func_exit;
+               }
+               dev_dbg(codec->dev, "Dynamic deactivate %s:%d DAI\n", dai_name,
+                       data_cport);
+       }
+       if (codec_state > GBAUDIO_CODEC_SHUTDOWN) {
+               cportid = data->connection->hd_cport_id;
+               ret = gb_audio_apbridgea_unregister_cport(data->connection,
+                                               i2s_port, cportid,
+                                               AUDIO_APBRIDGEA_DIRECTION_TX);
+               if (ret) {
+                       dev_err(codec->dev, "unregister_cport for %s failed:%d\n",
+                               module->name, ret);
+                       goto func_exit;
+               }
+               dev_dbg(codec->dev, "Dynamic Unregister %s:%d DAI\n", dai_name,
+                       cportid);
+       }
+       module->ctrlstate[dir] = GBAUDIO_CODEC_SHUTDOWN;
+
+func_exit:
+       mutex_unlock(&module->lock);
+       mutex_unlock(&codec->lock);
+       return ret;
+}
+
+static int gbaudio_module_enable(struct gbaudio_codec_info *codec,
+                                struct gbaudio_module_info *module, int dir)
+{
+       int ret = 0;
+       __u16 i2s_port, cportid;
+       int codec_state, module_state;
+       uint16_t data_cport;
+       uint8_t sig_bits, channels;
+       uint32_t format, rate;
+       struct gbaudio_data_connection *data;
+       const char *dai_name;
+
+       mutex_lock(&codec->lock);
+
+       codec_state = codec->stream[dir].state;
+       if (codec_state == GBAUDIO_CODEC_SHUTDOWN) {
+               mutex_unlock(&codec->lock);
+               return 0;
+       }
+
+       dai_name = codec->stream[dir].dai_name;
+       format = codec->stream[dir].format;
+       channels = codec->stream[dir].channels;
+       rate = codec->stream[dir].rate;
+       sig_bits = codec->stream[dir].sig_bits;
+
+       mutex_lock(&module->lock);
+       module_state = module->ctrlstate[dir];
+       if (module_state == codec_state) {
+               dev_dbg(codec->dev, "%s: module already configured\n",
+                       module->name);
+               goto func_exit;
+       }
 
        /* find the dai */
-       mutex_lock(&gb->lock);
-       gb_dai = gbaudio_find_dai(gb, -1, dai->name);
-       if (!gb_dai) {
-               dev_err(dai->dev, "%s: DAI not registered\n", dai->name);
-               mutex_unlock(&gb->lock);
-               return -EINVAL;
+       data = find_data(module, dai_name);
+       if (!data) {
+               dev_err(codec->dev, "%s:%s DATA connection missing\n",
+                       dai_name, module->name);
+               mutex_unlock(&module->lock);
+               mutex_unlock(&codec->lock);
+               return -ENODEV;
        }
 
        /* register cport */
-       i2s_port = 0;   /* fixed for now */
-       cportid = gb_dai->connection->hd_cport_id;
-       ret = gb_audio_apbridgea_register_cport(gb_dai->connection, i2s_port,
-                                               cportid,
+       if (module_state < codec_state) {
+               i2s_port = 0;   /* fixed for now */
+               cportid = data->connection->hd_cport_id;
+               ret = gb_audio_apbridgea_register_cport(data->connection,
+                                               i2s_port, cportid,
                                                AUDIO_APBRIDGEA_DIRECTION_TX);
-       dev_dbg(dai->dev, "Register %s:%d DAI, ret:%d\n", dai->name, cportid,
-               ret);
+               if (ret) {
+                       dev_err(codec->dev, "reg_cport for %s\n", module->name);
+                       goto func_exit;
+               }
+               module_state = GBAUDIO_CODEC_STARTUP;
+               dev_dbg(codec->dev, "Dynamic Register %s:%d DAI\n", dai_name,
+                       cportid);
+       }
+
+       /* hw_params */
+       if (module_state < codec_state) {
+               data_cport = data->connection->intf_cport_id;
+               ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport,
+                                         format, rate, channels, sig_bits);
+               if (ret) {
+                       dev_err(codec->dev, "set_pcm for %s\n", module->name);
+                       goto func_exit;
+               }
+               module_state = GBAUDIO_CODEC_HWPARAMS;
+               dev_dbg(codec->dev, "Dynamic hw_params %s:%d DAI\n", dai_name,
+                       data_cport);
+       }
 
-       if (!ret)
-               atomic_inc(&gb_dai->users);
-       mutex_unlock(&gb->lock);
+       /* prepare */
+       if (module_state < codec_state) {
+               data_cport = data->connection->intf_cport_id;
+               ret = gb_audio_gb_set_tx_data_size(module->mgmt_connection,
+                                                  data_cport, 192);
+               if (ret) {
+                       dev_err(codec->dev, "set_tx_data_size for %s\n",
+                               module->name);
+                       goto func_exit;
+               }
+               ret = gb_audio_gb_activate_tx(module->mgmt_connection,
+                                             data_cport);
+               if (ret) {
+                       dev_err(codec->dev, "activate_tx for %s\n",
+                               module->name);
+                       goto func_exit;
+               }
+               module_state = GBAUDIO_CODEC_PREPARE;
+               dev_dbg(codec->dev, "Dynamic prepare %s:%d DAI\n", dai_name,
+                       data_cport);
+       }
 
+func_exit:
+       module->ctrlstate[dir] = module_state;
+       mutex_unlock(&module->lock);
+       mutex_unlock(&codec->lock);
        return ret;
 }
 
-static void gbcodec_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
+int gbaudio_module_update(struct gbaudio_codec_info *codec,
+                                const char *w_name,
+                                struct gbaudio_module_info *module, int enable)
 {
-       int ret;
-       __u16 i2s_port, cportid;
+       int stream, ret = 0;
+       int pb_state;
 
-       struct gbaudio_dai *gb_dai;
-       struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev);
+       dev_dbg(module->dev, "Module update %s sequence\n",
+               enable ? "Enable":"Disable");
 
-       /* find the dai */
-       gb_dai = gbaudio_find_dai(gb, -1, dai->name);
-       if (!gb_dai) {
-               dev_err(dai->dev, "%s: DAI not registered\n", dai->name);
-               goto func_exit;
+       stream = find_stream(w_name);
+       if (!stream) {
+               dev_dbg(codec->dev, "No action required for %s\n", w_name);
+               return 0;
        }
 
-       atomic_dec(&gb_dai->users);
+       /* check if playback active */
+       pb_state = codec->stream[SNDRV_PCM_STREAM_PLAYBACK].state;
+       if ((stream & GB_PLAYBACK) && (pb_state > GBAUDIO_CODEC_SHUTDOWN)) {
+               if (enable)
+                       ret = gbaudio_module_enable(codec, module,
+                                                   SNDRV_PCM_STREAM_PLAYBACK);
+               else
+                       ret = gbaudio_module_disable(codec, module,
+                                                    SNDRV_PCM_STREAM_PLAYBACK);
+       }
 
-       if (!atomic_read(&gb->is_connected)) {
-               if (!atomic_read(&gb_dai->users))
-                       wake_up_interruptible(&gb_dai->wait_queue);
-               return;
+       /* TBD
+        * check if capture active
+        * cap_state = codec->stream[SNDRV_PCM_STREAM_CAPTURE].state;
+        * if ((stream & GB_CAPTURE) && (cap_state > GBAUDIO_CODEC_SHUTDOWN))
+        *
+        */
+
+       return ret;
+}
+EXPORT_SYMBOL(gbaudio_module_update);
+
+/*
+ * codec DAI ops
+ */
+static int gbcodec_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       __u16 i2s_port, cportid;
+       int state;
+       struct gbaudio_data_connection *data;
+       struct gbaudio_module_info *module;
+       struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
+
+       mutex_lock(&codec->lock);
+
+       if (list_empty(&codec->module_list)) {
+               dev_err(codec->dev, "No codec module available\n");
+               mutex_unlock(&codec->lock);
+               return -ENODEV;
        }
 
-       mutex_lock(&gb->lock);
-       /* deactivate rx/tx */
-       cportid = gb_dai->connection->intf_cport_id;
+       state = codec->stream[substream->stream].state;
+       list_for_each_entry(module, &codec->module_list, list) {
+               mutex_lock(&module->lock);
+               if (!module->is_connected) {
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
 
-       switch (substream->stream) {
-       case SNDRV_PCM_STREAM_CAPTURE:
-               ret = gb_audio_gb_deactivate_rx(gb->mgmt_connection, cportid);
-               break;
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection, cportid);
-               break;
-       default:
-               dev_err(dai->dev, "Invalid stream type during shutdown\n");
-               goto func_exit;
+               /* find the dai */
+               data = find_data(module, dai->name);
+               if (!data) {
+                       dev_err(dai->dev, "%s:%s DATA connection missing\n",
+                               dai->name, module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
+
+               /* register cport */
+               i2s_port = 0;   /* fixed for now */
+               cportid = data->connection->hd_cport_id;
+               ret = gb_audio_apbridgea_register_cport(data->connection,
+                                               i2s_port, cportid,
+                                               AUDIO_APBRIDGEA_DIRECTION_TX);
+               dev_dbg(dai->dev, "Register %s:%d DAI, ret:%d\n", dai->name,
+                       cportid, ret);
+               state = GBAUDIO_CODEC_STARTUP;
+               module->ctrlstate[substream->stream] = state;
+               dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
+               mutex_unlock(&module->lock);
        }
+       codec->stream[substream->stream].state = state;
+       codec->stream[substream->stream].dai_name = dai->name;
+       mutex_unlock(&codec->lock);
 
-       if (ret)
-               dev_err(dai->dev, "%d:Error during deactivate\n", ret);
+       return ret;
+}
 
-       /* un register cport */
-       i2s_port = 0;   /* fixed for now */
-       ret = gb_audio_apbridgea_unregister_cport(gb_dai->connection, i2s_port,
-                                       gb_dai->connection->hd_cport_id,
-                                       AUDIO_APBRIDGEA_DIRECTION_TX);
+static void gbcodec_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       int ret;
+       __u16 i2s_port, cportid;
+       int state, module_state;
+       struct gbaudio_module_info *module;
+       struct gbaudio_data_connection *data;
+       struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
 
-       dev_dbg(dai->dev, "Unregister %s:%d DAI, ret:%d\n", dai->name,
-               gb_dai->connection->hd_cport_id, ret);
-func_exit:
-       mutex_unlock(&gb->lock);
+       mutex_lock(&codec->lock);
 
-       /*
-       if (!atomic_read(&gb_dai->users))
-               wake_up_interruptible(&gb_dai->wait_queue);
-               */
+       if (list_empty(&codec->module_list)) {
+               dev_err(codec->dev, "No codec module available\n");
+               mutex_unlock(&codec->lock);
+               return;
+       }
+
+       state = codec->stream[substream->stream].state;
+       list_for_each_entry(module, &codec->module_list, list) {
+               mutex_lock(&module->lock);
+               if (!module->is_connected) {
+                       dev_err(dai->dev, "%s:%s module not connected\n",
+                               __func__, module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
+               module_state = module->ctrlstate[substream->stream];
+               if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
+                       dev_dbg(codec->dev, "%s: module already configured\n",
+                               module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
+
+               /* find the dai */
+               data = find_data(module, dai->name);
+               if (!data) {
+                       dev_err(dai->dev, "%s:%s DATA connection missing\n",
+                               dai->name, module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
 
+               /* deactivate */
+               cportid = data->connection->intf_cport_id;
+               switch (substream->stream) {
+               case SNDRV_PCM_STREAM_CAPTURE:
+                       ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
+                                                       cportid);
+                       /* unregister cport */
+                       i2s_port = 0;   /* fixed for now */
+                       cportid = data->connection->hd_cport_id;
+                       ret = gb_audio_apbridgea_unregister_cport(
+                                       data->connection, i2s_port, cportid,
+                                       AUDIO_APBRIDGEA_DIRECTION_RX);
+                       break;
+               case SNDRV_PCM_STREAM_PLAYBACK:
+                       ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
+                                                       cportid);
+                       /* unregister cport */
+                       i2s_port = 0;   /* fixed for now */
+                       cportid = data->connection->hd_cport_id;
+                       ret = gb_audio_apbridgea_unregister_cport(
+                                       data->connection, i2s_port, cportid,
+                                       AUDIO_APBRIDGEA_DIRECTION_TX);
+                       break;
+               }
+               dev_dbg(dai->dev, "Unregister %s:%d DAI, ret:%d\n", dai->name,
+                       cportid, ret);
+               state = GBAUDIO_CODEC_SHUTDOWN;
+               module->ctrlstate[substream->stream] = state;
+               dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
+               mutex_unlock(&module->lock);
+       }
+       codec->stream[substream->stream].state = state;
+       codec->stream[substream->stream].dai_name = NULL;
+       mutex_unlock(&codec->lock);
        return;
 }
 
@@ -142,19 +396,17 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream,
        uint8_t sig_bits, channels;
        uint32_t format, rate;
        uint16_t data_cport;
-       struct gbaudio_dai *gb_dai;
-       struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev);
+       struct gbaudio_module_info *module;
+       struct gbaudio_data_connection *data;
+       int state;
+       struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       mutex_lock(&codec->lock);
 
-       /* find the dai */
-       mutex_lock(&gb->lock);
-       gb_dai = gbaudio_find_dai(gb, -1, dai->name);
-       if (!gb_dai) {
-               dev_err(dai->dev, "%s: DAI not registered\n", dai->name);
-               ret = -EINVAL;
-               goto func_exit;
+       if (list_empty(&codec->module_list)) {
+               dev_err(codec->dev, "No codec module available\n");
+               mutex_unlock(&codec->lock);
+               return -ENODEV;
        }
 
        /*
@@ -164,54 +416,86 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream,
        if (params_channels(hwparams) != 2) {
                dev_err(dai->dev, "Invalid channel count:%d\n",
                        params_channels(hwparams));
-               ret = -EINVAL;
-               goto func_exit;
+               mutex_unlock(&codec->lock);
+               return -EINVAL;
        }
        channels = params_channels(hwparams);
 
        if (params_rate(hwparams) != 48000) {
                dev_err(dai->dev, "Invalid sampling rate:%d\n",
                        params_rate(hwparams));
-               ret = -EINVAL;
-               goto func_exit;
+               mutex_unlock(&codec->lock);
+               return -EINVAL;
        }
        rate = GB_AUDIO_PCM_RATE_48000;
 
        if (params_format(hwparams) != SNDRV_PCM_FORMAT_S16_LE) {
                dev_err(dai->dev, "Invalid format:%d\n",
                        params_format(hwparams));
-               ret = -EINVAL;
-               goto func_exit;
+               mutex_unlock(&codec->lock);
+               return -EINVAL;
        }
        format = GB_AUDIO_PCM_FMT_S16_LE;
 
-       data_cport = gb_dai->connection->intf_cport_id;
-       /* XXX check impact of sig_bit
-        * it should not change ideally
-        */
+       state = codec->stream[substream->stream].state;
+       list_for_each_entry(module, &codec->module_list, list) {
+               mutex_lock(&module->lock);
+               if (!module->is_connected) {
+                       dev_err(dai->dev, "%s:%s module not connected\n",
+                               __func__, module->name);
+                       ret = -ENODEV;
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
 
-       dev_dbg(dai->dev, "cport:%d, rate:%d, channel %d, format %d, sig_bits:%d\n",
-               data_cport, rate, channels, format, sig_bits);
-       ret = gb_audio_gb_set_pcm(gb->mgmt_connection, data_cport, format,
-                                 rate, channels, sig_bits);
-       if (ret) {
-               dev_err(dai->dev, "%d: Error during set_pcm\n", ret);
-               goto func_exit;
+               /* find the data connection */
+               data = find_data(module, dai->name);
+               if (!data) {
+                       dev_err(dai->dev, "%s:%s DATA connection missing\n",
+                               dai->name, module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
+
+               data_cport = data->connection->intf_cport_id;
+               /* XXX check impact of sig_bit
+                * it should not change ideally
+                */
+               dev_dbg(dai->dev,
+                       "cport:%d, rate:%d, channel %d, format %d, sig_bits:%d\n",
+                       data_cport, rate, channels, format, sig_bits);
+               ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport,
+                                         format, rate, channels, sig_bits);
+               if (ret) {
+                       dev_err(dai->dev, "%d: Error during set_pcm\n", ret);
+                       mutex_unlock(&module->lock);
+                       goto func_exit;
+               }
+               if (state < GBAUDIO_CODEC_HWPARAMS) {
+                       ret = gb_audio_apbridgea_set_config(data->connection, 0,
+                                               AUDIO_APBRIDGEA_PCM_FMT_16,
+                                               AUDIO_APBRIDGEA_PCM_RATE_48000,
+                                               6144000);
+                       if (ret) {
+                               dev_err(dai->dev,
+                                       "%d: Error during set_config\n", ret);
+                               mutex_unlock(&module->lock);
+                               goto func_exit;
+                       }
+               }
+               state = GBAUDIO_CODEC_HWPARAMS;
+               module->ctrlstate[substream->stream] = state;
+               dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
+               mutex_unlock(&module->lock);
        }
+       codec->stream[substream->stream].state = state;
+       codec->stream[substream->stream].format = format;
+       codec->stream[substream->stream].rate = rate;
+       codec->stream[substream->stream].channels = channels;
+       codec->stream[substream->stream].sig_bits = sig_bits;
 
-       /*
-        * XXX need to check if
-        * set config is always required
-        * check for mclk_freq as well
-        */
-       ret = gb_audio_apbridgea_set_config(gb_dai->connection, 0,
-                                           AUDIO_APBRIDGEA_PCM_FMT_16,
-                                           AUDIO_APBRIDGEA_PCM_RATE_48000,
-                                           6144000);
-       if (ret)
-               dev_err(dai->dev, "%d: Error during set_config\n", ret);
 func_exit:
-       mutex_unlock(&gb->lock);
+       mutex_unlock(&codec->lock);
        return ret;
 }
 
@@ -220,76 +504,110 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream,
 {
        int ret;
        uint16_t data_cport;
-       struct gbaudio_dai *gb_dai;
-       struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev);
+       struct gbaudio_data_connection *data;
+       struct gbaudio_module_info *module;
+       int state;
+       struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       mutex_lock(&codec->lock);
 
-       /* find the dai */
-       mutex_lock(&gb->lock);
-       gb_dai = gbaudio_find_dai(gb, -1, dai->name);
-       if (!gb_dai) {
-               dev_err(dai->dev, "%s: DAI not registered\n", dai->name);
-               ret = -EINVAL;
-               goto func_exit;
+       if (list_empty(&codec->module_list)) {
+               dev_err(codec->dev, "No codec module available\n");
+               mutex_unlock(&codec->lock);
+               return -ENODEV;
        }
 
-       /* deactivate rx/tx */
-       data_cport = gb_dai->connection->intf_cport_id;
+       state = codec->stream[substream->stream].state;
+       list_for_each_entry(module, &codec->module_list, list) {
+               mutex_lock(&module->lock);
+               if (!module->is_connected) {
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
 
-       switch (substream->stream) {
-       case SNDRV_PCM_STREAM_CAPTURE:
-               ret = gb_audio_gb_set_rx_data_size(gb->mgmt_connection,
-                                                  data_cport, 192);
-               if (ret) {
-                       dev_err(dai->dev,
-                               "%d:Error during set_rx_data_size, cport:%d\n",
-                               ret, data_cport);
-                       goto func_exit;
+               /* find the dai */
+               data = find_data(module, dai->name);
+               if (!data) {
+                       dev_err(dai->dev, "%s:%s DATA connection missing\n",
+                               dai->name, module->name);
+                       mutex_unlock(&module->lock);
+                       continue;
                }
-               ret = gb_audio_apbridgea_set_rx_data_size(gb_dai->connection, 0,
-                                                         192);
-               if (ret) {
-                       dev_err(dai->dev,
+               /* deactivate rx/tx */
+               data_cport = data->connection->intf_cport_id;
+
+               switch (substream->stream) {
+               case SNDRV_PCM_STREAM_CAPTURE:
+                       ret = gb_audio_gb_set_rx_data_size(
+                                               module->mgmt_connection,
+                                               data_cport, 192);
+                       if (ret) {
+                               dev_err(dai->dev,
+                                       "%d:Error during set_rx_data_size, cport:%d\n",
+                                       ret, data_cport);
+                               mutex_unlock(&module->lock);
+                               goto func_exit;
+                       }
+                       if (state < GBAUDIO_CODEC_PREPARE) {
+                               ret = gb_audio_apbridgea_set_rx_data_size(
+                                                       data->connection, 0,
+                                                       192);
+                               if (ret) {
+                                       dev_err(dai->dev,
                                "%d:Error during apbridgea_set_rx_data_size\n",
                                ret);
-                       goto func_exit;
-               }
-               ret = gb_audio_gb_activate_rx(gb->mgmt_connection, data_cport);
-               break;
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               ret = gb_audio_gb_set_tx_data_size(gb->mgmt_connection,
-                                                  data_cport, 192);
-               if (ret) {
-                       dev_err(dai->dev,
-                               "%d:Error during module set_tx_data_size, cport:%d\n",
-                               ret, data_cport);
-                       goto func_exit;
-               }
-               ret = gb_audio_apbridgea_set_tx_data_size(gb_dai->connection, 0,
-                                                         192);
-               if (ret) {
-                       dev_err(dai->dev,
-                               "%d:Error during apbridgea set_tx_data_size, cport\n",
-                               ret);
-                       goto func_exit;
+                                       mutex_unlock(&module->lock);
+                                       goto func_exit;
+                               }
+                       }
+                       ret = gb_audio_gb_activate_rx(module->mgmt_connection,
+                                                     data_cport);
+                       if (ret)
+                               dev_err(dai->dev,
+                                       "%s:Error during activate stream,%d\n",
+                                       module->name, ret);
+                       break;
+               case SNDRV_PCM_STREAM_PLAYBACK:
+                       ret = gb_audio_gb_set_tx_data_size(
+                                               module->mgmt_connection,
+                                               data_cport, 192);
+                       if (ret) {
+                               dev_err(dai->dev,
+                                       "%d:Error during module set_tx_data_size, cport:%d\n",
+                                       ret, data_cport);
+                               mutex_unlock(&module->lock);
+                               goto func_exit;
+                       }
+                       if (state < GBAUDIO_CODEC_PREPARE) {
+                               ret = gb_audio_apbridgea_set_tx_data_size(
+                                                       data->connection, 0,
+                                                       192);
+                               if (ret) {
+                                       dev_err(dai->dev,
+                                               "%d:Error during apbridgea set_tx_data_size, cport\n",
+                                               ret);
+                                       mutex_unlock(&module->lock);
+                                       goto func_exit;
+                               }
+                       }
+                       ret = gb_audio_gb_activate_tx(module->mgmt_connection,
+                                                     data_cport);
+                       if (ret)
+                               dev_err(dai->dev,
+                                       "%s:Error during activate stream,%d\n",
+                                       module->name, ret);
+                       break;
                }
-               ret = gb_audio_gb_activate_tx(gb->mgmt_connection, data_cport);
-               break;
-       default:
-               dev_err(dai->dev, "Invalid stream type %d during prepare\n",
-                       substream->stream);
-               ret = -EINVAL;
-               goto func_exit;
+               state = GBAUDIO_CODEC_PREPARE;
+               module->ctrlstate[substream->stream] = state;
+               dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
+               mutex_unlock(&module->lock);
        }
-
-       if (ret)
-               dev_err(dai->dev, "%d: Error during activate stream\n", ret);
+       codec->stream[substream->stream].state = state;
 
 func_exit:
-       mutex_unlock(&gb->lock);
-       return ret;
+       mutex_unlock(&codec->lock);
+       return 0;
 }
 
 static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -297,24 +615,19 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        int ret;
        int tx, rx, start, stop;
-       struct gbaudio_dai *gb_dai;
-       struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev);
-
-       if (!atomic_read(&gb->is_connected)) {
+       struct gbaudio_data_connection *data;
+       struct gbaudio_module_info *module;
+       struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
+
+       mutex_lock(&codec->lock);
+       if (list_empty(&codec->module_list)) {
+               dev_err(codec->dev, "No codec module available\n");
+               mutex_unlock(&codec->lock);
                if (cmd == SNDRV_PCM_TRIGGER_STOP)
                        return 0;
                return -ENODEV;
        }
 
-       /* find the dai */
-       mutex_lock(&gb->lock);
-       gb_dai = gbaudio_find_dai(gb, -1, dai->name);
-       if (!gb_dai) {
-               dev_err(dai->dev, "%s: DAI not registered\n", dai->name);
-               ret = -EINVAL;
-               goto func_exit;
-       }
-
        tx = rx = start = stop = 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -345,47 +658,60 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,
                goto func_exit;
        }
 
+       list_for_each_entry(module, &codec->module_list, list) {
+               mutex_lock(&module->lock);
+               if (!module->is_connected) {
+                       mutex_unlock(&module->lock);
+                       continue;
+               }
+
+               /* find the dai */
+               data = find_data(module, dai->name);
+               if (data)
+                       break;
+       }
+       if (!data) {
+               dev_err(dai->dev, "%s:%s DATA connection missing\n",
+                       dai->name, module->name);
+               ret = -ENODEV;
+               mutex_unlock(&module->lock);
+               goto func_exit;
+       }
        if (start && tx) {
-               ret = gb_audio_apbridgea_prepare_tx(gb_dai->connection, 0);
+               ret = gb_audio_apbridgea_prepare_tx(data->connection,
+                                                   0);
                if (!ret)
-                       ret = gb_audio_apbridgea_start_tx(gb_dai->connection, 0,
-                                                         0);
-       }
-
-       else if (start && rx) {
-               ret = gb_audio_apbridgea_prepare_rx(gb_dai->connection, 0);
+                       ret = gb_audio_apbridgea_start_tx(data->connection,
+                                                         0, 0);
+               codec->stream[substream->stream].state = GBAUDIO_CODEC_START;
+       } else if (start && rx) {
+               ret = gb_audio_apbridgea_prepare_rx(data->connection,
+                                                   0);
                if (!ret)
-                       ret = gb_audio_apbridgea_start_rx(gb_dai->connection,
+                       ret = gb_audio_apbridgea_start_rx(data->connection,
                                                          0);
-       }
-
-       else if (stop && tx) {
-               ret = gb_audio_apbridgea_stop_tx(gb_dai->connection, 0);
+               codec->stream[substream->stream].state = GBAUDIO_CODEC_START;
+       } else if (stop && tx) {
+               ret = gb_audio_apbridgea_stop_tx(data->connection, 0);
                if (!ret)
-                       ret = gb_audio_apbridgea_shutdown_tx(gb_dai->connection,
+                       ret = gb_audio_apbridgea_shutdown_tx(data->connection,
                                                             0);
-       }
-
-       else if (stop && rx) {
-               ret = gb_audio_apbridgea_stop_rx(gb_dai->connection, 0);
+               codec->stream[substream->stream].state = GBAUDIO_CODEC_STOP;
+       } else if (stop && rx) {
+               ret = gb_audio_apbridgea_stop_rx(data->connection, 0);
                if (!ret)
-                       ret = gb_audio_apbridgea_shutdown_rx(gb_dai->connection,
+                       ret = gb_audio_apbridgea_shutdown_rx(data->connection,
                                                             0);
-       }
-
-       else
+               codec->stream[substream->stream].state = GBAUDIO_CODEC_STOP;
+       } else
                ret = -EINVAL;
-
        if (ret)
-               dev_err(dai->dev, "%d:Error during %s stream\n", ret,
-                       start ? "Start" : "Stop");
-
-       /* in case device removed, return 0 for stop trigger */
-       if (stop && (ret == -ENODEV))
-               ret = 0;
+               dev_err(dai->dev, "%s:Error during %s stream:%d\n",
+                       module->name, start ? "Start" : "Stop", ret);
+       mutex_unlock(&module->lock);
 
 func_exit:
-       mutex_unlock(&gb->lock);
+       mutex_unlock(&codec->lock);
        return ret;
 }
 
@@ -409,476 +735,325 @@ static struct snd_soc_dai_ops gbcodec_dai_ops = {
        .digital_mute = gbcodec_digital_mute,
 };
 
-/*
- * codec driver ops
- */
-static int gbcodec_probe(struct snd_soc_codec *codec)
+int gbaudio_register_module(struct gbaudio_module_info *module)
 {
-       /* Empty function for now */
-       return 0;
-}
+       int ret;
+       struct snd_soc_codec *codec;
 
-static int gbcodec_remove(struct snd_soc_codec *codec)
-{
-       /* Empty function for now */
-       return 0;
-}
+       if (!gbcodec) {
+               dev_err(module->dev, "GB Codec not yet probed\n");
+               return -EAGAIN;
+       }
 
-static int gbcodec_write(struct snd_soc_codec *codec, unsigned int reg,
-                        unsigned int value)
-{
-       int ret = 0;
-       struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
-       u8 *gbcodec_reg = gbcodec->reg;
+       codec = gbcodec->codec;
+       mutex_lock(&gbcodec->lock);
 
-       if (reg == SND_SOC_NOPM)
-               return 0;
+       if (module->num_dais) {
+               dev_err(gbcodec->dev,
+                       "%d:DAIs not supported via gbcodec driver\n",
+                       module->num_dais);
+               mutex_unlock(&gbcodec->lock);
+               return -EINVAL;
+       }
 
-       if (reg >= GBCODEC_REG_COUNT)
-               return 0;
+       if (module->dapm_widgets)
+               snd_soc_dapm_new_controls(&codec->dapm, module->dapm_widgets,
+                                         module->num_dapm_widgets);
+       if (module->controls)
+               snd_soc_add_codec_controls(codec, module->controls,
+                                    module->num_controls);
+       if (module->dapm_routes)
+               snd_soc_dapm_add_routes(&codec->dapm, module->dapm_routes,
+                                       module->num_dapm_routes);
+
+       /* card already instantiated, create widgets here only */
+       if (codec->card->instantiated) {
+               ret = snd_soc_dapm_new_widgets(&codec->dapm);
+               if (!ret)
+                       snd_soc_dapm_link_dai_widgets_component(codec->card,
+                                                               &codec->dapm);
+       }
 
-       gbcodec_reg[reg] = value;
-       dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, value);
+       list_add(&module->list, &gbcodec->module_list);
+       dev_dbg(codec->dev, "Registered %s module\n", module->name);
 
-       return ret;
+       mutex_unlock(&gbcodec->lock);
+       return 0;
 }
+EXPORT_SYMBOL(gbaudio_register_module);
 
-static unsigned int gbcodec_read(struct snd_soc_codec *codec,
-                                unsigned int reg)
+void gbaudio_codec_cleanup(struct gbaudio_module_info *module)
 {
-       unsigned int val = 0;
-
-       struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
-       u8 *gbcodec_reg = gbcodec->reg;
-
-       if (reg == SND_SOC_NOPM)
-               return 0;
-
-       if (reg >= GBCODEC_REG_COUNT)
-               return 0;
-
-       val = gbcodec_reg[reg];
-       dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, val);
-
-       return val;
-}
+       struct gbaudio_data_connection *data;
+       int pb_state = gbcodec->stream[0].state;
+       int cap_state = gbcodec->stream[1].state;
+       int ret;
+       uint16_t i2s_port, cportid;
 
-/*
- * gb_snd management functions
- */
+       /* locks already acquired */
+       if (!pb_state && !cap_state)
+               return;
 
-/* XXX
- * since BE DAI path is not yet properly closed from above layer,
- * dsp dai.mi2s_dai_data.status_mask is still set to STATUS_PORT_STARTED
- * this causes immediate playback/capture to fail in case relevant mixer
- * control is not turned OFF
- * user need to try once again after failure to recover DSP state.
- */
-static void gb_audio_cleanup(struct gbaudio_codec_info *gb)
-{
-       int cportid, ret, timeout_result;
-       struct gbaudio_dai *gb_dai;
-       struct gb_connection *connection;
-       long timeout = msecs_to_jiffies(50);    /* 50ms */
-       struct device *dev = gb->dev;
-
-       list_for_each_entry(gb_dai, &gb->dai_list, list) {
-               /*
-                * In case of BE dailink, need to deactivate APBridge
-                * manually
-                */
-               if (atomic_read(&gb_dai->users)) {
-                       /* schedule a wait event */
-                       timeout_result =
-                               wait_event_interruptible_timeout(
-                                               gb_dai->wait_queue,
-                                               !atomic_read(&gb_dai->users),
-                                               timeout);
-                       if (!timeout_result)
-                               dev_warn(dev, "%s:DAI still in use.\n",
-                                        gb_dai->name);
-
-                       connection = gb_dai->connection;
-                       /* PB active */
-                       ret = gb_audio_apbridgea_stop_tx(connection, 0);
-                       if (ret)
-                               dev_info(dev, "%d:Failed during APBridge stop_tx\n",
-                                        ret);
-                       ret = gb_audio_apbridgea_shutdown_tx(connection, 0);
-                       if (ret)
-                               dev_info(dev, "%d:Failed during APBridge shutdown_tx\n",
-                                        ret);
-                       cportid = connection->intf_cport_id;
-                       ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection,
-                                                       cportid);
-                       if (ret)
-                               dev_info(dev,
-                                        "%d:Failed during deactivate_tx\n",
-                                        ret);
-                       cportid = connection->hd_cport_id;
-                       ret = gb_audio_apbridgea_unregister_cport(connection, 0,
-                                               cportid,
+       if (pb_state == GBAUDIO_CODEC_START) {
+               /* cleanup PB path, only APBridge specific */
+               data = find_data(module, gbcodec->stream[0].dai_name);
+               if (!data) {
+                       dev_err(gbcodec->dev, "%s: Missing data pointer\n",
+                               __func__);
+                       return;
+               }
+               ret = gb_audio_apbridgea_stop_tx(data->connection, 0);
+               if (ret)
+                       return;
+               ret = gb_audio_apbridgea_shutdown_tx(data->connection, 0);
+               if (ret)
+                       return;
+               i2s_port = 0;   /* fixed for now */
+               cportid = data->connection->hd_cport_id;
+               ret = gb_audio_apbridgea_unregister_cport(data->connection,
+                                               i2s_port, cportid,
                                                AUDIO_APBRIDGEA_DIRECTION_TX);
-                       if (ret)
-                               dev_info(dev, "%d:Failed during unregister cport\n",
-                                        ret);
+               gbcodec->stream[0].state = GBAUDIO_CODEC_SHUTDOWN;
+       }
+
+       if (cap_state == GBAUDIO_CODEC_START) {
+               /* cleanup CAP path, only APBridge specific */
+               data = find_data(module, gbcodec->stream[1].dai_name);
+               if (!data) {
+                       dev_err(gbcodec->dev, "%s: Missing data pointer\n",
+                               __func__);
+                       return;
                }
+               ret = gb_audio_apbridgea_stop_rx(data->connection, 0);
+               if (ret)
+                       return;
+               ret = gb_audio_apbridgea_shutdown_rx(data->connection, 0);
+               if (ret)
+                       return;
+               i2s_port = 0;   /* fixed for now */
+               cportid = data->connection->hd_cport_id;
+               ret = gb_audio_apbridgea_unregister_cport(data->connection,
+                                               i2s_port, cportid,
+                                               AUDIO_APBRIDGEA_DIRECTION_RX);
+               gbcodec->stream[1].state = GBAUDIO_CODEC_SHUTDOWN;
        }
 }
 
-static int gbaudio_register_codec(struct gbaudio_codec_info *gbcodec)
+void gbaudio_unregister_module(struct gbaudio_module_info *module)
 {
-       int ret, i;
-       struct device *dev = gbcodec->dev;
-       struct gb_connection *connection = gbcodec->mgmt_connection;
-       struct snd_soc_codec_driver *soc_codec_dev_gbcodec;
-       /*
-        * FIXME: malloc for topology happens via audio_gb driver
-        * should be done within codec driver itself
-        */
-       struct gb_audio_topology *topology;
+       struct snd_soc_codec *codec = gbcodec->codec;
+       struct snd_card *card = codec->card->snd_card;
 
-       soc_codec_dev_gbcodec = devm_kzalloc(gbcodec->dev,
-                                            sizeof(*soc_codec_dev_gbcodec),
-                                            GFP_KERNEL);
-       if (!soc_codec_dev_gbcodec) {
-               dev_err(gbcodec->dev, "Malloc failed for codec_driver\n");
-               return -ENOMEM;
-       }
+       dev_dbg(codec->dev, "Unregister %s module\n", module->name);
 
-       ret = gb_connection_enable(connection);
-       if (ret) {
-               dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
-               return ret;
-       }
+       /* complete widget processing, if ongoing */
+       snd_soc_dapm_sync(&codec->dapm);
 
-       gbcodec->dev_id = connection->intf->interface_id;
-       /* fetch topology data */
-       ret = gb_audio_gb_get_topology(connection, &topology);
-       if (ret) {
-               dev_err(dev, "%d:Error while fetching topology\n", ret);
-               goto tplg_fetch_err;
-       }
+       down_write(&card->controls_rwsem);
+       mutex_lock(&gbcodec->lock);
+       dev_dbg(codec->dev, "Process Unregister %s module\n", module->name);
+       mutex_lock(&module->lock);
 
-       /* process topology data */
-       ret = gbaudio_tplg_parse_data(gbcodec, topology);
-       if (ret) {
-               dev_err(dev, "%d:Error while parsing topology data\n",
-                         ret);
-               goto tplg_parse_err;
+       if (list_is_last(&module->list, &gbcodec->module_list)) {
+               dev_dbg(codec->dev, "Last module removed, cleanup APBridge\n");
+               gbaudio_codec_cleanup(module);
        }
-       gbcodec->topology = topology;
-
-       /* update codec info */
-       soc_codec_dev_gbcodec->probe = gbcodec_probe,
-       soc_codec_dev_gbcodec->remove = gbcodec_remove,
-
-       soc_codec_dev_gbcodec->read = gbcodec_read,
-       soc_codec_dev_gbcodec->write = gbcodec_write,
-
-       soc_codec_dev_gbcodec->reg_cache_size = GBCODEC_REG_COUNT,
-       soc_codec_dev_gbcodec->reg_cache_default = gbcodec_reg_defaults,
-       soc_codec_dev_gbcodec->reg_word_size = 1,
 
-       soc_codec_dev_gbcodec->idle_bias_off = true,
-       soc_codec_dev_gbcodec->ignore_pmdown_time = 1,
-
-       soc_codec_dev_gbcodec->controls = gbcodec->kctls;
-       soc_codec_dev_gbcodec->num_controls = gbcodec->num_kcontrols;
-       soc_codec_dev_gbcodec->dapm_widgets = gbcodec->widgets;
-       soc_codec_dev_gbcodec->num_dapm_widgets = gbcodec->num_dapm_widgets;
-       soc_codec_dev_gbcodec->dapm_routes = gbcodec->routes;
-       soc_codec_dev_gbcodec->num_dapm_routes = gbcodec->num_dapm_routes;
-
-       /* update DAI info */
-       for (i = 0; i < gbcodec->num_dais; i++)
-               gbcodec->dais[i].ops = &gbcodec_dai_ops;
-
-       /* register codec */
-       ret = snd_soc_register_codec(dev, soc_codec_dev_gbcodec,
-                                    gbcodec->dais, 1);
-       if (ret) {
-               dev_err(dev, "%d:Failed to register codec\n", ret);
-               goto codec_reg_err;
+       module->is_connected = 0;
+       if (module->dapm_routes) {
+               dev_dbg(codec->dev, "Removing %d routes\n",
+                       module->num_dapm_routes);
+               snd_soc_dapm_del_routes(&codec->dapm, module->dapm_routes,
+                                       module->num_dapm_routes);
        }
-
-       /* update DAI links in response to this codec */
-       ret = msm8994_add_dailink("msm8994-tomtom-mtp-snd-card", gbcodec->name,
-                                 gbcodec->dais[0].name, 1);
-       if (ret) {
-               dev_err(dev, "%d: Failed to add DAI links\n", ret);
-               goto add_dailink_err;
+       if (module->controls) {
+               dev_dbg(codec->dev, "Removing %d controls\n",
+                       module->num_controls);
+               soc_remove_codec_controls(codec, module->controls,
+                                         module->num_controls);
+       }
+       if (module->dapm_widgets) {
+               dev_dbg(codec->dev, "Removing %d widgets\n",
+                       module->num_dapm_widgets);
+               snd_soc_dapm_free_controls(&codec->dapm, module->dapm_widgets,
+                                          module->num_dapm_widgets);
        }
-       gbcodec->num_dai_links = 1;
 
-       return 0;
+       mutex_unlock(&module->lock);
 
-add_dailink_err:
-       snd_soc_unregister_codec(dev);
-codec_reg_err:
-       gbaudio_tplg_release(gbcodec);
-       gbcodec->topology = NULL;
-tplg_parse_err:
-       kfree(topology);
-tplg_fetch_err:
-       gb_connection_disable(gbcodec->mgmt_connection);
-       return ret;
-}
+       list_del(&module->list);
+       dev_dbg(codec->dev, "Unregistered %s module\n", module->name);
 
-static void gbaudio_unregister_codec(struct gbaudio_codec_info *gbcodec)
-{
-       gb_audio_cleanup(gbcodec);
-       msm8994_remove_dailink("msm8994-tomtom-mtp-snd-card", gbcodec->name,
-                              gbcodec->dais[0].name, 1);
-       snd_soc_unregister_codec(gbcodec->dev);
-       gbaudio_tplg_release(gbcodec);
-       kfree(gbcodec->topology);
-       gb_connection_disable(gbcodec->mgmt_connection);
+       mutex_unlock(&gbcodec->lock);
+       up_write(&card->controls_rwsem);
 }
+EXPORT_SYMBOL(gbaudio_unregister_module);
 
-static int gbaudio_codec_request_handler(struct gb_operation *op)
+/*
+ * codec driver ops
+ */
+static int gbcodec_probe(struct snd_soc_codec *codec)
 {
-       struct gb_connection *connection = op->connection;
-       struct gb_audio_streaming_event_request *req = op->request->payload;
+       struct gbaudio_codec_info *info;
+
+       info = devm_kzalloc(codec->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
 
-       dev_warn(&connection->bundle->dev,
-                "Audio Event received: cport: %u, event: %u\n",
-                req->data_cport, req->event);
+       info->dev = codec->dev;
+       INIT_LIST_HEAD(&info->module_list);
+       mutex_init(&info->lock);
+       info->codec = codec;
+       snd_soc_codec_set_drvdata(codec, info);
+       gbcodec = info;
 
+       /* Empty function for now */
        return 0;
 }
 
-static int gbaudio_dai_request_handler(struct gb_operation *op)
+static int gbcodec_remove(struct snd_soc_codec *codec)
 {
-       struct gb_connection *connection = op->connection;
-
-       dev_warn(&connection->bundle->dev, "Audio Event received\n");
-
+       /* Empty function for now */
        return 0;
 }
 
-static int gb_audio_add_mgmt_connection(struct gbaudio_codec_info *gbcodec,
-                               struct greybus_descriptor_cport *cport_desc,
-                               struct gb_bundle *bundle)
+static u8 gbcodec_reg[GBCODEC_REG_COUNT] = {
+       [GBCODEC_CTL_REG] = GBCODEC_CTL_REG_DEFAULT,
+       [GBCODEC_MUTE_REG] = GBCODEC_MUTE_REG_DEFAULT,
+       [GBCODEC_PB_LVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
+       [GBCODEC_PB_RVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
+       [GBCODEC_CAP_LVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
+       [GBCODEC_CAP_RVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
+       [GBCODEC_APB1_MUX_REG] = GBCODEC_APB1_MUX_REG_DEFAULT,
+       [GBCODEC_APB2_MUX_REG] = GBCODEC_APB2_MUX_REG_DEFAULT,
+};
+
+static int gbcodec_write(struct snd_soc_codec *codec, unsigned int reg,
+                        unsigned int value)
 {
-       struct gb_connection *connection;
+       int ret = 0;
 
-       /* Management Cport */
-       if (gbcodec->mgmt_connection) {
-               dev_err(&bundle->dev,
-                       "Can't have multiple Management connections\n");
-               return -ENODEV;
-       }
+       if (reg == SND_SOC_NOPM)
+               return 0;
 
-       connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
-                                         gbaudio_codec_request_handler);
-       if (IS_ERR(connection))
-               return PTR_ERR(connection);
+       BUG_ON(reg >= GBCODEC_REG_COUNT);
+               return 0;
 
-       gb_connection_set_data(connection, gbcodec);
-       gbcodec->mgmt_connection = connection;
+       gbcodec_reg[reg] = value;
+       dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, value);
 
-       return 0;
+       return ret;
 }
 
-static int gb_audio_add_data_connection(struct gbaudio_codec_info *gbcodec,
-                               struct greybus_descriptor_cport *cport_desc,
-                               struct gb_bundle *bundle)
+static unsigned int gbcodec_read(struct snd_soc_codec *codec,
+                                unsigned int reg)
 {
-       struct gb_connection *connection;
-       struct gbaudio_dai *dai;
+       unsigned int val = 0;
 
-       dai = devm_kzalloc(gbcodec->dev, sizeof(*dai), GFP_KERNEL);
-       if (!dai) {
-               dev_err(gbcodec->dev, "DAI Malloc failure\n");
-               return -ENOMEM;
-       }
+       if (reg == SND_SOC_NOPM)
+               return 0;
 
-       connection = gb_connection_create_flags(bundle,
-                                               le16_to_cpu(cport_desc->id),
-                                               gbaudio_dai_request_handler,
-                                               GB_CONNECTION_FLAG_CSD);
-       if (IS_ERR(connection)) {
-               devm_kfree(gbcodec->dev, dai);
-               return PTR_ERR(connection);
-       }
+       BUG_ON(reg >= GBCODEC_REG_COUNT);
 
-       gb_connection_set_data(connection, gbcodec);
-       atomic_set(&dai->users, 0);
-       init_waitqueue_head(&dai->wait_queue);
-       dai->data_cport = connection->intf_cport_id;
-       dai->connection = connection;
-       list_add(&dai->list, &gbcodec->dai_list);
+       val = gbcodec_reg[reg];
+       dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, val);
 
-       return 0;
+       return val;
 }
-/*
- * This is the basic hook get things initialized and registered w/ gb
- */
 
-static int gb_audio_probe(struct gb_bundle *bundle,
-                         const struct greybus_bundle_id *id)
-{
-       struct device *dev = &bundle->dev;
-       struct gbaudio_codec_info *gbcodec;
-       struct greybus_descriptor_cport *cport_desc;
-       struct gb_audio_manager_module_descriptor desc;
-       struct gbaudio_dai *dai, *_dai;
-       int ret, i;
-
-       /* There should be at least one Management and one Data cport */
-       if (bundle->num_cports < 2)
-               return -ENODEV;
+static struct snd_soc_dai_driver gbaudio_dai[] = {
+       {
+               .name = "greybus-apb1",
+               .id = 0,
+               .playback = {
+                       .stream_name = "GB Audio Playback",
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FORMAT_S16_LE,
+                       .rate_max = 48000,
+                       .rate_min = 48000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .capture = {
+                       .stream_name = "GB Audio Capture",
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FORMAT_S16_LE,
+                       .rate_max = 48000,
+                       .rate_min = 48000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &gbcodec_dai_ops,
+       },
+};
 
-       mutex_lock(&gb_codec_list_lock);
-       /*
-        * There can be only one Management connection and any number of data
-        * connections.
-        */
-       gbcodec = devm_kzalloc(dev, sizeof(*gbcodec), GFP_KERNEL);
-       if (!gbcodec) {
-               mutex_unlock(&gb_codec_list_lock);
-               return -ENOMEM;
-       }
+static struct snd_soc_codec_driver soc_codec_dev_gbaudio = {
+       .probe  = gbcodec_probe,
+       .remove = gbcodec_remove,
 
-       gbcodec->num_data_connections = bundle->num_cports - 1;
-       mutex_init(&gbcodec->lock);
-       INIT_LIST_HEAD(&gbcodec->dai_list);
-       INIT_LIST_HEAD(&gbcodec->widget_list);
-       INIT_LIST_HEAD(&gbcodec->codec_ctl_list);
-       INIT_LIST_HEAD(&gbcodec->widget_ctl_list);
-       gbcodec->dev = dev;
-       snprintf(gbcodec->name, NAME_SIZE, "%s.%s", dev->driver->name,
-                dev_name(dev));
-       greybus_set_drvdata(bundle, gbcodec);
-
-       /* Create all connections */
-       for (i = 0; i < bundle->num_cports; i++) {
-               cport_desc = &bundle->cport_desc[i];
-
-               switch (cport_desc->protocol_id) {
-               case GREYBUS_PROTOCOL_AUDIO_MGMT:
-                       ret = gb_audio_add_mgmt_connection(gbcodec, cport_desc,
-                                                          bundle);
-                       if (ret)
-                               goto destroy_connections;
-                       break;
-               case GREYBUS_PROTOCOL_AUDIO_DATA:
-                       ret = gb_audio_add_data_connection(gbcodec, cport_desc,
-                                                          bundle);
-                       if (ret)
-                               goto destroy_connections;
-                       break;
-               default:
-                       dev_err(dev, "Unsupported protocol: 0x%02x\n",
-                               cport_desc->protocol_id);
-                       ret = -ENODEV;
-                       goto destroy_connections;
-               }
-       }
+       .read = gbcodec_read,
+       .write = gbcodec_write,
 
-       /* There must be a management cport */
-       if (!gbcodec->mgmt_connection) {
-               ret = -EINVAL;
-               dev_err(dev, "Missing management connection\n");
-               goto destroy_connections;
-       }
+       .reg_cache_size = GBCODEC_REG_COUNT,
+       .reg_cache_default = gbcodec_reg_defaults,
+       .reg_word_size = 1,
 
-       /* Initialize management connection */
-       ret = gbaudio_register_codec(gbcodec);
-       if (ret)
-               goto destroy_connections;
-
-       /* Initialize data connections */
-       list_for_each_entry(dai, &gbcodec->dai_list, list) {
-               ret = gb_connection_enable(dai->connection);
-               if (ret)
-                       goto remove_dai;
-       }
-
-       /* inform above layer for uevent */
-       dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
-       /* prepare for the audio manager */
-       strlcpy(desc.name, gbcodec->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN);
-       desc.slot = 1; /* todo */
-       desc.vid = 2; /* todo */
-       desc.pid = 3; /* todo */
-       desc.cport = gbcodec->dev_id;
-       desc.devices = 0x2; /* todo */
-       gbcodec->manager_id = gb_audio_manager_add(&desc);
+       .idle_bias_off = true,
+       .ignore_pmdown_time = 1,
+};
 
-       atomic_set(&gbcodec->is_connected, 1);
-       list_add_tail(&gbcodec->list, &gb_codec_list);
-       dev_dbg(dev, "Add GB Audio device:%s\n", gbcodec->name);
-       mutex_unlock(&gb_codec_list_lock);
 
+#ifdef CONFIG_PM
+static int gbaudio_codec_suspend(struct device *dev)
+{
+       dev_dbg(dev, "%s: suspend\n", __func__);
        return 0;
-
-remove_dai:
-       list_for_each_entry_safe(dai, _dai, &gbcodec->dai_list, list)
-               gb_connection_disable(dai->connection);
-
-       gbaudio_unregister_codec(gbcodec);
-destroy_connections:
-       list_for_each_entry_safe(dai, _dai, &gbcodec->dai_list, list) {
-               gb_connection_destroy(dai->connection);
-               list_del(&dai->list);
-               devm_kfree(dev, dai);
-       }
-
-       if (gbcodec->mgmt_connection)
-               gb_connection_destroy(gbcodec->mgmt_connection);
-
-       devm_kfree(dev, gbcodec);
-       mutex_unlock(&gb_codec_list_lock);
-
-       return ret;
 }
 
-static void gb_audio_disconnect(struct gb_bundle *bundle)
+static int gbaudio_codec_resume(struct device *dev)
 {
-       struct gbaudio_codec_info *gbcodec = greybus_get_drvdata(bundle);
-       struct gbaudio_dai *dai, *_dai;
+       dev_dbg(dev, "%s: resume\n", __func__);
+       return 0;
+}
 
-       mutex_lock(&gb_codec_list_lock);
-       atomic_set(&gbcodec->is_connected, 0);
-       /* inform uevent to above layers */
-       gb_audio_manager_remove(gbcodec->manager_id);
+static const struct dev_pm_ops gbaudio_codec_pm_ops = {
+       .suspend        = gbaudio_codec_suspend,
+       .resume         = gbaudio_codec_resume,
+};
+#endif
 
-       mutex_lock(&gbcodec->lock);
-       list_for_each_entry_safe(dai, _dai, &gbcodec->dai_list, list)
-               gb_connection_disable(dai->connection);
-       gbaudio_unregister_codec(gbcodec);
-
-       list_for_each_entry_safe(dai, _dai, &gbcodec->dai_list, list) {
-               gb_connection_destroy(dai->connection);
-               list_del(&dai->list);
-               devm_kfree(gbcodec->dev, dai);
-       }
-       gb_connection_destroy(gbcodec->mgmt_connection);
-       gbcodec->mgmt_connection = NULL;
-       list_del(&gbcodec->list);
-       mutex_unlock(&gbcodec->lock);
+static int gbaudio_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_gbaudio,
+                       gbaudio_dai, ARRAY_SIZE(gbaudio_dai));
+}
 
-       devm_kfree(&bundle->dev, gbcodec);
-       mutex_unlock(&gb_codec_list_lock);
+static int gbaudio_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
 }
 
-static const struct greybus_bundle_id gb_audio_id_table[] = {
-       { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
-       { }
+static const struct of_device_id greybus_asoc_machine_of_match[]  = {
+       { .compatible = "qcom,ara-codec", },
+       {},
 };
-MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
 
-static struct greybus_driver gb_audio_driver = {
-       .name           = "gb-audio",
-       .probe          = gb_audio_probe,
-       .disconnect     = gb_audio_disconnect,
-       .id_table       = gb_audio_id_table,
+static struct platform_driver gbaudio_codec_driver = {
+       .driver = {
+               .name = "gb-codec",
+               .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &gbaudio_codec_pm_ops,
+#endif
+               .of_match_table = greybus_asoc_machine_of_match,
+       },
+       .probe = gbaudio_codec_probe,
+       .remove = gbaudio_codec_remove,
 };
-module_greybus_driver(gb_audio_driver);
+module_platform_driver(gbaudio_codec_driver);
 
-MODULE_DESCRIPTION("Greybus Audio codec driver");
+MODULE_DESCRIPTION("Greybus codec driver");
 MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:gbaudio-codec");
index 9197adcbc32ecc01fb9b0d15f5d2b5fa48771396..a2697dd629490204742bfb8ee3a5dd4c8ce529df 100644 (file)
@@ -68,6 +68,31 @@ static const u8 gbcodec_reg_defaults[GBCODEC_REG_COUNT] = {
        GBCODEC_APB2_MUX_REG_DEFAULT,
 };
 
+enum gbaudio_codec_state {
+       GBAUDIO_CODEC_SHUTDOWN = 0,
+       GBAUDIO_CODEC_STARTUP,
+       GBAUDIO_CODEC_HWPARAMS,
+       GBAUDIO_CODEC_PREPARE,
+       GBAUDIO_CODEC_START,
+       GBAUDIO_CODEC_STOP,
+};
+
+struct gbaudio_stream {
+       const char *dai_name;
+       int state;
+       uint8_t sig_bits, channels;
+       uint32_t format, rate;
+};
+
+struct gbaudio_codec_info {
+       struct device *dev;
+       struct snd_soc_codec *codec;
+       struct list_head module_list;
+       struct gbaudio_stream stream[2];        /* PB/CAP */
+       struct mutex lock;
+       u8 reg[GBCODEC_REG_COUNT];
+};
+
 struct gbaudio_widget {
        __u8 id;
        const char *name;
@@ -81,81 +106,80 @@ struct gbaudio_control {
        struct list_head list;
 };
 
-struct gbaudio_dai {
+struct gbaudio_data_connection {
        __le16 data_cport;
+       int cport_configured;
        char name[NAME_SIZE];
-       /* DAI users */
-       atomic_t users;
        struct gb_connection *connection;
        struct list_head list;
-       wait_queue_head_t wait_queue;
 };
 
-struct gbaudio_codec_info {
+/* stream direction */
+#define GB_PLAYBACK    BIT(0)
+#define GB_CAPTURE     BIT(1)
+
+enum gbaudio_module_state {
+       GBAUDIO_MODULE_OFF = 0,
+       GBAUDIO_MODULE_ON,
+};
+
+struct gbaudio_module_info {
        /* module info */
+       struct device *dev;
        int dev_id;     /* check if it should be bundle_id/hd_cport_id */
        int vid;
        int pid;
        int slot;
        int type;
-       int dai_added;
-       int codec_registered;
        int set_uevent;
        char vstr[NAME_SIZE];
        char pstr[NAME_SIZE];
        struct list_head list;
-       struct gb_audio_topology *topology;
        /* need to share this info to above user space */
        int manager_id;
        char name[NAME_SIZE];
 
-       /*
-        * there can be a rece condition between gb_audio_disconnect()
-        * and dai->trigger from above ASoC layer.
-        * To avoid any deadlock over codec_info->lock, atomic variable
-        * is used.
-        */
-       atomic_t is_connected;
+       /* used by codec_ops */
        struct mutex lock;
+       int is_connected;
+       int ctrlstate[2];       /* PB/CAP */
 
-       /* soc related data */
-       struct snd_soc_codec *codec;
-       struct device *dev;
-       u8 reg[GBCODEC_REG_COUNT];
-
-       /* dai_link related */
-       char card_name[NAME_SIZE];
-       char *dailink_name[MAX_DAIS];
-       int num_dai_links;
-
+       /* connection info */
        struct gb_connection *mgmt_connection;
        size_t num_data_connections;
+       struct list_head data_list;
+
        /* topology related */
        int num_dais;
-       int num_kcontrols;
+       int num_controls;
        int num_dapm_widgets;
        int num_dapm_routes;
        unsigned long dai_offset;
        unsigned long widget_offset;
        unsigned long control_offset;
        unsigned long route_offset;
-       struct snd_kcontrol_new *kctls;
-       struct snd_soc_dapm_widget *widgets;
-       struct snd_soc_dapm_route *routes;
+       struct snd_kcontrol_new *controls;
+       struct snd_soc_dapm_widget *dapm_widgets;
+       struct snd_soc_dapm_route *dapm_routes;
        struct snd_soc_dai_driver *dais;
 
-       /* lists */
-       struct list_head dai_list;
        struct list_head widget_list;
-       struct list_head codec_ctl_list;
+       struct list_head ctl_list;
        struct list_head widget_ctl_list;
+
+       struct gb_audio_topology *topology;
 };
 
-struct gbaudio_dai *gbaudio_find_dai(struct gbaudio_codec_info *gbcodec,
-                                    int data_cport, const char *name);
-int gbaudio_tplg_parse_data(struct gbaudio_codec_info *gbcodec,
+int gbaudio_tplg_parse_data(struct gbaudio_module_info *module,
                               struct gb_audio_topology *tplg_data);
-void gbaudio_tplg_release(struct gbaudio_codec_info *gbcodec);
+void gbaudio_tplg_release(struct gbaudio_module_info *module);
+
+int gbaudio_module_update(struct gbaudio_codec_info *codec,
+                                const char *w_name,
+                                struct gbaudio_module_info *module,
+                                int enable);
+int gbaudio_register_module(struct gbaudio_module_info *module);
+void gbaudio_unregister_module(struct gbaudio_module_info *module);
 
 /* protocol related */
 extern int gb_audio_gb_get_topology(struct gb_connection *connection,
index 1651c14c87ba95aab70b6a9b4da61abc207c9027..4901348a2ada12e299c84f9eb93b06de783ed4a4 100644 (file)
@@ -25,7 +25,32 @@ struct gbaudio_ctl_pvt {
        struct gb_audio_ctl_elem_info *info;
 };
 
-static const char *gbaudio_map_controlid(struct gbaudio_codec_info *gbcodec,
+static struct gbaudio_module_info *find_gb_module(
+                                       struct gbaudio_codec_info *codec,
+                                       char const *name)
+{
+       int dev_id, ret;
+       char begin[NAME_SIZE];
+       struct gbaudio_module_info *module;
+
+       if (!name)
+               return NULL;
+
+       ret = sscanf(name, "%s %d", begin, &dev_id);
+       dev_dbg(codec->dev, "%s:Find module#%d\n", __func__, dev_id);
+
+       mutex_lock(&codec->lock);
+       list_for_each_entry(module, &codec->module_list, list) {
+               if (module->dev_id == dev_id) {
+                       mutex_unlock(&codec->lock);
+                       return module;
+               }
+       }
+       mutex_unlock(&codec->lock);
+       return NULL;
+}
+
+static const char *gbaudio_map_controlid(struct gbaudio_module_info *module,
                                           __u8 control_id, __u8 index)
 {
        struct gbaudio_control *control;
@@ -33,14 +58,14 @@ static const char *gbaudio_map_controlid(struct gbaudio_codec_info *gbcodec,
        if (control_id == GBAUDIO_INVALID_ID)
                return NULL;
 
-       list_for_each_entry(control, &gbcodec->codec_ctl_list, list) {
+       list_for_each_entry(control, &module->ctl_list, list) {
                if (control->id == control_id) {
                        if (index == GBAUDIO_INVALID_ID)
                                return control->name;
                        return control->texts[index];
                }
        }
-       list_for_each_entry(control, &gbcodec->widget_ctl_list, list) {
+       list_for_each_entry(control, &module->widget_ctl_list, list) {
                if (control->id == control_id) {
                        if (index == GBAUDIO_INVALID_ID)
                                return control->name;
@@ -50,34 +75,23 @@ static const char *gbaudio_map_controlid(struct gbaudio_codec_info *gbcodec,
        return NULL;
 }
 
-static int gbaudio_map_widgetname(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_map_widgetname(struct gbaudio_module_info *module,
                                          const char *name)
 {
        struct gbaudio_widget *widget;
-       char widget_name[NAME_SIZE];
-       char prefix_name[NAME_SIZE];
-
-       snprintf(prefix_name, NAME_SIZE, "GB %d ", gbcodec->dev_id);
-       if (strncmp(name, prefix_name, strlen(prefix_name)))
-               return -EINVAL;
-
-       strlcpy(widget_name, name+strlen(prefix_name), NAME_SIZE);
-       dev_dbg(gbcodec->dev, "widget_name:%s, truncated widget_name:%s\n",
-               name, widget_name);
-
-       list_for_each_entry(widget, &gbcodec->widget_list, list) {
-               if (!strncmp(widget->name, widget_name, NAME_SIZE))
+       list_for_each_entry(widget, &module->widget_list, list) {
+               if (!strncmp(widget->name, name, NAME_SIZE))
                        return widget->id;
        }
        return -EINVAL;
 }
 
-static const char *gbaudio_map_widgetid(struct gbaudio_codec_info *gbcodec,
+static const char *gbaudio_map_widgetid(struct gbaudio_module_info *module,
                                          __u8 widget_id)
 {
        struct gbaudio_widget *widget;
 
-       list_for_each_entry(widget, &gbcodec->widget_list, list) {
+       list_for_each_entry(widget, &module->widget_list, list) {
                if (widget->id == widget_id)
                        return widget->name;
        }
@@ -91,14 +105,16 @@ static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
        const char *name;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_info *info;
+       struct gbaudio_module_info *module;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
 
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
 
        if (!info) {
-               dev_err(gbcodec->dev, "NULL info for %s\n", uinfo->id.name);
+               dev_err(module->dev, "NULL info for %s\n", uinfo->id.name);
                return -EINVAL;
        }
 
@@ -118,7 +134,10 @@ static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
                uinfo->value.enumerated.items = max;
                if (uinfo->value.enumerated.item > max - 1)
                        uinfo->value.enumerated.item = max - 1;
-               name = gbaudio_map_controlid(gbcodec, data->ctl_id,
+               module = find_gb_module(gbcodec, kcontrol->id.name);
+               if (!module)
+                       return -EINVAL;
+               name = gbaudio_map_controlid(module, data->ctl_id,
                                             uinfo->value.enumerated.item);
                strlcpy(uinfo->value.enumerated.name, name, NAME_SIZE);
                break;
@@ -137,16 +156,19 @@ static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol,
        struct gb_audio_ctl_elem_info *info;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_value gbvalue;
+       struct gbaudio_module_info *module;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
+       module = find_gb_module(gb, kcontrol->id.name);
+       if (!module)
+               return -EINVAL;
 
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
 
-       ret = gb_audio_gb_get_control(gb->mgmt_connection, data->ctl_id,
+       ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
                                      GB_AUDIO_INVALID_INDEX, &gbvalue);
        if (ret) {
                dev_err(codec->dev, "%d:Error in %s for %s\n", ret, __func__,
@@ -187,11 +209,14 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
        struct gb_audio_ctl_elem_info *info;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_value gbvalue;
+       struct gbaudio_module_info *module;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
+       module = find_gb_module(gb, kcontrol->id.name);
+       if (!module)
+               return -EINVAL;
 
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
@@ -223,7 +248,7 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
        if (ret)
                return ret;
 
-       ret = gb_audio_gb_set_control(gb->mgmt_connection, data->ctl_id,
+       ret = gb_audio_gb_set_control(module->mgmt_connection, data->ctl_id,
                                      GB_AUDIO_INVALID_INDEX, &gbvalue);
        if (ret) {
                dev_err(codec->dev, "%d:Error in %s for %s\n", ret, __func__,
@@ -250,7 +275,11 @@ static int gbcodec_mixer_dapm_ctl_info(struct snd_kcontrol *kcontrol,
        int platform_max, platform_min;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_info *info;
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
 
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
 
@@ -282,13 +311,16 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
        struct gb_audio_ctl_elem_info *info;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_value gbvalue;
+       struct gbaudio_module_info *module;
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
        struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
+       module = find_gb_module(gb, kcontrol->id.name);
+       if (!module)
+               return -EINVAL;
 
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
@@ -298,7 +330,7 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
                         "GB: Control '%s' is stereo, which is not supported\n",
                         kcontrol->id.name);
 
-       ret = gb_audio_gb_get_control(gb->mgmt_connection, data->ctl_id,
+       ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
                                      GB_AUDIO_INVALID_INDEX, &gbvalue);
        if (ret) {
                dev_err(codec->dev, "%d:Error in %s for %s\n", ret, __func__,
@@ -319,13 +351,16 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
        struct gb_audio_ctl_elem_info *info;
        struct gbaudio_ctl_pvt *data;
        struct gb_audio_ctl_elem_value gbvalue;
+       struct gbaudio_module_info *module;
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
        struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
 
-       if (!atomic_read(&gb->is_connected))
-               return -ENODEV;
+       dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
+       module = find_gb_module(gb, kcontrol->id.name);
+       if (!module)
+               return -EINVAL;
 
        data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
        info = (struct gb_audio_ctl_elem_info *)data->info;
@@ -352,7 +387,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
                }
                gbvalue.value.integer_value[0] =
                        ucontrol->value.integer.value[0];
-               ret = gb_audio_gb_set_control(gb->mgmt_connection,
+               ret = gb_audio_gb_set_control(module->mgmt_connection,
                                              data->ctl_id,
                                              GB_AUDIO_INVALID_INDEX, &gbvalue);
                if (ret) {
@@ -420,7 +455,7 @@ static int gbaudio_validate_kcontrol_count(struct gb_audio_widget *w)
        return ret;
 }
 
-static int gbaudio_tplg_create_kcontrol(struct gbaudio_codec_info *gb,
+static int gbaudio_tplg_create_kcontrol(struct gbaudio_module_info *gb,
                                        struct snd_kcontrol_new *kctl,
                                        struct gb_audio_control *ctl)
 {
@@ -452,23 +487,23 @@ static int gbaudio_tplg_create_kcontrol(struct gbaudio_codec_info *gb,
 static const char * const gbtexts[] = {"Stereo", "Left", "Right"};
 
 static const SOC_ENUM_SINGLE_DECL(
-       gbcodec_apb1_rx_enum, GBCODEC_APB1_MUX_REG, 0, gbtexts);
+       module_apb1_rx_enum, GBCODEC_APB1_MUX_REG, 0, gbtexts);
 
 static const SOC_ENUM_SINGLE_DECL(
-       gbcodec_mic_enum, GBCODEC_APB1_MUX_REG, 4, gbtexts);
+       module_mic_enum, GBCODEC_APB1_MUX_REG, 4, gbtexts);
 
-static int gbaudio_tplg_create_enum_ctl(struct gbaudio_codec_info *gb,
+static int gbaudio_tplg_create_enum_ctl(struct gbaudio_module_info *gb,
                                        struct snd_kcontrol_new *kctl,
                                        struct gb_audio_control *ctl)
 {
        switch (ctl->id) {
        case 8:
                *kctl = (struct snd_kcontrol_new)
-                       SOC_DAPM_ENUM(ctl->name, gbcodec_apb1_rx_enum);
+                       SOC_DAPM_ENUM(ctl->name, module_apb1_rx_enum);
                break;
        case 9:
                *kctl = (struct snd_kcontrol_new)
-                       SOC_DAPM_ENUM(ctl->name, gbcodec_mic_enum);
+                       SOC_DAPM_ENUM(ctl->name, module_mic_enum);
                break;
        default:
                return -EINVAL;
@@ -477,7 +512,7 @@ static int gbaudio_tplg_create_enum_ctl(struct gbaudio_codec_info *gb,
        return 0;
 }
 
-static int gbaudio_tplg_create_mixer_ctl(struct gbaudio_codec_info *gb,
+static int gbaudio_tplg_create_mixer_ctl(struct gbaudio_module_info *gb,
                                             struct snd_kcontrol_new *kctl,
                                             struct gb_audio_control *ctl)
 {
@@ -498,7 +533,7 @@ static int gbaudio_tplg_create_mixer_ctl(struct gbaudio_codec_info *gb,
        return 0;
 }
 
-static int gbaudio_tplg_create_wcontrol(struct gbaudio_codec_info *gb,
+static int gbaudio_tplg_create_wcontrol(struct gbaudio_module_info *gb,
                                             struct snd_kcontrol_new *kctl,
                                             struct gb_audio_control *ctl)
 {
@@ -532,11 +567,17 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
        int ret;
        struct snd_soc_codec *codec = w->codec;
        struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
+       struct gbaudio_module_info *module;
 
        dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
+       /* Find relevant module */
+       module = find_gb_module(gbcodec, w->name);
+       if (!module)
+               return -EINVAL;
+
        /* map name to widget id */
-       wid = gbaudio_map_widgetname(gbcodec, w->name);
+       wid = gbaudio_map_widgetname(module, w->name);
        if (wid < 0) {
                dev_err(codec->dev, "Invalid widget name:%s\n", w->name);
                return -EINVAL;
@@ -544,10 +585,16 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               ret = gb_audio_gb_enable_widget(gbcodec->mgmt_connection, wid);
+               ret = gb_audio_gb_enable_widget(module->mgmt_connection, wid);
+               if (!ret)
+                       ret = gbaudio_module_update(gbcodec, w->name, module,
+                                                   1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               ret = gb_audio_gb_disable_widget(gbcodec->mgmt_connection, wid);
+               ret = gb_audio_gb_disable_widget(module->mgmt_connection, wid);
+               if (!ret)
+                       ret = gbaudio_module_update(gbcodec, w->name, module,
+                                                   0);
                break;
        }
        if (ret)
@@ -556,7 +603,7 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
        return ret;
 }
 
-static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_tplg_create_widget(struct gbaudio_module_info *module,
                                      struct snd_soc_dapm_widget *dw,
                                      struct gb_audio_widget *w)
 {
@@ -565,10 +612,11 @@ static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
        struct gb_audio_control *curr;
        struct gbaudio_control *control, *_control;
        size_t size;
+       char temp_name[NAME_SIZE];
 
        ret = gbaudio_validate_kcontrol_count(w);
        if (ret) {
-               dev_err(gbcodec->dev, "Inavlid kcontrol count=%d for %s\n",
+               dev_err(module->dev, "Inavlid kcontrol count=%d for %s\n",
                        w->ncontrols, w->name);
                return ret;
        }
@@ -576,7 +624,7 @@ static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
        /* allocate memory for kcontrol */
        if (w->ncontrols) {
                size = sizeof(struct snd_kcontrol_new) * w->ncontrols;
-               widget_kctls = devm_kzalloc(gbcodec->dev, size, GFP_KERNEL);
+               widget_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL);
                if (!widget_kctls)
                        return -ENOMEM;
        }
@@ -584,15 +632,15 @@ static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
        /* create relevant kcontrols */
        for (i = 0; i < w->ncontrols; i++) {
                curr = &w->ctl[i];
-               ret = gbaudio_tplg_create_wcontrol(gbcodec, &widget_kctls[i],
+               ret = gbaudio_tplg_create_wcontrol(module, &widget_kctls[i],
                                                   curr);
                if (ret) {
-                       dev_err(gbcodec->dev,
+                       dev_err(module->dev,
                                "%s:%d type widget_ctl not supported\n",
                                curr->name, curr->iface);
                        goto error;
                }
-               control = devm_kzalloc(gbcodec->dev,
+               control = devm_kzalloc(module->dev,
                                       sizeof(struct gbaudio_control),
                                       GFP_KERNEL);
                if (!control) {
@@ -604,11 +652,15 @@ static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
                if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED)
                        control->texts = (const char * const *)
                                curr->info.value.enumerated.names;
-               list_add(&control->list, &gbcodec->widget_ctl_list);
-               dev_dbg(gbcodec->dev, "%s: control of type %d created\n",
+               list_add(&control->list, &module->widget_ctl_list);
+               dev_dbg(module->dev, "%s: control of type %d created\n",
                        widget_kctls[i].name, widget_kctls[i].iface);
        }
 
+       /* Prefix dev_id to widget control_name */
+       strlcpy(temp_name, w->name, NAME_SIZE);
+       snprintf(w->name, NAME_SIZE, "GB %d %s", module->dev_id, temp_name);
+
        switch (w->type) {
        case snd_soc_dapm_spk:
                *dw = (struct snd_soc_dapm_widget)
@@ -677,45 +729,19 @@ static int gbaudio_tplg_create_widget(struct gbaudio_codec_info *gbcodec,
                goto error;
        }
 
-       dev_dbg(gbcodec->dev, "%s: widget of type %d created\n", dw->name,
+       dev_dbg(module->dev, "%s: widget of type %d created\n", dw->name,
                dw->id);
        return 0;
 error:
-       list_for_each_entry_safe(control, _control, &gbcodec->widget_ctl_list,
+       list_for_each_entry_safe(control, _control, &module->widget_ctl_list,
                                 list) {
                list_del(&control->list);
-               devm_kfree(gbcodec->dev, control);
+               devm_kfree(module->dev, control);
        }
        return ret;
 }
 
-static int gbaudio_tplg_create_dai(struct gbaudio_codec_info *gbcodec,
-                                  struct snd_soc_dai_driver *gb_dai,
-                                  struct gb_audio_dai *dai)
-{
-       /*
-        * do not update name here,
-        * append dev_id before assigning it here
-        */
-
-       gb_dai->playback.stream_name = dai->playback.stream_name;
-       gb_dai->playback.channels_min = dai->playback.chan_min;
-       gb_dai->playback.channels_max = dai->playback.chan_max;
-       gb_dai->playback.formats = dai->playback.formats;
-       gb_dai->playback.rates = dai->playback.rates;
-       gb_dai->playback.sig_bits = dai->playback.sig_bits;
-
-       gb_dai->capture.stream_name = dai->capture.stream_name;
-       gb_dai->capture.channels_min = dai->capture.chan_min;
-       gb_dai->capture.channels_max = dai->capture.chan_max;
-       gb_dai->capture.formats = dai->capture.formats;
-       gb_dai->capture.rates = dai->capture.rates;
-       gb_dai->capture.sig_bits = dai->capture.sig_bits;
-
-       return 0;
-}
-
-static int gbaudio_tplg_process_kcontrols(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_tplg_process_kcontrols(struct gbaudio_module_info *module,
                                   struct gb_audio_control *controls)
 {
        int i, ret;
@@ -723,22 +749,23 @@ static int gbaudio_tplg_process_kcontrols(struct gbaudio_codec_info *gbcodec,
        struct gb_audio_control *curr;
        struct gbaudio_control *control, *_control;
        size_t size;
+       char temp_name[NAME_SIZE];
 
-       size = sizeof(struct snd_kcontrol_new) * gbcodec->num_kcontrols;
-       dapm_kctls = devm_kzalloc(gbcodec->dev, size, GFP_KERNEL);
+       size = sizeof(struct snd_kcontrol_new) * module->num_controls;
+       dapm_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL);
        if (!dapm_kctls)
                return -ENOMEM;
 
        curr = controls;
-       for (i = 0; i < gbcodec->num_kcontrols; i++) {
-               ret = gbaudio_tplg_create_kcontrol(gbcodec, &dapm_kctls[i],
+       for (i = 0; i < module->num_controls; i++) {
+               ret = gbaudio_tplg_create_kcontrol(module, &dapm_kctls[i],
                                                   curr);
                if (ret) {
-                       dev_err(gbcodec->dev, "%s:%d type not supported\n",
+                       dev_err(module->dev, "%s:%d type not supported\n",
                                curr->name, curr->iface);
                        goto error;
                }
-               control = devm_kzalloc(gbcodec->dev, sizeof(struct
+               control = devm_kzalloc(module->dev, sizeof(struct
                                                           gbaudio_control),
                                      GFP_KERNEL);
                if (!control) {
@@ -746,29 +773,33 @@ static int gbaudio_tplg_process_kcontrols(struct gbaudio_codec_info *gbcodec,
                        goto error;
                }
                control->id = curr->id;
+               /* Prefix dev_id to widget_name */
+               strlcpy(temp_name, curr->name, NAME_SIZE);
+               snprintf(curr->name, NAME_SIZE, "GB %d %s", module->dev_id,
+                        temp_name);
                control->name = curr->name;
                if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED)
                        control->texts = (const char * const *)
                                curr->info.value.enumerated.names;
-               list_add(&control->list, &gbcodec->codec_ctl_list);
-               dev_dbg(gbcodec->dev, "%d:%s created of type %d\n", curr->id,
+               list_add(&control->list, &module->ctl_list);
+               dev_dbg(module->dev, "%d:%s created of type %d\n", curr->id,
                        curr->name, curr->info.type);
                curr++;
        }
-       gbcodec->kctls = dapm_kctls;
+       module->controls = dapm_kctls;
 
        return 0;
 error:
-       list_for_each_entry_safe(control, _control, &gbcodec->codec_ctl_list,
+       list_for_each_entry_safe(control, _control, &module->ctl_list,
                                 list) {
                list_del(&control->list);
-               devm_kfree(gbcodec->dev, control);
+               devm_kfree(module->dev, control);
        }
-       devm_kfree(gbcodec->dev, dapm_kctls);
+       devm_kfree(module->dev, dapm_kctls);
        return ret;
 }
 
-static int gbaudio_tplg_process_widgets(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_tplg_process_widgets(struct gbaudio_module_info *module,
                                   struct gb_audio_widget *widgets)
 {
        int i, ret, ncontrols;
@@ -777,21 +808,21 @@ static int gbaudio_tplg_process_widgets(struct gbaudio_codec_info *gbcodec,
        struct gbaudio_widget *widget, *_widget;
        size_t size;
 
-       size = sizeof(struct snd_soc_dapm_widget) * gbcodec->num_dapm_widgets;
-       dapm_widgets = devm_kzalloc(gbcodec->dev, size, GFP_KERNEL);
+       size = sizeof(struct snd_soc_dapm_widget) * module->num_dapm_widgets;
+       dapm_widgets = devm_kzalloc(module->dev, size, GFP_KERNEL);
        if (!dapm_widgets)
                return -ENOMEM;
 
        curr = widgets;
-       for (i = 0; i < gbcodec->num_dapm_widgets; i++) {
-               ret = gbaudio_tplg_create_widget(gbcodec, &dapm_widgets[i],
+       for (i = 0; i < module->num_dapm_widgets; i++) {
+               ret = gbaudio_tplg_create_widget(module, &dapm_widgets[i],
                                                 curr);
                if (ret) {
-                       dev_err(gbcodec->dev, "%s:%d type not supported\n",
+                       dev_err(module->dev, "%s:%d type not supported\n",
                                curr->name, curr->type);
                        goto error;
                }
-               widget = devm_kzalloc(gbcodec->dev, sizeof(struct
+               widget = devm_kzalloc(module->dev, sizeof(struct
                                                           gbaudio_widget),
                                      GFP_KERNEL);
                if (!widget) {
@@ -800,69 +831,26 @@ static int gbaudio_tplg_process_widgets(struct gbaudio_codec_info *gbcodec,
                }
                widget->id = curr->id;
                widget->name = curr->name;
-               list_add(&widget->list, &gbcodec->widget_list);
+               list_add(&widget->list, &module->widget_list);
                ncontrols = curr->ncontrols;
                curr++;
                curr += ncontrols * sizeof(struct gb_audio_control);
        }
-       gbcodec->widgets = dapm_widgets;
+       module->dapm_widgets = dapm_widgets;
 
        return 0;
 
 error:
-       list_for_each_entry_safe(widget, _widget, &gbcodec->widget_list,
+       list_for_each_entry_safe(widget, _widget, &module->widget_list,
                                 list) {
                list_del(&widget->list);
-               devm_kfree(gbcodec->dev, widget);
-       }
-       devm_kfree(gbcodec->dev, dapm_widgets);
-       return ret;
-}
-
-static int gbaudio_tplg_process_dais(struct gbaudio_codec_info *gbcodec,
-                                  struct gb_audio_dai *dais)
-{
-       int i, ret;
-       struct snd_soc_dai_driver *gb_dais;
-       struct gb_audio_dai *curr;
-       size_t size;
-       char dai_name[NAME_SIZE];
-       struct gbaudio_dai *dai;
-
-       size = sizeof(struct snd_soc_dai_driver) * gbcodec->num_dais;
-       gb_dais = devm_kzalloc(gbcodec->dev, size, GFP_KERNEL);
-       if (!gb_dais)
-               return -ENOMEM;
-
-       curr = dais;
-       for (i = 0; i < gbcodec->num_dais; i++) {
-               ret = gbaudio_tplg_create_dai(gbcodec, &gb_dais[i], curr);
-               if (ret) {
-                       dev_err(gbcodec->dev, "%s failed to create\n",
-                               curr->name);
-                       goto error;
-               }
-               /* append dev_id to dai_name */
-               snprintf(dai_name, NAME_SIZE, "%s.%d", curr->name,
-                        gbcodec->dev_id);
-               dai = gbaudio_find_dai(gbcodec, curr->data_cport, NULL);
-               if (!dai)
-                       goto error;
-               strlcpy(dai->name, dai_name, NAME_SIZE);
-               dev_dbg(gbcodec->dev, "%s:DAI added\n", dai->name);
-               gb_dais[i].name = dai->name;
-               curr++;
+               devm_kfree(module->dev, widget);
        }
-       gbcodec->dais = gb_dais;
-
-       return 0;
-
-error:
-       devm_kfree(gbcodec->dev, gb_dais);
+       devm_kfree(module->dev, dapm_widgets);
        return ret;
 }
 
-static int gbaudio_tplg_process_routes(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_tplg_process_routes(struct gbaudio_module_info *module,
                                   struct gb_audio_route *routes)
 {
        int i, ret;
@@ -870,47 +858,47 @@ static int gbaudio_tplg_process_routes(struct gbaudio_codec_info *gbcodec,
        struct gb_audio_route *curr;
        size_t size;
 
-       size = sizeof(struct snd_soc_dapm_route) * gbcodec->num_dapm_routes;
-       dapm_routes = devm_kzalloc(gbcodec->dev, size, GFP_KERNEL);
+       size = sizeof(struct snd_soc_dapm_route) * module->num_dapm_routes;
+       dapm_routes = devm_kzalloc(module->dev, size, GFP_KERNEL);
        if (!dapm_routes)
                return -ENOMEM;
 
 
-       gbcodec->routes = dapm_routes;
+       module->dapm_routes = dapm_routes;
        curr = routes;
 
-       for (i = 0; i < gbcodec->num_dapm_routes; i++) {
+       for (i = 0; i < module->num_dapm_routes; i++) {
                dapm_routes->sink =
-                       gbaudio_map_widgetid(gbcodec, curr->destination_id);
+                       gbaudio_map_widgetid(module, curr->destination_id);
                if (!dapm_routes->sink) {
-                       dev_err(gbcodec->dev, "%d:%d:%d:%d - Invalid sink\n",
+                       dev_err(module->dev, "%d:%d:%d:%d - Invalid sink\n",
                                curr->source_id, curr->destination_id,
                                curr->control_id, curr->index);
                        ret = -EINVAL;
                        goto error;
                }
                dapm_routes->source =
-                       gbaudio_map_widgetid(gbcodec, curr->source_id);
+                       gbaudio_map_widgetid(module, curr->source_id);
                if (!dapm_routes->source) {
-                       dev_err(gbcodec->dev, "%d:%d:%d:%d - Invalid source\n",
+                       dev_err(module->dev, "%d:%d:%d:%d - Invalid source\n",
                                curr->source_id, curr->destination_id,
                                curr->control_id, curr->index);
                        ret = -EINVAL;
                        goto error;
                }
                dapm_routes->control =
-                       gbaudio_map_controlid(gbcodec,
+                       gbaudio_map_controlid(module,
                                                      curr->control_id,
                                                      curr->index);
                if ((curr->control_id !=  GBAUDIO_INVALID_ID) &&
                    !dapm_routes->control) {
-                       dev_err(gbcodec->dev, "%d:%d:%d:%d - Invalid control\n",
+                       dev_err(module->dev, "%d:%d:%d:%d - Invalid control\n",
                                curr->source_id, curr->destination_id,
                                curr->control_id, curr->index);
                        ret = -EINVAL;
                        goto error;
                }
-               dev_dbg(gbcodec->dev, "Route {%s, %s, %s}\n", dapm_routes->sink,
+               dev_dbg(module->dev, "Route {%s, %s, %s}\n", dapm_routes->sink,
                        (dapm_routes->control) ? dapm_routes->control:"NULL",
                        dapm_routes->source);
                dapm_routes++;
@@ -920,41 +908,39 @@ static int gbaudio_tplg_process_routes(struct gbaudio_codec_info *gbcodec,
        return 0;
 
 error:
-       devm_kfree(gbcodec->dev, dapm_routes);
+       devm_kfree(module->dev, dapm_routes);
        return ret;
 }
 
-static int gbaudio_tplg_process_header(struct gbaudio_codec_info *gbcodec,
+static int gbaudio_tplg_process_header(struct gbaudio_module_info *module,
                                 struct gb_audio_topology *tplg_data)
 {
        /* fetch no. of kcontrols, widgets & routes */
-       gbcodec->num_dais = tplg_data->num_dais;
-       gbcodec->num_kcontrols = tplg_data->num_controls;
-       gbcodec->num_dapm_widgets = tplg_data->num_widgets;
-       gbcodec->num_dapm_routes = tplg_data->num_routes;
+       module->num_controls = tplg_data->num_controls;
+       module->num_dapm_widgets = tplg_data->num_widgets;
+       module->num_dapm_routes = tplg_data->num_routes;
 
        /* update block offset */
-       gbcodec->dai_offset = (unsigned long)&tplg_data->data;
-       gbcodec->control_offset = gbcodec->dai_offset + tplg_data->size_dais;
-       gbcodec->widget_offset = gbcodec->control_offset +
+       module->dai_offset = (unsigned long)&tplg_data->data;
+       module->control_offset = module->dai_offset + tplg_data->size_dais;
+       module->widget_offset = module->control_offset +
                tplg_data->size_controls;
-       gbcodec->route_offset = gbcodec->widget_offset +
+       module->route_offset = module->widget_offset +
                tplg_data->size_widgets;
 
-       dev_dbg(gbcodec->dev, "DAI offset is 0x%lx\n", gbcodec->dai_offset);
-       dev_dbg(gbcodec->dev, "control offset is %lx\n",
-               gbcodec->control_offset);
-       dev_dbg(gbcodec->dev, "widget offset is %lx\n", gbcodec->widget_offset);
-       dev_dbg(gbcodec->dev, "route offset is %lx\n", gbcodec->route_offset);
+       dev_dbg(module->dev, "DAI offset is 0x%lx\n", module->dai_offset);
+       dev_dbg(module->dev, "control offset is %lx\n",
+               module->control_offset);
+       dev_dbg(module->dev, "widget offset is %lx\n", module->widget_offset);
+       dev_dbg(module->dev, "route offset is %lx\n", module->route_offset);
 
        return 0;
 }
 
-int gbaudio_tplg_parse_data(struct gbaudio_codec_info *gbcodec,
+int gbaudio_tplg_parse_data(struct gbaudio_module_info *module,
                               struct gb_audio_topology *tplg_data)
 {
        int ret;
-       struct gb_audio_dai *dais;
        struct gb_audio_control *controls;
        struct gb_audio_widget *widgets;
        struct gb_audio_route *routes;
@@ -962,90 +948,80 @@ int gbaudio_tplg_parse_data(struct gbaudio_codec_info *gbcodec,
        if (!tplg_data)
                return -EINVAL;
 
-       ret = gbaudio_tplg_process_header(gbcodec, tplg_data);
+       ret = gbaudio_tplg_process_header(module, tplg_data);
        if (ret) {
-               dev_err(gbcodec->dev, "%d: Error in parsing topology header\n",
+               dev_err(module->dev, "%d: Error in parsing topology header\n",
                        ret);
                return ret;
        }
 
        /* process control */
-       controls = (struct gb_audio_control *)gbcodec->control_offset;
-       ret = gbaudio_tplg_process_kcontrols(gbcodec, controls);
+       controls = (struct gb_audio_control *)module->control_offset;
+       ret = gbaudio_tplg_process_kcontrols(module, controls);
        if (ret) {
-               dev_err(gbcodec->dev,
+               dev_err(module->dev,
                        "%d: Error in parsing controls data\n", ret);
                return ret;
        }
-       dev_dbg(gbcodec->dev, "Control parsing finished\n");
-
-       /* process DAI */
-       dais = (struct gb_audio_dai *)gbcodec->dai_offset;
-       ret = gbaudio_tplg_process_dais(gbcodec, dais);
-       if (ret) {
-               dev_err(gbcodec->dev,
-                       "%d: Error in parsing DAIs data\n", ret);
-               return ret;
-       }
-       dev_dbg(gbcodec->dev, "DAI parsing finished\n");
+       dev_dbg(module->dev, "Control parsing finished\n");
 
        /* process widgets */
-       widgets = (struct gb_audio_widget *)gbcodec->widget_offset;
-       ret = gbaudio_tplg_process_widgets(gbcodec, widgets);
+       widgets = (struct gb_audio_widget *)module->widget_offset;
+       ret = gbaudio_tplg_process_widgets(module, widgets);
        if (ret) {
-               dev_err(gbcodec->dev,
+               dev_err(module->dev,
                        "%d: Error in parsing widgets data\n", ret);
                return ret;
        }
-       dev_dbg(gbcodec->dev, "Widget parsing finished\n");
+       dev_dbg(module->dev, "Widget parsing finished\n");
 
        /* process route */
-       routes = (struct gb_audio_route *)gbcodec->route_offset;
-       ret = gbaudio_tplg_process_routes(gbcodec, routes);
+       routes = (struct gb_audio_route *)module->route_offset;
+       ret = gbaudio_tplg_process_routes(module, routes);
        if (ret) {
-               dev_err(gbcodec->dev,
+               dev_err(module->dev,
                        "%d: Error in parsing routes data\n", ret);
                return ret;
        }
-       dev_dbg(gbcodec->dev, "Route parsing finished\n");
+       dev_dbg(module->dev, "Route parsing finished\n");
 
        return ret;
 }
 
-void gbaudio_tplg_release(struct gbaudio_codec_info *gbcodec)
+void gbaudio_tplg_release(struct gbaudio_module_info *module)
 {
        struct gbaudio_control *control, *_control;
        struct gbaudio_widget *widget, *_widget;
 
-       if (!gbcodec->topology)
+       if (!module->topology)
                return;
 
        /* release kcontrols */
-       list_for_each_entry_safe(control, _control, &gbcodec->codec_ctl_list,
+       list_for_each_entry_safe(control, _control, &module->ctl_list,
                                 list) {
                list_del(&control->list);
-               devm_kfree(gbcodec->dev, control);
+               devm_kfree(module->dev, control);
        }
-       if (gbcodec->kctls)
-               devm_kfree(gbcodec->dev, gbcodec->kctls);
+       if (module->controls)
+               devm_kfree(module->dev, module->controls);
 
        /* release widget controls */
-       list_for_each_entry_safe(control, _control, &gbcodec->widget_ctl_list,
+       list_for_each_entry_safe(control, _control, &module->widget_ctl_list,
                                 list) {
                list_del(&control->list);
-               devm_kfree(gbcodec->dev, control);
+               devm_kfree(module->dev, control);
        }
 
        /* release widgets */
-       list_for_each_entry_safe(widget, _widget, &gbcodec->widget_list,
+       list_for_each_entry_safe(widget, _widget, &module->widget_list,
                                 list) {
                list_del(&widget->list);
-               devm_kfree(gbcodec->dev, widget);
+               devm_kfree(module->dev, widget);
        }
-       if (gbcodec->widgets)
-               devm_kfree(gbcodec->dev, gbcodec->widgets);
+       if (module->dapm_widgets)
+               devm_kfree(module->dev, module->dapm_widgets);
 
        /* release routes */
-       if (gbcodec->routes)
-               devm_kfree(gbcodec->dev, gbcodec->routes);
+       if (module->dapm_routes)
+               devm_kfree(module->dev, module->dapm_routes);
 }