Merge branch 'topic/ice1724-quartet' into topic/hda
[cascardo/linux.git] / sound / pci / ice1712 / ice1724.c
index 10fc92c..ae29073 100644 (file)
@@ -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);