ASoC: sgtl5000: Calculate Lineout Channel Output Level
authorAlexander Stein <alexander.stein@systec-electronic.com>
Thu, 16 Apr 2015 12:51:57 +0000 (14:51 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 27 Apr 2015 14:42:20 +0000 (15:42 +0100)
Currently LO_VOL_* stays at it's default (0x4 each) but this should be
calculated after setting VAG_VAL and LO_VAGCNTRL.
LO_VOL_* = 40 * log10(VAG_VAL / LO_VAGCNTRL) + 15

To avoid the log10 operation a table for all valid register values is
precalculated which contains the corresponding value
(VAG_VAL * 100 / LO_VAGCNTRL).

Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/sgtl5000.c

index bab2b5e..1b88343 100644 (file)
@@ -1092,6 +1092,19 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
 }
 
 /*
+ * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
+ * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
+ * The calculatation was done for all possible register values which
+ * is the array index and the following formula: 10^((idx−15)/40) * 100
+ */
+static const u8 vol_quot_table[] = {
+       42, 45, 47, 50, 53, 56, 60, 63,
+       67, 71, 75, 79, 84, 89, 94, 100,
+       106, 112, 119, 126, 133, 141, 150, 158,
+       168, 178, 188, 200, 211, 224, 237, 251
+};
+
+/*
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
  * 2. charge pump, set to different value
@@ -1112,6 +1125,9 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
        u16 lreg_ctrl;
        int vag;
        int lo_vag;
+       int vol_quot;
+       int lo_vol;
+       size_t i;
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
@@ -1216,6 +1232,28 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                        SGTL5000_LINE_OUT_CURRENT_360u <<
                                SGTL5000_LINE_OUT_CURRENT_SHIFT);
 
+       /*
+        * Set lineout output level in range (0..31)
+        * the same value is used for right and left channel
+        *
+        * Searching for a suitable index solving this formula:
+        * idx = 40 * log10(vag_val / lo_cagcntrl) + 15
+        */
+       vol_quot = (vag * 100) / lo_vag;
+       lo_vol = 0;
+       for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
+               if (vol_quot >= vol_quot_table[i])
+                       lo_vol = i;
+               else
+                       break;
+       }
+
+       snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL,
+               SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
+               SGTL5000_LINE_OUT_VOL_LEFT_MASK,
+               lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
+               lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT);
+
        return 0;
 }