Initial import of patch.
authormnzaki <mnzaki@gmail.com>
Thu, 2 Sep 2010 11:46:19 +0000 (14:46 +0300)
committermnzaki <mnzaki@gmail.com>
Thu, 2 Sep 2010 11:46:19 +0000 (14:46 +0300)
What we have right now:
- All page 1 registers added as a u16 array of coefficients with routines
  to read/write the coefficients (aic3x_read_coeff_cache and
  aic3x_write_coeff respectively)
- Added syncing coeff_cache with hardware after a suspend/resume cycle
- Added ALSA controls for the 3-D depth simulation filter

What's missing:
- A lot

kernel-2.6.28/sound/soc/codecs/tlv320aic3x.c
kernel-2.6.28/sound/soc/codecs/tlv320aic3x.h

index 4f70822..b39b3ae 100644 (file)
@@ -59,6 +59,7 @@ struct aic3x_priv {
        unsigned int sysclk;
        int master;
        int prepare_reset;
        unsigned int sysclk;
        int master;
        int prepare_reset;
+       u16 coeff_cache[AIC3X_COEFF_CACHE_SIZE];
 };
 
 /*
 };
 
 /*
@@ -96,6 +97,28 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
        0x00, 0x00, 0x02,       /* 100 */
 };
 
        0x00, 0x00, 0x02,       /* 100 */
 };
 
+/* Page 1 registers store 2s compliment 16-bit numbers used for
+ * coefficients for effects. Each number is in 2 register, MSB followed
+ * by LSB. Therefore this array contains AIC3X_CACHEREGNUM/2 + 1 items.
+ */
+static const u16 aic3x_coeff[AIC3X_COEFF_CACHE_SIZE] =
+{
+       0x00, /* Reg 0 */
+       0x6be3, 0x9666, 0x675d, 0x6be3, /* Reg 1 - 8 */
+       0x9666, 0x675d, 0x7d83, 0x84ee, /* 9 - 16 */
+       0x7d83, 0x84ee, 0x3955, 0xf32d, /* 17 - 24 */
+       0x537e, 0x6be3, 0x9666, 0x675d, /* 25 - 32 */
+       0x6be3, 0x9666, 0x675d, 0x7d83, /* 33 - 40 */
+       0x84ee, 0x7d83, 0x84ee, 0x3955, /* 41 - 48 */
+       0xf32d, 0x537e, 0x7fff, 0x0000, /* 49 - 56 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 57 - 64 */
+       0x3955, 0xf32d, 0x537e, 0x3955, /* 65 - 72 */
+       0xf32d, 0x537e, 0x0000, 0x0000, /* 73 - 80 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 81 - 88 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 89 - 96 */
+       0x0000, 0x0000, 0x0000,         /* 97 - 102 */
+};
+
 /*
  * read aic3x register cache
  */
 /*
  * read aic3x register cache
  */
@@ -108,6 +131,12 @@ static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
        return cache[reg];
 }
 
        return cache[reg];
 }
 
+static inline unsigned int aic3x_read_coeff_cache(struct snd_soc_codec *codec,
+                                               unsigned int reg) {
+       u16 *cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache;
+    return cache[COEFF_OFFSET(reg)];
+}
+
 /*
  * write aic3x register cache
  */
 /*
  * write aic3x register cache
  */
@@ -135,13 +164,47 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
        data[0] = reg & 0xff;
        data[1] = value & 0xff;
 
        data[0] = reg & 0xff;
        data[1] = value & 0xff;
 
-       aic3x_write_reg_cache(codec, data[0], data[1]);
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
+       if (codec->hw_write(codec->control_data, data, 2) == 2){
+           aic3x_write_reg_cache(codec, data[0], data[1]);
                return 0;
                return 0;
-       else
+       } else
                return -EIO;
 }
 
                return -EIO;
 }
 
+/* Write a coefficient to the page 1 registers. Switching the page is
+ * not done here and is left to the caller.
+ */
+static int aic3x_write_coeff(struct snd_soc_codec *codec, unsigned int msbreg,
+                      int value)
+{
+    u8 i, values[2], data[2];
+    u16 outp;
+    u16 *cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache;
+
+       if (msbreg >= AIC3X_CACHEREGNUM)
+               return -1;
+
+    /* Change to 2s compliment and break into MSB and LSB */
+       if (value < 0)
+      outp = 65536 + value;
+    else
+      outp = value;
+
+    values[0] = (outp >> 8) & 0xff;
+    values[1] = outp & 0xff;
+
+       for(i = 0; i < 2; i++){
+               data[0] = (msbreg + i) & 0xff;
+               data[1] = values[i] & 0xff;
+
+               if (codec->hw_write(codec->control_data, data, 2) != 2)
+                       return -EIO;
+       }
+
+       cache[COEFF_OFFSET(msbreg)] = outp;
+       return 0;
+}
+
 /*
  * read from the aic3x register space
  */
 /*
  * read from the aic3x register space
  */
@@ -331,6 +394,39 @@ static int tlv320alc3x_info_volsw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
        return 0;
 }
 
+
+static int snd_soc_get_3d_attenuation_aic3x(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       int val = aic3x_read_coeff_cache(snd_kcontrol_chip(kcontrol), EFFECTS_3DATTEN);
+    if(val > 32767)
+         val = val - 65536;
+       val = ((val*100)/65530) + 50;
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+static int snd_soc_put_3d_attenuation_aic3x(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int reg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA);
+       int val = ucontrol->value.integer.value[0];
+
+       if(val){
+               aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, reg | 0x04);
+       } else {
+               aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, reg & 0xfb);
+       }
+
+       val = ((val - 50) * 65535) / 100 ;
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT);
+       aic3x_write_coeff(codec, EFFECTS_3DATTEN, val);
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+
+       return 1;
+}
+
 static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        /* Output */
        SOC_DOUBLE_R_TLV("PCM Playback Volume",
 static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        /* Output */
        SOC_DOUBLE_R_TLV("PCM Playback Volume",
@@ -399,6 +495,9 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
 
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
        SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
 
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
+
+       SOC_SINGLE_EXT("3D Control - Depth", EFFECTS_3DATTEN, 0, 100, 0,
+               snd_soc_get_3d_attenuation_aic3x, snd_soc_put_3d_attenuation_aic3x),
 };
 
 /* add non dapm controls */
 };
 
 /* add non dapm controls */
@@ -1215,12 +1314,28 @@ static int aic3x_resume(struct platform_device *pdev)
        struct snd_soc_codec *codec = socdev->codec;
        int i;
        u8 data[2];
        struct snd_soc_codec *codec = socdev->codec;
        int i;
        u8 data[2];
-       u8 *cache = codec->reg_cache;
+       u8 *reg_cache = codec->reg_cache;
+       u16 *coeff_cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache;
+
+       /* Sync hardware with the coeff_cache first so that filters can be
+        * turned on safely
+        */
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT);
+       for (i = 1; i < ARRAY_SIZE(aic3x_coeff); i++){
+               data[0] = i*2 - 1;
+               data[1] = (coeff_cache[i] >> 8) && 0xff;
+               codec->hw_write(codec->control_data, data, 2);
+
+               data[0]++;
+               data[1] = coeff_cache[i] & 0xff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
 
 
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
+       /* Sync hardware with the reg_cache */
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+       for (i = 1; i < ARRAY_SIZE(aic3x_reg); i++) {
                data[0] = i;
                data[0] = i;
-               data[1] = cache[i];
+               data[1] = reg_cache[i];
                codec->hw_write(codec->control_data, data, 2);
        }
 
                codec->hw_write(codec->control_data, data, 2);
        }
 
@@ -1339,6 +1454,11 @@ static int aic3x_init(struct snd_soc_device *socdev)
                goto card_err;
        }
 
                goto card_err;
        }
 
+       /* Set some defaults for coefficients */
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT);
+       aic3x_write_coeff(codec, EFFECTS_3DATTEN, -32768);
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+
        return ret;
 
 card_err:
        return ret;
 
 card_err:
@@ -1464,6 +1584,8 @@ static int aic3x_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
                return -ENOMEM;
 
        aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+    memcpy(aic3x->coeff_cache, aic3x_coeff, sizeof(aic3x_coeff));
+
        if (aic3x == NULL) {
                kfree(codec);
                return -ENOMEM;
        if (aic3x == NULL) {
                kfree(codec);
                return -ENOMEM;
index 15a98aa..c71cafc 100644 (file)
@@ -14,6 +14,8 @@
 
 /* AIC3X register space */
 #define AIC3X_CACHEREGNUM              103
 
 /* AIC3X register space */
 #define AIC3X_CACHEREGNUM              103
+#define AIC3X_COEFF_CACHE_SIZE 52
+#define COEFF_OFFSET(msbreg)   ((msbreg+1)/2)
 
 /* Page select register */
 #define AIC3X_PAGE_SELECT              0
 
 /* Page select register */
 #define AIC3X_PAGE_SELECT              0
 /* Clock generation control register */
 #define AIC3X_CLKGEN_CTRL_REG          102
 
 /* Clock generation control register */
 #define AIC3X_CLKGEN_CTRL_REG          102
 
+/* Page 1 registers for setting coefficients for filters */
+/* DAC Audio Effects for Left Channel */
+#define EFFECTS_LEFT_N0 1
+#define EFFECTS_LEFT_N1 3
+#define EFFECTS_LEFT_N2 5
+#define EFFECTS_LEFT_N3 7
+#define EFFECTS_LEFT_N4 9
+#define EFFECTS_LEFT_N5 11
+
+#define EFFECTS_LEFT_D1 13
+#define EFFECTS_LEFT_D2 15
+#define EFFECTS_LEFT_D4 17
+#define EFFECTS_LEFT_D5 19
+
+/* DAC De-Emphasis for Left Channel */
+
+#define DEEMPH_LEFT_N0 21
+#define DEEMPH_LEFT_N1 23
+#define DEEMPH_LEFT_D1 25
+
+/* DAC Audio Effects for Right Channel */
+
+#define EFFECTS_RIGHT_N0 27
+#define EFFECTS_RIGHT_N1 29
+#define EFFECTS_RIGHT_N2 31
+#define EFFECTS_RIGHT_N3 33
+#define EFFECTS_RIGHT_N4 35
+#define EFFECTS_RIGHT_N5 37
+
+#define EFFECTS_RIGHT_D1 39
+#define EFFECTS_RIGHT_D2 41
+#define EFFECTS_RIGHT_D4 43
+#define EFFECTS_RIGHT_D5 45
+
+/* DAC De-Emphasis for Right Channel */
+
+#define DEEMPH_RIGHT_N0 47
+#define DEEMPH_RIGHT_N1 49
+#define DEEMPH_RIGHT_D1 51
+
+/* DAC 3D Attenuation */
+
+#define EFFECTS_3DATTEN 53
+
+/* ADC High-Pass Filter for Left Channel */
+
+#define HIGHPASS_LEFT_NO 65
+#define HIGHPASS_LEFT_N1 67
+#define HIGHPASS_LEFT_D1 69
+
+/* ADC High-Pass Filter for Right Channel */
+
+#define HIGHPASS_RIGHT_NO 71
+#define HIGHPASS_RIGHT_N1 73
+#define HIGHPASS_RIGHT_D1 75
+
 /* Page select register bits */
 #define PAGE0_SELECT           0
 #define PAGE1_SELECT           1
 /* Page select register bits */
 #define PAGE0_SELECT           0
 #define PAGE1_SELECT           1