summaryrefslogtreecommitdiffstats
path: root/sound/pci/ice1712/ice1724.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/ice1712/ice1724.c')
-rw-r--r--sound/pci/ice1712/ice1724.c103
1 files changed, 83 insertions, 20 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 10fc92c..ae29073 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -53,6 +53,7 @@
#include "phase.h"
#include "wtm.h"
#include "se.h"
+#include "quartet.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -70,6 +71,7 @@ MODULE_SUPPORTED_DEVICE("{"
PHASE_DEVICE_DESC
WTM_DEVICE_DESC
SE_DEVICE_DESC
+ QTET_DEVICE_DESC
"{VIA,VT1720},"
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
@@ -104,6 +106,8 @@ static int PRO_RATE_LOCKED;
static int PRO_RATE_RESET = 1;
static unsigned int PRO_RATE_DEFAULT = 44100;
+static char *ext_clock_names[1] = { "IEC958 In" };
+
/*
* Basic I/O
*/
@@ -118,9 +122,12 @@ static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice)
return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
}
+/*
+ * locking rate makes sense only for internal clock mode
+ */
static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
{
- return ice->is_spdif_master(ice) || PRO_RATE_LOCKED;
+ return (!ice->is_spdif_master(ice)) && PRO_RATE_LOCKED;
}
/*
@@ -196,6 +203,12 @@ static void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */
}
+/* get gpio direction 0 = read, 1 = write */
+static unsigned int snd_vt1724_get_gpio_dir(struct snd_ice1712 *ice)
+{
+ return inl(ICEREG1724(ice, GPIO_DIRECTION));
+}
+
/* set the gpio mask (0 = writable) */
static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
{
@@ -205,6 +218,17 @@ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
}
+static unsigned int snd_vt1724_get_gpio_mask(struct snd_ice1712 *ice)
+{
+ unsigned int mask;
+ if (!ice->vt1720)
+ mask = (unsigned int)inb(ICEREG1724(ice, GPIO_WRITE_MASK_22));
+ else
+ mask = 0;
+ mask = (mask << 16) | inw(ICEREG1724(ice, GPIO_WRITE_MASK));
+ return mask;
+}
+
static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
{
outw(data, ICEREG1724(ice, GPIO_DATA));
@@ -651,16 +675,22 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
}
if (!force && is_pro_rate_locked(ice)) {
+ /* comparing required and current rate - makes sense for
+ * internal clock only */
spin_unlock_irqrestore(&ice->reg_lock, flags);
return (rate == ice->cur_rate) ? 0 : -EBUSY;
}
- 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 0;
+ if (force || !ice->is_spdif_master(ice)) {
+ /* force means the rate was switched by ucontrol, otherwise
+ * setting clock rate for internal clock mode */
+ 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 0;
+ }
}
ice->cur_rate = rate;
@@ -1016,6 +1046,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
VT1724_BUFFER_ALIGN);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
VT1724_BUFFER_ALIGN);
+ if (ice->pro_open)
+ ice->pro_open(ice, substream);
return 0;
}
@@ -1034,6 +1066,8 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
VT1724_BUFFER_ALIGN);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
VT1724_BUFFER_ALIGN);
+ if (ice->pro_open)
+ ice->pro_open(ice, substream);
return 0;
}
@@ -1787,15 +1821,21 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
+ int hw_rates_count = ice->hw_rates->count;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
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)
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
- strcpy(uinfo->value.enumerated.name, "IEC958 Input");
+ if (uinfo->value.enumerated.item >= hw_rates_count)
+ /* ext_clock items */
+ strcpy(uinfo->value.enumerated.name,
+ ice->ext_clock_names[
+ uinfo->value.enumerated.item - hw_rates_count]);
else
+ /* int clock items */
sprintf(uinfo->value.enumerated.name, "%d",
ice->hw_rates->list[uinfo->value.enumerated.item]);
return 0;
@@ -1809,7 +1849,8 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
spin_lock_irq(&ice->reg_lock);
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 {
rate = ice->get_rate(ice);
ucontrol->value.enumerated.item[0] = 0;
@@ -1824,8 +1865,14 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
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 */
-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 i2s_oval;
@@ -1834,27 +1881,30 @@ static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
/* setting 256fs */
i2s_oval = inb(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,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int old_rate, new_rate;
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;
+ /* if rate = 0 => external clock */
spin_lock_irq(&ice->reg_lock);
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);
+ if (item >= first_ext_clock) {
+ /* switching to external clock */
+ ice->set_spdif_clock(ice, item - first_ext_clock);
new_rate = 0;
} else {
/* internal on-card clock */
@@ -1866,7 +1916,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
}
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) {
/* notify akm chips as well */
unsigned int i;
@@ -2136,6 +2186,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_phase_cards,
snd_vt1724_wtm_cards,
snd_vt1724_se_cards,
+ snd_vt1724_qtet_cards,
NULL,
};
@@ -2434,7 +2485,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
mutex_init(&ice->open_mutex);
mutex_init(&ice->i2c_mutex);
ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
+ ice->gpio.get_mask = snd_vt1724_get_gpio_mask;
ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
+ ice->gpio.get_dir = snd_vt1724_get_gpio_dir;
ice->gpio.set_data = snd_vt1724_set_gpio_data;
ice->gpio.get_data = snd_vt1724_get_gpio_data;
ice->card = card;
@@ -2522,6 +2575,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
return err;
}
+ /* field init before calling chip_init */
+ ice->ext_clock_count = 0;
+
for (tbl = card_tables; *tbl; tbl++) {
for (c = *tbl; c->subvendor; c++) {
if (c->subvendor == ice->eeprom.subvendor) {
@@ -2560,6 +2616,13 @@ __found:
ice->set_mclk = stdclock_set_mclk;
if (!ice->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)
set_std_hw_rates(ice);
@@ -2719,7 +2782,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
if (ice->pm_saved_is_spdif_master) {
/* switching to external clock via SPDIF */
- ice->set_spdif_clock(ice);
+ ice->set_spdif_clock(ice, 0);
} else {
/* internal on-card clock */
snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
OpenPOWER on IntegriCloud