tristate "R-Car series SRU/SCU/SSIU/SSI support"
        depends on COMMON_CLK
        depends on OF || COMPILE_TEST
-       select SND_SIMPLE_CARD
+       select SND_SIMPLE_CARD_UTILS
        select REGMAP_MMIO
        help
          This option enables R-Car SRU/SCU/SSIU/SSI sound support
 
         */
        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);
+               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++;
+               }
        } else {
                for_each_child_of_node(dai_node, dai_np)
                        __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
 
                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_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,
 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);
 
  * 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
 /* 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);
        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)))
 
                               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_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;
 }