/* * linux/sound/soc/codecs/tlv320aic3101.c * * * Copyright (C) 2011 Texas Instruments, Inc. * * Based on sound/soc/codecs/wm8753.c by Liam Girdwood * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tlv320wn.h" #define ADC0_PGA_CH1_GAIN 58 #define ADC0_PGA_CH2_GAIN 58 #ifdef CONFIG_SND_SOC_4_ADCS #define ADC1_PGA_CH1_GAIN 58 #define ADC1_PGA_CH2_GAIN 58 #define ADC2_PGA_CH1_GAIN 58 #define ADC2_PGA_CH2_GAIN 58 #define ADC3_PGA_CH1_GAIN \ 58 /* (7+1) if use 6+2 daughter bord, change ch1_gain to 0 */ #define ADC3_PGA_CH2_GAIN 0 #endif #ifdef CONFIG_SND_SOC_4_ADCS unsigned int dmic_cfg; #else unsigned int dmic_cfg = 1; #endif /* ***************************************************************************** * Function Prototype ***************************************************************************** */ static int tlv320_regr_page0_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int tlv320_regr_page0_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int reg = ucontrol->value.integer.value[0]; int i = 0; unsigned short d2regvalue; struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { d2regvalue = snd_soc_read(codec, MAKE_REG(i, 0, reg)); dev_info(codec->dev, "[%d]regvalue = %d\n", reg, d2regvalue); } return 0; } static int tlv320_regr_page1_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int tlv320_regr_page1_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int reg = ucontrol->value.integer.value[0]; unsigned short d2regvalue; int i = 0; struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { d2regvalue = snd_soc_read(codec, MAKE_REG(i, 0, reg)); dev_info(codec->dev, "[%d]regvalue = %d\n", reg, d2regvalue); } return 0; } static int tlv320_adc_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int tlv320_adc_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int vol = ucontrol->value.integer.value[0]; int i = 0, Lchvol = 0, Rchvol = 0; struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); if (vol > 104) { vol = 104; /* dev_info(codec->dev, "set vol[%d] > max value(104),*/ /* modify your vol == 104\n", vol); */ } for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_LADC_VOL(i), vol); snd_soc_write(codec, ADC_RADC_VOL(i), vol); Lchvol = snd_soc_read(codec, ADC_LADC_VOL(i)); Rchvol = snd_soc_read(codec, ADC_RADC_VOL(i)); dev_info(codec->dev, "\n ADC[%d] LchVol %d,RchVol %d\n", i, Lchvol, Rchvol); } return 0; } static const struct snd_kcontrol_new tlv320_snd_controls[] = { SOC_SINGLE_EXT("Tlv320 page0 reg", 0, 0, 1000, 0, tlv320_regr_page0_get, tlv320_regr_page0_put), SOC_SINGLE_EXT("Tlv320 page1 reg", 0, 0, 1000, 0, tlv320_regr_page1_get, tlv320_regr_page1_put), SOC_SINGLE_EXT("ADC Digital Volume", 0, 0, 150, 0, tlv320_adc_volume_get, tlv320_adc_volume_put), }; static const u8 tlv320_reg[TLV320_CACHEREGNUM] = { 0x00, 0x00, 0x00, 0x00, /* 0 */ /*ADC_A registers start here */ 0x00, 0x11, 0x04, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00, /* 8 */ 0x00, 0x00, 0x00, 0x00, /* 12 */ 0x00, 0x00, 0x01, 0x01, /* 16 */ 0x80, 0x80, 0x04, 0x00, /* 20 */ 0x00, 0x00, 0x01, 0x00, /* 24 */ 0x00, 0x02, 0x01, 0x00, /* 28 */ 0x00, 0x10, 0x00, 0x00, /* 32 */ 0x00, 0x00, 0x02, 0x00, /* 36 */ 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, /* 44 */ 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x12, 0x00, 0x00, /* 52 */ 0x00, 0x00, 0x00, 0x44, /* 56 */ 0x00, 0x01, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, /* 64 */ 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, /* 72 */ 0x00, 0x00, 0x00, 0x00, /* 76 */ 0x00, 0x00, 0x88, 0x00, /* 80 */ 0x00, 0x00, 0x00, 0x00, /* 84 */ 0x7F, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x00, 0x00, /* 92 */ 0x7F, 0x00, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x00, 0x00, /* 100 */ 0x00, 0x00, 0x00, 0x00, /* 104 */ 0x00, 0x00, 0x00, 0x00, /* 108 */ 0x00, 0x00, 0x00, 0x00, /* 112 */ 0x00, 0x00, 0x00, 0x00, /* 116 */ 0x00, 0x00, 0x00, 0x00, /* 120 */ 0x00, 0x00, 0x00, 0x00, /* 124 - ADC_A PAGE0 Registers(127) ends here */ 0x00, 0x00, 0x00, 0x00, /* 128, PAGE1-0 */ 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */ 0x00, 0x00, 0x00, 0x00, /* 136, PAGE1-8 */ 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */ 0x00, 0x00, 0x00, 0x00, /* 144, PAGE1-16 */ 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */ 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */ 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */ 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */ 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */ 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */ 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */ 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */ 0xFF, 0x00, 0x3F, 0xFF, /* 180, PAGE1-52 */ 0x00, 0x3F, 0x00, 0x80, /* 184, PAGE1-56 */ 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */ 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */ 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */ 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */ 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */ 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */ 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */ 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */ 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */ 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */ 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */ 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */ 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */ 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */ 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */ 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */ 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 */ #ifdef CONFIG_SND_SOC_4_ADCS 0x00, 0x00, 0x00, 0x00, /* 0 */ /* ADC_B regsiters start here */ 0x00, 0x11, 0x04, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00, /* 8 */ 0x00, 0x00, 0x00, 0x00, /* 12 */ 0x00, 0x00, 0x01, 0x01, /* 16 */ 0x80, 0x80, 0x04, 0x00, /* 20 */ 0x00, 0x00, 0x01, 0x00, /* 24 */ 0x00, 0x02, 0x01, 0x00, /* 28 */ 0x00, 0x10, 0x00, 0x00, /* 32 */ 0x00, 0x00, 0x02, 0x00, /* 36 */ 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, /* 44 */ 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x12, 0x00, 0x00, /* 52 */ 0x00, 0x00, 0x00, 0x44, /* 56 */ 0x00, 0x01, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, /* 64 */ 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, /* 72 */ 0x00, 0x00, 0x00, 0x00, /* 76 */ 0x00, 0x00, 0x88, 0x00, /* 80 */ 0x00, 0x00, 0x00, 0x00, /* 84 */ 0x7F, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x00, 0x00, /* 92 */ 0x7F, 0x00, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x00, 0x00, /* 100 */ 0x00, 0x00, 0x00, 0x00, /* 104 */ 0x00, 0x00, 0x00, 0x00, /* 108 */ 0x00, 0x00, 0x00, 0x00, /* 112 */ 0x00, 0x00, 0x00, 0x00, /* 116 */ 0x00, 0x00, 0x00, 0x00, /* 120 */ 0x00, 0x00, 0x00, 0x00, /* 124 - ADC_B PAGE0 Registers(127) ends here */ 0x00, 0x00, 0x00, 0x00, /* 128, PAGE1-0 */ 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */ 0x00, 0x00, 0x00, 0x00, /* 136, PAGE1-8 */ 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */ 0x00, 0x00, 0x00, 0x00, /* 144, PAGE1-16 */ 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */ 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */ 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */ 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */ 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */ 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */ 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */ 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */ 0xFF, 0x00, 0x3F, 0xFF, /* 180, PAGE1-52 */ 0x00, 0x3F, 0x00, 0x80, /* 184, PAGE1-56 */ 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */ 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */ 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */ 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */ 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */ 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */ 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */ 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */ 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */ 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */ 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */ 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */ 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */ 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */ 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */ 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */ 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 */ 0x00, 0x00, 0x00, 0x00, /* 0 */ /*ADC_C registers start here */ 0x00, 0x11, 0x04, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00, /* 8 */ 0x00, 0x00, 0x00, 0x00, /* 12 */ 0x00, 0x00, 0x01, 0x01, /* 16 */ 0x80, 0x80, 0x04, 0x00, /* 20 */ 0x00, 0x00, 0x01, 0x00, /* 24 */ 0x00, 0x02, 0x01, 0x00, /* 28 */ 0x00, 0x10, 0x00, 0x00, /* 32 */ 0x00, 0x00, 0x02, 0x00, /* 36 */ 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, /* 44 */ 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x12, 0x00, 0x00, /* 52 */ 0x00, 0x00, 0x00, 0x44, /* 56 */ 0x00, 0x01, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, /* 64 */ 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, /* 72 */ 0x00, 0x00, 0x00, 0x00, /* 76 */ 0x00, 0x00, 0x88, 0x00, /* 80 */ 0x00, 0x00, 0x00, 0x00, /* 84 */ 0x7F, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x00, 0x00, /* 92 */ 0x7F, 0x00, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x00, 0x00, /* 100 */ 0x00, 0x00, 0x00, 0x00, /* 104 */ 0x00, 0x00, 0x00, 0x00, /* 108 */ 0x00, 0x00, 0x00, 0x00, /* 112 */ 0x00, 0x00, 0x00, 0x00, /* 116 */ 0x00, 0x00, 0x00, 0x00, /* 120 */ 0x00, 0x00, 0x00, 0x00, /* 124 - ADC_C PAGE0 Registers(127) ends here */ 0x00, 0x00, 0x00, 0x00, /* 128, PAGE1-0 */ 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */ 0x00, 0x00, 0x00, 0x00, /* 136, PAGE1-8 */ 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */ 0x00, 0x00, 0x00, 0x00, /* 144, PAGE1-16 */ 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */ 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */ 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */ 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */ 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */ 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */ 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */ 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */ 0xFF, 0x00, 0x3F, 0xFF, /* 180, PAGE1-52 */ 0x00, 0x3F, 0x00, 0x80, /* 184, PAGE1-56 */ 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */ 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */ 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */ 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */ 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */ 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */ 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */ 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */ 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */ 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */ 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */ 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */ 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */ 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */ 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */ 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */ 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 */ 0x00, 0x00, 0x00, 0x00, /* 0 */ /* ADC_D regsiters start here */ 0x00, 0x11, 0x04, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00, /* 8 */ 0x00, 0x00, 0x00, 0x00, /* 12 */ 0x00, 0x00, 0x01, 0x01, /* 16 */ 0x80, 0x80, 0x04, 0x00, /* 20 */ 0x00, 0x00, 0x01, 0x00, /* 24 */ 0x00, 0x02, 0x01, 0x00, /* 28 */ 0x00, 0x10, 0x00, 0x00, /* 32 */ 0x00, 0x00, 0x02, 0x00, /* 36 */ 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, /* 44 */ 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x12, 0x00, 0x00, /* 52 */ 0x00, 0x00, 0x00, 0x44, /* 56 */ 0x00, 0x01, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, /* 64 */ 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, /* 72 */ 0x00, 0x00, 0x00, 0x00, /* 76 */ 0x00, 0x00, 0x88, 0x00, /* 80 */ 0x00, 0x00, 0x00, 0x00, /* 84 */ 0x7F, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x00, 0x00, /* 92 */ 0x7F, 0x00, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x00, 0x00, /* 100 */ 0x00, 0x00, 0x00, 0x00, /* 104 */ 0x00, 0x00, 0x00, 0x00, /* 108 */ 0x00, 0x00, 0x00, 0x00, /* 112 */ 0x00, 0x00, 0x00, 0x00, /* 116 */ 0x00, 0x00, 0x00, 0x00, /* 120 */ 0x00, 0x00, 0x00, 0x00, /* 124 - ADC_D PAGE0 Registers(127) ends here */ 0x00, 0x00, 0x00, 0x00, /* 128, PAGE1-0 */ 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */ 0x00, 0x00, 0x00, 0x00, /* 136, PAGE1-8 */ 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */ 0x00, 0x00, 0x00, 0x00, /* 144, PAGE1-16 */ 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */ 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */ 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */ 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */ 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */ 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */ 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */ 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */ 0xFF, 0x00, 0x3F, 0xFF, /* 180, PAGE1-52 */ 0x00, 0x3F, 0x00, 0x80, /* 184, PAGE1-56 */ 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */ 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */ 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */ 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */ 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */ 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */ 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */ 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */ 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */ 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */ 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */ 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */ 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */ 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */ 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */ 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */ 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 */ #endif }; /* *---------------------------------------------------------------------------- * Function : adc31xx_change_page * Purpose : This function is to switch between page 0 and page 1. * *---------------------------------------------------------------------------- */ static int tlv320_change_page(unsigned int device, struct snd_soc_codec *codec, u8 new_page) { struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); u8 data[2]; data[0] = 0x0; data[1] = new_page; if (i2c_master_send(tlv320->adc_control_data[device], data, 2) != 2) { dev_err(codec->dev, "adc31xx_change_page %d: I2C Wrte Error\n", device); return -1; } tlv320->adc_page_no[device] = new_page; return 0; } static inline void tlv320_write_reg_cache(struct snd_soc_codec *codec, u8 device, u8 page, u16 reg, u8 value) { u8 *cache = codec->reg_cache; int offset; offset = device * ADC3101_CACHEREGNUM; if (page == 1) offset += 128; if (offset + reg >= TLV320_CACHEREGNUM) return; dev_dbg(codec->dev, "(%d) wrote %#x to %#x (%d) cache offset %d\n", device, value, reg, reg, offset); cache[offset + reg] = value; } static unsigned int tlv320_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { u8 *cache = codec->reg_cache; u16 device, page, reg_no; int offset; page = (reg & 0x3f800) >> 11; device = (reg & 0x700) >> 8; reg_no = reg & 0x7f; if (page > 1) { dev_warn(codec->dev, "unable to read register: page:%u, reg:%u\n", page, reg_no); return -EINVAL; } offset = device * ADC3101_CACHEREGNUM; if (page == 1) offset += 128; if (offset + reg_no >= TLV320_CACHEREGNUM) { dev_warn(codec->dev, "unable to read register: page:%u, reg:%u\n", page, reg_no); return -EINVAL; } dev_dbg(codec->dev, "(%d) read %#x from %#x (%d) cache offset %d\n", device, cache[offset + reg_no], reg_no, reg_no, offset); return cache[offset + reg_no]; } static int tlv320_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { int ret = 0; u8 data[2]; u16 page; u16 device; unsigned int reg_no; struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); struct i2c_client *i2cdev; if (!tlv320) return -ENODEV; page = (reg & 0x3f800) >> 11; /* bit7 is zero while using MAKE_REG */ /* bit7 is used by soc-cache to store page */ if (reg & 0x80) page = 1; device = (reg & 0x700) >> 8; reg_no = reg & 0x7f; dev_dbg(codec->dev, "AIC Write dev %#x page %d reg %#x val %#x\n", device, page, reg_no, value); i2cdev = tlv320->adc_control_data[device]; if (!i2cdev) return -ENODEV; mutex_lock(&tlv320->codecMutex); if (tlv320->adc_page_no[device] != page) tlv320_change_page(device, codec, page); /* * data is * D15..D8 register offset * D7...D0 register data */ data[0] = reg_no; data[1] = value; if (i2c_master_send(i2cdev, data, 2) != 2) { dev_err(codec->dev, "Error in i2c write in i2c dev: %x\n", device); ret = -EIO; } else if ((page < 2) && !((page == 0) && (reg == 1))) { tlv320_write_reg_cache(codec, device, page, reg_no, value); } mutex_unlock(&tlv320->codecMutex); return ret; } static void tlv320_dmic_cfg(struct snd_soc_codec *codec) { snd_soc_write(codec, ADC_GPIO2_CTRL(0), 0x28); /* reg 51 */ snd_soc_write(codec, ADC_GPIO1_CTRL(0), 0x04); /* reg 52 */ snd_soc_write(codec, ADC_MIC_POLARITY_CTRL(0), 0x01); /* reg 80 */ snd_soc_write(codec, ADC_ADC_DIGITAL(0), 0x0E); /* reg 81 */ snd_soc_write(codec, ADC_ADC_DIGITAL(0), 0xCE); /* reg 81 */ snd_soc_write(codec, ADC_LADC_VOL(0), 0x10); /* reg 83 */ snd_soc_write(codec, ADC_RADC_VOL(0), 0x10); /* reg 84 */ snd_soc_write(codec, ADC_ADC_FGA(0), 0x00); /* reg 82 */ } static void tlv320_PGA_Gain(struct snd_soc_codec *codec) { /*adc analog gain, it will effect the volume after your record*/ struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); #ifdef CONFIG_SND_SOC_4_ADCS int ref_ch = tlv320->ref_ch; #endif switch (tlv320->adc_pos) { case 0: /*ADC0*/ snd_soc_write(codec, ADC_LEFT_APGA_CTRL(0), ADC0_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(0), ADC0_PGA_CH2_GAIN); break; #ifdef CONFIG_SND_SOC_4_ADCS case 1: /*ADC1*/ snd_soc_write(codec, ADC_LEFT_APGA_CTRL(0), ADC0_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(0), ADC0_PGA_CH2_GAIN); snd_soc_write(codec, ADC_LEFT_APGA_CTRL(1), ADC1_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(1), ADC1_PGA_CH2_GAIN); break; case 2: /*ADC2*/ snd_soc_write(codec, ADC_LEFT_APGA_CTRL(0), ADC0_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(0), ADC0_PGA_CH2_GAIN); snd_soc_write(codec, ADC_LEFT_APGA_CTRL(1), ADC1_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(1), ADC1_PGA_CH2_GAIN); snd_soc_write(codec, ADC_LEFT_APGA_CTRL(2), ADC2_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(2), ADC2_PGA_CH2_GAIN); break; case 3: /*ADC3,2ch ref,1ch ref,no ref*/ snd_soc_write(codec, ADC_LEFT_APGA_CTRL(0), ADC0_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(0), ADC0_PGA_CH2_GAIN); snd_soc_write(codec, ADC_LEFT_APGA_CTRL(1), ADC1_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(1), ADC1_PGA_CH2_GAIN); snd_soc_write(codec, ADC_LEFT_APGA_CTRL(2), ADC2_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(2), ADC2_PGA_CH2_GAIN); if (ref_ch == 2) { snd_soc_write(codec, ADC_LEFT_APGA_CTRL(3), ADC3_PGA_CH2_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(3), ADC3_PGA_CH2_GAIN); } else if (ref_ch == 1) { snd_soc_write(codec, ADC_LEFT_APGA_CTRL(3), ADC3_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(3), ADC3_PGA_CH2_GAIN); } else { snd_soc_write(codec, ADC_LEFT_APGA_CTRL(3), ADC3_PGA_CH1_GAIN); snd_soc_write(codec, ADC_RIGHT_APGA_CTRL(3), ADC3_PGA_CH1_GAIN); } break; default: dev_err(codec->dev, "no adc pos found!\n"); break; #endif } } static int tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); u8 data = 65; /*dspmode + dout enable*/ int i; int choffset_1 = 1, choffset_2 = 0, offset = 0; dev_info(codec->dev, "%s: ##Data length: %x\n", __func__, params_format(params)); for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) snd_soc_write(codec, ADC_DOUT_CTRL(i), 16); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: data |= (TLV320_WORD_LEN_16BITS << 4); choffset_2 = 0; offset = 32; break; case SNDRV_PCM_FORMAT_S24_LE: data |= (TLV320_WORD_LEN_24BITS << 4); choffset_2 = 8; offset = 64; break; case SNDRV_PCM_FORMAT_S32_LE: data |= (TLV320_WORD_LEN_32BITS << 4); choffset_2 = 0; offset = 64; break; default: dev_info(codec->dev, "%s: ##- Not support format\n", __func__); break; } for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_INTERFACE_CTRL_1(i), data); snd_soc_write(codec, ADC_INTERFACE_CTRL_2(i), 14); } dev_info(codec->dev, "%s: ##choffset_1: %d,choffset_2: %d,offset: %d,data: %d\n", __func__, choffset_1, choffset_2, offset, data); /* DOUT disable: bus keeper disabled */ for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_ADC_DIGITAL(i), 194); /*LADC/RADC powerUP*/ snd_soc_write(codec, ADC_ADC_FGA(i), 0); snd_soc_write(codec, ADC_LADC_VOL(i), 0); snd_soc_write(codec, ADC_RADC_VOL(i), 0); snd_soc_write(codec, ADC_ADC_PHASE_COMP(i), 0); snd_soc_write(codec, ADC_MICBIAS_CTRL(i), 120); /*MICBIAS Connect AVDD*/ snd_soc_write(codec, ADC_LEFT_PGA_SEL_1(i), 63); snd_soc_write(codec, ADC_LEFT_PGA_SEL_2(i), 63); snd_soc_write(codec, ADC_RIGHT_PGA_SEL_1(i), 63); snd_soc_write(codec, ADC_RIGHT_PGA_SEL_2(i), 63); snd_soc_write(codec, ADC_I2S_TDM_CTRL(i), TIME_SOLT_MODE | EARLY_3STATE_ENABLED); snd_soc_write(codec, ADC_CH_OFFSET_2(i), choffset_2); } for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_CH_OFFSET_1(i), choffset_1); choffset_1 += offset; } /*dmic register configure*/ if (dmic_cfg) { dev_info(codec->dev, " %s dmic config ......\n", __func__); tlv320_dmic_cfg(codec); if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) { dev_info(codec->dev, "%s: ## format: %d\n", __func__, params_format(params)); for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_I2S_TDM_CTRL(i), TIME_SOLT_MODE | EARLY_3STATE_ENABLED); snd_soc_write(codec, ADC_CH_OFFSET_2(i), choffset_2); } } else { for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_I2S_TDM_CTRL(i), 2); /* reg38 */ snd_soc_write(codec, ADC_CH_OFFSET_1(i), 0); /* reg 28 */ } } } /* mandatory delay to allow ADC clocks to synchronize */ mdelay(100); for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) snd_soc_write(codec, ADC_DOUT_CTRL(i), 18); tlv320_PGA_Gain(codec); return 0; } static int tlv320_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = dai->codec; int i = 0, clk_mux; struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); dev_info(codec->dev, " %s+: source=%d\n", __func__, source); switch (source) { case AIC3101_PLL_ADC_FS_CLKIN_MCLK: clk_mux = TLV320_CODEC_CLKIN_MCLK; break; case AIC3101_PLL_ADC_FS_CLKIN_BCLK: clk_mux = TLV320_CODEC_CLKIN_BCLK; break; default: dev_err(codec->dev, "source %d not supported\n", source); return -EINVAL; } /*clk -- mclk*/ for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) snd_soc_write(codec, ADC_CLKGEN_MUX(i), clk_mux); /* reg4 */ for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) { snd_soc_write(codec, ADC_ADC_NADC(i), 129); /* nadc reg18 */ snd_soc_write(codec, ADC_ADC_MADC(i), 130); /* madc reg19 */ snd_soc_write(codec, ADC_ADC_AOSR(i), 128); /* aosr reg20 */ } /* Set the signal processing block (PRB) modes */ for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) snd_soc_write(codec, ADC_PRB_SELECT(i), 1); /* reg61 */ dev_info(codec->dev, " %s-:\n", __func__); return 0; } /* *---------------------------------------------------------------------------- * Function : aic31xx_init * Purpose : This function is to initialise the AIC31xx driver * register the mixer and dsp interfaces with the kernel. * *---------------------------------------------------------------------------- */ static int tlv320_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct tlv320_priv *tlv320 = snd_soc_codec_get_drvdata(codec); int i = 0; for (i = tlv320->adc_pos; i < NUM_ADC3101; i++) snd_soc_write(codec, ADC_RESET(i), 1); return 0; } /* * Codec probe function, called upon codec registration * */ static int tlv320_codec_probe(struct snd_soc_codec *codec) { int ret = 0; struct tlv320_priv *tlv320; tlv320 = snd_soc_codec_get_drvdata(codec); codec->control_data = tlv320->adc_control_data[0]; return ret; } static struct snd_soc_codec_driver soc_codec_driver_tlv320 = { .probe = tlv320_codec_probe, //.controls = tlv320_snd_controls, //.num_controls = ARRAY_SIZE(tlv320_snd_controls), .read = tlv320_read_reg_cache, .write = tlv320_write, .reg_cache_size = ARRAY_SIZE(tlv320_reg), .reg_word_size = sizeof(u8), .reg_cache_default = tlv320_reg, }; static struct snd_soc_dai_ops tlv320_dai_ops = { .startup = tlv320_codec_startup, .hw_params = tlv320_hw_params, .set_pll = tlv320_dai_set_pll, }; static struct snd_soc_dai_driver tlv320aic3101_dai_driver[] = {{ .name = "tlv320aic3101-codec", .capture = { .stream_name = "Capture", .channels_min = 1, #ifdef CONFIG_SND_SOC_4_ADCS .channels_max = 8, #else .channels_max = 2, #endif .rates = TLV320_RATES, .formats = TLV320_FORMATS, }, .ops = &tlv320_dai_ops, } }; static int tlv320_i2c_probe(struct i2c_client *pdev, const struct i2c_device_id *id) { int ret = 0; struct tlv320_priv *tlv320; int reset_gpio; static int adc_pos; int ref_ch; static int i; static struct tlv320_priv *tlv320_global; if (i == 0) { if (of_property_read_u32(pdev->dev.of_node, "ref-ch", &ref_ch)) ref_ch = 1; ref_ch = (ref_ch <= 2) && (ref_ch >= 0) ? ref_ch : 1; if (of_property_read_u32(pdev->dev.of_node, "adc-pos", &adc_pos)) adc_pos = 0; i = adc_pos; } dev_info(&pdev->dev, "TLV320AIC3101 Audio Codec %s (%d), adc_pos:%d,ref_ch:%d\n", TLV320_VERSION, i, adc_pos, ref_ch); if (i == adc_pos) { tlv320 = devm_kzalloc(&pdev->dev, sizeof(struct tlv320_priv), GFP_KERNEL); if (tlv320 == NULL) return -ENOMEM; i2c_set_clientdata(pdev, tlv320); tlv320_global = tlv320; tlv320->adc_pos = adc_pos; tlv320->ref_ch = ref_ch; tlv320->adc_control_data[i] = pdev; mutex_init(&tlv320->codecMutex); ret = snd_soc_register_codec( &pdev->dev, &soc_codec_driver_tlv320, tlv320aic3101_dai_driver, ARRAY_SIZE(tlv320aic3101_dai_driver)); if (ret) dev_err(&pdev->dev, "codec: %s : snd_soc_register_codec failed\n", __func__); reset_gpio = of_get_named_gpio(pdev->dev.of_node, "rst-gpio", 0); if (reset_gpio < 0) { dev_err(&pdev->dev, "Failed to get reset gpio from device tree!\n"); return -EINVAL; } ret = devm_gpio_request_one(&pdev->dev, reset_gpio, 0, "tlv320_reset"); if (ret < 0) { dev_err(&pdev->dev, "Failed to request reset gpio! %d\n", ret); return -EINVAL; } tlv320->reset_gpiod = gpio_to_desc(reset_gpio); /* Reset ADC */ ret = gpiod_direction_output(tlv320->reset_gpiod, 0); if (ret < 0) { dev_err(&pdev->dev, "could not set gpio(%d) to 0 (err=%d)\n", reset_gpio, ret); return -EINVAL; } mdelay(10); ret = gpiod_direction_output(tlv320->reset_gpiod, 1); if (ret < 0) { dev_err(&pdev->dev, "could not set gpio(%d) to 1 (err=%d)\n", reset_gpio, ret); return -EINVAL; } } else { tlv320_global->adc_control_data[i] = pdev; } dev_info(&pdev->dev, "%s: complete (%d)\n", __func__, i); i++; return ret; } static int tlv320_i2c_remove(struct i2c_client *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } static const struct i2c_device_id tlv320_i2c_id[] = {{"tlv320adc3101", 0}, {} }; MODULE_DEVICE_TABLE(i2c, tlv320_i2c_id); static const struct of_device_id tlv3203101_of_match[] = { { .compatible = "ti,tlv320aic3101", }, {} }; MODULE_DEVICE_TABLE(of, tlv3203101_of_match); static struct i2c_driver tlv320_i2c_driver = { .driver = { .name = AUDIO_NAME, .owner = THIS_MODULE, .of_match_table = tlv3203101_of_match, }, .probe = tlv320_i2c_probe, .remove = tlv320_i2c_remove, .id_table = tlv320_i2c_id, }; module_i2c_driver(tlv320_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320 codec driver"); MODULE_LICENSE("GPL");