ASoC: rsnd: merge .nolock_start and .prepare
[linux-2.6-microblaze.git] / sound / soc / sh / rcar / core.c
index f237002..e46415c 100644 (file)
@@ -1,16 +1,12 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on fsi.c
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRU/SCU/SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
 
 /*
  * Renesas R-Car sound device structure
 #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 },
@@ -284,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:
@@ -335,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;
@@ -371,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++) {
@@ -544,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)))
@@ -552,6 +560,15 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
        return priv->rdai + id;
 }
 
+static struct snd_soc_dai_driver
+*rsnd_daidrv_get(struct rsnd_priv *priv, int id)
+{
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
+               return NULL;
+
+       return priv->daidrv + id;
+}
+
 #define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
 static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
 {
@@ -676,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;
@@ -685,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 */
@@ -715,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:
@@ -722,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);
@@ -750,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)
 {
@@ -767,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]);
@@ -785,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
@@ -806,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
@@ -844,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             |
@@ -877,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);
@@ -917,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,
@@ -948,17 +941,28 @@ 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);
 }
 
+static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       return rsnd_dai_call(prepare, io, priv);
+}
+
 static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        .startup        = rsnd_soc_dai_startup,
        .shutdown       = rsnd_soc_dai_shutdown,
        .trigger        = rsnd_soc_dai_trigger,
        .set_fmt        = rsnd_soc_dai_set_fmt,
        .set_tdm_slot   = rsnd_soc_set_dai_tdm_slot,
+       .prepare        = rsnd_soc_dai_prepare,
 };
 
 void rsnd_parse_connect_common(struct rsnd_dai *rdai,
@@ -1037,7 +1041,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        int io_i;
 
        rdai            = rsnd_rdai_get(priv, dai_i);
-       drv             = priv->daidrv + dai_i;
+       drv             = rsnd_daidrv_get(priv, dai_i);
        io_playback     = &rdai->playback;
        io_capture      = &rdai->capture;
 
@@ -1067,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);
@@ -1085,6 +1090,12 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
                of_node_put(capture);
        }
 
+       if (rsnd_ssi_is_pin_sharing(io_capture) ||
+           rsnd_ssi_is_pin_sharing(io_playback)) {
+               /* should have symmetric_rates if pin sharing */
+               drv->symmetric_rates = 1;
+       }
+
        dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
                rsnd_io_to_mod_ssi(io_playback) ? "play"    : " -- ",
                rsnd_io_to_mod_ssi(io_capture) ? "capture" : "  --   ");
@@ -1252,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);
 
-       return !!runtime;
+       if (!runtime) {
+               dev_warn(dev, "Can't update kctrl when idle\n");
+               return 0;
+       }
+
+       return 1;
 }
 
 struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
@@ -1606,7 +1624,7 @@ static struct platform_driver rsnd_driver = {
 };
 module_platform_driver(rsnd_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Renesas R-Car audio driver");
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 MODULE_ALIAS("platform:rcar-pcm-audio");