ASoC: ak4613: tidyup CTRL1 value selection method
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 16 Nov 2015 06:01:29 +0000 (06:01 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 16 Nov 2015 13:18:28 +0000 (13:18 +0000)
Current CTRL1 selection method didn't care about simultaneous
playback / capture. This patch tidyup it.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/ak4613.c

index 394c10ff049ef1e0fe9c09e6b0cb1a6403cb5e24..dab127603ff6e7b107b9ab594b2c75c99bbabef4 100644 (file)
 #define DFS_DOUBLE_SPEED       (1 << 2)
 #define DFS_QUAD_SPEED         (2 << 2)
 
-struct ak4613_priv {
-       struct mutex lock;
-
-       unsigned int fmt;
-       u8 fmt_ctrl;
-       u8 oc;
-       u8 ic;
-       int cnt;
-};
-
 struct ak4613_formats {
        unsigned int width;
        unsigned int fmt;
@@ -94,6 +84,16 @@ struct ak4613_interface {
        struct ak4613_formats playback;
 };
 
+struct ak4613_priv {
+       struct mutex lock;
+       const struct ak4613_interface *iface;
+
+       unsigned int fmt;
+       u8 oc;
+       u8 ic;
+       int cnt;
+};
+
 /*
  * Playback Volume
  *
@@ -128,7 +128,7 @@ static const struct reg_default ak4613_reg[] = {
        { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
 };
 
-#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
 #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
 static const struct ak4613_interface ak4613_iface[] = {
        /* capture */                           /* playback */
@@ -242,7 +242,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
                priv->cnt = 0;
        }
        if (!priv->cnt)
-               priv->fmt_ctrl = NO_FMT;
+               priv->iface = NULL;
        mutex_unlock(&priv->lock);
 }
 
@@ -267,13 +267,35 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
+static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
+                                   int is_play,
+                                   unsigned int fmt, unsigned int width)
+{
+       const struct ak4613_formats *fmts;
+
+       fmts = (is_play) ? &iface->playback : &iface->capture;
+
+       if (fmts->fmt != fmt)
+               return false;
+
+       if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+               if (fmts->width != width)
+                       return false;
+       } else {
+               if (fmts->width < width)
+                       return false;
+       }
+
+       return true;
+}
+
 static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
-       const struct ak4613_formats *fmts;
+       const struct ak4613_interface *iface;
        struct device *dev = codec->dev;
        unsigned int width = params_width(params);
        unsigned int fmt = priv->fmt;
@@ -307,33 +329,27 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
         * It doesn't support TDM at this point
         */
        fmt_ctrl = NO_FMT;
-       for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
-               fmts = (is_play) ?      &ak4613_iface[i].playback :
-                                       &ak4613_iface[i].capture;
-
-               if (fmts->fmt != fmt)
-                       continue;
+       ret = -EINVAL;
+       iface = NULL;
 
-               if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
-                       if (fmts->width != width)
-                               continue;
-               } else {
-                       if (fmts->width < width)
+       mutex_lock(&priv->lock);
+       if (priv->iface) {
+               if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
+                       iface = priv->iface;
+       } else {
+               for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) {
+                       if (!ak4613_dai_fmt_matching(ak4613_iface + i,
+                                                    is_play,
+                                                    fmt, width))
                                continue;
+                       iface = ak4613_iface + i;
+                       break;
                }
-
-               fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
-               break;
        }
 
-       ret = -EINVAL;
-       if (fmt_ctrl == NO_FMT)
-               goto hw_params_end;
-
-       mutex_lock(&priv->lock);
-       if ((priv->fmt_ctrl == NO_FMT) ||
-           (priv->fmt_ctrl == fmt_ctrl)) {
-               priv->fmt_ctrl = fmt_ctrl;
+       if ((priv->iface == NULL) ||
+           (priv->iface == iface)) {
+               priv->iface = iface;
                priv->cnt++;
                ret = 0;
        }
@@ -342,6 +358,8 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                goto hw_params_end;
 
+       fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
+
        snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
        snd_soc_write(codec, CTRL2, ctrl2);
 
@@ -487,7 +505,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
 
        ak4613_parse_of(priv, dev);
 
-       priv->fmt_ctrl          = NO_FMT;
+       priv->iface             = NULL;
        priv->cnt               = 0;
 
        mutex_init(&priv->lock);