[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / sound / i2c / other / ak4xxx-adda.c
index 5da49e2eb35047248abea410872d1a90921b5acc..de03f689fa2e04dd4f951fbcbb7c272408723b4f 100644 (file)
@@ -2,7 +2,7 @@
  *   ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
  *   AD and DA converters
  *
- *     Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>,
+ *     Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>,
  *                             Takashi Iwai <tiwai@suse.de>
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
 #include <sound/tlv.h>
 #include <sound/ak4xxx-adda.h>
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx  AD/DA converters");
 MODULE_LICENSE("GPL");
 
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
  * Used for AK4524 input/ouput attenuation, AK4528, and
  * AK5365 input attenuation
  */
-static unsigned char vol_cvt_datt[128] = {
+static const unsigned char vol_cvt_datt[128] = {
        0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
        0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
        0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
@@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = {
 /*
  * dB tables
  */
-static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
-static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
 
 /*
  * initialize all the ak4xxx chips
  */
 void snd_akm4xxx_init(struct snd_akm4xxx *ak)
 {
-       static unsigned char inits_ak4524[] = {
+       static const unsigned char inits_ak4524[] = {
                0x00, 0x07, /* 0: all power up */
                0x01, 0x00, /* 1: ADC/DAC reset */
                0x02, 0x60, /* 2: 24bit I2S */
@@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x07, 0x00, /* 7: DAC right muted */
                0xff, 0xff
        };
-       static unsigned char inits_ak4528[] = {
+       static const unsigned char inits_ak4528[] = {
                0x00, 0x07, /* 0: all power up */
                0x01, 0x00, /* 1: ADC/DAC reset */
                0x02, 0x60, /* 2: 24bit I2S */
@@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x05, 0x00, /* 5: ADC right muted */
                0xff, 0xff
        };
-       static unsigned char inits_ak4529[] = {
+       static const unsigned char inits_ak4529[] = {
                0x09, 0x01, /* 9: ATS=0, RSTN=1 */
                0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
                0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
@@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x08, 0x55, /* 8: deemphasis all off */
                0xff, 0xff
        };
-       static unsigned char inits_ak4355[] = {
+       static const unsigned char inits_ak4355[] = {
                0x01, 0x02, /* 1: reset and soft-mute */
                0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
                             * disable DZF, sharp roll-off, RSTN#=0 */
@@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x01, 0x01, /* 1: un-reset, unmute */
                0xff, 0xff
        };
-       static unsigned char inits_ak4358[] = {
+       static const unsigned char inits_ak4358[] = {
                0x01, 0x02, /* 1: reset and soft-mute */
                0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
                             * disable DZF, sharp roll-off, RSTN#=0 */
@@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x01, 0x01, /* 1: un-reset, unmute */
                0xff, 0xff
        };
-       static unsigned char inits_ak4381[] = {
+       static const unsigned char inits_ak4381[] = {
                0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
                0x01, 0x02, /* 1: de-emphasis off, normal speed,
                             * sharp roll-off, DZF off */
@@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        };
 
        int chip, num_chips;
-       unsigned char *ptr, reg, data, *inits;
+       const unsigned char *ptr, *inits;
+       unsigned char reg, data;
 
        memset(ak->images, 0, sizeof(ak->images));
        memset(ak->volumes, 0, sizeof(ak->volumes));
@@ -462,15 +463,7 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
-static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
+#define ak4xxx_switch_info     snd_ctl_boolean_mono_info
 
 static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
@@ -480,8 +473,8 @@ static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
        int addr = AK_GET_ADDR(kcontrol->private_value);
        int shift = AK_GET_SHIFT(kcontrol->private_value);
        int invert = AK_GET_INVERT(kcontrol->private_value);
-       unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
+       /* we observe the (1<<shift) bit only */
+       unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
        if (invert)
                val = ! val;
        ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
@@ -513,6 +506,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define AK5365_NUM_INPUTS 5
+
+static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
+       const char **input_names;
+       int  num_names, idx;
+
+       input_names = ak->adc_info[mixer_ch].input_names;
+
+       num_names = 0;
+       while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+               ++num_names;
+       
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = num_names;
+       idx = uinfo->value.enumerated.item;
+       if (idx >= num_names)
+               return -EINVAL;
+       strncpy(uinfo->value.enumerated.name, input_names[idx],
+               sizeof(uinfo->value.enumerated.name));
+       return 0;
+}
+
+static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char val;
+
+       val = snd_akm4xxx_get(ak, chip, addr) & mask;
+       ucontrol->value.enumerated.item[0] = val;
+       return 0;
+}
+
+static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char oval, val;
+
+       oval = snd_akm4xxx_get(ak, chip, addr);
+       val = oval & ~mask;
+       val |= ucontrol->value.enumerated.item[0] & mask;
+       if (val != oval) {
+               snd_akm4xxx_write(ak, chip, addr, val);
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * build AK4xxx controls
  */
@@ -524,6 +577,26 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
 
        mixer_ch = 0;
        for (idx = 0; idx < ak->num_dacs; ) {
+               /* mute control for Revolution 7.1 - AK4381 */
+               if (ak->type == SND_AK4381 
+                               &&  ak->dac_info[mixer_ch].switch_name) {
+                       memset(&knew, 0, sizeof(knew));
+                       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       knew.count = 1;
+                       knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       knew.name = ak->dac_info[mixer_ch].switch_name;
+                       knew.info = ak4xxx_switch_info;
+                       knew.get = ak4xxx_switch_get;
+                       knew.put = ak4xxx_switch_put;
+                       knew.access = 0;
+                       /* register 1, bit 0 (SMUTE): 0 = normal operation,
+                          1 = mute */
+                       knew.private_value =
+                               AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
+                       err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+                       if (err < 0)
+                               return err;
+               }
                memset(&knew, 0, sizeof(knew));
                if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
                        knew.name = "DAC Volume";
@@ -647,9 +720,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
 
                if (ak->type == SND_AK5365 && (idx % 2) == 0) {
                        if (! ak->adc_info || 
-                           ! ak->adc_info[mixer_ch].switch_name)
+                           ! ak->adc_info[mixer_ch].switch_name) {
                                knew.name = "Capture Switch";
-                       else
+                               knew.index = mixer_ch + ak->idx_offset * 2;
+                       } else
                                knew.name = ak->adc_info[mixer_ch].switch_name;
                        knew.info = ak4xxx_switch_info;
                        knew.get = ak4xxx_switch_get;
@@ -662,6 +736,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
                        err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
                        if (err < 0)
                                return err;
+
+                       memset(&knew, 0, sizeof(knew));
+                       knew.name = ak->adc_info[mixer_ch].selector_name;
+                       if (!knew.name) {
+                               knew.name = "Capture Channel";
+                               knew.index = mixer_ch + ak->idx_offset * 2;
+                       }
+
+                       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       knew.info = ak4xxx_capture_source_info;
+                       knew.get = ak4xxx_capture_source_get;
+                       knew.put = ak4xxx_capture_source_put;
+                       knew.access = 0;
+                       /* input selector control: reg. 1, bits 0-2.
+                        * mis-use 'shift' to pass mixer_ch */
+                       knew.private_value
+                               = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
+                       err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+                       if (err < 0)
+                               return err;
                }
 
                idx += num_stereo;