@@ -271,6 +271,19 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
if (ctu_mod) {
u32 converted_chan = rsnd_io_converted_chan(io);
+ /*
+ * !! Note !!
+ *
+ * converted_chan will be used for CTU,
+ * or TDM Split mode.
+ * User shouldn't use CTU with TDM Split mode.
+ */
+ if (rsnd_runtime_is_tdm_split(io)) {
+ struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+ dev_err(dev, "CTU and TDM Split should be used\n");
+ }
+
if (converted_chan)
return converted_chan;
}
@@ -313,6 +326,11 @@ int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
return rsnd_runtime_channel_for_ssi(io) >= 6;
}
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
+{
+ return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
+}
+
/*
* ADINR function
*/
@@ -784,6 +802,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
switch (slots) {
case 2:
+ /* TDM Split Mode */
case 6:
case 8:
/* TDM Extend Mode */
@@ -1004,6 +1023,7 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
struct device_node *endpoint)
{
struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *remote_port = of_graph_get_remote_port(endpoint);
struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint);
if (!rsnd_io_to_mod_ssi(io))
@@ -1020,6 +1040,15 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
rsnd_flags_set(io, RSND_STREAM_HDMI1);
dev_dbg(dev, "%s connected to HDMI1\n", io->name);
}
+
+ /*
+ * This driver assumes that it is TDM Split mode
+ * if remote node has multi endpoint
+ */
+ if (of_get_child_count(remote_port) > 1) {
+ rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+ dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+ }
}
void rsnd_parse_connect_common(struct rsnd_dai *rdai,
@@ -433,6 +433,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
struct snd_pcm_hw_params *params);
int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
/*
* DT
@@ -467,6 +468,7 @@ struct rsnd_dai_stream {
/* flags */
#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */
#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */
+#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
@@ -298,6 +298,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
}
+ if (rsnd_runtime_is_tdm_split(io))
+ chan = rsnd_io_converted_chan(io);
+
main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) {
dev_err(dev, "unsupported clock rate\n");
@@ -360,9 +363,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
u32 cr_own = ssi->cr_own;
u32 cr_mode = ssi->cr_mode;
u32 wsr = ssi->wsr;
- int is_tdm;
+ int width;
+ int is_tdm, is_tdm_split;
- is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
@@ -381,7 +386,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
* rsnd_ssiu_init_gen2()
*/
wsr = ssi->wsr;
- if (is_tdm) {
+ if (is_tdm || is_tdm_split) {
wsr |= WS_MODE;
cr_own |= CHNL_8;
}
@@ -397,7 +402,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own |= TRMD;
cr_own &= ~DWL_MASK;
- switch (snd_pcm_format_width(runtime->format)) {
+ width = snd_pcm_format_width(runtime->format);
+ if (is_tdm_split) {
+ /*
+ * The SWL and DWL bits in SSICR should be fixed at 32-bit
+ * setting when TDM split mode.
+ * see datasheet
+ * Operation :: TDM Format Split Function (TDM Split Mode)
+ */
+ width = 32;
+ }
+
+ switch (width) {
case 8:
cr_own |= DWL_8;
break;
@@ -407,6 +423,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
case 24:
cr_own |= DWL_24;
break;
+ case 32:
+ cr_own |= DWL_32;
+ break;
}
if (rsnd_ssi_is_dma_mode(mod)) {
@@ -16,6 +16,10 @@ struct rsnd_ssiu {
int id_sub;
};
+/* SSI_MODE */
+#define TDM_EXT (1 << 0)
+#define TDM_SPLIT (1 << 8)
+
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
#define for_each_rsnd_ssiu(pos, priv, i) \
@@ -165,14 +169,15 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
ssiu->usrcnt++;
- if (rsnd_runtime_is_tdm(io)) {
- /*
- * TDM Extend Mode
- * see
- * rsnd_ssi_config_init()
- */
- mode = 0x1;
- }
+ /*
+ * TDM Extend/Split Mode
+ * see
+ * rsnd_ssi_config_init()
+ */
+ if (rsnd_runtime_is_tdm(io))
+ mode = TDM_EXT;
+ else if (rsnd_runtime_is_tdm_split(io))
+ mode = TDM_SPLIT;
rsnd_mod_write(mod, SSI_MODE, mode);