/* * ac108.c -- ac108 ALSA Soc Audio driver * * Author: panjunwen * * This program 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. * */ #define DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ac108.h" /* test enable config */ #define AC108_DAPM_TEST_EN 0 #define AC108_CODEC_RW_TEST_EN 0 #define AC108_ADC_PATTERN_SEL ADC_PTN_0x123456 #define AC108_NUM_MAX 4 #define AC108_SLOT_WIDTH 32 #define AC108_DMIC_EN 0 /* 0:ADC 1:DMIC */ #define AC108_ENCODING_EN 0 /* TX Encoding mode enable */ #define AC108_REGULATOR_NAME "voltage_enable" #define AC108_RATES (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_KNOT) #define AC108_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) struct i2c_client *i2c_clt[AC108_NUM_MAX]; int regulator_en; unsigned int ac108_bclk_div_val; struct ac108_public_config ac108_pub_cfg; EXPORT_SYMBOL(ac108_pub_cfg); struct ac108_priv { struct i2c_client *i2c; struct snd_soc_codec *codec; }; static const struct regmap_config ac108_regmap_config = { .reg_bits = 8, /* Number of bits in a register address */ .val_bits = 8, /* Number of bits in a register value */ }; struct real_val_to_reg_val { unsigned int real_val; unsigned int reg_val; }; struct pll_div { unsigned int freq_in; unsigned int freq_out; unsigned int m1; unsigned int m2; unsigned int n; unsigned int k1; unsigned int k2; }; static const struct real_val_to_reg_val ac108_sample_rate[] = { {8000, 0}, {11025, 1}, {12000, 2}, {16000, 3}, {22050, 4}, {24000, 5}, {32000, 6}, {44100, 7}, {48000, 8}, {96000, 9}, }; static const struct real_val_to_reg_val ac108_sample_resolution[] = { {8, 1}, {12, 2}, {16, 3}, {20, 4}, {24, 5}, {28, 6}, {32, 7}, }; static const struct real_val_to_reg_val ac108_bclk_div[] = { {0, 0}, {1, 1}, {2, 2}, {4, 3}, {6, 4}, {8, 5}, {12, 6}, {16, 7}, {24, 8}, {32, 9}, {48, 10}, {64, 11}, {96, 12}, {128, 13}, {176, 14}, {192, 15}, }; /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] ; * M1[0,31], M2[0,1], N[0,1023], K1[0,31], K2[0,1] */ static const struct pll_div ac108_pll_div[] = { /**/ {400000, 24576000, 0, 0, 983, 7, 1}, /*24576000/48*/ {512000, 24576000, 0, 0, 960, 9, 1}, /*24576000/32*/ {768000, 24576000, 0, 0, 640, 9, 1}, {800000, 24576000, 0, 0, 768, 24, 0}, /*24576000/24*/ {1024000, 24576000, 0, 0, 480, 9, 1}, {1600000, 24576000, 0, 0, 384, 24, 0}, /*24576000/12*/ {2048000, 24576000, 0, 0, 240, 9, 1}, /*24576000/8*/ {3072000, 24576000, 0, 0, 160, 9, 1}, /*24576000/6*/ {4096000, 24576000, 0, 0, 120, 9, 1}, {6000000, 24576000, 4, 0, 512, 24, 0}, {12000000, 24576000, 9, 0, 512, 24, 0}, /**/ {13000000, 24576000, 12, 0, 639, 12, 1}, {15360000, 24576000, 9, 0, 320, 9, 1}, {16000000, 24576000, 9, 0, 384, 24, 0}, {19200000, 24576000, 11, 0, 384, 24, 0}, /**/ {19680000, 24576000, 15, 1, 999, 24, 0}, {24000000, 24576000, 9, 0, 256, 24, 0}, {400000, 22579200, 0, 0, 1016, 8, 1}, {512000, 22579200, 0, 0, 882, 9, 1}, {768000, 22579200, 0, 0, 588, 9, 1}, /**/ {800000, 22579200, 0, 0, 508, 8, 1}, {1024000, 22579200, 0, 0, 441, 9, 1}, /**/ {1600000, 22579200, 0, 0, 254, 8, 1}, {2048000, 22579200, 1, 0, 441, 9, 1}, {3072000, 22579200, 2, 0, 441, 9, 1}, {4096000, 22579200, 3, 0, 441, 9, 1}, /**/ {6000000, 22579200, 5, 0, 429, 18, 0}, /**/ {12000000, 22579200, 11, 0, 429, 18, 0}, /**/ {13000000, 22579200, 12, 0, 429, 18, 0}, {15360000, 22579200, 14, 0, 441, 9, 1}, {16000000, 22579200, 24, 0, 882, 24, 0}, {19200000, 22579200, 4, 0, 147, 24, 0}, /**/ {19680000, 22579200, 13, 1, 771, 23, 0}, {24000000, 22579200, 24, 0, 588, 24, 0}, {12288000, 24576000, 9, 0, 400, 9, 1}, /* 24576000/2 */ {11289600, 22579200, 9, 0, 400, 9, 1}, /* g22579200/2 */ {24576000 / 1, 24576000, 9, 0, 200, 9, 1}, /* 24576000 */ {24576000 / 4, 24576000, 4, 0, 400, 9, 1}, /* 6144000 */ {24576000 / 16, 24576000, 0, 0, 320, 9, 1}, /* 1536000 */ {24576000 / 64, 24576000, 0, 0, 640, 4, 1}, /* 384000 */ {24576000 / 96, 24576000, 0, 0, 960, 4, 1}, /* 256000 */ {24576000 / 128, 24576000, 0, 0, 512, 1, 1}, /* 192000 */ {24576000 / 176, 24576000, 0, 0, 880, 4, 0}, /* 140000 */ {24576000 / 192, 24576000, 0, 0, 960, 4, 0}, /* 128000 */ {22579200 / 1, 22579200, 9, 0, 200, 9, 1}, /* 22579200 */ {22579200 / 4, 22579200, 4, 0, 400, 9, 1}, /* 5644800 */ {22579200 / 16, 22579200, 0, 0, 320, 9, 1}, /* 1411200 */ {22579200 / 64, 22579200, 0, 0, 640, 4, 1}, /* 352800 */ {22579200 / 96, 22579200, 0, 0, 960, 4, 1}, /* 235200 */ {22579200 / 128, 22579200, 0, 0, 512, 1, 1}, /* 176400 */ {22579200 / 176, 22579200, 0, 0, 880, 4, 0}, /* 128290 */ {22579200 / 192, 22579200, 0, 0, 960, 4, 0}, /* 117600 */ {22579200 / 6, 22579200, 2, 0, 360, 9, 1}, /* 3763200 */ {22579200 / 8, 22579200, 0, 0, 160, 9, 1}, /* 2822400 */ {22579200 / 12, 22579200, 0, 0, 240, 9, 1}, /* 1881600 */ {22579200 / 24, 22579200, 0, 0, 480, 9, 1}, /* 940800 */ {22579200 / 32, 22579200, 0, 0, 640, 9, 1}, /* 705600 */ {22579200 / 48, 22579200, 0, 0, 960, 9, 1}, /* 470400 */ }; static const DECLARE_TLV_DB_SCALE(adc1_pga_gain_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(adc2_pga_gain_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(adc3_pga_gain_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(adc4_pga_gain_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(ch1_digital_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(ch2_digital_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(ch3_digital_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(ch4_digital_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(channel1_ch1_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel1_ch2_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel1_ch3_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel1_ch4_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel2_ch1_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel2_ch2_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel2_ch3_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel2_ch4_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel3_ch1_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel3_ch2_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel3_ch3_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel3_ch4_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel4_ch1_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel4_ch2_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel4_ch3_dig_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(channel4_ch4_dig_mix_vol_tlv, -600, 600, 0); /* static const DECLARE_TLV_DB_SCALE(adc_pga_gain_tlv,0,100,0); */ /* static const DECLARE_TLV_DB_SCALE(digital_vol_tlv,-11925,75,0); */ /* static const DECLARE_TLV_DB_SCALE(digital_mix_vol_tlv,-600,600,0); */ /************* General(volume) controls ************/ /* ac108 common controls */ static const struct snd_kcontrol_new ac108_controls[] = { SOC_SINGLE_TLV("ADC1 PGA gain", ANA_PGA1_CTRL, ADC1_ANALOG_PGA, 0x1f, 0, adc1_pga_gain_tlv), SOC_SINGLE_TLV("ADC2 PGA gain", ANA_PGA2_CTRL, ADC2_ANALOG_PGA, 0x1f, 0, adc2_pga_gain_tlv), SOC_SINGLE_TLV("ADC3 PGA gain", ANA_PGA3_CTRL, ADC3_ANALOG_PGA, 0x1f, 0, adc3_pga_gain_tlv), SOC_SINGLE_TLV("ADC4 PGA gain", ANA_PGA4_CTRL, ADC4_ANALOG_PGA, 0x1f, 0, adc4_pga_gain_tlv), SOC_SINGLE_TLV("CH1 digital volume", ADC1_DVOL_CTRL, 0, 0xff, 0, ch1_digital_vol_tlv), SOC_SINGLE_TLV("CH2 digital volume", ADC2_DVOL_CTRL, 0, 0xff, 0, ch2_digital_vol_tlv), SOC_SINGLE_TLV("CH3 digital volume", ADC3_DVOL_CTRL, 0, 0xff, 0, ch3_digital_vol_tlv), SOC_SINGLE_TLV("CH4 digital volume", ADC4_DVOL_CTRL, 0, 0xff, 0, ch4_digital_vol_tlv), SOC_SINGLE_TLV("CH1 ch1 mixer gain", ADC1_DMIX_SRC, ADC1_ADC1_DMXL_GC, 1, 0, channel1_ch1_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH1 ch2 mixer gain", ADC1_DMIX_SRC, ADC1_ADC2_DMXL_GC, 1, 0, channel1_ch2_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH1 ch3 mixer gain", ADC1_DMIX_SRC, ADC1_ADC3_DMXL_GC, 1, 0, channel1_ch3_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH1 ch4 mixer gain", ADC1_DMIX_SRC, ADC1_ADC4_DMXL_GC, 1, 0, channel1_ch4_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH2 ch1 mixer gain", ADC2_DMIX_SRC, ADC2_ADC1_DMXL_GC, 1, 0, channel2_ch1_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH2 ch2 mixer gain", ADC2_DMIX_SRC, ADC2_ADC2_DMXL_GC, 1, 0, channel2_ch2_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH2 ch3 mixer gain", ADC2_DMIX_SRC, ADC2_ADC3_DMXL_GC, 1, 0, channel2_ch3_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH2 ch4 mixer gain", ADC2_DMIX_SRC, ADC2_ADC4_DMXL_GC, 1, 0, channel2_ch4_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH3 ch1 mixer gain", ADC3_DMIX_SRC, ADC3_ADC1_DMXL_GC, 1, 0, channel3_ch1_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH3 ch2 mixer gain", ADC3_DMIX_SRC, ADC3_ADC2_DMXL_GC, 1, 0, channel3_ch2_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH3 ch3 mixer gain", ADC3_DMIX_SRC, ADC3_ADC3_DMXL_GC, 1, 0, channel3_ch3_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH3 ch4 mixer gain", ADC3_DMIX_SRC, ADC3_ADC4_DMXL_GC, 1, 0, channel3_ch4_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH4 ch1 mixer gain", ADC4_DMIX_SRC, ADC4_ADC1_DMXL_GC, 1, 0, channel4_ch1_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH4 ch2 mixer gain", ADC4_DMIX_SRC, ADC4_ADC2_DMXL_GC, 1, 0, channel4_ch2_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH4 ch3 mixer gain", ADC4_DMIX_SRC, ADC4_ADC3_DMXL_GC, 1, 0, channel4_ch3_dig_mix_vol_tlv), SOC_SINGLE_TLV("CH4 ch4 mixer gain", ADC4_DMIX_SRC, ADC4_ADC4_DMXL_GC, 1, 0, channel4_ch4_dig_mix_vol_tlv), /* SOC_SINGLE_TLV("CH1 mixer gain", ADC1_DMIX_SRC, */ /* ADC1_ADC1_DMXL_GC, 0x0f, 0, digital_mix_vol_tlv), */ /* SOC_SINGLE_TLV("CH2 mixer gain", ADC2_DMIX_SRC, */ /* ADC2_ADC1_DMXL_GC, 0x0f, 0, digital_mix_vol_tlv), */ /* SOC_SINGLE_TLV("CH3 mixer gain", ADC3_DMIX_SRC, */ /* ADC3_ADC1_DMXL_GC, 0x0f, 0, digital_mix_vol_tlv), */ /* SOC_SINGLE_TLV("CH4 mixer gain", ADC4_DMIX_SRC, */ /* ADC4_ADC1_DMXL_GC, 0x0f, 0, digital_mix_vol_tlv), */ }; /**************************** DAPM controls ************************/ /* ADC12 DMIC1 Source Select Mux */ static const char * const adc12_dmic1_src_mux_text[] = { "ADC12 switch", "DMIC1 switch" }; static const struct soc_enum adc12_dmic1_src_mux_enum = SOC_ENUM_SINGLE(DMIC_EN, DMIC1_EN, 2, adc12_dmic1_src_mux_text); static const struct snd_kcontrol_new adc12_dmic1_src_mux = SOC_DAPM_ENUM("ADC12 DMIC1 MUX", adc12_dmic1_src_mux_enum); /* ADC34 DMIC2 Source Select Mux */ static const char * const const adc34_dmic2_src_mux_text[] = { "ADC34 switch", "DMIC2 switch" }; static const struct soc_enum adc34_dmic2_src_mux_enum = SOC_ENUM_SINGLE(DMIC_EN, DMIC2_EN, 2, adc34_dmic2_src_mux_text); static const struct snd_kcontrol_new adc34_dmic2_src_mux = SOC_DAPM_ENUM("ADC34 DMIC2 MUX", adc34_dmic2_src_mux_enum); /* ADC1 Digital Source Select Mux */ static const char * const adc1_digital_src_mux_text[] = { "ADC1 switch", "ADC2 switch", "ADC3 switch", "ADC4 switch" }; static const struct soc_enum adc1_digital_src_mux_enum = SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC1_SRS, 4, adc1_digital_src_mux_text); static const struct snd_kcontrol_new adc1_digital_src_mux = SOC_DAPM_ENUM("ADC1 DIG MUX", adc1_digital_src_mux_enum); /* ADC2 Digital Source Select Mux */ static const char * const adc2_digital_src_mux_text[] = { "ADC1 switch", "ADC2 switch", "ADC3 switch", "ADC4 switch" }; static const struct soc_enum adc2_digital_src_mux_enum = SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC2_SRS, 4, adc2_digital_src_mux_text); static const struct snd_kcontrol_new adc2_digital_src_mux = SOC_DAPM_ENUM("ADC2 DIG MUX", adc2_digital_src_mux_enum); /* ADC3 Digital Source Select Mux */ static const char * const adc3_digital_src_mux_text[] = { "ADC1 switch", "ADC2 switch", "ADC3 switch", "ADC4 switch" }; static const struct soc_enum adc3_digital_src_mux_enum = SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC3_SRS, 4, adc3_digital_src_mux_text); static const struct snd_kcontrol_new adc3_digital_src_mux = SOC_DAPM_ENUM("ADC3 DIG MUX", adc3_digital_src_mux_enum); /* ADC4 Digital Source Select Mux */ static const char * const adc4_digital_src_mux_text[] = { "ADC1 switch", "ADC2 switch", "ADC3 switch", "ADC4 switch" }; static const struct soc_enum adc4_digital_src_mux_enum = SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC4_SRS, 4, adc4_digital_src_mux_text); static const struct snd_kcontrol_new adc4_digital_src_mux = SOC_DAPM_ENUM("ADC4 DIG MUX", adc4_digital_src_mux_enum); /* ADC1 Digital Source Control Mixer */ static const struct snd_kcontrol_new adc1_digital_src_mixer[] = { SOC_DAPM_SINGLE("ADC1 DAT switch", ADC1_DMIX_SRC, ADC1_ADC1_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC2 DAT switch", ADC1_DMIX_SRC, ADC1_ADC2_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC3 DAT switch", ADC1_DMIX_SRC, ADC1_ADC3_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC4 DAT switch", ADC1_DMIX_SRC, ADC1_ADC4_DMXL_SRC, 1, 0), }; /* ADC2 Digital Source Control Mixer */ static const struct snd_kcontrol_new adc2_digital_src_mixer[] = { SOC_DAPM_SINGLE("ADC1 DAT switch", ADC2_DMIX_SRC, ADC2_ADC1_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC2 DAT switch", ADC2_DMIX_SRC, ADC2_ADC2_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC3 DAT switch", ADC2_DMIX_SRC, ADC2_ADC3_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC4 DAT switch", ADC2_DMIX_SRC, ADC2_ADC4_DMXL_SRC, 1, 0), }; /* ADC3 Digital Source Control Mixer */ static const struct snd_kcontrol_new adc3_digital_src_mixer[] = { SOC_DAPM_SINGLE("ADC1 DAT switch", ADC3_DMIX_SRC, ADC3_ADC1_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC2 DAT switch", ADC3_DMIX_SRC, ADC3_ADC2_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC3 DAT switch", ADC3_DMIX_SRC, ADC3_ADC3_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC4 DAT switch", ADC3_DMIX_SRC, ADC3_ADC4_DMXL_SRC, 1, 0), }; /* ADC4 Digital Source Control Mixer */ static const struct snd_kcontrol_new adc4_digital_src_mixer[] = { SOC_DAPM_SINGLE("ADC1 DAT switch", ADC4_DMIX_SRC, ADC4_ADC1_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC2 DAT switch", ADC4_DMIX_SRC, ADC4_ADC2_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC3 DAT switch", ADC4_DMIX_SRC, ADC4_ADC3_DMXL_SRC, 1, 0), SOC_DAPM_SINGLE("ADC4 DAT switch", ADC4_DMIX_SRC, ADC4_ADC4_DMXL_SRC, 1, 0), }; /* I2S TX1 Ch1 Mapping Mux */ static const char * const i2s_tx1_ch1_map_mux_text[] = { "ADC1 Sample switch", "ADC2 Sample switch", "ADC3 Sample switch", "ADC4 Sample switch" }; static const struct soc_enum i2s_tx1_ch1_map_mux_enum = SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH1_MAP, 4, i2s_tx1_ch1_map_mux_text); static const struct snd_kcontrol_new i2s_tx1_ch1_map_mux = SOC_DAPM_ENUM("I2S TX1 CH1 MUX", i2s_tx1_ch1_map_mux_enum); /* I2S TX1 Ch2 Mapping Mux */ static const char * const i2s_tx1_ch2_map_mux_text[] = { "ADC1 Sample switch", "ADC2 Sample switch", "ADC3 Sample switch", "ADC4 Sample switch" }; static const struct soc_enum i2s_tx1_ch2_map_mux_enum = SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH2_MAP, 4, i2s_tx1_ch2_map_mux_text); static const struct snd_kcontrol_new i2s_tx1_ch2_map_mux = SOC_DAPM_ENUM("I2S TX1 CH2 MUX", i2s_tx1_ch2_map_mux_enum); /* I2S TX1 Ch3 Mapping Mux */ static const char * const i2s_tx1_ch3_map_mux_text[] = { "ADC1 Sample switch", "ADC2 Sample switch", "ADC3 Sample switch", "ADC4 Sample switch" }; static const struct soc_enum i2s_tx1_ch3_map_mux_enum = SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH3_MAP, 4, i2s_tx1_ch3_map_mux_text); static const struct snd_kcontrol_new i2s_tx1_ch3_map_mux = SOC_DAPM_ENUM("I2S TX1 CH3 MUX", i2s_tx1_ch3_map_mux_enum); /* I2S TX1 Ch4 Mapping Mux */ static const char * const i2s_tx1_ch4_map_mux_text[] = { "ADC1 Sample switch", "ADC2 Sample switch", "ADC3 Sample switch", "ADC4 Sample switch" }; static const struct soc_enum i2s_tx1_ch4_map_mux_enum = SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH4_MAP, 4, i2s_tx1_ch4_map_mux_text); static const struct snd_kcontrol_new i2s_tx1_ch4_map_mux = SOC_DAPM_ENUM("I2S TX1 CH4 MUX", i2s_tx1_ch4_map_mux_enum); /******************* DAPM widgets *******************************************/ /* ac108 dapm widgets */ static const struct snd_soc_dapm_widget ac108_dapm_widgets[] = { /* input widgets */ SND_SOC_DAPM_INPUT("MIC1P"), SND_SOC_DAPM_INPUT("MIC1N"), SND_SOC_DAPM_INPUT("MIC2P"), SND_SOC_DAPM_INPUT("MIC2N"), SND_SOC_DAPM_INPUT("MIC3P"), SND_SOC_DAPM_INPUT("MIC3N"), SND_SOC_DAPM_INPUT("MIC4P"), SND_SOC_DAPM_INPUT("MIC4N"), SND_SOC_DAPM_INPUT("DMIC1"), SND_SOC_DAPM_INPUT("DMIC2"), /* MIC PGA */ SND_SOC_DAPM_PGA("MIC1 PGA", ANA_ADC1_CTRL1, ADC1_PGA_ENABLE, 0, NULL, 0), SND_SOC_DAPM_PGA("MIC2 PGA", ANA_ADC2_CTRL1, ADC2_PGA_ENABLE, 0, NULL, 0), SND_SOC_DAPM_PGA("MIC3 PGA", ANA_ADC3_CTRL1, ADC3_PGA_ENABLE, 0, NULL, 0), SND_SOC_DAPM_PGA("MIC4 PGA", ANA_ADC4_CTRL1, ADC4_PGA_ENABLE, 0, NULL, 0), /* DMIC PGA */ SND_SOC_DAPM_PGA("DMIC1L PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("DMIC1R PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("DMIC2L PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("DMIC2R PGA", SND_SOC_NOPM, 0, 0, NULL, 0), /* ADC1 DIG MUX */ SND_SOC_DAPM_MUX("ADC1 DIG MUX", ADC_DIG_EN, ENAD1, 0, &adc1_digital_src_mux), /* ADC2 DIG MUX */ SND_SOC_DAPM_MUX("ADC2 DIG MUX", ADC_DIG_EN, ENAD2, 0, &adc2_digital_src_mux), /* ADC3 DIG MUX */ SND_SOC_DAPM_MUX("ADC3 DIG MUX", ADC_DIG_EN, ENAD3, 0, &adc3_digital_src_mux), /* ADC4 DIG MUX */ SND_SOC_DAPM_MUX("ADC4 DIG MUX", ADC_DIG_EN, ENAD4, 0, &adc4_digital_src_mux), /* ADC12 DMIC1 MUX */ SND_SOC_DAPM_MUX("ADC12 DMIC1 MUX", SND_SOC_NOPM, 0, 0, &adc12_dmic1_src_mux), /* ADC34 DMIC2 MUX */ SND_SOC_DAPM_MUX("ADC34 DMIC2 MUX", SND_SOC_NOPM, 0, 0, &adc34_dmic2_src_mux), /* ADC1 VIR PGA */ SND_SOC_DAPM_PGA("ADC1 VIR PGA", ANA_ADC1_CTRL1, ADC1_DSM_ENABLE, 0, NULL, 0), /* ADC2 VIR PGA */ SND_SOC_DAPM_PGA("ADC2 VIR PGA", ANA_ADC2_CTRL1, ADC2_DSM_ENABLE, 0, NULL, 0), /* ADC3 VIR PGA */ SND_SOC_DAPM_PGA("ADC3 VIR PGA", ANA_ADC3_CTRL1, ADC3_DSM_ENABLE, 0, NULL, 0), /* ADC4 VIR PGA */ SND_SOC_DAPM_PGA("ADC4 VIR PGA", ANA_ADC4_CTRL1, ADC4_DSM_ENABLE, 0, NULL, 0), /* ADC1 DIG MIXER */ SND_SOC_DAPM_MIXER("ADC1 DIG MIXER", SND_SOC_NOPM, 0, 0, adc1_digital_src_mixer, ARRAY_SIZE(adc1_digital_src_mixer)), /* ADC2 DIG MIXER */ SND_SOC_DAPM_MIXER("ADC2 DIG MIXER", SND_SOC_NOPM, 0, 0, adc2_digital_src_mixer, ARRAY_SIZE(adc2_digital_src_mixer)), /* ADC3 DIG MIXER */ SND_SOC_DAPM_MIXER("ADC3 DIG MIXER", SND_SOC_NOPM, 0, 0, adc3_digital_src_mixer, ARRAY_SIZE(adc3_digital_src_mixer)), /* ADC4 DIG MIXER */ SND_SOC_DAPM_MIXER("ADC4 DIG MIXER", SND_SOC_NOPM, 0, 0, adc4_digital_src_mixer, ARRAY_SIZE(adc4_digital_src_mixer)), /* I2S TX1 CH1 MUX */ SND_SOC_DAPM_MUX("I2S TX1 CH1 MUX", SND_SOC_NOPM, 0, 0, &i2s_tx1_ch1_map_mux), /* I2S TX1 CH2 MUX */ SND_SOC_DAPM_MUX("I2S TX1 CH2 MUX", SND_SOC_NOPM, 0, 0, &i2s_tx1_ch2_map_mux), /* I2S TX1 CH3 MUX */ SND_SOC_DAPM_MUX("I2S TX1 CH3 MUX", SND_SOC_NOPM, 0, 0, &i2s_tx1_ch3_map_mux), /* I2S TX1 CH4 MUX */ SND_SOC_DAPM_MUX("I2S TX1 CH4 MUX", SND_SOC_NOPM, 0, 0, &i2s_tx1_ch4_map_mux), /* AIF OUT -> (stream widget, stname must be same with codec \ * dai_driver stream_name, which will be used to build dai widget) */ SND_SOC_DAPM_AIF_OUT("AIF ADC OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), }; /***************** DAPM routes *******************************************/ /* ac108 dapm routes */ static const struct snd_soc_dapm_route ac108_dapm_routes[] = { /* MIC */ {"MIC1 PGA", NULL, "MIC1P"}, {"MIC1 PGA", NULL, "MIC1N"}, {"MIC2 PGA", NULL, "MIC2P"}, {"MIC2 PGA", NULL, "MIC2N"}, {"MIC3 PGA", NULL, "MIC3P"}, {"MIC3 PGA", NULL, "MIC3N"}, {"MIC4 PGA", NULL, "MIC4P"}, {"MIC4 PGA", NULL, "MIC4N"}, /* DMIC */ {"DMIC1L PGA", NULL, "DMIC1"}, {"DMIC1R PGA", NULL, "DMIC1"}, {"DMIC2L PGA", NULL, "DMIC2"}, {"DMIC2R PGA", NULL, "DMIC2"}, /* ADC1 DIG MUX */ {"ADC1 DIG MUX", "ADC1 switch", "MIC1 PGA"}, {"ADC1 DIG MUX", "ADC2 switch", "MIC2 PGA"}, {"ADC1 DIG MUX", "ADC3 switch", "MIC3 PGA"}, {"ADC1 DIG MUX", "ADC4 switch", "MIC4 PGA"}, /* ADC2 DIG MUX */ {"ADC2 DIG MUX", "ADC1 switch", "MIC1 PGA"}, {"ADC2 DIG MUX", "ADC2 switch", "MIC2 PGA"}, {"ADC2 DIG MUX", "ADC3 switch", "MIC3 PGA"}, {"ADC2 DIG MUX", "ADC4 switch", "MIC4 PGA"}, /* ADC3 DIG MUX */ {"ADC3 DIG MUX", "ADC1 switch", "MIC1 PGA"}, {"ADC3 DIG MUX", "ADC2 switch", "MIC2 PGA"}, {"ADC3 DIG MUX", "ADC3 switch", "MIC3 PGA"}, {"ADC3 DIG MUX", "ADC4 switch", "MIC4 PGA"}, /* ADC4 DIG MUX */ {"ADC4 DIG MUX", "ADC1 switch", "MIC1 PGA"}, {"ADC4 DIG MUX", "ADC2 switch", "MIC2 PGA"}, {"ADC4 DIG MUX", "ADC3 switch", "MIC3 PGA"}, {"ADC4 DIG MUX", "ADC4 switch", "MIC4 PGA"}, /* ADC12 DMIC1 MUX */ {"ADC12 DMIC1 MUX", "ADC12 switch", "ADC1 DIG MUX"}, {"ADC12 DMIC1 MUX", "ADC12 switch", "ADC2 DIG MUX"}, {"ADC12 DMIC1 MUX", "DMIC1 switch", "DMIC1L PGA"}, {"ADC12 DMIC1 MUX", "DMIC1 switch", "DMIC1R PGA"}, /* ADC34 DMIC2 MUX */ {"ADC34 DMIC2 MUX", "ADC34 switch", "ADC3 DIG MUX"}, {"ADC34 DMIC2 MUX", "ADC34 switch", "ADC4 DIG MUX"}, {"ADC34 DMIC2 MUX", "DMIC2 switch", "DMIC2L PGA"}, {"ADC34 DMIC2 MUX", "DMIC2 switch", "DMIC2R PGA"}, /* ADC1 VIR PGA */ {"ADC1 VIR PGA", NULL, "ADC12 DMIC1 MUX"}, /* ADC2 VIR PGA */ {"ADC2 VIR PGA", NULL, "ADC12 DMIC1 MUX"}, /* ADC3 VIR PGA */ {"ADC3 VIR PGA", NULL, "ADC34 DMIC2 MUX"}, /* ADC4 VIR PGA */ {"ADC4 VIR PGA", NULL, "ADC34 DMIC2 MUX"}, /* ADC1 DIG MIXER */ {"ADC1 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, {"ADC1 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, {"ADC1 DIG MIXER", "ADC3 DAT switch", "ADC3 VIR PGA"}, {"ADC1 DIG MIXER", "ADC4 DAT switch", "ADC4 VIR PGA"}, /* ADC2 DIG MIXER */ {"ADC2 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, {"ADC2 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, {"ADC2 DIG MIXER", "ADC3 DAT switch", "ADC3 VIR PGA"}, {"ADC2 DIG MIXER", "ADC4 DAT switch", "ADC4 VIR PGA"}, /* ADC3 DIG MIXER */ {"ADC3 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, {"ADC3 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, {"ADC3 DIG MIXER", "ADC3 DAT switch", "ADC3 VIR PGA"}, {"ADC3 DIG MIXER", "ADC4 DAT switch", "ADC4 VIR PGA"}, /* ADC4 DIG MIXER */ {"ADC4 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, {"ADC4 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, {"ADC4 DIG MIXER", "ADC3 DAT switch", "ADC3 VIR PGA"}, {"ADC4 DIG MIXER", "ADC4 DAT switch", "ADC4 VIR PGA"}, /* I2S TX1 CH1 MUX */ {"I2S TX1 CH1 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, {"I2S TX1 CH1 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, {"I2S TX1 CH1 MUX", "ADC3 Sample switch", "ADC3 DIG MIXER"}, {"I2S TX1 CH1 MUX", "ADC4 Sample switch", "ADC4 DIG MIXER"}, /* I2S TX1 CH2 MUX */ {"I2S TX1 CH2 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, {"I2S TX1 CH2 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, {"I2S TX1 CH2 MUX", "ADC3 Sample switch", "ADC3 DIG MIXER"}, {"I2S TX1 CH2 MUX", "ADC4 Sample switch", "ADC4 DIG MIXER"}, /* I2S TX1 CH3 MUX */ {"I2S TX1 CH3 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, {"I2S TX1 CH3 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, {"I2S TX1 CH3 MUX", "ADC3 Sample switch", "ADC3 DIG MIXER"}, {"I2S TX1 CH3 MUX", "ADC4 Sample switch", "ADC4 DIG MIXER"}, /* I2S TX1 CH4 MUX */ {"I2S TX1 CH4 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, {"I2S TX1 CH4 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, {"I2S TX1 CH4 MUX", "ADC3 Sample switch", "ADC3 DIG MIXER"}, {"I2S TX1 CH4 MUX", "ADC4 Sample switch", "ADC4 DIG MIXER"}, /* AIF OUT */ {"AIF ADC OUT", NULL, "I2S TX1 CH1 MUX"}, {"AIF ADC OUT", NULL, "I2S TX1 CH2 MUX"}, {"AIF ADC OUT", NULL, "I2S TX1 CH3 MUX"}, {"AIF ADC OUT", NULL, "I2S TX1 CH4 MUX"}, }; static int ac108_read(u8 reg, u8 *rt_value, struct i2c_client *client) { int ret; u8 read_cmd[3] = { 0 }; u8 cmd_len = 0; read_cmd[0] = reg; cmd_len = 1; if (client->adapter == NULL) pr_err("ac108_read client->adapter==NULL\n"); ret = i2c_master_send(client, read_cmd, cmd_len); if (ret != cmd_len) { pr_err("ac108_read error1\n"); return -1; } ret = i2c_master_recv(client, rt_value, 1); if (ret != 1) { pr_err("ac108_read error2, ret = %d.\n", ret); return -1; } return 0; } static int ac108_write(u8 reg, unsigned char value, struct i2c_client *client) { int ret = 0; u8 write_cmd[2] = { 0 }; write_cmd[0] = reg; write_cmd[1] = value; ret = i2c_master_send(client, write_cmd, 2); if (ret != 2) { pr_err("ac108_write error->[REG-0x%02x,val-0x%02x]\n", reg, value); return -1; } return 0; } static int ac108_update_bits(u8 reg, u8 mask, u8 value, struct i2c_client *client) { u8 val_old, val_new; ac108_read(reg, &val_old, client); val_new = (val_old & ~mask) | (value & mask); if (val_new != val_old) ac108_write(reg, val_new, client); return 0; } static int ac108_multi_chips_read(u8 reg, unsigned char *rt_value) { u8 i; for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) ac108_read(reg, rt_value++, i2c_clt[i]); return 0; } static int ac108_multi_chips_write(u8 reg, unsigned char value) { u8 i; for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) ac108_write(reg, value, i2c_clt[i]); return 0; } static int ac108_multi_chips_update_bits(u8 reg, u8 mask, u8 value) { u8 i; for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) ac108_update_bits(reg, mask, value, i2c_clt[i]); return 0; } static void ac108_set_vol(struct i2c_client *i2c) { u32 i; for (i = 0; i < 4; i++) { /*set the gain for referenced channels, always used for aec*/ if ((ac108_pub_cfg.ref_chip_addr == i2c->addr) && (ac108_pub_cfg.ref_channel_num == i)) { ac108_write(ANA_PGA1_CTRL + i, ac108_pub_cfg.ref_pga_gain, i2c); /*if two referenced channel used, eg. spk+, spk-*/ if (ac108_pub_cfg.pa_double_used == 1) { i++; ac108_write(ANA_PGA1_CTRL + i, ac108_pub_cfg.ref_pga_gain, i2c); } } else { ac108_write(ANA_PGA1_CTRL + i, ac108_pub_cfg.pga_gain, i2c); } } } static void ac108_hw_init(struct i2c_client *i2c) { /*** Chip reset ***/ /* ac108_write(CHIP_AUDIO_RST, 0x12, i2c); * 0x00=0x12: resets all register to their default state */ #if !AC108_DMIC_EN /*** Analog voltage enable ***/ ac108_write(PWR_CTRL6, 0x01, i2c);/*0x06=0x01: Enable Analog LDO */ ac108_write(PWR_CTRL7, 0x9b, i2c); /*0x07=0x9b: VREF faststart Enable, Enable VREF @ 3.4V (5V) or * 3.1V (3.3V) (needed for Analog LDO and MICBIAS) */ ac108_write(PWR_CTRL9, 0x81, i2c); /*0x09=0x81: VREFP faststart Enable, Enable VREFP * (needed by all audio input channels) */ ac108_write(ANA_ADC3_CTRL7, 0x03, i2c); #endif /*** SYSCLK Config ***/ ac108_write(MOD_CLK_EN, 0x93, i2c); /*0x21=0x93: Module clock enable */ ac108_write(MOD_RST_CTRL, 0x93, i2c); /*0x22=0x93: Module reset de-asserted */ /*** I2S Common Config ***/ ac108_update_bits(I2S_CTRL, 0x1 << SDO1_EN | 0x1 << GEN, 0x1 << SDO1_EN | 0x1 << GEN, i2c); /*SDO1 enable, Globe Enable */ ac108_update_bits(I2S_BCLK_CTRL, 0x1 << EDGE_TRANSFER, 0x0 << EDGE_TRANSFER, i2c); /*SDO drive data and SDI sample data at the different BCLK edge */ ac108_update_bits(I2S_LRCK_CTRL1, 0x3 << LRCK_PERIODH, (((ac108_pub_cfg.ac108_nums * ac108_pub_cfg.slot_width) * 2 - 1) >> 8) << LRCK_PERIODH, i2c); ac108_write(I2S_LRCK_CTRL2, ((ac108_pub_cfg.ac108_nums * ac108_pub_cfg.slot_width) * 2 - 1), i2c); /*config LRCK period: 16bit * 8ch = 128, * 32bit * 8ch = 256, 32bit *16ch =512 */ ac108_update_bits(I2S_FMT_CTRL1, 0x1 << ENCD_SEL | 0x1 << TX_SLOT_HIZ | 0x1 << TX_STATE, !!AC108_ENCODING_EN << ENCD_SEL | 0x0 << TX_SLOT_HIZ | 0x1 << TX_STATE, i2c); ac108_update_bits(I2S_FMT_CTRL2, 0x7 << SLOT_WIDTH_SEL, (AC108_SLOT_WIDTH / 4 - 1) << SLOT_WIDTH_SEL, i2c); /*16bit or 32bit Slot Width */ ac108_write(I2S_FMT_CTRL3, 0x70, i2c); /*0x36=0x70: TX MSB first, TX2 Mute, * LRCK = 1 BCLK width (short frame), Linear PCM Data Mode */ /* Transfer 0 after each sample in each * slot(sample resolution < slot width), */ ac108_write(I2S_TX1_CHMP_CTRL1, 0xe4, i2c); /*0x3C=0xe4: TX1 CHn Map to CHn adc sample, n=[1,4] */ ac108_write(I2S_TX1_CHMP_CTRL2, 0xe4, i2c); /*0x3D=0xe4: TX1 CHn Map to CH(n-4) adc sample, n=[5,8] */ ac108_write(I2S_TX1_CHMP_CTRL3, 0xe4, i2c); /*0x3E=0xe4: TX1 CHn Map to CH(n-8) adc sample, n=[9,12] */ ac108_write(I2S_TX1_CHMP_CTRL4, 0xe4, i2c); /*0x3F=0xe4: TX1 CHn Map to CH(n-12) adc sample, n=[13,16] */ /*** ADC DIG part Config***/ ac108_write(ADC_DIG_EN, 0x1f, i2c); /*0x61=0x1f: Digital part globe enable, ADCs digital part enable */ if (ac108_pub_cfg.debug_mode) { /*0x66=0x00: Digital ADCs channel HPF disable*/ ac108_write(HPF_EN, 0x00, i2c); /*0X7F=0x00: ADC pattern select: *0:ADC normal, 1:0x5A5A5A, 2:0x123456, 3:0x00, 4~7:I2S RX data */ ac108_write(ADC_DIG_DEBUG, 0x01, i2c); pr_err("AC108, enable debug mode!\n"); } ac108_write(ANA_ADC4_CTRL7, 0x0f, i2c); /*0xBB=0x0f: Gating ADCs CLK de-asserted (ADCs CLK Enable) */ #if 0 /*** ADCs analog PGA gain Config***/ if (i2c->addr == 0x3b) { ac108_write(ANA_PGA1_CTRL, ac108->pga_gain, i2c); /*0x90=0x3d: ADC1 PGA gain 30.5dB */ ac108_write(ANA_PGA2_CTRL, ac108->pga_gain, i2c); /*0x91=0x3d: ADC2 PGA gain 30.5dB */ #ifdef CONFIG_SND_MOZART_SINGLE_AC108 ac108_write(ANA_PGA3_CTRL, ac108->pga_gain, i2c); #else ac108_write(ANA_PGA3_CTRL, ac108->ref_pga_gain, i2c); #endif /*0x92=0x3d: ADC3 PGA gain 30.5dB */ ac108_write(ANA_PGA4_CTRL, ac108->ref_pga_gain, i2c); /*0x93=0x3d: ADC4 PGA gain 30.5dB */ } else if (i2c->addr == 0x35) { ac108_write(ANA_PGA1_CTRL, ac108->pga_gain, i2c); /*0x90=0x3d: ADC1 PGA gain 30.5dB */ ac108_write(ANA_PGA2_CTRL, ac108->pga_gain, i2c); /*0x91=0x3d: ADC2 PGA gain 30.5dB */ ac108_write(ANA_PGA3_CTRL, ac108->pga_gain, i2c); /*0x92=0x3d: ADC3 PGA gain 30.5dB */ ac108_write(ANA_PGA4_CTRL, ac108->pga_gain, i2c); /*0x93=0x3d: ADC4 PGA gain 30.5dB */ } #endif #if !AC108_DMIC_EN ac108_set_vol(i2c); /*** enable AAF/ADC/PGA and UnMute Config ***/ ac108_write(ANA_ADC1_CTRL1, 0x07, i2c); /*0xA0=0x07: ADC1 AAF & ADC enable, ADC1 PGA enable, * ADC1 MICBIAS enable and UnMute */ ac108_write(ANA_ADC2_CTRL1, 0x07, i2c); /*0xA7=0x07: ADC2 AAF & ADC enable, ADC2 PGA enable, * ADC2 MICBIAS enable and UnMute */ ac108_write(ANA_ADC3_CTRL1, 0x07, i2c); /*0xAE=0x07: ADC3 AAF & ADC enable, ADC3 PGA enable, * ADC3 MICBIAS enable and UnMute */ ac108_write(ANA_ADC4_CTRL1, 0x07, i2c); /*0xB5=0x07: ADC4 AAF & ADC enable, ADC4 PGA enable, * ADC4 MICBIAS enable and UnMute */ /* ac108_update_bits(PWR_CTRL7, 0x1<%s\n", __func__); switch (clk_id) { case SYSCLK_SRC_MCLK: pr_debug("AC108 SYSCLK source select MCLK\n\n"); ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, 0x0 << SYSCLK_SRC); /* System Clock Source Select MCLK */ break; case SYSCLK_SRC_PLL: pr_debug("AC108 SYSCLK source select PLL\n\n"); ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, 0x1 << SYSCLK_SRC); /* System Clock Source Select PLL */ break; default: pr_err("AC108 SYSCLK source config error:%d\n\n", clk_id); return -EINVAL; } /* SYSCLK Enable */ ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_EN, 0x1 << SYSCLK_EN); return 0; } static int ac108_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { unsigned int i = 0; unsigned int m1 = 0, m2 = 0, n = 0, k1 = 0, k2 = 0; pr_debug("\n--->%s\n", __func__); if (!freq_out) return 0; if (freq_in < 128000 || freq_in > 24576000) { pr_err("AC109 PLLCLK source freq only support [128K,24M]"); pr_err("while now %u\n\n", freq_in); return -EINVAL; } else if ((freq_in == 24576000 || freq_in == 22579200) && pll_id == SYSCLK_SRC_MCLK) { /* System Clock Source Select MCLK, SYSCLK Enable */ pr_debug("AC108 don't need to use PLL\n\n"); ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC | 0x1 << SYSCLK_EN, 0x0 << SYSCLK_SRC | 0x1 << SYSCLK_EN); return 0; /* Don't need to use PLL */ } /* PLL Clock Source Select */ switch (pll_id) { case PLLCLK_SRC_MCLK: pr_debug("AC108 PLLCLK input source select MCLK\n"); ac108_multi_chips_update_bits( SYSCLK_CTRL, 0x3 << PLLCLK_SRC, 0x0 << PLLCLK_SRC); break; case PLLCLK_SRC_BCLK: pr_debug("AC108 PLLCLK input source select BCLK\n"); ac108_multi_chips_update_bits( SYSCLK_CTRL, 0x3 << PLLCLK_SRC, 0x1 << PLLCLK_SRC); break; case PLLCLK_SRC_GPIO2: pr_debug("AC108 PLLCLK input source select GPIO2\n"); ac108_multi_chips_update_bits( SYSCLK_CTRL, 0x3 << PLLCLK_SRC, 0x2 << PLLCLK_SRC); break; case PLLCLK_SRC_GPIO3: pr_debug("AC108 PLLCLK input source select GPIO3\n"); ac108_multi_chips_update_bits( SYSCLK_CTRL, 0x3 << PLLCLK_SRC, 0x3 << PLLCLK_SRC); break; default: pr_err("AC108 PLLCLK source config error:%d\n\n", pll_id); return -EINVAL; } /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)]; */ for (i = 0; i < ARRAY_SIZE(ac108_pll_div); i++) { if (ac108_pll_div[i].freq_in == freq_in && ac108_pll_div[i].freq_out == freq_out) { m1 = ac108_pll_div[i].m1; m2 = ac108_pll_div[i].m2; n = ac108_pll_div[i].n; k1 = ac108_pll_div[i].k1; k2 = ac108_pll_div[i].k2; pr_debug("AC108 PLL freq_in match:%u, freq_out:%u\n", freq_in, freq_out); break; } } if (i == ARRAY_SIZE(ac108_pll_div)) { pr_err("AC108 don't match PLLCLK freq_in and freq_out table\n\n"); return -EINVAL; } /* Config PLL DIV param M1/M2/N/K1/K2 */ ac108_multi_chips_update_bits(PLL_CTRL2, 0x1f << PLL_PREDIV1 | 0x1 << PLL_PREDIV2, m1 << PLL_PREDIV1 | m2 << PLL_PREDIV2); ac108_multi_chips_update_bits(PLL_CTRL3, 0x3 << PLL_LOOPDIV_MSB, (n >> 8) << PLL_LOOPDIV_MSB); ac108_multi_chips_update_bits(PLL_CTRL4, 0xff << PLL_LOOPDIV_LSB, (u8) n << PLL_LOOPDIV_LSB); ac108_multi_chips_update_bits(PLL_CTRL5, 0x1f << PLL_POSTDIV1 | 0x1 << PLL_POSTDIV2, k1 << PLL_POSTDIV1 | k2 << PLL_POSTDIV2); /* PLL module enable */ ac108_multi_chips_update_bits(PLL_LOCK_CTRL, 0x1 << PLL_LOCK_EN, 0x1 << PLL_LOCK_EN); /* PLL CLK lock enable */ ac108_multi_chips_update_bits(PLL_CTRL1, 0x1 << PLL_EN | 0x1 << PLL_COM_EN, 0x1 << PLL_EN | 0x1 << PLL_COM_EN); /* PLL Common voltage Enable, PLL Enable */ /* PLLCLK Enable, System Clock Source Select PLL, SYSCLK Enable */ ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << PLLCLK_EN | 0x1 << SYSCLK_SRC | 0x1 << SYSCLK_EN, 0x1 << PLLCLK_EN | 0x1 << SYSCLK_SRC | 0x1 << SYSCLK_EN ); return 0; } static int ac108_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { /* pr_debug("\n--->%s\n", __func__); */ unsigned int i; unsigned int bclk_div = 0, bclk_div_reg_val = 0; if (!div_id) { /* use div_id to judge Master/Slave mode, * 0: Slave mode, 1: Master mode */ pr_debug("AC108 work as Slave mode."); pr_debug("it don't need to config BCLK_DIV.\n"); return 0; } bclk_div = div / (ac108_pub_cfg.ac108_nums * ac108_pub_cfg.slot_width * (AC108_ENCODING_EN ? (ac108_pub_cfg.ac108_nums * 4 + 1) / 2 : 1)); for (i = 0; i < ARRAY_SIZE(ac108_bclk_div); i++) { if (ac108_bclk_div[i].real_val == bclk_div) { bclk_div_reg_val = ac108_bclk_div[i].reg_val; pr_debug("AC108 set BCLK_DIV_[%u]\n\n", bclk_div); break; } } if (i == ARRAY_SIZE(ac108_bclk_div)) { pr_err("AC108 don't support BCLK_DIV_[%u]\n\n", bclk_div); return -EINVAL; } /* AC108 set BCLK DIV */ ac108_bclk_div_val = bclk_div_reg_val; #if !AC108_ENCODING_EN /* TX Encoding mode wil config BCLK_DIV at trigger function */ ac108_multi_chips_update_bits(I2S_BCLK_CTRL, 0xf << BCLKDIV, bclk_div_reg_val << BCLKDIV); #endif return 0; } static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { unsigned char i, tx_offset, i2s_mode, lrck_polarity, brck_polarity; struct ac108_priv *ac108 = dev_get_drvdata(dai->dev); pr_debug("\n--->%s\n", __func__); /* AC108 config Master/Slave mode */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: /* AC108 Master */ pr_debug("AC108 set to work as Master\n"); ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x3 << LRCK_IOEN, ac108->i2c); /* BCLK & LRCK output */ break; case SND_SOC_DAIFMT_CBS_CFS: /* AC108 Slave */ pr_debug("AC108 set to work as Slave\n"); ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac108->i2c); /* BCLK & LRCK input */ break; default: pr_err("AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12); return -EINVAL; } for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) { /* multi_chips: only one chip set as Master, * and the others also need to set as Slave */ if (i2c_clt[i] == ac108->i2c) continue; ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, i2c_clt[i]); } /* AC108 config I2S/LJ/RJ/PCM format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: pr_debug("AC108 config I2S format\n"); i2s_mode = LEFT_JUSTIFIED_FORMAT; tx_offset = 1; break; case SND_SOC_DAIFMT_RIGHT_J: pr_debug("AC108 config RIGHT-JUSTIFIED format\n"); i2s_mode = RIGHT_JUSTIFIED_FORMAT; tx_offset = 0; break; case SND_SOC_DAIFMT_LEFT_J: pr_debug("AC108 config LEFT-JUSTIFIED format\n"); i2s_mode = LEFT_JUSTIFIED_FORMAT; tx_offset = 0; break; case SND_SOC_DAIFMT_DSP_A: pr_debug("AC108 config PCM-A format\n"); i2s_mode = PCM_FORMAT; tx_offset = 1; break; case SND_SOC_DAIFMT_DSP_B: pr_debug("AC108 config PCM-B format\n"); i2s_mode = PCM_FORMAT; tx_offset = 0; break; default: pr_err("AC108 I2S format config error:%u\n\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } ac108_multi_chips_update_bits(I2S_FMT_CTRL1, 0x3 << MODE_SEL | 0x1 << TX2_OFFSET | 0x1 << TX1_OFFSET, i2s_mode << MODE_SEL | tx_offset << TX2_OFFSET | tx_offset << TX1_OFFSET); /* AC108 config BCLK&LRCK polarity */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: pr_debug("AC108 BCLK&LRCK polarity: BCLK_normal,LRCK_normal\n"); brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P; lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH; break; case SND_SOC_DAIFMT_NB_IF: pr_debug("AC108 BCLK&LRCK polarity:BCLK_normal,LRCK_invert\n"); brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P; lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW; break; case SND_SOC_DAIFMT_IB_NF: pr_debug("AC108 BCLK&LRCK polarity:BCLK_invert,LRCK_normal\n"); brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N; lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH; break; case SND_SOC_DAIFMT_IB_IF: pr_debug("AC108 BCLK&LRCK polarity:BCLK_invert,LRCK_invert\n"); brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N; lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW; break; default: pr_err("AC108 config BCLK/LRCLK polarity error:%u\n\n", (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8); return -EINVAL; } ac108_multi_chips_update_bits(I2S_BCLK_CTRL, 0x1 << BCLK_POLARITY, brck_polarity << BCLK_POLARITY); ac108_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x1 << LRCK_POLARITY, lrck_polarity << LRCK_POLARITY); return 0; } static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { unsigned int i, channels, channels_en, sample_resolution; pr_debug("\n--->%s\n", __func__); /* AC108 hw init */ for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) { /* (params_channels(params)+3)/4 */ ac108_hw_init(i2c_clt[i]); } /* AC108 set sample rate */ for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) { if (ac108_sample_rate[i].real_val == params_rate(params)) { ac108_multi_chips_update_bits(ADC_SPRC, 0xf << ADC_FS_I2S1, ac108_sample_rate [i].reg_val << ADC_FS_I2S1); break; } } /* AC108 set channels */ channels = params_channels(params); if (channels != ac108_pub_cfg.ac108_nums * 4) return -EINVAL; for (i = 0; i < (channels + 3) / 4; i++) { channels_en = (channels >= 4 * (i + 1)) ? 0x000f << (4 * i) : ((1 << (channels % 4)) - 1) << (4 * i); ac108_write(I2S_TX1_CTRL1, channels - 1, i2c_clt[i]); ac108_write(I2S_TX1_CTRL2, (u8) channels_en, i2c_clt[i]); ac108_write(I2S_TX1_CTRL3, channels_en >> 8, i2c_clt[i]); } for (; i < ac108_pub_cfg.ac108_nums; i++) { ac108_write(I2S_TX1_CTRL1, 0, i2c_clt[i]); ac108_write(I2S_TX1_CTRL2, 0, i2c_clt[i]); ac108_write(I2S_TX1_CTRL3, 0, i2c_clt[i]); } /* AC108 set sample resorution */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: sample_resolution = 8; break; case SNDRV_PCM_FORMAT_S16_LE: sample_resolution = 16; break; case SNDRV_PCM_FORMAT_S20_3LE: sample_resolution = 20; break; case SNDRV_PCM_FORMAT_S24_LE: sample_resolution = 24; break; case SNDRV_PCM_FORMAT_S32_LE: sample_resolution = 32; break; default: dev_err(dai->dev, "AC108 don't supported the sample resolution: %u\n", params_format(params)); return -EINVAL; } #if AC108_ENCODING_EN /* if(sample_resolution <= 24 && sample_resolution != 16) * sample_resolution += 4; * TX Encoding mode, SR add 4bits to mark channel number */ #endif for (i = 0; i < ARRAY_SIZE(ac108_sample_resolution); i++) { if (ac108_sample_resolution[i].real_val == sample_resolution) { ac108_multi_chips_update_bits(I2S_FMT_CTRL2, 0x7 << SAMPLE_RESOLUTION, ac108_sample_resolution [i].reg_val << SAMPLE_RESOLUTION); break; } } ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN, 0x1 << TXEN); return 0; } static int ac108_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { pr_debug("\n--->%s\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { pr_debug("AC108 I2S TX block Enable\n\n"); /* ac108_multi_chips_update_bits * (I2S_CTRL, 0x1<%s\n", __func__); pr_debug("AC108 reset all register to their default value\n\n"); ac108_multi_chips_write(CHIP_AUDIO_RST, 0x12); /* if config TX Encoding mode, also disable BCLK */ return 0; } /*** define ac108 dai_ops struct ***/ static const struct snd_soc_dai_ops ac108_dai_ops = { /*DAI clocking configuration */ .set_sysclk = ac108_set_sysclk, .set_pll = ac108_set_pll, .set_clkdiv = ac108_set_clkdiv, /*ALSA PCM audio operations */ .hw_params = ac108_hw_params, .trigger = ac108_trigger, .hw_free = ac108_hw_free, /*DAI format configuration */ .set_fmt = ac108_set_fmt, }; /*** define ac108 dai_driver struct ***/ static struct snd_soc_dai_driver ac108_dai0 = { .name = "ac108-pcm0", .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AC108_NUM_MAX * 4, .rates = AC108_RATES, .formats = AC108_FORMATS, }, .ops = &ac108_dai_ops, }; static struct snd_soc_dai_driver ac108_dai1 = { .name = "ac108-pcm1", .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AC108_NUM_MAX * 4, .rates = AC108_RATES, .formats = AC108_FORMATS, }, .ops = &ac108_dai_ops, }; static struct snd_soc_dai_driver ac108_dai2 = { .name = "ac108-pcm2", .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AC108_NUM_MAX * 4, .rates = AC108_RATES, .formats = AC108_FORMATS, }, .ops = &ac108_dai_ops, }; static struct snd_soc_dai_driver ac108_dai3 = { .name = "ac108-pcm3", .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AC108_NUM_MAX * 4, .rates = AC108_RATES, .formats = AC108_FORMATS, }, .ops = &ac108_dai_ops, }; static struct snd_soc_dai_driver *ac108_dai[] = { &ac108_dai0, &ac108_dai1, &ac108_dai2, &ac108_dai3, }; static int ac108_probe(struct snd_soc_codec *codec) { struct ac108_priv *ac108 = dev_get_drvdata(codec->dev); int ret = 0; codec->control_data = devm_regmap_init_i2c(ac108->i2c, &ac108_regmap_config); ret = PTR_RET(codec->control_data); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } ac108->codec = codec; return 0; } static int ac108_remove(struct snd_soc_codec *codec) { return 0; } #ifdef CONFIG_PM static int ac108_suspend(struct snd_soc_codec *codec) { if (regulator_en && !IS_ERR_OR_NULL(ac108_pub_cfg.vol_supply.vcc3v3)) { regulator_disable(ac108_pub_cfg.vol_supply.vcc3v3); } if (regulator_en && gpio_is_valid(ac108_pub_cfg.power_gpio)) { gpio_set_value(ac108_pub_cfg.power_gpio, 0); gpio_free(ac108_pub_cfg.power_gpio); } if (regulator_en && gpio_is_valid(ac108_pub_cfg.reset_gpio)) { gpio_set_value(ac108_pub_cfg.reset_gpio, 0); gpio_free(ac108_pub_cfg.reset_gpio); } regulator_en = 0; return 0; } static int ac108_resume(struct snd_soc_codec *codec) { int ret; u8 i; if (!regulator_en && !IS_ERR_OR_NULL(ac108_pub_cfg.vol_supply.vcc3v3)) { ret = regulator_enable(ac108_pub_cfg.vol_supply.vcc3v3); if (ret != 0) pr_err("%s: fail to enable regulator!\n", __func__); } if (!regulator_en && gpio_is_valid(ac108_pub_cfg.power_gpio)) { ret = gpio_request(ac108_pub_cfg.power_gpio, "gpio-power"); if (!ret) { gpio_direction_output(ac108_pub_cfg.power_gpio, 1); gpio_set_value(ac108_pub_cfg.power_gpio, 1); msleep(20); } } if (!regulator_en && gpio_is_valid(ac108_pub_cfg.reset_gpio)) { ret = gpio_request(ac108_pub_cfg.reset_gpio, "reset gpio"); if (!ret) { gpio_direction_output(ac108_pub_cfg.reset_gpio, 1); gpio_set_value(ac108_pub_cfg.reset_gpio, 1); msleep(20); } } regulator_en = 1; for (i = 0; i < ac108_pub_cfg.ac108_nums; i++) ac108_hw_init(i2c_clt[i]); return 0; } #else #define ac108_suspend NULL #define ac108_resume NULL #endif static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int reg) { /* pr_debug("\n--->%s\n",__func__); */ u8 val_r; struct ac108_priv *ac108 = dev_get_drvdata(codec->dev); ac108_read(reg, &val_r, ac108->i2c); return val_r; } static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { /* pr_debug("\n--->%s\n",__func__); */ ac108_multi_chips_write(reg, value); return 0; } /*** define ac108 codec_driver struct ***/ static const struct snd_soc_codec_driver ac108_soc_codec_driver = { .probe = ac108_probe, .remove = ac108_remove, .suspend = ac108_suspend, .resume = ac108_resume, #if AC108_CODEC_RW_TEST_EN .read = ac108_codec_read, .write = ac108_codec_write, #endif #if AC108_DAPM_TEST_EN .controls = ac108_controls, .num_controls = ARRAY_SIZE(ac108_controls), .dapm_widgets = ac108_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ac108_dapm_widgets), .dapm_routes = ac108_dapm_routes, .num_dapm_routes = ARRAY_SIZE(ac108_dapm_routes), #endif }; static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int val = 0, flag = 0; int ret; u8 i = 0, reg, num, value_w, value_r; struct ac108_priv *ac108 = dev_get_drvdata(dev); ret = kstrtol(buf, 16, (long *)&val); flag = (val >> 16) & 0xF; if (flag) { reg = (val >> 8) & 0xFF; value_w = val & 0xFF; ac108_write(reg, value_w, ac108->i2c); dev_info(dev, "Write 0x%02x to REG:0x%02x\n", value_w, reg); } else { reg = (val >> 8) & 0xFF; num = val & 0xff; dev_info(dev, "\nRead: start REG:0x%02x, count:0x%02x\n", reg, num); do { value_r = 0; ac108_read(reg, &value_r, ac108->i2c); dev_info(dev, "REG[0x%02x]: 0x%02x; ", reg, value_r); reg++; i++; } while (i < num); } return count; } static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf) { #if 1 dev_info(dev, "echo flag|reg|val > ac108\n"); dev_info(dev, "eg read star address=0x06,count 0x10:echo 0610 >ac108\n"); dev_info(dev, "eg write value:0xfe to address: 0x06 :echo 106fe > ac108\n"); return 0; #else return snprintf(buf, PAGE_SIZE, "echo flag|reg|val > ac108\n" "eg read star address=0x06,count 0x10:echo 0610 >ac108\n" "eg write value:0xfe to address:0x06 :echo 106fe > ac108\n"); #endif } static DEVICE_ATTR(ac108, 0644, ac108_show, ac108_store); static struct attribute *ac108_debug_attrs[] = { &dev_attr_ac108.attr, NULL, }; static struct attribute_group ac108_debug_attr_group = { .name = "ac108_debug", .attrs = ac108_debug_attrs, }; static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { struct ac108_priv *ac108; struct device_node *np = i2c->dev.of_node; u32 temp_val; u8 reg; int ret = 0; struct gpio_config config; ac108 = devm_kzalloc(&i2c->dev, sizeof(struct ac108_priv), GFP_KERNEL); if (!ac108) { dev_err(&i2c->dev, "Unable to allocate ac108 private data\n"); return -ENOMEM; } ac108->i2c = i2c; dev_set_drvdata(&i2c->dev, ac108); ret = of_property_read_u32(np, "pga_gain", &temp_val); if (ret < 0) { pr_err("[ac108]pga_gain configurations missing or invalid.\n"); ac108_pub_cfg.pga_gain = 0x32; } else { ac108_pub_cfg.pga_gain = temp_val; } ret = of_property_read_u32(np, "ref_pga_gain", &temp_val); if (ret < 0) { pr_err("[ac108]ref_pga_gain configurations missing or invalid.\n"); ac108_pub_cfg.ref_pga_gain = 0x08; } else { ac108_pub_cfg.ref_pga_gain = temp_val; } ret = of_property_read_u32(np, "twi_bus", &temp_val); if (ret < 0) { pr_err("[ac108]twi_bus configurations missing or invalid.\n"); ac108_pub_cfg.i2c_bus_num = 0; } else { ac108_pub_cfg.i2c_bus_num = temp_val; } ret = of_property_read_u32(np, "debug_mode", &temp_val); if (ret < 0) { pr_err("[ac108]debug_mode configurations missing or invalid.\n"); ac108_pub_cfg.debug_mode = 0; } else { ac108_pub_cfg.debug_mode = temp_val; } ret = of_property_read_u32(np, "codec_mic_used", &temp_val); if (ret < 0) { pr_err("[ac108]codec_mic_used configurations missing or invalid.\n"); ac108_pub_cfg.codec_mic_used = 0; } else { ac108_pub_cfg.codec_mic_used = temp_val; } ret = of_property_read_u32(np, "ref_chip_addr", &temp_val); if (ret < 0) { pr_err("[ac108]ref_chip_addr configurations missing or invalid.\n"); ac108_pub_cfg.ref_chip_addr = 0; } else { ac108_pub_cfg.ref_chip_addr = temp_val; } ret = of_property_read_u32(np, "slot_width", &temp_val); if (ret < 0) { pr_err("[ac108]slot_width configurations missing or invalid.\n"); ac108_pub_cfg.slot_width = 0; } else { ac108_pub_cfg.slot_width = temp_val; } ret = of_property_read_u32(np, "pa_double_used", &temp_val); if (ret < 0) { pr_err("[ac108]pa_double_used configurations missing or invalid.\n"); ac108_pub_cfg.pa_double_used = 0; } else { ac108_pub_cfg.pa_double_used = temp_val; } ret = of_property_read_u32(np, "ref_channel_num", &temp_val); if (ret < 0) { pr_err("[ac108]ref_channel_num configurations missing or invalid.\n"); ac108_pub_cfg.ref_channel_num = 0; } else { ac108_pub_cfg.ref_channel_num = temp_val; } if (!regulator_en) { ret = of_property_read_string(np, AC108_REGULATOR_NAME, &ac108_pub_cfg.power_name); if (!ret) { ac108_pub_cfg.vol_supply.vcc3v3 = regulator_get(NULL, ac108_pub_cfg.power_name); if (IS_ERR_OR_NULL(ac108_pub_cfg.vol_supply.vcc3v3)) { pr_err("get ac108 audio-3v3 failed\n"); goto err1; } if (!of_property_read_u32(np, "power_vol", &ac108_pub_cfg.power_vol)) { regulator_set_voltage(ac108_pub_cfg.vol_supply.vcc3v3, ac108_pub_cfg.power_vol, ac108_pub_cfg.power_vol); ret = regulator_enable(ac108_pub_cfg.vol_supply.vcc3v3); if (ret) { dev_err(&i2c->dev, "Failed to enable voltage reference\n"); goto err1; } } } else { dev_info(&i2c->dev, "ac108: voltage_enable missing or invalid\n"); } /*gpio power enable*/ ac108_pub_cfg.power_gpio = of_get_named_gpio_flags(np, "gpio-power", 0, (enum of_gpio_flags *)&config); if (gpio_is_valid(ac108_pub_cfg.power_gpio)) { ret = gpio_request(ac108_pub_cfg.power_gpio, "power gpio"); if (!ret) { gpio_direction_output( ac108_pub_cfg.power_gpio, 1 ); gpio_set_value(ac108_pub_cfg.power_gpio, 1); msleep(20); } else { pr_err("%s, line:%d, failed request power gpio: %d!\n", __func__, __LINE__, ac108_pub_cfg.power_gpio); goto err2; } } /*gpio reset enable*/ ac108_pub_cfg.reset_gpio = of_get_named_gpio_flags(np, "gpio-reset", 0, (enum of_gpio_flags *)&config); if (gpio_is_valid(ac108_pub_cfg.reset_gpio)) { ret = gpio_request(ac108_pub_cfg.reset_gpio, "reset gpio"); if (!ret) { gpio_direction_output( ac108_pub_cfg.reset_gpio, 1 ); gpio_set_value(ac108_pub_cfg.reset_gpio, 1); msleep(20); } else { pr_err("%s, line:%d, failed request reset gpio: %d!\n", __func__, __LINE__, ac108_pub_cfg.reset_gpio); goto err3; } } regulator_en = 1; } /* ac108 detect */ ac108_read(CHIP_AUDIO_RST, ®, i2c); if (reg != 0x4a) { pr_err("%s, line: %d, ac108 hardware detect failed\n\n", __func__, __LINE__); goto err4; } ac108_pub_cfg.ac108_nums++; if (i2c_id->driver_data < AC108_NUM_MAX) { i2c_clt[ac108_pub_cfg.ac108_nums - 1] = i2c; ret = snd_soc_register_codec(&i2c->dev, &ac108_soc_codec_driver, ac108_dai[i2c_id->driver_data], 1); if (ret < 0) { dev_err(&i2c->dev, "Failed to register ac108: %d\n", ret); goto err4; } } ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group); if (ret) { pr_err("failed to create attr group\n"); goto err4; } dev_info(&i2c->dev, "ac108: %s probe succeed!\n\n", i2c_id->name); return 0; err4: if (ac108_pub_cfg.reset_gpio) gpio_free(ac108_pub_cfg.reset_gpio); err3: if (ac108_pub_cfg.power_gpio) gpio_free(ac108_pub_cfg.power_gpio); err2: if (ac108_pub_cfg.vol_supply.vcc3v3) regulator_disable(ac108_pub_cfg.vol_supply.vcc3v3); err1: devm_kfree(&i2c->dev, ac108); return ret; } static int ac108_i2c_remove(struct i2c_client *i2c) { /* sysfs_remove_group(&i2c->dev.kobj, &ac108_debug_attr_group); */ snd_soc_unregister_codec(&i2c->dev); return 0; } static const unsigned short ac108_i2c_addr[] = { 0x3b, 0x35, 0x3c, 0x36, I2C_CLIENT_END, }; static const struct i2c_device_id ac108_i2c_id[] = { {"MicArray_0", 0}, /* ac108_0 */ {"MicArray_1", 1}, /* ac108_1 */ {"MicArray_2", 2}, /* ac108_2 */ {"MicArray_3", 3}, /* ac108_3 */ {} }; MODULE_DEVICE_TABLE(i2c, ac108_i2c_id); static const struct of_device_id ac108_dt_ids[] = { {.compatible = "MicArray_0",}, /* ac108_0 */ {.compatible = "MicArray_1",}, /* ac108_1 */ {.compatible = "MicArray_2",}, /* ac108_2 */ {.compatible = "MicArray_3",}, /* ac108_3 */ {} }; MODULE_DEVICE_TABLE(of, ac108_dt_ids); static struct i2c_driver ac108_i2c_driver = { .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .driver = { .name = "ac108", .owner = THIS_MODULE, .of_match_table = ac108_dt_ids, }, .probe = ac108_i2c_probe, .remove = ac108_i2c_remove, .id_table = ac108_i2c_id, }; static int __init ac108_init(void) { int ret; pr_info("Enter ac108_init\n"); ret = i2c_add_driver(&ac108_i2c_driver); if (ret != 0) pr_err("Failed to register ac108 i2c driver : %d\n", ret); return ret; } module_init(ac108_init); static void __exit ac108_exit(void) { i2c_del_driver(&ac108_i2c_driver); } module_exit(ac108_exit); MODULE_DESCRIPTION("ASoC ac108 codec driver"); MODULE_AUTHOR("panjunwen"); MODULE_LICENSE("GPL");