summaryrefslogtreecommitdiffstats
path: root/sound/soc/sh
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-10-22 23:26:37 +0200
committerTakashi Iwai <tiwai@suse.de>2018-10-22 23:26:37 +0200
commit5e3cdecf7834a764b9d24f6e696adf3e03813fab (patch)
tree2a1083ca53de6992b04d5026f6cb3310adccac04 /sound/soc/sh
parentb5a229350b72b929edac5ba77c825f8ebb413533 (diff)
parent65dfb6d6dd2850f3f99f08536d2b14190350c854 (diff)
downloadtalos-obmc-linux-5e3cdecf7834a764b9d24f6e696adf3e03813fab.tar.gz
talos-obmc-linux-5e3cdecf7834a764b9d24f6e696adf3e03813fab.zip
Merge tag 'asoc-v5.0' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v5.0/v4.20 As ever there's a lot of small and driver specific changes going on here, but we do also have some relatively large changes in the core thanks to the hard work of Charles and Morimoto-san: - More component transitions from Morimoto-san, I think we're about finished with this. Thanks for all the hard work! - Morimoto-san also added a bunch of for_each_foo macros - A bunch of cleanups and fixes for DAPM from Charles. - MCLK support for several different devices, including CS42L51, STM32 SAI, and MAX98373. - Support for Allwinner A64 CODEC analog, Intel boards with DA7219 and MAX98927, Meson AXG PDM inputs, Nuvoton NAU8822, Renesas R8A7744 and TI PCM3060.
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/hac.c3
-rw-r--r--sound/soc/sh/rcar/adg.c4
-rw-r--r--sound/soc/sh/rcar/core.c124
-rw-r--r--sound/soc/sh/rcar/ctu.c2
-rw-r--r--sound/soc/sh/rcar/dma.c109
-rw-r--r--sound/soc/sh/rcar/gen.c33
-rw-r--r--sound/soc/sh/rcar/rsnd.h63
-rw-r--r--sound/soc/sh/rcar/src.c2
-rw-r--r--sound/soc/sh/rcar/ssi.c112
-rw-r--r--sound/soc/sh/rcar/ssiu.c92
10 files changed, 348 insertions, 196 deletions
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index c2b496398e6b..17622ceb98c0 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -319,13 +319,12 @@ static int hac_soc_platform_probe(struct platform_device *pdev)
if (ret != 0)
return ret;
- return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+ return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
}
static int hac_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 051f96405346..28327dd2c6cb 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -582,7 +582,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
int i;
for_each_rsnd_clk(clk, adg, i)
- dev_dbg(dev, "%s : %p : %ld\n",
+ dev_dbg(dev, "%s : %pa : %ld\n",
clk_name[i], clk, clk_get_rate(clk));
dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
@@ -595,7 +595,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
* by BRGCKR::BRGCKR_31
*/
for_each_rsnd_clkout(clk, adg, i)
- dev_dbg(dev, "clkout %d : %p : %ld\n", i,
+ dev_dbg(dev, "clkout %d : %pa : %ld\n", i,
clk, clk_get_rate(clk));
}
#else
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index d23c2bbff0cf..f930f51b686f 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -102,7 +102,9 @@
#include "rsnd.h"
#define RSND_RATES SNDRV_PCM_RATE_8000_192000
-#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
static const struct of_device_id rsnd_of_match[] = {
{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
@@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct device *dev = rsnd_priv_to_dev(priv);
switch (snd_pcm_format_width(runtime->format)) {
+ case 8:
+ return 16 << 16;
case 16:
return 8 << 16;
case 24:
@@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
target = cmd ? cmd : ssiu;
}
- /* Non target mod or 24bit data needs normal DALIGN */
+ /* Non target mod or non 16bit needs normal DALIGN */
if ((snd_pcm_format_width(runtime->format) != 16) ||
(mod != target))
return 0x76543210;
@@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
* HW 24bit data is located as 0x******00
*
*/
- if (snd_pcm_format_width(runtime->format) == 16)
+ if (snd_pcm_format_width(runtime->format) != 24)
return 0;
for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
@@ -540,6 +544,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
return rdai->ssi_lane;
}
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
+{
+ if (width > 0)
+ rdai->chan_width = width;
+
+ return rdai->chan_width;
+}
+
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
{
if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
@@ -681,6 +693,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
rdai->frm_clk_inv = 0;
break;
case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_DSP_B:
rdai->sys_delay = 1;
rdai->data_alignment = 0;
rdai->frm_clk_inv = 1;
@@ -690,6 +703,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
rdai->data_alignment = 1;
rdai->frm_clk_inv = 1;
break;
+ case SND_SOC_DAIFMT_DSP_A:
+ rdai->sys_delay = 0;
+ rdai->data_alignment = 0;
+ rdai->frm_clk_inv = 1;
+ break;
}
/* set clock inversion */
@@ -720,6 +738,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct device *dev = rsnd_priv_to_dev(priv);
+ switch (slot_width) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ /* use default */
+ slot_width = 32;
+ }
+
switch (slots) {
case 2:
case 6:
@@ -727,6 +755,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
/* TDM Extend Mode */
rsnd_rdai_channels_set(rdai, slots);
rsnd_rdai_ssi_lane_set(rdai, 1);
+ rsnd_rdai_width_set(rdai, slot_width);
break;
default:
dev_err(dev, "unsupported TDM slots (%d)\n", slots);
@@ -755,7 +784,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = {
192000,
};
-static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
+static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
unsigned int *list, int list_num,
struct snd_interval *baseline, struct snd_interval *iv)
{
@@ -772,14 +801,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
if (!snd_interval_test(iv, list[i]))
continue;
- rate = rsnd_ssi_clk_query(priv,
+ rate = rsnd_ssi_clk_query(rdai,
baseline->min, list[i], NULL);
if (rate > 0) {
p.min = min(p.min, list[i]);
p.max = max(p.max, list[i]);
}
- rate = rsnd_ssi_clk_query(priv,
+ rate = rsnd_ssi_clk_query(rdai,
baseline->max, list[i], NULL);
if (rate > 0) {
p.min = min(p.min, list[i]);
@@ -790,17 +819,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
return snd_interval_refine(iv, &p);
}
-static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule,
- int is_play)
+static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval ic;
- struct snd_soc_dai *dai = rule->private;
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
- struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+ struct rsnd_dai_stream *io = rule->private;
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
/*
* possible sampling rate limitation is same as
@@ -811,34 +837,19 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
- return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
+ return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
ARRAY_SIZE(rsnd_soc_hw_rate_list),
&ic, ir);
}
-static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_rate(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_rate(params, rule, 0);
-}
-
-static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule,
- int is_play)
+static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval ic;
- struct snd_soc_dai *dai = rule->private;
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
- struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+ struct rsnd_dai_stream *io = rule->private;
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
/*
* possible sampling rate limitation is same as
@@ -849,23 +860,11 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
- return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
+ return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
ARRAY_SIZE(rsnd_soc_hw_channels_list),
ir, &ic);
}
-static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_channels(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_channels(params, rule, 0);
-}
-
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
@@ -882,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int max_channels = rsnd_rdai_channels_get(rdai);
- int ret;
int i;
rsnd_dai_stream_init(io, substream);
@@ -922,25 +919,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- is_play ? rsnd_soc_hw_rule_rate_playback :
- rsnd_soc_hw_rule_rate_capture,
- dai,
+ rsnd_soc_hw_rule_rate,
+ is_play ? &rdai->playback : &rdai->capture,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- is_play ? rsnd_soc_hw_rule_channels_playback :
- rsnd_soc_hw_rule_channels_capture,
- dai,
+ rsnd_soc_hw_rule_channels,
+ is_play ? &rdai->playback : &rdai->capture,
SNDRV_PCM_HW_PARAM_RATE, -1);
}
- /*
- * call rsnd_dai_call without spinlock
- */
- ret = rsnd_dai_call(nolock_start, io, priv);
- if (ret < 0)
- rsnd_dai_call(nolock_stop, io, priv);
-
- return ret;
+ return 0;
}
static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
@@ -953,7 +941,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
/*
* call rsnd_dai_call without spinlock
*/
- rsnd_dai_call(nolock_stop, io, priv);
+ rsnd_dai_call(cleanup, io, priv);
rsnd_dai_stream_quit(io);
}
@@ -1083,6 +1071,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
rdai->capture.rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
+ rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
for (io_i = 0;; io_i++) {
playback = of_parse_phandle(dai_np, "playback", io_i);
@@ -1274,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ if (!runtime) {
+ dev_warn(dev, "Can't update kctrl when idle\n");
+ return 0;
+ }
- return !!runtime;
+ return 1;
}
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 6a55aa753003..ad702377a6c3 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -258,7 +258,7 @@ static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
struct snd_pcm_hw_params *be_params;
int stream = substream->stream;
- list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ for_each_dpcm_be(fe, stream, dpcm) {
be_params = &dpcm->hw_params;
if (params_channels(fe_params) != params_channels(be_params))
ctu->channels = params_channels(be_params);
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index d65ea7bc4dac..6d1947515dc8 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -106,9 +106,9 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
@@ -116,7 +116,7 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
/*
* DMAEngine release uses mutex lock.
* Thus, it shouldn't be called under spinlock.
- * Let's call it under nolock_start
+ * Let's call it under prepare
*/
if (dmaen->chan)
dma_release_channel(dmaen->chan);
@@ -126,23 +126,22 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
struct device *dev = rsnd_priv_to_dev(priv);
- if (dmaen->chan) {
- dev_err(dev, "it already has dma channel\n");
- return -EIO;
- }
+ /* maybe suspended */
+ if (dmaen->chan)
+ return 0;
/*
* DMAEngine request uses mutex lock.
* Thus, it shouldn't be called under spinlock.
- * Let's call it under nolock_start
+ * Let's call it under prepare
*/
dmaen->chan = rsnd_dmaen_request_channel(io,
dma->mod_from,
@@ -291,8 +290,8 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_dmaen_ops = {
.name = "audmac",
- .nolock_start = rsnd_dmaen_nolock_start,
- .nolock_stop = rsnd_dmaen_nolock_stop,
+ .prepare = rsnd_dmaen_prepare,
+ .cleanup = rsnd_dmaen_cleanup,
.start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop,
.pointer= rsnd_dmaen_pointer,
@@ -302,16 +301,26 @@ static struct rsnd_mod_ops rsnd_dmaen_ops = {
* Audio DMAC peri peri
*/
static const u8 gen2_id_table_ssiu[] = {
- 0x00, /* SSI00 */
- 0x04, /* SSI10 */
- 0x08, /* SSI20 */
- 0x0c, /* SSI3 */
- 0x0d, /* SSI4 */
- 0x0e, /* SSI5 */
- 0x0f, /* SSI6 */
- 0x10, /* SSI7 */
- 0x11, /* SSI8 */
- 0x12, /* SSI90 */
+ /* SSI00 ~ SSI07 */
+ 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c,
+ /* SSI10 ~ SSI17 */
+ 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40,
+ /* SSI20 ~ SSI27 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44,
+ /* SSI30 ~ SSI37 */
+ 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
+ /* SSI40 ~ SSI47 */
+ 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
+ /* SSI5 */
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI6 */
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI7 */
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI8 */
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI90 ~ SSI97 */
+ 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56,
};
static const u8 gen2_id_table_scu[] = {
0x2d, /* SCU_SRCI0 */
@@ -337,18 +346,23 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
const u8 *entry = NULL;
- int id = rsnd_mod_id(mod);
+ int id = 255;
int size = 0;
if (mod == ssi) {
+ int busif = rsnd_ssi_get_busif(io);
+
entry = gen2_id_table_ssiu;
size = ARRAY_SIZE(gen2_id_table_ssiu);
+ id = (rsnd_mod_id(mod) * 8) + busif;
} else if (mod == src) {
entry = gen2_id_table_scu;
size = ARRAY_SIZE(gen2_id_table_scu);
+ id = rsnd_mod_id(mod);
} else if (mod == dvc) {
entry = gen2_id_table_cmd;
size = ARRAY_SIZE(gen2_id_table_cmd);
+ id = rsnd_mod_id(mod);
}
if ((!entry) || (size <= id)) {
@@ -382,7 +396,7 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
+ dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
}
@@ -491,11 +505,11 @@ static struct rsnd_mod_ops rsnd_dmapp_ops = {
#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
-#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
-#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
+#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
-#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
-#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
+#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
@@ -521,6 +535,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
!!rsnd_io_to_mod_mix(io) ||
!!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
+ int busif = rsnd_ssi_get_busif(io);
struct dma_addr {
dma_addr_t out_addr;
dma_addr_t in_addr;
@@ -537,25 +552,35 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
},
/* SSI */
/* Capture */
- {{{ RDMA_SSI_O_N(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 } },
+ {{{ RDMA_SSI_O_N(ssi, id), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 } },
/* Playback */
- {{ 0, RDMA_SSI_I_N(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) } }
+ {{ 0, RDMA_SSI_I_N(ssi, id) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) } }
},
/* SSIU */
/* Capture */
- {{{ RDMA_SSIU_O_N(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 } },
+ {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 } },
/* Playback */
- {{ 0, RDMA_SSIU_I_N(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) } } },
+ {{ 0, RDMA_SSIU_I_N(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) } } },
};
+ /*
+ * FIXME
+ *
+ * We can't support SSI9-4/5/6/7, because its address is
+ * out of calculation rule
+ */
+ if ((id == 9) && (busif >= 4))
+ dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
+ id, busif);
+
/* it shouldn't happen */
if (use_cmd && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 0230301fe078..1f7881cc16b2 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -219,12 +219,33 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
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_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80),
- RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
- RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
- RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
+ RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
+ RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
+ RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
};
static const struct rsnd_regmap_field_conf conf_scu[] = {
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 8f7a0abfa751..4464d1d0a042 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -156,9 +156,30 @@ enum rsnd_reg {
RSND_REG_SSI_MODE2,
RSND_REG_SSI_CONTROL,
RSND_REG_SSI_CTRL,
- RSND_REG_SSI_BUSIF_MODE,
- RSND_REG_SSI_BUSIF_ADINR,
- RSND_REG_SSI_BUSIF_DALIGN,
+ RSND_REG_SSI_BUSIF0_MODE,
+ RSND_REG_SSI_BUSIF0_ADINR,
+ RSND_REG_SSI_BUSIF0_DALIGN,
+ RSND_REG_SSI_BUSIF1_MODE,
+ RSND_REG_SSI_BUSIF1_ADINR,
+ RSND_REG_SSI_BUSIF1_DALIGN,
+ RSND_REG_SSI_BUSIF2_MODE,
+ RSND_REG_SSI_BUSIF2_ADINR,
+ RSND_REG_SSI_BUSIF2_DALIGN,
+ RSND_REG_SSI_BUSIF3_MODE,
+ RSND_REG_SSI_BUSIF3_ADINR,
+ RSND_REG_SSI_BUSIF3_DALIGN,
+ RSND_REG_SSI_BUSIF4_MODE,
+ RSND_REG_SSI_BUSIF4_ADINR,
+ RSND_REG_SSI_BUSIF4_DALIGN,
+ RSND_REG_SSI_BUSIF5_MODE,
+ RSND_REG_SSI_BUSIF5_ADINR,
+ RSND_REG_SSI_BUSIF5_DALIGN,
+ RSND_REG_SSI_BUSIF6_MODE,
+ RSND_REG_SSI_BUSIF6_ADINR,
+ RSND_REG_SSI_BUSIF6_DALIGN,
+ RSND_REG_SSI_BUSIF7_MODE,
+ RSND_REG_SSI_BUSIF7_ADINR,
+ RSND_REG_SSI_BUSIF7_DALIGN,
RSND_REG_SSI_INT_ENABLE,
RSND_REG_SSI_SYS_STATUS0,
RSND_REG_SSI_SYS_STATUS1,
@@ -274,15 +295,12 @@ struct rsnd_mod_ops {
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
- int (*nolock_start)(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv);
- int (*nolock_stop)(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv);
int (*prepare)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
+ int (*cleanup)(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv);
};
struct rsnd_dai_stream;
@@ -300,9 +318,8 @@ struct rsnd_mod {
/*
* status
*
- * 0xH0000CBA
+ * 0xH0000CB0
*
- * A 0: nolock_start 1: nolock_stop
* B 0: init 1: quit
* C 0: start 1: stop
*
@@ -313,9 +330,8 @@ struct rsnd_mod {
* H 0: hw_params
* H 0: pointer
* H 0: prepare
+ * H 0: cleanup
*/
-#define __rsnd_mod_shift_nolock_start 0
-#define __rsnd_mod_shift_nolock_stop 0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8
@@ -328,11 +344,12 @@ struct rsnd_mod {
#define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_shift_pointer 28 /* always called */
#define __rsnd_mod_shift_prepare 28 /* always called */
+#define __rsnd_mod_shift_cleanup 28 /* always called */
#define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove 0
-#define __rsnd_mod_add_nolock_start 1
-#define __rsnd_mod_add_nolock_stop -1
+#define __rsnd_mod_add_prepare 0
+#define __rsnd_mod_add_cleanup 0
#define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1
@@ -342,10 +359,11 @@ struct rsnd_mod {
#define __rsnd_mod_add_fallback 0
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_add_pointer 0
-#define __rsnd_mod_add_prepare 0
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 0
+#define __rsnd_mod_call_prepare 0
+#define __rsnd_mod_call_cleanup 0
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
@@ -355,9 +373,6 @@ struct rsnd_mod {
#define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_pointer 0
-#define __rsnd_mod_call_nolock_start 0
-#define __rsnd_mod_call_nolock_stop 1
-#define __rsnd_mod_call_prepare 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_name(mod) ((mod)->ops->name)
@@ -438,6 +453,7 @@ struct rsnd_dai_stream {
char name[RSND_DAI_NAME_SIZE];
struct snd_pcm_substream *substream;
struct rsnd_mod *mod[RSND_MOD_MAX];
+ struct rsnd_mod *dma;
struct rsnd_dai *rdai;
struct device *dmac_dev; /* for IPMMU */
u32 parent_ssi_status;
@@ -467,6 +483,7 @@ struct rsnd_dai {
int max_channels; /* 2ch - 16ch */
int ssi_lane; /* 1lane - 4lane */
+ int chan_width; /* 16/24/32 bit width */
unsigned int clk_master:1;
unsigned int bit_clk_inv:1;
@@ -500,6 +517,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
int ssi_lane);
+#define rsnd_rdai_width_set(rdai, width) \
+ rsnd_rdai_width_ctrl(rdai, width)
+#define rsnd_rdai_width_get(rdai) \
+ rsnd_rdai_width_ctrl(rdai, 0)
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
@@ -692,6 +714,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+int rsnd_ssi_get_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
#define RSND_SSI_HDMI_PORT0 0xf0
@@ -709,7 +732,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *playback,
struct device_node *capture);
-unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx);
/*
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index beccfbac7581..cd38a43b976f 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -158,7 +158,7 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod,
struct snd_soc_dpcm *dpcm;
struct snd_pcm_hw_params *be_params;
- list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ for_each_dpcm_be(fe, stream, dpcm) {
be_params = &dpcm->hw_params;
if (params_rate(fe_params) != params_rate(be_params))
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 3f880ec66459..fcb4df23248c 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -42,7 +42,13 @@
#define DWL_24 (5 << 19) /* Data Word Length */
#define DWL_32 (6 << 19) /* Data Word Length */
+/*
+ * System word length
+ */
+#define SWL_16 (1 << 16) /* R/W System Word Length */
+#define SWL_24 (2 << 16) /* R/W System Word Length */
#define SWL_32 (3 << 16) /* R/W System Word Length */
+
#define SCKD (1 << 15) /* Serial Bit Clock Direction */
#define SWSD (1 << 14) /* Serial WS Direction */
#define SCKP (1 << 13) /* Serial Bit Clock Polarity */
@@ -72,7 +78,6 @@
struct rsnd_ssi {
struct rsnd_mod mod;
- struct rsnd_mod *dma;
u32 flags;
u32 cr_own;
@@ -145,6 +150,11 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
return use_busif;
}
+int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
+{
+ return 0; /* BUSIF0 only for now */
+}
+
static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, SSISR, 0);
@@ -220,14 +230,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
return 0;
}
-unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
+static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
+{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int width = rsnd_rdai_width_get(rdai);
+
+ switch (width) {
+ case 32: return SWL_32;
+ case 24: return SWL_24;
+ case 16: return SWL_16;
+ }
+
+ dev_err(dev, "unsupported slot width value: %d\n", width);
+ return 0;
+}
+
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx)
{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
int ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12,
};
int j, ret;
unsigned int main_rate;
+ int width = rsnd_rdai_width_get(rdai);
for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
@@ -240,12 +268,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
if (j == 0)
continue;
- /*
- * this driver is assuming that
- * system word is 32bit x chan
- * see rsnd_ssi_init()
- */
- main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j];
+ main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
ret = rsnd_adg_clk_query(priv, main_rate);
if (ret < 0)
@@ -289,10 +312,15 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return -EINVAL;
}
+ if (ssi->chan != chan) {
+ dev_err(dev, "SSI parent/child should use same chan\n");
+ return -EINVAL;
+ }
+
return 0;
}
- main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx);
+ main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) {
dev_err(dev, "unsupported clock rate\n");
return -EIO;
@@ -312,9 +340,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
* SSICR : FORCE, SCKD, SWSD
* SSIWSR : CONT
*/
- ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
+ ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
+ SCKD | SWSD | CKDV(idx);
ssi->wsr = CONT;
ssi->rate = rate;
+ ssi->chan = chan;
dev_dbg(dev, "%s[%d] outputs %u Hz\n",
rsnd_mod_name(mod),
@@ -340,6 +370,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
ssi->cr_clk = 0;
ssi->rate = 0;
+ ssi->chan = 0;
rsnd_adg_ssi_clk_stop(mod);
}
@@ -357,15 +388,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
is_tdm = rsnd_runtime_is_ssi_tdm(io);
- /*
- * always use 32bit system word.
- * see also rsnd_ssi_master_clk_enable()
- */
- cr_own |= FORCE | SWL_32;
+ cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
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;
@@ -373,6 +400,17 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own |= DEL;
/*
+ * TDM Mode
+ * see
+ * rsnd_ssiu_init_gen2()
+ */
+ wsr = ssi->wsr;
+ if (is_tdm) {
+ wsr |= WS_MODE;
+ cr_own |= CHNL_8;
+ }
+
+ /*
* We shouldn't exchange SWSP after running.
* This means, parent needs to care it.
*/
@@ -384,6 +422,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own &= ~DWL_MASK;
switch (snd_pcm_format_width(runtime->format)) {
+ case 8:
+ cr_own |= DWL_8;
+ break;
case 16:
cr_own |= DWL_16;
break;
@@ -399,16 +440,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_mode = DIEN; /* PIO : enable Data interrupt */
}
- /*
- * TDM Extend Mode
- * see
- * rsnd_ssiu_init_gen2()
- */
- wsr = ssi->wsr;
- if (is_tdm) {
- wsr |= WS_MODE;
- cr_own |= CHNL_8;
- }
init_end:
ssi->cr_own = cr_own;
ssi->cr_mode = cr_mode;
@@ -488,26 +519,16 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- int chan = params_channels(params);
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ unsigned int fmt_width = snd_pcm_format_width(params_format(params));
- /*
- * snd_pcm_ops::hw_params will be called *before*
- * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
- * in 1st call.
- */
- if (ssi->usrcnt) {
- /*
- * Already working.
- * It will happen if SSI has parent/child connection.
- * it is error if child <-> parent SSI uses
- * different channels.
- */
- if (ssi->chan != chan)
- return -EIO;
- }
+ if (fmt_width > rdai->chan_width) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
- ssi->chan = chan;
+ dev_err(dev, "invalid combination of slot-width and format-data-width\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -873,7 +894,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int ret;
/*
@@ -888,7 +908,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return ret;
/* SSI probe might be called many times in MUX multi path */
- ret = rsnd_dma_attach(io, mod, &ssi->dma);
+ ret = rsnd_dma_attach(io, mod, &io->dma);
return ret;
}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 016fbf5ac242..39b67643b5dc 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -10,9 +10,12 @@
struct rsnd_ssiu {
struct rsnd_mod mod;
+ u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
+ unsigned int usrcnt;
};
#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) \
for (i = 0; \
(i < rsnd_ssiu_nr(priv)) && \
@@ -120,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
int hdmi = rsnd_ssi_hdmi_port(io);
int ret;
u32 mode = 0;
@@ -128,6 +132,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
if (ret < 0)
return ret;
+ ssiu->usrcnt++;
+
if (rsnd_runtime_is_ssi_tdm(io)) {
/*
* TDM Extend Mode
@@ -140,15 +146,59 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SSI_MODE, mode);
if (rsnd_ssi_use_busif(io)) {
- rsnd_mod_write(mod, SSI_BUSIF_ADINR,
- rsnd_get_adinr_bit(mod, io) |
- (rsnd_io_is_play(io) ?
- rsnd_runtime_channel_after_ctu(io) :
- rsnd_runtime_channel_original(io)));
- rsnd_mod_write(mod, SSI_BUSIF_MODE,
- rsnd_get_busif_shift(io, mod) | 1);
- rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
- rsnd_get_dalign(mod, io));
+ int id = rsnd_mod_id(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
+ /*
+ * FIXME
+ *
+ * We can't support SSI9-4/5/6/7, because its address is
+ * out of calculation rule
+ */
+ if ((id == 9) && (busif >= 4)) {
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
+ id, busif);
+ }
+
+#define RSND_WRITE_BUSIF(i) \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \
+ rsnd_get_adinr_bit(mod, io) | \
+ (rsnd_io_is_play(io) ? \
+ rsnd_runtime_channel_after_ctu(io) : \
+ rsnd_runtime_channel_original(io))); \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \
+ rsnd_get_busif_shift(io, mod) | 1); \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \
+ rsnd_get_dalign(mod, io))
+
+ switch (busif) {
+ case 0:
+ RSND_WRITE_BUSIF(0);
+ break;
+ case 1:
+ RSND_WRITE_BUSIF(1);
+ break;
+ case 2:
+ RSND_WRITE_BUSIF(2);
+ break;
+ case 3:
+ RSND_WRITE_BUSIF(3);
+ break;
+ case 4:
+ RSND_WRITE_BUSIF(4);
+ break;
+ case 5:
+ RSND_WRITE_BUSIF(5);
+ break;
+ case 6:
+ RSND_WRITE_BUSIF(6);
+ break;
+ case 7:
+ RSND_WRITE_BUSIF(7);
+ break;
+ }
}
if (hdmi) {
@@ -194,10 +244,12 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ int busif = rsnd_ssi_get_busif(io);
+
if (!rsnd_ssi_use_busif(io))
return 0;
- rsnd_mod_write(mod, SSI_CTRL, 0x1);
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0x1);
@@ -209,10 +261,16 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
if (!rsnd_ssi_use_busif(io))
return 0;
- rsnd_mod_write(mod, SSI_CTRL, 0);
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
+
+ if (--ssiu->usrcnt)
+ return 0;
if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0);
@@ -246,6 +304,16 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
return rsnd_dai_connect(mod, io, mod->type);
}
+static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod,
+ enum rsnd_mod_type type)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
+ return &ssiu->busif_status[busif];
+}
+
int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
@@ -269,7 +337,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
for_each_rsnd_ssiu(ssiu, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
- ops, NULL, rsnd_mod_get_status,
+ ops, NULL, rsnd_ssiu_get_status,
RSND_MOD_SSIU, i);
if (ret)
return ret;
OpenPOWER on IntegriCloud