summaryrefslogtreecommitdiff
path: root/sound/soc/uniphier/aio-core.c
diff options
context:
space:
mode:
authorKatsuhiro Suzuki <suzuki.katsuhiro@socionext.com>2018-05-08 12:16:39 +0900
committerMark Brown <broonie@kernel.org>2018-05-09 18:40:39 +0900
commit5a748de0644d16ceb4192ebf785742619b88109b (patch)
treedf7f3c3cbe31af36092def4d5016c252f3b265fd /sound/soc/uniphier/aio-core.c
parent0e7b25c673ec916dee8d927fc8de5806d900cba8 (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.c58
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.