[alsa-devel] [PATCH 0/8] ASoC: rsnd: add Volume Ramp support
Hi Mark
These patches add Volume Ramp support on Renesas R-Car sound driver.
Kuninori Morimoto (8): ASoC: rsnd: tidyup debug information when read/write ASoC: rsnd: tidyup RSND_DVC_VOLUME_NUM to RSND_DVC_CHANNELS ASoC: rsnd: add struct rsnd_dvc_cfg and control DVC settings ASoC: rsnd: control DVC_DVUCR under rsnd_dvc_volume_update() ASoC: rsnd: move DVC_DVUER settings under rsnd_dvc_volume_update() ASoC: rsnd: enable multiple DVC valume settings ASoC: rsnd: enable single DVC valume settings ASoC: rsnd: Add Volume Ramp support
sound/soc/sh/rcar/dvc.c | 155 ++++++++++++++++++++++++++++++++++------------ sound/soc/sh/rcar/gen.c | 30 ++++++--- sound/soc/sh/rcar/rsnd.h | 6 ++ 3 files changed, 145 insertions(+), 46 deletions(-)
Best regards --- Kuninori Morimoto
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
b8c637864a6904a9ba8e0df556d5bdf9f26b2c54 (ASoC: rsnd: use regmap_mmio instead of original regmap bus) added regmap_mmio support on Renesas R-Car sound driver. Then, debug information of register read/write indicates regmap index, not register address. This is a little bit confusable information. This patch tidyup debug message, and added regmap debug hint on comment area.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index f95e7ab..61dee68 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -8,6 +8,17 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +/* + * #define DEBUG + * + * you can also add below in + * ${LINUX}/drivers/base/regmap/regmap.c + * for regmap debug + * + * #define LOG_DEVICE "xxxx.rcar_sound" + */ + #include "rsnd.h"
struct rsnd_gen { @@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return 0;
- regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); + dev_dbg(dev, "r %s(%d) - %4d : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
- dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); + regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
return val; } @@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return;
- regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); + dev_dbg(dev, "w %s(%d) - %4d : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
- dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); + regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); }
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, @@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, if (!rsnd_is_accessible_reg(priv, gen, reg)) return;
+ dev_dbg(dev, "b %s(%d) - %4d : %08x/%08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); + regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), mask, data); - - dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n", - rsnd_mod_name(mod), reg, data, mask); }
#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
On Tue, Oct 21, 2014 at 06:13:46PM -0700, Kuninori Morimoto wrote:
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
b8c637864a6904a9ba8e0df556d5bdf9f26b2c54 (ASoC: rsnd: use regmap_mmio instead of original regmap bus) added regmap_mmio support on Renesas R-Car sound driver.
Applied, thanks.
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
RSND_DVC_VOLUME_NUM means DVC channel number. This patch tidyups this un-understandable naming
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 3f44393..b5f95ad4 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -12,7 +12,7 @@
#define RSND_DVC_NAME_SIZE 16 #define RSND_DVC_VOLUME_MAX 100 -#define RSND_DVC_VOLUME_NUM 2 +#define RSND_DVC_CHANNELS 2
#define DVC_NAME "dvc"
@@ -20,8 +20,8 @@ struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct clk *clk; - u8 volume[RSND_DVC_VOLUME_NUM]; - u8 mute[RSND_DVC_VOLUME_NUM]; + u8 volume[RSND_DVC_CHANNELS]; + u8 mute[RSND_DVC_CHANNELS]; };
#define rsnd_mod_to_dvc(_mod) \ @@ -37,11 +37,11 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); u32 max = (0x00800000 - 1); - u32 vol[RSND_DVC_VOLUME_NUM]; + u32 vol[RSND_DVC_CHANNELS]; u32 mute = 0; int i;
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { + for (i = 0; i < RSND_DVC_CHANNELS; i++) { vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; mute |= (!!dvc->mute[i]) << i; } @@ -150,7 +150,7 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); u8 *val = (u8 *)kctrl->private_value;
- uinfo->count = RSND_DVC_VOLUME_NUM; + uinfo->count = RSND_DVC_CHANNELS; uinfo->value.integer.min = 0;
if (val == dvc->volume) { @@ -170,7 +170,7 @@ static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, u8 *val = (u8 *)kctrl->private_value; int i;
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) + for (i = 0; i < RSND_DVC_CHANNELS; i++) ucontrol->value.integer.value[i] = val[i];
return 0; @@ -183,7 +183,7 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, u8 *val = (u8 *)kctrl->private_value; int i, change = 0;
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { + for (i = 0; i < RSND_DVC_CHANNELS; i++) { change |= (ucontrol->value.integer.value[i] != val[i]); val[i] = ucontrol->value.integer.value[i]; }
On Tue, Oct 21, 2014 at 06:13:56PM -0700, Kuninori Morimoto wrote:
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
RSND_DVC_VOLUME_NUM means DVC channel number. This patch tidyups this un-understandable naming
Applied, thanks.
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
DVC can control Digital Volume / Mute / Volume Ramp etc, and these uses different max value. Current driver is using fixed max value for each settings. This patch adds new struct rsnd_dvc_cfg, and control these.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 51 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index b5f95ad4..deaf0fa 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -11,17 +11,21 @@ #include "rsnd.h"
#define RSND_DVC_NAME_SIZE 16 -#define RSND_DVC_VOLUME_MAX 100 #define RSND_DVC_CHANNELS 2
#define DVC_NAME "dvc"
+struct rsnd_dvc_cfg { + unsigned int max; + u32 val[RSND_DVC_CHANNELS]; +}; + struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct clk *clk; - u8 volume[RSND_DVC_CHANNELS]; - u8 mute[RSND_DVC_CHANNELS]; + struct rsnd_dvc_cfg volume; + struct rsnd_dvc_cfg mute; };
#define rsnd_mod_to_dvc(_mod) \ @@ -36,18 +40,15 @@ struct rsnd_dvc { static void rsnd_dvc_volume_update(struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 max = (0x00800000 - 1); - u32 vol[RSND_DVC_CHANNELS]; u32 mute = 0; int i;
for (i = 0; i < RSND_DVC_CHANNELS; i++) { - vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; - mute |= (!!dvc->mute[i]) << i; + mute |= (!!dvc->mute.val[i]) << i; }
- rsnd_mod_write(mod, DVC_VOL0R, vol[0]); - rsnd_mod_write(mod, DVC_VOL1R, vol[1]); + rsnd_mod_write(mod, DVC_VOL0R, dvc->volume.val[0]); + rsnd_mod_write(mod, DVC_VOL1R, dvc->volume.val[1]);
rsnd_mod_write(mod, DVC_ZCMCR, mute); } @@ -146,20 +147,16 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo) { - struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u8 *val = (u8 *)kctrl->private_value; + struct rsnd_dvc_cfg *cfg = (struct rsnd_dvc_cfg *)kctrl->private_value;
uinfo->count = RSND_DVC_CHANNELS; uinfo->value.integer.min = 0; + uinfo->value.integer.max = cfg->max;
- if (val == dvc->volume) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; - } else { + if (cfg->max == 1) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->value.integer.max = 1; - } + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
return 0; } @@ -167,11 +164,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *ucontrol) { - u8 *val = (u8 *)kctrl->private_value; + struct rsnd_dvc_cfg *cfg = (struct rsnd_dvc_cfg *)kctrl->private_value; int i;
for (i = 0; i < RSND_DVC_CHANNELS; i++) - ucontrol->value.integer.value[i] = val[i]; + ucontrol->value.integer.value[i] = cfg->val[i];
return 0; } @@ -180,12 +177,12 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *ucontrol) { struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); - u8 *val = (u8 *)kctrl->private_value; + struct rsnd_dvc_cfg *cfg = (struct rsnd_dvc_cfg *)kctrl->private_value; int i, change = 0;
for (i = 0; i < RSND_DVC_CHANNELS; i++) { - change |= (ucontrol->value.integer.value[i] != val[i]); - val[i] = ucontrol->value.integer.value[i]; + change |= (ucontrol->value.integer.value[i] != cfg->val[i]); + cfg->val[i] = ucontrol->value.integer.value[i]; }
if (change) @@ -198,7 +195,7 @@ static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct snd_soc_pcm_runtime *rtd, const unsigned char *name, - u8 *private) + struct rsnd_dvc_cfg *private) { struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; @@ -232,18 +229,20 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, int ret;
/* Volume */ + dvc->volume.max = 0x00800000 - 1; ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, rsnd_dai_is_play(rdai, io) ? "DVC Out Playback Volume" : "DVC In Capture Volume", - dvc->volume); + &dvc->volume); if (ret < 0) return ret;
/* Mute */ + dvc->mute.max = 1; ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, rsnd_dai_is_play(rdai, io) ? "DVC Out Mute Switch" : "DVC In Mute Switch", - dvc->mute); + &dvc->mute); if (ret < 0) return ret;
On Tue, Oct 21, 2014 at 06:14:14PM -0700, Kuninori Morimoto wrote:
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
DVC can control Digital Volume / Mute / Volume Ramp etc, and these uses different max value.
Applied, thanks.
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
rsnd_dvc_volume_update() is main function to control DVC feature like Digital Volume / Mute / Ramp etc. DVC_DVUCR should be controlled under this function.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index deaf0fa..3952237 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -40,6 +40,7 @@ struct rsnd_dvc { static void rsnd_dvc_volume_update(struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 dvucr = 0; u32 mute = 0; int i;
@@ -47,10 +48,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) mute |= (!!dvc->mute.val[i]) << i; }
+ /* Enable Digital Volume */ + dvucr = 0x100; rsnd_mod_write(mod, DVC_VOL0R, dvc->volume.val[0]); rsnd_mod_write(mod, DVC_VOL1R, dvc->volume.val[1]);
- rsnd_mod_write(mod, DVC_ZCMCR, mute); + /* Enable Mute */ + if (mute) { + dvucr |= 0x1; + rsnd_mod_write(mod, DVC_ZCMCR, mute); + } + + rsnd_mod_write(mod, DVC_DVUCR, dvucr); }
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, @@ -103,9 +112,6 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
- /* enable Volume / Mute */ - rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101); - /* ch0/ch1 Volume */ rsnd_dvc_volume_update(dvc_mod);
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
We need to Enable/Disable DVC_DVUER register if we set DVCp_ZCMCR, DVCp_VRCTR, DVCp_VRPDR, DVCp_VRDBR, DVCp_VOL0R, DVCp_VOL1R, DVCp_VOL2R, DVCp_VOL3R, DVCp_VOL4R, DVCp_VOL5R, DVCp_VOL6R, DVCp_VOL7R and, these are controlled under rsnd_dvc_volume_update(). This patch moves DVC_DVUER settings to it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 3952237..2fbaf27 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -48,6 +48,9 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) mute |= (!!dvc->mute.val[i]) << i; }
+ /* Enable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 1); + /* Enable Digital Volume */ dvucr = 0x100; rsnd_mod_write(mod, DVC_VOL0R, dvc->volume.val[0]); @@ -60,6 +63,9 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) }
rsnd_mod_write(mod, DVC_DVUCR, dvucr); + + /* Disable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 0); }
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, @@ -117,8 +123,6 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
- rsnd_mod_write(dvc_mod, DVC_DVUER, 1); - rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
return 0;
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
DVC controls some digital volume features. Some of them requests values for "each channels", but, some of them requests values for "feature". Current dvc.c is supporting Mute/Volume, and these have "each channels" settings. This patch adds rsnd_dvc_cfg_m and care about multiple settings for each channels.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 2fbaf27..e4dd1d8 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -17,6 +17,12 @@
struct rsnd_dvc_cfg { unsigned int max; + unsigned int size; + u32 *val; +}; + +struct rsnd_dvc_cfg_m { + struct rsnd_dvc_cfg cfg; u32 val[RSND_DVC_CHANNELS]; };
@@ -24,8 +30,8 @@ struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct clk *clk; - struct rsnd_dvc_cfg volume; - struct rsnd_dvc_cfg mute; + struct rsnd_dvc_cfg_m volume; + struct rsnd_dvc_cfg_m mute; };
#define rsnd_mod_to_dvc(_mod) \ @@ -44,9 +50,8 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) u32 mute = 0; int i;
- for (i = 0; i < RSND_DVC_CHANNELS; i++) { - mute |= (!!dvc->mute.val[i]) << i; - } + for (i = 0; i < dvc->mute.cfg.size; i++) + mute |= (!!dvc->mute.cfg.val[i]) << i;
/* Enable DVC Register access */ rsnd_mod_write(mod, DVC_DVUER, 1); @@ -177,7 +182,7 @@ static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, struct rsnd_dvc_cfg *cfg = (struct rsnd_dvc_cfg *)kctrl->private_value; int i;
- for (i = 0; i < RSND_DVC_CHANNELS; i++) + for (i = 0; i < cfg->size; i++) ucontrol->value.integer.value[i] = cfg->val[i];
return 0; @@ -190,7 +195,7 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, struct rsnd_dvc_cfg *cfg = (struct rsnd_dvc_cfg *)kctrl->private_value; int i, change = 0;
- for (i = 0; i < RSND_DVC_CHANNELS; i++) { + for (i = 0; i < cfg->size; i++) { change |= (ucontrol->value.integer.value[i] != cfg->val[i]); cfg->val[i] = ucontrol->value.integer.value[i]; } @@ -230,6 +235,19 @@ static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, return 0; }
+static int _rsnd_dvc_pcm_new_m(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + struct rsnd_dvc_cfg_m *private, + u32 max) +{ + private->cfg.max = max; + private->cfg.size = RSND_DVC_CHANNELS; + private->cfg.val = private->val; + return __rsnd_dvc_pcm_new(mod, rdai, rtd, name, &private->cfg); +} + static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct snd_soc_pcm_runtime *rtd) @@ -239,20 +257,18 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, int ret;
/* Volume */ - dvc->volume.max = 0x00800000 - 1; - ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, + ret = _rsnd_dvc_pcm_new_m(mod, rdai, rtd, rsnd_dai_is_play(rdai, io) ? "DVC Out Playback Volume" : "DVC In Capture Volume", - &dvc->volume); + &dvc->volume, 0x00800000 - 1); if (ret < 0) return ret;
/* Mute */ - dvc->mute.max = 1; - ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, + ret = _rsnd_dvc_pcm_new_m(mod, rdai, rtd, rsnd_dai_is_play(rdai, io) ? "DVC Out Mute Switch" : "DVC In Mute Switch", - &dvc->mute); + &dvc->mute, 1); if (ret < 0) return ret;
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
DVC controls some digital volume features. Some of them requests values for "each channels", but, some of them requests values for "feature". And, Volume Ramp has "feature" settings. This patch adds rsnd_dvc_cfg_s and care about single settings. Compiler will report like below at this point, but, it will be removed if Volume Ramp was supported. warning: '_rsnd_dvc_pcm_new_s' defined but not used
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index e4dd1d8..2654ab0 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -26,6 +26,11 @@ struct rsnd_dvc_cfg_m { u32 val[RSND_DVC_CHANNELS]; };
+struct rsnd_dvc_cfg_s { + struct rsnd_dvc_cfg cfg; + u32 val; +}; + struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; @@ -248,6 +253,19 @@ static int _rsnd_dvc_pcm_new_m(struct rsnd_mod *mod, return __rsnd_dvc_pcm_new(mod, rdai, rtd, name, &private->cfg); }
+static int _rsnd_dvc_pcm_new_s(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + struct rsnd_dvc_cfg_s *private, + u32 max) +{ + private->cfg.max = max; + private->cfg.size = 1; + private->cfg.val = &private->val; + return __rsnd_dvc_pcm_new(mod, rdai, rtd, name, &private->cfg); +} + static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct snd_soc_pcm_runtime *rtd)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
This patch adds Volume Ramp to Renesas sound driver.
This sample indicates Mute -> Volume 100% -> Mute
amixer set "DVC Out Ramp" 100% // Mute as default amixer set "DVC Out Ramp Period" 80% amixer set "DVC Out Ramp Enable" on aplay xxx.wav & amixer set "DVC Out Ramp" 0% // to Volume 100% amixer set "DVC Out Ramp" 100% // to Mute
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 34 ++++++++++++++++++++++++++++++++++ sound/soc/sh/rcar/gen.c | 3 +++ sound/soc/sh/rcar/rsnd.h | 6 ++++++ 3 files changed, 43 insertions(+)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 2654ab0..f353f7d 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -37,6 +37,9 @@ struct rsnd_dvc { struct clk *clk; struct rsnd_dvc_cfg_m volume; struct rsnd_dvc_cfg_m mute; + struct rsnd_dvc_cfg_s ren; /* Ramp Enable */ + struct rsnd_dvc_cfg_s rperiod; /* Ramp Period */ + struct rsnd_dvc_cfg_s rvol; /* Ramp Volume */ };
#define rsnd_mod_to_dvc(_mod) \ @@ -66,6 +69,15 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_VOL0R, dvc->volume.val[0]); rsnd_mod_write(mod, DVC_VOL1R, dvc->volume.val[1]);
+ /* Enable Ramp */ + if (dvc->ren.val) { + dvucr |= 0x10; + rsnd_mod_write(mod, DVC_VRCTR, 0xff); + rsnd_mod_write(mod, DVC_VRPDR, dvc->rperiod.val << 8 | + dvc->rperiod.val); + rsnd_mod_write(mod, DVC_VRDBR, dvc->rvol.val); + } + /* Enable Mute */ if (mute) { dvucr |= 0x1; @@ -290,6 +302,28 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, if (ret < 0) return ret;
+ /* Ramp */ + ret = _rsnd_dvc_pcm_new_s(mod, rdai, rtd, + rsnd_dai_is_play(rdai, io) ? + "DVC Out Ramp Enable" : "DVC In Ramp Enable", + &dvc->ren, 1); + if (ret < 0) + return ret; + + ret = _rsnd_dvc_pcm_new_s(mod, rdai, rtd, + rsnd_dai_is_play(rdai, io) ? + "DVC Out Ramp Period" : "DVC In Ramp Period", + &dvc->rperiod, 0x17); /* 10111 */ + if (ret < 0) + return ret; + + ret = _rsnd_dvc_pcm_new_s(mod, rdai, rtd, + rsnd_dai_is_play(rdai, io) ? + "DVC Out Ramp Volume" : "DVC In Ramp Volume", + &dvc->rvol, 0x3ff); + if (ret < 0) + return ret; + return 0; }
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 61dee68..4cb3202 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -324,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), + RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), + RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), + RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d119adf..ed44ca8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -91,6 +91,9 @@ enum rsnd_reg { RSND_REG_SHARE20, RSND_REG_SHARE21, RSND_REG_SHARE22, + RSND_REG_SHARE23, + RSND_REG_SHARE24, + RSND_REG_SHARE25,
RSND_REG_MAX, }; @@ -129,6 +132,9 @@ enum rsnd_reg { #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 +#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 +#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 +#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
struct rsnd_of_data; struct rsnd_priv;
On Tue, Oct 21, 2014 at 06:14:55PM -0700, Kuninori Morimoto wrote:
This sample indicates Mute -> Volume 100% -> Mute
amixer set "DVC Out Ramp" 100% // Mute as default amixer set "DVC Out Ramp Period" 80%
Normally this would be expressed as an enum with some sort of time units. We did discuss at the mini-summit making a standard way of expressing this but nobody did that yet.
amixer set "DVC Out Ramp Enable" on
That "Enable" should be a Switch control.
aplay xxx.wav & amixer set "DVC Out Ramp" 0% // to Volume 100% amixer set "DVC Out Ramp" 100% // to Mute
I'm not sure I quite understand this control - what exactly is this setting? It appears that the ramp value is the opposite of the volume we end up with which is a bit odd and the comments suggest that this is actually triggering a ramp when normally ramps would be done as part of a volume set, mute or power up/down operation.
Hi Mark
Thank you for your feedback
amixer set "DVC Out Ramp" 100% // Mute as default amixer set "DVC Out Ramp Period" 80%
Normally this would be expressed as an enum with some sort of time units. We did discuss at the mini-summit making a standard way of expressing this but nobody did that yet.
OK, I can be a 1st guy :) The HW setting is like below
value: mean 00000: 128 dB/1 step 00001: 64 dB/1 step 00010: 32 dB/1 step ... 10101: 0.125 dB/2048 steps 10110: 0.125 dB/4096 steps 10111: 0.125 dB/8192 steps
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
amixer set "DVC Out Ramp Period" 15000 // 15sec
aplay xxx.wav & amixer set "DVC Out Ramp" 0% // to Volume 100% amixer set "DVC Out Ramp" 100% // to Mute
I'm not sure I quite understand this control - what exactly is this setting? It appears that the ramp value is the opposite of the volume we end up with which is a bit odd and the comments suggest that this is actually triggering a ramp when normally ramps would be done as part of a volume set, mute or power up/down operation.
Current "DVC Out Ramp" want to have direct value of register. It is...
000: 1 time ... 031: 0.5 time ... 3FE: 4.1 x 10^-7 time 3FF: Mute
Maybe I can used inverted value for it ?
amixer set "DVC Out Ramp" 100% // to Volume 100% amixer set "DVC Out Ramp" 0% // to Mute
On Tue, Oct 28, 2014 at 05:26:06PM -0700, Kuninori Morimoto wrote:
amixer set "DVC Out Ramp" 100% // Mute as default amixer set "DVC Out Ramp Period" 80%
Normally this would be expressed as an enum with some sort of time units. We did discuss at the mini-summit making a standard way of expressing this but nobody did that yet.
OK, I can be a 1st guy :) The HW setting is like below
value: mean 00000: 128 dB/1 step
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
Yes, please - much easier for users.
amixer set "DVC Out Ramp" 0% // to Volume 100% amixer set "DVC Out Ramp" 100% // to Mute
I'm not sure I quite understand this control - what exactly is this setting? It appears that the ramp value is the opposite of the volume we end up with which is a bit odd and the comments suggest that this is actually triggering a ramp when normally ramps would be done as part of a volume set, mute or power up/down operation.
Current "DVC Out Ramp" want to have direct value of register. It is...
000: 1 time ... 031: 0.5 time ... 3FE: 4.1 x 10^-7 time 3FF: Mute
Maybe I can used inverted value for it ?
That sounds like it'd address part of it, though I'm still not 100% sure what the effect of this control is - is it the final value or something (0.5*programmed volume for example)?
Hi Mark
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
Yes, please - much easier for users.
OK, will try again
000: 1 time ... 031: 0.5 time ... 3FE: 4.1 x 10^-7 time 3FF: Mute
Maybe I can used inverted value for it ?
That sounds like it'd address part of it, though I'm still not 100% sure what the effect of this control is - is it the final value or something (0.5*programmed volume for example)?
In easy explain, we can set "Volume Ramp Period" (= it will be "time" instead), and "Volume scale". see below...
/* * we already have default Volume here. * I use it as "volume X" */
/* * This sample want to use "Volume Up" * Mute -> volume X */
/* * target volume for "start" is Mute. * volume X x 0 time = volume 0 */ amixer set "DVC Out Ramp" 0% // Mute as default
/* * We want to Volume up in 15sec */ amixer set "DVC Out Ramp Period" 15000
/* * Start sound playback with Volume Ramp */ amixer set "DVC Out Ramp Enable" on aplay xxx.wav &
/* * Volume up. Mute -> volume X * Current Volume = Mute = * volume X x 0 time = volume 0 * Set next target volume * volume X x 1 time = volume X */ amixer set "DVC Out Ramp" 100% // to Volume 100%
/* * Back to Mute again * Current Volume = * volume X x 1 time = volume X * Set next target volume * volume X x 0 time = volume 0 */ amixer set "DVC Out Ramp" 0% // to Mute
Best regards --- Kuninori Morimoto
On Wed, Oct 29, 2014 at 05:28:19PM -0700, Kuninori Morimoto wrote:
000: 1 time ... 031: 0.5 time ... 3FE: 4.1 x 10^-7 time 3FF: Mute
Maybe I can used inverted value for it ?
That sounds like it'd address part of it, though I'm still not 100% sure what the effect of this control is - is it the final value or something (0.5*programmed volume for example)?
In easy explain, we can set "Volume Ramp Period" (= it will be "time" instead), and "Volume scale". see below...
/*
- target volume for "start" is Mute.
- volume X x 0 time = volume 0
*/ amixer set "DVC Out Ramp" 0% // Mute as default
I'm sorry, this explanation still isn't at all clear to me. Can you explain it in words please?
Hi Mark
/*
- target volume for "start" is Mute.
- volume X x 0 time = volume 0
*/ amixer set "DVC Out Ramp" 0% // Mute as default
I'm sorry, this explanation still isn't at all clear to me. Can you explain it in words please?
Our DVC Volume Ramp is doing "Normal volume" x "Volume scale". "Volume scale" exchange Volume in "X db / Y step" (= speed). Our "Volume Ramp" exchange this "Volume scale" in "X db / Y step" speed.
"Normal Volume" x 0 => "Normal Volume" x 1
Does this good answer for you ?
Best regards --- Kuninori Morimoto
On Mon, Nov 03, 2014 at 04:30:00PM -0800, Kuninori Morimoto wrote:
/*
- target volume for "start" is Mute.
- volume X x 0 time = volume 0
*/ amixer set "DVC Out Ramp" 0% // Mute as default
I'm sorry, this explanation still isn't at all clear to me. Can you explain it in words please?
Our DVC Volume Ramp is doing "Normal volume" x "Volume scale". "Volume scale" exchange Volume in "X db / Y step" (= speed). Our "Volume Ramp" exchange this "Volume scale" in "X db / Y step" speed.
"Normal Volume" x 0 => "Normal Volume" x 1
Does this good answer for you ?
OK, that's what I'd thought that the control should be doing based on the naming but the examples you were showing were confusing. Let me take a look at the new version you posted...
Hi Mark again
OK, I can be a 1st guy :) The HW setting is like below
value: mean 00000: 128 dB/1 step
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
Yes, please - much easier for users.
I tried to use "time" for Volume Ramp, but it seems difficult.
1) datasheet indicates Volume Ramp (= x dB / y step) but, there is no document "what is step" here. (even though HW guy...)
2) Volume UP/Down time depends on "Volume Ramp" and Start/Stop Volume If 0% -> 100% takes X sec, 50% -> 100% takes X/2 sec. But,we don't know final Volume (= 5, 6) when user sets "Volume Ramp" (= 1).
1. amixer set "DVC Out Ramp Period" xxx // set Period 2. amixer set "DVC Out Ramp" 0% // Mute as default 3. amixer set "DVC Out Ramp" on // enable Volume Ramp 4. aplay xxx.wav & 5. amixer set "DVC Out Ramp" 100% // to Volume 100% 6. amixer set "DVC Out Ramp" 0% // to Mute
3) If we can calculate it somehow, Volume UP/Down speed is not same.
amixer set "DVC Out Ramp Period" 10000 // Volume UP/Down in 10 sec 0% -> 100% 50% -> 100% are happen in 10 sec. 90% -> 100% This is confusable ?
Best regards --- Kuninori Morimoto
On Wed, Oct 29, 2014 at 11:11:23PM -0700, Kuninori Morimoto wrote:
OK, I can be a 1st guy :) The HW setting is like below
value: mean 00000: 128 dB/1 step
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
Yes, please - much easier for users.
I tried to use "time" for Volume Ramp, but it seems difficult.
No, just quote it as you've listed it above rather than with the absolute time.
Hi Mark
value: mean 00000: 128 dB/1 step
Current "DVC Out Ramp Period" wants to have direct value of register. But, upstream want to have time like this ?
Yes, please - much easier for users.
I tried to use "time" for Volume Ramp, but it seems difficult.
No, just quote it as you've listed it above rather than with the absolute time.
Sorry, do you mean list it in source code as comment ? or, do you mean like this ?
amixer "DVC Ramp time" "128db/1step"
On Mon, Nov 03, 2014 at 04:07:44PM -0800, Kuninori Morimoto wrote:
No, just quote it as you've listed it above rather than with the absolute time.
Sorry, do you mean list it in source code as comment ? or, do you mean like this ?
amixer "DVC Ramp time" "128db/1step"
Like this second one (just say 128dB/step if it's only one step).
Hi Mark
No, just quote it as you've listed it above rather than with the absolute time.
Sorry, do you mean list it in source code as comment ? or, do you mean like this ?
amixer "DVC Ramp time" "128db/1step"
Like this second one (just say 128dB/step if it's only one step).
Maybe this is bikeshed, but I want to use same as "datasheet words". Some of them is not "1 step".
"128 dB/1 step", "64 dB/1 step", "32 dB/1 step", "16 dB/1 step", "8 dB/1 step", "4 dB/1 step", "2 dB/1 step", "1 dB/1 step", "0.5 dB/1 step", "0.25 dB/1 step", "0.125 dB/1 step", "0.125 dB/2 steps", "0.125 dB/4 steps", "0.125 dB/8 steps", "0.125 dB/16 steps", "0.125 dB/32 steps", "0.125 dB/64 steps", "0.125 dB/128 steps", "0.125 dB/256 steps", "0.125 dB/512 steps", "0.125 dB/1024 steps", "0.125 dB/2048 steps", "0.125 dB/4096 steps", "0.125 dB/8192 steps",
On Tue, Nov 04, 2014 at 04:10:39PM -0800, Kuninori Morimoto wrote:
Like this second one (just say 128dB/step if it's only one step).
Maybe this is bikeshed, but I want to use same as "datasheet words". Some of them is not "1 step".
"0.125 dB/1 step", "0.125 dB/2 steps", "0.125 dB/4 steps",
That's absolutely fine - I didn't realise they weren't all a single step.
participants (2)
-
Kuninori Morimoto
-
Mark Brown