These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / soc / intel / atom / sst-atom-controls.c
index 90aa5c0..d55388e 100644 (file)
@@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv)
                              sizeof(cmd.header) + cmd.header.length);
 }
 
-int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
+static int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo)
 {
        struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
@@ -774,8 +774,120 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
        return ret;
 }
 
+int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+               unsigned int rx_mask, int slots, int slot_width)
+{
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       ctx->ssp_cmd.nb_slots = slots;
+       ctx->ssp_cmd.active_tx_slot_map = tx_mask;
+       ctx->ssp_cmd.active_rx_slot_map = rx_mask;
+       ctx->ssp_cmd.nb_bits_per_slots = slot_width;
+
+       return 0;
+}
+
+static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai,
+               unsigned int fmt)
+{
+       int format;
+
+       format = fmt & SND_SOC_DAIFMT_INV_MASK;
+       dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
+
+       switch (format) {
+       case SND_SOC_DAIFMT_NB_NF:
+               return SSP_FS_ACTIVE_LOW;
+       case SND_SOC_DAIFMT_NB_IF:
+               return SSP_FS_ACTIVE_HIGH;
+       case SND_SOC_DAIFMT_IB_IF:
+               return SSP_FS_ACTIVE_LOW;
+       case SND_SOC_DAIFMT_IB_NF:
+               return SSP_FS_ACTIVE_HIGH;
+       default:
+               dev_err(dai->dev, "Invalid frame sync polarity %d\n", format);
+       }
+
+       return -EINVAL;
+}
+
+static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       int format;
+
+       format = (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+       dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
+
+       switch (format) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return SSP_MODE_MASTER;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               return SSP_MODE_SLAVE;
+       default:
+               dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
+       }
+
+       return -EINVAL;
+}
+
+
+int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       unsigned int mode;
+       int fs_polarity;
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+       switch (mode) {
+       case SND_SOC_DAIFMT_DSP_B:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1);
+               ctx->ssp_cmd.start_delay = 0;
+               ctx->ssp_cmd.data_polarity = 1;
+               ctx->ssp_cmd.frame_sync_width = 1;
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1);
+               ctx->ssp_cmd.start_delay = 1;
+               ctx->ssp_cmd.data_polarity = 1;
+               ctx->ssp_cmd.frame_sync_width = 1;
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1);
+               ctx->ssp_cmd.start_delay = 1;
+               ctx->ssp_cmd.data_polarity = 0;
+               ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots;
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1);
+               ctx->ssp_cmd.start_delay = 0;
+               ctx->ssp_cmd.data_polarity = 0;
+               ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots;
+               break;
+
+       default:
+               dev_dbg(dai->dev, "using default ssp configs\n");
+       }
+
+       fs_polarity = sst_get_frame_sync_polarity(dai, fmt);
+       if (fs_polarity < 0)
+               return fs_polarity;
+
+       ctx->ssp_cmd.frame_sync_polarity = fs_polarity;
+
+       return 0;
+}
+
 /**
  * sst_ssp_config - contains SSP configuration for media UC
+ * this can be overwritten by set_dai_xxx APIs
  */
 static const struct sst_ssp_config sst_ssp_configs = {
        .ssp_id = SSP_CODEC,
@@ -789,47 +901,56 @@ static const struct sst_ssp_config sst_ssp_configs = {
        .fs_frequency = SSP_FS_48_KHZ,
        .active_slot_map = 0xF,
        .start_delay = 0,
+       .frame_sync_polarity = SSP_FS_ACTIVE_HIGH,
+       .data_polarity = 1,
 };
 
+void sst_fill_ssp_defaults(struct snd_soc_dai *dai)
+{
+       const struct sst_ssp_config *config;
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       config = &sst_ssp_configs;
+
+       ctx->ssp_cmd.selection = config->ssp_id;
+       ctx->ssp_cmd.nb_bits_per_slots = config->bits_per_slot;
+       ctx->ssp_cmd.nb_slots = config->slots;
+       ctx->ssp_cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
+       ctx->ssp_cmd.duplex = config->duplex;
+       ctx->ssp_cmd.active_tx_slot_map = config->active_slot_map;
+       ctx->ssp_cmd.active_rx_slot_map = config->active_slot_map;
+       ctx->ssp_cmd.frame_sync_frequency = config->fs_frequency;
+       ctx->ssp_cmd.frame_sync_polarity = config->frame_sync_polarity;
+       ctx->ssp_cmd.data_polarity = config->data_polarity;
+       ctx->ssp_cmd.frame_sync_width = config->fs_width;
+       ctx->ssp_cmd.ssp_protocol = config->ssp_protocol;
+       ctx->ssp_cmd.start_delay = config->start_delay;
+       ctx->ssp_cmd.reserved1 = ctx->ssp_cmd.reserved2 = 0xFF;
+}
+
 int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
 {
-       struct sst_cmd_sba_hw_set_ssp cmd;
        struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
        const struct sst_ssp_config *config;
 
        dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
 
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.header.command_id = SBA_HW_SET_SSP;
-       cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
+       SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst);
+       drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP;
+       drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
                                - sizeof(struct sst_dsp_header);
 
        config = &sst_ssp_configs;
        dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
 
        if (enable)
-               cmd.switch_state = SST_SWITCH_ON;
+               drv->ssp_cmd.switch_state = SST_SWITCH_ON;
        else
-               cmd.switch_state = SST_SWITCH_OFF;
-
-       cmd.selection = config->ssp_id;
-       cmd.nb_bits_per_slots = config->bits_per_slot;
-       cmd.nb_slots = config->slots;
-       cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
-       cmd.duplex = config->duplex;
-       cmd.active_tx_slot_map = config->active_slot_map;
-       cmd.active_rx_slot_map = config->active_slot_map;
-       cmd.frame_sync_frequency = config->fs_frequency;
-       cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH;
-       cmd.data_polarity = 1;
-       cmd.frame_sync_width = config->fs_width;
-       cmd.ssp_protocol = config->ssp_protocol;
-       cmd.start_delay = config->start_delay;
-       cmd.reserved1 = cmd.reserved2 = 0xFF;
+               drv->ssp_cmd.switch_state = SST_SWITCH_OFF;
 
        return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                               SST_TASK_SBA, 0, &cmd,
-                               sizeof(cmd.header) + cmd.header.length);
+                               SST_TASK_SBA, 0, &drv->ssp_cmd,
+                               sizeof(drv->ssp_cmd.header) + drv->ssp_cmd.header.length);
 }
 
 static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
@@ -1177,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
                dev_dbg(dai->dev, "Stream name=%s\n",
                                dai->playback_widget->name);
                w = dai->playback_widget;
-               list_for_each_entry(p, &w->sinks, list_source) {
+               snd_soc_dapm_widget_for_each_sink_path(w, p) {
                        if (p->connected && !p->connected(w, p->sink))
                                continue;
 
@@ -1196,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
                dev_dbg(dai->dev, "Stream name=%s\n",
                                dai->capture_widget->name);
                w = dai->capture_widget;
-               list_for_each_entry(p, &w->sources, list_sink) {
+               snd_soc_dapm_widget_for_each_source_path(w, p) {
                        if (p->connected && !p->connected(w, p->sink))
                                continue;
 
@@ -1280,36 +1401,32 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
        down_read(&card->controls_rwsem);
 
        list_for_each_entry(kctl, &card->controls, list) {
-               idx = strstr(kctl->id.name, " ");
+               idx = strchr(kctl->id.name, ' ');
                if (idx == NULL)
                        continue;
-               index  = strlen(kctl->id.name) - strlen(idx);
+               index = idx - (char*)kctl->id.name;
+               if (strncmp(kctl->id.name, w->name, index))
+                       continue;
 
-               if (strstr(kctl->id.name, "Volume") &&
-                   !strncmp(kctl->id.name, w->name, index))
+               if (strstr(kctl->id.name, "Volume"))
                        ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN);
 
-               else if (strstr(kctl->id.name, "params") &&
-                        !strncmp(kctl->id.name, w->name, index))
+               else if (strstr(kctl->id.name, "params"))
                        ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO);
 
                else if (strstr(kctl->id.name, "Switch") &&
-                        !strncmp(kctl->id.name, w->name, index) &&
                         strstr(kctl->id.name, "Gain")) {
                        struct sst_gain_mixer_control *mc =
                                                (void *)kctl->private_value;
 
                        mc->w = w;
 
-               } else if (strstr(kctl->id.name, "interleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
+               } else if (strstr(kctl->id.name, "interleaver")) {
                        struct sst_enum *e = (void *)kctl->private_value;
 
                        e->w = w;
 
-               } else if (strstr(kctl->id.name, "deinterleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
-
+               } else if (strstr(kctl->id.name, "deinterleaver")) {
                        struct sst_enum *e = (void *)kctl->private_value;
 
                        e->w = w;