ASoC: intel: add support for specifying PCM format
authorVinod Koul <vinod.koul@intel.com>
Wed, 6 May 2015 16:36:43 +0000 (22:06 +0530)
committerMark Brown <broonie@kernel.org>
Wed, 6 May 2015 18:50:22 +0000 (19:50 +0100)
With this machines can configure the PCM format applied on SSP port using
the set_fmt API

Signed-off-by: Praveen Diwakar <praveen.diwakar@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.h
sound/soc/intel/atom/sst-mfld-platform-pcm.c

index 93c6c8b5fbc61fb9054766fa067024386201d60c..e024d98948fab8b22dd83bad097239b83941ea89 100644 (file)
@@ -774,8 +774,107 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
        return ret;
 }
 
+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,
index da13f6fa7d1c62001bc00b3a4e101216f11a15f9..53551a657b51c1bd0d1c821e67ad0a109847fc2a 100644 (file)
@@ -869,6 +869,7 @@ struct sst_enum {
        SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
                          SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
 
+int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt);
 void sst_fill_ssp_defaults(struct snd_soc_dai *dai);
 
 #endif
index 1fb2448e0fed05e0f547ac0c28e28dbe3008688d..580f5e92580e1af0c8e742d5ad5971319c8b27cd 100644 (file)
@@ -450,6 +450,20 @@ static int sst_be_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       int ret = 0;
+
+       if (!dai->active)
+               return 0;
+
+       ret = sst_fill_ssp_config(dai, fmt);
+       if (ret < 0)
+               dev_err(dai->dev, "sst_set_format failed..\n");
+
+       return ret;
+}
+
 static void sst_disable_ssp(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
@@ -475,6 +489,7 @@ static struct snd_soc_dai_ops sst_compr_dai_ops = {
 static struct snd_soc_dai_ops sst_be_dai_ops = {
        .startup = sst_enable_ssp,
        .hw_params = sst_be_hw_params,
+       .set_fmt = sst_set_format,
        .shutdown = sst_disable_ssp,
 };