[ALSA] ice1724 - Improved the Juli rate setting

* moving most of clock-specific code to card-specific routines
* support for ESI Juli
* to-be-researched - monitoring of analog/digital inputs

Signed-off-by: Pavel Hofman <dustin@seznam.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 3bfd705..ceac870 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -106,15 +106,19 @@
  *  Basic I/O
  */
  
+/*
+ *  default rates, default clock routines
+ */
+
 /* check whether the clock mode is spdif-in */
-static inline int is_spdif_master(struct snd_ice1712 *ice)
+static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice)
 {
 	return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
 }
 
 static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
 {
-	return is_spdif_master(ice) || PRO_RATE_LOCKED;
+	return ice->is_spdif_master(ice) || PRO_RATE_LOCKED;
 }
 
 /*
@@ -391,51 +395,61 @@
 #define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\
 	VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE)
 
-static int get_max_rate(struct snd_ice1712 *ice)
+static const unsigned int stdclock_rate_list[16] = {
+	48000, 24000, 12000, 9600, 32000, 16000, 8000, 96000, 44100,
+	22050, 11025, 88200, 176400, 0, 192000, 64000
+};
+
+static unsigned int stdclock_get_rate(struct snd_ice1712 *ice)
 {
+	unsigned int rate;
+	rate = stdclock_rate_list[inb(ICEMT1724(ice, RATE)) & 15];
+	return rate;
+}
+
+static void stdclock_set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(stdclock_rate_list); i++) {
+		if (stdclock_rate_list[i] == rate) {
+			outb(i, ICEMT1724(ice, RATE));
+			return;
+		}
+	}
+}
+
+static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice,
+				       unsigned int rate)
+{
+	unsigned char val, old;
+	/* check MT02 */
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
-		if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720)
-			return 192000;
+		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
+		if (rate > 96000)
+			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
 		else
-			return 96000;
-	} else
-		return 48000;
+			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
+		if (val != old) {
+			outb(val, ICEMT1724(ice, I2S_FORMAT));
+			/* master clock changed */
+			return 1;
+		}
+	}
+	/* no change in master clock */
+	return 0;
 }
 
 static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
 				    int force)
 {
 	unsigned long flags;
-	unsigned char val, old;
-	unsigned int i, mclk_change;
+	unsigned char mclk_change;
+	unsigned int i, old_rate;
 
-	if (rate > get_max_rate(ice))
+	if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
 		return;
-
-	switch (rate) {
-	case 8000: val = 6; break;
-	case 9600: val = 3; break;
-	case 11025: val = 10; break;
-	case 12000: val = 2; break;
-	case 16000: val = 5; break;
-	case 22050: val = 9; break;
-	case 24000: val = 1; break;
-	case 32000: val = 4; break;
-	case 44100: val = 8; break;
-	case 48000: val = 0; break;
-	case 64000: val = 15; break;
-	case 88200: val = 11; break;
-	case 96000: val = 7; break;
-	case 176400: val = 12; break;
-	case 192000: val = 14; break;
-	default:
-		snd_BUG();
-		val = 0;
-		break;
-	}
-
 	spin_lock_irqsave(&ice->reg_lock, flags);
-	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 
+	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
 	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
 		/* running? we cannot change the rate now... */
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
@@ -446,9 +460,9 @@
 		return;
 	}
 
-	old = inb(ICEMT1724(ice, RATE));
-	if (force || old != val)
-		outb(val, ICEMT1724(ice, RATE));
+	old_rate = ice->get_rate(ice);
+	if (force || (old_rate != rate))
+		ice->set_rate(ice, rate);
 	else if (rate == ice->cur_rate) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
 		return;
@@ -456,19 +470,9 @@
 
 	ice->cur_rate = rate;
 
-	/* check MT02 */
-	mclk_change = 0;
-	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
-		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
-		if (rate > 96000)
-			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
-		else
-			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
-		if (val != old) {
-			outb(val, ICEMT1724(ice, I2S_FORMAT));
-			mclk_change = 1;
-		}
-	}
+	/* setting master clock */
+	mclk_change = ice->set_mclk(ice, rate);
+
 	spin_unlock_irqrestore(&ice->reg_lock, flags);
 
 	if (mclk_change && ice->gpio.i2s_mclk_changed)
@@ -727,43 +731,32 @@
 /*
  * set rate constraints
  */
-static int set_rate_constraints(struct snd_ice1712 *ice,
-				struct snd_pcm_substream *substream)
+static void set_std_hw_rates(struct snd_ice1712 *ice)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	if (ice->hw_rates) {
-		/* hardware specific */
-		runtime->hw.rate_min = ice->hw_rates->list[0];
-		runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1];
-		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-		return snd_pcm_hw_constraint_list(runtime, 0,
-						  SNDRV_PCM_HW_PARAM_RATE,
-						  ice->hw_rates);
-	}
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		/* I2S */
 		/* VT1720 doesn't support more than 96kHz */
 		if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720)
-			return snd_pcm_hw_constraint_list(runtime, 0,
-							  SNDRV_PCM_HW_PARAM_RATE,
-							  &hw_constraints_rates_192);
-		else {
-			runtime->hw.rates = SNDRV_PCM_RATE_KNOT |
-				SNDRV_PCM_RATE_8000_96000;
-			runtime->hw.rate_max = 96000;
-			return snd_pcm_hw_constraint_list(runtime, 0,
-							  SNDRV_PCM_HW_PARAM_RATE,
-							  &hw_constraints_rates_96);
-		}
-	} else if (ice->ac97) {
+			ice->hw_rates = &hw_constraints_rates_192;
+		else
+			ice->hw_rates = &hw_constraints_rates_96;
+	} else {
 		/* ACLINK */
-		runtime->hw.rate_max = 48000;
-		runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
-		return snd_pcm_hw_constraint_list(runtime, 0,
-						  SNDRV_PCM_HW_PARAM_RATE,
-						  &hw_constraints_rates_48);
+		ice->hw_rates = &hw_constraints_rates_48;
 	}
-	return 0;
+}
+
+static int set_rate_constraints(struct snd_ice1712 *ice,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.rate_min = ice->hw_rates->list[0];
+	runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1];
+	runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+	return snd_pcm_hw_constraint_list(runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  ice->hw_rates);
 }
 
 /* multi-channel playback needs alignment 8x32bit regardless of the channels
@@ -824,7 +817,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_pro_substream = NULL;
 
 	return 0;
@@ -835,7 +828,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->capture_pro_substream = NULL;
 	return 0;
 }
@@ -980,7 +973,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_con_substream = NULL;
 	if (ice->spdif.ops.close)
 		ice->spdif.ops.close(ice, substream);
@@ -1016,7 +1009,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->capture_con_substream = NULL;
 	if (ice->spdif.ops.close)
 		ice->spdif.ops.close(ice, substream);
@@ -1162,7 +1155,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_con_substream_ds[substream->number] = NULL;
 	ice->pcm_reserved[substream->number] = NULL;
 
@@ -1580,50 +1573,18 @@
 static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
 					      struct snd_ctl_elem_info *uinfo)
 {
-	static const char * const texts_1724[] = {
-		"8000",		/* 0: 6 */
-		"9600",		/* 1: 3 */
-		"11025",	/* 2: 10 */
-		"12000",	/* 3: 2 */
-		"16000",	/* 4: 5 */
-		"22050",	/* 5: 9 */
-		"24000",	/* 6: 1 */
-		"32000",	/* 7: 4 */
-		"44100",	/* 8: 8 */
-		"48000",	/* 9: 0 */
-		"64000",	/* 10: 15 */
-		"88200",	/* 11: 11 */
-		"96000",	/* 12: 7 */
-		"176400",	/* 13: 12 */
-		"192000",	/* 14: 14 */
-		"IEC958 Input",	/* 15: -- */
-	};
-	static const char * const texts_1720[] = {
-		"8000",		/* 0: 6 */
-		"9600",		/* 1: 3 */
-		"11025",	/* 2: 10 */
-		"12000",	/* 3: 2 */
-		"16000",	/* 4: 5 */
-		"22050",	/* 5: 9 */
-		"24000",	/* 6: 1 */
-		"32000",	/* 7: 4 */
-		"44100",	/* 8: 8 */
-		"48000",	/* 9: 0 */
-		"64000",	/* 10: 15 */
-		"88200",	/* 11: 11 */
-		"96000",	/* 12: 7 */
-		"IEC958 Input",	/* 13: -- */
-	};
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = ice->vt1720 ? 14 : 16;
+	uinfo->value.enumerated.items = ice->hw_rates->count + 1;
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name,
-	       ice->vt1720 ? texts_1720[uinfo->value.enumerated.item] :
-	       texts_1724[uinfo->value.enumerated.item]);
+	if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
+		strcpy(uinfo->value.enumerated.name, "IEC958 Input");
+	else
+		sprintf(uinfo->value.enumerated.name, "%d",
+			ice->hw_rates->list[uinfo->value.enumerated.item]);
 	return 0;
 }
 
@@ -1631,68 +1592,79 @@
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static const unsigned char xlate[16] = {
-		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
-	};
-	unsigned char val;
+	unsigned int i, rate;
 	
 	spin_lock_irq(&ice->reg_lock);
-	if (is_spdif_master(ice)) {
-		ucontrol->value.enumerated.item[0] = ice->vt1720 ? 13 : 15;
+	if (ice->is_spdif_master(ice)) {
+		ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
 	} else {
-		val = xlate[inb(ICEMT1724(ice, RATE)) & 15];
-		if (val == 255) {
-			snd_BUG();
-			val = 0;
+		rate = ice->get_rate(ice);
+		ucontrol->value.enumerated.item[0] = 0;
+		for (i = 0; i < ice->hw_rates->count; i++) {
+			if (ice->hw_rates->list[i] == rate) {
+				ucontrol->value.enumerated.item[0] = i;
+				break;
+			}
 		}
-		ucontrol->value.enumerated.item[0] = val;
 	}
 	spin_unlock_irq(&ice->reg_lock);
 	return 0;
 }
 
+/* setting clock to external - SPDIF */
+static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
+{
+	unsigned char oval;
+	unsigned char i2s_oval;
+	oval = inb(ICEMT1724(ice, RATE));
+	outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+	/* setting 256fs */
+	i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
+	outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
+}
+
 static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	unsigned char oval;
-	int rate;
-	int change = 0;
-	int spdif = ice->vt1720 ? 13 : 15;
+	unsigned int old_rate, new_rate;
+	unsigned int item = ucontrol->value.enumerated.item[0];
+	unsigned int spdif = ice->hw_rates->count;
+
+	if (item > spdif)
+		return -EINVAL;
 
 	spin_lock_irq(&ice->reg_lock);
-	oval = inb(ICEMT1724(ice, RATE));
-	if (ucontrol->value.enumerated.item[0] == spdif) {
-		unsigned char i2s_oval;
-		outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
-		/* setting 256fs */
-		i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
-		outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X,
-		     ICEMT1724(ice, I2S_FORMAT));
+	if (ice->is_spdif_master(ice))
+		old_rate = 0;
+	else
+		old_rate = ice->get_rate(ice);
+	if (item == spdif) {
+		/* switching to external clock via SPDIF */
+		ice->set_spdif_clock(ice);
+		new_rate = 0;
 	} else {
-		rate = rates[ucontrol->value.integer.value[0] % 15];
-		if (rate <= get_max_rate(ice)) {
-			PRO_RATE_DEFAULT = rate;
-			spin_unlock_irq(&ice->reg_lock);
-			snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 1);
-			spin_lock_irq(&ice->reg_lock);
-		}
+		/* internal on-card clock */
+		new_rate = ice->hw_rates->list[item];
+		ice->pro_rate_default = new_rate;
+		spin_unlock_irq(&ice->reg_lock);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+		spin_lock_irq(&ice->reg_lock);
 	}
-	change = inb(ICEMT1724(ice, RATE)) != oval;
 	spin_unlock_irq(&ice->reg_lock);
 
-	if ((oval & VT1724_SPDIF_MASTER) !=
-	    (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER)) {
+	/* the first reset to the SPDIF master mode? */
+	if (old_rate != new_rate && !new_rate) {
 		/* notify akm chips as well */
-		if (is_spdif_master(ice)) {
-			unsigned int i;
-			for (i = 0; i < ice->akm_codecs; i++) {
-				if (ice->akm[i].ops.set_rate_val)
-					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
-			}
+		unsigned int i;
+		if (ice->gpio.set_pro_rate)
+			ice->gpio.set_pro_rate(ice, 0);
+		for (i = 0; i < ice->akm_codecs; i++) {
+			if (ice->akm[i].ops.set_rate_val)
+				ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
 		}
 	}
-	return change;
+	return old_rate != new_rate;
 }
 
 static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
@@ -2343,6 +2315,19 @@
         * was called so in ice1712 driver, and vt1724 driver is derived from
         * ice1712 driver.
         */
+	ice->pro_rate_default = PRO_RATE_DEFAULT;
+	if (!ice->is_spdif_master)
+		ice->is_spdif_master = stdclock_is_spdif_master;
+	if (!ice->get_rate)
+		ice->get_rate = stdclock_get_rate;
+	if (!ice->set_rate)
+		ice->set_rate = stdclock_set_rate;
+	if (!ice->set_mclk)
+		ice->set_mclk = stdclock_set_mclk;
+	if (!ice->set_spdif_clock)
+		ice->set_spdif_clock = stdclock_set_spdif_clock;
+	if (!ice->hw_rates)
+		set_std_hw_rates(ice);
 
 	if ((err = snd_vt1724_pcm_profi(ice, pcm_dev++)) < 0) {
 		snd_card_free(card);