Merge branch 'fix/rcar' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@kernel.org>
Wed, 7 Jun 2017 19:30:32 +0000 (20:30 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 7 Jun 2017 19:30:32 +0000 (20:30 +0100)
1  2 
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/cmd.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c

diff --combined sound/soc/sh/rcar/adg.c
index 36bece8621b700c5f996f2324e4227b24ea56c2f,d3b0dc145a560c8a35ddc4320810039f481db5aa..4a72fd74ddc2e665564c1d9b90d12dca1fca5d03
@@@ -480,9 -480,6 +480,9 @@@ static void rsnd_adg_get_clkout(struct 
        if (req_rate[0] % 48000 == 0)
                adg->flags = AUDIO_OUT_48;
  
 +      if (of_get_property(np, "clkout-lr-asynchronous", NULL))
 +              adg->flags = LRCLK_ASYNC;
 +
        /*
         * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
         * have 44.1kHz or 48kHz base clocks for now.
                                rbga = rbgx;
                                adg->rbga_rate_for_441khz = rate / div;
                                ckr |= brg_table[i] << 20;
-                               if (req_441kHz_rate)
+                               if (req_441kHz_rate &&
+                                   !(adg_mode_flags(adg) & AUDIO_OUT_48))
                                        parent_clk_name = __clk_get_name(clk);
                        }
                }
                                rbgb = rbgx;
                                adg->rbgb_rate_for_48khz = rate / div;
                                ckr |= brg_table[i] << 16;
-                               if (req_48kHz_rate)
+                               if (req_48kHz_rate &&
+                                   (adg_mode_flags(adg) & AUDIO_OUT_48))
                                        parent_clk_name = __clk_get_name(clk);
                        }
                }
                        clk = clk_register_fixed_rate(dev, clkout_name[i],
                                                      parent_clk_name, 0,
                                                      req_rate[0]);
 -                      adg->clkout[i] = ERR_PTR(-ENOENT);
                        if (!IS_ERR(clk))
                                adg->clkout[i] = clk;
                }
@@@ -580,6 -580,7 +582,6 @@@ int rsnd_adg_probe(struct rsnd_priv *pr
  {
        struct rsnd_adg *adg;
        struct device *dev = rsnd_priv_to_dev(priv);
 -      struct device_node *np = dev->of_node;
        int ret;
  
        adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
        rsnd_adg_get_clkin(priv, adg);
        rsnd_adg_get_clkout(priv, adg);
  
 -      if (of_get_property(np, "clkout-lr-asynchronous", NULL))
 -              adg->flags = LRCLK_ASYNC;
 -
        priv->adg = adg;
  
        rsnd_adg_clk_enable(priv);
diff --combined sound/soc/sh/rcar/cmd.c
index 98835e9d1d7d13ddc905917a34419e61add7cc83,d879c010cf03c4607ebdab3c854a582d816ddf62..9a136d86e2a91884443f2e0b03c260d594e5ab25
@@@ -82,9 -82,6 +82,9 @@@ static int rsnd_cmd_init(struct rsnd_mo
                        [9] = 0x2,
                };
  
 +              if (unlikely(!src))
 +                      return -EIO;
 +
                data = path[rsnd_mod_id(src)] |
                        cmd_case[rsnd_mod_id(src)] << 16;
        }
@@@ -92,6 -89,7 +92,7 @@@
        dev_dbg(dev, "ctu/mix path = 0x%08x", data);
  
        rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+       rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
        rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
  
        rsnd_adg_set_cmd_timsel_gen2(mod, io);
diff --combined sound/soc/sh/rcar/core.c
index bc12c449857acec5b2740a17ab16680058c4e917,8c1f4e2e0c4fb8c3ac09a641b4b8a928defb871c..7a8c08933503f4e20a73c11f5aee36b39e0de49d
@@@ -343,6 -343,57 +343,57 @@@ u32 rsnd_get_dalign(struct rsnd_mod *mo
                return 0x76543210;
  }
  
+ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
+ {
+       enum rsnd_mod_type playback_mods[] = {
+               RSND_MOD_SRC,
+               RSND_MOD_CMD,
+               RSND_MOD_SSIU,
+       };
+       enum rsnd_mod_type capture_mods[] = {
+               RSND_MOD_CMD,
+               RSND_MOD_SRC,
+               RSND_MOD_SSIU,
+       };
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_mod *tmod = NULL;
+       enum rsnd_mod_type *mods =
+               rsnd_io_is_play(io) ?
+               playback_mods : capture_mods;
+       int i;
+       /*
+        * This is needed for 24bit data
+        * We need to shift 8bit
+        *
+        * Linux 24bit data is located as 0x00******
+        * HW    24bit data is located as 0x******00
+        *
+        */
+       switch (runtime->sample_bits) {
+       case 16:
+               return 0;
+       case 32:
+               break;
+       }
+       for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
+               tmod = rsnd_io_to_mod(io, mods[i]);
+               if (tmod)
+                       break;
+       }
+       if (tmod != mod)
+               return 0;
+       if (rsnd_io_is_play(io))
+               return  (0 << 20) | /* shift to Left */
+                       (8 << 16);  /* 8bit */
+       else
+               return  (1 << 20) | /* shift to Right */
+                       (8 << 16);  /* 8bit */
+ }
  /*
   *    rsnd_dai functions
   */
@@@ -715,16 -766,11 +766,16 @@@ static int rsnd_soc_dai_startup(struct 
  {
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
 +      int ret;
  
        /*
         * call rsnd_dai_call without spinlock
         */
 -      return rsnd_dai_call(nolock_start, io, priv);
 +      ret = rsnd_dai_call(nolock_start, io, priv);
 +      if (ret < 0)
 +              rsnd_dai_call(nolock_stop, io, priv);
 +
 +      return ret;
  }
  
  static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
@@@ -774,131 -820,32 +825,131 @@@ void rsnd_parse_connect_common(struct r
        of_node_put(node);
  }
  
 -static int rsnd_dai_probe(struct rsnd_priv *priv)
 +static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
 +                                          int *is_graph)
  {
 +      struct device *dev = rsnd_priv_to_dev(priv);
 +      struct device_node *np = dev->of_node;
        struct device_node *dai_node;
 -      struct device_node *dai_np;
 +      struct device_node *ret;
 +
 +      *is_graph = 0;
 +
 +      /*
 +       * parse both previous dai (= rcar_sound,dai), and
 +       * graph dai (= ports/port)
 +       */
 +      dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
 +      if (dai_node) {
 +              ret = dai_node;
 +              goto of_node_compatible;
 +      }
 +
 +      ret = np;
 +
 +      dai_node = of_graph_get_next_endpoint(np, NULL);
 +      if (dai_node)
 +              goto of_node_graph;
 +
 +      return NULL;
 +
 +of_node_graph:
 +      *is_graph = 1;
 +of_node_compatible:
 +      of_node_put(dai_node);
 +
 +      return ret;
 +}
 +
 +static void __rsnd_dai_probe(struct rsnd_priv *priv,
 +                           struct device_node *dai_np,
 +                           int dai_i, int is_graph)
 +{
        struct device_node *playback, *capture;
        struct rsnd_dai_stream *io_playback;
        struct rsnd_dai_stream *io_capture;
 -      struct snd_soc_dai_driver *rdrv, *drv;
 +      struct snd_soc_dai_driver *drv;
        struct rsnd_dai *rdai;
        struct device *dev = rsnd_priv_to_dev(priv);
 -      int nr, dai_i, io_i;
 -      int ret;
 +      int io_i;
 +
 +      rdai            = rsnd_rdai_get(priv, dai_i);
 +      drv             = priv->daidrv + dai_i;
 +      io_playback     = &rdai->playback;
 +      io_capture      = &rdai->capture;
 +
 +      snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
 +
 +      rdai->priv      = priv;
 +      drv->name       = rdai->name;
 +      drv->ops        = &rsnd_soc_dai_ops;
 +
 +      snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
 +               "DAI%d Playback", dai_i);
 +      drv->playback.rates             = RSND_RATES;
 +      drv->playback.formats           = RSND_FMTS;
 +      drv->playback.channels_min      = 2;
 +      drv->playback.channels_max      = 6;
 +      drv->playback.stream_name       = rdai->playback.name;
 +
 +      snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
 +               "DAI%d Capture", dai_i);
 +      drv->capture.rates              = RSND_RATES;
 +      drv->capture.formats            = RSND_FMTS;
 +      drv->capture.channels_min       = 2;
 +      drv->capture.channels_max       = 6;
 +      drv->capture.stream_name        = rdai->capture.name;
 +
 +      rdai->playback.rdai             = rdai;
 +      rdai->capture.rdai              = rdai;
 +      rsnd_set_slot(rdai, 2, 1); /* default */
 +
 +      for (io_i = 0;; io_i++) {
 +              playback = of_parse_phandle(dai_np, "playback", io_i);
 +              capture  = of_parse_phandle(dai_np, "capture", io_i);
 +
 +              if (!playback && !capture)
 +                      break;
  
 -      dai_node = rsnd_dai_of_node(priv);
 -      nr = of_get_child_count(dai_node);
 -      if (!nr) {
 -              ret = -EINVAL;
 -              goto rsnd_dai_probe_done;
 +              rsnd_parse_connect_ssi(rdai, playback, capture);
 +              rsnd_parse_connect_src(rdai, playback, capture);
 +              rsnd_parse_connect_ctu(rdai, playback, capture);
 +              rsnd_parse_connect_mix(rdai, playback, capture);
 +              rsnd_parse_connect_dvc(rdai, playback, capture);
 +
 +              of_node_put(playback);
 +              of_node_put(capture);
        }
  
 +      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" : "  --   ");
 +}
 +
 +static int rsnd_dai_probe(struct rsnd_priv *priv)
 +{
 +      struct device_node *dai_node;
 +      struct device_node *dai_np;
 +      struct snd_soc_dai_driver *rdrv;
 +      struct device *dev = rsnd_priv_to_dev(priv);
 +      struct rsnd_dai *rdai;
 +      int nr;
 +      int is_graph;
 +      int dai_i;
 +
 +      dai_node = rsnd_dai_of_node(priv, &is_graph);
 +      if (is_graph)
 +              nr = of_graph_get_endpoint_count(dai_node);
 +      else
 +              nr = of_get_child_count(dai_node);
 +
 +      if (!nr)
 +              return -EINVAL;
 +
        rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
        rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
 -      if (!rdrv || !rdai) {
 -              ret = -ENOMEM;
 -              goto rsnd_dai_probe_done;
 -      }
 +      if (!rdrv || !rdai)
 +              return -ENOMEM;
  
        priv->rdai_nr   = nr;
        priv->daidrv    = rdrv;
         * parse all dai
         */
        dai_i = 0;
 -      for_each_child_of_node(dai_node, dai_np) {
 -              rdai            = rsnd_rdai_get(priv, dai_i);
 -              drv             = rdrv + dai_i;
 -              io_playback     = &rdai->playback;
 -              io_capture      = &rdai->capture;
 -
 -              snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
 -
 -              rdai->priv      = priv;
 -              drv->name       = rdai->name;
 -              drv->ops        = &rsnd_soc_dai_ops;
 -
 -              snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
 -                       "DAI%d Playback", dai_i);
 -              drv->playback.rates             = RSND_RATES;
 -              drv->playback.formats           = RSND_FMTS;
 -              drv->playback.channels_min      = 2;
 -              drv->playback.channels_max      = 6;
 -              drv->playback.stream_name       = rdai->playback.name;
 -
 -              snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
 -                       "DAI%d Capture", dai_i);
 -              drv->capture.rates              = RSND_RATES;
 -              drv->capture.formats            = RSND_FMTS;
 -              drv->capture.channels_min       = 2;
 -              drv->capture.channels_max       = 6;
 -              drv->capture.stream_name        = rdai->capture.name;
 -
 -              rdai->playback.rdai             = rdai;
 -              rdai->capture.rdai              = rdai;
 -              rsnd_set_slot(rdai, 2, 1); /* default */
 -
 -              for (io_i = 0;; io_i++) {
 -                      playback = of_parse_phandle(dai_np, "playback", io_i);
 -                      capture  = of_parse_phandle(dai_np, "capture", io_i);
 -
 -                      if (!playback && !capture)
 -                              break;
 -
 -                      rsnd_parse_connect_ssi(rdai, playback, capture);
 -                      rsnd_parse_connect_src(rdai, playback, capture);
 -                      rsnd_parse_connect_ctu(rdai, playback, capture);
 -                      rsnd_parse_connect_mix(rdai, playback, capture);
 -                      rsnd_parse_connect_dvc(rdai, playback, capture);
 -
 -                      of_node_put(playback);
 -                      of_node_put(capture);
 +      if (is_graph) {
 +              for_each_endpoint_of_node(dai_node, dai_np) {
 +                      __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
 +                      rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
 +                      dai_i++;
                }
 -
 -              dai_i++;
 -
 -              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" : "  --   ");
 +      } else {
 +              for_each_child_of_node(dai_node, dai_np)
 +                      __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
        }
  
 -      ret = 0;
 -
 -rsnd_dai_probe_done:
 -      of_node_put(dai_node);
 -
 -      return ret;
 +      return 0;
  }
  
  /*
@@@ -968,14 -965,12 +1019,14 @@@ static int rsnd_hw_params(struct snd_pc
  
  static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
  {
 -      struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
 +      snd_pcm_uframes_t pointer = 0;
 +
 +      rsnd_dai_call(pointer, io, &pointer);
  
 -      return bytes_to_frames(runtime, io->byte_pos);
 +      return pointer;
  }
  
  static struct snd_pcm_ops rsnd_pcm_ops = {
diff --combined sound/soc/sh/rcar/gen.c
index 99f93a17511e57ad2244466a09244c7a270cbe79,4b0980728e13ec75f18ac07135ab4971290b5310..ee00e3516911ef32b6fbdd3113f49776231b96a1
@@@ -219,8 -219,6 +219,8 @@@ static int rsnd_gen2_probe(struct rsnd_
                RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
                RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
                RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
 +              RSND_GEN_S_REG(HDMI0_SEL,       0x9e0),
 +              RSND_GEN_S_REG(HDMI1_SEL,       0x9e4),
  
                /* FIXME: it needs SSI_MODE2/3 in the future */
                RSND_GEN_M_REG(SSI_BUSIF_MODE,  0x0,    0x80),
                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
                RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
+               RSND_GEN_M_REG(CMD_BUSIF_MODE,  0x184,  0x20),
                RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188,  0x20),
                RSND_GEN_M_REG(CMD_ROUTE_SLCT,  0x18c,  0x20),
                RSND_GEN_M_REG(CMD_CTRL,        0x190,  0x20),
diff --combined sound/soc/sh/rcar/rsnd.h
index d4f89d5e6994f9841d123b746cc4d367c1f8dd6a,323af41ecfcb8ffea222f25fbe6c524968f29fd5..bd8def0bc212e50ee19681e34fac7c31f1f104ea
@@@ -18,7 -18,6 +18,7 @@@
  #include <linux/list.h>
  #include <linux/module.h>
  #include <linux/of_device.h>
 +#include <linux/of_graph.h>
  #include <linux/of_irq.h>
  #include <linux/sh_dma.h>
  #include <linux/workqueue.h>
@@@ -74,6 -73,7 +74,7 @@@ enum rsnd_reg 
        RSND_REG_SCU_SYS_INT_EN0,
        RSND_REG_SCU_SYS_INT_EN1,
        RSND_REG_CMD_CTRL,
+       RSND_REG_CMD_BUSIF_MODE,
        RSND_REG_CMD_BUSIF_DALIGN,
        RSND_REG_CMD_ROUTE_SLCT,
        RSND_REG_CMDOUT_TIMSEL,
        RSND_REG_SSI_SYS_STATUS5,
        RSND_REG_SSI_SYS_STATUS6,
        RSND_REG_SSI_SYS_STATUS7,
 +      RSND_REG_HDMI0_SEL,
 +      RSND_REG_HDMI1_SEL,
  
        /* SSI */
        RSND_REG_SSICR,
@@@ -207,6 -205,7 +208,7 @@@ void rsnd_bset(struct rsnd_priv *priv, 
                    u32 mask, u32 data);
  u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
  u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
  
  /*
   *    R-Car DMA
@@@ -269,9 -268,6 +271,9 @@@ struct rsnd_mod_ops 
                         struct rsnd_dai_stream *io,
                         struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *hw_params);
 +      int (*pointer)(struct rsnd_mod *mod,
 +                     struct rsnd_dai_stream *io,
 +                     snd_pcm_uframes_t *pointer);
        int (*fallback)(struct rsnd_mod *mod,
                        struct rsnd_dai_stream *io,
                        struct rsnd_priv *priv);
@@@ -309,7 -305,6 +311,7 @@@ struct rsnd_mod 
   * H  0: pcm_new
   * H  0: fallback
   * H  0: hw_params
 + * H  0: pointer
   */
  #define __rsnd_mod_shift_nolock_start 0
  #define __rsnd_mod_shift_nolock_stop  0
  #define __rsnd_mod_shift_pcm_new      28 /* always called */
  #define __rsnd_mod_shift_fallback     28 /* always called */
  #define __rsnd_mod_shift_hw_params    28 /* always called */
 +#define __rsnd_mod_shift_pointer      28 /* always called */
  
  #define __rsnd_mod_add_probe          0
  #define __rsnd_mod_add_remove         0
  #define __rsnd_mod_add_pcm_new                0
  #define __rsnd_mod_add_fallback               0
  #define __rsnd_mod_add_hw_params      0
 +#define __rsnd_mod_add_pointer                0
  
  #define __rsnd_mod_call_probe         0
  #define __rsnd_mod_call_remove                0
  #define __rsnd_mod_call_pcm_new               0
  #define __rsnd_mod_call_fallback      0
  #define __rsnd_mod_call_hw_params     0
 +#define __rsnd_mod_call_pointer               0
  #define __rsnd_mod_call_nolock_start  0
  #define __rsnd_mod_call_nolock_stop   1
  
@@@ -428,6 -420,7 +430,6 @@@ struct rsnd_dai_stream 
        char name[RSND_DAI_NAME_SIZE];
        struct snd_pcm_substream *substream;
        struct rsnd_mod *mod[RSND_MOD_MAX];
 -      struct rsnd_dai_path_info *info; /* rcar_snd.h */
        struct rsnd_dai *rdai;
        u32 parent_ssi_status;
        int byte_pos;
@@@ -484,6 -477,7 +486,6 @@@ int rsnd_dai_pointer_offset(struct rsnd
  int rsnd_dai_connect(struct rsnd_mod *mod,
                     struct rsnd_dai_stream *io,
                     enum rsnd_mod_type type);
 -#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
  
  /*
   *    R-Car Gen1/Gen2
@@@ -654,13 -648,6 +656,13 @@@ int rsnd_ssi_is_dma_mode(struct rsnd_mo
  int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
  u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
  
 +#define RSND_SSI_HDMI_PORT0   0xf0
 +#define RSND_SSI_HDMI_PORT1   0xf1
 +int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
 +void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
 +                                  struct device_node *endpoint,
 +                                  int dai_i);
 +
  #define rsnd_ssi_is_pin_sharing(io)   \
        __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
  int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
diff --combined sound/soc/sh/rcar/src.c
index e4bde0c8d93a69bdfa794948364644274160028f,76a477a3ccb5d88e18fd8398d9ad2b2616a99f48..8dbe9ebcbff12b9400bc82c7615e698bb4d07222
  
  #define SRC_NAME "src"
  
 -/* SRCx_STATUS */
 -#define OUF_SRCO      ((1 << 12) | (1 << 13))
 -#define OUF_SRCI      ((1 <<  9) | (1 <<  8))
 -
  /* SCU_SYSTEM_STATUS0/1 */
  #define OUF_SRC(id)   ((1 << (id + 16)) | (1 << id))
  
@@@ -51,6 -55,20 +51,6 @@@ struct rsnd_src 
   *
   */
  
 -/*
 - * src.c is caring...
 - *
 - * Gen1
 - *
 - * [mem] -> [SRU] -> [SSI]
 - *        |--------|
 - *
 - * Gen2
 - *
 - * [mem] -> [SRC] -> [SSIU] -> [SSI]
 - *        |-----------------|
 - */
 -
  static void rsnd_src_activation(struct rsnd_mod *mod)
  {
        rsnd_mod_write(mod, SRC_SWRSR, 0);
@@@ -172,11 -190,13 +172,13 @@@ static void rsnd_src_set_convert_rate(s
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       int is_play = rsnd_io_is_play(io);
        int use_src = 0;
        u32 fin, fout;
        u32 ifscr, fsrate, adinr;
        u32 cr, route;
        u32 bsdsr, bsisr;
+       u32 i_busif, o_busif, tmp;
        uint ratio;
  
        if (!runtime)
                break;
        }
  
+       /* BUSIF_MODE */
+       tmp = rsnd_get_busif_shift(io, mod);
+       i_busif = ( is_play ? tmp : 0) | 1;
+       o_busif = (!is_play ? tmp : 0) | 1;
        rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
  
        rsnd_mod_write(mod, SRC_SRCIR, 1);      /* initialize */
        rsnd_mod_write(mod, SRC_BSISR, bsisr);
        rsnd_mod_write(mod, SRC_SRCIR, 0);      /* cancel initialize */
  
-       rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
-       rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
+       rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);
+       rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif);
        rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
  
        rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
diff --combined sound/soc/sh/rcar/ssi.c
index 2363d0beeafd3d5b24b998ddbdfb25090308e707,91e5c07911b4a5b14364becf64c568d7a61cc1c4..59ca6e3f46bca88be123d781f23fa5f57ef74ac5
@@@ -11,7 -11,6 +11,7 @@@
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
 +#include <sound/simple_card_utils.h>
  #include <linux/delay.h>
  #include "rsnd.h"
  #define RSND_SSI_NAME_SIZE 16
@@@ -82,8 -81,6 +82,8 @@@ struct rsnd_ssi 
  /* flags */
  #define RSND_SSI_CLK_PIN_SHARE                (1 << 0)
  #define RSND_SSI_NO_BUSIF             (1 << 1) /* SSI+DMA without BUSIF */
 +#define RSND_SSI_HDMI0                        (1 << 2) /* for HDMI0 */
 +#define RSND_SSI_HDMI1                        (1 << 3) /* for HDMI1 */
  
  #define for_each_rsnd_ssi(pos, priv, i)                                       \
        for (i = 0;                                                     \
  #define rsnd_ssi_is_run_mods(mod, io) \
        (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
  
 +int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
 +{
 +      struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
 +      struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 +
 +      if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0)
 +              return RSND_SSI_HDMI_PORT0;
 +
 +      if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1)
 +              return RSND_SSI_HDMI_PORT1;
 +
 +      return 0;
 +}
 +
  int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
  {
        struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
@@@ -319,7 -302,7 +319,7 @@@ static void rsnd_ssi_config_init(struc
         * always use 32bit system word.
         * see also rsnd_ssi_master_clk_enable()
         */
-       cr_own = FORCE | SWL_32 | PDTA;
+       cr_own = FORCE | SWL_32;
  
        if (rdai->bit_clk_inv)
                cr_own |= SCKP;
@@@ -567,6 -550,13 +567,13 @@@ static void __rsnd_ssi_interrupt(struc
                struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
                u32 *buf = (u32 *)(runtime->dma_area +
                                   rsnd_dai_pointer_offset(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
                 * see rsnd_ssi_init()
                 */
                if (rsnd_io_is_play(io))
-                       rsnd_mod_write(mod, SSITDR, *buf);
+                       rsnd_mod_write(mod, SSITDR, (*buf) << shift);
                else
-                       *buf = rsnd_mod_read(mod, SSIRDR);
+                       *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
  
                elapsed = rsnd_dai_pointer_update(io, sizeof(*buf));
        }
@@@ -685,17 -675,6 +692,17 @@@ static int rsnd_ssi_common_probe(struc
        return ret;
  }
  
 +static int rsnd_ssi_pointer(struct rsnd_mod *mod,
 +                          struct rsnd_dai_stream *io,
 +                          snd_pcm_uframes_t *pointer)
 +{
 +      struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 +
 +      *pointer = bytes_to_frames(runtime, io->byte_pos);
 +
 +      return 0;
 +}
 +
  static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .name   = SSI_NAME,
        .probe  = rsnd_ssi_common_probe,
        .start  = rsnd_ssi_start,
        .stop   = rsnd_ssi_stop,
        .irq    = rsnd_ssi_irq,
 +      .pointer= rsnd_ssi_pointer,
        .pcm_new = rsnd_ssi_pcm_new,
        .hw_params = rsnd_ssi_hw_params,
  };
@@@ -738,6 -716,11 +745,11 @@@ static int rsnd_ssi_dma_remove(struct r
                               struct rsnd_priv *priv)
  {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+       /* Do nothing for SSI parent mod */
+       if (ssi_parent_mod == mod)
+               return 0;
  
        /* PIO will request IRQ again */
        free_irq(ssi->irq, mod);
@@@ -803,6 -786,13 +815,6 @@@ int rsnd_ssi_is_dma_mode(struct rsnd_mo
  }
  
  
 -/*
 - *            Non SSI
 - */
 -static struct rsnd_mod_ops rsnd_ssi_non_ops = {
 -      .name   = SSI_NAME,
 -};
 -
  /*
   *            ssi mod function
   */
@@@ -857,47 -847,6 +869,47 @@@ void rsnd_parse_connect_ssi(struct rsnd
        of_node_put(node);
  }
  
 +static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
 +                                           struct rsnd_dai_stream *io,
 +                                           struct device_node *remote_ep)
 +{
 +      struct device *dev = rsnd_priv_to_dev(priv);
 +      struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
 +      struct rsnd_ssi *ssi;
 +
 +      if (!mod)
 +              return;
 +
 +      ssi  = rsnd_mod_to_ssi(mod);
 +
 +      if (strstr(remote_ep->full_name, "hdmi0")) {
 +              ssi->flags |= RSND_SSI_HDMI0;
 +              dev_dbg(dev, "%s[%d] connected to HDMI0\n",
 +                       rsnd_mod_name(mod), rsnd_mod_id(mod));
 +      }
 +
 +      if (strstr(remote_ep->full_name, "hdmi1")) {
 +              ssi->flags |= RSND_SSI_HDMI1;
 +              dev_dbg(dev, "%s[%d] connected to HDMI1\n",
 +                      rsnd_mod_name(mod), rsnd_mod_id(mod));
 +      }
 +}
 +
 +void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
 +                                  struct device_node *endpoint,
 +                                  int dai_i)
 +{
 +      struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
 +      struct device_node *remote_ep;
 +
 +      remote_ep = of_graph_get_remote_endpoint(endpoint);
 +      if (!remote_ep)
 +              return;
 +
 +      __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
 +      __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture,  remote_ep);
 +}
 +
  struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
  {
        if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@@ -1003,6 -952,7 +1015,6 @@@ int rsnd_ssi_probe(struct rsnd_priv *pr
                        goto rsnd_ssi_probe_done;
                }
  
 -              ops = &rsnd_ssi_non_ops;
                if (of_property_read_bool(np, "pio-transfer"))
                        ops = &rsnd_ssi_pio_ops;
                else
diff --combined sound/soc/sh/rcar/ssiu.c
index 13d648ef1ed6fb56a97f14d29c063c29fbb8fcef,512d238b79e2895f13a4b1b7be3e145859a65280..bed2c9c0004b8fb0c6ccb1d9215443f4846e1eba
@@@ -123,7 -123,6 +123,7 @@@ static int rsnd_ssiu_init_gen2(struct r
                               struct rsnd_dai_stream *io,
                               struct rsnd_priv *priv)
  {
 +      int hdmi = rsnd_ssi_hdmi_port(io);
        int ret;
  
        ret = rsnd_ssiu_init(mod, io, priv);
                               (rsnd_io_is_play(io) ?
                                rsnd_runtime_channel_after_ctu(io) :
                                rsnd_runtime_channel_original(io)));
-               rsnd_mod_write(mod, SSI_BUSIF_MODE,  1);
+               rsnd_mod_write(mod, SSI_BUSIF_MODE,
+                              rsnd_get_busif_shift(io, mod) | 1);
                rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
                               rsnd_get_dalign(mod, io));
        }
  
 +      if (hdmi) {
 +              enum rsnd_mod_type rsnd_ssi_array[] = {
 +                      RSND_MOD_SSIM1,
 +                      RSND_MOD_SSIM2,
 +                      RSND_MOD_SSIM3,
 +              };
 +              struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
 +              struct rsnd_mod *pos;
 +              u32 val;
 +              int i, shift;
 +
 +              i = rsnd_mod_id(ssi_mod);
 +
 +              /* output all same SSI as default */
 +              val =   i << 16 |
 +                      i << 20 |
 +                      i << 24 |
 +                      i << 28 |
 +                      i;
 +
 +              for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
 +                      shift   = (i * 4) + 16;
 +                      val     = (val & ~(0xF << shift)) |
 +                              rsnd_mod_id(pos) << shift;
 +              }
 +
 +              switch (hdmi) {
 +              case RSND_SSI_HDMI_PORT0:
 +                      rsnd_mod_write(mod, HDMI0_SEL, val);
 +                      break;
 +              case RSND_SSI_HDMI_PORT1:
 +                      rsnd_mod_write(mod, HDMI1_SEL, val);
 +                      break;
 +              }
 +      }
 +
        return 0;
  }