Merge branch 'asoc-4.19' into asoc-4.20 Cirrus conflict
[linux-2.6-microblaze.git] / sound / soc / sh / rcar / core.c
index d23c2bb..40d7dc4 100644 (file)
 #include "rsnd.h"
 
 #define RSND_RATES SNDRV_PCM_RATE_8000_192000
-#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\
+                  SNDRV_PCM_FMTBIT_S16_LE |\
+                  SNDRV_PCM_FMTBIT_S24_LE)
 
 static const struct of_device_id rsnd_of_match[] = {
        { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
@@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        struct device *dev = rsnd_priv_to_dev(priv);
 
        switch (snd_pcm_format_width(runtime->format)) {
+       case 8:
+               return 16 << 16;
        case 16:
                return 8 << 16;
        case 24:
@@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
                target = cmd ? cmd : ssiu;
        }
 
-       /* Non target mod or 24bit data needs normal DALIGN */
+       /* Non target mod or non 16bit needs normal DALIGN */
        if ((snd_pcm_format_width(runtime->format) != 16) ||
            (mod != target))
                return 0x76543210;
@@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
         * HW    24bit data is located as 0x******00
         *
         */
-       if (snd_pcm_format_width(runtime->format) == 16)
+       if (snd_pcm_format_width(runtime->format) != 24)
                return 0;
 
        for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
@@ -540,6 +544,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
        return rdai->ssi_lane;
 }
 
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
+{
+       if (width > 0)
+               rdai->chan_width = width;
+
+       return rdai->chan_width;
+}
+
 struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
 {
        if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
@@ -681,6 +693,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                rdai->frm_clk_inv = 0;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_DSP_B:
                rdai->sys_delay = 1;
                rdai->data_alignment = 0;
                rdai->frm_clk_inv = 1;
@@ -690,6 +703,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                rdai->data_alignment = 1;
                rdai->frm_clk_inv = 1;
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               rdai->sys_delay = 0;
+               rdai->data_alignment = 0;
+               rdai->frm_clk_inv = 1;
+               break;
        }
 
        /* set clock inversion */
@@ -720,6 +738,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct device *dev = rsnd_priv_to_dev(priv);
 
+       switch (slot_width) {
+       case 16:
+       case 24:
+       case 32:
+               break;
+       default:
+               dev_err(dev, "unsupported slot width value: %d\n", slot_width);
+               return -EINVAL;
+       }
+
        switch (slots) {
        case 2:
        case 6:
@@ -727,6 +755,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
                /* TDM Extend Mode */
                rsnd_rdai_channels_set(rdai, slots);
                rsnd_rdai_ssi_lane_set(rdai, 1);
+               rsnd_rdai_width_set(rdai, slot_width);
                break;
        default:
                dev_err(dev, "unsupported TDM slots (%d)\n", slots);
@@ -755,7 +784,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = {
        192000,
 };
 
-static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
+static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
                            unsigned int *list, int list_num,
                            struct snd_interval *baseline, struct snd_interval *iv)
 {
@@ -772,14 +801,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
                if (!snd_interval_test(iv, list[i]))
                        continue;
 
-               rate = rsnd_ssi_clk_query(priv,
+               rate = rsnd_ssi_clk_query(rdai,
                                          baseline->min, list[i], NULL);
                if (rate > 0) {
                        p.min = min(p.min, list[i]);
                        p.max = max(p.max, list[i]);
                }
 
-               rate = rsnd_ssi_clk_query(priv,
+               rate = rsnd_ssi_clk_query(rdai,
                                          baseline->max, list[i], NULL);
                if (rate > 0) {
                        p.min = min(p.min, list[i]);
@@ -790,17 +819,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
        return snd_interval_refine(iv, &p);
 }
 
-static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
-                                  struct snd_pcm_hw_rule *rule,
-                                  int is_play)
+static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                struct snd_pcm_hw_rule *rule)
 {
        struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        struct snd_interval ic;
-       struct snd_soc_dai *dai = rule->private;
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+       struct rsnd_dai_stream *io = rule->private;
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 
        /*
         * possible sampling rate limitation is same as
@@ -811,34 +837,19 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
        ic.min =
        ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
 
-       return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
+       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
                                ARRAY_SIZE(rsnd_soc_hw_rate_list),
                                &ic, ir);
 }
 
-static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params,
-                                struct snd_pcm_hw_rule *rule)
-{
-       return __rsnd_soc_hw_rule_rate(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params,
-                                         struct snd_pcm_hw_rule *rule)
-{
-       return __rsnd_soc_hw_rule_rate(params, rule, 0);
-}
-
-static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
-                                      struct snd_pcm_hw_rule *rule,
-                                      int is_play)
+static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+                                    struct snd_pcm_hw_rule *rule)
 {
        struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        struct snd_interval ic;
-       struct snd_soc_dai *dai = rule->private;
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+       struct rsnd_dai_stream *io = rule->private;
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 
        /*
         * possible sampling rate limitation is same as
@@ -849,23 +860,11 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
        ic.min =
        ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
 
-       return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
+       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
                                ARRAY_SIZE(rsnd_soc_hw_channels_list),
                                ir, &ic);
 }
 
-static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params,
-                                             struct snd_pcm_hw_rule *rule)
-{
-       return __rsnd_soc_hw_rule_channels(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params,
-                                            struct snd_pcm_hw_rule *rule)
-{
-       return __rsnd_soc_hw_rule_channels(params, rule, 0);
-}
-
 static const struct snd_pcm_hardware rsnd_pcm_hardware = {
        .info =         SNDRV_PCM_INFO_INTERLEAVED      |
                        SNDRV_PCM_INFO_MMAP             |
@@ -882,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
        struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
        struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int max_channels = rsnd_rdai_channels_get(rdai);
-       int ret;
        int i;
 
        rsnd_dai_stream_init(io, substream);
@@ -922,25 +919,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
                int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                   is_play ? rsnd_soc_hw_rule_rate_playback :
-                                             rsnd_soc_hw_rule_rate_capture,
-                                   dai,
+                                   rsnd_soc_hw_rule_rate,
+                                   is_play ? &rdai->playback : &rdai->capture,
                                    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                   is_play ? rsnd_soc_hw_rule_channels_playback :
-                                             rsnd_soc_hw_rule_channels_capture,
-                                   dai,
+                                   rsnd_soc_hw_rule_channels,
+                                   is_play ? &rdai->playback : &rdai->capture,
                                    SNDRV_PCM_HW_PARAM_RATE, -1);
        }
 
-       /*
-        * call rsnd_dai_call without spinlock
-        */
-       ret = rsnd_dai_call(nolock_start, io, priv);
-       if (ret < 0)
-               rsnd_dai_call(nolock_stop, io, priv);
-
-       return ret;
+       return 0;
 }
 
 static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
@@ -953,7 +941,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
        /*
         * call rsnd_dai_call without spinlock
         */
-       rsnd_dai_call(nolock_stop, io, priv);
+       rsnd_dai_call(cleanup, io, priv);
 
        rsnd_dai_stream_quit(io);
 }
@@ -1083,6 +1071,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        rdai->capture.rdai              = rdai;
        rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
        rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
+       rsnd_rdai_width_set(rdai, 32);   /* default 32bit width */
 
        for (io_i = 0;; io_i++) {
                playback = of_parse_phandle(dai_np, "playback", io_i);
@@ -1274,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
 int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
 {
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (!runtime) {
+               dev_warn(dev, "Can't update kctrl when idle\n");
+               return 0;
+       }
 
-       return !!runtime;
+       return 1;
 }
 
 struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)