aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch315
1 files changed, 315 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch
new file mode 100644
index 0000000..0a6e504
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0061-ASoC-R-Car-add-tdm16-support-enable-tdm-for-ssi78.patch
@@ -0,0 +1,315 @@
+From 7e4907c9f824c1b52b4c2cf8be91d62c75839e39 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 24 Nov 2016 15:50:25 +0300
+Subject: [PATCH] ASoC: R-Car: add tdm16 support, enable tdm for ssi78
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/sh/rcar/adg.c | 13 ++++------
+ sound/soc/sh/rcar/core.c | 19 ++++++++++----
+ sound/soc/sh/rcar/gen.c | 4 +++
+ sound/soc/sh/rcar/rsnd.h | 3 +++
+ sound/soc/sh/rcar/ssi.c | 66 +++++++++++++++++++++++++++++++++++++++++-------
+ sound/soc/sh/rcar/ssiu.c | 11 +++++---
+ 6 files changed, 91 insertions(+), 25 deletions(-)
+
+diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
+index 85a33ac..a73b45c 100644
+--- a/sound/soc/sh/rcar/adg.c
++++ b/sound/soc/sh/rcar/adg.c
+@@ -46,15 +46,12 @@ struct rsnd_adg {
+ #define adg_mode_flags(adg) (adg->flags)
+
+ #define for_each_rsnd_clk(pos, adg, i) \
+- for (i = 0; \
+- (i < CLKMAX) && \
+- ((pos) = adg->clk[i]); \
+- i++)
++ for (i = 0; i < CLKMAX; i++) \
++ if (((pos) = adg->clk[i])) \
++
+ #define for_each_rsnd_clkout(pos, adg, i) \
+- for (i = 0; \
+- (i < CLKOUTMAX) && \
+- ((pos) = adg->clkout[i]); \
+- i++)
++ for (i = 0; i < CLKOUTMAX; i++) \
++ if (((pos) = adg->clkout[i]))
+ #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+
+ static u32 rsnd_adg_calculate_rbgx(unsigned long div)
+diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
+index 448072c..75e992f 100644
+--- a/sound/soc/sh/rcar/core.c
++++ b/sound/soc/sh/rcar/core.c
+@@ -277,7 +277,10 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
+
+ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
+ {
+- return rsnd_runtime_channel_for_ssi(io) >= 6;
++ if (rsnd_runtime_channel_for_ssi(io) < 6)
++ return 0;
++ else
++ return rsnd_runtime_channel_for_ssi(io);
+ }
+
+ /*
+@@ -322,8 +325,10 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+ target = cmd ? cmd : ssiu;
+ }
+
+- mask <<= runtime->channels * 4;
+- val = val & mask;
++ if (runtime->channels < 8) {
++ mask <<= runtime->channels * 4;
++ val = val & mask;
++ }
+
+ switch (runtime->sample_bits) {
+ case 16:
+@@ -680,6 +685,10 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ switch (slots) {
+ case 6:
+ /* TDM Extend Mode */
++ case 8:
++ /* TDM Mode */
++ case 16:
++ /* TDM16 Mode */
+ rsnd_set_slot(rdai, slots, 1);
+ break;
+ default:
+@@ -775,7 +784,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
+ drv->playback.rates = RSND_RATES;
+ drv->playback.formats = RSND_FMTS;
+ drv->playback.channels_min = 2;
+- drv->playback.channels_max = 6;
++ drv->playback.channels_max = 16;
+ drv->playback.stream_name = rdai->playback.name;
+
+ snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+@@ -783,7 +792,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
+ drv->capture.rates = RSND_RATES;
+ drv->capture.formats = RSND_FMTS;
+ drv->capture.channels_min = 2;
+- drv->capture.channels_max = 6;
++ drv->capture.channels_max = 16;
+ drv->capture.stream_name = rdai->capture.name;
+
+ rdai->playback.rdai = rdai;
+diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
+index e785fe94..fce2a7b 100644
+--- a/sound/soc/sh/rcar/gen.c
++++ b/sound/soc/sh/rcar/gen.c
+@@ -334,6 +334,9 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
+ RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
+ RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
+ RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
++ RSND_GEN_M_REG(SSIFMR, 0x24, 0x40),
++ RSND_GEN_M_REG(SSIFSR, 0x28, 0x40),
++ RSND_GEN_M_REG(SSICRE, 0x30, 0x40),
+ };
+ int ret_ssiu;
+ int ret_scu;
+@@ -407,6 +410,7 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
+ ret = rsnd_gen1_probe(priv);
+ else if (rsnd_is_gen2(priv))
+ ret = rsnd_gen2_probe(priv);
++ /* TODO: add gen3 */
+
+ if (ret < 0)
+ dev_err(dev, "unknown generation R-Car sound device\n");
+diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
+index bf9596b..8ccd9d0 100644
+--- a/sound/soc/sh/rcar/rsnd.h
++++ b/sound/soc/sh/rcar/rsnd.h
+@@ -166,6 +166,9 @@ enum rsnd_reg {
+ RSND_REG_SSITDR,
+ RSND_REG_SSIRDR,
+ RSND_REG_SSIWSR,
++ RSND_REG_SSIFMR,
++ RSND_REG_SSIFSR,
++ RSND_REG_SSICRE,
+
+ RSND_REG_MAX,
+ };
+diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
+index 630cb6b..62abb58 100644
+--- a/sound/soc/sh/rcar/ssi.c
++++ b/sound/soc/sh/rcar/ssi.c
+@@ -35,7 +35,13 @@
+ #define DWL_24 (5 << 19) /* Data Word Length */
+ #define DWL_32 (6 << 19) /* Data Word Length */
+
+-#define SWL_32 (3 << 16) /* R/W System Word Length */
++#define SWL_16 (1 << 16) /* R/W System Word Length 16 bit */
++#define SWL_24 (2 << 16) /* R/W System Word Length 24 bit */
++#define SWL_32 (3 << 16) /* R/W System Word Length 32 bit */
++#define SWL_48 (4 << 16) /* R/W System Word Length 48 bit */
++#define SWL_64 (5 << 16) /* R/W System Word Length 64 bit */
++#define SWL_128 (6 << 16) /* R/W System Word Length 128 bit */
++#define SWL_256 (7 << 16) /* R/W System Word Length 256 bit */
+ #define SCKD (1 << 15) /* Serial Bit Clock Direction */
+ #define SWSD (1 << 14) /* Serial WS Direction */
+ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */
+@@ -61,6 +67,11 @@
+ #define CONT (1 << 8) /* WS Continue Function */
+ #define WS_MODE (1 << 0) /* WS Mode */
+
++/*
++ * SSICRE
++ */
++#define CHNL_16 (1 << 0) /* Channels */
++
+ #define SSI_NAME "ssi"
+
+ struct rsnd_ssi {
+@@ -71,6 +82,7 @@ struct rsnd_ssi {
+ u32 cr_own;
+ u32 cr_clk;
+ u32 cr_mode;
++ u32 cre_own;
+ u32 wsr;
+ int chan;
+ int rate;
+@@ -224,8 +236,12 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
+
+ /*
+ * Find best clock, and try to start ADG
++ *
++ * Start with j = 1 because:
++ * "CKDV = 000 is invalid when WS_MODE = 1 or CONT = 1 in the WS
++ * Mode Register."
+ */
+- for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
++ for (j = 1; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+ /*
+ * It will set SSIWSR.CONT here, but SSICR.CKDV = 000
+@@ -239,15 +255,23 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
+ /*
+ * this driver is assuming that
+ * system word is 32bit x chan
+- * see rsnd_ssi_init()
++ *
++ * Expect:
++ * TDM 16ch mode where SWL should be 16 bit
+ */
+- main_rate = rate * 32 * chan * ssi_clk_mul_table[j];
++ if (chan != 16)
++ main_rate = rate * 32 * chan * ssi_clk_mul_table[j];
++ else
++ main_rate = rate * 16 * chan * ssi_clk_mul_table[j];
+
+ ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
+ if (0 == ret) {
+- ssi->cr_clk = FORCE | SWL_32 |
++ ssi->cr_clk = FORCE |
+ SCKD | SWSD | CKDV(j);
+- ssi->wsr = CONT;
++ if (chan != 16)
++ ssi->cr_clk |= SWL_32;
++ else
++ ssi->cr_clk |= SWL_16;
+
+ ssi->rate = rate;
+
+@@ -288,10 +312,13 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
+ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
+ {
++ struct rsnd_priv *priv = rsnd_io_to_priv(io);
++ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ u32 cr_own;
++ u32 cre_own;
+ u32 cr_mode;
+ u32 wsr;
+ int is_tdm;
+@@ -301,12 +328,24 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
+ /*
+ * always use 32bit system word.
+ * see also rsnd_ssi_master_clk_enable()
++ * NOPE!
+ */
+- cr_own = FORCE | SWL_32 | PDTA;
++ cr_own = FORCE | PDTA;
++ cre_own = 0;
++
++ /*
++ * TDM16 mode can handle only 16bit data
++ */
++ if (rsnd_runtime_channel_for_ssi(io) != 16)
++ cr_own |= SWL_32;
++ else
++ cr_own |= SWL_16;
++
++ cre_own = 0;
+
+ if (rdai->bit_clk_inv)
+ cr_own |= SCKP;
+- if (rdai->frm_clk_inv ^ is_tdm)
++ if (rdai->frm_clk_inv ^ (!!is_tdm))
+ cr_own |= SWSP;
+ if (rdai->data_alignment)
+ cr_own |= SDTA;
+@@ -337,12 +376,20 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
+ * rsnd_ssiu_init_gen2()
+ */
+ wsr = ssi->wsr;
+- if (is_tdm) {
++ if (is_tdm == 8) {
+ wsr |= WS_MODE;
+ cr_own |= CHNL_8;
++ } else if (is_tdm == 16) {
++ wsr |= WS_MODE;
++ cre_own |= CHNL_16;
++ } else if (is_tdm) {
++ dev_err(dev, "%s[%d] invalid tdm channels %d\n",
++ rsnd_mod_name(mod),
++ rsnd_mod_id(mod), is_tdm);
+ }
+
+ ssi->cr_own = cr_own;
++ ssi->cre_own = cre_own;
+ ssi->cr_mode = cr_mode;
+ ssi->wsr = wsr;
+ }
+@@ -352,6 +399,7 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ rsnd_mod_write(mod, SSIWSR, ssi->wsr);
++ rsnd_mod_write(mod, SSICRE, ssi->cre_own);
+ rsnd_mod_write(mod, SSICR, ssi->cr_own |
+ ssi->cr_clk |
+ ssi->cr_mode); /* without EN */
+diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
+index 3f95d6b..19f5f5e 100644
+--- a/sound/soc/sh/rcar/ssiu.c
++++ b/sound/soc/sh/rcar/ssiu.c
+@@ -61,13 +61,18 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
+ case 4:
+ shift = 16;
+ break;
++ case 8:
++ /* ignore? */
++ break;
+ default:
+ return -EINVAL;
+ }
+
+- mask1 |= 0x3 << shift;
+- val1 = rsnd_rdai_is_clk_master(rdai) ?
+- 0x2 << shift : 0x1 << shift;
++ if (shift >= 0) {
++ mask1 |= 0x3 << shift;
++ val1 = rsnd_rdai_is_clk_master(rdai) ?
++ 0x2 << shift : 0x1 << shift;
++ }
+
+ } else if (multi_ssi_slaves) {
+
+--
+1.9.1
+