Commit 1f39d939 authored by Alexander Stein's avatar Alexander Stein Committed by Mark Brown
Browse files

ASoC: sgtl5000: Calculate Lineout Channel Output Level



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: default avatarAlexander Stein <alexander.stein@systec-electronic.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent d2b7c2aa
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -1091,6 +1091,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
@@ -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;
}