summaryrefslogtreecommitdiff
path: root/sound/soc/sh
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/rcar/adg.c169
-rw-r--r--sound/soc/sh/rcar/core.c73
-rw-r--r--sound/soc/sh/rcar/dma.c57
-rw-r--r--sound/soc/sh/rcar/gen.c70
-rw-r--r--sound/soc/sh/rcar/rsnd.h23
-rw-r--r--sound/soc/sh/rcar/ssi.c13
-rw-r--r--sound/soc/sh/rcar/ssiu.c15
7 files changed, 292 insertions, 128 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index ca1e1281cefa..7bc4421835d7 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -11,7 +11,7 @@
#define CLKB 1
#define CLKC 2
#define CLKI 3
-#define CLKMAX 4
+#define CLKINMAX 4
#define CLKOUT 0
#define CLKOUT1 1
@@ -25,44 +25,56 @@ static struct rsnd_mod_ops adg_ops = {
.name = "adg",
};
+#define ADG_HZ_441 0
+#define ADG_HZ_48 1
+#define ADG_HZ_SIZE 2
+
struct rsnd_adg {
- struct clk *clk[CLKMAX];
+ struct clk *clkin[CLKINMAX];
struct clk *clkout[CLKOUTMAX];
struct clk *null_clk;
struct clk_onecell_data onecell;
struct rsnd_mod mod;
- int clk_rate[CLKMAX];
- u32 flags;
+ int clkin_rate[CLKINMAX];
+ int clkin_size;
+ int clkout_size;
u32 ckr;
u32 rbga;
u32 rbgb;
- int rbga_rate_for_441khz; /* RBGA */
- int rbgb_rate_for_48khz; /* RBGB */
+ int rbg_rate[ADG_HZ_SIZE]; /* RBGA / RBGB */
};
-#define LRCLK_ASYNC (1 << 0)
-#define AUDIO_OUT_48 (1 << 1)
-
-#define for_each_rsnd_clk(pos, adg, i) \
+#define for_each_rsnd_clkin(pos, adg, i) \
for (i = 0; \
- (i < CLKMAX) && \
- ((pos) = adg->clk[i]); \
+ (i < adg->clkin_size) && \
+ ((pos) = adg->clkin[i]); \
i++)
#define for_each_rsnd_clkout(pos, adg, i) \
for (i = 0; \
- (i < CLKOUTMAX) && \
+ (i < adg->clkout_size) && \
((pos) = adg->clkout[i]); \
i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
-static const char * const clk_name[] = {
+static const char * const clkin_name_gen4[] = {
+ [CLKA] = "clkin",
+};
+
+static const char * const clkin_name_gen2[] = {
[CLKA] = "clk_a",
[CLKB] = "clk_b",
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
+static const char * const clkout_name_gen2[] = {
+ [CLKOUT] = "audio_clkout",
+ [CLKOUT1] = "audio_clkout1",
+ [CLKOUT2] = "audio_clkout2",
+ [CLKOUT3] = "audio_clkout3",
+};
+
static u32 rsnd_adg_calculate_rbgx(unsigned long div)
{
int i;
@@ -116,11 +128,11 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
unsigned int val, en;
unsigned int min, diff;
unsigned int sel_rate[] = {
- adg->clk_rate[CLKA], /* 0000: CLKA */
- adg->clk_rate[CLKB], /* 0001: CLKB */
- adg->clk_rate[CLKC], /* 0010: CLKC */
- adg->rbga_rate_for_441khz, /* 0011: RBGA */
- adg->rbgb_rate_for_48khz, /* 0100: RBGB */
+ adg->clkin_rate[CLKA], /* 0000: CLKA */
+ adg->clkin_rate[CLKB], /* 0001: CLKB */
+ adg->clkin_rate[CLKC], /* 0010: CLKC */
+ adg->rbg_rate[ADG_HZ_441], /* 0011: RBGA */
+ adg->rbg_rate[ADG_HZ_48], /* 0100: RBGB */
};
min = ~0;
@@ -291,6 +303,7 @@ 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,
@@ -303,17 +316,17 @@ 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 (i = 0; i < CLKMAX; i++)
- if (rate == adg->clk_rate[i])
+ for_each_rsnd_clkin(clk, adg, i)
+ if (rate == adg->clkin_rate[i])
return sel_table[i];
/*
* find divided clock from BRGA/BRGB
*/
- if (rate == adg->rbga_rate_for_441khz)
+ if (rate == adg->rbg_rate[ADG_HZ_441])
return 0x10;
- if (rate == adg->rbgb_rate_for_48khz)
+ if (rate == adg->rbg_rate[ADG_HZ_48])
return 0x20;
return -EIO;
@@ -341,13 +354,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk(ssi_mod, data);
- if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
- if (rsnd_flags_has(adg, AUDIO_OUT_48))
- ckr = 0x80000000;
- } else {
- if (0 == (rate % 8000))
- ckr = 0x80000000;
- }
+ if (0 == (rate % 8000))
+ ckr = 0x80000000; /* BRGB output = 48kHz */
rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
rsnd_mod_write(adg_mod, BRRA, adg->rbga);
@@ -355,8 +363,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
(ckr) ? 'B' : 'A',
- (ckr) ? adg->rbgb_rate_for_48khz :
- adg->rbga_rate_for_441khz);
+ (ckr) ? adg->rbg_rate[ADG_HZ_48] :
+ adg->rbg_rate[ADG_HZ_441]);
return 0;
}
@@ -367,7 +375,7 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
struct clk *clk;
int i;
- for_each_rsnd_clk(clk, adg, i) {
+ for_each_rsnd_clkin(clk, adg, i) {
if (enable) {
clk_prepare_enable(clk);
@@ -376,7 +384,7 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
- adg->clk_rate[i] = clk_get_rate(clk);
+ adg->clkin_rate[i] = clk_get_rate(clk);
} else {
clk_disable_unprepare(clk);
}
@@ -425,19 +433,30 @@ 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;
+ const char * const *clkin_name;
+ int clkin_size;
int i;
- for (i = 0; i < CLKMAX; i++) {
- clk = devm_clk_get(dev, clk_name[i]);
+ clkin_name = clkin_name_gen2;
+ clkin_size = ARRAY_SIZE(clkin_name_gen2);
+ if (rsnd_is_gen4(priv)) {
+ clkin_name = clkin_name_gen4;
+ clkin_size = ARRAY_SIZE(clkin_name_gen4);
+ }
+
+ for (i = 0; i < clkin_size; i++) {
+ clk = devm_clk_get(dev, clkin_name[i]);
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;
+ adg->clkin[i] = clk;
}
+ adg->clkin_size = clkin_size;
+
return 0;
err:
@@ -467,18 +486,13 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
struct property *prop;
u32 ckr, rbgx, rbga, rbgb;
u32 rate, div;
-#define REQ_SIZE 2
- u32 req_rate[REQ_SIZE] = {};
+ u32 req_rate[ADG_HZ_SIZE] = {};
uint32_t count = 0;
- unsigned long req_48kHz_rate, req_441kHz_rate;
+ unsigned long req_Hz[ADG_HZ_SIZE];
+ int clkout_size;
int i, req_size;
const char *parent_clk_name = NULL;
- static const char * const clkout_name[] = {
- [CLKOUT] = "audio_clkout",
- [CLKOUT1] = "audio_clkout1",
- [CLKOUT2] = "audio_clkout2",
- [CLKOUT3] = "audio_clkout3",
- };
+ const char * const *clkout_name;
int brg_table[] = {
[CLKA] = 0x0,
[CLKB] = 0x1,
@@ -499,27 +513,21 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
goto rsnd_adg_get_clkout_end;
req_size = prop->length / sizeof(u32);
- if (req_size > REQ_SIZE) {
+ if (req_size > ADG_HZ_SIZE) {
dev_err(dev, "too many clock-frequency\n");
return -EINVAL;
}
of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
- req_48kHz_rate = 0;
- req_441kHz_rate = 0;
+ req_Hz[ADG_HZ_48] = 0;
+ req_Hz[ADG_HZ_441] = 0;
for (i = 0; i < req_size; i++) {
if (0 == (req_rate[i] % 44100))
- req_441kHz_rate = req_rate[i];
+ req_Hz[ADG_HZ_441] = req_rate[i];
if (0 == (req_rate[i] % 48000))
- req_48kHz_rate = req_rate[i];
+ req_Hz[ADG_HZ_48] = req_rate[i];
}
- if (req_rate[0] % 48000 == 0)
- rsnd_flags_set(adg, AUDIO_OUT_48);
-
- if (of_get_property(np, "clkout-lr-asynchronous", NULL))
- rsnd_flags_set(adg, LRCLK_ASYNC);
-
/*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
* have 44.1kHz or 48kHz base clocks for now.
@@ -529,47 +537,48 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
* rsnd_adg_ssi_clk_try_start()
* rsnd_ssi_master_clk_start()
*/
- adg->rbga_rate_for_441khz = 0;
- adg->rbgb_rate_for_48khz = 0;
- for_each_rsnd_clk(clk, adg, i) {
+ for_each_rsnd_clkin(clk, adg, i) {
rate = clk_get_rate(clk);
if (0 == rate) /* not used */
continue;
/* RBGA */
- if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
+ if (!adg->rbg_rate[ADG_HZ_441] && (0 == rate % 44100)) {
div = 6;
- if (req_441kHz_rate)
- div = rate / req_441kHz_rate;
+ if (req_Hz[ADG_HZ_441])
+ div = rate / req_Hz[ADG_HZ_441];
rbgx = rsnd_adg_calculate_rbgx(div);
if (BRRx_MASK(rbgx) == rbgx) {
rbga = rbgx;
- adg->rbga_rate_for_441khz = rate / div;
+ adg->rbg_rate[ADG_HZ_441] = rate / div;
ckr |= brg_table[i] << 20;
- if (req_441kHz_rate &&
- !rsnd_flags_has(adg, AUDIO_OUT_48))
+ if (req_Hz[ADG_HZ_441])
parent_clk_name = __clk_get_name(clk);
}
}
/* RBGB */
- if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
+ if (!adg->rbg_rate[ADG_HZ_48] && (0 == rate % 48000)) {
div = 6;
- if (req_48kHz_rate)
- div = rate / req_48kHz_rate;
+ if (req_Hz[ADG_HZ_48])
+ div = rate / req_Hz[ADG_HZ_48];
rbgx = rsnd_adg_calculate_rbgx(div);
if (BRRx_MASK(rbgx) == rbgx) {
rbgb = rbgx;
- adg->rbgb_rate_for_48khz = rate / div;
+ adg->rbg_rate[ADG_HZ_48] = rate / div;
ckr |= brg_table[i] << 16;
- if (req_48kHz_rate &&
- rsnd_flags_has(adg, AUDIO_OUT_48))
+ if (req_Hz[ADG_HZ_48])
parent_clk_name = __clk_get_name(clk);
}
}
}
+ clkout_name = clkout_name_gen2;
+ clkout_size = ARRAY_SIZE(clkout_name_gen2);
+ if (rsnd_is_gen4(priv))
+ clkout_size = 1; /* reuse clkout_name_gen2[] */
+
/*
* ADG supports BRRA/BRRB output only.
* this means all clkout0/1/2/3 will be * same rate
@@ -586,13 +595,14 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
goto err;
adg->clkout[CLKOUT] = clk;
+ adg->clkout_size = 1;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* for clkout0/1/2/3
*/
else {
- for (i = 0; i < CLKOUTMAX; i++) {
+ for (i = 0; i < clkout_size; i++) {
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name, 0,
req_rate[0]);
@@ -602,7 +612,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
adg->clkout[i] = clk;
}
adg->onecell.clks = adg->clkout;
- adg->onecell.clk_num = CLKOUTMAX;
+ adg->onecell.clk_num = clkout_size;
+ adg->clkout_size = clkout_size;
of_clk_add_provider(np, of_clk_src_onecell_get,
&adg->onecell);
}
@@ -647,22 +658,22 @@ void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
struct clk *clk;
int i;
- for_each_rsnd_clk(clk, adg, i)
+ for_each_rsnd_clkin(clk, adg, i)
dbg_msg(dev, m, "%-18s : %pa : %ld\n",
__clk_get_name(clk), clk, clk_get_rate(clk));
dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
adg->ckr, adg->rbga, adg->rbgb);
- 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);
+ dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbg_rate[ADG_HZ_441]);
+ dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbg_rate[ADG_HZ_48]);
/*
* Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
* by BRGCKR::BRGCKR_31
*/
for_each_rsnd_clkout(clk, adg, i)
- dbg_msg(dev, m, "clkout %d : %pa : %ld\n", i,
- clk, clk_get_rate(clk));
+ dbg_msg(dev, m, "%-18s : %pa : %ld\n",
+ __clk_get_name(clk), clk, clk_get_rate(clk));
}
#else
#define rsnd_adg_clk_dbg_info(priv, m)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 2d269ac8c137..cb17f7d0cf0c 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -102,6 +102,7 @@ static const struct of_device_id rsnd_of_match[] = {
{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
{ .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 },
+ { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 },
/* Special Handling */
{ .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) },
{},
@@ -827,6 +828,13 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
break;
default:
/* use default */
+ /*
+ * Indicate warning if DT has "dai-tdm-slot-width"
+ * but the value was not expected.
+ */
+ if (slot_width)
+ dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n",
+ slot_width);
slot_width = 32;
}
@@ -869,7 +877,8 @@ static unsigned int rsnd_soc_hw_rate_list[] = {
static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
unsigned int *list, int list_num,
- struct snd_interval *baseline, struct snd_interval *iv)
+ struct snd_interval *baseline, struct snd_interval *iv,
+ struct rsnd_dai_stream *io, char *unit)
{
struct snd_interval p;
unsigned int rate;
@@ -899,6 +908,16 @@ static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
}
}
+ /* Indicate error once if it can't handle */
+ if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) {
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_warn(dev, "It can't handle %d %s <-> %d %s\n",
+ baseline->min, unit, baseline->max, unit);
+ rsnd_flags_set(io, RSND_HW_RULE_ERR);
+ }
+
return snd_interval_refine(iv, &p);
}
@@ -922,7 +941,7 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
ARRAY_SIZE(rsnd_soc_hw_rate_list),
- &ic, ir);
+ &ic, ir, io, "ch");
}
static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
@@ -945,7 +964,7 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
ARRAY_SIZE(rsnd_soc_hw_channels_list),
- ir, &ic);
+ ir, &ic, io, "Hz");
}
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
@@ -970,6 +989,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
unsigned int max_channels = rsnd_rdai_channels_get(rdai);
int i;
+ rsnd_flags_del(io, RSND_HW_RULE_ERR);
+
rsnd_dai_stream_init(io, substream);
/*
@@ -1343,6 +1364,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
struct snd_soc_dai_driver *drv;
struct rsnd_dai *rdai;
struct device *dev = rsnd_priv_to_dev(priv);
+ int playback_exist = 0, capture_exist = 0;
int io_i;
rdai = rsnd_rdai_get(priv, dai_i);
@@ -1357,22 +1379,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
drv->ops = &rsnd_soc_dai_ops;
drv->pcm_new = rsnd_pcm_new;
- snprintf(io_playback->name, RSND_DAI_NAME_SIZE,
- "DAI%d Playback", dai_i);
- drv->playback.rates = RSND_RATES;
- drv->playback.formats = RSND_FMTS;
- drv->playback.channels_min = 2;
- drv->playback.channels_max = 8;
- drv->playback.stream_name = io_playback->name;
-
- snprintf(io_capture->name, RSND_DAI_NAME_SIZE,
- "DAI%d Capture", dai_i);
- drv->capture.rates = RSND_RATES;
- drv->capture.formats = RSND_FMTS;
- drv->capture.channels_min = 2;
- drv->capture.channels_max = 8;
- drv->capture.stream_name = io_capture->name;
-
io_playback->rdai = rdai;
io_capture->rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
@@ -1386,6 +1392,14 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
if (!playback && !capture)
break;
+ if (io_i == 0) {
+ /* check whether playback/capture property exists */
+ if (playback)
+ playback_exist = 1;
+ if (capture)
+ capture_exist = 1;
+ }
+
rsnd_parse_connect_ssi(rdai, playback, capture);
rsnd_parse_connect_ssiu(rdai, playback, capture);
rsnd_parse_connect_src(rdai, playback, capture);
@@ -1397,6 +1411,23 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
of_node_put(capture);
}
+ if (playback_exist) {
+ snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i);
+ drv->playback.rates = RSND_RATES;
+ drv->playback.formats = RSND_FMTS;
+ drv->playback.channels_min = 2;
+ drv->playback.channels_max = 8;
+ drv->playback.stream_name = io_playback->name;
+ }
+ if (capture_exist) {
+ snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i);
+ drv->capture.rates = RSND_RATES;
+ drv->capture.formats = RSND_FMTS;
+ drv->capture.channels_min = 2;
+ drv->capture.channels_max = 8;
+ drv->capture.stream_name = io_capture->name;
+ }
+
if (rsnd_ssi_is_pin_sharing(io_capture) ||
rsnd_ssi_is_pin_sharing(io_playback)) {
/* should have symmetric_rate if pin sharing */
@@ -1444,7 +1475,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
if (is_graph) {
for_each_endpoint_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv)) {
+ if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
@@ -1455,7 +1486,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
} else {
for_each_child_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv)) {
+ if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 463ab237d7bd..1c494e521463 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -653,22 +653,54 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
}
+/*
+ * Gen4 DMA read/write register offset
+ *
+ * ex) R-Car V4H case
+ * mod / SYS-DMAC in / SYS-DMAC out
+ * SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000
+ */
+#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i))
+static dma_addr_t
+rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+ int is_play, int is_from)
+{
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_GEN4_SDMC);
+ int id = rsnd_mod_id(mod);
+ int busif = rsnd_mod_id_sub(mod);
+
+ /*
+ * SSI0 only is supported
+ */
+ if (id != 0) {
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_err(dev, "This driver doesn't support non SSI0");
+ return -EINVAL;
+ }
+
+ return RDMA_SSI_SDMC(addr, busif);
+}
+
static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
struct rsnd_mod *mod,
int is_play, int is_from)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ if (!mod)
+ return 0;
+
/*
* gen1 uses default DMA addr
*/
if (rsnd_is_gen1(priv))
return 0;
-
- if (!mod)
- return 0;
-
- return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
+ else if (rsnd_is_gen4(priv))
+ return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
+ else
+ return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
}
#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
@@ -885,19 +917,28 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
/*
* for Gen2 or later
*/
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
- if (!dmac || !res) {
+ if (!dmac) {
dev_err(dev, "dma allocate failed\n");
return 0; /* it will be PIO mode */
}
+ /* for Gen4 doesn't have DMA-pp */
+ if (rsnd_is_gen4(priv))
+ goto audmapp_end;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
+ if (!res) {
+ dev_err(dev, "lack of audmapp in DT\n");
+ return 0; /* it will be PIO mode */
+ }
+
dmac->dmapp_num = 0;
dmac->ppres = res->start;
dmac->ppbase = devm_ioremap_resource(dev, res);
if (IS_ERR(dmac->ppbase))
return PTR_ERR(dmac->ppbase);
-
+audmapp_end:
priv->dma = dmac;
/* dummy mem mod for debug */
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 925565baaa41..86bdecc24956 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -216,6 +216,74 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
}
/*
+ * Gen4
+ */
+static int rsnd_gen4_probe(struct rsnd_priv *priv)
+{
+ static const struct rsnd_regmap_field_conf conf_ssiu[] = {
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
+ RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
+ RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
+ RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
+ RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
+
+ RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0),
+ RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4),
+ RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8),
+ RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20),
+ RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24),
+ RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28),
+ RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40),
+ RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44),
+ RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48),
+ RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60),
+ RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64),
+ RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68),
+ RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500),
+ RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504),
+ RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508),
+ RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520),
+ RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524),
+ RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528),
+ RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540),
+ RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544),
+ RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548),
+ RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560),
+ RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564),
+ RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568),
+ RSND_GEN_S_REG(SSI_CTRL, 0x010),
+ RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018),
+ RSND_GEN_S_REG(SSI_MODE, 0x00c),
+ RSND_GEN_S_REG(SSI_MODE2, 0xa0c),
+ };
+ static const struct rsnd_regmap_field_conf conf_adg[] = {
+ RSND_GEN_S_REG(BRRA, 0x00),
+ RSND_GEN_S_REG(BRRB, 0x04),
+ RSND_GEN_S_REG(BRGCKR, 0x08),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
+ };
+ static const struct rsnd_regmap_field_conf conf_ssi[] = {
+ RSND_GEN_S_REG(SSICR, 0x00),
+ RSND_GEN_S_REG(SSISR, 0x04),
+ RSND_GEN_S_REG(SSITDR, 0x08),
+ RSND_GEN_S_REG(SSIRDR, 0x0c),
+ RSND_GEN_S_REG(SSIWSR, 0x20),
+ };
+ static const struct rsnd_regmap_field_conf conf_sdmc[] = {
+ RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000),
+ };
+ int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg);
+ int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu);
+ int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi);
+ int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc);
+
+ return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
+}
+
+/*
* Gen2
*/
static int rsnd_gen2_probe(struct rsnd_priv *priv)
@@ -484,6 +552,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
else if (rsnd_is_gen2(priv) ||
rsnd_is_gen3(priv))
ret = rsnd_gen2_probe(priv);
+ else if (rsnd_is_gen4(priv))
+ ret = rsnd_gen4_probe(priv);
if (ret < 0)
dev_err(dev, "unknown generation R-Car sound device\n");
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index d9cd190d7e19..239705d52517 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -31,6 +31,11 @@
#define RSND_GEN2_SSIU 2
#define RSND_GEN2_SSI 3
+#define RSND_GEN4_ADG 0
+#define RSND_GEN4_SSIU 1
+#define RSND_GEN4_SSI 2
+#define RSND_GEN4_SDMC 3
+
#define RSND_BASE_MAX 4
/*
@@ -197,6 +202,7 @@ enum rsnd_reg {
SSI_SYS_INT_ENABLE5,
SSI_SYS_INT_ENABLE6,
SSI_SYS_INT_ENABLE7,
+ SSI_BUSIF,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@@ -513,6 +519,7 @@ struct rsnd_dai_stream {
#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */
#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */
#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */
+#define RSND_HW_RULE_ERR (1 << 3) /* hw_rule error */
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
@@ -628,6 +635,7 @@ struct rsnd_priv {
#define RSND_GEN1 (1 << 0)
#define RSND_GEN2 (2 << 0)
#define RSND_GEN3 (3 << 0)
+#define RSND_GEN4 (4 << 0)
#define RSND_SOC_MASK (0xFF << 4)
#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */
@@ -702,6 +710,7 @@ struct rsnd_priv {
#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
+#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
#define rsnd_is_e3(priv) (((priv)->flags & \
(RSND_GEN_MASK | RSND_SOC_MASK)) == \
(RSND_GEN3 | RSND_SOC_E))
@@ -891,18 +900,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
dev_info(dev, param); \
} while (0)
-/*
- * If you don't need rsnd_dai_call debug message,
- * define RSND_DEBUG_NO_DAI_CALL as 1 on top of core.c
- *
- * #define RSND_DEBUG_NO_DAI_CALL 1
- */
-#define rsnd_dbg_dai_call(dev, param...) \
- if (!IS_BUILTIN(RSND_DEBUG_NO_DAI_CALL)) \
- 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,
@@ -913,3 +910,5 @@ void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
#else
#define rsnd_debugfs_probe NULL
#endif
+
+#endif /* RSND_H */
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 7ade6c5ed96f..8ddee5b03ece 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -303,15 +303,14 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
}
+ ret = -EIO;
main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
- if (!main_rate) {
- dev_err(dev, "unsupported clock rate\n");
- return -EIO;
- }
+ if (!main_rate)
+ goto rate_err;
ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
if (ret < 0)
- return ret;
+ goto rate_err;
/*
* SSI clock will be output contiguously
@@ -333,6 +332,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
rsnd_mod_name(mod), chan, rate);
return 0;
+
+rate_err:
+ dev_err(dev, "unsupported clock rate\n");
+ return ret;
}
static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 281bc20d4c5d..17bd8cc86dd0 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -29,8 +29,8 @@ struct rsnd_ssiu {
i++)
/*
- * SSI Gen2 Gen3
- * 0 BUSIF0-3 BUSIF0-7
+ * SSI Gen2 Gen3 Gen4
+ * 0 BUSIF0-3 BUSIF0-7 BUSIF0-7
* 1 BUSIF0-3 BUSIF0-7
* 2 BUSIF0-3 BUSIF0-7
* 3 BUSIF0 BUSIF0-7
@@ -40,10 +40,11 @@ struct rsnd_ssiu {
* 7 BUSIF0 BUSIF0
* 8 BUSIF0 BUSIF0
* 9 BUSIF0-3 BUSIF0-7
- * total 22 52
+ * total 22 52 8
*/
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 };
+static const int gen4_id[] = { 0 };
/* enable busif buffer over/under run interrupt. */
#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
@@ -152,6 +153,10 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
/* clear status */
rsnd_ssiu_busif_err_status_clear(mod);
+ /* Gen4 doesn't have SSI_MODE */
+ if (rsnd_is_gen4(priv))
+ goto ssi_mode_setting_end;
+
/*
* SSI_MODE0
*/
@@ -206,6 +211,7 @@ 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);
+ssi_mode_setting_end:
/*
* Enable busif buffer over/under run interrupt.
* It will be handled from ssi.c
@@ -553,6 +559,9 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
} else if (rsnd_is_gen3(priv)) {
list = gen3_id;
nr = ARRAY_SIZE(gen3_id);
+ } else if (rsnd_is_gen4(priv)) {
+ list = gen4_id;
+ nr = ARRAY_SIZE(gen4_id);
} else {
dev_err(dev, "unknown SSIU\n");
return -ENODEV;