aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/rcar
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c185
-rw-r--r--sound/soc/sh/rcar/cmd.c29
-rw-r--r--sound/soc/sh/rcar/core.c307
-rw-r--r--sound/soc/sh/rcar/ctu.c22
-rw-r--r--sound/soc/sh/rcar/debugfs.c96
-rw-r--r--sound/soc/sh/rcar/dma.c48
-rw-r--r--sound/soc/sh/rcar/dvc.c22
-rw-r--r--sound/soc/sh/rcar/gen.c17
-rw-r--r--sound/soc/sh/rcar/mix.c20
-rw-r--r--sound/soc/sh/rcar/rsnd.h92
-rw-r--r--sound/soc/sh/rcar/src.c51
-rw-r--r--sound/soc/sh/rcar/ssi.c179
-rw-r--r--sound/soc/sh/rcar/ssiu.c181
14 files changed, 990 insertions, 261 deletions
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 5d1ff8ef26f9..d07eccfa3ac2 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
+snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index b9aacf3d3b29..5f1e72edfee0 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -3,8 +3,8 @@
// Helper routines for R-Car sound ADG.
//
// Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
#include "rsnd.h"
#define CLKA 0
@@ -28,6 +28,7 @@ static struct rsnd_mod_ops adg_ops = {
struct rsnd_adg {
struct clk *clk[CLKMAX];
struct clk *clkout[CLKOUTMAX];
+ struct clk *null_clk;
struct clk_onecell_data onecell;
struct rsnd_mod mod;
int clk_rate[CLKMAX];
@@ -64,13 +65,13 @@ static const char * const clk_name[] = {
static u32 rsnd_adg_calculate_rbgx(unsigned long div)
{
- int i, ratio;
+ int i;
if (!div)
return 0;
for (i = 3; i >= 0; i--) {
- ratio = 2 << (i * 2);
+ int ratio = 2 << (i * 2);
if (0 == (div % ratio))
return (u32)((i << 8) | ((div / ratio) - 1));
}
@@ -111,7 +112,7 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
- int idx, sel, div, step;
+ int sel;
unsigned int val, en;
unsigned int min, diff;
unsigned int sel_rate[] = {
@@ -126,8 +127,9 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
val = 0;
en = 0;
for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
- idx = 0;
- step = 2;
+ int idx = 0;
+ int step = 2;
+ int div;
if (!sel_rate[sel])
continue;
@@ -289,7 +291,6 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
- struct clk *clk;
int i;
int sel_table[] = {
[CLKA] = 0x1,
@@ -302,10 +303,9 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
* find suitable clock from
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
*/
- for_each_rsnd_clk(clk, adg, i) {
+ for (i = 0; i < CLKMAX; i++)
if (rate == adg->clk_rate[i])
return sel_table[i];
- }
/*
* find divided clock from BRGA/BRGB
@@ -364,46 +364,103 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
- struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
- int i, ret;
+ int i;
for_each_rsnd_clk(clk, adg, i) {
- ret = 0;
if (enable) {
- ret = clk_prepare_enable(clk);
+ clk_prepare_enable(clk);
/*
* We shouldn't use clk_get_rate() under
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
- adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
+ adg->clk_rate[i] = clk_get_rate(clk);
} else {
clk_disable_unprepare(clk);
}
+ }
+}
+
+static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
+ const char * const name,
+ const char *parent)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct clk *clk;
+
+ clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
+ if (IS_ERR_OR_NULL(clk)) {
+ dev_err(dev, "create null clk error\n");
+ return ERR_CAST(clk);
+ }
+
+ return clk;
+}
+
+static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv)
+{
+ struct rsnd_adg *adg = priv->adg;
+
+ if (!adg->null_clk) {
+ static const char * const name = "rsnd_adg_null";
- if (ret < 0)
- dev_warn(dev, "can't use clk %d\n", i);
+ adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL);
}
+
+ return adg->null_clk;
+}
+
+static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv)
+{
+ struct rsnd_adg *adg = priv->adg;
+
+ if (adg->null_clk)
+ clk_unregister_fixed_rate(adg->null_clk);
}
-static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
- struct rsnd_adg *adg)
+static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
{
+ struct rsnd_adg *adg = priv->adg;
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
int i;
for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]);
- adg->clk[i] = IS_ERR(clk) ? NULL : clk;
+
+ if (IS_ERR_OR_NULL(clk))
+ clk = rsnd_adg_null_clk_get(priv);
+ if (IS_ERR_OR_NULL(clk))
+ goto err;
+
+ adg->clk[i] = clk;
}
+
+ return 0;
+
+err:
+ dev_err(dev, "adg clock IN get failed\n");
+
+ rsnd_adg_null_clk_clean(priv);
+
+ return -EIO;
}
-static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
- struct rsnd_adg *adg)
+static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv)
{
+ struct rsnd_adg *adg = priv->adg;
+ struct clk *clk;
+ int i;
+
+ for_each_rsnd_clkout(clk, adg, i)
+ clk_unregister_fixed_rate(clk);
+}
+
+static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
+{
+ struct rsnd_adg *adg = priv->adg;
struct clk *clk;
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
@@ -443,9 +500,8 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
req_size = prop->length / sizeof(u32);
if (req_size > REQ_SIZE) {
- dev_err(dev,
- "too many clock-frequency, use top %d\n", REQ_SIZE);
- req_size = REQ_SIZE;
+ dev_err(dev, "too many clock-frequency\n");
+ return -EINVAL;
}
of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
@@ -526,10 +582,11 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
if (!count) {
clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
parent_clk_name, 0, req_rate[0]);
- if (!IS_ERR(clk)) {
- adg->clkout[CLKOUT] = clk;
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
- }
+ if (IS_ERR_OR_NULL(clk))
+ goto err;
+
+ adg->clkout[CLKOUT] = clk;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* for clkout0/1/2/3
@@ -539,8 +596,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name, 0,
req_rate[0]);
- if (!IS_ERR(clk))
- adg->clkout[i] = clk;
+ if (IS_ERR_OR_NULL(clk))
+ goto err;
+
+ adg->clkout[i] = clk;
}
adg->onecell.clks = adg->clkout;
adg->onecell.clk_num = CLKOUTMAX;
@@ -552,34 +611,61 @@ rsnd_adg_get_clkout_end:
adg->ckr = ckr;
adg->rbga = rbga;
adg->rbgb = rbgb;
+
+ return 0;
+
+err:
+ dev_err(dev, "adg clock OUT get failed\n");
+
+ rsnd_adg_unregister_clkout(priv);
+
+ return -EIO;
}
-#ifdef DEBUG
-static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
+#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
+__printf(3, 4)
+static void dbg_msg(struct device *dev, struct seq_file *m,
+ const char *fmt, ...)
{
+ char msg[128];
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, args);
+ va_end(args);
+
+ if (m)
+ seq_puts(m, msg);
+ else
+ dev_dbg(dev, "%s", msg);
+}
+
+void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
+{
+ struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
int i;
for_each_rsnd_clk(clk, adg, i)
- dev_dbg(dev, "%s : %pa : %ld\n",
+ dbg_msg(dev, m, "%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",
+ dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
adg->ckr, adg->rbga, adg->rbgb);
- dev_dbg(dev, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
- dev_dbg(dev, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
+ dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
+ dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
/*
* Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
* by BRGCKR::BRGCKR_31
*/
for_each_rsnd_clkout(clk, adg, i)
- dev_dbg(dev, "clkout %d : %pa : %ld\n", i,
+ dbg_msg(dev, m, "clkout %d : %pa : %ld\n", i,
clk, clk_get_rate(clk));
}
#else
-#define rsnd_adg_clk_dbg_info(priv, adg)
+#define rsnd_adg_clk_dbg_info(priv, m)
#endif
int rsnd_adg_probe(struct rsnd_priv *priv)
@@ -597,13 +683,18 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
if (ret)
return ret;
- rsnd_adg_get_clkin(priv, adg);
- rsnd_adg_get_clkout(priv, adg);
- rsnd_adg_clk_dbg_info(priv, adg);
-
priv->adg = adg;
+ ret = rsnd_adg_get_clkin(priv);
+ if (ret)
+ return ret;
+
+ ret = rsnd_adg_get_clkout(priv);
+ if (ret)
+ return ret;
+
rsnd_adg_clk_enable(priv);
+ rsnd_adg_clk_dbg_info(priv, NULL);
return 0;
}
@@ -612,15 +703,13 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
- struct rsnd_adg *adg = priv->adg;
- struct clk *clk;
- int i;
- for_each_rsnd_clkout(clk, adg, i)
- if (adg->clkout[i])
- clk_unregister_fixed_rate(adg->clkout[i]);
+ rsnd_adg_unregister_clkout(priv);
of_clk_del_provider(np);
rsnd_adg_clk_disable(priv);
+
+ /* It should be called after rsnd_adg_clk_disable() */
+ rsnd_adg_null_clk_clean(priv);
}
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index e6bb6a9a0684..329e6ab1b222 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -43,8 +43,6 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
if (mix) {
struct rsnd_dai *rdai;
- struct rsnd_mod *src;
- struct rsnd_dai_stream *tio;
int i;
/*
@@ -54,8 +52,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
*/
data = 0;
for_each_rsnd_dai(rdai, priv, i) {
- tio = &rdai->playback;
- src = rsnd_io_to_mod_src(tio);
+ struct rsnd_dai_stream *tio = &rdai->playback;
+ struct rsnd_mod *src = rsnd_io_to_mod_src(tio);
+
if (mix == rsnd_io_to_mod_mix(tio))
data |= path[rsnd_mod_id(src)];
@@ -115,12 +114,26 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod,
return 0;
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_cmd_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
+}
+#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_cmd_ops = {
.name = CMD_NAME,
.init = rsnd_cmd_init,
.start = rsnd_cmd_start,
.stop = rsnd_cmd_stop,
.get_status = rsnd_mod_get_status,
+ DEBUG_INFO
};
static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
@@ -142,7 +155,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_cmd *cmd;
- int i, nr, ret;
+ int i, nr;
/* This driver doesn't support Gen1 at this point */
if (rsnd_is_gen1(priv))
@@ -161,9 +174,9 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
priv->cmd = cmd;
for_each_rsnd_cmd(cmd, priv, i) {
- ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
- &rsnd_cmd_ops, NULL,
- RSND_MOD_CMD, i);
+ int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+ &rsnd_cmd_ops, NULL,
+ RSND_MOD_CMD, i);
if (ret)
return ret;
}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 0bfcb77e5f65..7e380d71b0f8 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -90,14 +90,6 @@
*
*/
-/*
- * you can enable below define if you don't need
- * DAI status debug message when debugging
- * see rsnd_dbg_dai_call()
- *
- * #define RSND_DEBUG_NO_DAI_CALL 1
- */
-
#include <linux/pm_runtime.h>
#include "rsnd.h"
@@ -216,7 +208,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
mod->clk = clk;
mod->priv = priv;
- return ret;
+ return 0;
}
void rsnd_mod_quit(struct rsnd_mod *mod)
@@ -230,12 +222,12 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
struct rsnd_dai_stream *io))
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_dai_stream *io;
struct rsnd_dai *rdai;
int i;
for_each_rsnd_dai(rdai, priv, i) {
- io = &rdai->playback;
+ struct rsnd_dai_stream *io = &rdai->playback;
+
if (mod == io->mod[mod->type])
callback(mod, io);
@@ -267,8 +259,9 @@ int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
*/
if (params)
return params_channels(params);
- else
+ else if (runtime)
return runtime->channels;
+ return 0;
}
int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
@@ -433,19 +426,19 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
{
- enum rsnd_mod_type playback_mods[] = {
+ static const enum rsnd_mod_type playback_mods[] = {
RSND_MOD_SRC,
RSND_MOD_CMD,
RSND_MOD_SSIU,
};
- enum rsnd_mod_type capture_mods[] = {
+ static const enum rsnd_mod_type capture_mods[] = {
RSND_MOD_CMD,
RSND_MOD_SRC,
RSND_MOD_SSIU,
};
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_mod *tmod = NULL;
- enum rsnd_mod_type *mods =
+ const enum rsnd_mod_type *mods =
rsnd_io_is_play(io) ?
playback_mods : capture_mods;
int i;
@@ -486,13 +479,12 @@ struct rsnd_mod *rsnd_mod_next(int *iterator,
enum rsnd_mod_type *array,
int array_size)
{
- struct rsnd_mod *mod;
- enum rsnd_mod_type type;
int max = array ? array_size : RSND_MOD_MAX;
for (; *iterator < max; (*iterator)++) {
- type = (array) ? array[*iterator] : *iterator;
- mod = rsnd_io_to_mod(io, type);
+ enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator;
+ struct rsnd_mod *mod = rsnd_io_to_mod(io, type);
+
if (mod)
return mod;
}
@@ -534,16 +526,22 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
},
};
-static int rsnd_status_update(u32 *status,
+static int rsnd_status_update(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod, enum rsnd_mod_type type,
int shift, int add, int timing)
{
+ u32 *status = mod->ops->get_status(mod, io, type);
u32 mask = 0xF << shift;
u8 val = (*status >> shift) & 0xF;
u8 next_val = (val + add) & 0xF;
int func_call = (val == timing);
+ /* no status update */
+ if (add == 0 || shift == 28)
+ return 1;
+
if (next_val == 0xF) /* underflow case */
- func_call = 0;
+ func_call = -1;
else
*status = (*status & ~mask) + (next_val << shift);
@@ -559,19 +557,16 @@ static int rsnd_status_update(u32 *status,
enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \
for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \
int tmp = 0; \
- u32 *status = mod->ops->get_status(mod, io, types[i]); \
- int func_call = rsnd_status_update(status, \
+ int func_call = rsnd_status_update(io, mod, types[i], \
__rsnd_mod_shift_##fn, \
__rsnd_mod_add_##fn, \
__rsnd_mod_call_##fn); \
- rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \
- rsnd_mod_name(mod), *status, \
- (func_call && (mod)->ops->fn) ? #fn : ""); \
- if (func_call && (mod)->ops->fn) \
+ if (func_call > 0 && (mod)->ops->fn) \
tmp = (mod)->ops->fn(mod, io, param); \
- if (tmp && (tmp != -EPROBE_DEFER)) \
- dev_err(dev, "%s : %s error %d\n", \
- rsnd_mod_name(mod), #fn, tmp); \
+ if (unlikely(func_call < 0) || \
+ unlikely(tmp && (tmp != -EPROBE_DEFER))) \
+ dev_err(dev, "%s : %s error (%d, %d)\n", \
+ rsnd_mod_name(mod), #fn, tmp, func_call);\
ret |= tmp; \
} \
ret; \
@@ -694,9 +689,9 @@ static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
static
struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- return rtd->cpu_dai;
+ return asoc_rtd_to_cpu(rtd, 0);
}
static
@@ -759,13 +754,13 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ /* set clock master for audio interface */
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
rdai->clk_master = 0;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
- rdai->clk_master = 1; /* codec is slave, cpu is master */
+ case SND_SOC_DAIFMT_BP_FP:
+ rdai->clk_master = 1; /* cpu is master */
break;
default:
return -EINVAL;
@@ -1044,6 +1039,31 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
return rsnd_dai_call(prepare, io, priv);
}
+static u64 rsnd_soc_dai_formats[] = {
+ /*
+ * 1st Priority
+ *
+ * Well tested formats.
+ * Select below from Sound Card, not auto
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+ /*
+ * 2nd Priority
+ *
+ * Supported, but not well tested
+ */
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.startup = rsnd_soc_dai_startup,
.shutdown = rsnd_soc_dai_shutdown,
@@ -1051,6 +1071,8 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.set_fmt = rsnd_soc_dai_set_fmt,
.set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
.prepare = rsnd_soc_dai_prepare,
+ .auto_selectable_formats = rsnd_soc_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
};
static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
@@ -1061,7 +1083,7 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
struct device_node *np;
int is_play = rsnd_io_is_play(io);
- int i, j;
+ int i;
if (!ssiu_np)
return;
@@ -1078,13 +1100,11 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
if (!node)
break;
- j = 0;
for_each_child_of_node(ssiu_np, np) {
if (np == node) {
rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
dev_dbg(dev, "%s is part of TDM Split\n", io->name);
}
- j++;
}
of_node_put(node);
@@ -1132,15 +1152,15 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
of_node_put(remote_node);
}
-void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
struct device_node *node,
struct device_node *playback,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np;
- struct rsnd_mod *mod;
int i;
if (!node)
@@ -1148,7 +1168,16 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
i = 0;
for_each_child_of_node(node, np) {
+ struct rsnd_mod *mod;
+
+ i = rsnd_node_fixed_index(dev, np, name, i);
+ if (i < 0) {
+ of_node_put(np);
+ break;
+ }
+
mod = mod_get(priv, i);
+
if (np == playback)
rsnd_dai_connect(mod, &rdai->playback, mod->type);
if (np == capture)
@@ -1159,6 +1188,57 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
of_node_put(node);
}
+int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx)
+{
+ char node_name[16];
+
+ /*
+ * rsnd is assuming each device nodes are sequential numbering,
+ * but some of them are not.
+ * This function adjusts index for it.
+ *
+ * ex)
+ * Normal case, special case
+ * ssi-0
+ * ssi-1
+ * ssi-2
+ * ssi-3 ssi-3
+ * ssi-4 ssi-4
+ * ...
+ *
+ * assume Max 64 node
+ */
+ for (; idx < 64; idx++) {
+ snprintf(node_name, sizeof(node_name), "%s-%d", name, idx);
+
+ if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0)
+ return idx;
+ }
+
+ dev_err(dev, "strange node numbering (%s)",
+ of_node_full_name(node));
+ return -EINVAL;
+}
+
+int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *np;
+ int i;
+
+ i = 0;
+ for_each_child_of_node(node, np) {
+ i = rsnd_node_fixed_index(dev, np, name, i);
+ if (i < 0) {
+ of_node_put(np);
+ return 0;
+ }
+ i++;
+ }
+
+ return i;
+}
+
static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
int *is_graph)
{
@@ -1258,7 +1338,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
struct device_node *dai_np,
int dai_i)
{
- struct device_node *playback, *capture;
struct rsnd_dai_stream *io_playback;
struct rsnd_dai_stream *io_capture;
struct snd_soc_dai_driver *drv;
@@ -1301,8 +1380,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
for (io_i = 0;; io_i++) {
- playback = of_parse_phandle(dai_np, "playback", io_i);
- capture = of_parse_phandle(dai_np, "capture", io_i);
+ struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i);
+ struct device_node *capture = of_parse_phandle(dai_np, "capture", io_i);
if (!playback && !capture)
break;
@@ -1320,8 +1399,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
if (rsnd_ssi_is_pin_sharing(io_capture) ||
rsnd_ssi_is_pin_sharing(io_playback)) {
- /* should have symmetric_rates if pin sharing */
- drv->symmetric_rates = 1;
+ /* should have symmetric_rate if pin sharing */
+ drv->symmetric_rate = 1;
}
dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
@@ -1366,7 +1445,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
for_each_endpoint_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
if (rsnd_is_gen3(priv)) {
- struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+ rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
@@ -1377,7 +1456,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
for_each_child_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
if (rsnd_is_gen3(priv)) {
- struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+ rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
rsnd_parse_connect_simple(priv, &rdai->capture, dai_np);
@@ -1392,6 +1471,26 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
/*
* pcm ops
*/
+static int rsnd_hw_update(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (hw_params)
+ ret = rsnd_dai_call(hw_params, io, substream, hw_params);
+ else
+ ret = rsnd_dai_call(hw_free, io, substream);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
static int rsnd_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
@@ -1399,7 +1498,7 @@ static int rsnd_hw_params(struct snd_soc_component *component,
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
/*
* rsnd assumes that it might be used under DPCM if user want to use
@@ -1416,11 +1515,11 @@ static int rsnd_hw_params(struct snd_soc_component *component,
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct device *dev = rsnd_priv_to_dev(priv);
struct snd_soc_dpcm *dpcm;
- struct snd_pcm_hw_params *be_params;
int stream = substream->stream;
for_each_dpcm_be(fe, stream, dpcm) {
- be_params = &dpcm->hw_params;
+ struct snd_pcm_hw_params *be_params = &dpcm->hw_params;
+
if (params_channels(hw_params) != params_channels(be_params))
io->converted_chan = params_channels(be_params);
if (params_rate(hw_params) != params_rate(be_params))
@@ -1428,21 +1527,84 @@ static int rsnd_hw_params(struct snd_soc_component *component,
}
if (io->converted_chan)
dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
- if (io->converted_rate)
+ if (io->converted_rate) {
+ /*
+ * SRC supports convert rates from params_rate(hw_params)/k_down
+ * to params_rate(hw_params)*k_up, where k_up is always 6, and
+ * k_down depends on number of channels and SRC unit.
+ * So all SRC units can upsample audio up to 6 times regardless
+ * its number of channels. And all SRC units can downsample
+ * 2 channel audio up to 6 times too.
+ */
+ int k_up = 6;
+ int k_down = 6;
+ int channel;
+ struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+
dev_dbg(dev, "convert rate = %d\n", io->converted_rate);
+
+ channel = io->converted_chan ? io->converted_chan :
+ params_channels(hw_params);
+
+ switch (rsnd_mod_id(src_mod)) {
+ /*
+ * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times.
+ * SRC1, SRC3 and SRC4 can downsample 4 channel audio
+ * up to 4 times.
+ * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio
+ * no more than twice.
+ */
+ case 1:
+ case 3:
+ case 4:
+ if (channel > 4) {
+ k_down = 2;
+ break;
+ }
+ fallthrough;
+ case 0:
+ if (channel > 2)
+ k_down = 4;
+ break;
+
+ /* Other SRC units do not support more than 2 channels */
+ default:
+ if (channel > 2)
+ return -EINVAL;
+ }
+
+ if (params_rate(hw_params) > io->converted_rate * k_down) {
+ hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+ io->converted_rate * k_down;
+ hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+ io->converted_rate * k_down;
+ hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+ } else if (params_rate(hw_params) * k_up < io->converted_rate) {
+ hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+ (io->converted_rate + k_up - 1) / k_up;
+ hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+ (io->converted_rate + k_up - 1) / k_up;
+ hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+ }
+
+ /*
+ * TBD: Max SRC input and output rates also depend on number
+ * of channels and SRC unit:
+ * SRC1, SRC3 and SRC4 do not support more than 128kHz
+ * for 6 channel and 96kHz for 8 channel audio.
+ * Perhaps this function should return EINVAL if the input or
+ * the output rate exceeds the limitation.
+ */
+ }
}
- return rsnd_dai_call(hw_params, io, substream, hw_params);
+ return rsnd_hw_update(substream, hw_params);
}
static int rsnd_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-
- return rsnd_dai_call(hw_free, io, substream);
+ return rsnd_hw_update(substream, NULL);
}
static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
@@ -1472,7 +1634,7 @@ static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
uinfo->value.enumerated.items = cfg->max;
if (uinfo->value.enumerated.item >= cfg->max)
uinfo->value.enumerated.item = cfg->max - 1;
- strlcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
cfg->texts[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
} else {
@@ -1651,10 +1813,12 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
* snd_soc_component
*/
static const struct snd_soc_component_driver rsnd_soc_component = {
- .name = "rsnd",
- .hw_params = rsnd_hw_params,
- .hw_free = rsnd_hw_free,
- .pointer = rsnd_pointer,
+ .name = "rsnd",
+ .probe = rsnd_debugfs_probe,
+ .hw_params = rsnd_hw_params,
+ .hw_free = rsnd_hw_free,
+ .pointer = rsnd_pointer,
+ .legacy_dai_naming = 1,
};
static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
@@ -1805,19 +1969,26 @@ static int rsnd_remove(struct platform_device *pdev)
rsnd_cmd_remove,
rsnd_adg_remove,
};
- int ret = 0, i;
+ int i;
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
- ret |= rsnd_dai_call(remove, &rdai->playback, priv);
- ret |= rsnd_dai_call(remove, &rdai->capture, priv);
+ int ret;
+
+ ret = rsnd_dai_call(remove, &rdai->playback, priv);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i);
+
+ ret = rsnd_dai_call(remove, &rdai->capture, priv);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i);
}
for (i = 0; i < ARRAY_SIZE(remove_func); i++)
remove_func[i](priv);
- return ret;
+ return 0;
}
static int __maybe_unused rsnd_suspend(struct device *dev)
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 7647b3d4c0ba..e39eb2ac7e95 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -171,7 +171,11 @@ static int rsnd_ctu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- rsnd_mod_power_on(mod);
+ int ret;
+
+ ret = rsnd_mod_power_on(mod);
+ if (ret < 0)
+ return ret;
rsnd_ctu_activation(mod);
@@ -207,6 +211,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
NULL,
&ctu->pass, RSND_MAX_CHANNELS,
0xC);
+ if (ret < 0)
+ return ret;
/* ROW0 */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
@@ -273,6 +279,19 @@ static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
return mod->id % 4;
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ctu_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
+}
+#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME,
.probe = rsnd_ctu_probe_,
@@ -283,6 +302,7 @@ static struct rsnd_mod_ops rsnd_ctu_ops = {
.id = rsnd_ctu_id,
.id_sub = rsnd_ctu_id_sub,
.id_cmd = rsnd_mod_id_raw,
+ DEBUG_INFO
};
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/sh/rcar/debugfs.c
new file mode 100644
index 000000000000..26d3b310b9db
--- /dev/null
+++ b/sound/soc/sh/rcar/debugfs.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// // Renesas R-Car debugfs support
+//
+// Copyright (c) 2021 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// > mount -t debugfs none /sys/kernel/debug
+// > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/
+// > cat playback/xxx
+// > cat capture/xxx
+//
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include "rsnd.h"
+
+static int rsnd_debugfs_show(struct seq_file *m, void *v)
+{
+ struct rsnd_dai_stream *io = m->private;
+ struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ int i;
+
+ /* adg is out of mods */
+ rsnd_adg_clk_dbg_info(priv, m);
+
+ for_each_rsnd_mod(i, mod, io) {
+ u32 *status = mod->ops->get_status(mod, io, mod->type);
+
+ seq_printf(m, "name: %s\n", rsnd_mod_name(mod));
+ seq_printf(m, "status: %08x\n", *status);
+
+ if (mod->ops->debug_info)
+ mod->ops->debug_info(m, io, mod);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs);
+
+void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
+ void __iomem *base, int offset, int size)
+{
+ int i, j;
+
+ for (i = 0; i < size; i += 0x10) {
+ phys_addr_t addr = _addr + offset + i;
+
+ seq_printf(m, "%pa:", &addr);
+ for (j = 0; j < 0x10; j += 0x4)
+ seq_printf(m, " %08x", __raw_readl(base + offset + i + j));
+ seq_puts(m, "\n");
+ }
+}
+
+void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
+ int reg_id, int offset, int size)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
+ rsnd_debugfs_reg_show(m,
+ rsnd_gen_get_phy_addr(priv, reg_id),
+ rsnd_gen_get_base_addr(priv, reg_id),
+ offset, size);
+}
+
+int rsnd_debugfs_probe(struct snd_soc_component *component)
+{
+ struct rsnd_priv *priv = dev_get_drvdata(component->dev);
+ struct rsnd_dai *rdai;
+ struct dentry *dir;
+ char name[64];
+ int i;
+
+ /* Gen1 is not supported */
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ for_each_rsnd_dai(rdai, priv, i) {
+ /*
+ * created debugfs will be automatically
+ * removed, nothing to do for _remove.
+ * see
+ * soc_cleanup_component_debugfs()
+ */
+ snprintf(name, sizeof(name), "rdai%d", i);
+ dir = debugfs_create_dir(name, component->debugfs_root);
+
+ debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops);
+ debugfs_create_file("capture", 0444, dir, &rdai->capture, &rsnd_debugfs_fops);
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 95aa26d62e4f..463ab237d7bd 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -44,7 +44,8 @@ struct rsnd_dma {
};
struct rsnd_dma_ctrl {
- void __iomem *base;
+ void __iomem *ppbase;
+ phys_addr_t ppres;
int dmaen_num;
int dmapp_num;
};
@@ -101,7 +102,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
if (dmaen->chan)
- dmaengine_terminate_all(dmaen->chan);
+ dmaengine_terminate_async(dmaen->chan);
return 0;
}
@@ -236,16 +237,25 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
return 0;
}
-struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
- struct rsnd_mod *mod, char *name)
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
+ struct rsnd_mod *mod, char *x)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct dma_chan *chan = NULL;
struct device_node *np;
int i = 0;
for_each_child_of_node(of_node, np) {
+ i = rsnd_node_fixed_index(dev, np, name, i);
+ if (i < 0) {
+ chan = NULL;
+ of_node_put(np);
+ break;
+ }
+
if (i == rsnd_mod_id_raw(mod) && (!chan))
- chan = of_dma_request_slave_channel(np, name);
+ chan = of_dma_request_slave_channel(np, x);
i++;
}
@@ -415,7 +425,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
}
#define rsnd_dmapp_addr(dmac, dma, reg) \
- (dmac->base + 0x20 + reg + \
+ (dmac->ppbase + 0x20 + reg + \
(0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
{
@@ -504,12 +514,31 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
return 0;
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_dmapp_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+ struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+
+ rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase,
+ 0x20 + 0x10 * dmapp->dmapp_id, 0x10);
+}
+#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_dmapp_ops = {
.name = "audmac-pp",
.start = rsnd_dmapp_start,
.stop = rsnd_dmapp_stop,
.quit = rsnd_dmapp_stop,
.get_status = rsnd_mod_get_status,
+ DEBUG_INFO
};
/*
@@ -864,9 +893,10 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
}
dmac->dmapp_num = 0;
- dmac->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(dmac->base))
- return PTR_ERR(dmac->base);
+ dmac->ppres = res->start;
+ dmac->ppbase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dmac->ppbase))
+ return PTR_ERR(dmac->ppbase);
priv->dma = dmac;
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 8d91c0eb0880..16befcbc312c 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -186,7 +186,11 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- rsnd_mod_power_on(mod);
+ int ret;
+
+ ret = rsnd_mod_power_on(mod);
+ if (ret < 0)
+ return ret;
rsnd_dvc_activation(mod);
@@ -282,8 +286,21 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
- mod, "tx");
+ DVC_NAME, mod, "tx");
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_dvc_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
}
+#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
+#else
+#define DEBUG_INFO
+#endif
static struct rsnd_mod_ops rsnd_dvc_ops = {
.name = DVC_NAME,
@@ -293,6 +310,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = {
.quit = rsnd_dvc_quit,
.pcm_new = rsnd_dvc_pcm_new,
.get_status = rsnd_mod_get_status,
+ DEBUG_INFO
};
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index af19010b9d88..925565baaa41 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -141,6 +141,15 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
return gen->res[reg_id];
}
+#ifdef CONFIG_DEBUG_FS
+void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ return gen->base[reg_id];
+}
+#endif
+
#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \
_rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
@@ -224,6 +233,14 @@ 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(SSI_SYS_INT_ENABLE0, 0x850),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index a3e0370f5704..1de0e085804c 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -146,7 +146,11 @@ static int rsnd_mix_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- rsnd_mod_power_on(mod);
+ int ret;
+
+ ret = rsnd_mod_power_on(mod);
+ if (ret < 0)
+ return ret;
rsnd_mix_activation(mod);
@@ -250,6 +254,19 @@ static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
return ret;
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_mix_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
+}
+#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_mix_ops = {
.name = MIX_NAME,
.probe = rsnd_mix_probe_,
@@ -257,6 +274,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = {
.quit = rsnd_mix_quit,
.pcm_new = rsnd_mix_pcm_new,
.get_status = rsnd_mod_get_status,
+ DEBUG_INFO
};
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index ea6cbaa9743e..d9cd190d7e19 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -189,6 +189,14 @@ enum rsnd_reg {
SSI_SYS_STATUS5,
SSI_SYS_STATUS6,
SSI_SYS_STATUS7,
+ SSI_SYS_INT_ENABLE0,
+ SSI_SYS_INT_ENABLE1,
+ SSI_SYS_INT_ENABLE2,
+ SSI_SYS_INT_ENABLE3,
+ SSI_SYS_INT_ENABLE4,
+ SSI_SYS_INT_ENABLE5,
+ SSI_SYS_INT_ENABLE6,
+ SSI_SYS_INT_ENABLE7,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@@ -237,6 +245,7 @@ enum rsnd_reg {
#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i))
#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i))
#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i))
+#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))
struct rsnd_priv;
@@ -260,8 +269,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
int rsnd_dma_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
int rsnd_dma_probe(struct rsnd_priv *priv);
-struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
- struct rsnd_mod *mod, char *name);
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
+ struct rsnd_mod *mod, char *x);
/*
* R-Car sound mod
@@ -336,6 +345,11 @@ struct rsnd_mod_ops {
int (*id)(struct rsnd_mod *mod);
int (*id_sub)(struct rsnd_mod *mod);
int (*id_cmd)(struct rsnd_mod *mod);
+
+#ifdef CONFIG_DEBUG_FS
+ void (*debug_info)(struct seq_file *m,
+ struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+#endif
};
struct rsnd_dai_stream;
@@ -350,19 +364,13 @@ struct rsnd_mod {
/*
* status
*
- * 0xH0000CB0
+ * 0xH000DCB0
*
* B 0: init 1: quit
* C 0: start 1: stop
* D 0: hw_params 1: hw_free
*
* H is always called (see __rsnd_mod_call)
- * H 0: probe 1: remove
- * H 0: pcm_new
- * H 0: fallback
- * H 0: pointer
- * H 0: prepare
- * H 0: cleanup
*/
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
@@ -383,12 +391,12 @@ struct rsnd_mod {
#define __rsnd_mod_add_remove 0
#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
-#define __rsnd_mod_add_stop -1
-#define __rsnd_mod_add_hw_params 1
-#define __rsnd_mod_add_hw_free -1
+#define __rsnd_mod_add_init 1 /* needs protect */
+#define __rsnd_mod_add_quit -1 /* needs protect */
+#define __rsnd_mod_add_start 1 /* needs protect */
+#define __rsnd_mod_add_stop -1 /* needs protect */
+#define __rsnd_mod_add_hw_params 1 /* needs protect */
+#define __rsnd_mod_add_hw_free -1 /* needs protect */
#define __rsnd_mod_add_irq 0
#define __rsnd_mod_add_pcm_new 0
#define __rsnd_mod_add_fallback 0
@@ -398,16 +406,16 @@ struct rsnd_mod {
#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
-#define __rsnd_mod_call_stop 1
+#define __rsnd_mod_call_init 0 /* needs protect */
+#define __rsnd_mod_call_quit 1 /* needs protect */
+#define __rsnd_mod_call_start 0 /* needs protect */
+#define __rsnd_mod_call_stop 1 /* needs protect */
+#define __rsnd_mod_call_hw_params 0 /* needs protect */
+#define __rsnd_mod_call_hw_free 1 /* needs protect */
#define __rsnd_mod_call_irq 0
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0
-#define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_pointer 0
-#define __rsnd_mod_call_hw_free 1
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
@@ -446,11 +454,13 @@ struct rsnd_mod *rsnd_mod_next(int *iterator,
#define for_each_rsnd_mod_array(iterator, pos, io, array) \
for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
-void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
struct device_node *node,
struct device_node *playback,
struct device_node *capture);
+int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name);
+int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx);
int rsnd_channel_normalization(int chan);
#define rsnd_runtime_channel_original(io) \
@@ -583,24 +593,28 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg);
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
+#ifdef CONFIG_DEBUG_FS
+void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id);
+#endif
/*
* R-Car ADG
*/
int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate);
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod);
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate);
int rsnd_adg_probe(struct rsnd_priv *priv);
void rsnd_adg_remove(struct rsnd_priv *priv);
int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io,
unsigned int in_rate,
unsigned int out_rate);
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
struct rsnd_dai_stream *io);
#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1)
#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0)
void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
+void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m);
/*
* R-Car sound priv
@@ -766,7 +780,8 @@ int rsnd_ssi_probe(struct rsnd_priv *priv);
void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
+u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io);
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
#define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
@@ -790,6 +805,7 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
struct device_node *playback,
struct device_node *capture);
#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
+bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod);
/*
* R-Car SRC
@@ -806,7 +822,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
#define rsnd_parse_connect_src(rdai, playback, capture) \
- rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
+ rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get, \
rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
playback, capture)
@@ -818,7 +834,7 @@ void rsnd_ctu_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
- rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
+ rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get, \
rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
playback, capture)
@@ -830,7 +846,7 @@ void rsnd_mix_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
#define rsnd_parse_connect_mix(rdai, playback, capture) \
- rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
+ rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get, \
rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
playback, capture)
@@ -842,7 +858,7 @@ void rsnd_dvc_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
- rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
+ rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get, \
rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
playback, capture)
@@ -870,9 +886,10 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
*
* #define RSND_DEBUG_NO_IRQ_STATUS 1
*/
-#define rsnd_dbg_irq_status(dev, param...) \
+#define rsnd_print_irq_status(dev, param...) do { \
if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS)) \
- dev_dbg(dev, param)
+ dev_info(dev, param); \
+} while (0)
/*
* If you don't need rsnd_dai_call debug message,
@@ -885,3 +902,14 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
dev_dbg(dev, param)
#endif
+
+#ifdef CONFIG_DEBUG_FS
+int rsnd_debugfs_probe(struct snd_soc_component *component);
+void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
+ void __iomem *base, int offset, int size);
+void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
+ int reg_id, int offset, int size);
+
+#else
+#define rsnd_debugfs_probe NULL
+#endif
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 585ffba0244b..f832165e46bc 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -6,9 +6,18 @@
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
/*
+ * You can use Synchronous Sampling Rate Convert (if no DVC)
+ *
+ * amixer set "SRC Out Rate" on
+ * aplay xxx.wav &
+ * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz
+ * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz
+ */
+
+/*
* you can enable below define if you don't need
* SSI interrupt status debug message when debugging
- * see rsnd_dbg_irq_status()
+ * see rsnd_print_irq_status()
*
* #define RSND_DEBUG_NO_IRQ_STATUS 1
*/
@@ -73,7 +82,7 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
int is_play = rsnd_io_is_play(io);
return rsnd_dma_request_channel(rsnd_src_of_node(priv),
- mod,
+ SRC_NAME, mod,
is_play ? "rx" : "tx");
}
@@ -412,8 +421,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
if ((status0 & val0) || (status1 & val1)) {
- rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
- rsnd_mod_name(mod), status0, status1);
+ rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
+ rsnd_mod_name(mod), status0, status1);
ret = true;
}
@@ -454,11 +463,14 @@ static int rsnd_src_init(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
+ int ret;
/* reset sync convert_rate */
src->sync.val = 0;
- rsnd_mod_power_on(mod);
+ ret = rsnd_mod_power_on(mod);
+ if (ret < 0)
+ return ret;
rsnd_src_activation(mod);
@@ -588,6 +600,25 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
return ret;
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_src_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_mod_id(mod) * 0x20, 0x20);
+ seq_puts(m, "\n");
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0x1c0, 0x20);
+ seq_puts(m, "\n");
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ 0x200 + rsnd_mod_id(mod) * 0x40, 0x40);
+}
+#define DEBUG_INFO .debug_info = rsnd_src_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_src_ops = {
.name = SRC_NAME,
.dma_req = rsnd_src_dma_req,
@@ -599,6 +630,7 @@ static struct rsnd_mod_ops rsnd_src_ops = {
.irq = rsnd_src_irq,
.pcm_new = rsnd_src_pcm_new,
.get_status = rsnd_mod_get_status,
+ DEBUG_INFO
};
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -627,7 +659,7 @@ int rsnd_src_probe(struct rsnd_priv *priv)
if (!node)
return 0; /* not used is not error */
- nr = of_get_child_count(node);
+ nr = rsnd_node_count(priv, node, SRC_NAME);
if (!nr) {
ret = -EINVAL;
goto rsnd_src_probe_done;
@@ -647,6 +679,13 @@ int rsnd_src_probe(struct rsnd_priv *priv)
if (!of_device_is_available(np))
goto skip;
+ i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);
+ if (i < 0) {
+ ret = -EINVAL;
+ of_node_put(np);
+ goto rsnd_src_probe_done;
+ }
+
src = rsnd_src_get(priv, i);
snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fc5d089868df..7ade6c5ed96f 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -11,7 +11,7 @@
/*
* you can enable below define if you don't need
* SSI interrupt status debug message when debugging
- * see rsnd_dbg_irq_status()
+ * see rsnd_print_irq_status()
*
* #define RSND_DEBUG_NO_IRQ_STATUS 1
*/
@@ -24,23 +24,23 @@
/*
* SSICR
*/
-#define FORCE (1 << 31) /* Fixed */
-#define DMEN (1 << 28) /* DMA Enable */
-#define UIEN (1 << 27) /* Underflow Interrupt Enable */
-#define OIEN (1 << 26) /* Overflow Interrupt Enable */
-#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
-#define DIEN (1 << 24) /* Data Interrupt Enable */
-#define CHNL_4 (1 << 22) /* Channels */
-#define CHNL_6 (2 << 22) /* Channels */
-#define CHNL_8 (3 << 22) /* Channels */
-#define DWL_MASK (7 << 19) /* Data Word Length mask */
-#define DWL_8 (0 << 19) /* Data Word Length */
-#define DWL_16 (1 << 19) /* Data Word Length */
-#define DWL_18 (2 << 19) /* Data Word Length */
-#define DWL_20 (3 << 19) /* Data Word Length */
-#define DWL_22 (4 << 19) /* Data Word Length */
-#define DWL_24 (5 << 19) /* Data Word Length */
-#define DWL_32 (6 << 19) /* Data Word Length */
+#define FORCE (1u << 31) /* Fixed */
+#define DMEN (1u << 28) /* DMA Enable */
+#define UIEN (1u << 27) /* Underflow Interrupt Enable */
+#define OIEN (1u << 26) /* Overflow Interrupt Enable */
+#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */
+#define DIEN (1u << 24) /* Data Interrupt Enable */
+#define CHNL_4 (1u << 22) /* Channels */
+#define CHNL_6 (2u << 22) /* Channels */
+#define CHNL_8 (3u << 22) /* Channels */
+#define DWL_MASK (7u << 19) /* Data Word Length mask */
+#define DWL_8 (0u << 19) /* Data Word Length */
+#define DWL_16 (1u << 19) /* Data Word Length */
+#define DWL_18 (2u << 19) /* Data Word Length */
+#define DWL_20 (3u << 19) /* Data Word Length */
+#define DWL_22 (4u << 19) /* Data Word Length */
+#define DWL_24 (5u << 19) /* Data Word Length */
+#define DWL_32 (6u << 19) /* Data Word Length */
/*
* System word length
@@ -111,14 +111,12 @@ struct rsnd_ssi {
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
-#define rsnd_ssi_is_multi_slave(mod, io) \
- (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_is_multi_secondary(mod, io) \
+ (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod)))
#define rsnd_ssi_is_run_mods(mod, io) \
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
-static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
{
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
@@ -165,10 +163,9 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
}
-static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
+static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io)
{
- struct rsnd_mod *mod;
- enum rsnd_mod_type types[] = {
+ static const enum rsnd_mod_type types[] = {
RSND_MOD_SSIM1,
RSND_MOD_SSIM2,
RSND_MOD_SSIM3,
@@ -177,7 +174,8 @@ static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
mask = 0;
for (i = 0; i < ARRAY_SIZE(types); i++) {
- mod = rsnd_io_to_mod(io, types[i]);
+ struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]);
+
if (!mod)
continue;
@@ -193,7 +191,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
u32 mods;
- mods = rsnd_ssi_multi_slaves_runtime(io) |
+ mods = rsnd_ssi_multi_secondaries_runtime(io) |
1 << rsnd_mod_id(ssi_mod);
if (ssi_parent_mod)
@@ -202,10 +200,10 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
return mods;
}
-u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
+u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io)
{
if (rsnd_runtime_is_multi_ssi(io))
- return rsnd_ssi_multi_slaves(io);
+ return rsnd_ssi_multi_secondaries(io);
return 0;
}
@@ -230,7 +228,7 @@ 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[] = {
+ static const int ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12,
};
int j, ret;
@@ -283,7 +281,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
if (!rsnd_ssi_can_output_clk(mod))
return 0;
- if (rsnd_ssi_is_multi_slave(mod, io))
+ if (rsnd_ssi_is_multi_secondary(mod, io))
return 0;
if (rsnd_runtime_is_tdm_split(io))
@@ -397,7 +395,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
* see
* rsnd_ssiu_init_gen2()
*/
- wsr = ssi->wsr;
if (is_tdm || is_tdm_split) {
wsr |= WS_MODE;
cr_own |= CHNL_8;
@@ -472,13 +469,20 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ int ret;
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
+ ret = rsnd_ssi_master_clk_start(mod, io);
+ if (ret < 0)
+ return ret;
+
ssi->usrcnt++;
- rsnd_mod_power_on(mod);
+ ret = rsnd_mod_power_on(mod);
+ if (ret < 0)
+ return ret;
rsnd_ssi_config_init(mod, io);
@@ -552,7 +556,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
* EN will be set via SSIU :: SSI_CONTROL
* if Multi channel mode
*/
- if (rsnd_ssi_multi_slaves_runtime(io))
+ if (rsnd_ssi_multi_secondaries_runtime(io))
return 0;
/*
@@ -594,10 +598,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
* Capture: It might not receave data. Do nothing
*/
if (rsnd_io_is_play(io)) {
- rsnd_mod_write(mod, SSICR, cr | EN);
+ rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
rsnd_ssi_status_check(mod, DIRQ);
}
+ /* In multi-SSI mode, stop is performed by setting ssi0129 in
+ * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
+ */
+ if (rsnd_ssi_multi_secondaries_runtime(io))
+ return 0;
+
/*
* disable SSI,
* and, wait idle state
@@ -616,6 +626,11 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
int enable)
{
u32 val = 0;
+ int is_tdm, is_tdm_split;
+ int id = rsnd_mod_id(mod);
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
if (rsnd_is_gen1(priv))
return 0;
@@ -629,6 +644,19 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
if (enable)
val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
+ if (is_tdm || is_tdm_split) {
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 9:
+ val |= 0x0000ff00;
+ break;
+ }
+ }
+
rsnd_mod_write(mod, SSI_INT_ENABLE, val);
return 0;
@@ -660,12 +688,14 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
/* DMA only */
if (is_dma && (status & (UIRQ | OIRQ))) {
- rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n",
- rsnd_mod_name(mod), status);
+ rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
stop = true;
}
+ stop |= rsnd_ssiu_busif_err_status_clear(mod);
+
rsnd_ssi_status_clear(mod);
rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);
@@ -737,6 +767,9 @@ static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
if (!rsnd_rdai_is_clk_master(rdai))
return;
+ if (rsnd_ssi_is_multi_secondary(mod, io))
+ return;
+
switch (rsnd_mod_id(mod)) {
case 1:
case 2:
@@ -776,9 +809,9 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
/*
* SSIP/SSIU/IRQ are not needed on
- * SSI Multi slaves
+ * SSI Multi secondaries
*/
- if (rsnd_ssi_is_multi_slave(mod, io))
+ if (rsnd_ssi_is_multi_secondary(mod, io))
return 0;
/*
@@ -906,13 +939,6 @@ static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_ssi_prepare(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- return rsnd_ssi_master_clk_start(mod, io);
-}
-
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME,
.probe = rsnd_ssi_common_probe,
@@ -925,7 +951,6 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.pointer = rsnd_ssi_pio_pointer,
.pcm_new = rsnd_ssi_pcm_new,
.hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
.get_status = rsnd_ssi_get_status,
};
@@ -937,9 +962,9 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
/*
* SSIP/SSIU/IRQ/DMA are not needed on
- * SSI Multi slaves
+ * SSI Multi secondaries
*/
- if (rsnd_ssi_is_multi_slave(mod, io))
+ if (rsnd_ssi_is_multi_secondary(mod, io))
return 0;
ret = rsnd_ssi_common_probe(mod, io, priv);
@@ -996,8 +1021,36 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
name = is_play ? "rx" : "tx";
return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
- mod, name);
+ SSI_NAME, mod, name);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ssi_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ?
+ "provider" : "consumer");
+ seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv);
+ seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv);
+ seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod));
+ seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod));
+ seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io));
+ seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io),
+ rsnd_runtime_is_tdm_split(io));
+ seq_printf(m, "chan: %d\n", ssi->chan);
+ seq_printf(m, "user: %d\n", ssi->usrcnt);
+
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI,
+ rsnd_mod_id(mod) * 0x40, 0x40);
}
+#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info
+#else
+#define DEBUG_INFO
+#endif
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = SSI_NAME,
@@ -1012,11 +1065,11 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.pcm_new = rsnd_ssi_pcm_new,
.fallback = rsnd_ssi_fallback,
.hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
.get_status = rsnd_ssi_get_status,
+ DEBUG_INFO
};
-static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
{
return mod->ops == &rsnd_ssi_dma_ops;
}
@@ -1028,7 +1081,7 @@ static void rsnd_ssi_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- enum rsnd_mod_type types[] = {
+ static const enum rsnd_mod_type types[] = {
RSND_MOD_SSI,
RSND_MOD_SSIM1,
RSND_MOD_SSIM2,
@@ -1054,9 +1107,9 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node;
struct device_node *np;
- struct rsnd_mod *mod;
int i;
node = rsnd_ssi_of_node(priv);
@@ -1065,7 +1118,16 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
i = 0;
for_each_child_of_node(node, np) {
+ struct rsnd_mod *mod;
+
+ i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
+ if (i < 0) {
+ of_node_put(np);
+ break;
+ }
+
mod = rsnd_ssi_mod_get(priv, i);
+
if (np == playback)
rsnd_ssi_connect(mod, &rdai->playback);
if (np == capture)
@@ -1107,7 +1169,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
if (!node)
return -EINVAL;
- nr = of_get_child_count(node);
+ nr = rsnd_node_count(priv, node, SSI_NAME);
if (!nr) {
ret = -EINVAL;
goto rsnd_ssi_probe_done;
@@ -1127,6 +1189,13 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
if (!of_device_is_available(np))
goto skip;
+ i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
+ if (i < 0) {
+ ret = -EINVAL;
+ of_node_put(np);
+ goto rsnd_ssi_probe_done;
+ }
+
ssi = rsnd_ssi_get(priv, i);
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index f35d88211887..281bc20d4c5d 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -45,6 +45,89 @@ struct rsnd_ssiu {
static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
+/* enable busif buffer over/under run interrupt. */
+#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
+#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
+static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
+{
+ int id = rsnd_mod_id(mod);
+ int shift, offset;
+ int i;
+
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ shift = id;
+ offset = 0;
+ break;
+ case 9:
+ shift = 1;
+ offset = 1;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
+ u32 val = 0xf << (shift * 4);
+ u32 sys_int_enable = rsnd_mod_read(mod, reg);
+
+ if (enable)
+ sys_int_enable |= val;
+ else
+ sys_int_enable &= ~val;
+ rsnd_mod_write(mod, reg, sys_int_enable);
+ }
+}
+
+bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
+{
+ bool error = false;
+ int id = rsnd_mod_id(mod);
+ int shift, offset;
+ int i;
+
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ shift = id;
+ offset = 0;
+ break;
+ case 9:
+ shift = 1;
+ offset = 1;
+ break;
+ default:
+ goto out;
+ }
+
+ for (i = 0; i < 4; i++) {
+ u32 reg = SSI_SYS_STATUS(i * 2) + offset;
+ u32 status = rsnd_mod_read(mod, reg);
+ u32 val = 0xf << (shift * 4);
+
+ status &= val;
+ if (status) {
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
+ error = true;
+ }
+ rsnd_mod_write(mod, reg, val);
+ }
+out:
+ return error;
+}
+
static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
enum rsnd_mod_type type)
@@ -60,28 +143,14 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- u32 ssis = rsnd_ssi_multi_slaves_runtime(io);
+ u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
int use_busif = rsnd_ssi_use_busif(io);
int id = rsnd_mod_id(mod);
int is_clk_master = rsnd_rdai_is_clk_master(rdai);
u32 val1, val2;
- int i;
/* clear status */
- switch (id) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- for (i = 0; i < 4; i++)
- rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
- break;
- case 9:
- for (i = 0; i < 4; i++)
- rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
- break;
- }
+ rsnd_ssiu_busif_err_status_clear(mod);
/*
* SSI_MODE0
@@ -137,12 +206,31 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
+ /*
+ * Enable busif buffer over/under run interrupt.
+ * It will be handled from ssi.c
+ * see
+ * __rsnd_ssi_interrupt()
+ */
+ rsnd_ssiu_busif_err_irq_enable(mod);
+
+ return 0;
+}
+
+static int rsnd_ssiu_quit(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ /* disable busif buffer over/under run interrupt. */
+ rsnd_ssiu_busif_err_irq_disable(mod);
+
return 0;
}
static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
.name = SSIU_NAME,
.init = rsnd_ssiu_init,
+ .quit = rsnd_ssiu_quit,
.get_status = rsnd_ssiu_get_status,
};
@@ -209,7 +297,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *pos;
u32 val;
- int i, shift;
+ int i;
i = rsnd_mod_id(ssi_mod);
@@ -221,7 +309,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
i;
for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
- shift = (i * 4) + 16;
+ int shift = (i * 4) + 20;
+
val = (val & ~(0xF << shift)) |
rsnd_mod_id(pos) << shift;
}
@@ -246,7 +335,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
- if (rsnd_ssi_multi_slaves_runtime(io))
+ if (rsnd_ssi_multi_secondaries_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0x1);
return 0;
@@ -267,7 +356,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
if (--ssiu->usrcnt)
return 0;
- if (rsnd_ssi_multi_slaves_runtime(io))
+ if (rsnd_ssi_multi_secondaries_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0);
return 0;
@@ -310,16 +399,31 @@ static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
name = is_play ? "rx" : "tx";
return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
- mod, name);
+ SSIU_NAME, mod, name);
}
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ssiu_debug_info(struct seq_file *m,
+ struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU,
+ rsnd_mod_id(mod) * 0x80, 0x80);
+}
+#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
.name = SSIU_NAME,
.dma_req = rsnd_ssiu_dma_req,
.init = rsnd_ssiu_init_gen2,
+ .quit = rsnd_ssiu_quit,
.start = rsnd_ssiu_start_gen2,
.stop = rsnd_ssiu_stop_gen2,
.get_status = rsnd_ssiu_get_status,
+ DEBUG_INFO
};
static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
@@ -334,18 +438,21 @@ static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
struct rsnd_dai_stream *io)
{
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
- struct rsnd_mod *mod;
struct rsnd_ssiu *ssiu;
+ int is_dma_mode;
int i;
if (!ssi_mod)
return;
+ is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
+
/* select BUSIF0 */
for_each_rsnd_ssiu(ssiu, priv, i) {
- mod = rsnd_mod_get(ssiu);
+ struct rsnd_mod *mod = rsnd_mod_get(ssiu);
- if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
+ if (is_dma_mode &&
+ (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
(rsnd_mod_id_sub(mod) == 0)) {
rsnd_dai_connect(mod, io, mod->type);
return;
@@ -358,18 +465,27 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node = rsnd_ssiu_of_node(priv);
- struct device_node *np;
- struct rsnd_mod *mod;
struct rsnd_dai_stream *io_p = &rdai->playback;
struct rsnd_dai_stream *io_c = &rdai->capture;
- int i;
/* use rcar_sound,ssiu if exist */
if (node) {
- i = 0;
+ struct device_node *np;
+ int i = 0;
+
for_each_child_of_node(node, np) {
+ struct rsnd_mod *mod;
+
+ i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
+ if (i < 0) {
+ of_node_put(np);
+ break;
+ }
+
mod = rsnd_ssiu_mod_get(priv, i);
+
if (np == playback)
rsnd_dai_connect(mod, io_p, mod->type);
if (np == capture)
@@ -394,7 +510,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
struct rsnd_ssiu *ssiu;
struct rsnd_mod_ops *ops;
const int *list = NULL;
- int i, nr, ret;
+ int i, nr;
/*
* Keep DT compatibility.
@@ -405,10 +521,13 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
*/
node = rsnd_ssiu_of_node(priv);
if (node)
- nr = of_get_child_count(node);
+ nr = rsnd_node_count(priv, node, SSIU_NAME);
else
nr = priv->ssi_nr;
+ if (!nr)
+ return -EINVAL;
+
ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
if (!ssiu)
return -ENOMEM;
@@ -441,6 +560,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
}
for_each_rsnd_ssiu(ssiu, priv, i) {
+ int ret;
+
if (node) {
int j;