diff options
author | Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com> | 2018-05-08 12:16:39 +0900 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-05-09 18:40:39 +0900 |
commit | 5a748de0644d16ceb4192ebf785742619b88109b (patch) | |
tree | df7f3c3cbe31af36092def4d5016c252f3b265fd /sound/soc/uniphier/aio-core.c | |
parent | 0e7b25c673ec916dee8d927fc8de5806d900cba8 (diff) |
ASoC: uniphier: add digital output volume for UniPhier sound system
This patch adds controllers for digital volume of PCM output. Volume
effects simply linear, not dB scale as follows:
Gained PCM = Original * 0x4000 / Volume
The value range of volume is from 0x0001 to 0xffff. 0x0000 works as
mute. Initial value is 0x4000 (+0dB).
Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/uniphier/aio-core.c')
-rw-r--r-- | sound/soc/uniphier/aio-core.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c index e37b80921abb..638cb3fc5f7b 100644 --- a/sound/soc/uniphier/aio-core.c +++ b/sound/soc/uniphier/aio-core.c @@ -660,6 +660,64 @@ void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable) } /** + * aio_port_get_volume - get volume of AIO port block + * @sub: the AIO substream pointer + * + * Return: current volume, range is 0x0000 - 0xffff + */ +int aio_port_get_volume(struct uniphier_aio_sub *sub) +{ + struct regmap *r = sub->aio->chip->regmap; + u32 v; + + regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v); + + return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v); +} + +/** + * aio_port_set_volume - set volume of AIO port block + * @sub: the AIO substream pointer + * @vol: target volume, range is 0x0000 - 0xffff. + * + * Change digital volume and perfome fade-out/fade-in effect for specified + * output slot of port. Gained PCM value can calculate as the following: + * Gained = Original * vol / 0x4000 + */ +void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol) +{ + struct regmap *r = sub->aio->chip->regmap; + int oport_map = sub->swm->oport.map; + int cur, diff, slope = 0, fs; + + if (sub->swm->dir == PORT_DIR_INPUT) + return; + + cur = aio_port_get_volume(sub); + diff = abs(vol - cur); + fs = params_rate(&sub->params); + if (fs) + slope = diff / AUD_VOL_FADE_TIME * 1000 / fs; + slope = max(1, slope); + + regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0), + OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16); + regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0), + OPORTMXTYVOLPARA2_TARGET_MASK, vol); + + if (cur < vol) + regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0), + OPORTMXTYVOLPARA2_FADE_MASK, + OPORTMXTYVOLPARA2_FADE_FADEIN); + else + regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0), + OPORTMXTYVOLPARA2_FADE_MASK, + OPORTMXTYVOLPARA2_FADE_FADEOUT); + + regmap_write(r, AOUTFADECTR0, BIT(oport_map)); +} + +/** * aio_if_set_param - set parameters of AIO DMA I/F block * @sub: the AIO substream pointer * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM. |