mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
AndroidComputer Codec:add TINY ALSA support
This commit is contained in:
10
sound/soc/codecs/cx2070x-i2c.h
Normal file → Executable file
10
sound/soc/codecs/cx2070x-i2c.h
Normal file → Executable file
@@ -48,13 +48,13 @@
|
||||
__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)
|
||||
|
||||
212
sound/soc/codecs/cx2070x.c
Normal file → Executable file
212
sound/soc/codecs/cx2070x.c
Normal file → Executable file
@@ -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®_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®_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");
|
||||
|
||||
21
sound/soc/codecs/cx2070x.h
Normal file → Executable file
21
sound/soc/codecs/cx2070x.h
Normal file → Executable file
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user