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

Commit 1ff97cb9 authored by Pavel Hofman's avatar Pavel Hofman Committed by Takashi Iwai
Browse files

ALSA: ice1724 - Support for multiple external clock types



* Support for customization of the external clock names
* Adding hooks to playback_pro_open and capture_pro_open, allowing e.g.
  limiting available stream rates to a single value when the external
  clock rate is detected

Signed-off-by: default avatarPavel Hofman <pavel.hofman@ivitera.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6796d5a0
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -379,8 +379,11 @@ struct snd_ice1712 {
	unsigned int (*get_rate)(struct snd_ice1712 *ice);
	unsigned int (*get_rate)(struct snd_ice1712 *ice);
	void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate);
	void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate);
	unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
	unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
	void (*set_spdif_clock)(struct snd_ice1712 *ice);
	int (*set_spdif_clock)(struct snd_ice1712 *ice, int type);

	int (*get_spdif_master_type)(struct snd_ice1712 *ice);
	char **ext_clock_names;
	int ext_clock_count;
	void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
#ifdef CONFIG_PM
#ifdef CONFIG_PM
	int (*pm_suspend)(struct snd_ice1712 *);
	int (*pm_suspend)(struct snd_ice1712 *);
	int (*pm_resume)(struct snd_ice1712 *);
	int (*pm_resume)(struct snd_ice1712 *);
+45 −13
Original line number Original line Diff line number Diff line
@@ -104,6 +104,8 @@ static int PRO_RATE_LOCKED;
static int PRO_RATE_RESET = 1;
static int PRO_RATE_RESET = 1;
static unsigned int PRO_RATE_DEFAULT = 44100;
static unsigned int PRO_RATE_DEFAULT = 44100;


static char *ext_clock_names[1] = { "IEC958 In" };

/*
/*
 *  Basic I/O
 *  Basic I/O
 */
 */
@@ -1042,6 +1044,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
				   VT1724_BUFFER_ALIGN);
				   VT1724_BUFFER_ALIGN);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
				   VT1724_BUFFER_ALIGN);
				   VT1724_BUFFER_ALIGN);
	if (ice->pro_open)
		ice->pro_open(ice, substream);
	return 0;
	return 0;
}
}


@@ -1060,6 +1064,8 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
				   VT1724_BUFFER_ALIGN);
				   VT1724_BUFFER_ALIGN);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
				   VT1724_BUFFER_ALIGN);
				   VT1724_BUFFER_ALIGN);
	if (ice->pro_open)
		ice->pro_open(ice, substream);
	return 0;
	return 0;
}
}


@@ -1813,15 +1819,21 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
					      struct snd_ctl_elem_info *uinfo)
					      struct snd_ctl_elem_info *uinfo)
{
{
	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);

	int hw_rates_count = ice->hw_rates->count;
	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->count = 1;
	uinfo->count = 1;
	uinfo->value.enumerated.items = ice->hw_rates->count + 1;

	uinfo->value.enumerated.items = hw_rates_count + ice->ext_clock_count;
	/* upper limit - keep at top */
	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
	if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
	if (uinfo->value.enumerated.item >= hw_rates_count)
		strcpy(uinfo->value.enumerated.name, "IEC958 Input");
		/* ext_clock items */
		strcpy(uinfo->value.enumerated.name,
				ice->ext_clock_names[
				uinfo->value.enumerated.item - hw_rates_count]);
	else
	else
		/* int clock items */
		sprintf(uinfo->value.enumerated.name, "%d",
		sprintf(uinfo->value.enumerated.name, "%d",
			ice->hw_rates->list[uinfo->value.enumerated.item]);
			ice->hw_rates->list[uinfo->value.enumerated.item]);
	return 0;
	return 0;
@@ -1835,7 +1847,8 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,


	spin_lock_irq(&ice->reg_lock);
	spin_lock_irq(&ice->reg_lock);
	if (ice->is_spdif_master(ice)) {
	if (ice->is_spdif_master(ice)) {
		ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
		ucontrol->value.enumerated.item[0] = ice->hw_rates->count +
			ice->get_spdif_master_type(ice);
	} else {
	} else {
		rate = ice->get_rate(ice);
		rate = ice->get_rate(ice);
		ucontrol->value.enumerated.item[0] = 0;
		ucontrol->value.enumerated.item[0] = 0;
@@ -1850,8 +1863,14 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
	return 0;
	return 0;
}
}


static int stdclock_get_spdif_master_type(struct snd_ice1712 *ice)
{
	/* standard external clock - only single type - SPDIF IN */
	return 0;
}

/* setting clock to external - SPDIF */
/* setting clock to external - SPDIF */
static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
static int stdclock_set_spdif_clock(struct snd_ice1712 *ice, int type)
{
{
	unsigned char oval;
	unsigned char oval;
	unsigned char i2s_oval;
	unsigned char i2s_oval;
@@ -1860,27 +1879,30 @@ static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
	/* setting 256fs */
	/* setting 256fs */
	i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
	i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
	outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
	outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
	return 0;
}
}



static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
					     struct snd_ctl_elem_value *ucontrol)
					     struct snd_ctl_elem_value *ucontrol)
{
{
	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
	unsigned int old_rate, new_rate;
	unsigned int old_rate, new_rate;
	unsigned int item = ucontrol->value.enumerated.item[0];
	unsigned int item = ucontrol->value.enumerated.item[0];
	unsigned int spdif = ice->hw_rates->count;
	unsigned int first_ext_clock = ice->hw_rates->count;


	if (item > spdif)
	if (item >  first_ext_clock + ice->ext_clock_count - 1)
		return -EINVAL;
		return -EINVAL;


	/* if rate = 0 => external clock */
	spin_lock_irq(&ice->reg_lock);
	spin_lock_irq(&ice->reg_lock);
	if (ice->is_spdif_master(ice))
	if (ice->is_spdif_master(ice))
		old_rate = 0;
		old_rate = 0;
	else
	else
		old_rate = ice->get_rate(ice);
		old_rate = ice->get_rate(ice);
	if (item == spdif) {
	if (item >= first_ext_clock) {
		/* switching to external clock via SPDIF */
		/* switching to external clock */
		ice->set_spdif_clock(ice);
		ice->set_spdif_clock(ice, item - first_ext_clock);
		new_rate = 0;
		new_rate = 0;
	} else {
	} else {
		/* internal on-card clock */
		/* internal on-card clock */
@@ -1892,7 +1914,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
	}
	}
	spin_unlock_irq(&ice->reg_lock);
	spin_unlock_irq(&ice->reg_lock);


	/* the first reset to the SPDIF master mode? */
	/* the first switch to the ext. clock mode? */
	if (old_rate != new_rate && !new_rate) {
	if (old_rate != new_rate && !new_rate) {
		/* notify akm chips as well */
		/* notify akm chips as well */
		unsigned int i;
		unsigned int i;
@@ -2550,6 +2572,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
		return err;
		return err;
	}
	}


	/* field init before calling chip_init */
	ice->ext_clock_count = 0;

	for (tbl = card_tables; *tbl; tbl++) {
	for (tbl = card_tables; *tbl; tbl++) {
		for (c = *tbl; c->subvendor; c++) {
		for (c = *tbl; c->subvendor; c++) {
			if (c->subvendor == ice->eeprom.subvendor) {
			if (c->subvendor == ice->eeprom.subvendor) {
@@ -2588,6 +2613,13 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
		ice->set_mclk = stdclock_set_mclk;
		ice->set_mclk = stdclock_set_mclk;
	if (!ice->set_spdif_clock)
	if (!ice->set_spdif_clock)
		ice->set_spdif_clock = stdclock_set_spdif_clock;
		ice->set_spdif_clock = stdclock_set_spdif_clock;
	if (!ice->get_spdif_master_type)
		ice->get_spdif_master_type = stdclock_get_spdif_master_type;
	if (!ice->ext_clock_names)
		ice->ext_clock_names = ext_clock_names;
	if (!ice->ext_clock_count)
		ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);

	if (!ice->hw_rates)
	if (!ice->hw_rates)
		set_std_hw_rates(ice);
		set_std_hw_rates(ice);


@@ -2747,7 +2779,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)


	if (ice->pm_saved_is_spdif_master) {
	if (ice->pm_saved_is_spdif_master) {
		/* switching to external clock via SPDIF */
		/* switching to external clock via SPDIF */
		ice->set_spdif_clock(ice);
		ice->set_spdif_clock(ice, 0);
	} else {
	} else {
		/* internal on-card clock */
		/* internal on-card clock */
		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+2 −1
Original line number Original line Diff line number Diff line
@@ -529,13 +529,14 @@ static inline unsigned char juli_set_mclk(struct snd_ice1712 *ice,
}
}


/* setting clock to external - SPDIF */
/* setting clock to external - SPDIF */
static void juli_set_spdif_clock(struct snd_ice1712 *ice)
static int juli_set_spdif_clock(struct snd_ice1712 *ice, int type)
{
{
	unsigned int old;
	unsigned int old;
	old = ice->gpio.get_data(ice);
	old = ice->gpio.get_data(ice);
	/* external clock (= 0), multiply 1x, 48kHz */
	/* external clock (= 0), multiply 1x, 48kHz */
	ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X |
	ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X |
			GPIO_FREQ_48KHZ);
			GPIO_FREQ_48KHZ);
	return 0;
}
}


/* Called when ak4114 detects change in the input SPDIF stream */
/* Called when ak4114 detects change in the input SPDIF stream */