[alsa-devel] [PATCH 3/3] ASoC: rsnd: add HDMI output support
Kuninori Morimoto
kuninori.morimoto.gx at renesas.com
Thu May 18 03:28:22 CEST 2017
From: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
Renesas R-Car Gen3 can output HDMI sound if SSIU/SSI are connected to
R-Car built-in HDMI device (R-Car Gen3 built-in HDMI device will be
controlled by DRM/KMS driver).
If SSIx was connected to HDMI0/1 on DT, SSI driver will detect it
automatically by this patch.
Note is that now Renesas R-Car sound driver is assuming that it is
using OF-graph base simple card for HDMI sound.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
---
sound/soc/sh/Kconfig | 2 +-
sound/soc/sh/rcar/core.c | 7 ++++--
sound/soc/sh/rcar/gen.c | 2 ++
sound/soc/sh/rcar/rsnd.h | 9 ++++++++
sound/soc/sh/rcar/ssi.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
sound/soc/sh/rcar/ssiu.c | 37 ++++++++++++++++++++++++++++++
6 files changed, 112 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 147ebec..1aa5cd7 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -38,7 +38,7 @@ config SND_SOC_RCAR
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
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6825325..373cabb 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -960,8 +960,11 @@ 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);
+ 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);
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 4b09807..ee00e35 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
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),
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index b6299dc..cc929fc 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -171,6 +171,8 @@ enum rsnd_reg {
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,
@@ -652,6 +654,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
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 --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index c224695..e23fcab 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -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
@@ -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; \
@@ -99,6 +102,20 @@ struct rsnd_ssi {
#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);
@@ -840,6 +857,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
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)))
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 512d238..bed2c9c 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
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);
@@ -150,6 +151,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
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;
}
--
1.9.1
More information about the Alsa-devel
mailing list