Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
authorMark Brown <broonie@kernel.org>
Thu, 18 Jan 2018 11:55:37 +0000 (11:55 +0000)
committerMark Brown <broonie@kernel.org>
Thu, 18 Jan 2018 11:55:37 +0000 (11:55 +0000)
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
include/sound/soc.h
sound/soc/rockchip/rk3399_gru_sound.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/ssi.c
sound/soc/soc-core.c

index 085bec364caf6592539535d13a6e50a05515c888..5bed9a5957729453c3196a88781802bf41d853a5 100644 (file)
@@ -4,7 +4,7 @@ Renesas R-Car sound
 * Modules
 =============================================
 
-Renesas R-Car sound is constructed from below modules
+Renesas R-Car and RZ/G sound is constructed from below modules
 (for Gen2 or later)
 
  SCU           : Sampling Rate Converter Unit
@@ -197,12 +197,17 @@ Ex)
        [MEM] -> [SRC2] -> [CTU03] -+
 
        sound {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
                compatible = "simple-scu-audio-card";
                ...
-               simple-audio-card,cpu-0 {
+               simple-audio-card,cpu@0 {
+                       reg = <0>;
                        sound-dai = <&rcar_sound 0>;
                };
-               simple-audio-card,cpu-1 {
+               simple-audio-card,cpu@1 {
+                       reg = <1>;
                        sound-dai = <&rcar_sound 1>;
                };
                simple-audio-card,codec {
@@ -334,9 +339,11 @@ Required properties:
 
 - compatible                   : "renesas,rcar_sound-<soctype>", fallbacks
                                  "renesas,rcar_sound-gen1" if generation1, and
-                                 "renesas,rcar_sound-gen2" if generation2
+                                 "renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
                                  "renesas,rcar_sound-gen3" if generation3
                                  Examples with soctypes are:
+                                   - "renesas,rcar_sound-r8a7743" (RZ/G1M)
+                                   - "renesas,rcar_sound-r8a7745" (RZ/G1E)
                                    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
                                    - "renesas,rcar_sound-r8a7779" (R-Car H1)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
index 6e865c2bcffe4219782b03b1fa166013074bf65f..8fd59dadaf011dea42f43f923d3b94f7c43c2258 100644 (file)
@@ -494,6 +494,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
 #endif
 
+void snd_soc_disconnect_sync(struct device *dev);
+
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
                const char *dai_link, int stream);
 struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
index d64fbbd505448b4c90a04a40d5ebc90dd83fd42b..fa6cd1de828be95991dee4eaea9dec40f69d9fef 100644 (file)
@@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
+       snd_jack_set_key(
+               rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
        snd_jack_set_key(
                rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
        snd_jack_set_key(
index f12a88a21dfa24d32f04dad32635dee2482a9337..64d5ecb865283f73c344494d0595abd25d200d1c 100644 (file)
@@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
        return 0;
 }
 
-int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+                                             struct snd_pcm_hw_params *params)
 {
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 
-       return runtime->channels;
+       /*
+        * params will be added when refine
+        * see
+        *      __rsnd_soc_hw_rule_rate()
+        *      __rsnd_soc_hw_rule_channels()
+        */
+       if (params)
+               return params_channels(params);
+       else
+               return runtime->channels;
 }
 
-int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+                                              struct snd_pcm_hw_params *params)
 {
-       int chan = rsnd_runtime_channel_original(io);
+       int chan = rsnd_runtime_channel_original_with_params(io, params);
        struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
 
        if (ctu_mod) {
@@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
        return chan;
 }
 
-int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+                                            struct snd_pcm_hw_params *params)
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        int chan = rsnd_io_is_play(io) ?
-               rsnd_runtime_channel_after_ctu(io) :
-               rsnd_runtime_channel_original(io);
+               rsnd_runtime_channel_after_ctu_with_params(io, params) :
+               rsnd_runtime_channel_original_with_params(io, params);
 
        /* Use Multi SSI */
        if (rsnd_runtime_is_ssi_multi(io))
@@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
 
-       switch (runtime->sample_bits) {
+       switch (snd_pcm_format_width(runtime->format)) {
        case 16:
                return 8 << 16;
-       case 32:
+       case 24:
                return 0 << 16;
        }
 
@@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
        struct rsnd_mod *target;
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       u32 val = 0x76543210;
-       u32 mask = ~0;
 
        /*
-        * *Hardware* L/R and *Software* L/R are inverted.
+        * *Hardware* L/R and *Software* L/R are inverted for 16bit data.
+        *          31..16 15...0
+        *      HW: [L ch] [R ch]
+        *      SW: [R ch] [L ch]
         * We need to care about inversion timing to control
         * Playback/Capture correctly.
         * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
@@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
                target = cmd ? cmd : ssiu;
        }
 
-       mask <<= runtime->channels * 4;
-       val = val & mask;
-
-       switch (runtime->sample_bits) {
-       case 16:
-               val |= 0x67452301 & ~mask;
-               break;
-       case 32:
-               val |= 0x76543210 & ~mask;
-               break;
-       }
-
-       /*
-        * exchange channeles on SRC if possible,
-        * otherwise, R/L volume settings on DVC
-        * changes inverted channels
-        */
-       if (mod == target)
-               return val;
-       else
+       /* Non target mod or 24bit data needs normal DALIGN */
+       if ((snd_pcm_format_width(runtime->format) != 16) ||
+           (mod != target))
                return 0x76543210;
+       /* Target mod needs inverted DALIGN when 16bit */
+       else
+               return 0x67452301;
 }
 
 u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
@@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
         * HW    24bit data is located as 0x******00
         *
         */
-       switch (runtime->sample_bits) {
-       case 16:
+       if (snd_pcm_format_width(runtime->format) == 16)
                return 0;
-       case 32:
-               break;
-       }
 
        for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
                tmod = rsnd_io_to_mod(io, mods[i]);
@@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
-               rsnd_dai_stream_init(io, substream);
-
                ret = rsnd_dai_call(init, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
@@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
                ret |= rsnd_dai_call(quit, io, priv);
 
-               rsnd_dai_stream_quit(io);
                break;
        default:
                ret = -EINVAL;
@@ -784,8 +776,9 @@ 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)
+static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                  struct snd_pcm_hw_rule *rule,
+                                  int is_play)
 {
        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);
@@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
        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;
 
        /*
         * possible sampling rate limitation is same as
         * 2ch if it supports multi ssi
+        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
         */
        ic = *ic_;
-       if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
-               ic.min = 2;
-               ic.max = 2;
-       }
+       ic.min =
+       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
 
        return rsnd_soc_hw_rule(priv, 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)
+static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+                                      struct snd_pcm_hw_rule *rule,
+                                      int is_play)
 {
        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);
@@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
        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;
 
        /*
         * possible sampling rate limitation is same as
         * 2ch if it supports multi ssi
+        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
         */
        ic = *ic_;
-       if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
-               ic.min = 2;
-               ic.max = 2;
-       }
+       ic.min =
+       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
 
        return rsnd_soc_hw_rule(priv, 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             |
@@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
        int ret;
        int i;
 
+       rsnd_dai_stream_init(io, substream);
+
        /*
         * Channel Limitation
         * It depends on Platform design
@@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
         * It depends on Clock Master Mode
         */
        if (rsnd_rdai_is_clk_master(rdai)) {
+               int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                   rsnd_soc_hw_rule_rate, dai,
+                                   is_play ? rsnd_soc_hw_rule_rate_playback :
+                                             rsnd_soc_hw_rule_rate_capture,
+                                   dai,
                                    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                   rsnd_soc_hw_rule_channels, dai,
+                                   is_play ? rsnd_soc_hw_rule_channels_playback :
+                                             rsnd_soc_hw_rule_channels_capture,
+                                   dai,
                                    SNDRV_PCM_HW_PARAM_RATE, -1);
        }
 
@@ -915,6 +940,8 @@ 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_stream_quit(io);
 }
 
 static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
@@ -990,7 +1017,7 @@ of_node_compatible:
 
 static void __rsnd_dai_probe(struct rsnd_priv *priv,
                             struct device_node *dai_np,
-                            int dai_i, int is_graph)
+                            int dai_i)
 {
        struct device_node *playback, *capture;
        struct rsnd_dai_stream *io_playback;
@@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
        dai_i = 0;
        if (is_graph) {
                for_each_endpoint_of_node(dai_node, dai_np) {
-                       __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
+                       __rsnd_dai_probe(priv, dai_np, dai_i);
                        rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
                        dai_i++;
                }
        } else {
                for_each_child_of_node(dai_node, dai_np)
-                       __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
+                       __rsnd_dai_probe(priv, dai_np, dai_i++);
        }
 
        return 0;
@@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev)
        };
        int ret = 0, i;
 
+       snd_soc_disconnect_sync(&pdev->dev);
+
        pm_runtime_disable(&pdev->dev);
 
        for_each_rsnd_dai(rdai, priv, i) {
index 4d750bdf8e2449981537a4b6d41bea33af321789..41de23417c4a11199140f32c8b7804c51e606a24 100644 (file)
@@ -71,25 +71,7 @@ static struct rsnd_mod mem = {
 static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
                                  struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       bool elapsed = false;
-       unsigned long flags;
-
-       /*
-        * Renesas sound Gen1 needs 1 DMAC,
-        * Gen2 needs 2 DMAC.
-        * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
-        * But, Audio-DMAC-peri-peri doesn't have interrupt,
-        * and this driver is assuming that here.
-        */
-       spin_lock_irqsave(&priv->lock, flags);
-
        if (rsnd_io_is_working(io))
-               elapsed = true;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (elapsed)
                rsnd_dai_period_elapsed(io);
 }
 
index 57cd2bc773c2ab419e33a814d07b815a42af99cb..ad6523595b0acdd0f3c3a7932b5ae535e9eb4cab 100644 (file)
@@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
                struct device_node *playback,
                struct device_node *capture);
 
-int rsnd_runtime_channel_original(struct rsnd_dai_stream *io);
-int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io);
-int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
+#define rsnd_runtime_channel_original(io) \
+       rsnd_runtime_channel_original_with_params(io, NULL)
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+                               struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_after_ctu(io)                     \
+       rsnd_runtime_channel_after_ctu_with_params(io, NULL)
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+                               struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_for_ssi(io) \
+       rsnd_runtime_channel_for_ssi_with_params(io, NULL)
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+                                struct snd_pcm_hw_params *params);
 int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
 int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
 
index cbf3bf312d23bda9427747c1af2dde30d9fcf43d..97a9db892a8f06461be29eacceae01e8c40f8da9 100644 (file)
@@ -79,8 +79,8 @@ struct rsnd_ssi {
        int irq;
        unsigned int usrcnt;
 
+       /* for PIO */
        int byte_pos;
-       int period_pos;
        int byte_per_period;
        int next_period_byte;
 };
@@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
        if (rsnd_io_is_play(io))
                cr_own |= TRMD;
 
-       switch (runtime->sample_bits) {
+       switch (snd_pcm_format_width(runtime->format)) {
        case 16:
                cr_own |= DWL_16;
                break;
-       case 32:
+       case 24:
                cr_own |= DWL_24;
                break;
        }
@@ -414,63 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
                                        ssi->cr_en);
 }
 
-static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
-                                 struct rsnd_dai_stream *io)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
-       ssi->byte_pos           = 0;
-       ssi->period_pos         = 0;
-       ssi->byte_per_period    = runtime->period_size *
-                                 runtime->channels *
-                                 samples_to_bytes(runtime, 1);
-       ssi->next_period_byte   = ssi->byte_per_period;
-}
-
-static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod,
-                                  struct rsnd_dai_stream *io,
-                                  int additional)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       int pos = ssi->byte_pos + additional;
-
-       pos %= (runtime->periods * ssi->byte_per_period);
-
-       return pos;
-}
-
-static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod,
-                                   struct rsnd_dai_stream *io,
-                                   int byte)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       bool ret = false;
-       int byte_pos;
-
-       byte_pos = ssi->byte_pos + byte;
-
-       if (byte_pos >= ssi->next_period_byte) {
-               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
-               ssi->period_pos++;
-               ssi->next_period_byte += ssi->byte_per_period;
-
-               if (ssi->period_pos >= runtime->periods) {
-                       byte_pos = 0;
-                       ssi->period_pos = 0;
-                       ssi->next_period_byte = ssi->byte_per_period;
-               }
-
-               ret = true;
-       }
-
-       WRITE_ONCE(ssi->byte_pos, byte_pos);
-
-       return ret;
-}
-
 /*
  *     SSI mod common functions
  */
@@ -484,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
        if (!rsnd_ssi_is_run_mods(mod, io))
                return 0;
 
-       rsnd_ssi_pointer_init(mod, io);
-
        ssi->usrcnt++;
 
        rsnd_mod_power_on(mod);
@@ -656,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
        return 0;
 }
 
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io);
 static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io)
 {
@@ -674,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
        status = rsnd_ssi_status_get(mod);
 
        /* PIO only */
-       if (!is_dma && (status & DIRQ)) {
-               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-               u32 *buf = (u32 *)(runtime->dma_area +
-                                  rsnd_ssi_pointer_offset(mod, io, 0));
-               int shift = 0;
-
-               switch (runtime->sample_bits) {
-               case 32:
-                       shift = 8;
-                       break;
-               }
-
-               /*
-                * 8/16/32 data can be assesse to TDR/RDR register
-                * directly as 32bit data
-                * see rsnd_ssi_init()
-                */
-               if (rsnd_io_is_play(io))
-                       rsnd_mod_write(mod, SSITDR, (*buf) << shift);
-               else
-                       *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
-
-               elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf));
-       }
+       if (!is_dma && (status & DIRQ))
+               elapsed = rsnd_ssi_pio_interrupt(mod, io);
 
        /* DMA only */
        if (is_dma && (status & (UIRQ | OIRQ)))
@@ -835,7 +756,71 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_ssi_pointer(struct rsnd_mod *mod,
+/*
+ *     SSI PIO functions
+ */
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
+       int shift = 0;
+       int byte_pos;
+       bool elapsed = false;
+
+       if (snd_pcm_format_width(runtime->format) == 24)
+               shift = 8;
+
+       /*
+        * 8/16/32 data can be assesse to TDR/RDR register
+        * directly as 32bit data
+        * see rsnd_ssi_init()
+        */
+       if (rsnd_io_is_play(io))
+               rsnd_mod_write(mod, SSITDR, (*buf) << shift);
+       else
+               *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
+
+       byte_pos = ssi->byte_pos + sizeof(*buf);
+
+       if (byte_pos >= ssi->next_period_byte) {
+               int period_pos = byte_pos / ssi->byte_per_period;
+
+               if (period_pos >= runtime->periods) {
+                       byte_pos = 0;
+                       period_pos = 0;
+               }
+
+               ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
+
+               elapsed = true;
+       }
+
+       WRITE_ONCE(ssi->byte_pos, byte_pos);
+
+       return elapsed;
+}
+
+static int rsnd_ssi_pio_init(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io,
+                            struct rsnd_priv *priv)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       if (!rsnd_ssi_is_parent(mod, io)) {
+               ssi->byte_pos           = 0;
+               ssi->byte_per_period    = runtime->period_size *
+                                         runtime->channels *
+                                         samples_to_bytes(runtime, 1);
+               ssi->next_period_byte   = ssi->byte_per_period;
+       }
+
+       return rsnd_ssi_init(mod, io, priv);
+}
+
+static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            snd_pcm_uframes_t *pointer)
 {
@@ -851,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .name   = SSI_NAME,
        .probe  = rsnd_ssi_common_probe,
        .remove = rsnd_ssi_common_remove,
-       .init   = rsnd_ssi_init,
+       .init   = rsnd_ssi_pio_init,
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_start,
        .stop   = rsnd_ssi_stop,
        .irq    = rsnd_ssi_irq,
-       .pointer= rsnd_ssi_pointer,
+       .pointer = rsnd_ssi_pio_pointer,
        .pcm_new = rsnd_ssi_pcm_new,
        .hw_params = rsnd_ssi_hw_params,
 };
index 9b79c2199781a7fc171a2bb1eac02989e2f1b3b5..e018a2badfde6f01f952b24b122d55fc386e3f8b 100644 (file)
@@ -1393,6 +1393,16 @@ static int soc_init_dai_link(struct snd_soc_card *card,
        return 0;
 }
 
+void snd_soc_disconnect_sync(struct device *dev)
+{
+       struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL);
+
+       if (!component || !component->card)
+               return;
+
+       snd_card_disconnect_sync(component->card->snd_card);
+}
+
 /**
  * snd_soc_add_dai_link - Add a DAI link dynamically
  * @card: The ASoC card to which the DAI link is added