Merge branches 'release', 'ejd', 'sony' and 'wmi' into release
[sfrench/cifs-2.6.git] / sound / pci / ice1712 / phase.c
index 3ac25058bb588fa583afc3bcc0a5b21ec577b6d7..5a158b73dcaa2050211bf55291d3de67b0621ebd 100644 (file)
@@ -33,7 +33,6 @@
  *             CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "phase.h"
 #include <sound/tlv.h>
 
+/* AC97 register cache for Phase28 */
+struct phase28_spec {
+       unsigned short master[2];
+       unsigned short vol[8];
+};
+
 /* WM8770 registers */
 #define WM_DAC_ATTEN           0x00    /* DAC1-8 analog attenuation */
 #define WM_DAC_MASTER_ATTEN    0x08    /* DAC master analog attenuation */
@@ -313,27 +318,32 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i;
        for (i=0; i<2; i++)
-               ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int ch, change = 0;
 
        snd_ice1712_save_gpio_status(ice);
        for (ch = 0; ch < 2; ch++) {
-               if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) {
+               unsigned int vol = ucontrol->value.integer.value[ch];
+               if (vol > WM_VOL_MAX)
+                       continue;
+               vol |= spec->master[ch] & WM_VOL_MUTE;
+               if (vol != spec->master[ch]) {
                        int dac;
-                       ice->spec.phase28.master[ch] &= WM_VOL_MUTE;
-                       ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch];
+                       spec->master[ch] = vol;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
-                                          ice->spec.phase28.vol[dac + ch],
-                                          ice->spec.phase28.master[ch]);
+                                          spec->vol[dac + ch],
+                                          spec->master[ch]);
                        change = 1;
                }
        }
@@ -382,12 +392,18 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 
        unsigned int tmp;
        struct snd_akm4xxx *ak;
+       struct phase28_spec *spec;
        const unsigned short *p;
        int i;
 
        ice->num_total_dacs = 8;
        ice->num_total_adcs = 2;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        // Initialize analog chips
        ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
        if (!ak)
@@ -417,11 +433,11 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 
        snd_ice1712_restore_gpio_status(ice);
 
-       ice->spec.phase28.master[0] = WM_VOL_MUTE;
-       ice->spec.phase28.master[1] = WM_VOL_MUTE;
+       spec->master[0] = WM_VOL_MUTE;
+       spec->master[1] = WM_VOL_MUTE;
        for (i = 0; i < ice->num_total_dacs; i++) {
-               ice->spec.phase28.vol[i] = WM_VOL_MUTE;
-               wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]);
+               spec->vol[i] = WM_VOL_MUTE;
+               wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
        }
 
        return 0;
@@ -443,18 +459,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *
 static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i, ofs, voices;
 
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xff;
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] =
+                       spec->vol[ofs+i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i, idx, ofs, voices;
        int change = 0;
 
@@ -462,12 +481,16 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
        ofs = kcontrol->private_value & 0xff;
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               idx  = WM_DAC_ATTEN + ofs + i;
-               if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) {
-                       ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE;
-                       ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i];
-                       wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i],
-                                  ice->spec.phase28.master[i]);
+               unsigned int vol;
+               vol = ucontrol->value.integer.value[i];
+               if (vol > 0x7f)
+                       continue;
+               vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
+               if (vol != spec->vol[ofs+i]) {
+                       spec->vol[ofs+i] = vol;
+                       idx  = WM_DAC_ATTEN + ofs + i;
+                       wm_set_vol(ice, idx, spec->vol[ofs+i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -489,19 +512,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
 static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int voices, ofs, i;
 
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xFF;
 
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
+               ucontrol->value.integer.value[i] =
+                       (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int change = 0, voices, ofs, i;
 
        voices = kcontrol->private_value >> 8;
@@ -509,13 +535,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
-                       ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE;
-                       ice->spec.phase28.vol[ofs + i] |=
+                       spec->vol[ofs + i] &= ~WM_VOL_MUTE;
+                       spec->vol[ofs + i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
-                       wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i],
-                                  ice->spec.phase28.master[i]);
+                       wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -532,29 +558,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
 
-       ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1;
-       ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[0] =
+               (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[1] =
+               (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int change = 0, i;
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < 2; i++) {
-               int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
                        int dac;
-                       ice->spec.phase28.master[i] &= ~WM_VOL_MUTE;
-                       ice->spec.phase28.master[i] |=
+                       spec->master[i] &= ~WM_VOL_MUTE;
+                       spec->master[i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
-                                          ice->spec.phase28.vol[dac + i],
-                                          ice->spec.phase28.master[i]);
+                                          spec->vol[dac + i],
+                                          spec->master[i]);
                        change = 1;
                }
        }
@@ -595,8 +625,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        unsigned short ovol, nvol;
        int change = 0;
 
-       snd_ice1712_save_gpio_status(ice);
        nvol = ucontrol->value.integer.value[0];
+       if (nvol > PCM_RES)
+               return -EINVAL;
+       snd_ice1712_save_gpio_status(ice);
        nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
        ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
        if (ovol != nvol) {