]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - sound/soc/sh/rcar/ssi.c
Merge branch 'asoc-4.19' into asoc-4.20 for rcar dep
[thirdparty/linux.git] / sound / soc / sh / rcar / ssi.c
index 3f880ec66459a989306ee38303692e35d354ca37..3adcc4f778f76ef460fd11d8fb1e83740c1d83b2 100644 (file)
 #define        DWL_24          (5 << 19)       /* Data Word Length */
 #define        DWL_32          (6 << 19)       /* Data Word Length */
 
+/*
+ * System word length
+ */
+#define        SWL_16          (1 << 16)       /* R/W System Word Length */
+#define        SWL_24          (2 << 16)       /* R/W System Word Length */
 #define        SWL_32          (3 << 16)       /* R/W System Word Length */
+
 #define        SCKD            (1 << 15)       /* Serial Bit Clock Direction */
 #define        SWSD            (1 << 14)       /* Serial WS Direction */
 #define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
@@ -72,7 +78,6 @@
 
 struct rsnd_ssi {
        struct rsnd_mod mod;
-       struct rsnd_mod *dma;
 
        u32 flags;
        u32 cr_own;
@@ -145,6 +150,11 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
        return use_busif;
 }
 
+int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
+{
+       return 0; /* BUSIF0 only for now */
+}
+
 static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, SSISR, 0);
@@ -220,14 +230,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
        return 0;
 }
 
-unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
+static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int width = rsnd_rdai_width_get(rdai);
+
+       switch (width) {
+       case 32: return SWL_32;
+       case 24: return SWL_24;
+       case 16: return SWL_16;
+       }
+
+       dev_err(dev, "unsupported slot width value: %d\n", width);
+       return 0;
+}
+
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
                       int param1, int param2, int *idx)
 {
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
        int ssi_clk_mul_table[] = {
                1, 2, 4, 8, 16, 6, 12,
        };
        int j, ret;
        unsigned int main_rate;
+       int width = rsnd_rdai_width_get(rdai);
 
        for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
 
@@ -240,12 +268,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
                if (j == 0)
                        continue;
 
-               /*
-                * this driver is assuming that
-                * system word is 32bit x chan
-                * see rsnd_ssi_init()
-                */
-               main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j];
+               main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
 
                ret = rsnd_adg_clk_query(priv, main_rate);
                if (ret < 0)
@@ -289,10 +312,15 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
                        return -EINVAL;
                }
 
+               if (ssi->chan != chan) {
+                       dev_err(dev, "SSI parent/child should use same chan\n");
+                       return -EINVAL;
+               }
+
                return 0;
        }
 
-       main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx);
+       main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
        if (!main_rate) {
                dev_err(dev, "unsupported clock rate\n");
                return -EIO;
@@ -312,9 +340,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
         * SSICR  : FORCE, SCKD, SWSD
         * SSIWSR : CONT
         */
-       ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
+       ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
+                       SCKD | SWSD | CKDV(idx);
        ssi->wsr = CONT;
        ssi->rate = rate;
+       ssi->chan = chan;
 
        dev_dbg(dev, "%s[%d] outputs %u Hz\n",
                rsnd_mod_name(mod),
@@ -340,6 +370,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
 
        ssi->cr_clk     = 0;
        ssi->rate       = 0;
+       ssi->chan       = 0;
 
        rsnd_adg_ssi_clk_stop(mod);
 }
@@ -357,11 +388,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
 
        is_tdm = rsnd_runtime_is_ssi_tdm(io);
 
-       /*
-        * always use 32bit system word.
-        * see also rsnd_ssi_master_clk_enable()
-        */
-       cr_own |= FORCE | SWL_32;
+       cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
 
        if (rdai->bit_clk_inv)
                cr_own |= SCKP;
@@ -384,6 +411,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
 
        cr_own &= ~DWL_MASK;
        switch (snd_pcm_format_width(runtime->format)) {
+       case 8:
+               cr_own |= DWL_8;
+               break;
        case 16:
                cr_own |= DWL_16;
                break;
@@ -488,26 +518,16 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
                              struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
 {
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int chan = params_channels(params);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       unsigned int fmt_width = snd_pcm_format_width(params_format(params));
 
-       /*
-        * snd_pcm_ops::hw_params will be called *before*
-        * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
-        * in 1st call.
-        */
-       if (ssi->usrcnt) {
-               /*
-                * Already working.
-                * It will happen if SSI has parent/child connection.
-                * it is error if child <-> parent SSI uses
-                * different channels.
-                */
-               if (ssi->chan != chan)
-                       return -EIO;
-       }
+       if (fmt_width > rdai->chan_width) {
+               struct rsnd_priv *priv = rsnd_io_to_priv(io);
+               struct device *dev = rsnd_priv_to_dev(priv);
 
-       ssi->chan = chan;
+               dev_err(dev, "invalid combination of slot-width and format-data-width\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -873,7 +893,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
                              struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        int ret;
 
        /*
@@ -888,7 +907,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
                return ret;
 
        /* SSI probe might be called many times in MUX multi path */
-       ret = rsnd_dma_attach(io, mod, &ssi->dma);
+       ret = rsnd_dma_attach(io, mod, &io->dma);
 
        return ret;
 }