diff --git a/Makefile b/Makefile index a48acaf..fdd762c 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,10 @@ snd-soc-wm8960-objs := wm8960.o -snd-soc-ac108-objs := ac108.o -snd-soc-ac101-objs := ac101.o +snd-soc-ac108-objs := ac108.o ac101.o snd-soc-simple-card-objs := simple-card.o obj-m += snd-soc-wm8960.o obj-m += snd-soc-ac108.o -obj-m += snd-soc-ac101.o obj-m += snd-soc-simple-card.o @@ -17,7 +15,6 @@ clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean install: - sudo cp snd-soc-ac101.ko /lib/modules/$(shell uname -r)/kernel/sound/soc/codecs/ sudo cp snd-soc-ac108.ko /lib/modules/$(shell uname -r)/kernel/sound/soc/codecs/ sudo cp snd-soc-wm8960.ko /lib/modules/$(shell uname -r)/kernel/sound/soc/codecs/ sudo cp snd-soc-simple-card.ko /lib/modules/$(shell uname -r)/kernel/sound/soc/generic/ diff --git a/ac101.c b/ac101.c index 131f823..26f13f5 100644 --- a/ac101.c +++ b/ac101.c @@ -19,14 +19,12 @@ * the License, or (at your option) any later version. * */ -#undef AC10X_DEBG +#undef AC101_DEBG #include -#include #include #include #include #include -#include #include #include #include @@ -34,7 +32,8 @@ #include #include #include -#include "ac101.h" +#include "ac101_regs.h" +#include "ac10x.h" /*Default initialize configuration*/ static bool speaker_double_used = 1; @@ -47,165 +46,174 @@ static bool dmic_used = 0; static int adc_digital_val = 0xb0b0; static bool drc_used = false; -#define ac10x_RATES (SNDRV_PCM_RATE_8000_96000 & \ +#define AC101_RATES (SNDRV_PCM_RATE_8000_96000 & \ ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200)) -#define ac10x_FORMATS (/*SNDRV_PCM_FMTBIT_S16_LE | \ +#define AC101_FORMATS (/*SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE |*/ \ SNDRV_PCM_FMTBIT_S32_LE | \ 0) -/*struct for ac10x*/ -struct ac10x_priv { - struct snd_soc_codec *codec; - struct regmap* regmap; - - unsigned sysclk; - - struct mutex dac_mutex; - struct mutex adc_mutex; - u8 dac_enable; - struct mutex aifclk_mutex; - u8 aif1_clken; - u8 aif2_clken; - - struct work_struct codec_resume; - struct delayed_work dlywork; - - struct gpio_desc* gpiod_spk_amp_gate; -}; static struct ac10x_priv* static_ac10x; + +int ac101_read(struct snd_soc_codec *codec, unsigned reg) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + int r, v = 0; + + if ((r = regmap_read(ac10x->regmap101, reg, &v)) < 0) { + return r; + } + return v; +} + +int ac101_write(struct snd_soc_codec *codec, unsigned reg, unsigned val) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + return regmap_write(ac10x->regmap101, reg, val); +} + +int ac101_update_bits(struct snd_soc_codec *codec, unsigned reg, + unsigned mask, unsigned value +) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + return regmap_update_bits(ac10x->regmap101, reg, mask, value); +} + void drc_config(struct snd_soc_codec *codec) { int reg_val; - reg_val = snd_soc_read(codec, 0xa3); + reg_val = ac101_read(codec, 0xa3); reg_val &= ~(0x7ff<<0); reg_val |= 1<<0; - snd_soc_write(codec, 0xa3, reg_val); - snd_soc_write(codec, 0xa4, 0x2baf); + ac101_write(codec, 0xa3, reg_val); + ac101_write(codec, 0xa4, 0x2baf); - reg_val = snd_soc_read(codec, 0xa5); + reg_val = ac101_read(codec, 0xa5); reg_val &= ~(0x7ff<<0); reg_val |= 1<<0; - snd_soc_write(codec, 0xa5, reg_val); - snd_soc_write(codec, 0xa6, 0x2baf); + ac101_write(codec, 0xa5, reg_val); + ac101_write(codec, 0xa6, 0x2baf); - reg_val = snd_soc_read(codec, 0xa7); + reg_val = ac101_read(codec, 0xa7); reg_val &= ~(0x7ff<<0); - snd_soc_write(codec, 0xa7, reg_val); - snd_soc_write(codec, 0xa8, 0x44a); + ac101_write(codec, 0xa7, reg_val); + ac101_write(codec, 0xa8, 0x44a); - reg_val = snd_soc_read(codec, 0xa9); + reg_val = ac101_read(codec, 0xa9); reg_val &= ~(0x7ff<<0); - snd_soc_write(codec, 0xa9, reg_val); - snd_soc_write(codec, 0xaa, 0x1e06); + ac101_write(codec, 0xa9, reg_val); + ac101_write(codec, 0xaa, 0x1e06); - reg_val = snd_soc_read(codec, 0xab); + reg_val = ac101_read(codec, 0xab); reg_val &= ~(0x7ff<<0); reg_val |= (0x352<<0); - snd_soc_write(codec, 0xab, reg_val); - snd_soc_write(codec, 0xac, 0x6910); + ac101_write(codec, 0xab, reg_val); + ac101_write(codec, 0xac, 0x6910); - reg_val = snd_soc_read(codec, 0xad); + reg_val = ac101_read(codec, 0xad); reg_val &= ~(0x7ff<<0); reg_val |= (0x77a<<0); - snd_soc_write(codec, 0xad, reg_val); - snd_soc_write(codec, 0xae, 0xaaaa); + ac101_write(codec, 0xad, reg_val); + ac101_write(codec, 0xae, 0xaaaa); - reg_val = snd_soc_read(codec, 0xaf); + reg_val = ac101_read(codec, 0xaf); reg_val &= ~(0x7ff<<0); reg_val |= (0x2de<<0); - snd_soc_write(codec, 0xaf, reg_val); - snd_soc_write(codec, 0xb0, 0xc982); + ac101_write(codec, 0xaf, reg_val); + ac101_write(codec, 0xb0, 0xc982); - snd_soc_write(codec, 0x16, 0x9f9f); + ac101_write(codec, 0x16, 0x9f9f); } + void drc_enable(struct snd_soc_codec *codec,bool on) { int reg_val; if (on) { - snd_soc_write(codec, 0xb5, 0xA080); - reg_val = snd_soc_read(codec, MOD_CLK_ENA); + ac101_write(codec, 0xb5, 0xA080); + reg_val = ac101_read(codec, MOD_CLK_ENA); reg_val |= (0x1<<6); - snd_soc_write(codec, MOD_CLK_ENA, reg_val); - reg_val = snd_soc_read(codec, MOD_RST_CTRL); + ac101_write(codec, MOD_CLK_ENA, reg_val); + reg_val = ac101_read(codec, MOD_RST_CTRL); reg_val |= (0x1<<6); - snd_soc_write(codec, MOD_RST_CTRL, reg_val); + ac101_write(codec, MOD_RST_CTRL, reg_val); - reg_val = snd_soc_read(codec, 0xa0); + reg_val = ac101_read(codec, 0xa0); reg_val |= (0x7<<0); - snd_soc_write(codec, 0xa0, reg_val); + ac101_write(codec, 0xa0, reg_val); } else { - snd_soc_write(codec, 0xb5, 0x0); - reg_val = snd_soc_read(codec, MOD_CLK_ENA); + ac101_write(codec, 0xb5, 0x0); + reg_val = ac101_read(codec, MOD_CLK_ENA); reg_val &= ~(0x1<<6); - snd_soc_write(codec, MOD_CLK_ENA, reg_val); - reg_val = snd_soc_read(codec, MOD_RST_CTRL); + ac101_write(codec, MOD_CLK_ENA, reg_val); + reg_val = ac101_read(codec, MOD_RST_CTRL); reg_val &= ~(0x1<<6); - snd_soc_write(codec, MOD_RST_CTRL, reg_val); + ac101_write(codec, MOD_RST_CTRL, reg_val); - reg_val = snd_soc_read(codec, 0xa0); + reg_val = ac101_read(codec, 0xa0); reg_val &= ~(0x7<<0); - snd_soc_write(codec, 0xa0, reg_val); + ac101_write(codec, 0xa0, reg_val); } } + void set_configuration(struct snd_soc_codec *codec) { if (speaker_double_used) { - snd_soc_update_bits(codec, SPKOUT_CTRL, (0x1f<dac_mutex); switch (event) { case SND_SOC_DAPM_PRE_PMU: - AC10X_DBG("%s,line:%d\n",__func__,__LINE__); + AC101_DBG("%s,line:%d\n",__func__,__LINE__); if (ac10x->dac_enable == 0){ /*enable dac module clk*/ - snd_soc_update_bits(codec, MOD_CLK_ENA, (0x1<dac_enable++; break; @@ -233,11 +241,11 @@ static int late_enable_dac(struct snd_soc_codec* codec, int event) { if (ac10x->dac_enable != 0){ ac10x->dac_enable = 0; - snd_soc_update_bits(codec, DAC_DIG_CTRL, (0x1<aifclk_mutex); @@ -277,12 +285,12 @@ static int ac10x_aif1clk(struct snd_soc_codec* codec, int event) { case SND_SOC_DAPM_PRE_PMU: if (ac10x->aif1_clken == 0){ /*enable AIF1CLK*/ - snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken == 0) - snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif1_clken++; @@ -298,12 +306,12 @@ static int ac10x_aif1clk(struct snd_soc_codec* codec, int event) { ac10x->aif1_clken = 0; #endif /*disable AIF1CLK*/ - snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<aif2_clken == 0) - snd_soc_update_bits(codec, SYSCLK_CTRL, (0x1<private_value; + unsigned int val, mask = (1 << fls(mc->max)) - 1; + unsigned int invert = mc->invert; + int ret; + + if ((ret = ac101_read(static_ac10x->codec, mc->reg)) < 0) + return ret; + + val = (ret >> mc->shift) & mask; + ucontrol->value.integer.value[0] = val - mc->min; + if (invert) { + ucontrol->value.integer.value[0] = + mc->max - ucontrol->value.integer.value[0]; + } + return 0; +} + +/** + * snd_ac101_put_volsw - single mixer put callback + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Callback to set the value of a single mixer control, or a double mixer + * control that spans 2 registers. + * + * Returns 0 for success. + */ +static int snd_ac101_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol +){ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int sign_bit = mc->sign_bit; + unsigned int val, mask = (1 << fls(mc->max)) - 1; + unsigned int invert = mc->invert; + int ret; + + if (sign_bit) + mask = BIT(sign_bit + 1) - 1; + + val = ((ucontrol->value.integer.value[0] + mc->min) & mask); + if (invert) { + val = mc->max - val; + } + + mask = mask << mc->shift; + val = val << mc->shift; + + ret = ac101_update_bits(static_ac10x->codec, mc->reg, mask, val); + return ret; +} + + static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -11925, 75, 0); static const DECLARE_TLV_DB_SCALE(dac_mix_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(dig_vol_tlv, -7308, 116, 0); static const DECLARE_TLV_DB_SCALE(speaker_vol_tlv, -4800, 150, 0); static const DECLARE_TLV_DB_SCALE(headphone_vol_tlv, -6300, 100, 0); -static const struct snd_kcontrol_new ac10x_controls[] = { +static struct snd_kcontrol_new ac101_controls[] = { /*DAC*/ SOC_DOUBLE_TLV("DAC volume", DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R, 0xff, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC mixer gain", DAC_MXR_GAIN, DACL_MXR_GAIN, DACR_MXR_GAIN, 0xf, 0, dac_mix_vol_tlv), @@ -406,31 +481,35 @@ static const struct kv_map codec_aif1_wsize[] = { {32, 3}, }; -static const unsigned ac10x_bclkdivs[] = { +static const unsigned ac101_bclkdivs[] = { 1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 0, 0, }; -static int ac10x_aif_mute(struct snd_soc_dai *codec_dai, int mute) +int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); - AC10X_DBG("%s() L%d mute=%d\n", __func__, __LINE__, mute); + AC101_DBG("%s() L%d mute=%d\n", __func__, __LINE__, mute); - snd_soc_write(codec, DAC_VOL_CTRL, mute? 0: 0xA0A0); + ac101_write(codec, DAC_VOL_CTRL, mute? 0: 0xA0A0); if (!mute) { late_enable_dac(codec, SND_SOC_DAPM_PRE_PMU); - ac10x_headphone_event(codec, SND_SOC_DAPM_POST_PMU); + ac101_headphone_event(codec, SND_SOC_DAPM_POST_PMU); if (drc_used) { drc_enable(codec, 1); } if (ac10x->gpiod_spk_amp_gate) { gpiod_set_value(ac10x->gpiod_spk_amp_gate, 1); } + #if _MASTER_MULTI_CODEC != _MASTER_AC101 + /* enable global clock */ + ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_PRE_PMU); + #endif } else { if (ac10x->gpiod_spk_amp_gate) { gpiod_set_value(ac10x->gpiod_spk_amp_gate, 0); @@ -438,36 +517,90 @@ static int ac10x_aif_mute(struct snd_soc_dai *codec_dai, int mute) if (drc_used) { drc_enable(codec, 0); } - ac10x_headphone_event(codec, SND_SOC_DAPM_PRE_PMD); + ac101_headphone_event(codec, SND_SOC_DAPM_PRE_PMD); late_enable_dac(codec, SND_SOC_DAPM_POST_PMD); ac10x->aif1_clken = 1; - ac10x_aif1clk(codec, SND_SOC_DAPM_POST_PMD); + ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD); } return 0; } -static void ac10x_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) +void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; int reg_val; - AC10X_DBG("%s,line:%d\n", __func__, __LINE__); + AC101_DBG("%s,line:%d stream = %d, play-active = %d\n", __func__, __LINE__, + substream->stream, codec_dai->playback_active); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - reg_val = (snd_soc_read(codec, AIF_SR_CTRL) >> 12); - reg_val &= 0xf; + reg_val = (ac101_read(codec, AIF_SR_CTRL) >> 12) & 0xF; if (codec_dai->playback_active && dmic_used && reg_val == 0x4) { - snd_soc_update_bits(codec, AIF_SR_CTRL, (0xf<codec; -static int ac10x_set_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, - unsigned int freq_in, unsigned int freq_out); + AC101_DBG("%s, line:%d, pll_id:%d\n", __func__, __LINE__, pll_id); -static int ac10x_hw_params(struct snd_pcm_substream *substream, + if (!freq_out) + return 0; + if ((freq_in < 128000) || (freq_in > 24576000)) { + return -EINVAL; + } else if ((freq_in == 24576000) || (freq_in == 22579200)) { + if (pll_id == AC101_MCLK1) { + /*select aif1 clk source from mclk1*/ + ac101_update_bits(codec, SYSCLK_CTRL, (0x3<aif1_clken = 1; + ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD); + #endif /* get channels count & slot size */ channels = params_channels(params); @@ -504,16 +643,16 @@ static int ac10x_hw_params(struct snd_pcm_substream *substream, break; } } - snd_soc_update_bits(codec, AIF_CLK_CTRL, (0x7<capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) { - snd_soc_update_bits(codec, AIF_SR_CTRL, (0xf< 2) reg_val = 2; - snd_soc_update_bits(codec, AIF1_ADCDAT_CTRL, 0x3 << AIF1_SLOT_SIZ, reg_val << AIF1_SLOT_SIZ); + ac101_update_bits(codec, AIF1_ADCDAT_CTRL, 0x3 << AIF1_SLOT_SIZ, reg_val << AIF1_SLOT_SIZ); /* setting pll if it's master mode */ - reg_val = snd_soc_read(codec, AIF_CLK_CTRL); + reg_val = ac101_read(codec, AIF_CLK_CTRL); if ((reg_val & (0x1 << AIF1_MSTR_MOD)) == 0) { unsigned bclkdiv; - ac10x_set_pll(codec_dai, AC10X_MCLK1, 0, ac10x->sysclk, freq_out); + ac101_set_pll(codec_dai, AC101_MCLK1, 0, ac10x->sysclk, freq_out); bclkdiv = freq_out / (aif1_lrck_div * params_rate(params)); - for (i = 0; i < ARRAY_SIZE(ac10x_bclkdivs) - 1; i++) { - if (ac10x_bclkdivs[i] >= bclkdiv) { + for (i = 0; i < ARRAY_SIZE(ac101_bclkdivs) - 1; i++) { + if (ac101_bclkdivs[i] >= bclkdiv) { break; } } - snd_soc_update_bits(codec, AIF_CLK_CTRL, (0xf<codec; struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); - AC10X_DBG("%s,line:%d, id=%d freq=%d, dir=%d\n", __func__, __LINE__, + AC101_DBG("%s,line:%d, id=%d freq=%d, dir=%d\n", __func__, __LINE__, clk_id, freq, dir); ac10x->sysclk = freq; return 0; } +#endif -static int ac10x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { int reg_val; int AIF_CLK_CTRL = AIF1_CLK_CTRL; struct snd_soc_codec *codec = codec_dai->codec; - AC10X_DBG("%s() L%d\n", __func__, __LINE__); + AC101_DBG("%s() L%d\n", __func__, __LINE__); /* * master or slave selection * 0 = Master mode * 1 = Slave mode */ - reg_val = snd_soc_read(codec, AIF_CLK_CTRL); + reg_val = ac101_read(codec, AIF_CLK_CTRL); reg_val &= ~(0x1<codec; - - AC10X_DBG("%s, line:%d, pll_id:%d\n", __func__, __LINE__, pll_id); - - if (!freq_out) - return 0; - if ((freq_in < 128000) || (freq_in > 24576000)) { - return -EINVAL; - } else if ((freq_in == 24576000) || (freq_in == 22579200)) { - if (pll_id == AC10X_MCLK1) { - /*select aif1 clk source from mclk1*/ - snd_soc_update_bits(codec, SYSCLK_CTRL, (0x3<codec; - AC10X_DBG("%s,line:%d\n", __func__, __LINE__); + AC101_DBG("\n\n%s,line:%d\n", __func__, __LINE__); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { } return 0; } -static int ac10x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - AC10X_DBG("%s,line:%d, SND_SOC_BIAS_ON\n", __func__, __LINE__); - break; - case SND_SOC_BIAS_PREPARE: - AC10X_DBG("%s,line:%d, SND_SOC_BIAS_PREPARE\n", __func__, __LINE__); - break; - case SND_SOC_BIAS_STANDBY: - AC10X_DBG("%s,line:%d, SND_SOC_BIAS_STANDBY\n", __func__, __LINE__); - break; - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, OMIXER_DACA_CTRL, (0xf<codec, SND_SOC_DAPM_PRE_PMU); } - snd_soc_codec_get_dapm(codec)->bias_level = level; return 0; } +#endif -/* - * due to miss channels order in cpu_dai, we meed defer the clock starting. - */ -static void __ac10x_work_start_clock(struct work_struct *work) { - struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, dlywork.work); - - /* enable global clock */ - ac10x_aif1clk(ac10x->codec, SND_SOC_DAPM_PRE_PMU); - - return; -} - -extern int register_start_clock(int (*start_clock)(void)); - -static int ac10x_start_clock(void) { - schedule_delayed_work(&static_ac10x->dlywork, msecs_to_jiffies(30)); - return 0; -} - -static int ac10x_trigger(struct snd_pcm_substream *substream, int cmd, +#if 0 +static int ac101_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { int ret = 0; - AC10X_DBG("%s() stream=%d cmd=%d\n", + AC101_DBG("%s() stream=%d cmd=%d\n", __FUNCTION__, substream->stream, cmd); switch (cmd) { @@ -787,18 +843,18 @@ static int ac10x_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static const struct snd_soc_dai_ops ac10x_aif1_dai_ops = { - .set_sysclk = ac10x_set_dai_sysclk, - .set_fmt = ac10x_set_dai_fmt, - .hw_params = ac10x_hw_params, - .trigger = ac10x_trigger, - .shutdown = ac10x_aif_shutdown, - .digital_mute = ac10x_aif_mute, - .set_pll = ac10x_set_pll, - .startup = ac10x_audio_startup, +static const struct snd_soc_dai_ops ac101_aif1_dai_ops = { + //.startup = ac101_audio_startup, + //.shutdown = ac101_aif_shutdown, + //.set_sysclk = ac101_set_dai_sysclk, + //.set_pll = ac101_set_pll, + //.set_fmt = ac101_set_dai_fmt, + //.hw_params = ac101_hw_params, + //.trigger = ac101_trigger, + //.digital_mute = ac101_aif_mute, }; -static struct snd_soc_dai_driver ac10x_dai[] = { +static struct snd_soc_dai_driver ac101_dai[] = { { .name = "ac10x-aif1", .id = AIF1_CLK, @@ -806,43 +862,147 @@ static struct snd_soc_dai_driver ac10x_dai[] = { .stream_name = "Playback", .channels_min = 1, .channels_max = 8, - .rates = ac10x_RATES, - .formats = ac10x_FORMATS, + .rates = AC101_RATES, + .formats = AC101_FORMATS, }, #if 0 .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 8, - .rates = ac10x_RATES, - .formats = ac10x_FORMATS, + .rates = AC101_RATES, + .formats = AC101_FORMATS, }, #endif - .ops = &ac10x_aif1_dai_ops, + .ops = &ac101_aif1_dai_ops, } }; +#endif static void codec_resume_work(struct work_struct *work) { struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, codec_resume); struct snd_soc_codec *codec = ac10x->codec; - AC10X_DBG("%s() L%d +++\n", __func__, __LINE__); + AC101_DBG("%s() L%d +++\n", __func__, __LINE__); set_configuration(codec); if (drc_used) { drc_config(codec); } /*enable this bit to prevent leakage from ldoin*/ - snd_soc_update_bits(codec, ADDA_TUNE3, (0x1<bias_level = level; + return 0; +} + +int ac101_codec_probe(struct snd_soc_codec *codec) +{ + int ret = 0; + struct ac10x_priv *ac10x; + + ac10x = dev_get_drvdata(codec->dev); + if (ac10x == NULL) { + AC101_DBG("not set client data %s() L%d\n", __func__, __LINE__); + return -ENOMEM; + } + ac10x->codec = codec; + + INIT_WORK(&ac10x->codec_resume, codec_resume_work); + ac10x->dac_enable = 0; + ac10x->aif1_clken = 0; + ac10x->aif2_clken = 0; + mutex_init(&ac10x->dac_mutex); + mutex_init(&ac10x->adc_mutex); + mutex_init(&ac10x->aifclk_mutex); + + #if _MASTER_MULTI_CODEC == _MASTER_AC101 + asoc_simple_card_register_set_clock(ac101_set_clock); + #endif + + set_configuration(ac10x->codec); + + /*enable this bit to prevent leakage from ldoin*/ + ac101_update_bits(codec, ADDA_TUNE3, (0x1<get = snd_ac101_get_volsw; + skn->put = snd_ac101_put_volsw; + } + ret = snd_soc_add_codec_controls(codec, ac101_controls, ARRAY_SIZE(ac101_controls)); + if (ret) { + pr_err("[ac10x] Failed to register audio mode control, " + "will continue without it.\n"); + } + return 0; +} + +/* power down chip */ +int ac101_codec_remove(struct snd_soc_codec *codec) +{ + // struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + return 0; +} + +int ac101_codec_suspend(struct snd_soc_codec *codec) +{ + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + AC101_DBG("[codec]:suspend\n"); + regcache_cache_only(ac10x->regmap101, true); + return 0; +} + +int ac101_codec_resume(struct snd_soc_codec *codec) +{ + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + int ret; + + AC101_DBG("[codec]:resume"); + + /* Sync reg_cache with the hardware */ + regcache_cache_only(ac10x->regmap101, false); + ret = regcache_sync(ac10x->regmap101); + if (ret != 0) { + dev_err(codec->dev, "Failed to sync register cache: %d\n", ret); + regcache_cache_only(ac10x->regmap101, true); + return ret; + } + + ac101_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + schedule_work(&ac10x->codec_resume); + return 0; +} /***************************************************************************/ -static ssize_t ac10x_debug_store(struct device *dev, +static ssize_t ac101_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { static int val = 0, flag = 0; @@ -854,7 +1014,7 @@ static ssize_t ac10x_debug_store(struct device *dev, if(flag) { reg = (val >> 16) & 0xFF; value_w = val & 0xFFFF; - snd_soc_write(ac10x->codec, reg, value_w); + ac101_write(ac10x->codec, reg, value_w); printk("write 0x%x to reg:0x%x\n",value_w,reg); } else { reg =(val>>8)& 0xFF; @@ -862,7 +1022,7 @@ static ssize_t ac10x_debug_store(struct device *dev, printk("\n"); printk("read:start add:0x%x,count:0x%x\n",reg,num); do { - value_r[i] = snd_soc_read(ac10x->codec, reg); + value_r[i] = ac101_read(ac10x->codec, reg); printk("0x%x: 0x%04x ",reg,value_r[i]); reg+=1; i++; @@ -874,7 +1034,7 @@ static ssize_t ac10x_debug_store(struct device *dev, } return count; } -static ssize_t ac10x_debug_show(struct device *dev, +static ssize_t ac101_debug_show(struct device *dev, struct device_attribute *attr, char *buf) { printk("echo flag|reg|val > ac10x\n"); @@ -882,7 +1042,7 @@ static ssize_t ac10x_debug_show(struct device *dev, printk("eg write value:0x13fe to address:0x06 :echo 10613fe > ac10x\n"); return 0; } -static DEVICE_ATTR(ac10x, 0644, ac10x_debug_show, ac10x_debug_store); +static DEVICE_ATTR(ac10x, 0644, ac101_debug_show, ac101_debug_store); static struct attribute *audio_debug_attrs[] = { &dev_attr_ac10x.attr, @@ -890,9 +1050,10 @@ static struct attribute *audio_debug_attrs[] = { }; static struct attribute_group audio_debug_attr_group = { - .name = "ac10x_debug", + .name = "ac101_debug", .attrs = audio_debug_attrs, }; +/***************************************************************************/ /************************************************************/ static const struct regmap_config ac101_regmap = { @@ -903,111 +1064,24 @@ static const struct regmap_config ac101_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int ac10x_codec_probe(struct snd_soc_codec *codec) +int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct ac10x_priv *ac10x = i2c_get_clientdata(i2c); int ret = 0; - struct ac10x_priv *ac10x; + unsigned v = 0; - ac10x = dev_get_drvdata(codec->dev); - if (ac10x == NULL) { - AC10X_DBG("not set client data %s() L%d\n", __func__, __LINE__); - return -ENOMEM; - } - ac10x->codec = codec; + AC101_DBG("%s,line:%d\n", __func__, __LINE__); - INIT_DELAYED_WORK(&ac10x->dlywork, __ac10x_work_start_clock); - INIT_WORK(&ac10x->codec_resume, codec_resume_work); - ac10x->dac_enable = 0; - ac10x->aif1_clken = 0; - ac10x->aif2_clken = 0; - mutex_init(&ac10x->dac_mutex); - mutex_init(&ac10x->adc_mutex); - mutex_init(&ac10x->aifclk_mutex); - - register_start_clock(ac10x_start_clock); - - set_configuration(ac10x->codec); - - /*enable this bit to prevent leakage from ldoin*/ - snd_soc_update_bits(codec, ADDA_TUNE3, (0x1<regmap, true); - return 0; -} - -static int ac10x_codec_resume(struct snd_soc_codec *codec) -{ - struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); - int ret; - - AC10X_DBG("[codec]:resume"); - - /* Sync reg_cache with the hardware */ - regcache_cache_only(ac10x->regmap, false); - ret = regcache_sync(ac10x->regmap); - if (ret != 0) { - dev_err(codec->dev, "Failed to sync register cache: %d\n", ret); - regcache_cache_only(ac10x->regmap, true); - return ret; - } - - ac10x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - schedule_work(&ac10x->codec_resume); - return 0; -} -static struct snd_soc_codec_driver soc_codec_dev_sndvir_audio = { - .probe = ac10x_codec_probe, - .remove = ac10x_codec_remove, - .suspend = ac10x_codec_suspend, - .resume = ac10x_codec_resume, - .set_bias_level = ac10x_set_bias_level, - .ignore_pmdown_time = 1, -}; - -static int ac10x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) -{ - int ret = 0; - struct ac10x_priv *ac10x; - unsigned v; - - AC10X_DBG("%s,line:%d\n", __func__, __LINE__); - ac10x = devm_kzalloc(&i2c->dev, sizeof(struct ac10x_priv), GFP_KERNEL); - if (ac10x == NULL) { - AC10X_DBG("no memory %s() L%d\n", __func__, __LINE__); - return -ENOMEM; - } - i2c_set_clientdata(i2c, ac10x); static_ac10x = ac10x; - ac10x->regmap = devm_regmap_init_i2c(i2c, &ac101_regmap); - if (IS_ERR(ac10x->regmap)) { - ret = PTR_ERR(ac10x->regmap); + ac10x->regmap101 = devm_regmap_init_i2c(i2c, &ac101_regmap); + if (IS_ERR(ac10x->regmap101)) { + ret = PTR_ERR(ac10x->regmap101); dev_err(&i2c->dev, "Fail to initialize I/O: %d\n", ret); return ret; } - ret = regmap_read(ac10x->regmap, CHIP_AUDIO_RST, &v); + ret = regmap_read(ac10x->regmap101, CHIP_AUDIO_RST, &v); if (ret < 0) { dev_err(&i2c->dev, "failed to read vendor ID: %d\n", ret); return ret; @@ -1019,11 +1093,6 @@ static int ac10x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return -ENODEV; } - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_sndvir_audio, ac10x_dai, ARRAY_SIZE(ac10x_dai)); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to register ac10x: %d\n", ret); - } - ret = sysfs_create_group(&i2c->dev.kobj, &audio_debug_attr_group); if (ret) { pr_err("failed to create attr group\n"); @@ -1037,78 +1106,45 @@ static int ac10x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return 0; } -static void ac10x_shutdown(struct i2c_client *i2c) +void ac101_shutdown(struct i2c_client *i2c) { - int reg_val; - struct snd_soc_codec *codec = NULL; struct ac10x_priv *ac10x = i2c_get_clientdata(i2c); + struct snd_soc_codec *codec = ac10x->codec; + int reg_val; - if (ac10x->codec == NULL) { + if (codec == NULL) { pr_err("%s() L%d: no sound card.\n", __func__, __LINE__); return; } - codec = ac10x->codec; /*set headphone volume to 0*/ - reg_val = snd_soc_read(codec, HPOUT_CTRL); + reg_val = ac101_read(codec, HPOUT_CTRL); reg_val &= ~(0x3f<dev.kobj, &audio_debug_attr_group); - snd_soc_unregister_codec(&i2c->dev); - if (ac10x) { - kfree(ac10x); - } return 0; } -static const struct i2c_device_id ac10x_id[] = { - {"ac10x-codec", 0}, - {}, -}; -static const struct of_device_id ac101_of_match[] = { - { .compatible = "x-power,ac101", }, - { } -}; -MODULE_DEVICE_TABLE(of, ac101_of_match); - -static struct i2c_driver ac10x_codec_driver = { - .class = I2C_CLASS_HWMON, - .id_table = ac10x_id, - .driver = { - .name = "ac10x-codec", - .owner = THIS_MODULE, - .of_match_table = ac101_of_match, - }, - .probe = ac10x_probe, - .remove = ac10x_remove, - .shutdown = ac10x_shutdown, -}; -module_i2c_driver(ac10x_codec_driver); - MODULE_DESCRIPTION("ASoC ac10x driver"); MODULE_AUTHOR("huangxin,liushaohua"); MODULE_AUTHOR("PeterYang"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ac10x-codec"); - diff --git a/ac108.c b/ac108.c index dfa0359..fb441dc 100644 --- a/ac108.c +++ b/ac108.c @@ -25,8 +25,9 @@ #include #include #include "ac108.h" +#include "ac10x.h" -#define _USE_CAPTURE 0 +#define _USE_CAPTURE 1 #define _MASTER_INDEX 0 /** @@ -46,18 +47,6 @@ struct pll_div { unsigned int k2; }; -struct ac10x_priv { - struct i2c_client *i2c[4]; - int codec_index; - int sysclk; - unsigned mclk; /* master clock or aif_clock/aclk */ - int clk_id; - unsigned char i2s_mode; - unsigned char data_protocol; - struct delayed_work dlywork; - int trgr_cnt; - int tdm_chips_cnt; -}; static struct ac10x_priv *ac10x; struct real_val_to_reg_val { @@ -165,7 +154,7 @@ static const struct pll_div ac108_pll_div_list[] = { /* AC108 definition */ -#define AC108_CHANNELS_MAX 16 /* range[1, 16] */ +#define AC108_CHANNELS_MAX 8 /* range[1, 16] */ #define AC108_RATES (SNDRV_PCM_RATE_8000_96000 & \ ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200)) @@ -177,46 +166,79 @@ static const struct pll_div ac108_pll_div_list[] = { static const DECLARE_TLV_DB_SCALE(tlv_adc_pga_gain, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(tlv_ch_digital_vol, -11925,75,0); -static int ac10x_read(u8 reg, u8 *rt_value, struct i2c_client *client) { - int ret; +int ac10x_read(u8 reg, u8 *rt_value, struct i2c_client *client) { + int i = 0, ret; u8 read_cmd[3] = { reg, 0, 0 }; u8 cmd_len = 1; + #if _I2C_MUTEX_EN + mutex_lock(&ac10x->i2c_mutex); + #endif +//__retry: ret = i2c_master_send(client, read_cmd, cmd_len); if (ret != cmd_len) { - pr_err("ac10x_read error1\n"); - return -1; + /* + if (ret == -EAGAIN && i++ < 5) { + usleep_range(1, 100); + goto __retry; + } + */ + pr_err("ac10x_read error1 %d tried %d\n", ret, i); + ret = -1;goto __ret; } +//__retry2: ret = i2c_master_recv(client, rt_value, 1); if (ret != 1) { - pr_err("ac10x_read error2, ret = %d.\n", ret); - return -1; + /* + if (ret == -EAGAIN && i++ < 5) { + usleep_range(1, 100); + goto __retry2; + } + */ + pr_err("ac10x_read error2 %d tried %d.\n", ret, i); + ret = -2;goto __ret; } - - return 0; + ret = 0; +__ret: + #if _I2C_MUTEX_EN + mutex_unlock(&ac10x->i2c_mutex); + #endif + return ret; } -static int ac10x_write(u8 reg, unsigned char val, struct i2c_client *client) { +int ac10x_write(u8 reg, unsigned char val, struct i2c_client *client) { int ret = 0; u8 write_cmd[2] = { reg, val }; + #if _I2C_MUTEX_EN + mutex_lock(&ac10x->i2c_mutex); + #endif ret = i2c_master_send(client, write_cmd, 2); if (ret != 2) { pr_err("ac10x_write error->[REG-0x%02x,val-0x%02x]\n", reg, val); - return -1; + ret = -1; + } else { + ret = 0; } - return 0; + + #if _I2C_MUTEX_EN + mutex_unlock(&ac10x->i2c_mutex); + #endif + return ret; } -static int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct i2c_client *client) { +int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct i2c_client *client) { u8 val_old, val_new; + int ret; + + if ((ret = ac10x_read(reg, &val_old, client)) < 0) { + return ret; + } - ac10x_read(reg, &val_old, client); val_new = (val_old & ~mask) | (val & mask); if (val_new != val_old) { ac10x_write(reg, val_new, client); } - return 0; } @@ -237,16 +259,13 @@ static int snd_ac108_get_volsw(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = (1 << fls(mc->max)) - 1; unsigned int invert = mc->invert; - int chip = mc->autodisable; + int ret, chip = mc->autodisable; u8 val; - int ret; - ret = ac10x_read(mc->reg, &val, ac10x->i2c[chip]); - if (ret < 0) + if ((ret = ac10x_read(mc->reg, &val, ac10x->i2c[chip])) < 0) return ret; val = (val >> mc->shift) & mask; - ucontrol->value.integer.value[0] = val - mc->min; if (invert) { ucontrol->value.integer.value[0] = @@ -271,11 +290,9 @@ static int snd_ac108_put_volsw(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int sign_bit = mc->sign_bit; - unsigned int mask = (1 << fls(mc->max)) - 1; + unsigned int val, mask = (1 << fls(mc->max)) - 1; unsigned int invert = mc->invert; - unsigned int val, val_mask; - int chip = mc->autodisable; - int err; + int ret, chip = mc->autodisable; if (sign_bit) mask = BIT(sign_bit + 1) - 1; @@ -284,14 +301,12 @@ static int snd_ac108_put_volsw(struct snd_kcontrol *kcontrol, if (invert) { val = mc->max - val; } - val_mask = mask << mc->shift; + + mask = mask << mc->shift; val = val << mc->shift; - err = ac10x_update_bits(mc->reg, val_mask, val, ac10x->i2c[chip]); - if (err < 0) - return err; - - return err; + ret = ac10x_update_bits(mc->reg, mask, val, ac10x->i2c[chip]); + return ret; } #define SOC_AC108_SINGLE_TLV(xname, reg, shift, max, invert, chip, tlv_array) \ @@ -451,17 +466,6 @@ static const struct snd_soc_dapm_route ac108_dapm_routes[] = { }; -#if 0 -static int ac108_multi_chips_read(u8 reg, u8 *rt_value, struct ac10x_priv *ac10x) { - u8 i; - - for (i = 0; i < ac10x->codec_index; i++) { - ac10x_read(reg, rt_value++, ac10x->i2c[i]); - } - return 0; -} -#endif - static int ac108_multi_chips_write(u8 reg, u8 val, struct ac10x_priv *ac10x) { u8 i; for (i = 0; i < ac10x->codec_index; i++) { @@ -561,7 +565,7 @@ static int ac108_configure_clocking(struct ac10x_priv *ac10x, unsigned int rate) ac108_multi_chips_update_bits(PLL_LOCK_CTRL, 0x1 << PLL_LOCK_EN, 0x1 << PLL_LOCK_EN, ac10x); /*0x10: PLL Common voltage Enable, PLL Enable,PLL loop divider factor detection enable*/ ac108_multi_chips_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN | 0x01 << PLL_NDET, - 0x1 << PLL_EN | 0x1 << PLL_COM_EN | 0x01 << PLL_NDET, ac10x); + 0x01 << PLL_EN | 0x01 << PLL_COM_EN | 0x01 << PLL_NDET, ac10x); /** * 0x20: enable pll,pll source from mclk, sysclk source from @@ -657,20 +661,26 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h struct snd_soc_codec *codec = dai->codec; struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); unsigned bclkdiv; - u8 r; + int ret = 0; + u8 v; - dev_dbg(dai->dev, "%s() stream=%d\n", __func__, substream->stream); + dev_dbg(dai->dev, "%s() stream=%d play:%d capt:%d +++\n", __func__, + substream->stream, dai->playback_active, dai->capture_active); + + if (ac10x->i2c101) { + ret = ac101_hw_params(substream, params, dai); + } /* nothing should be done when it isn't capturing stream. */ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) { - return 0; + // TODO: } channels = params_channels(params); /* Master mode, to clear cpu_dai fifos, output bclk without lrck */ - ac10x_read(I2S_CTRL, &r, ac10x->i2c[_MASTER_INDEX]); - if (r & (0x02 << LRCK_IOEN)) { + ac10x_read(I2S_CTRL, &v, ac10x->i2c[_MASTER_INDEX]); + if (v & (0x02 << LRCK_IOEN)) { ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x02 << LRCK_IOEN, ac10x->i2c[_MASTER_INDEX]); } @@ -780,7 +790,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h */ ac108_multi_chips_slots(ac10x, channels); - ac10x->trgr_cnt = 0; + dev_dbg(dai->dev, "%s() stream=%d ---\n", __func__, substream->stream); return 0; } @@ -830,7 +840,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: /*AC108 Master*/ - if (ac10x->tdm_chips_cnt < 2) { + if (ac10x->tdm_chips_cnt < 2 || _MASTER_MULTI_CODEC == _MASTER_AC108) { dev_dbg(dai->dev, "AC108 set to work as Master\n"); /** * 0x30:chip is master mode ,BCLK & LRCK output @@ -965,26 +975,40 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { ac108_multi_chips_write(HPF_EN, 0x00, ac10x); + if (ac10x->i2c101) { + return ac101_set_dai_fmt(dai, fmt); + } return 0; } /* * due to miss channels order in cpu_dai, we meed defer the clock starting. */ -static void ac108_work_start_clock(struct work_struct *work) { - struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, dlywork.work); +static int ac108_set_clock(int y_start_n_stop) { u8 r; - /* enable lrck clock */ - ac10x_read(I2S_CTRL, &r, ac10x->i2c[_MASTER_INDEX]); - if (r & (0x02 << LRCK_IOEN)) { - ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac10x->i2c[_MASTER_INDEX]); + dev_dbg(ac10x->codec->dev, "%s() L%d start:%d\n", __func__, __LINE__, y_start_n_stop); + + if (y_start_n_stop) { + /* enable lrck clock */ + ac10x_read(I2S_CTRL, &r, ac10x->i2c[_MASTER_INDEX]); + if (r & (0x02 << LRCK_IOEN)) { + ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac10x->i2c[_MASTER_INDEX]); + } + + /* enable global clock */ + ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x); + } else { + /* disable lrck clock if it's enabled */ + ac10x_read(I2S_CTRL, &r, ac10x->i2c[_MASTER_INDEX]); + if (r & (0x01 << LRCK_IOEN)) { + ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x); + ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x02 << LRCK_IOEN, ac10x->i2c[_MASTER_INDEX]); + ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x); + } } - /* enable global clock */ - ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x); - - return; + return 0; } static int ac108_trigger(struct snd_pcm_substream *substream, int cmd, @@ -993,6 +1017,7 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_codec *codec = dai->codec; struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); int ret = 0; + u8 r; dev_dbg(dai->dev, "%s() stream=%d cmd=%d\n", __FUNCTION__, substream->stream, cmd); @@ -1001,20 +1026,20 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (ac10x->trgr_cnt++ > 0) { - break; + /* disable global clock if lrck disabled */ + ac10x_read(I2S_CTRL, &r, ac10x->i2c[_MASTER_INDEX]); + if ((r & (0x01 << LRCK_IOEN)) == 0) { + /* disable global clock */ + ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x); + + /*0x21: Module clock enable*/ + ac108_multi_chips_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x); + + /*0x22: Module reset de-asserted*/ + ac108_multi_chips_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x); + + /* delayed clock starting, move to simple_card_trigger() */ } - /* disable global clock */ - ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x); - - /*0x21: Module clock enable*/ - ac108_multi_chips_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x); - - /*0x22: Module reset de-asserted*/ - ac108_multi_chips_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x); - - /* delayed clock starting */ - schedule_delayed_work(&ac10x->dlywork, msecs_to_jiffies(30)); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -1027,19 +1052,55 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +int ac108_audio_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai +) { + struct snd_soc_codec *codec = dai->codec; + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + if (ac10x->i2c101) { + return ac101_audio_startup(substream, dai); + } + return 0; +} + +void ac108_aif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai +) { + struct snd_soc_codec *codec = dai->codec; + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + if (ac10x->i2c101) { + ac101_aif_shutdown(substream, dai); + } +} + +int ac108_aif_mute(struct snd_soc_dai *dai, int mute) { + struct snd_soc_codec *codec = dai->codec; + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + if (ac10x->i2c101) { + return ac101_aif_mute(dai, mute); + } + return 0; +} static const struct snd_soc_dai_ops ac108_dai_ops = { + .startup = ac108_audio_startup, + .shutdown = ac108_aif_shutdown, + /*DAI clocking configuration*/ - .set_sysclk = ac108_set_sysclk, + .set_sysclk = ac108_set_sysclk, /*ALSA PCM audio operations*/ - .hw_params = ac108_hw_params, - .trigger = ac108_trigger, - - // .hw_free = ac108_hw_free, + .hw_params = ac108_hw_params, + .trigger = ac108_trigger, + .digital_mute = ac108_aif_mute, /*DAI format configuration*/ - .set_fmt = ac108_set_fmt, + .set_fmt = ac108_set_fmt, + + // .hw_free = ac108_hw_free, }; static struct snd_soc_dai_driver ac108_dai0 = { @@ -1150,14 +1211,17 @@ static int ac108_add_widgets(struct snd_soc_codec *codec) { return 0; } - static int ac108_probe(struct snd_soc_codec *codec) { + ac10x->codec = codec; dev_set_drvdata(codec->dev, ac10x); ac108_add_widgets(codec); + + if (ac10x->i2c101) { + ac101_codec_probe(codec); + } return 0; } - static int ac108_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); @@ -1186,18 +1250,49 @@ static int ac108_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_l break; } + if (ac10x->i2c101) { + ac101_set_bias_level(codec, level); + } return 0; } +int ac108_codec_remove(struct snd_soc_codec *codec) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); -static const struct snd_soc_codec_driver ac108_soc_codec_driver = { - .probe = ac108_probe, + if (! ac10x->i2c101) { + return 0; + } + return ac101_codec_remove(codec); +} + +int ac108_codec_suspend(struct snd_soc_codec *codec) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + if (! ac10x->i2c101) { + return 0; + } + return ac101_codec_suspend(codec); +} + +int ac108_codec_resume(struct snd_soc_codec *codec) { + struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); + + if (! ac10x->i2c101) { + return 0; + } + return ac101_codec_resume(codec); +} + +static struct snd_soc_codec_driver ac10x_soc_codec_driver = { + .probe = ac108_probe, + .remove = ac108_codec_remove, + .suspend = ac108_codec_suspend, + .resume = ac108_codec_resume, .set_bias_level = ac108_set_bias_level, - .read = ac108_codec_read, - .write = ac108_codec_write, + .read = ac108_codec_read, + .write = ac108_codec_write, }; - static ssize_t ac108_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[4]; @@ -1241,25 +1336,22 @@ static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, co static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf) { #if 1 - printk("echo flag|reg|val > ac10x\n"); - printk("eg read star addres=0x06,count 0x10:echo 0610 >ac10x\n"); - printk("eg write value:0xfe to address:0x06 :echo 106fe > ac10x\n"); + printk("echo flag|reg|val > ac108\n"); + printk("eg read star addres=0x06,count 0x10:echo 0610 >ac108\n"); + printk("eg write value:0xfe to address:0x06 :echo 106fe > ac108\n"); return 0; #else - return snprintf(buf, PAGE_SIZE, - "echo flag|reg|val > ac10x\n" - "eg read star addres=0x06,count 0x10:echo 0610 >ac10x\n" - "eg write value:0xfe to address:0x06 :echo 106fe > ac10x\n"); + return snprintf(buf, PAGE_SIZE,"echo flag|reg|val > ac108\n" + "eg read star addres=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, @@ -1267,9 +1359,9 @@ static struct attribute_group ac108_debug_attr_group = { static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { - int ret = 0; struct device_node *np = i2c->dev.of_node; unsigned int val = 0; + int ret = 0; if (ac10x == NULL) { ac10x = devm_kzalloc(&i2c->dev, sizeof(struct ac10x_priv), GFP_KERNEL); @@ -1277,7 +1369,16 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i dev_err(&i2c->dev, "Unable to allocate ac10x private data\n"); return -ENOMEM; } - INIT_DELAYED_WORK(&ac10x->dlywork, ac108_work_start_clock); + #if _I2C_MUTEX_EN + mutex_init(&ac10x->i2c_mutex); + #endif + } + + if ((int)i2c_id->driver_data == AC101_I2C_ID) { + ac10x->i2c101 = i2c; + i2c_set_clientdata(i2c, ac10x); + ret = ac101_probe(i2c, i2c_id); + goto __ret; } ret = of_property_read_u32(np, "data-protocol", &val); @@ -1304,25 +1405,39 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i ac10x->i2c[i2c_id->driver_data] = i2c; ac10x->codec_index++; - /* when all i2c prepared, we bind codec to i2c[_MASTER_INDEX] */ - if (ac10x->codec_index == ac10x->tdm_chips_cnt) { - ret = snd_soc_register_codec(&ac10x->i2c[_MASTER_INDEX]->dev, &ac108_soc_codec_driver, - ac108_dai[_MASTER_INDEX], 1); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to register ac10x codec: %d\n", ret); - } - } - ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group); if (ret) { pr_err("failed to create attr group\n"); } +__ret: + /* when all i2c prepared, we bind codec to i2c[_MASTER_INDEX] */ + if ((ac10x->codec_index != 0 && ac10x->tdm_chips_cnt < 2) + || (ac10x->codec_index == ac10x->tdm_chips_cnt && ac10x->i2c101)) { + #if _MASTER_MULTI_CODEC == _MASTER_AC108 + asoc_simple_card_register_set_clock(ac108_set_clock); + #endif + /* no playback stream */ + if (! ac10x->i2c101) { + memset(&ac108_dai[_MASTER_INDEX]->playback, '\0', sizeof ac108_dai[_MASTER_INDEX]->playback); + } + ret = snd_soc_register_codec(&ac10x->i2c[_MASTER_INDEX]->dev, &ac10x_soc_codec_driver, + ac108_dai[_MASTER_INDEX], 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register ac10x codec: %d\n", ret); + } + } return ret; } -static int ac108_i2c_remove(struct i2c_client *client) { - snd_soc_unregister_codec(&client->dev); +static int ac108_i2c_remove(struct i2c_client *i2c) { + if (ac10x->i2c101) { + ac101_remove(ac10x->i2c101); + } + if (ac10x->codec != NULL) { + snd_soc_unregister_codec(&ac10x->i2c[_MASTER_INDEX]->dev); + ac10x->codec = NULL; + } return 0; } @@ -1331,6 +1446,7 @@ static const struct i2c_device_id ac108_i2c_id[] = { { "ac108_1", 1 }, { "ac108_2", 2 }, { "ac108_3", 3 }, + { "ac101", AC101_I2C_ID }, { } }; MODULE_DEVICE_TABLE(i2c, ac108_i2c_id); @@ -1340,6 +1456,7 @@ static const struct of_device_id ac108_of_match[] = { { .compatible = "x-power,ac108_1", }, { .compatible = "x-power,ac108_2", }, { .compatible = "x-power,ac108_3", }, + { .compatible = "x-power,ac101", }, { } }; MODULE_DEVICE_TABLE(of, ac108_of_match); diff --git a/ac10x.h b/ac10x.h index 2747655..1b3cc5e 100644 --- a/ac10x.h +++ b/ac10x.h @@ -16,6 +16,9 @@ #define __AC10X_H__ #define AC101_I2C_ID 4 +#define _MASTER_AC108 0 +#define _MASTER_AC101 1 +#define _MASTER_MULTI_CODEC _MASTER_AC108 #ifdef AC101_DEBG #define AC101_DBG(format,args...) printk("[AC101] "format,##args) @@ -23,8 +26,13 @@ #define AC101_DBG(...) #endif +#define _I2C_MUTEX_EN 1 + struct ac10x_priv { struct i2c_client *i2c[4]; + #if _I2C_MUTEX_EN + struct mutex i2c_mutex; + #endif int codec_index; unsigned sysclk; unsigned mclk; /* master clock or aif_clock/aclk */ @@ -32,7 +40,6 @@ struct ac10x_priv { unsigned char i2s_mode; unsigned char data_protocol; struct delayed_work dlywork; - int trgr_cnt; int tdm_chips_cnt; /* struct for ac101 .begin */ @@ -48,6 +55,7 @@ struct ac10x_priv { u8 aif2_clken; struct work_struct codec_resume; + struct delayed_work dlywork101; struct gpio_desc* gpiod_spk_amp_gate; /* struct for ac101 .end */ }; @@ -78,4 +86,7 @@ int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id); void ac101_shutdown(struct i2c_client *i2c); int ac101_remove(struct i2c_client *i2c); +/* simple card export */ +int asoc_simple_card_register_set_clock(int (*set_clock)(int)); + #endif//__AC10X_H__ diff --git a/seeed-8mic-voicecard-overlay.dts b/seeed-8mic-voicecard-overlay.dts index 5c69c4b..9e6f89b 100644 --- a/seeed-8mic-voicecard-overlay.dts +++ b/seeed-8mic-voicecard-overlay.dts @@ -103,28 +103,6 @@ system-clock-id = <1>; }; }; - - simple-audio-card,dai-link@1 { - format = "dsp_a"; - bitclock-master = <&codec1_dai>; - frame-master = <&codec1_dai>; - /* bitclock-inversion; */ - /* frame-inversion; */ - - cpu { - sound-dai = <&i2s>; - dai-tdm-slot-num = <2>; - dai-tdm-slot-width = <32>; - dai-tdm-slot-tx-mask = <1 1 0 0>; - dai-tdm-slot-rx-mask = <1 1 0 0>; - }; - - codec1_dai: codec { - sound-dai = <&ac101>; - clocks = <&ac10x_mclk>; - system-clock-id = <1>; - }; - }; }; }; diff --git a/seeed-8mic-voicecard.dtbo b/seeed-8mic-voicecard.dtbo index 20e533a..aee93d9 100644 Binary files a/seeed-8mic-voicecard.dtbo and b/seeed-8mic-voicecard.dtbo differ diff --git a/simple-card.c b/simple-card.c index e2a102e..915bc78 100644 --- a/simple-card.c +++ b/simple-card.c @@ -202,32 +202,35 @@ err: return ret; } -static int (* _start_clock)(void); +static int (* _set_clock)(int y_start_n_stop); -int register_start_clock(int (*start_clock)(void)) { - _start_clock = start_clock; +int asoc_simple_card_register_set_clock(int (*set_clock)(int)) { + _set_clock = set_clock; return 0; } -EXPORT_SYMBOL(register_start_clock); +EXPORT_SYMBOL(asoc_simple_card_register_set_clock); static int asoc_simple_card_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->codec_dai; int ret = 0; - dev_dbg(rtd->card->dev, "%s() stream=%d cmd=%d\n", - __FUNCTION__, substream->stream, cmd); + dev_dbg(rtd->card->dev, "%s() stream=%d cmd=%d play:%d, capt:%d\n", + __FUNCTION__, substream->stream, cmd, + dai->playback_active, dai->capture_active); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (_start_clock) _start_clock(); + if (_set_clock) _set_clock(1); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (_set_clock) _set_clock(0); break; default: ret = -EINVAL; diff --git a/snd-soc-wm8960.mod.c b/snd-soc-wm8960.mod.c deleted file mode 100644 index b75d7be..0000000 --- a/snd-soc-wm8960.mod.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include - -MODULE_INFO(vermagic, VERMAGIC_STRING); - -__visible struct module __this_module -__attribute__((section(".gnu.linkonce.this_module"))) = { - .name = KBUILD_MODNAME, - .init = init_module, -#ifdef CONFIG_MODULE_UNLOAD - .exit = cleanup_module, -#endif - .arch = MODULE_ARCH_INIT, -}; - -static const struct modversion_info ____versions[] -__used -__attribute__((section("__versions"))) = { - { 0xdb0d8ebc, __VMLINUX_SYMBOL_STR(module_layout) }, - { 0xb077e70a, __VMLINUX_SYMBOL_STR(clk_unprepare) }, - { 0xe56a9336, __VMLINUX_SYMBOL_STR(snd_pcm_format_width) }, - { 0xf9a482f9, __VMLINUX_SYMBOL_STR(msleep) }, - { 0xeb711ae7, __VMLINUX_SYMBOL_STR(snd_soc_params_to_bclk) }, - { 0x815588a6, __VMLINUX_SYMBOL_STR(clk_enable) }, - { 0x2e5810c6, __VMLINUX_SYMBOL_STR(__aeabi_unwind_cpp_pr1) }, - { 0xd9ead207, __VMLINUX_SYMBOL_STR(i2c_del_driver) }, - { 0xaa3b6018, __VMLINUX_SYMBOL_STR(snd_soc_dapm_get_volsw) }, - { 0x52eb2dc5, __VMLINUX_SYMBOL_STR(regmap_update_bits_base) }, - { 0xb6e6d99d, __VMLINUX_SYMBOL_STR(clk_disable) }, - { 0xf7802486, __VMLINUX_SYMBOL_STR(__aeabi_uidivmod) }, - { 0x70139129, __VMLINUX_SYMBOL_STR(snd_soc_add_codec_controls) }, - { 0xb1ad28e0, __VMLINUX_SYMBOL_STR(__gnu_mcount_nc) }, - { 0xb7051343, __VMLINUX_SYMBOL_STR(snd_soc_dapm_new_controls) }, - { 0xcb5daba2, __VMLINUX_SYMBOL_STR(snd_soc_put_volsw) }, - { 0x66da0eca, __VMLINUX_SYMBOL_STR(snd_soc_get_volsw) }, - { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, - { 0x37dc1ecd, __VMLINUX_SYMBOL_STR(snd_soc_info_enum_double) }, - { 0x82108f90, __VMLINUX_SYMBOL_STR(snd_soc_dapm_add_routes) }, - { 0xe707d823, __VMLINUX_SYMBOL_STR(__aeabi_uidiv) }, - { 0xe872d1ce, __VMLINUX_SYMBOL_STR(snd_soc_read) }, - { 0x1b55d4fa, __VMLINUX_SYMBOL_STR(dev_err) }, - { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, - { 0xac92dc30, __VMLINUX_SYMBOL_STR(snd_soc_update_bits) }, - { 0x3e9d3734, __VMLINUX_SYMBOL_STR(of_find_property) }, - { 0x8b4dfb4c, __VMLINUX_SYMBOL_STR(snd_soc_dapm_put_volsw) }, - { 0xa0195a8c, __VMLINUX_SYMBOL_STR(snd_ctl_boolean_mono_info) }, - { 0x2196324, __VMLINUX_SYMBOL_STR(__aeabi_idiv) }, - { 0x59e5070d, __VMLINUX_SYMBOL_STR(__do_div64) }, - { 0x94680ad3, __VMLINUX_SYMBOL_STR(snd_soc_info_volsw) }, - { 0xf204b815, __VMLINUX_SYMBOL_STR(i2c_register_driver) }, - { 0x34cffba9, __VMLINUX_SYMBOL_STR(snd_soc_get_enum_double) }, - { 0xff227eee, __VMLINUX_SYMBOL_STR(__devm_regmap_init_i2c) }, - { 0x7c9a7371, __VMLINUX_SYMBOL_STR(clk_prepare) }, - { 0x8c211eeb, __VMLINUX_SYMBOL_STR(devm_clk_get) }, - { 0xee9ce628, __VMLINUX_SYMBOL_STR(snd_soc_unregister_codec) }, - { 0xc98126c9, __VMLINUX_SYMBOL_STR(snd_soc_put_enum_double) }, - { 0x103b85f7, __VMLINUX_SYMBOL_STR(snd_soc_register_codec) }, - { 0x40c57909, __VMLINUX_SYMBOL_STR(devm_kmalloc) }, - { 0xd79caef6, __VMLINUX_SYMBOL_STR(regmap_write) }, - { 0xad83053c, __VMLINUX_SYMBOL_STR(regcache_sync) }, - { 0x44c19f83, __VMLINUX_SYMBOL_STR(snd_soc_write) }, -}; - -static const char __module_depends[] -__used -__attribute__((section(".modinfo"))) = -"depends=snd-pcm,snd-soc-core,snd"; - -MODULE_ALIAS("i2c:wm8960"); -MODULE_ALIAS("of:N*T*Cwlf,wm8960"); -MODULE_ALIAS("of:N*T*Cwlf,wm8960C*"); - -MODULE_INFO(srcversion, "2690F666DC1933DEF3E5373");