[alsa-devel] ASoC: Defining "signed integer" mixer controls?
Hi all...
I'm posting this via GMane since my server at home seems to be down, hopefully it gets through. I hope to put a version of the TLV320AIC3204 driver that I've been working on up there -- I did try posting it to the list, but I suspect it's either been left in the moderation queue or silently dropped. In short, I got the sound working; just testing playback for now... Recording should work, once I get the mixer set up.
My query though; the mixer on this CODEC provides gain settings, helpfully scaled in dB, as signed integers. For instance; the four line level output drivers: Headphone left/right,and Line Out left/right, can all be adjusted in gain from -6dB through to +29dB.
These are set in individual registers as the lower 6 bits; so: -6 dB is represented as 111010 (0x3a) 29 dB is represented as 011101 (0x1d)
At the moment, things "half work" with the following code: /* * DAC digital volumes. From -63.5 to +24 dB in 0.5 dB steps */ static DECLARE_TLV_DB_MINMAX(dac_tlv, -6350, 2400); /* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */ static DECLARE_TLV_DB_MINMAX(adc_tlv, 0, 0); /* * Output driver stage volumes; -6dB through to +29dB */ static DECLARE_TLV_DB_MINMAX(output_stage_tlv, -600, 2900);
static const struct snd_kcontrol_new aic3204_snd_controls[] = { /* Output */ SOC_DOUBLE_R_TLV("Headphone Output Volume", AIC3204_HPLGAIN, AIC3204_HPRGAIN, 0, 29, 0, output_stage_tlv), SOC_DOUBLE_R_TLV("Line Output Volume", AIC3204_LOLGAIN, AIC3204_LORGAIN, 0, 29, 0, output_stage_tlv), SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC3204_LDACVOL, AIC3204_RDACVOL, 0, 127, 0, dac_tlv), ...
However; it treats the bitfield as unsigned, which is wrong in this case. The bitfield is a signed integer in two's complement format. How do I convince ALSA that these integers have a sign bit?
Regards, Stuart Longland
On 3 June 2010 02:07, Stuart Longland redhatter@gentoo.org wrote:
Hi all...
I'm posting this via GMane since my server at home seems to be down, hopefully it gets through. I hope to put a version of the TLV320AIC3204 driver that I've been working on up there -- I did try posting it to the list, but I suspect it's either been left in the moderation queue or silently dropped. In short, I got the sound working; just testing playback for now... Recording should work, once I get the mixer set up.
My query though; the mixer on this CODEC provides gain settings, helpfully scaled in dB, as signed integers. For instance; the four line level output drivers: Headphone left/right,and Line Out left/right, can all be adjusted in gain from -6dB through to +29dB.
These are set in individual registers as the lower 6 bits; so: -6 dB is represented as 111010 (0x3a) 29 dB is represented as 011101 (0x1d)
However; it treats the bitfield as unsigned, which is wrong in this case. The bitfield is a signed integer in two's complement format. How do I convince ALSA that these integers have a sign bit?
ALSA is not set up to convert bitfields to dB values. It can only convert integers to dB values. These integers normally being 32bit. So, I think you will have to write some code in your driver to convert these 6bit signed integers to 32bit unsigned integers and then pass the 32bit unsigned integer to user land. Something like: u32 value; /* Make the value an unsigned int even though we think it is a 6bit signed in. */
/* sign extend tmp from 6 bit signed to 32bit signed */ if (value & 0x20) value = value | 0xffffffe0; /* moved the value from the signed range to the unsigned range. */ value = value + 6;
Other way: /* reduce value to 6 bit signed value. value = value - 6; value = value & 0x3f;
Kind Regards
James
On 3 June 2010 12:21, Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Thu, Jun 03, 2010 at 08:09:36AM +0100, James Courtier-Dutton wrote:
ALSA is not set up to convert bitfields to dB values.
ASoC (which is what he's actually using here) is - most controls are defined as bitfields in the register map.
I was approaching it from the user space/kernel space divide. The user space does not handle bitfields for controls, it uses integers. The driver must therefore present the controls within the hardware as integers to user space. I thought he was having problems because the translation was not being done in the driver, so user space was handling the value wrongly.
Stuart Longland wrote:
/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */ static DECLARE_TLV_DB_MINMAX(adc_tlv, 0, 0);
The comment is wrong, this control goes from 0 to 0 dB.
SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC3204_LDACVOL, AIC3204_RDACVOL, 0, 127, 0, dac_tlv),
However; it treats the bitfield as unsigned, which is wrong in this case. The bitfield is a signed integer in two's complement format. How do I convince ALSA that these integers have a sign bit?
ALSA's controls use signed values, it's the SOC_ macros that assume bitfields. You should be able to define a control with your own callbacks like in a non-ASoC driver.
Regards, Clemens
On Thu, Jun 03, 2010 at 10:25:16AM +0200, Clemens Ladisch wrote:
Stuart Longland wrote:
/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */ static DECLARE_TLV_DB_MINMAX(adc_tlv, 0, 0);
The comment is wrong, this control goes from 0 to 0 dB.
SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC3204_LDACVOL, AIC3204_RDACVOL, 0, 127, 0, dac_tlv),
However; it treats the bitfield as unsigned, which is wrong in this case. The bitfield is a signed integer in two's complement format. How do I convince ALSA that these integers have a sign bit?
ALSA's controls use signed values, it's the SOC_ macros that assume bitfields. You should be able to define a control with your own callbacks like in a non-ASoC driver.
Ahh okay... makes sense... I'll have a closer look; perhaps some additional macros could be written to allow use of signed integer bitfields as well. I'm sure the TLV320AIC3204 is not the only CODEC that uses such beasts.
On 3 June 2010 11:33, Stuart Longland redhatter@gentoo.org wrote:
On Thu, Jun 03, 2010 at 10:25:16AM +0200, Clemens Ladisch wrote:
Stuart Longland wrote:
SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC3204_LDACVOL, AIC3204_RDACVOL, 0, 127, 0, dac_tlv),
However; it treats the bitfield as unsigned, which is wrong in this case. The bitfield is a signed integer in two's complement format. How do I convince ALSA that these integers have a sign bit?
ALSA's controls use signed values, it's the SOC_ macros that assume bitfields. You should be able to define a control with your own callbacks like in a non-ASoC driver.
Ahh okay... makes sense... I'll have a closer look; perhaps some additional macros could be written to allow use of signed integer bitfields as well. I'm sure the TLV320AIC3204 is not the only CODEC that uses such beasts.
I am not aware of any codec that uses signed bitfields. (My experience is with AC97, HD-Audio, DSPs and various ADC and DACs.) Your TLV320AIC3204 might be the first!!!
Kind Regards
James
On Thu, Jun 03, 2010 at 11:07:57AM +1000, Stuart Longland wrote:
Please do remember to CC maintainers on posts to mailing lists. I've had to remind you previously about dropping CCs (and see that you were doing that again this morning)...
My query though; the mixer on this CODEC provides gain settings, helpfully scaled in dB, as signed integers. For instance; the four line level output drivers: Headphone left/right,and Line Out left/right, can all be adjusted in gain from -6dB through to +29dB.
Are you looking for SOC_DOUBLE_R_SX_TLV and variants thereof by any chance? If you need variants you'd need to add them but that's straightforward.
On Thu, Jun 03, 2010 at 12:20:24PM +0100, Mark Brown wrote:
On Thu, Jun 03, 2010 at 11:07:57AM +1000, Stuart Longland wrote:
Please do remember to CC maintainers on posts to mailing lists. I've had to remind you previously about dropping CCs (and see that you were doing that again this morning)...
Well no, this was a separate query to the other thread, and one of a more general nature (not specific to the 'AIC3204... and not necessarily ASoC specific either).
My query though; the mixer on this CODEC provides gain settings, helpfully scaled in dB, as signed integers. For instance; the four line level output drivers: Headphone left/right,and Line Out left/right, can all be adjusted in gain from -6dB through to +29dB.
Are you looking for SOC_DOUBLE_R_SX_TLV and variants thereof by any chance? If you need variants you'd need to add them but that's straightforward.
Is this something that has been added since kernel 2.6.34? I'll have a hunt around for it, but I haven't spotted that in the kernel tree I'm using.
I'm running slightly-behind bleeding edge here, since I hit a few regressions[1] with the latest code (ARM-wise), and rather than battle those in this early phase of development, I decided to move back to something stable, get it working, then bring it forward. It's for this reason that my driver currently uses the older driver registration model.
Once I get it working; there will likely be two forks of it -- one brought up to mainline to go into the tree... and one to be backported to kernel 2.6.28 which is what we're using in our product (as everything else we have works with that kernel).
Regards,
On 4 Jun 2010, at 10:27, Stuart Longland wrote:
On Thu, Jun 03, 2010 at 12:20:24PM +0100, Mark Brown wrote:
Please do remember to CC maintainers on posts to mailing lists. I've had to remind you previously about dropping CCs (and see that you were doing that again this morning)...
Well no, this was a separate query to the other thread, and one of a more general nature (not specific to the 'AIC3204... and not necessarily ASoC specific either).
You're replying in the middle of the existing thread (which tends to indicate a continuation of the same discussion) and hadn't CCed anyone at all - Takashi and Jaroslav are also much more likely to notice your post if you CC them.
Are you looking for SOC_DOUBLE_R_SX_TLV and variants thereof by any chance? If you need variants you'd need to add them but that's straightforward.
Is this something that has been added since kernel 2.6.34? I'll have a hunt around for it, but I haven't spotted that in the kernel tree I'm using.
Yes.
I'm running slightly-behind bleeding edge here, since I hit a few regressions[1] with the latest code (ARM-wise), and rather than battle those in this early phase of development, I decided to move back to something stable, get it working, then bring it forward. It's for this reason that my driver currently uses the older driver registration model.
The device model registration has been supported in mainline for over a year now, it's certainly there in 2.6.34.
Once I get it working; there will likely be two forks of it -- one brought up to mainline to go into the tree... and one to be backported to kernel 2.6.28 which is what we're using in our product (as everything else we have works with that kernel).
For 2.6.28 you'll be as well just backporting ASoC en masse.
participants (4)
-
Clemens Ladisch
-
James Courtier-Dutton
-
Mark Brown
-
Stuart Longland