]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/i2c/other/ak4xxx-adda.c
[ALSA] Remove sound/driver.h
[linux-2.6-omap-h63xx.git] / sound / i2c / other / ak4xxx-adda.c
index 5da49e2eb35047248abea410872d1a90921b5acc..35fbbf2cb9fa84bb47241c2de5ce7c9c9941e323 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
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -31,7 +30,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 +139,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 +161,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 +183,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 +193,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 +209,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 +226,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 +245,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 +258,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));
@@ -292,6 +292,11 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        case SND_AK5365:
                /* FIXME: any init sequence? */
                return;
+       case NON_AKM:
+               /* fake value for non-akm codecs using akm infrastructure
+                * (e.g. of ice1724) - certainly FIXME
+                */
+               return;
        default:
                snd_BUG();
                return;
@@ -376,8 +381,11 @@ static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
 static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
-                         ucontrol->value.integer.value[0]);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned int val = ucontrol->value.integer.value[0];
+       if (val > mask)
+               return -EINVAL;
+       return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
 }
 
 static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
@@ -408,11 +416,16 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        int addr = AK_GET_ADDR(kcontrol->private_value);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned int val[2];
        int change;
 
-       change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
-       change |= put_ak_reg(kcontrol, addr + 1,
-                            ucontrol->value.integer.value[1]);
+       val[0] = ucontrol->value.integer.value[0];
+       val[1] = ucontrol->value.integer.value[1];
+       if (val[0] > mask || val[1] > mask)
+               return -EINVAL;
+       change = put_ak_reg(kcontrol, addr, val[0]);
+       change |= put_ak_reg(kcontrol, addr + 1, val[1]);
        return change;
 }
 
@@ -462,15 +475,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 +485,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 +518,81 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define AK5365_NUM_INPUTS 5
+
+static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
+{
+       int num_names;
+       const char **input_names;
+
+       input_names = ak->adc_info[mixer_ch].input_names;
+       num_names = 0;
+       while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+               ++num_names;
+       return num_names;
+}
+
+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;
+
+       num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+       if (!num_names)
+               return -EINVAL;
+       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;
+       input_names = ak->adc_info[mixer_ch].input_names;
+       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 mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
+       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;
+       int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+
+       if (ucontrol->value.enumerated.item[0] >= num_names)
+               return -EINVAL;
+
+       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 +604,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 +747,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 +763,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;