ASoC: dwc: add check for master/slave format
authorMaruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@amd.com>
Fri, 23 Oct 2015 21:15:41 +0000 (17:15 -0400)
committerMark Brown <broonie@kernel.org>
Fri, 23 Oct 2015 21:29:38 +0000 (06:29 +0900)
DW i2s controller's master/slave config can be read from a
read-only register. Machine driver can try to set a master/slave
format on cpu-dai using 'set_fmt' of dai ops. A check is added to
verify codec is master when dwc is slave and vice-versa.

Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/dwc/designware_i2s.c

index 3a52f82b55232b9336b8fb9661437021d1b24f11..f427325ae4486cb612de45d0fce41177de6fa9c3 100644 (file)
@@ -341,12 +341,43 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if (dev->capability & DW_I2S_SLAVE)
+                       ret = 0;
+               else
+                       ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (dev->capability & DW_I2S_MASTER)
+                       ret = 0;
+               else
+                       ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBS_CFM:
+               ret = -EINVAL;
+               break;
+       default:
+               dev_dbg(dev->dev, "dwc : Invalid master/slave format\n");
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
 static struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .startup        = dw_i2s_startup,
        .shutdown       = dw_i2s_shutdown,
        .hw_params      = dw_i2s_hw_params,
        .prepare        = dw_i2s_prepare,
        .trigger        = dw_i2s_trigger,
+       .set_fmt        = dw_i2s_set_fmt,
 };
 
 static const struct snd_soc_component_driver dw_i2s_component = {