diff options
author | Mark Brown <broonie@kernel.org> | 2017-11-10 21:30:57 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-11-10 21:30:57 +0000 |
commit | f904f84609b679c4bd056095a8d778bb40a049cb (patch) | |
tree | 8a3ff7acd944e928b79a807a516091eb9e4f320e /sound/soc | |
parent | 1cae41464ca8a1cced5ce00832f76e5881d2d23b (diff) | |
parent | c409c2a963475f0288ba3bb47a10f04f6441ffb9 (diff) |
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 72 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 51 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ctu.c | 88 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 84 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 60 | ||||
-rw-r--r-- | sound/soc/sh/rcar/mix.c | 158 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 22 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 53 |
8 files changed, 400 insertions, 188 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index e11ce5036bcf..8ddb08714faa 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -44,7 +44,6 @@ struct rsnd_adg { #define LRCLK_ASYNC (1 << 0) #define AUDIO_OUT_48 (1 << 1) -#define adg_mode_flags(adg) (adg->flags) #define for_each_rsnd_clk(pos, adg, i) \ for (i = 0; \ @@ -58,6 +57,13 @@ struct rsnd_adg { i++) #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) { int i, ratio; @@ -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_adg *adg = rsnd_priv_to_adg(priv); 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 shift = (id % 4) * 8; u32 mask = 0xFF << shift; @@ -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); break; } + + dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); } int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; int i; int sel_table[] = { @@ -321,8 +329,6 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) [CLKI] = 0x0, }; - dev_dbg(dev, "request clock = %d\n", rate); - /* * find suitable clock from * 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) rsnd_adg_set_ssi_clk(ssi_mod, data); - if (adg_mode_flags(adg) & LRCLK_ASYNC) { - if (adg_mode_flags(adg) & AUDIO_OUT_48) + if (rsnd_flags_has(adg, LRCLK_ASYNC)) { + if (rsnd_flags_has(adg, AUDIO_OUT_48)) ckr = 0x80000000; } else { if (0 == (rate % 8000)) @@ -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, BRRB, adg->rbgb); - dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", - rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), - data, 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); return 0; } @@ -409,21 +416,12 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, { struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; - static const char * const clk_name[] = { - [CLKA] = "clk_a", - [CLKB] = "clk_b", - [CLKC] = "clk_c", - [CLKI] = "clk_i", - }; int i; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); 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, @@ -479,10 +477,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } 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)) - adg->flags |= LRCLK_ASYNC; + rsnd_flags_set(adg, LRCLK_ASYNC); /* * 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, adg->rbga_rate_for_441khz = rate / div; ckr |= brg_table[i] << 20; 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); } } @@ -528,7 +526,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, adg->rbgb_rate_for_48khz = rate / div; ckr |= brg_table[i] << 16; 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); } } @@ -572,12 +570,35 @@ rsnd_adg_get_clkout_end: adg->ckr = ckr; adg->rbga = rbga; 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", - 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) { @@ -596,6 +617,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkout(priv, adg); + rsnd_adg_clk_dbg_info(priv, adg); priv->adg = adg; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 107133297e8d..c70eb2097816 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -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 rsnd_mod *mod) { @@ -172,8 +164,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, void rsnd_mod_quit(struct rsnd_mod *mod) { - if (mod->clk) - clk_unprepare(mod->clk); + clk_unprepare(mod->clk); mod->clk = NULL; } @@ -200,7 +191,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, int rsnd_io_is_working(struct rsnd_dai_stream *io) { /* 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) @@ -407,11 +401,9 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, for (; *iterator < max; (*iterator)++) { type = (array) ? array[*iterator] : *iterator; - mod = io->mod[type]; - if (!mod) - continue; - - return mod; + mod = rsnd_io_to_mod(io, type); + if (mod) + return mod; } return NULL; @@ -1242,6 +1234,33 @@ struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *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, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index e7f53f44165d..d201d551866d 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -81,8 +81,11 @@ struct rsnd_ctu { struct rsnd_kctrl_cfg_m sv3; struct rsnd_kctrl_cfg_s reset; int channels; + u32 flags; }; +#define KCTRL_INITIALIZED (1 << 0) + #define rsnd_ctu_nr(priv) ((priv)->ctu_nr) #define for_each_rsnd_ctu(pos, priv, i) \ for ((i) = 0; \ @@ -130,7 +133,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, int 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)); @@ -147,44 +150,44 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, rsnd_mod_write(mod, CTU_SCMDR, scmdr); if (scmdr > 0) { - rsnd_mod_write(mod, CTU_SV00R, ctu->sv0.val[0]); - rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]); - rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]); - rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]); - rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]); - rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]); - rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]); - rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]); + rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0)); + rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1)); + rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2)); + rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3)); + rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4)); + rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5)); + rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6)); + rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7)); } if (scmdr > 1) { - rsnd_mod_write(mod, CTU_SV10R, ctu->sv1.val[0]); - rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]); - rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]); - rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]); - rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]); - rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]); - rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]); - rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]); + rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0)); + rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1)); + rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2)); + rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3)); + rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4)); + rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5)); + rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6)); + rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7)); } if (scmdr > 2) { - rsnd_mod_write(mod, CTU_SV20R, ctu->sv2.val[0]); - rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]); - rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]); - rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]); - rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]); - rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]); - rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]); - rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]); + rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0)); + rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1)); + rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2)); + rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3)); + rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4)); + rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5)); + rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6)); + rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7)); } if (scmdr > 3) { - rsnd_mod_write(mod, CTU_SV30R, ctu->sv3.val[0]); - rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]); - rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]); - rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]); - rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]); - rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]); - rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]); - rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]); + rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0)); + rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1)); + rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2)); + rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3)); + rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4)); + rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5)); + rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6)); + rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7)); } rsnd_mod_write(mod, CTU_CTUIR, 0); @@ -196,17 +199,17 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); int i; - if (!ctu->reset.val) + if (!rsnd_kctrl_vals(ctu->reset)) return; for (i = 0; i < RSND_MAX_CHANNELS; i++) { - ctu->pass.val[i] = 0; - ctu->sv0.val[i] = 0; - ctu->sv1.val[i] = 0; - ctu->sv2.val[i] = 0; - ctu->sv3.val[i] = 0; + rsnd_kctrl_valm(ctu->pass, i) = 0; + rsnd_kctrl_valm(ctu->sv0, i) = 0; + rsnd_kctrl_valm(ctu->sv1, i) = 0; + rsnd_kctrl_valm(ctu->sv2, 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, @@ -277,6 +280,9 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); int ret; + if (rsnd_flags_has(ctu, KCTRL_INITIALIZED)) + return 0; + /* CTU Pass */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", rsnd_kctrl_accept_anytime, @@ -326,6 +332,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, rsnd_ctu_value_reset, &ctu->reset, 1); + rsnd_flags_set(ctu, KCTRL_INITIALIZED); + return ret; } diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 041ec1080d52..fd557abfe390 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -60,6 +60,14 @@ struct rsnd_dma_ctrl { #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) #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 */ @@ -211,11 +219,9 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, dma->mod_from, dma->mod_to); if (IS_ERR_OR_NULL(dmaen->chan)) { - int ret = PTR_ERR(dmaen->chan); - dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); - return ret; + return -EIO; } return 0; @@ -747,20 +753,22 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, rsnd_mod_name(this), rsnd_mod_id(this)); for (i = 0; i <= idx; i++) { dev_dbg(dev, " %s[%d]%s\n", - rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), - (mod[i] == *mod_from) ? " from" : - (mod[i] == *mod_to) ? " to" : ""); + rsnd_mod_name(mod[i] ? mod[i] : &mem), + rsnd_mod_id (mod[i] ? mod[i] : &mem), + (mod[i] == *mod_from) ? " from" : + (mod[i] == *mod_to) ? " to" : ""); } } -int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod) +static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, + struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dma *dma; struct rsnd_mod_ops *ops; enum rsnd_mod_type type; 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, type = RSND_MOD_AUDMA; } - if (!(*dma_mod)) { - struct rsnd_dma *dma; + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return -ENOMEM; + *dma_mod = rsnd_mod_get(dma); - *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, - rsnd_mod_get_status, type, dma_id); - if (ret < 0) - return ret; + dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", + rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), + rsnd_mod_name(mod_from ? mod_from : &mem), + 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", - rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), - rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), - rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + ret = attach(io, dma, mod_from, mod_to); + if (ret < 0) + 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; + + 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) 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); - if (ret < 0) - return ret; - - return 0; + return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type); } int rsnd_dma_probe(struct rsnd_priv *priv) @@ -866,5 +881,6 @@ int rsnd_dma_probe(struct rsnd_priv *priv) priv->dma = dmac; - return 0; + /* dummy mem mod for debug */ + return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0); } diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 1743ade3cc55..dbe54f024d68 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -44,8 +44,11 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ 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_nr(priv) ((priv)->dvc_nr) @@ -58,33 +61,6 @@ struct rsnd_dvc { ((pos) = (struct rsnd_dvc *)(priv)->dvc + 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) { rsnd_mod_write(mod, DVC_SWRSR, 0); @@ -97,8 +73,9 @@ static void rsnd_dvc_halt(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_SWRSR, 0); } -#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) -#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) +#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \ + 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, struct rsnd_mod *mod) @@ -108,12 +85,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, int i; /* Enable Ramp */ - if (dvc->ren.val) + if (rsnd_kctrl_vals(dvc->ren)) for (i = 0; i < RSND_MAX_CHANNELS; i++) - val[i] = dvc->volume.cfg.max; + val[i] = rsnd_kctrl_max(dvc->volume); else 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 */ rsnd_mod_write(mod, DVC_VOL0R, val[0]); @@ -143,7 +120,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, dvucr |= 0x101; /* Enable Ramp */ - if (dvc->ren.val) { + if (rsnd_kctrl_vals(dvc->ren)) { dvucr |= 0x10; /* @@ -185,10 +162,10 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, u32 vrdbr = 0; int i; - for (i = 0; i < dvc->mute.cfg.size; i++) - zcmcr |= (!!dvc->mute.cfg.val[i]) << i; + for (i = 0; i < rsnd_kctrl_size(dvc->mute); 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); vrdbr = rsnd_dvc_get_vrdbr(dvc); } @@ -254,6 +231,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, int channels = rsnd_rdai_channels_get(rdai); int ret; + if (rsnd_flags_has(dvc, KCTRL_INITIALIZED)) + return 0; + /* Volume */ ret = rsnd_kctrl_new_m(mod, io, rtd, is_play ? @@ -292,7 +272,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->rup, - dvc_ramp_rate); + volume_ramp_rate, + VOLUME_RAMP_MAX_DVC); if (ret < 0) return ret; @@ -302,11 +283,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->rdown, - dvc_ramp_rate); + volume_ramp_rate, + VOLUME_RAMP_MAX_DVC); if (ret < 0) return ret; + rsnd_flags_set(dvc, KCTRL_INITIALIZED); + return 0; } diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 6c4826c189a4..7998380766f6 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -7,6 +7,33 @@ * it under the terms of the GNU General Public License version 2 as * 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" #define MIX_NAME_SIZE 16 @@ -14,8 +41,27 @@ struct rsnd_mix { 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_nr(priv) ((priv)->mix_nr) #define for_each_rsnd_mix(pos, priv, i) \ @@ -36,26 +82,43 @@ static void rsnd_mix_halt(struct rsnd_mod *mod) 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, struct rsnd_mod *mod) { - rsnd_mod_write(mod, MIX_MDBAR, 0); - rsnd_mod_write(mod, MIX_MDBBR, 0); - rsnd_mod_write(mod, MIX_MDBCR, 0); - rsnd_mod_write(mod, MIX_MDBDR, 0); + 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); + 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, struct rsnd_mod *mod) { + struct rsnd_mix *mix = rsnd_mod_to_mix(mod); + rsnd_mod_write(mod, MIX_MIXIR, 1); /* General Information */ rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); /* volume step */ - rsnd_mod_write(mod, MIX_MIXMR, 0); - rsnd_mod_write(mod, MIX_MVPDR, 0); + rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); + rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | + rsnd_kctrl_vals(mix->rdw)); /* common volume parameter */ rsnd_mix_volume_parameter(io, mod); @@ -109,11 +172,94 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, 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 = { .name = MIX_NAME, .probe = rsnd_mix_probe_, .init = rsnd_mix_init, .quit = rsnd_mix_quit, + .pcm_new = rsnd_mix_pcm_new, }; 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 c5de71f2dc8c..57cd2bc773c2 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -355,8 +355,9 @@ struct rsnd_mod { #define __rsnd_mod_call_nolock_start 0 #define __rsnd_mod_call_nolock_stop 1 -#define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) +#define rsnd_mod_to_priv(mod) ((mod)->priv) +#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_off(mod) clk_disable((mod)->clk) #define rsnd_mod_get(ip) (&(ip)->mod) @@ -371,7 +372,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, enum rsnd_mod_type type, int id); 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 rsnd_mod *mod); void rsnd_mod_interrupt(struct rsnd_mod *mod, @@ -601,6 +601,10 @@ 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_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 */ @@ -627,6 +631,10 @@ struct rsnd_kctrl_cfg_s { struct rsnd_kctrl_cfg cfg; 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_runtime(struct rsnd_dai_stream *io); @@ -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), \ 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), \ - 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 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 03c2a1f02643..fece1e5f582f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -101,9 +101,6 @@ struct rsnd_ssi { #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #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_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) @@ -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_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; - if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1)) + if (rsnd_flags_has(ssi, RSND_SSI_HDMI1)) return RSND_SSI_HDMI_PORT1; return 0; @@ -134,7 +131,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) if (!rsnd_ssi_is_dma_mode(mod)) return 0; - if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF))) + if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF))) use_busif = 1; if (rsnd_io_to_mod_src(io)) use_busif = 1; |