[alsa-devel] [PATCH v2] snd-es18xx: Add GPO controls

Takashi Iwai tiwai at suse.de
Tue Nov 4 10:31:59 CET 2014


At Mon,  3 Nov 2014 21:35:48 +0100,
Ondrej Zary wrote:
> 
> Add GPO0 and GPO1 (General Purpose Outputs) controls to mixer.
> These can be used on some cards to control amplifier mute (seen in ES1868
> datasheet) or additional onboard chips such as QX2130 QXpander processor.
> 
> These GPOs are present on ES1868, ES1869, ES1887 and ES1888 chips.
> 
> Tested on ES1868 with QX2130.
> 
> Signed-off-by: Ondrej Zary <linux at rainbow-software.org>

Thanks, applied.


Takashi

> ---
>  sound/isa/es18xx.c |   52 ++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 10 deletions(-)
> 
> diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
> index 6faaac6..0ead1c8 100644
> --- a/sound/isa/es18xx.c
> +++ b/sound/isa/es18xx.c
> @@ -156,6 +156,7 @@ struct snd_es18xx {
>  #define ES18XX_I2S	0x0200	/* I2S mixer control */
>  #define ES18XX_MUTEREC	0x0400	/* Record source can be muted */
>  #define ES18XX_CONTROL	0x0800	/* Has control ports */
> +#define ES18XX_GPO_2BIT	0x1000	/* GPO0,1 controlled by PM port */
>  
>  /* Power Management */
>  #define ES18XX_PM	0x07
> @@ -1136,11 +1137,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
>  		return snd_es18xx_read(chip, reg);
>  }
>  
> -#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \
> +#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \
>  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
>    .info = snd_es18xx_info_single, \
>    .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \
> -  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
> +  .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) }
> +
> +#define ES18XX_FL_INVERT	(1 << 0)
> +#define ES18XX_FL_PMPORT	(1 << 1)
>  
>  static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
>  {
> @@ -1159,10 +1163,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
>  	int reg = kcontrol->private_value & 0xff;
>  	int shift = (kcontrol->private_value >> 8) & 0xff;
>  	int mask = (kcontrol->private_value >> 16) & 0xff;
> -	int invert = (kcontrol->private_value >> 24) & 0xff;
> +	int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
> +	int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
>  	int val;
> -	
> -	val = snd_es18xx_reg_read(chip, reg);
> +
> +	if (pm_port)
> +		val = inb(chip->port + ES18XX_PM);
> +	else
> +		val = snd_es18xx_reg_read(chip, reg);
>  	ucontrol->value.integer.value[0] = (val >> shift) & mask;
>  	if (invert)
>  		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
> @@ -1175,7 +1183,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
>  	int reg = kcontrol->private_value & 0xff;
>  	int shift = (kcontrol->private_value >> 8) & 0xff;
>  	int mask = (kcontrol->private_value >> 16) & 0xff;
> -	int invert = (kcontrol->private_value >> 24) & 0xff;
> +	int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
> +	int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
>  	unsigned char val;
>  	
>  	val = (ucontrol->value.integer.value[0] & mask);
> @@ -1183,6 +1192,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
>  		val = mask - val;
>  	mask <<= shift;
>  	val <<= shift;
> +	if (pm_port) {
> +		unsigned char cur = inb(chip->port + ES18XX_PM);
> +
> +		if ((cur & mask) == val)
> +			return 0;
> +		outb((cur & ~mask) | val, chip->port + ES18XX_PM);
> +		return 1;
> +	}
> +
>  	return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
>  }
>  
> @@ -1304,7 +1322,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
>  	ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
>  
>  static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
> -ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
> +ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT),
>  ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
>  ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
>  ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
> @@ -1363,6 +1381,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
>  ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
>  };
>  
> +static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = {
> +ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT),
> +ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT),
> +};
> +
>  static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
>  {
>  	int data;
> @@ -1629,10 +1652,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
>  
>  	switch (chip->version) {
>  	case 0x1868:
> -		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
> +		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT;
>  		break;
>  	case 0x1869:
> -		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
> +		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT;
>  		break;
>  	case 0x1878:
>  		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
> @@ -1642,7 +1665,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
>  		break;
>  	case 0x1887:
>  	case 0x1888:
> -		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
> +		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
>  		break;
>  	default:
>  		snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
> @@ -1944,6 +1967,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
>  				return err;
>  		}
>  	}
> +	if (chip->caps & ES18XX_GPO_2BIT) {
> +		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) {
> +			err = snd_ctl_add(card,
> +					  snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx],
> +						       chip));
> +			if (err < 0)
> +				return err;
> +		}
> +	}
>  	return 0;
>  }
>         
> -- 
> Ondrej Zary
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list