Commit 3479307f authored by Jochen Voss's avatar Jochen Voss Committed by Jaroslav Kysela

[ALSA] Fix volume control for the AK4358 DAC

Fix volume control for the AK4358 DAC.
The attenuation control registers of the AK4358 use only 7bit for the
volume, the msb is used to enable attenuation output.  Without this
patch there are 256 volume levels the lower 128 of which are mute.
Signed-off-by: default avatarJochen Voss <voss@seehuhn.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 071c73ad
...@@ -284,11 +284,13 @@ EXPORT_SYMBOL(snd_akm4xxx_init); ...@@ -284,11 +284,13 @@ EXPORT_SYMBOL(snd_akm4xxx_init);
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff) #define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
#define AK_GET_ADDR(val) ((val) & 0xff) #define AK_GET_ADDR(val) ((val) & 0xff)
#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) #define AK_GET_SHIFT(val) (((val) >> 16) & 0x3f)
#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
#define AK_GET_INVERT(val) (((val) >> 23) & 1) #define AK_GET_INVERT(val) (((val) >> 23) & 1)
#define AK_GET_MASK(val) (((val) >> 24) & 0xff) #define AK_GET_MASK(val) (((val) >> 24) & 0xff)
#define AK_COMPOSE(chip,addr,shift,mask) \ #define AK_COMPOSE(chip,addr,shift,mask) \
(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
#define AK_NEEDSMSB (1<<22)
#define AK_INVERT (1<<23) #define AK_INVERT (1<<23)
static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
...@@ -309,10 +311,13 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol, ...@@ -309,10 +311,13 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value);
int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value); unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char val = snd_akm4xxx_get(ak, chip, addr); unsigned char val = snd_akm4xxx_get(ak, chip, addr);
if (needsmsb)
val &= 0x7f;
ucontrol->value.integer.value[0] = invert ? mask - val : val; ucontrol->value.integer.value[0] = invert ? mask - val : val;
return 0; return 0;
} }
...@@ -323,6 +328,7 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, ...@@ -323,6 +328,7 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value);
int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value); unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
...@@ -330,6 +336,8 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, ...@@ -330,6 +336,8 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
if (invert) if (invert)
nval = mask - nval; nval = mask - nval;
if (needsmsb)
nval |= 0x80;
change = snd_akm4xxx_get(ak, chip, addr) != nval; change = snd_akm4xxx_get(ak, chip, addr) != nval;
if (change) if (change)
snd_akm4xxx_write(ak, chip, addr, nval); snd_akm4xxx_write(ak, chip, addr, nval);
...@@ -354,13 +362,19 @@ static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, ...@@ -354,13 +362,19 @@ static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value);
int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value); unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char val = snd_akm4xxx_get(ak, chip, addr); unsigned char val;
val = snd_akm4xxx_get(ak, chip, addr);
if (needsmsb)
val &= 0x7f;
ucontrol->value.integer.value[0] = invert ? mask - val : val; ucontrol->value.integer.value[0] = invert ? mask - val : val;
val = snd_akm4xxx_get(ak, chip, addr+1); val = snd_akm4xxx_get(ak, chip, addr+1);
if (needsmsb)
val &= 0x7f;
ucontrol->value.integer.value[1] = invert ? mask - val : val; ucontrol->value.integer.value[1] = invert ? mask - val : val;
return 0; return 0;
...@@ -372,6 +386,7 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, ...@@ -372,6 +386,7 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value); int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value);
int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value); unsigned int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
...@@ -379,6 +394,8 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, ...@@ -379,6 +394,8 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
if (invert) if (invert)
nval = mask - nval; nval = mask - nval;
if (needsmsb)
nval |= 0x80;
change0 = snd_akm4xxx_get(ak, chip, addr) != nval; change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
if (change0) if (change0)
snd_akm4xxx_write(ak, chip, addr, nval); snd_akm4xxx_write(ak, chip, addr, nval);
...@@ -386,6 +403,8 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, ...@@ -386,6 +403,8 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
nval = ucontrol->value.integer.value[1] % (mask+1); nval = ucontrol->value.integer.value[1] % (mask+1);
if (invert) if (invert)
nval = mask - nval; nval = mask - nval;
if (needsmsb)
nval |= 0x80;
change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval; change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
if (change1) if (change1)
snd_akm4xxx_write(ak, chip, addr+1, nval); snd_akm4xxx_write(ak, chip, addr+1, nval);
...@@ -585,16 +604,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) ...@@ -585,16 +604,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
/* register 4-9, chip #0 only */ /* register 4-9, chip #0 only */
ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
break; break;
case SND_AK4358: case SND_AK4358: {
if (idx >= 6) /* register 4-9 and 11-12, chip #0 only */
/* register 4-9, chip #0 only */ int addr = idx < 6 ? idx + 4 : idx + 5;
ctl->private_value = ctl->private_value =
AK_COMPOSE(0, idx + 5, 0, 255); AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
else
/* register 4-9, chip #0 only */
ctl->private_value =
AK_COMPOSE(0, idx + 4, 0, 255);
break; break;
}
case SND_AK4381: case SND_AK4381:
/* register 3 & 4 */ /* register 3 & 4 */
ctl->private_value = ctl->private_value =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment