diff -drupN a/sound/soc/codecs/ac107.c b/sound/soc/codecs/ac107.c --- a/sound/soc/codecs/ac107.c 1970-01-01 03:00:00.000000000 +0300 +++ b/sound/soc/codecs/ac107.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,2170 @@ +/* + * ac107.c -- ac107 ALSA Soc Audio driver + * + * Version: 1.0 + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ac107.h" + +#define AC107_DEBUG_EN 1 + +#if AC107_DEBUG_EN +#define AC107_DEBUG(...) printk(__VA_ARGS__) +#else +#define AC107_DEBUG(...) +#endif + +#define AC107_ADC_PATTERN_SEL ADC_PTN_NORMAL /* 0:ADC normal, 1:0x5A5A5A, 2:0x123456, 3:0x000000, 4~7:I2S_RX_DATA, other:reserved */ + +/* AC107 config */ +#define AC107_CHIP_NUMS 1 /* range[1, 8] */ +#define AC107_CHIP_NUMS_MAX 8 /* range[1, 8] */ +#define AC107_SLOT_WIDTH 32 /* 8/12/16/20/24/28/32bit Slot Width */ +#define AC107_ENCODING_EN 0 /* TX Encoding mode enable */ +#define AC107_ENCODING_CH_NUMS 2 /* TX Encoding channel numbers, must be dual, range[1, 16] */ +#define AC107_ENCODING_FMT 0 /* TX Encoding format: 0:first channel number 0, other:first channel number 1 */ +/*range[1, 1024], default PCM mode, I2S/LJ/RJ mode shall divide by 2 */ +//#define AC107_LRCK_PERIOD (AC107_SLOT_WIDTH*(AC107_ENCODING_EN ? 2 : AC107_CHIP_NUMS*2)) +#define AC107_LRCK_PERIOD (AC107_SLOT_WIDTH*(AC107_ENCODING_EN ? 2 : AC107_CHIP_NUMS)) +#define AC107_MATCH_DTS_EN 1 /* AC107 match method select: 0: i2c_detect, 1:devices tree */ + +#define AC107_KCONTROL_EN 1 +#define AC107_DAPM_EN 0 +#define AC107_CODEC_RW_USER_EN 1 +#define AC107_PGA_GAIN ADC_PGA_GAIN_28dB //-6dB and 0dB, 3~30dB, 1dB step +#define AC107_DMIC_EN 0 //0:ADC 1:DMIC +#define AC107_PDM_EN 0 //0:I2S 1:PDM + +#define AC107_DVCC_NAME "ac107_dvcc_1v8" +#define AC107_AVCC_VCCIO_NAME "ac107_avcc_vccio_3v3" +#define AC107_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) +#define AC107_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int ac107_regulator_en; +struct i2c_client *i2c_ctrl[AC107_CHIP_NUMS_MAX]; + +struct ac107_voltage_supply { + struct regulator *dvcc_1v8; + struct regulator *avcc_vccio_3v3; +}; + +struct ac107_priv { + struct i2c_client *i2c; + struct snd_soc_codec *codec; + struct ac107_voltage_supply vol_supply; + int reset_gpio; +}; + +static const struct regmap_config ac107_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 reg_default_value { + u8 reg_addr; + u8 default_val; +}; + +struct pll_div { + u32 freq_in; + u32 freq_out; + u32 m1; + u32 m2; + u32 n; + u32 k1; + u32 k2; +}; + +static const struct real_val_to_reg_val ac107_sample_rate[] = { + {8000, 0}, + {11025, 1}, + {12000, 2}, + {16000, 3}, + {22050, 4}, + {24000, 5}, + {32000, 6}, + {44100, 7}, + {48000, 8}, +}; + +static const struct real_val_to_reg_val ac107_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 ac107_pll_div[] = { + {400000, 12288000, 0, 0, 983, 15, 1}, // + {512000, 12288000, 0, 0, 960, 19, 1}, //24576000/48 + {768000, 12288000, 0, 0, 640, 19, 1}, //24576000/32 + {800000, 12288000, 0, 0, 768, 24, 1}, + {1024000, 12288000, 0, 0, 480, 19, 1}, //24576000/24 + {1600000, 12288000, 0, 0, 384, 24, 1}, + {2048000, 12288000, 0, 0, 240, 19, 1}, //24576000/12 + {3072000, 12288000, 0, 0, 160, 19, 1}, //24576000/8 + {4096000, 12288000, 0, 0, 120, 19, 1}, //24576000/6 + {6000000, 12288000, 4, 0, 512, 24, 1}, + {6144000, 12288000, 1, 0, 160, 19, 1}, //24576000/4 + {12000000, 12288000, 9, 0, 512, 24, 1}, + {13000000, 12288000, 12, 0, 639, 25, 1}, // + {15360000, 12288000, 9, 0, 320, 19, 1}, + {16000000, 12288000, 9, 0, 384, 24, 1}, + {19200000, 12288000, 11, 0, 384, 24, 1}, + {19680000, 12288000, 15, 1, 999, 24, 1}, // + {24000000, 12288000, 9, 0, 256, 24, 1}, + + {400000, 11289600, 0, 0, 1016, 17, 1}, // + {512000, 11289600, 0, 0, 882, 19, 1}, + {768000, 11289600, 0, 0, 588, 19, 1}, + {800000, 11289600, 0, 0, 508, 17, 1}, // + {1024000, 11289600, 0, 0, 441, 19, 1}, + {1600000, 11289600, 0, 0, 254, 17, 1}, // + {2048000, 11289600, 1, 0, 441, 19, 1}, + {3072000, 11289600, 0, 0, 147, 19, 1}, + {4096000, 11289600, 3, 0, 441, 19, 1}, + {6000000, 11289600, 1, 0, 143, 18, 1}, // + {6144000, 11289600, 1, 0, 147, 19, 1}, + {12000000, 11289600, 3, 0, 143, 18, 1}, // + {13000000, 11289600, 12, 0, 429, 18, 1}, // + {15360000, 11289600, 14, 0, 441, 19, 1}, + {16000000, 11289600, 24, 0, 882, 24, 1}, + {19200000, 11289600, 4, 0, 147, 24, 1}, + {19680000, 11289600, 13, 1, 771, 23, 1}, // + {24000000, 11289600, 24, 0, 588, 24, 1}, + + {12288000, 12288000, 9, 0, 400, 19, 1}, //24576000/2 + {11289600, 11289600, 9, 0, 400, 19, 1}, //22579200/2 + + {24576000 / 1, 12288000, 9, 0, 200, 19, 1}, //24576000 + {24576000 / 16, 12288000, 0, 0, 320, 19, 1}, //1536000 + {24576000 / 64, 12288000, 0, 0, 640, 9, 1}, //384000 + {24576000 / 96, 12288000, 0, 0, 960, 9, 1}, //256000 + {24576000 / 128, 12288000, 0, 0, 512, 3, 1}, //192000 + {24576000 / 176, 12288000, 0, 0, 880, 4, 1}, //140000 + {24576000 / 192, 12288000, 0, 0, 960, 4, 1}, //128000 + + {22579200 / 1, 11289600, 9, 0, 200, 19, 1}, //22579200 + {22579200 / 4, 11289600, 4, 0, 400, 19, 1}, //5644800 + {22579200 / 16, 11289600, 0, 0, 320, 19, 1}, //1411200 + {22579200 / 64, 11289600, 0, 0, 640, 9, 1}, //352800 + {22579200 / 96, 11289600, 0, 0, 960, 9, 1}, //235200 + {22579200 / 128, 11289600, 0, 0, 512, 3, 1}, //176400 + {22579200 / 176, 11289600, 0, 0, 880, 4, 1}, //128290 + {22579200 / 192, 11289600, 0, 0, 960, 4, 1}, //117600 + + {22579200 / 6, 11289600, 2, 0, 360, 19, 1}, //3763200 + {22579200 / 8, 11289600, 0, 0, 160, 19, 1}, //2822400 + {22579200 / 12, 11289600, 0, 0, 240, 19, 1}, //1881600 + {22579200 / 24, 11289600, 0, 0, 480, 19, 1}, //940800 + {22579200 / 32, 11289600, 0, 0, 640, 19, 1}, //705600 + {22579200 / 48, 11289600, 0, 0, 960, 19, 1}, //470400 +}; + +const struct reg_default_value ac107_reg_default_value[] = { + /*** Chip reset ***/ + {CHIP_AUDIO_RST, 0x4B}, + + /*** Power Control ***/ + {PWR_CTRL1, 0x00}, + {PWR_CTRL2, 0x11}, + + /*** PLL Configure Control ***/ + {PLL_CTRL1, 0x48}, + {PLL_CTRL2, 0x00}, + {PLL_CTRL3, 0x03}, + {PLL_CTRL4, 0x0D}, + {PLL_CTRL5, 0x00}, + {PLL_CTRL6, 0x0F}, + {PLL_CTRL7, 0xD0}, + {PLL_LOCK_CTRL, 0x00}, + + /*** System Clock Control ***/ + {SYSCLK_CTRL, 0x00}, + {MOD_CLK_EN, 0x00}, + {MOD_RST_CTRL, 0x00}, + + /*** I2S Common Control ***/ + {I2S_CTRL, 0x00}, + {I2S_BCLK_CTRL, 0x00}, + {I2S_LRCK_CTRL1, 0x00}, + {I2S_LRCK_CTRL2, 0x00}, + {I2S_FMT_CTRL1, 0x00}, + {I2S_FMT_CTRL2, 0x55}, + {I2S_FMT_CTRL3, 0x60}, + + /*** I2S TX Control ***/ + {I2S_TX_CTRL1, 0x00}, + {I2S_TX_CTRL2, 0x00}, + {I2S_TX_CTRL3, 0x00}, + {I2S_TX_CHMP_CTRL1, 0x00}, + {I2S_TX_CHMP_CTRL2, 0x00}, + + /*** I2S RX Control ***/ + {I2S_RX_CTRL1, 0x00}, + {I2S_RX_CTRL2, 0x03}, + {I2S_RX_CTRL3, 0x00}, + {I2S_RX_CHMP_CTRL1, 0x00}, + {I2S_RX_CHMP_CTRL2, 0x00}, + + /*** PDM Control ***/ + {PDM_CTRL, 0x00}, + + /*** ADC Common Control ***/ + {ADC_SPRC, 0x00}, + {ADC_DIG_EN, 0x00}, + {DMIC_EN, 0x00}, + {HPF_EN, 0x03}, + + /*** ADC Digital Channel Volume Control ***/ + {ADC1_DVOL_CTRL, 0xA0}, + {ADC2_DVOL_CTRL, 0xA0}, + + /*** ADC Digital Mixer Source and Gain Control ***/ + {ADC1_DMIX_SRC, 0x01}, + {ADC2_DMIX_SRC, 0x02}, + + /*** ADC_DIG_DEBUG ***/ + {ADC_DIG_DEBUG, 0x00}, + + /*** Pad Function and Drive Control ***/ + {ADC_ANA_DEBUG1, 0x11}, + {ADC_ANA_DEBUG2, 0x11}, + {I2S_PADDRV_CTRL, 0x55}, + + /*** ADC1 Analog Control ***/ + {ANA_ADC1_CTRL1, 0x00}, + {ANA_ADC1_CTRL2, 0x00}, + {ANA_ADC1_CTRL3, 0x00}, + {ANA_ADC1_CTRL4, 0x00}, + {ANA_ADC1_CTRL5, 0x00}, + + /*** ADC2 Analog Control ***/ + {ANA_ADC2_CTRL1, 0x00}, + {ANA_ADC2_CTRL2, 0x00}, + {ANA_ADC2_CTRL3, 0x00}, + {ANA_ADC2_CTRL4, 0x00}, + {ANA_ADC2_CTRL5, 0x00}, + + /*** ADC Dither Control ***/ + {ADC_DITHER_CTRL, 0x00}, +}; + +const u8 ac107_kcontrol_dapm_reg[] = { +#if AC107_KCONTROL_EN + ANA_ADC1_CTRL3, ANA_ADC2_CTRL3, ADC1_DVOL_CTRL, ADC2_DVOL_CTRL, + ADC1_DMIX_SRC, ADC2_DMIX_SRC, ADC_DIG_DEBUG, +#endif + +#if AC107_DAPM_EN + DMIC_EN, ADC1_DMIX_SRC, ADC2_DMIX_SRC, I2S_TX_CHMP_CTRL1, + I2S_TX_CHMP_CTRL2, ANA_ADC1_CTRL5, ANA_ADC2_CTRL5, ADC_DIG_EN, +#endif +}; + +static int ac107_read(u8 reg, u8 *rt_value, struct i2c_client *client); +static int ac107_update_bits(u8 reg, u8 mask, u8 value, + struct i2c_client *client); + +#define AC107_KCONTROL_FUNC(n) \ +int ac107_codec##n##_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\ +{\ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;\ + unsigned int reg = mc->reg;\ + unsigned int shift = mc->shift;\ + unsigned int max = mc->max;\ + unsigned int mask = (1 << fls(max)) - 1;\ + unsigned int invert = mc->invert;\ + u8 reg_val;\ +\ + ac107_read(reg, ®_val, i2c_ctrl[n]);\ + ucontrol->value.integer.value[0] = reg_val >> shift & mask;\ + if (invert) {\ + ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0];\ + } \ + /*printk("read: REG-0x%02x, shift-%d, val-%d\n",reg,shift,ucontrol->value.integer.value[0]);*/\ +\ + return 0;\ +} \ +\ +int ac107_codec##n##_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\ +{\ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;\ + unsigned int reg = mc->reg;\ + unsigned int shift = mc->shift;\ + unsigned int max = mc->max;\ + unsigned int mask = (1 << fls(max)) - 1;\ + unsigned int invert = mc->invert;\ + u8 reg_val;\ +\ + reg_val = ucontrol->value.integer.value[0] & mask;\ + if (invert) {\ + reg_val = max - reg_val;\ + } \ + ac107_update_bits(reg, mask< (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 *******************************************/ +//ac107 dapm routes +static const struct snd_soc_dapm_route ac107_dapm_routes[] = { + //MIC1 PGA + {"MIC1 PGA", NULL, "MIC1P"}, + {"MIC1 PGA", NULL, "MIC1N"}, + + //MIC2 PGA + {"MIC2 PGA", NULL, "MIC2P"}, + {"MIC2 PGA", NULL, "MIC2N"}, + + //DMIC PGA + {"DMICL PGA", NULL, "DMIC"}, + {"DMICR PGA", NULL, "DMIC"}, + + //ADC DMIC MUX + {"ADC DMIC MUX", "ADC switch", "MIC1 PGA"}, + {"ADC DMIC MUX", "ADC switch", "MIC2 PGA"}, + {"ADC DMIC MUX", "DMIC switch", "DMICL PGA"}, + {"ADC DMIC MUX", "DMIC switch", "DMICR PGA"}, + + //ADC1 VIR PGA + {"ADC1 VIR PGA", NULL, "ADC DMIC MUX"}, + + //ADC2 VIR PGA + {"ADC2 VIR PGA", NULL, "ADC DMIC MUX"}, + + //ADC1 DIG MIXER + {"ADC1 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, + {"ADC1 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, + + //ADC2 DIG MIXER + {"ADC2 DIG MIXER", "ADC1 DAT switch", "ADC1 VIR PGA"}, + {"ADC2 DIG MIXER", "ADC2 DAT switch", "ADC2 VIR PGA"}, + + //I2S TX CH1 MUX + {"I2S TX CH1 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH1 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH2 MUX + {"I2S TX CH2 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH2 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH3 MUX + {"I2S TX CH3 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH3 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH4 MUX + {"I2S TX CH4 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH4 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH5 MUX + {"I2S TX CH5 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH5 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH6 MUX + {"I2S TX CH6 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH6 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH7 MUX + {"I2S TX CH7 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH7 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH8 MUX + {"I2S TX CH8 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH8 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH9 MUX + {"I2S TX CH9 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH9 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH10 MUX + {"I2S TX CH10 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH10 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH11 MUX + {"I2S TX CH11 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH11 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH12 MUX + {"I2S TX CH12 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH12 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH13 MUX + {"I2S TX CH13 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH13 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH14 MUX + {"I2S TX CH14 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH14 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH15 MUX + {"I2S TX CH15 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH15 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //I2S TX CH16 MUX + {"I2S TX CH16 MUX", "ADC1 Sample switch", "ADC1 DIG MIXER"}, + {"I2S TX CH16 MUX", "ADC2 Sample switch", "ADC2 DIG MIXER"}, + + //AIF ADC OUT + {"AIF ADC OUT", NULL, "I2S TX CH1 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH2 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH3 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH4 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH5 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH6 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH7 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH8 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH9 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH10 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH11 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH12 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH13 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH14 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH15 MUX"}, + {"AIF ADC OUT", NULL, "I2S TX CH16 MUX"}, +}; + +static int ac107_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 == NULL || client->adapter == NULL) { + pr_err("ac107_read client or client->adapter is NULL\n"); + return -1; + } + + ret = i2c_master_send(client, read_cmd, cmd_len); + if (ret != cmd_len) { + pr_err("ac107_read error1->[REG-0x%02x]\n", reg); + return -1; + } + + ret = i2c_master_recv(client, rt_value, 1); + if (ret != 1) { + pr_err("ac107_read error2->[REG-0x%02x], ret=%d\n", reg, ret); + return -1; + } + + return 0; +} + +static int ac107_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; + + if (client == NULL || client->adapter == NULL) { + pr_err("ac107_write client or client->adapter is NULL\n"); + return -1; + } + + ret = i2c_master_send(client, write_cmd, 2); + if (ret != 2) { + pr_err("ac107_write error->[REG-0x%02x,val-0x%02x]\n", reg, + value); + return -1; + } + + return 0; +} + +static int ac107_update_bits(u8 reg, u8 mask, u8 value, + struct i2c_client *client) +{ + u8 val_old, val_new; + + ac107_read(reg, &val_old, client); + val_new = (val_old & ~mask) | (value & mask); + if (val_new != val_old) { + ac107_write(reg, val_new, client); + } + + return 0; +} + +#if 0 +static int ac107_multi_chips_read(u8 reg, unsigned char *rt_value) +{ + u8 i; + + for (i = 0; i < AC107_CHIP_NUMS; i++) { + ac107_read(reg, rt_value++, i2c_ctrl[i]); + } + + return 0; +} +#endif + +static int ac107_multi_chips_write(u8 reg, unsigned char value) +{ + u8 i; + + for (i = 0; i < AC107_CHIP_NUMS; i++) { + ac107_write(reg, value, i2c_ctrl[i]); + } + + return 0; +} + +static int ac107_multi_chips_update_bits(u8 reg, u8 mask, u8 value) +{ + u8 i; + + for (i = 0; i < AC107_CHIP_NUMS; i++) { + ac107_update_bits(reg, mask, value, i2c_ctrl[i]); + } + + return 0; +} + +static void ac107_hw_init(struct i2c_client *i2c) +{ + u8 reg_val; + + /*** Analog voltage enable ***/ + ac107_write(PWR_CTRL1, 0x80, i2c); /*0x01=0x80: VREF Enable */ + ac107_write(PWR_CTRL2, 0x55, i2c); /*0x02=0x55: MICBIAS1&2 Enable */ + + /*** SYSCLK Config ***/ + ac107_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_EN, 0x1 << SYSCLK_EN, i2c); /*SYSCLK Enable */ + ac107_write(MOD_CLK_EN, 0x07, i2c); /*0x21=0x07: Module clock enable */ + ac107_write(MOD_RST_CTRL, 0x03, i2c); /*0x22=0x03: Module reset de-asserted */ + + /*** I2S Common Config ***/ + ac107_update_bits(I2S_CTRL, 0x1 << SDO_EN, 0x1 << SDO_EN, i2c); /*SDO enable */ + ac107_update_bits(I2S_BCLK_CTRL, 0x1 << EDGE_TRANSFER, 0x0 << EDGE_TRANSFER, i2c); /*SDO drive data and SDI sample data at the different BCLK edge */ + ac107_update_bits(I2S_LRCK_CTRL1, 0x3 << LRCK_PERIODH, + ((AC107_LRCK_PERIOD - 1) >> 8) << LRCK_PERIODH, i2c); + ac107_write(I2S_LRCK_CTRL2, (u8) (AC107_LRCK_PERIOD - 1), i2c); /*config LRCK period */ + /*Encoding mode format select 0~N-1, Encoding mode enable, Turn to hi-z state (TDM) when not transferring slot */ + ac107_update_bits(I2S_FMT_CTRL1, + 0x1 << ENCD_FMT | 0x1 << ENCD_SEL | 0x1 << TX_SLOT_HIZ + | 0x1 << TX_STATE, + !!AC107_ENCODING_FMT << ENCD_FMT | + !!AC107_ENCODING_EN << ENCD_SEL | 0x0 << TX_SLOT_HIZ + | 0x1 << TX_STATE, i2c); + ac107_update_bits(I2S_FMT_CTRL2, 0x7 << SLOT_WIDTH_SEL, (AC107_SLOT_WIDTH / 4 - 1) << SLOT_WIDTH_SEL, i2c); /*8/12/16/20/24/28/32bit Slot Width */ + /*0x36=0x60: TX MSB first, SDOUT normal, PCM frame type, Linear PCM Data Mode */ + ac107_update_bits(I2S_FMT_CTRL3, + 0x1 << TX_MLS | 0x1 << SDOUT_MUTE | 0x1 << LRCK_WIDTH + | 0x3 << TX_PDM, + 0x0 << TX_MLS | 0x0 << SDOUT_MUTE | 0x0 << LRCK_WIDTH + | 0x0 << TX_PDM, i2c); + + ac107_update_bits(I2S_TX_CHMP_CTRL1, !AC107_DAPM_EN * 0xff, 0xaa, i2c); /*0x3c=0xaa: TX CH1/3/5/7 map to adc1, TX CH2/4/6/8 map to adc2 */ + ac107_update_bits(I2S_TX_CHMP_CTRL2, !AC107_DAPM_EN * 0xff, 0xaa, i2c); /*0x3d=0xaa: TX CH9/11/13/15 map to adc1, TX CH10/12/14/16 map to adc2 */ + + /*PDM Interface Latch ADC1 data on rising clock edge. Latch ADC2 data on falling clock edge, PDM Enable */ + ac107_update_bits(PDM_CTRL, 0x1 << PDM_TIMING | 0x1 << PDM_EN, + 0x0 << PDM_TIMING | !!AC107_PDM_EN << PDM_EN, i2c); + + /*** ADC DIG part Config***/ + ac107_update_bits(ADC_DIG_EN, !AC107_DAPM_EN * 0x7, 0x7, i2c); /*0x61=0x07: Digital part globe enable, ADCs digital part enable */ + ac107_update_bits(DMIC_EN, !AC107_DAPM_EN * 0x1, !!AC107_DMIC_EN, i2c); /*DMIC Enable */ + + /* ADC pattern select */ +#if AC107_KCONTROL_EN + ac107_read(ADC_DIG_DEBUG, ®_val, i2c); + ac107_write(HPF_EN, !(reg_val & 0x7) * 0x03, i2c); +#else + ac107_write(HPF_EN, !AC107_ADC_PATTERN_SEL * 0x03, i2c); + ac107_update_bits(ADC_DIG_DEBUG, 0x7 << ADC_PTN_SEL, + (AC107_ADC_PATTERN_SEL & 0x7) << ADC_PTN_SEL, i2c); +#endif + + //ADC Digital Volume Config + ac107_update_bits(ADC1_DVOL_CTRL, !AC107_KCONTROL_EN * 0xff, 0xA0, i2c); + ac107_update_bits(ADC2_DVOL_CTRL, !AC107_KCONTROL_EN * 0xff, 0xA0, i2c); + + /*** ADCs analog PGA gain Config***/ + ac107_update_bits(ANA_ADC1_CTRL3, + !AC107_KCONTROL_EN * 0x1f << RX1_PGA_GAIN_CTRL, + AC107_PGA_GAIN << RX1_PGA_GAIN_CTRL, i2c); + ac107_update_bits(ANA_ADC2_CTRL3, + !AC107_KCONTROL_EN * 0x1f << RX2_PGA_GAIN_CTRL, + AC107_PGA_GAIN << RX2_PGA_GAIN_CTRL, i2c); + + /*** ADCs analog global Enable***/ + ac107_update_bits(ANA_ADC1_CTRL5, !AC107_DAPM_EN * 0x1 << RX1_GLOBAL_EN, + 0x1 << RX1_GLOBAL_EN, i2c); + ac107_update_bits(ANA_ADC2_CTRL5, !AC107_DAPM_EN * 0x1 << RX2_GLOBAL_EN, + 0x1 << RX2_GLOBAL_EN, i2c); + + //VREF Fast Start-up Disable + ac107_update_bits(PWR_CTRL1, 0x1 << VREF_FSU_DISABLE, + 0x1 << VREF_FSU_DISABLE, i2c); +} + +static int ac107_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + AC107_DEBUG("\n--->%s\n", __FUNCTION__); + + switch (clk_id) { + case SYSCLK_SRC_MCLK: + AC107_DEBUG("AC107 SYSCLK source select MCLK\n\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << SYSCLK_SRC, SYSCLK_SRC_MCLK << SYSCLK_SRC); //System Clock Source Select MCLK + break; + case SYSCLK_SRC_BCLK: + AC107_DEBUG("AC107 SYSCLK source select BCLK\n\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << SYSCLK_SRC, SYSCLK_SRC_BCLK << SYSCLK_SRC); //System Clock Source Select BCLK + break; + case SYSCLK_SRC_PLL: + AC107_DEBUG("AC107 SYSCLK source select PLL\n\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << SYSCLK_SRC, SYSCLK_SRC_PLL << SYSCLK_SRC); //System Clock Source Select PLL + break; + default: + pr_err("AC107 SYSCLK source config error:%d\n\n", clk_id); + return -EINVAL; + } + + //SYSCLK Enable + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_EN, + 0x1 << SYSCLK_EN); + return 0; +} + +static int ac107_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + u32 i, m1, m2, n, k1, k2; + AC107_DEBUG("\n--->%s\n", __FUNCTION__); + + freq_in = freq_in / 2; + if (!freq_out) + return 0; + + if (freq_in < 128000 || freq_in > 24576000) { + pr_err + ("AC107 PLLCLK source input freq only support [128K,24M],while now %u\n\n", + freq_in); + return -EINVAL; + } else if ((freq_in == 12288000 || freq_in == 11289600) + && (pll_id == PLLCLK_SRC_MCLK || pll_id == PLLCLK_SRC_BCLK)) { + //System Clock Source Select MCLK/BCLK, SYSCLK Enable + AC107_DEBUG + ("AC107 don't need to use PLL, SYSCLK source select %s\n\n", + pll_id ? "BCLK" : "MCLK"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, + 0x3 << SYSCLK_SRC | 0x1 << + SYSCLK_EN, + pll_id << SYSCLK_SRC | 0x1 << + SYSCLK_EN); + return 0; //Don't need to use PLL + } + //PLL Clock Source Select + switch (pll_id) { + case PLLCLK_SRC_MCLK: + AC107_DEBUG("AC107 PLLCLK input source select MCLK\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << PLLCLK_SRC, + PLLCLK_SRC_MCLK << PLLCLK_SRC); + break; + case PLLCLK_SRC_BCLK: + AC107_DEBUG("AC107 PLLCLK input source select BCLK\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << PLLCLK_SRC, + PLLCLK_SRC_BCLK << PLLCLK_SRC); + break; + case PLLCLK_SRC_PDMCLK: + AC107_DEBUG("AC107 PLLCLK input source select PDMCLK\n"); + ac107_multi_chips_update_bits(SYSCLK_CTRL, 0x3 << PLLCLK_SRC, + PLLCLK_SRC_PDMCLK << PLLCLK_SRC); + break; + default: + pr_err("AC107 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(ac107_pll_div); i++) { + if (ac107_pll_div[i].freq_in == freq_in + && ac107_pll_div[i].freq_out == freq_out) { + m1 = ac107_pll_div[i].m1; + m2 = ac107_pll_div[i].m2; + n = ac107_pll_div[i].n; + k1 = ac107_pll_div[i].k1; + k2 = ac107_pll_div[i].k2; + AC107_DEBUG + ("AC107 PLL freq_in match:%u, freq_out:%u\n\n", + freq_in, freq_out); + break; + } + } + + if (i == ARRAY_SIZE(ac107_pll_div)) { + pr_err + ("AC107 don't match PLLCLK freq_in and freq_out table\n\n"); + return -EINVAL; + } + //Config PLL DIV param M1/M2/N/K1/K2 + ac107_multi_chips_update_bits(PLL_CTRL2, + 0x1f << PLL_PREDIV1 | 0x1 << PLL_PREDIV2, + m1 << PLL_PREDIV1 | m2 << PLL_PREDIV2); + ac107_multi_chips_update_bits(PLL_CTRL3, 0x3 << PLL_LOOPDIV_MSB, + (n >> 8) << PLL_LOOPDIV_MSB); + ac107_multi_chips_update_bits(PLL_CTRL4, 0xff << PLL_LOOPDIV_LSB, + (u8) n << PLL_LOOPDIV_LSB); + ac107_multi_chips_update_bits(PLL_CTRL5, + 0x1f << PLL_POSTDIV1 | 0x1 << + PLL_POSTDIV2, + k1 << PLL_POSTDIV1 | k2 << PLL_POSTDIV2); + + //Config PLL module current + //ac107_multi_chips_update_bits(PLL_CTRL1, 0x7<%s\n", __FUNCTION__); + + if (!div_id) { //use div_id to judge Master/Slave mode, 0: Slave mode, 1: Master mode + AC107_DEBUG + ("AC107 work as Slave mode, don't need to config BCLK_DIV\n\n"); + return 0; + } + + //bclk_div = div / (AC107_LRCK_PERIOD); //default PCM mode + bclk_div = div/(2*AC107_LRCK_PERIOD); //I2S/LJ/RJ mode + + for (i = 0; i < ARRAY_SIZE(ac107_bclk_div); i++) { + if (ac107_bclk_div[i].real_val == bclk_div) { + bclk_div_reg_val = ac107_bclk_div[i].reg_val; + AC107_DEBUG("AC107 set BCLK_DIV_[%u]\n\n", bclk_div); + break; + } + } + + if (i == ARRAY_SIZE(ac107_bclk_div)) { + pr_err("AC107 don't support BCLK_DIV_[%u]\n\n", bclk_div); + return -EINVAL; + } + //AC107 set BCLK DIV + ac107_multi_chips_update_bits(I2S_BCLK_CTRL, 0xf << BCLKDIV, + bclk_div_reg_val << BCLKDIV); + return 0; +} + +static int ac107_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + u8 i, tx_offset, i2s_mode, sign_ext, lrck_polarity, brck_polarity; + struct ac107_priv *ac107 = dev_get_drvdata(dai->dev); + AC107_DEBUG("\n--->%s\n", __FUNCTION__); + + //AC107 config Master/Slave mode + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: //AC107 Master + AC107_DEBUG("AC107 set to work as Master\n"); + ac107_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x3 << LRCK_IOEN, ac107->i2c); //BCLK & LRCK output + break; + case SND_SOC_DAIFMT_CBS_CFS: //AC107 Slave + AC107_DEBUG("AC107 set to work as Slave\n"); + ac107_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac107->i2c); //BCLK & LRCK input + break; + default: + pr_err("AC107 Master/Slave mode config error:%u\n\n", + (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12); + return -EINVAL; + } + for (i = 0; i < AC107_CHIP_NUMS; i++) { //multi_chips: only one chip set as Master, and the others also need to set as Slave + if (i2c_ctrl[i] == ac107->i2c) + continue; + ac107_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, + i2c_ctrl[i]); + } + + //AC107 config I2S/LJ/RJ/PCM format + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + AC107_DEBUG("AC107 config I2S format\n"); + i2s_mode = LEFT_JUSTIFIED_FORMAT; + tx_offset = 1; + sign_ext = TRANSFER_ZERO_AFTER; + break; + case SND_SOC_DAIFMT_RIGHT_J: + AC107_DEBUG("AC107 config RIGHT-JUSTIFIED format\n"); + i2s_mode = RIGHT_JUSTIFIED_FORMAT; + tx_offset = 0; + sign_ext = SIGN_EXTENSION_MSB; + break; + case SND_SOC_DAIFMT_LEFT_J: + AC107_DEBUG("AC107 config LEFT-JUSTIFIED format\n"); + i2s_mode = LEFT_JUSTIFIED_FORMAT; + tx_offset = 0; + sign_ext = TRANSFER_ZERO_AFTER; + break; + case SND_SOC_DAIFMT_DSP_A: + AC107_DEBUG("AC107 config PCM-A format\n"); + i2s_mode = PCM_FORMAT; + tx_offset = 1; + sign_ext = TRANSFER_ZERO_AFTER; + break; + case SND_SOC_DAIFMT_DSP_B: + AC107_DEBUG("AC107 config PCM-B format\n"); + i2s_mode = PCM_FORMAT; + tx_offset = 0; + sign_ext = TRANSFER_ZERO_AFTER; + break; + default: + pr_err("AC107 I2S format config error:%u\n\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + ac107_multi_chips_update_bits(I2S_FMT_CTRL1, + 0x3 << MODE_SEL | 0x1 << TX_OFFSET, + i2s_mode << MODE_SEL | tx_offset << + TX_OFFSET); + ac107_multi_chips_update_bits(I2S_FMT_CTRL3, 0x3 << SEXT, + sign_ext << SEXT); + + //AC107 config BCLK&LRCK polarity + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + AC107_DEBUG + ("AC107 config 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: + AC107_DEBUG + ("AC107 config 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: + AC107_DEBUG + ("AC107 config 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: + AC107_DEBUG + ("AC107 config 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("AC107 config BCLK/LRCLK polarity error:%u\n\n", + (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8); + return -EINVAL; + } + ac107_multi_chips_update_bits(I2S_BCLK_CTRL, 0x1 << BCLK_POLARITY, + brck_polarity << BCLK_POLARITY); + ac107_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x1 << LRCK_POLARITY, + lrck_polarity << LRCK_POLARITY); + + return 0; +} + +static int ac107_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u16 i, channels, channels_en, sample_resolution; + struct ac107_priv *ac107 = dev_get_drvdata(dai->dev); + AC107_DEBUG("\n--->%s\n", __FUNCTION__); + + //AC107 hw init + for (i = 0; i < AC107_CHIP_NUMS; i++) { + ac107_hw_init(i2c_ctrl[i]); + } + + //AC107 set sample rate + for (i = 0; i < ARRAY_SIZE(ac107_sample_rate); i++) { + if (ac107_sample_rate[i].real_val == + params_rate(params) / + (AC107_ENCODING_EN ? AC107_ENCODING_CH_NUMS / 2 : 1)) { + ac107_multi_chips_update_bits(ADC_SPRC, + 0xf << ADC_FS_I2S, + ac107_sample_rate + [i].reg_val << + ADC_FS_I2S); + break; + } + } + + //AC107 set channels + channels = + params_channels(params) * + (AC107_ENCODING_EN ? AC107_ENCODING_CH_NUMS / 2 : 1); + for (i = 0; i < (channels + 1) / 2; i++) { + channels_en = + (channels >= + 2 * (i + 1)) ? 0x0003 << (2 * i) : ((1 << (channels % 2)) - + 1) << (2 * i); + ac107_write(I2S_TX_CTRL1, channels - 1, i2c_ctrl[i]); + ac107_write(I2S_TX_CTRL2, (u8) channels_en, i2c_ctrl[i]); + ac107_write(I2S_TX_CTRL3, channels_en >> 8, i2c_ctrl[i]); + } + for (; i < AC107_CHIP_NUMS; i++) { + ac107_write(I2S_TX_CTRL1, 0, i2c_ctrl[i]); + ac107_write(I2S_TX_CTRL2, 0, i2c_ctrl[i]); + ac107_write(I2S_TX_CTRL3, 0, i2c_ctrl[i]); + } + + //AC107 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, + "AC107 don't supported the sample resolution: %u\n", + params_format(params)); + return -EINVAL; + } + ac107_multi_chips_update_bits(I2S_FMT_CTRL2, 0x7 << SAMPLE_RESOLUTION, + (sample_resolution / 4 - + 1) << SAMPLE_RESOLUTION); + + //AC107 TX enable, Globle enable + ac107_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, + 0x1 << TXEN | 0x1 << GEN); + + //AC107 PLL Enable and through MCLK Pin output Enable + ac107_read(SYSCLK_CTRL, (u8 *)&i, ac107->i2c); + if (i & 0x80) { //PLLCLK Enable + if (!(i & 0x0c)) { //SYSCLK select MCLK + //MCLK output Clock 24MHz from DPLL + ac107_update_bits(I2S_CTRL, 0x1 << MCLK_IOEN, + 0x1 << MCLK_IOEN, ac107->i2c); + ac107_update_bits(I2S_PADDRV_CTRL, 0x03 << MCLK_DRV, + 0x03 << MCLK_DRV, ac107->i2c); + for (i = 0; i < AC107_CHIP_NUMS; i++) { //multi_chips: only one chip MCLK output PLL_test, and the others MCLK config as input + if (i2c_ctrl[i] == ac107->i2c) + continue; + ac107_update_bits(I2S_CTRL, 0x1 << MCLK_IOEN, + 0x0 << MCLK_IOEN, + i2c_ctrl[i]); + } + //the chip which MCLK config as output, should select PLL as its SYCCLK source + ac107_update_bits(SYSCLK_CTRL, 0x3 << SYSCLK_SRC, + SYSCLK_SRC_PLL << SYSCLK_SRC, + ac107->i2c); + //the chip which MCLK config as output, PLL Common voltage Enable, PLL Enable + ac107_update_bits(PLL_CTRL1, + 0x1 << PLL_EN | 0x1 << PLL_COM_EN, + 0x1 << PLL_EN | 0x1 << PLL_COM_EN, + ac107->i2c); + } else if ((i & 0x0c) >> 2 == 0x2) { //SYSCLK select PLL + ac107_multi_chips_update_bits(PLL_LOCK_CTRL, + 0x7 << SYSCLK_HOLD_TIME, + 0x3 << SYSCLK_HOLD_TIME); + //All chips PLL Common voltage Enable, PLL Enable + ac107_multi_chips_update_bits(PLL_CTRL1, + 0x1 << PLL_EN | 0x1 << + PLL_COM_EN, + 0x1 << PLL_EN | 0x1 << + PLL_COM_EN); + } + } + + return 0; +} + +static int ac107_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u8 i, j; + AC107_DEBUG("\n--->%s\n", __FUNCTION__); + + //AC107 I2S Globle disable + ac107_multi_chips_update_bits(I2S_CTRL, 0x1 << GEN, 0x0 << GEN); + +#if AC107_KCONTROL_EN || AC107_DAPM_EN + for (i = 0; i < ARRAY_SIZE(ac107_reg_default_value); i++) { + for (j = 0; j < sizeof(ac107_kcontrol_dapm_reg); j++) { + if (ac107_reg_default_value[i].reg_addr == + ac107_kcontrol_dapm_reg[j]) + break; + } + if (j == sizeof(ac107_kcontrol_dapm_reg)) { + ac107_multi_chips_write(ac107_reg_default_value + [i].reg_addr, + ac107_reg_default_value + [i].default_val); + } + } + +#else + + AC107_DEBUG("AC107 reset all register to their default value\n\n"); + ac107_multi_chips_write(CHIP_AUDIO_RST, 0x12); +#endif + + return 0; +} + +/*** define ac107 dai_ops struct ***/ +static const struct snd_soc_dai_ops ac107_dai_ops = { + /*DAI clocking configuration */ + .set_sysclk = ac107_set_sysclk, + .set_pll = ac107_set_pll, + .set_clkdiv = ac107_set_clkdiv, + + /*ALSA PCM audio operations */ + .hw_params = ac107_hw_params, + .hw_free = ac107_hw_free, + + /*DAI format configuration */ + .set_fmt = ac107_set_fmt, +}; + +/*** define ac107 dai_driver struct ***/ +static struct snd_soc_dai_driver ac107_dai0 = { + .name = "ac107-pcm0", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai1 = { + .name = "ac107-pcm1", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai2 = { + .name = "ac107-pcm2", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai3 = { + .name = "ac107-pcm3", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai4 = { + .name = "ac107-pcm4", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai5 = { + .name = "ac107-pcm5", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai6 = { + .name = "ac107-pcm6", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver ac107_dai7 = { + .name = "ac107-pcm7", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC107_CHIP_NUMS * 2, + .rates = AC107_RATES, + .formats = AC107_FORMATS, + }, + .ops = &ac107_dai_ops, +}; + +static struct snd_soc_dai_driver *ac107_dai[] = { + &ac107_dai0, + &ac107_dai1, + &ac107_dai2, + &ac107_dai3, + &ac107_dai4, + &ac107_dai5, + &ac107_dai6, + &ac107_dai7, +}; + +static int ac107_probe(struct snd_soc_codec *codec) +{ + struct ac107_priv *ac107 = dev_get_drvdata(codec->dev); + int ret = 0; + + codec->control_data = + devm_regmap_init_i2c(ac107->i2c, &ac107_regmap_config); + ret = PTR_RET(codec->control_data); + if (ret) { + dev_err(codec->dev, "AC107 regmap init I2C Failed: %d\n", ret); + return ret; + } + ac107->codec = codec; + +#if AC107_KCONTROL_EN + ac107_multi_chips_update_bits(ANA_ADC1_CTRL3, 0x1f << RX1_PGA_GAIN_CTRL, AC107_PGA_GAIN << RX1_PGA_GAIN_CTRL); //ADC1 PGA Gain default + ac107_multi_chips_update_bits(ANA_ADC2_CTRL3, 0x1f << RX2_PGA_GAIN_CTRL, AC107_PGA_GAIN << RX2_PGA_GAIN_CTRL); //ADC2 PGA Gain default + snd_soc_add_codec_controls(codec, ac107_volume_controls, AC107_CHIP_NUMS * 2); //PGA Gain Control + snd_soc_add_codec_controls(codec, ac107_volume_controls + 16, AC107_CHIP_NUMS * 2); //Digital Volume Control +#endif + +#if AC107_DAPM_EN + ac107_multi_chips_write(I2S_TX_CHMP_CTRL1, 0xaa); //defatul map: TX CH1/3/5/7 map to adc1, TX CH2/4/6/8 map to adc2 + ac107_multi_chips_write(I2S_TX_CHMP_CTRL2, 0xaa); //defatul map: TX CH9/11/13/15 map to adc1, TX CH10/12/14/16 map to adc2 +#endif + + return 0; +} + +static int ac107_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static int ac107_suspend(struct snd_soc_codec *codec) +{ + struct ac107_priv *ac107 = dev_get_drvdata(codec->dev); + +#if AC107_MATCH_DTS_EN + if ((ac107_regulator_en & 0x1) && !IS_ERR(ac107->vol_supply.dvcc_1v8)) { + regulator_disable(ac107->vol_supply.dvcc_1v8); + ac107_regulator_en &= ~0x1; + } + + if ((ac107_regulator_en & 0x2) + && !IS_ERR(ac107->vol_supply.avcc_vccio_3v3)) { + regulator_disable(ac107->vol_supply.avcc_vccio_3v3); + ac107_regulator_en &= ~0x2; + } + if (gpio_is_valid(ac107->reset_gpio)) { + gpio_set_value(ac107->reset_gpio, 0); + gpio_free(ac107->reset_gpio); + } +#endif + + return 0; +} + +static int ac107_resume(struct snd_soc_codec *codec) +{ + struct ac107_priv *ac107 = dev_get_drvdata(codec->dev); + int ret; + +#if AC107_MATCH_DTS_EN + if (!(ac107_regulator_en & 0x1) && !IS_ERR(ac107->vol_supply.dvcc_1v8)) { + ret = regulator_enable(ac107->vol_supply.dvcc_1v8); + if (ret != 0) + pr_err + ("[AC107] %s: some error happen, fail to enable regulator dvcc_1v8!\n", + __func__); + ac107_regulator_en |= 0x1; + } + + if (!(ac107_regulator_en & 0x2) + && !IS_ERR(ac107->vol_supply.avcc_vccio_3v3)) { + ret = regulator_enable(ac107->vol_supply.avcc_vccio_3v3); + if (ret != 0) + pr_err + ("[AC107] %s: some error happen, fail to enable regulator avcc_vccio_3v3!\n", + __func__); + ac107_regulator_en |= 0x2; + } + if (gpio_is_valid(ac107->reset_gpio)) { + ret = gpio_request(ac107->reset_gpio, "reset gpio"); + if (!ret) { + gpio_direction_output(ac107->reset_gpio, 1); + gpio_set_value(ac107->reset_gpio, 1); + msleep(20); + } + } +#endif + + return 0; +} + +static unsigned int ac107_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + //AC107_DEBUG("\n--->%s\n",__FUNCTION__); + u8 val_r; + struct ac107_priv *ac107 = dev_get_drvdata(codec->dev); + + ac107_read(reg, &val_r, ac107->i2c); + return val_r; +} + +static int ac107_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + //AC107_DEBUG("\n--->%s\n",__FUNCTION__); + ac107_multi_chips_write(reg, value); + return 0; +} + +/*** define ac107 codec_driver struct ***/ +static const struct snd_soc_codec_driver ac107_soc_codec_driver = { + .probe = ac107_probe, + .remove = ac107_remove, + .suspend = ac107_suspend, + .resume = ac107_resume, + +#if AC107_CODEC_RW_USER_EN + .read = ac107_codec_read, + .write = ac107_codec_write, +#endif +/* +#if AC107_KCONTROL_EN + .controls = ac107_controls, + .num_controls = ARRAY_SIZE(ac107_controls), +#endif +*/ +#if AC107_DAPM_EN + .dapm_widgets = ac107_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ac107_dapm_widgets), + .dapm_routes = ac107_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ac107_dapm_routes), +#endif +}; + +static ssize_t ac107_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = 0, flag = 0; + u8 i = 0, reg, num, value_w, value_r; + + struct ac107_priv *ac107 = dev_get_drvdata(dev); + val = simple_strtol(buf, NULL, 16); + flag = (val >> 16) & 0xFF; + + if (flag) { + reg = (val >> 8) & 0xFF; + value_w = val & 0xFF; + printk("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n", + reg, value_w, flag); + while (flag--) { + ac107_write(reg, value_w, ac107->i2c); + printk("Write 0x%02x to REG:0x%02x\n", value_w, reg); + reg++; + } + } else { + reg = (val >> 8) & 0xFF; + num = val & 0xff; + printk("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num); + + do { + value_r = 0; + ac107_read(reg, &value_r, ac107->i2c); + printk("REG[0x%02x]: 0x%02x; ", reg, value_r); + reg++; + i++; + if ((i == num) || (i % 4 == 0)) + printk("\n"); + } while (i < num); + } + + return count; +} + +static ssize_t ac107_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + printk("/*** AC107 driver version: V1.0 ***/\n"); + printk("echo flag|reg|val > ac107\n"); + printk("eg->read start addres=0x00,count=0xff: echo 00ff >ac107\n"); + printk + ("eg->write start addres=0x70,value=0xa0,count=0x2: echo 270a0 >ac107\n"); + //printk("eg write value:0xfe to address:0x06 :echo 106fe > ac107\n"); + return 0; +} + +static DEVICE_ATTR(ac107, 0644, ac107_show, ac107_store); + +static struct attribute *ac107_debug_attrs[] = { + &dev_attr_ac107.attr, + NULL, +}; + +static struct attribute_group ac107_debug_attr_group = { + .name = "ac107_debug", + .attrs = ac107_debug_attrs, +}; + +static int ac107_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) +{ + struct ac107_priv *ac107; + struct device_node *np = i2c->dev.of_node; + const char *regulator_name = NULL; + int ret = 0; + struct gpio_config config; + + ac107 = devm_kzalloc(&i2c->dev, sizeof(struct ac107_priv), GFP_KERNEL); + if (ac107 == NULL) { + dev_err(&i2c->dev, "Unable to allocate ac107 private data\n"); + return -ENOMEM; + } + + ac107->i2c = i2c; + dev_set_drvdata(&i2c->dev, ac107); + +#if AC107_MATCH_DTS_EN + if (!ac107_regulator_en) { + ret = of_property_read_string(np, AC107_DVCC_NAME, ®ulator_name); //(const char**) + if (ret) { + pr_err("get ac107 DVCC regulator name failed \n"); + } else { + ac107->vol_supply.dvcc_1v8 = + regulator_get(NULL, regulator_name); + if (IS_ERR(ac107->vol_supply.dvcc_1v8) + || !ac107->vol_supply.dvcc_1v8) { + pr_err("get ac107 dvcc_1v8 failed, return!\n"); + return -EFAULT; + } + regulator_set_voltage(ac107->vol_supply.dvcc_1v8, + 1800000, 1800000); + ret = regulator_enable(ac107->vol_supply.dvcc_1v8); + if (ret != 0) + pr_err + ("[AC107] %s: some error happen, fail to enable regulator dvcc_1v8!\n", + __func__); + ac107_regulator_en |= 0x1; + } + + ret = of_property_read_string(np, AC107_AVCC_VCCIO_NAME, ®ulator_name); //(const char**) + if (ret) { + pr_err("get ac107 AVCC_VCCIO regulator name failed \n"); + } else { + ac107->vol_supply.avcc_vccio_3v3 = + regulator_get(NULL, regulator_name); + if (IS_ERR(ac107->vol_supply.avcc_vccio_3v3) + || !ac107->vol_supply.avcc_vccio_3v3) { + pr_err + ("get ac107 avcc_vccio_3v3 failed, return!\n"); + return -EFAULT; + } + regulator_set_voltage(ac107->vol_supply.avcc_vccio_3v3, + 3300000, 3300000); + ret = + regulator_enable(ac107->vol_supply.avcc_vccio_3v3); + if (ret != 0) + pr_err + ("[AC107] %s: some error happen, fail to enable regulator avcc_vccio_3v3!\n", + __func__); + ac107_regulator_en |= 0x2; + } + + /*gpio reset enable */ + ac107->reset_gpio = of_get_named_gpio_flags(np, + "gpio-reset", 0, + (enum of_gpio_flags + *)&config); + if (gpio_is_valid(ac107->reset_gpio)) { + ret = gpio_request(ac107->reset_gpio, "reset gpio"); + if (!ret) { + gpio_direction_output(ac107->reset_gpio, 1); + gpio_set_value(ac107->reset_gpio, 1); + msleep(20); + } else { + pr_err + ("%s, line:%d, failed request reset gpio: %d!\n", + __func__, __LINE__, ac107->reset_gpio); + } + } + } +#endif + + if (i2c_id->driver_data < AC107_CHIP_NUMS) { + i2c_ctrl[i2c_id->driver_data] = i2c; + ret = snd_soc_register_codec(&i2c->dev, &ac107_soc_codec_driver, + ac107_dai[i2c_id->driver_data], 1); + if (ret < 0) { + dev_err(&i2c->dev, + "Failed to register ac107 codec: %d\n", ret); + } + } else { + pr_err("The wrong i2c_id number :%d\n", + (int)(i2c_id->driver_data)); + } + + ret = sysfs_create_group(&i2c->dev.kobj, &ac107_debug_attr_group); + if (ret) { + pr_err("failed to create attr group\n"); + } + + return ret; +} + +static int ac107_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +#if !AC107_MATCH_DTS_EN +static int ac107_i2c_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + u8 ac107_chip_id; + struct i2c_adapter *adapter = client->adapter; + + ac107_read(CHIP_AUDIO_RST, &ac107_chip_id, client); + AC107_DEBUG("\nAC107_Chip_ID on I2C-%d:0x%02X\n", adapter->nr, + ac107_chip_id); + + if (ac107_chip_id == 0x4B) { + if (client->addr == 0x36) { + strlcpy(info->type, "ac107_0", I2C_NAME_SIZE); + return 0; + } else if (client->addr == 0x37) { + strlcpy(info->type, "ac107_1", I2C_NAME_SIZE); + return 0; + } else if (client->addr == 0x38) { + strlcpy(info->type, "ac107_2", I2C_NAME_SIZE); + return 0; + } else if (client->addr == 0x39) { + strlcpy(info->type, "ac107_3", I2C_NAME_SIZE); + return 0; + } + } + + return -ENODEV; +} +#endif + +static const unsigned short ac107_i2c_addr[] = { +#if AC107_CHIP_NUMS > 0 + 0x36, +#endif + +#if AC107_CHIP_NUMS > 1 + 0x37, +#endif + +#if AC107_CHIP_NUMS > 2 + 0x38, +#endif + +#if AC107_CHIP_NUMS > 3 + 0x39, +#endif + +#if AC107_CHIP_NUMS > 4 + 0x36, +#endif + +#if AC107_CHIP_NUMS > 5 + 0x37, +#endif + +#if AC107_CHIP_NUMS > 6 + 0x38, +#endif + +#if AC107_CHIP_NUMS > 7 + 0x39, +#endif + + I2C_CLIENT_END, +}; + +static struct i2c_board_info const ac107_i2c_board_info[] = { +#if AC107_CHIP_NUMS > 0 + {I2C_BOARD_INFO("ac107_0", 0x36),}, +#endif + +#if AC107_CHIP_NUMS > 1 + {I2C_BOARD_INFO("ac107_1", 0x37),}, +#endif + +#if AC107_CHIP_NUMS > 2 + {I2C_BOARD_INFO("ac107_2", 0x38),}, +#endif + +#if AC107_CHIP_NUMS > 3 + {I2C_BOARD_INFO("ac107_3", 0x39),}, +#endif + +#if AC107_CHIP_NUMS > 4 + {I2C_BOARD_INFO("ac107_4", 0x36),}, +#endif + +#if AC107_CHIP_NUMS > 5 + {I2C_BOARD_INFO("ac107_5", 0x37),}, +#endif + +#if AC107_CHIP_NUMS > 6 + {I2C_BOARD_INFO("ac107_6", 0x38),}, +#endif + +#if AC107_CHIP_NUMS > 7 + {I2C_BOARD_INFO("ac107_7", 0x39),}, +#endif + +}; + +static const struct i2c_device_id ac107_i2c_id[] = { +#if AC107_CHIP_NUMS > 0 + {"ac107_0", 0}, +#endif + +#if AC107_CHIP_NUMS > 1 + {"ac107_1", 1}, +#endif + +#if AC107_CHIP_NUMS > 2 + {"ac107_2", 2}, +#endif + +#if AC107_CHIP_NUMS > 3 + {"ac107_3", 3}, +#endif + +#if AC107_CHIP_NUMS > 4 + {"ac107_4", 4}, +#endif + +#if AC107_CHIP_NUMS > 5 + {"ac107_5", 5}, +#endif + +#if AC107_CHIP_NUMS > 6 + {"ac107_6", 6}, +#endif + +#if AC107_CHIP_NUMS > 7 + {"ac107_7", 7}, +#endif + + {} +}; + +MODULE_DEVICE_TABLE(i2c, ac107_i2c_id); + +static struct of_device_id ac107_dt_ids[] = { +#if AC107_CHIP_NUMS > 0 + {.compatible = "ac107_0",}, +#endif + +#if AC107_CHIP_NUMS > 1 + {.compatible = "ac107_1",}, +#endif + +#if AC107_CHIP_NUMS > 2 + {.compatible = "ac107_2",}, +#endif + +#if AC107_CHIP_NUMS > 3 + {.compatible = "ac107_3",}, +#endif + +#if AC107_CHIP_NUMS > 4 + {.compatible = "ac107_4",}, +#endif + +#if AC107_CHIP_NUMS > 5 + {.compatible = "ac107_5",}, +#endif + +#if AC107_CHIP_NUMS > 6 + {.compatible = "ac107_6",}, +#endif + +#if AC107_CHIP_NUMS > 7 + {.compatible = "ac107_7",}, +#endif + {}, +}; +MODULE_DEVICE_TABLE(of, ac107_dt_ids); + +static struct i2c_driver ac107_i2c_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ac107", + .owner = THIS_MODULE, +#if AC107_MATCH_DTS_EN + .of_match_table = ac107_dt_ids, +#endif + }, + .probe = ac107_i2c_probe, + .remove = ac107_i2c_remove, + .id_table = ac107_i2c_id, +#if !AC107_MATCH_DTS_EN + .address_list = ac107_i2c_addr, + .detect = ac107_i2c_detect, +#endif +}; + +static int __init ac107_init(void) +{ + int ret; + ret = i2c_add_driver(&ac107_i2c_driver); + if (ret != 0) + pr_err("Failed to register ac107 i2c driver : %d \n", ret); + + return ret; +} + +module_init(ac107_init); + +static void __exit ac107_exit(void) +{ + i2c_del_driver(&ac107_i2c_driver); +} + +module_exit(ac107_exit); + +MODULE_DESCRIPTION("ASoC ac107 codec driver"); +MODULE_AUTHOR("panjunwen"); +MODULE_LICENSE("GPL");