AndroidComputer Codec:add TINY ALSA support
authorzhangjun <zhangjun@rock-chips.com>
Mon, 14 Oct 2013 08:50:31 +0000 (16:50 +0800)
committerzhangjun <zhangjun@rock-chips.com>
Mon, 14 Oct 2013 08:50:31 +0000 (16:50 +0800)
sound/soc/codecs/cx2070x-i2c.h [changed mode: 0644->0755]
sound/soc/codecs/cx2070x.c [changed mode: 0644->0755]
sound/soc/codecs/cx2070x.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 096fc8f..410440b
   __REG(PATCH_VERSION,                 0x1003, 0x1003, 0x00,       0, RO,W)
   __REG(CHIP_VERSION,                  0x1005, 0x1005, 0x00,       0, RO,B)
   __REG(RELEASE_TYPE,                  0x1006, 0x1006, 0x00,       0, RO,B)
-
+  __REG(USB_LOCAL_VOLUME,       0x004E, 0x004E, 0x42,       0, RW,B)
   __REG(ROM_PATCH_VER_HB,              0x1584, 0xFFFF, 0x00,       0, RO,B)
   __REG(ROM_PATCH_VER_MB,              0x1585, 0xFFFF, 0x00,       0, RO,B)
   __REG(ROM_PATCH_VER_LB,              0x1586, 0xFFFF, 0x00,       0, RO,B)
   
-  __REG(DAC1_GAIN_LEFT,                        0x100D, 0x100D, 0xc9,    0x4A, RW,B)
-  __REG(DAC2_GAIN_RIGHT,               0x100E, 0x100E, 0xc9,    0x4A, RW,B)
+  __REG(DAC1_GAIN_LEFT,                        0x100D, 0x100D, 0x00,    0x00, RW,B)
+  __REG(DAC2_GAIN_RIGHT,               0x100E, 0x100E, 0x00,    0x00, RW,B)
   __REG(DSP_MAX_VOLUME,                        0x100F, 0x100F, 0x00,       0, RW,B)
 
   __REG(CLASS_D_GAIN,                  0x1011, 0x1010, b_00000000, 0, RW,B)
@@ -81,8 +81,8 @@
 
   __REG(ADC1_GAIN_LEFT,                        0x1013, 0x1012, 0x00,    0x4A, RW,B)
   __REG(ADC1_GAIN_RIGHT,               0x1014, 0x1013, 0x00,    0x4A, RW,B)
-  __REG(ADC2_GAIN_LEFT,                        0x1015, 0x1014, 0x00,    0x4A, RW,B)
-  __REG(ADC2_GAIN_RIGHT,               0x1016, 0x1015, 0x00,    0x4A, RW,B)
+  __REG(ADC2_GAIN_LEFT,                        0x1015, 0x1014, 0x00,    0x00, RW,B)
+  __REG(ADC2_GAIN_RIGHT,               0x1016, 0x1015, 0x00,    0x00, RW,B)
   __REG(DSP_MAX_MIC_GAIN,              0x1017, 0x1016, 0x00,       0, RW,B)
 
   __REG(VOLUME_MUTE,                   0x1018, 0x1017, 0, 0, WI,B)
old mode 100644 (file)
new mode 100755 (executable)
index 050db44..4b5cec0
@@ -216,6 +216,8 @@ struct cx2070x_priv
     enum Cx_INPUT_SEL input_sel;
     enum Cx_OUTPUT_SEL output_sel;
        unsigned int mute;
+    long int playback_path;
+       long int capture_path;
 };
 
 #define get_cx2070x_priv(_codec_) ((struct cx2070x_priv *)snd_soc_codec_get_drvdata(codec))
@@ -434,6 +436,7 @@ static int NOINLINE cx2070x_real_write(struct snd_soc_codec *codec, unsigned int
         msg[0].addr  = client->addr;
         msg[0].flags = client->flags & I2C_M_TEN;
         msg[0].buf   = &data[0];
+        msg[0].scl_rate = 200 * 1000;
         data[0]=(u8)(ri->addr>>8);
         data[1]=(u8)(ri->addr>>0);
         switch(ri->type&REG_WIDTH_MASK)
@@ -489,11 +492,13 @@ static int NOINLINE cx2070x_real_read(struct snd_soc_codec *codec, unsigned int
     msg[0].flags = client->flags & I2C_M_TEN;
     msg[0].len   = 2;
     msg[0].buf   = &data[0];
+    msg[0].scl_rate = 200 * 1000;
 
     msg[1].addr  = client->addr;
     msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
     msg[1].len   = ((ri->type&REG_WIDTH_MASK)==REG_WIDTH_W)?2:1;
     msg[1].buf   = &data[2];
+    msg[1].scl_rate = 200 * 1000;
 
     if (i2c_transfer(adap,msg,2)!=2)
         return -EIO;
@@ -711,6 +716,180 @@ static const struct snd_kcontrol_new cx2070x_snd_controls[]=
     SOC_ENUM_EXT("Master Playback Switch", output_select_enum[0], output_select_event_get, output_select_event_set),
 };
 
+//For tiny alsa playback/capture/voice call path
+static const char *cx2070x_playback_path_mode[] = {"OFF", "RCV", "SPK", "HP", "HP_NO_MIC", "BT", "SPK_HP", //0-6
+               "RING_SPK", "RING_HP", "RING_HP_NO_MIC", "RING_SPK_HP"};//7-10
+
+static const char *cx2070x_capture_path_mode[] = {"MIC OFF", "Main Mic", "Hands Free Mic", "BT Sco Mic"};
+
+static const SOC_ENUM_SINGLE_DECL(cx2070x_playback_path_type, 0, 0, cx2070x_playback_path_mode);
+
+static const SOC_ENUM_SINGLE_DECL(cx2070x_capture_path_type, 0, 0, cx2070x_capture_path_mode);
+
+
+static int cx2070x_playback_path_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+    struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct cx2070x_priv  *cx2070x = get_cx2070x_priv(codec);
+
+       if (!cx2070x) {
+               printk("%s : cx2070x_priv is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       printk("%s : playback_path %ld\n",__func__,ucontrol->value.integer.value[0]);
+
+       ucontrol->value.integer.value[0] = cx2070x->playback_path;
+
+       return 0;
+}
+
+static int cx2070x_playback_path_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+    struct cx2070x_priv  *cx2070x = get_cx2070x_priv(codec);
+       long int pre_path;
+
+       if (!cx2070x) {
+               printk("%s : cx2070x_priv is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       if (cx2070x->playback_path == ucontrol->value.integer.value[0]){
+               printk("%s : playback_path is not changed!\n",__func__);
+               return 0;
+       }
+
+       pre_path = cx2070x->playback_path;
+       cx2070x->playback_path = ucontrol->value.integer.value[0];
+
+       printk("%s : set playback_path %ld, pre_path %ld\n", __func__,
+               cx2070x->playback_path, pre_path);
+
+       switch (cx2070x->playback_path) {
+       case OFF:
+               if (pre_path != OFF) {
+            cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,(cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC) & ~(1 << 3));
+        }                      
+               break;
+       case RCV:
+               break;
+       case SPK_PATH:
+       case RING_SPK:
+        printk("%s : >>>>>>>>>>>>>>>PUT SPK_PATH\n",__func__);
+               if (pre_path == OFF) {
+                       cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_3);
+        }
+               break;
+       case HP_PATH:
+       case HP_NO_MIC:
+       case RING_HP:
+       case RING_HP_NO_MIC:
+               if (pre_path == OFF) {
+                       cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_3);
+        }
+               break;
+       case BT:
+               break;
+       case SPK_HP:
+       case RING_SPK_HP:
+           if (pre_path == OFF) {
+                       cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_3);
+        }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cx2070x_capture_path_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+    struct cx2070x_priv  *cx2070x = get_cx2070x_priv(codec);
+
+       if (!cx2070x) {
+               printk("%s : cx2070x_priv is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       printk("%s : capture_path %ld\n", __func__,
+               ucontrol->value.integer.value[0]);
+
+       ucontrol->value.integer.value[0] = cx2070x->capture_path;
+
+       return 0;
+}
+
+static int cx2070x_capture_path_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+    struct cx2070x_priv  *cx2070x = get_cx2070x_priv(codec);
+       long int pre_path;
+
+       if (!cx2070x) {
+               printk("%s : cx2070x_priv is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       if (cx2070x->capture_path == ucontrol->value.integer.value[0]){
+               printk("%s : capture_path is not changed!\n", __func__);
+               return 0;
+       }
+
+       pre_path = cx2070x->capture_path;
+       cx2070x->capture_path = ucontrol->value.integer.value[0];
+
+       printk("%s : set capture_path %ld, pre_path %ld\n", __func__,
+               cx2070x->capture_path, pre_path);
+
+       switch (cx2070x->capture_path) {
+       case MIC_OFF:
+               if (pre_path != MIC_OFF) {
+            cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,(cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC) & ~(DSP_INIT_STREAM_5));
+        }
+               break;
+       case Main_Mic:
+    printk("%s : >>>>>>>>>>>>>>>PUT MAIN_MIC_PATH\n",__func__);
+        if (pre_path == MIC_OFF) {
+            cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_5);
+        }
+               break;
+       case Hands_Free_Mic:
+               if (pre_path == MIC_OFF) {
+            cx2070x_real_read(codec,DSP_INIT);
+            cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_5);
+        }
+               break;
+       case BT_Sco_Mic:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new cx2070x_snd_path_controls[] = {
+       SOC_ENUM_EXT("Playback Path", cx2070x_playback_path_type,
+               cx2070x_playback_path_get, cx2070x_playback_path_put),
+
+       SOC_ENUM_EXT("Capture MIC Path", cx2070x_capture_path_type,
+               cx2070x_capture_path_get, cx2070x_capture_path_put),
+};
+
+
 // add non dapm controls
 static int cx2070x_add_controls(struct snd_soc_codec *codec)
 {
@@ -1116,12 +1295,13 @@ static int cx2070x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm
     /*params for port2 by showy.zhang*/
     cx2070x_real_write(codec,STREAM5_RATE,s5);
     cx2070x_real_write(codec,STREAM3_RATE,s3);// cause by incorrect parameter
-
+#if 0
+    cx2070x_real_read(codec,DSP_INIT);
     dsp=cx2070x_read_reg_cache(codec,DSP_INIT);
-
+    printk(">>>>>>>>>>>> dsp = %0x", dsp);
     if ((err=cx2070x_dsp_init(codec,dsp|DSP_INIT_NEWC))<0)
         return err;
-
+#endif
     return 0;
 }
 
@@ -1130,20 +1310,25 @@ static int cx2070x_mute(struct snd_soc_dai *dai, int mute)
     struct snd_soc_codec *codec = dai->codec;
 
     ERROR("%lu: %s(%d) called\n",jiffies,__func__,mute);
-
+#if 0
     cx2070x_real_write(codec,VOLUME_MUTE,mute?VOLUME_MUTE_ALL:b_00000000);
 
-/*
     if( mute)
     {
-        cx2070x_real_write(codec,DSP_POWER,0xe0); // deep sleep mode
-        cx2070x_dsp_init(codec,DSP_INIT_STREAM_OFF);
+//          cx2070x_real_write(codec,DSP_POWER,0xe0); // deep sleep mode
+//          cx2070x_dsp_init(codec,DSP_INIT_STREAM_OFF);
+        /*mute I2S output*/
+        cx2070x_real_read(codec,DSP_INIT);
+        cx2070x_write(codec,DSP_INIT,(cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC) & ~(1 << 3));
     }
     else
     {
-        cx2070x_dsp_init(codec,DSP_INIT_NEWC | 0xff);
+        /*unmute I2S output*/
+        cx2070x_real_read(codec,DSP_INIT);
+        cx2070x_write(codec,DSP_INIT,cx2070x_read_reg_cache(codec,DSP_INIT)| DSP_INIT_NEWC | DSP_INIT_STREAM_3);
+        //cx2070x_dsp_init(codec,DSP_INIT_NEWC | 0xff);
     }
-*/
+#endif
     return 0;
 }
 
@@ -1591,8 +1776,10 @@ static int NOINLINE cx2070x_init(struct snd_soc_codec* codec)
     cx2070x_apply_firmware_patch(codec);
 #endif
 
-    cx2070x_add_controls(codec);
-    cx2070x_add_widgets(codec);
+    //cx2070x_add_controls(codec);
+    //cx2070x_add_widgets(codec);
+    snd_soc_add_controls(codec, cx2070x_snd_path_controls,
+                               ARRAY_SIZE(cx2070x_snd_path_controls));
 
     //snd_soc_dapm_nc_pin(&codec->dapm, "LINE IN");
     //snd_soc_dapm_nc_pin( &codec->dapm, "LINE OUT");
@@ -1635,6 +1822,9 @@ static int NOINLINE cx2070x_init(struct snd_soc_codec* codec)
 #if defined(CONFIG_SND_CXLIFEGUARD)
     cxdbg_dev_init(codec);
 #endif 
+
+    cx2070x_real_write(codec, USB_LOCAL_VOLUME, 0x42);
+
     if( ret == 0)
     {
         printk(KERN_INFO "CX2070X: codec is ready.\n");
old mode 100644 (file)
new mode 100755 (executable)
index 5b04e8f..2c7c713
@@ -61,6 +61,27 @@ enum Cx_OUTPUT_SEL{
     Cx_OUTPUT_SEL_DPORT2,
 };
 
+enum {
+       OFF,
+       RCV,
+       SPK_PATH,
+       HP_PATH,
+       HP_NO_MIC,
+       BT,
+       SPK_HP,
+       RING_SPK,
+       RING_HP,
+       RING_HP_NO_MIC,
+       RING_SPK_HP,
+};
+
+enum {
+       MIC_OFF,
+       Main_Mic,
+       Hands_Free_Mic,
+       BT_Sco_Mic,
+};
+
 #define CX2070X_I2C_DRIVER_NAME        "cx2070x-i2c"
 #define CX2070X_SPI_DRIVER_NAME        "cx2070x-spi"
 #define CX2070X_FIRMWARE_FILENAME "cnxt/cx2070x.fw"