Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1d7093f authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai
Browse files

ALSA: oxygen: add S/PDIF source selection for Claro cards



Add a mixer control to switch between the optical and coaxial S/PDIF
inputs on the HT-Omega Claro and Claro halo cards.

Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5fc51524
Loading
Loading
Loading
Loading
+88 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
 *   GPIO 6 -> enable on-board S/PDIF input
 *
 * Claro models:
 *   GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
 *   GPIO 8 -> enable headphone amplifier
 *
 * CM9780:
@@ -137,6 +138,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
#define GPIO_MERIDIAN_DIG_EXT	0x0010
#define GPIO_MERIDIAN_DIG_BOARD	0x0040

#define GPIO_CLARO_DIG_COAX	0x0040
#define GPIO_CLARO_HP		0x0100

struct generic_data {
@@ -268,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip)

static void claro_init(struct oxygen *chip)
{
	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
	ak4396_init(chip);
	wm8785_init(chip);
	claro_enable_hp(chip);
@@ -275,6 +279,8 @@ static void claro_init(struct oxygen *chip)

static void claro_halo_init(struct oxygen *chip)
{
	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
	ak4396_init(chip);
	ak5385_init(chip);
	claro_enable_hp(chip);
@@ -523,14 +529,24 @@ static const struct snd_kcontrol_new hpf_control = {
	.put = hpf_put,
};

static int meridian_dig_source_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
static int meridian_dig_source_info(struct snd_kcontrol *ctl,
				    struct snd_ctl_elem_info *info)
{
	static const char *const names[2] = { "On-board", "Extension" };

	return snd_ctl_enum_info(info, 1, 2, names);
}

static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
static int claro_dig_source_info(struct snd_kcontrol *ctl,
				 struct snd_ctl_elem_info *info)
{
	static const char *const names[2] = { "Optical", "Coaxial" };

	return snd_ctl_enum_info(info, 1, 2, names);
}

static int meridian_dig_source_get(struct snd_kcontrol *ctl,
				   struct snd_ctl_elem_value *value)
{
	struct oxygen *chip = ctl->private_data;

@@ -540,7 +556,19 @@ static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem
	return 0;
}

static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
static int claro_dig_source_get(struct snd_kcontrol *ctl,
				struct snd_ctl_elem_value *value)
{
	struct oxygen *chip = ctl->private_data;

	value->value.enumerated.item[0] =
		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
		   GPIO_CLARO_DIG_COAX);
	return 0;
}

static int meridian_dig_source_put(struct snd_kcontrol *ctl,
				   struct snd_ctl_elem_value *value)
{
	struct oxygen *chip = ctl->private_data;
	u16 old_reg, new_reg;
@@ -560,6 +588,25 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem
	return changed;
}

static int claro_dig_source_put(struct snd_kcontrol *ctl,
				struct snd_ctl_elem_value *value)
{
	struct oxygen *chip = ctl->private_data;
	u16 old_reg, new_reg;
	int changed;

	mutex_lock(&chip->mutex);
	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
	new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
	if (value->value.enumerated.item[0])
		new_reg |= GPIO_CLARO_DIG_COAX;
	changed = new_reg != old_reg;
	if (changed)
		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
	mutex_unlock(&chip->mutex);
	return changed;
}

static const struct snd_kcontrol_new meridian_dig_source_control = {
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "IEC958 Source Capture Enum",
@@ -568,6 +615,14 @@ static const struct snd_kcontrol_new meridian_dig_source_control = {
	.put = meridian_dig_source_put,
};

static const struct snd_kcontrol_new claro_dig_source_control = {
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "IEC958 Source Capture Enum",
	.info = claro_dig_source_info,
	.get = claro_dig_source_get,
	.put = claro_dig_source_put,
};

static int generic_mixer_init(struct oxygen *chip)
{
	return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
@@ -600,6 +655,34 @@ static int meridian_mixer_init(struct oxygen *chip)
	return 0;
}

static int claro_mixer_init(struct oxygen *chip)
{
	int err;

	err = generic_wm8785_mixer_init(chip);
	if (err < 0)
		return err;
	err = snd_ctl_add(chip->card,
			  snd_ctl_new1(&claro_dig_source_control, chip));
	if (err < 0)
		return err;
	return 0;
}

static int claro_halo_mixer_init(struct oxygen *chip)
{
	int err;

	err = generic_mixer_init(chip);
	if (err < 0)
		return err;
	err = snd_ctl_add(chip->card,
			  snd_ctl_new1(&claro_dig_source_control, chip));
	if (err < 0)
		return err;
	return 0;
}

static void dump_ak4396_registers(struct oxygen *chip,
				  struct snd_info_buffer *buffer)
{
@@ -700,13 +783,14 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
		break;
	case MODEL_CLARO:
		chip->model.init = claro_init;
		chip->model.mixer_init = claro_mixer_init;
		chip->model.cleanup = claro_cleanup;
		chip->model.suspend = claro_suspend;
		chip->model.resume = claro_resume;
		break;
	case MODEL_CLARO_HALO:
		chip->model.init = claro_halo_init;
		chip->model.mixer_init = generic_mixer_init;
		chip->model.mixer_init = claro_halo_mixer_init;
		chip->model.cleanup = claro_cleanup;
		chip->model.suspend = claro_suspend;
		chip->model.resume = claro_resume;