OSDN Git Service

ASoC: rsnd: Add Volume Ramp support
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 10 Nov 2014 03:52:06 +0000 (19:52 -0800)
committerMark Brown <broonie@kernel.org>
Mon, 10 Nov 2014 15:14:10 +0000 (15:14 +0000)
This patch adds Volume Ramp to Renesas sound driver.

amixer set "DVC Out" 100%
amixer set "DVC Out Ramp Up Rate"   "0.125 dB/64 steps"
amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
amixer set "DVC Out Ramp" on
aplay xxx.wav &
amixer set "DVC Out"  80%  // Volume Down
amixer set "DVC Out" 100%  // Volume Up

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h

index 956b84e..e2c8473 100644 (file)
@@ -38,6 +38,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 rup;      /* Ramp Rate Up */
+       struct rsnd_dvc_cfg_s rdown;    /* Ramp Rate Down */
 };
 
 #define rsnd_mod_to_dvc(_mod)  \
@@ -49,9 +52,37 @@ 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_volume_update(struct rsnd_mod *mod)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 val[RSND_DVC_CHANNELS];
        u32 dvucr = 0;
        u32 mute = 0;
        int i;
@@ -62,10 +93,35 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
        /* Disable DVC Register access */
        rsnd_mod_write(mod, DVC_DVUER, 0);
 
+       /* Enable Ramp */
+       if (dvc->ren.val) {
+               dvucr |= 0x10;
+
+               /* Digital Volume Max */
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.cfg.max;
+
+               rsnd_mod_write(mod, DVC_VRCTR, 0xff);
+               rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
+                                              dvc->rdown.val);
+               /*
+                * FIXME !!
+                * use scale-downed Digital Volume
+                * as Volume Ramp
+                * 7F FFFF -> 3FF
+                */
+               rsnd_mod_write(mod, DVC_VRDBR,
+                              0x3ff - (dvc->volume.val[0] >> 13));
+
+       } else {
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.val[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]);
+       dvucr |= 0x100;
+       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
+       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
 
        /*  Enable Mute */
        if (mute) {
@@ -324,6 +380,31 @@ 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 Switch" : "DVC In Ramp Switch",
+                       &dvc->ren, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = _rsnd_dvc_pcm_new_e(mod, rdai, rtd,
+                       rsnd_dai_is_play(rdai, io) ?
+                       "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
+                       &dvc->rup,
+                       dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
+       if (ret < 0)
+               return ret;
+
+       ret = _rsnd_dvc_pcm_new_e(mod, rdai, rtd,
+                       rsnd_dai_is_play(rdai, io) ?
+                       "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
+                       &dvc->rdown,
+                       dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
+
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
index a0fed66..87a6f2d 100644 (file)
@@ -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),
index d119adf..ed44ca8 100644 (file)
@@ -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;