Commit f904f846 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

parents 1cae4146 c409c2a9
...@@ -43,7 +43,7 @@ Example 1. Sampling Rate Conversion ...@@ -43,7 +43,7 @@ Example 1. Sampling Rate Conversion
label = "sound-card"; label = "sound-card";
prefix = "codec"; prefix = "codec";
routing = "codec Playback", "DAI0 Playback", routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback"; "DAI0 Capture", "codec Capture";
convert-rate = <48000>; convert-rate = <48000>;
dais = <&cpu_port>; dais = <&cpu_port>;
...@@ -79,7 +79,8 @@ Example 2. 2 CPU 1 Codec (Mixing) ...@@ -79,7 +79,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
label = "sound-card"; label = "sound-card";
prefix = "codec"; prefix = "codec";
routing = "codec Playback", "DAI0 Playback", routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback"; "codec Playback", "DAI1 Playback",
"DAI0 Capture", "codec Capture";
convert-rate = <48000>; convert-rate = <48000>;
dais = <&cpu_port0 dais = <&cpu_port0
......
...@@ -44,7 +44,6 @@ struct rsnd_adg { ...@@ -44,7 +44,6 @@ struct rsnd_adg {
#define LRCLK_ASYNC (1 << 0) #define LRCLK_ASYNC (1 << 0)
#define AUDIO_OUT_48 (1 << 1) #define AUDIO_OUT_48 (1 << 1)
#define adg_mode_flags(adg) (adg->flags)
#define for_each_rsnd_clk(pos, adg, i) \ #define for_each_rsnd_clk(pos, adg, i) \
for (i = 0; \ for (i = 0; \
...@@ -58,6 +57,13 @@ struct rsnd_adg { ...@@ -58,6 +57,13 @@ struct rsnd_adg {
i++) i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
static const char * const clk_name[] = {
[CLKA] = "clk_a",
[CLKB] = "clk_b",
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
static u32 rsnd_adg_calculate_rbgx(unsigned long div) static u32 rsnd_adg_calculate_rbgx(unsigned long div)
{ {
int i, ratio; int i, ratio;
...@@ -280,6 +286,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) ...@@ -280,6 +286,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct device *dev = rsnd_priv_to_dev(priv);
int id = rsnd_mod_id(ssi_mod); int id = rsnd_mod_id(ssi_mod);
int shift = (id % 4) * 8; int shift = (id % 4) * 8;
u32 mask = 0xFF << shift; u32 mask = 0xFF << shift;
...@@ -306,12 +313,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) ...@@ -306,12 +313,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val); rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
break; break;
} }
dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
} }
int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
{ {
struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk; struct clk *clk;
int i; int i;
int sel_table[] = { int sel_table[] = {
...@@ -321,8 +329,6 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) ...@@ -321,8 +329,6 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
[CLKI] = 0x0, [CLKI] = 0x0,
}; };
dev_dbg(dev, "request clock = %d\n", rate);
/* /*
* find suitable clock from * find suitable clock from
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
...@@ -366,8 +372,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ...@@ -366,8 +372,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk(ssi_mod, data); rsnd_adg_set_ssi_clk(ssi_mod, data);
if (adg_mode_flags(adg) & LRCLK_ASYNC) { if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
if (adg_mode_flags(adg) & AUDIO_OUT_48) if (rsnd_flags_has(adg, AUDIO_OUT_48))
ckr = 0x80000000; ckr = 0x80000000;
} else { } else {
if (0 == (rate % 8000)) if (0 == (rate % 8000))
...@@ -378,9 +384,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ...@@ -378,9 +384,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_mod_write(adg_mod, BRRA, adg->rbga); rsnd_mod_write(adg_mod, BRRA, adg->rbga);
rsnd_mod_write(adg_mod, BRRB, adg->rbgb); rsnd_mod_write(adg_mod, BRRB, adg->rbgb);
dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), (ckr) ? 'B' : 'A',
data, rate); (ckr) ? adg->rbgb_rate_for_48khz :
adg->rbga_rate_for_441khz);
return 0; return 0;
} }
...@@ -409,21 +416,12 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, ...@@ -409,21 +416,12 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
{ {
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk; struct clk *clk;
static const char * const clk_name[] = {
[CLKA] = "clk_a",
[CLKB] = "clk_b",
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
int i; int i;
for (i = 0; i < CLKMAX; i++) { for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]); clk = devm_clk_get(dev, clk_name[i]);
adg->clk[i] = IS_ERR(clk) ? NULL : clk; adg->clk[i] = IS_ERR(clk) ? NULL : clk;
} }
for_each_rsnd_clk(clk, adg, i)
dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
} }
static void rsnd_adg_get_clkout(struct rsnd_priv *priv, static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
...@@ -479,10 +477,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ...@@ -479,10 +477,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
} }
if (req_rate[0] % 48000 == 0) if (req_rate[0] % 48000 == 0)
adg->flags |= AUDIO_OUT_48; rsnd_flags_set(adg, AUDIO_OUT_48);
if (of_get_property(np, "clkout-lr-asynchronous", NULL)) if (of_get_property(np, "clkout-lr-asynchronous", NULL))
adg->flags |= LRCLK_ASYNC; rsnd_flags_set(adg, LRCLK_ASYNC);
/* /*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
...@@ -512,7 +510,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ...@@ -512,7 +510,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
adg->rbga_rate_for_441khz = rate / div; adg->rbga_rate_for_441khz = rate / div;
ckr |= brg_table[i] << 20; ckr |= brg_table[i] << 20;
if (req_441kHz_rate && if (req_441kHz_rate &&
!(adg_mode_flags(adg) & AUDIO_OUT_48)) !rsnd_flags_has(adg, AUDIO_OUT_48))
parent_clk_name = __clk_get_name(clk); parent_clk_name = __clk_get_name(clk);
} }
} }
...@@ -528,7 +526,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ...@@ -528,7 +526,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
adg->rbgb_rate_for_48khz = rate / div; adg->rbgb_rate_for_48khz = rate / div;
ckr |= brg_table[i] << 16; ckr |= brg_table[i] << 16;
if (req_48kHz_rate && if (req_48kHz_rate &&
(adg_mode_flags(adg) & AUDIO_OUT_48)) rsnd_flags_has(adg, AUDIO_OUT_48))
parent_clk_name = __clk_get_name(clk); parent_clk_name = __clk_get_name(clk);
} }
} }
...@@ -572,12 +570,35 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ...@@ -572,12 +570,35 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
adg->ckr = ckr; adg->ckr = ckr;
adg->rbga = rbga; adg->rbga = rbga;
adg->rbgb = rbgb; adg->rbgb = rbgb;
}
#ifdef DEBUG
static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
int i;
for_each_rsnd_clk(clk, adg, i)
dev_dbg(dev, "%s : %p : %ld\n",
clk_name[i], clk, clk_get_rate(clk));
for_each_rsnd_clkout(clk, adg, i)
dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
ckr, rbga, rbgb); 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);
/*
* 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 : %p : %ld\n", i,
clk, clk_get_rate(clk));
} }
#else
#define rsnd_adg_clk_dbg_info(priv, adg)
#endif
int rsnd_adg_probe(struct rsnd_priv *priv) int rsnd_adg_probe(struct rsnd_priv *priv)
{ {
...@@ -596,6 +617,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) ...@@ -596,6 +617,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkin(priv, adg);
rsnd_adg_get_clkout(priv, adg); rsnd_adg_get_clkout(priv, adg);
rsnd_adg_clk_dbg_info(priv, adg);
priv->adg = adg; priv->adg = adg;
......
...@@ -121,14 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) ...@@ -121,14 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
} }
} }
char *rsnd_mod_name(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
return "unknown";
return mod->ops->name;
}
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod) struct rsnd_mod *mod)
{ {
...@@ -172,8 +164,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, ...@@ -172,8 +164,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
void rsnd_mod_quit(struct rsnd_mod *mod) void rsnd_mod_quit(struct rsnd_mod *mod)
{ {
if (mod->clk) clk_unprepare(mod->clk);
clk_unprepare(mod->clk);
mod->clk = NULL; mod->clk = NULL;
} }
...@@ -200,7 +191,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, ...@@ -200,7 +191,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
int rsnd_io_is_working(struct rsnd_dai_stream *io) int rsnd_io_is_working(struct rsnd_dai_stream *io)
{ {
/* see rsnd_dai_stream_init/quit() */ /* see rsnd_dai_stream_init/quit() */
return !!io->substream; if (io->substream)
return snd_pcm_running(io->substream);
return 0;
} }
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
...@@ -407,11 +401,9 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, ...@@ -407,11 +401,9 @@ struct rsnd_mod *rsnd_mod_next(int *iterator,
for (; *iterator < max; (*iterator)++) { for (; *iterator < max; (*iterator)++) {
type = (array) ? array[*iterator] : *iterator; type = (array) ? array[*iterator] : *iterator;
mod = io->mod[type]; mod = rsnd_io_to_mod(io, type);
if (!mod) if (mod)
continue; return mod;
return mod;
} }
return NULL; return NULL;
...@@ -1242,6 +1234,33 @@ struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) ...@@ -1242,6 +1234,33 @@ struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg)
return &cfg->cfg; return &cfg->cfg;
} }
const char * const volume_ramp_rate[] = {
"128 dB/1 step", /* 00000 */
"64 dB/1 step", /* 00001 */
"32 dB/1 step", /* 00010 */
"16 dB/1 step", /* 00011 */
"8 dB/1 step", /* 00100 */
"4 dB/1 step", /* 00101 */
"2 dB/1 step", /* 00110 */
"1 dB/1 step", /* 00111 */
"0.5 dB/1 step", /* 01000 */
"0.25 dB/1 step", /* 01001 */
"0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */
"0.125 dB/2 steps", /* 01011 */
"0.125 dB/4 steps", /* 01100 */
"0.125 dB/8 steps", /* 01101 */
"0.125 dB/16 steps", /* 01110 */
"0.125 dB/32 steps", /* 01111 */
"0.125 dB/64 steps", /* 10000 */
"0.125 dB/128 steps", /* 10001 */
"0.125 dB/256 steps", /* 10010 */
"0.125 dB/512 steps", /* 10011 */
"0.125 dB/1024 steps", /* 10100 */
"0.125 dB/2048 steps", /* 10101 */
"0.125 dB/4096 steps", /* 10110 */
"0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */
};
int rsnd_kctrl_new(struct rsnd_mod *mod, int rsnd_kctrl_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd, struct snd_soc_pcm_runtime *rtd,
......
...@@ -81,8 +81,11 @@ struct rsnd_ctu { ...@@ -81,8 +81,11 @@ struct rsnd_ctu {
struct rsnd_kctrl_cfg_m sv3; struct rsnd_kctrl_cfg_m sv3;
struct rsnd_kctrl_cfg_s reset; struct rsnd_kctrl_cfg_s reset;
int channels; int channels;
u32 flags;
}; };
#define KCTRL_INITIALIZED (1 << 0)
#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) #define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
#define for_each_rsnd_ctu(pos, priv, i) \ #define for_each_rsnd_ctu(pos, priv, i) \
for ((i) = 0; \ for ((i) = 0; \
...@@ -130,7 +133,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, ...@@ -130,7 +133,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
int i; int i;
for (i = 0; i < RSND_MAX_CHANNELS; i++) { for (i = 0; i < RSND_MAX_CHANNELS; i++) {
u32 val = ctu->pass.val[i]; u32 val = rsnd_kctrl_valm(ctu->pass, i);
cpmdr |= val << (28 - (i * 4)); cpmdr |= val << (28 - (i * 4));
...@@ -147,44 +150,44 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, ...@@ -147,44 +150,44 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, CTU_SCMDR, scmdr); rsnd_mod_write(mod, CTU_SCMDR, scmdr);
if (scmdr > 0) { if (scmdr > 0) {
rsnd_mod_write(mod, CTU_SV00R, ctu->sv0.val[0]); rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0));
rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]); rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1));
rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]); rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2));
rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]); rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3));
rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]); rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4));
rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]); rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5));
rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]); rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6));
rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]); rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7));
} }
if (scmdr > 1) { if (scmdr > 1) {
rsnd_mod_write(mod, CTU_SV10R, ctu->sv1.val[0]); rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0));
rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]); rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1));
rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]); rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2));
rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]); rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3));
rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]); rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4));
rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]); rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5));
rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]); rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6));
rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]); rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7));
} }
if (scmdr > 2) { if (scmdr > 2) {
rsnd_mod_write(mod, CTU_SV20R, ctu->sv2.val[0]); rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0));
rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]); rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1));
rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]); rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2));
rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]); rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3));
rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]); rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4));
rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]); rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5));
rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]); rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6));
rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]); rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7));
} }
if (scmdr > 3) { if (scmdr > 3) {
rsnd_mod_write(mod, CTU_SV30R, ctu->sv3.val[0]); rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0));
rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]); rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1));
rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]); rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2));
rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]); rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3));
rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]); rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4));
rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]); rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5));
rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]); rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6));
rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]); rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7));
} }
rsnd_mod_write(mod, CTU_CTUIR, 0); rsnd_mod_write(mod, CTU_CTUIR, 0);
...@@ -196,17 +199,17 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, ...@@ -196,17 +199,17 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int i; int i;
if (!ctu->reset.val) if (!rsnd_kctrl_vals(ctu->reset))
return; return;
for (i = 0; i < RSND_MAX_CHANNELS; i++) { for (i = 0; i < RSND_MAX_CHANNELS; i++) {
ctu->pass.val[i] = 0; rsnd_kctrl_valm(ctu->pass, i) = 0;
ctu->sv0.val[i] = 0; rsnd_kctrl_valm(ctu->sv0, i) = 0;
ctu->sv1.val[i] = 0; rsnd_kctrl_valm(ctu->sv1, i) = 0;
ctu->sv2.val[i] = 0; rsnd_kctrl_valm(ctu->sv2, i) = 0;
ctu->sv3.val[i] = 0; rsnd_kctrl_valm(ctu->sv3, i) = 0;
} }
ctu->reset.val = 0; rsnd_kctrl_vals(ctu->reset) = 0;
} }
static int rsnd_ctu_init(struct rsnd_mod *mod, static int rsnd_ctu_init(struct rsnd_mod *mod,
...@@ -277,6 +280,9 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ...@@ -277,6 +280,9 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int ret; int ret;
if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
return 0;
/* CTU Pass */ /* CTU Pass */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
rsnd_kctrl_accept_anytime, rsnd_kctrl_accept_anytime,
...@@ -326,6 +332,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ...@@ -326,6 +332,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
rsnd_ctu_value_reset, rsnd_ctu_value_reset,
&ctu->reset, 1); &ctu->reset, 1);
rsnd_flags_set(ctu, KCTRL_INITIALIZED);
return ret; return ret;
} }
......
...@@ -60,6 +60,14 @@ struct rsnd_dma_ctrl { ...@@ -60,6 +60,14 @@ struct rsnd_dma_ctrl {
#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
/* for DEBUG */
static struct rsnd_mod_ops mem_ops = {
.name = "mem",
};
static struct rsnd_mod mem = {
};
/* /*
* Audio DMAC * Audio DMAC
*/ */
...@@ -211,11 +219,9 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, ...@@ -211,11 +219,9 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
dma->mod_from, dma->mod_from,
dma->mod_to); dma->mod_to);
if (IS_ERR_OR_NULL(dmaen->chan)) { if (IS_ERR_OR_NULL(dmaen->chan)) {
int ret = PTR_ERR(dmaen->chan);
dmaen->chan = NULL; dmaen->chan = NULL;
dev_err(dev, "can't get dma channel\n"); dev_err(dev, "can't get dma channel\n");
return ret; return -EIO;
} }
return 0; return 0;
...@@ -747,20 +753,22 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, ...@@ -747,20 +753,22 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
rsnd_mod_name(this), rsnd_mod_id(this)); rsnd_mod_name(this), rsnd_mod_id(this));
for (i = 0; i <= idx; i++) { for (i = 0; i <= idx; i++) {
dev_dbg(dev, " %s[%d]%s\n", dev_dbg(dev, " %s[%d]%s\n",
rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), rsnd_mod_name(mod[i] ? mod[i] : &mem),
(mod[i] == *mod_from) ? " from" : rsnd_mod_id (mod[i] ? mod[i] : &mem),
(mod[i] == *mod_to) ? " to" : ""); (mod[i] == *mod_from) ? " from" :
(mod[i] == *mod_to) ? " to" : "");
} }
} }
int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
struct rsnd_mod **dma_mod) struct rsnd_mod **dma_mod)
{ {
struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_from = NULL;
struct rsnd_mod *mod_to = NULL; struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dma *dma;
struct rsnd_mod_ops *ops; struct rsnd_mod_ops *ops;
enum rsnd_mod_type type; enum rsnd_mod_type type;
int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
...@@ -800,40 +808,47 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ...@@ -800,40 +808,47 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
type = RSND_MOD_AUDMA; type = RSND_MOD_AUDMA;
} }
if (!(*dma_mod)) { dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
struct rsnd_dma *dma; if (!dma)
return -ENOMEM;
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); *dma_mod = rsnd_mod_get(dma);
if (!dma)
return -ENOMEM;
*dma_mod = rsnd_mod_get(dma); ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
rsnd_mod_get_status, type, dma_id);
if (ret < 0)
return ret;
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
rsnd_mod_get_status, type, dma_id); rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
if (ret < 0) rsnd_mod_name(mod_from ? mod_from : &mem),
return ret; rsnd_mod_id (mod_from ? mod_from : &mem),
rsnd_mod_name(mod_to ? mod_to : &mem),
rsnd_mod_id (mod_to ? mod_to : &mem));
dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", ret = attach(io, dma, mod_from, mod_to);
rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), if (ret < 0)
rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), return ret;
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
dma->mod_from = mod_from;
dma->mod_to = mod_to;
return 0;
}
int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
struct rsnd_mod **dma_mod)
{
if (!(*dma_mod)) {
int ret = rsnd_dma_alloc(io, mod, dma_mod);
ret = attach(io, dma, mod_from, mod_to);
if (ret < 0) if (ret < 0)
return ret; return ret;
dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
dma->mod_from = mod_from;
dma->mod_to = mod_to;
} }
ret = rsnd_dai_connect(*dma_mod, io, type); return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
if (ret < 0)
return ret;
return 0;
} }
int rsnd_dma_probe(struct rsnd_priv *priv) int rsnd_dma_probe(struct rsnd_priv *priv)
...@@ -866,5 +881,6 @@ int rsnd_dma_probe(struct rsnd_priv *priv) ...@@ -866,5 +881,6 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
priv->dma = dmac; priv->dma = dmac;
return 0; /* dummy mem mod for debug */
return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
} }
...@@ -44,8 +44,11 @@ struct rsnd_dvc { ...@@ -44,8 +44,11 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
u32 flags;
}; };
#define KCTRL_INITIALIZED (1 << 0)
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
...@@ -58,33 +61,6 @@ struct rsnd_dvc { ...@@ -58,33 +61,6 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
i++) i++)
static const char * const dvc_ramp_rate[] = {
"128 dB/1 step", /* 00000 */
"64 dB/1 step", /* 00001 */
"32 dB/1 step", /* 00010 */
"16 dB/1 step", /* 00011 */
"8 dB/1 step", /* 00100 */
"4 dB/1 step", /* 00101 */
"2 dB/1 step", /* 00110 */
"1 dB/1 step", /* 00111 */
"0.5 dB/1 step", /* 01000 */
"0.25 dB/1 step", /* 01001 */
"0.125 dB/1 step", /* 01010 */
"0.125 dB/2 steps", /* 01011 */
"0.125 dB/4 steps", /* 01100 */
"0.125 dB/8 steps", /* 01101 */
"0.125 dB/16 steps", /* 01110 */
"0.125 dB/32 steps", /* 01111 */
"0.125 dB/64 steps", /* 10000 */
"0.125 dB/128 steps", /* 10001 */
"0.125 dB/256 steps", /* 10010 */
"0.125 dB/512 steps", /* 10011 */
"0.125 dB/1024 steps", /* 10100 */
"0.125 dB/2048 steps", /* 10101 */
"0.125 dB/4096 steps", /* 10110 */
"0.125 dB/8192 steps", /* 10111 */
};
static void rsnd_dvc_activation(struct rsnd_mod *mod) static void rsnd_dvc_activation(struct rsnd_mod *mod)
{ {
rsnd_mod_write(mod, DVC_SWRSR, 0); rsnd_mod_write(mod, DVC_SWRSR, 0);
...@@ -97,8 +73,9 @@ static void rsnd_dvc_halt(struct rsnd_mod *mod) ...@@ -97,8 +73,9 @@ static void rsnd_dvc_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, DVC_SWRSR, 0); rsnd_mod_write(mod, DVC_SWRSR, 0);
} }
#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) #define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) rsnd_kctrl_vals(dvc->rdown))
#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
struct rsnd_mod *mod) struct rsnd_mod *mod)
...@@ -108,12 +85,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, ...@@ -108,12 +85,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
int i; int i;
/* Enable Ramp */ /* Enable Ramp */
if (dvc->ren.val) if (rsnd_kctrl_vals(dvc->ren))
for (i = 0; i < RSND_MAX_CHANNELS; i++) for (i = 0; i < RSND_MAX_CHANNELS; i++)
val[i] = dvc->volume.cfg.max; val[i] = rsnd_kctrl_max(dvc->volume);
else else
for (i = 0; i < RSND_MAX_CHANNELS; i++) for (i = 0; i < RSND_MAX_CHANNELS; i++)
val[i] = dvc->volume.val[i]; val[i] = rsnd_kctrl_valm(dvc->volume, i);
/* Enable Digital Volume */ /* Enable Digital Volume */
rsnd_mod_write(mod, DVC_VOL0R, val[0]); rsnd_mod_write(mod, DVC_VOL0R, val[0]);
...@@ -143,7 +120,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, ...@@ -143,7 +120,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
dvucr |= 0x101; dvucr |= 0x101;
/* Enable Ramp */ /* Enable Ramp */
if (dvc->ren.val) { if (rsnd_kctrl_vals(dvc->ren)) {
dvucr |= 0x10; dvucr |= 0x10;
/* /*
...@@ -185,10 +162,10 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, ...@@ -185,10 +162,10 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
u32 vrdbr = 0; u32 vrdbr = 0;
int i; int i;
for (i = 0; i < dvc->mute.cfg.size; i++) for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
zcmcr |= (!!dvc->mute.cfg.val[i]) << i; zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
if (dvc->ren.val) { if (rsnd_kctrl_vals(dvc->ren)) {
vrpdr = rsnd_dvc_get_vrpdr(dvc); vrpdr = rsnd_dvc_get_vrpdr(dvc);
vrdbr = rsnd_dvc_get_vrdbr(dvc); vrdbr = rsnd_dvc_get_vrdbr(dvc);
} }
...@@ -254,6 +231,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ...@@ -254,6 +231,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int channels = rsnd_rdai_channels_get(rdai); int channels = rsnd_rdai_channels_get(rdai);
int ret; int ret;
if (rsnd_flags_has(dvc, KCTRL_INITIALIZED))
return 0;
/* Volume */ /* Volume */
ret = rsnd_kctrl_new_m(mod, io, rtd, ret = rsnd_kctrl_new_m(mod, io, rtd,
is_play ? is_play ?
...@@ -292,7 +272,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ...@@ -292,7 +272,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
rsnd_kctrl_accept_anytime, rsnd_kctrl_accept_anytime,
rsnd_dvc_volume_update, rsnd_dvc_volume_update,
&dvc->rup, &dvc->rup,
dvc_ramp_rate); volume_ramp_rate,
VOLUME_RAMP_MAX_DVC);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -302,11 +283,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ...@@ -302,11 +283,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
rsnd_kctrl_accept_anytime, rsnd_kctrl_accept_anytime,
rsnd_dvc_volume_update, rsnd_dvc_volume_update,
&dvc->rdown, &dvc->rdown,
dvc_ramp_rate); volume_ramp_rate,
VOLUME_RAMP_MAX_DVC);
if (ret < 0) if (ret < 0)
return ret; return ret;
rsnd_flags_set(dvc, KCTRL_INITIALIZED);
return 0; return 0;
} }
......
...@@ -7,6 +7,33 @@ ...@@ -7,6 +7,33 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
/*
* CTUn MIXn
* +------+ +------+
* [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| ->
* [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| ->
* [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| ->
* [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| ->
* +------+ +------+
*
* ex)
* DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
* DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
*
* MIX Volume
* amixer set "MIX",0 100% // DAI0 Volume
* amixer set "MIX",1 100% // DAI1 Volume
*
* Volume Ramp
* amixer set "MIX Ramp Up Rate" "0.125 dB/1 step"
* amixer set "MIX Ramp Down Rate" "4 dB/1 step"
* amixer set "MIX Ramp" on
* aplay xxx.wav &
* amixer set "MIX",0 80% // DAI0 Volume Down
* amixer set "MIX",1 100% // DAI1 Volume Up
*/
#include "rsnd.h" #include "rsnd.h"
#define MIX_NAME_SIZE 16 #define MIX_NAME_SIZE 16
...@@ -14,8 +41,27 @@ ...@@ -14,8 +41,27 @@
struct rsnd_mix { struct rsnd_mix {
struct rsnd_mod mod; struct rsnd_mod mod;
struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */
u32 flags;
}; };
#define ONCE_KCTRL_INITIALIZED (1 << 0)
#define HAS_VOLA (1 << 1)
#define HAS_VOLB (1 << 2)
#define HAS_VOLC (1 << 3)
#define HAS_VOLD (1 << 4)
#define VOL_MAX 0x3ff
#define rsnd_mod_to_mix(_mod) \
container_of((_mod), struct rsnd_mix, mod)
#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) #define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
#define rsnd_mix_nr(priv) ((priv)->mix_nr) #define rsnd_mix_nr(priv) ((priv)->mix_nr)
#define for_each_rsnd_mix(pos, priv, i) \ #define for_each_rsnd_mix(pos, priv, i) \
...@@ -36,26 +82,43 @@ static void rsnd_mix_halt(struct rsnd_mod *mod) ...@@ -36,26 +82,43 @@ static void rsnd_mix_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, MIX_SWRSR, 0); rsnd_mod_write(mod, MIX_SWRSR, 0);
} }
#define rsnd_mix_get_vol(mix, X) \
rsnd_flags_has(mix, HAS_VOL##X) ? \
(VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
struct rsnd_mod *mod) struct rsnd_mod *mod)
{ {
rsnd_mod_write(mod, MIX_MDBAR, 0); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
rsnd_mod_write(mod, MIX_MDBBR, 0); struct device *dev = rsnd_priv_to_dev(priv);
rsnd_mod_write(mod, MIX_MDBCR, 0); struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
rsnd_mod_write(mod, MIX_MDBDR, 0); u32 volA = rsnd_mix_get_vol(mix, A);
u32 volB = rsnd_mix_get_vol(mix, B);
u32 volC = rsnd_mix_get_vol(mix, C);
u32 volD = rsnd_mix_get_vol(mix, D);
dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
volA, volB, volC, volD);
rsnd_mod_write(mod, MIX_MDBAR, volA);
rsnd_mod_write(mod, MIX_MDBBR, volB);
rsnd_mod_write(mod, MIX_MDBCR, volC);
rsnd_mod_write(mod, MIX_MDBDR, volD);
} }
static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
struct rsnd_mod *mod) struct rsnd_mod *mod)
{ {
struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
rsnd_mod_write(mod, MIX_MIXIR, 1); rsnd_mod_write(mod, MIX_MIXIR, 1);
/* General Information */ /* General Information */
rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
/* volume step */ /* volume step */
rsnd_mod_write(mod, MIX_MIXMR, 0); rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
rsnd_mod_write(mod, MIX_MVPDR, 0); rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
rsnd_kctrl_vals(mix->rdw));
/* common volume parameter */ /* common volume parameter */
rsnd_mix_volume_parameter(io, mod); rsnd_mix_volume_parameter(io, mod);
...@@ -109,11 +172,94 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, ...@@ -109,11 +172,94 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
return 0; return 0;
} }
static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
struct rsnd_kctrl_cfg_s *volume;
int ret;
switch (rsnd_mod_id(src_mod)) {
case 3:
case 6: /* MDBAR */
volume = &mix->volumeA;
rsnd_flags_set(mix, HAS_VOLA);
break;
case 4:
case 9: /* MDBBR */
volume = &mix->volumeB;
rsnd_flags_set(mix, HAS_VOLB);
break;
case 0:
case 1: /* MDBCR */
volume = &mix->volumeC;
rsnd_flags_set(mix, HAS_VOLC);
break;
case 2:
case 5: /* MDBDR */
volume = &mix->volumeD;
rsnd_flags_set(mix, HAS_VOLD);
break;
default:
dev_err(dev, "unknown SRC is connected\n");
return -EINVAL;
}
/* Volume */
ret = rsnd_kctrl_new_s(mod, io, rtd,
"MIX Playback Volume",
rsnd_kctrl_accept_anytime,
rsnd_mix_volume_update,
volume, VOL_MAX);
if (ret < 0)
return ret;
rsnd_kctrl_vals(*volume) = VOL_MAX;
if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
return ret;
/* Ramp */
ret = rsnd_kctrl_new_s(mod, io, rtd,
"MIX Ramp Switch",
rsnd_kctrl_accept_anytime,
rsnd_mix_volume_update,
&mix->ren, 1);
if (ret < 0)
return ret;
ret = rsnd_kctrl_new_e(mod, io, rtd,
"MIX Ramp Up Rate",
rsnd_kctrl_accept_anytime,
rsnd_mix_volume_update,
&mix->rup,
volume_ramp_rate,
VOLUME_RAMP_MAX_MIX);
if (ret < 0)
return ret;
ret = rsnd_kctrl_new_e(mod, io, rtd,
"MIX Ramp Down Rate",
rsnd_kctrl_accept_anytime,
rsnd_mix_volume_update,
&mix->rdw,
volume_ramp_rate,
VOLUME_RAMP_MAX_MIX);
rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
return ret;
}
static struct rsnd_mod_ops rsnd_mix_ops = { static struct rsnd_mod_ops rsnd_mix_ops = {
.name = MIX_NAME, .name = MIX_NAME,
.probe = rsnd_mix_probe_, .probe = rsnd_mix_probe_,
.init = rsnd_mix_init, .init = rsnd_mix_init,
.quit = rsnd_mix_quit, .quit = rsnd_mix_quit,
.pcm_new = rsnd_mix_pcm_new,
}; };
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
......
...@@ -355,8 +355,9 @@ struct rsnd_mod { ...@@ -355,8 +355,9 @@ struct rsnd_mod {
#define __rsnd_mod_call_nolock_start 0 #define __rsnd_mod_call_nolock_start 0
#define __rsnd_mod_call_nolock_stop 1 #define __rsnd_mod_call_nolock_stop 1
#define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_name(mod) ((mod)->ops->name)
#define rsnd_mod_id(mod) ((mod)->id)
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
#define rsnd_mod_power_off(mod) clk_disable((mod)->clk) #define rsnd_mod_power_off(mod) clk_disable((mod)->clk)
#define rsnd_mod_get(ip) (&(ip)->mod) #define rsnd_mod_get(ip) (&(ip)->mod)
...@@ -371,7 +372,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, ...@@ -371,7 +372,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
enum rsnd_mod_type type, enum rsnd_mod_type type,
int id); int id);
void rsnd_mod_quit(struct rsnd_mod *mod); void rsnd_mod_quit(struct rsnd_mod *mod);
char *rsnd_mod_name(struct rsnd_mod *mod);
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod); struct rsnd_mod *mod);
void rsnd_mod_interrupt(struct rsnd_mod *mod, void rsnd_mod_interrupt(struct rsnd_mod *mod,
...@@ -601,6 +601,10 @@ struct rsnd_priv { ...@@ -601,6 +601,10 @@ struct rsnd_priv {
#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) #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_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
#define rsnd_flags_has(p, f) ((p)->flags & (f))
#define rsnd_flags_set(p, f) ((p)->flags |= (f))
#define rsnd_flags_del(p, f) ((p)->flags &= ~(f))
/* /*
* rsnd_kctrl * rsnd_kctrl
*/ */
...@@ -627,6 +631,10 @@ struct rsnd_kctrl_cfg_s { ...@@ -627,6 +631,10 @@ struct rsnd_kctrl_cfg_s {
struct rsnd_kctrl_cfg cfg; struct rsnd_kctrl_cfg cfg;
u32 val; u32 val;
}; };
#define rsnd_kctrl_size(x) ((x).cfg.size)
#define rsnd_kctrl_max(x) ((x).cfg.max)
#define rsnd_kctrl_valm(x, i) ((x).val[i]) /* = (x).cfg.val[i] */
#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */
int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
...@@ -652,9 +660,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, ...@@ -652,9 +660,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
NULL, 1, max) NULL, 1, max)
#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts) \ #define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \
rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
texts, 1, ARRAY_SIZE(texts)) texts, 1, size)
extern const char * const volume_ramp_rate[];
#define VOLUME_RAMP_MAX_DVC (0x17 + 1)
#define VOLUME_RAMP_MAX_MIX (0x0a + 1)
/* /*
* R-Car SSI * R-Car SSI
......
...@@ -101,9 +101,6 @@ struct rsnd_ssi { ...@@ -101,9 +101,6 @@ struct rsnd_ssi {
#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_ssi_flags_has(p, f) ((p)->flags & f)
#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f)
#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f))
#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
#define rsnd_ssi_is_multi_slave(mod, io) \ #define rsnd_ssi_is_multi_slave(mod, io) \
(rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
...@@ -116,10 +113,10 @@ int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) ...@@ -116,10 +113,10 @@ int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0)) if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
return RSND_SSI_HDMI_PORT0; return RSND_SSI_HDMI_PORT0;
if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1)) if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
return RSND_SSI_HDMI_PORT1; return RSND_SSI_HDMI_PORT1;
return 0; return 0;
...@@ -134,7 +131,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) ...@@ -134,7 +131,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
if (!rsnd_ssi_is_dma_mode(mod)) if (!rsnd_ssi_is_dma_mode(mod))
return 0; return 0;
if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF))) if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
use_busif = 1; use_busif = 1;
if (rsnd_io_to_mod_src(io)) if (rsnd_io_to_mod_src(io))
use_busif = 1; use_busif = 1;
...@@ -198,10 +195,15 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) ...@@ -198,10 +195,15 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
{ {
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
u32 mods;
return rsnd_ssi_multi_slaves_runtime(io) | mods = rsnd_ssi_multi_slaves_runtime(io) |
1 << rsnd_mod_id(ssi_mod) | 1 << rsnd_mod_id(ssi_mod);
1 << rsnd_mod_id(ssi_parent_mod);
if (ssi_parent_mod)
mods |= 1 << rsnd_mod_id(ssi_parent_mod);
return mods;
} }
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
...@@ -601,15 +603,18 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, ...@@ -601,15 +603,18 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
if (rsnd_ssi_is_parent(mod, io)) if (rsnd_ssi_is_parent(mod, io))
return 0; return 0;
/*
* disable all IRQ,
* and, wait all data was sent
*/
cr = ssi->cr_own | cr = ssi->cr_own |
ssi->cr_clk; ssi->cr_clk;
rsnd_mod_write(mod, SSICR, cr | EN); /*
rsnd_ssi_status_check(mod, DIRQ); * disable all IRQ,
* Playback: Wait all data was sent
* Capture: It might not receave data. Do nothing
*/
if (rsnd_io_is_play(io)) {
rsnd_mod_write(mod, SSICR, cr | EN);
rsnd_ssi_status_check(mod, DIRQ);
}
/* /*
* disable SSI, * disable SSI,
...@@ -793,13 +798,13 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, ...@@ -793,13 +798,13 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
* But it don't need to call request_irq() many times. * But it don't need to call request_irq() many times.
* Let's control it by RSND_SSI_PROBED flag. * Let's control it by RSND_SSI_PROBED flag.
*/ */
if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
ret = request_irq(ssi->irq, ret = request_irq(ssi->irq,
rsnd_ssi_interrupt, rsnd_ssi_interrupt,
IRQF_SHARED, IRQF_SHARED,
dev_name(dev), mod); dev_name(dev), mod);
rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED); rsnd_flags_set(ssi, RSND_SSI_PROBED);
} }
return ret; return ret;
...@@ -817,10 +822,10 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, ...@@ -817,10 +822,10 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
return 0; return 0;
/* PIO will request IRQ again */ /* PIO will request IRQ again */
if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
free_irq(ssi->irq, mod); free_irq(ssi->irq, mod);
rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED); rsnd_flags_del(ssi, RSND_SSI_PROBED);
} }
return 0; return 0;
...@@ -1003,13 +1008,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, ...@@ -1003,13 +1008,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
ssi = rsnd_mod_to_ssi(mod); ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) { if (strstr(remote_ep->full_name, "hdmi0")) {
rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0); rsnd_flags_set(ssi, RSND_SSI_HDMI0);
dev_dbg(dev, "%s[%d] connected to HDMI0\n", dev_dbg(dev, "%s[%d] connected to HDMI0\n",
rsnd_mod_name(mod), rsnd_mod_id(mod)); rsnd_mod_name(mod), rsnd_mod_id(mod));
} }
if (strstr(remote_ep->full_name, "hdmi1")) { if (strstr(remote_ep->full_name, "hdmi1")) {
rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1); rsnd_flags_set(ssi, RSND_SSI_HDMI1);
dev_dbg(dev, "%s[%d] connected to HDMI1\n", dev_dbg(dev, "%s[%d] connected to HDMI1\n",
rsnd_mod_name(mod), rsnd_mod_id(mod)); rsnd_mod_name(mod), rsnd_mod_id(mod));
} }
...@@ -1042,7 +1047,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) ...@@ -1042,7 +1047,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE)); return !!(rsnd_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
} }
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
...@@ -1128,10 +1133,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ...@@ -1128,10 +1133,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
} }
if (of_get_property(np, "shared-pin", NULL)) if (of_get_property(np, "shared-pin", NULL))
rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
if (of_get_property(np, "no-busif", NULL)) if (of_get_property(np, "no-busif", NULL))
rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF); rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
ssi->irq = irq_of_parse_and_map(np, 0); ssi->irq = irq_of_parse_and_map(np, 0);
if (!ssi->irq) { if (!ssi->irq) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment