ASoC: rsnd: add HDMI output support
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@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
4d4b334bda
commit
7fa72cca39
6 changed files with 112 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -909,8 +909,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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -170,6 +170,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,
|
||||
|
@ -646,6 +648,13 @@ int rsnd_ssi_is_dma_mode(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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -835,6 +852,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)))
|
||||
|
|
|
@ -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);
|
||||
|
@ -149,6 +150,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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue