Fix: 4MIC recording by portaudio & pyaudio

This commit is contained in:
Peter.Yang 2018-04-02 07:59:17 +00:00
parent 86329f0719
commit 8211f4c000
5 changed files with 131 additions and 62 deletions

View file

@ -225,7 +225,7 @@ aplay -D plughw:1,0 -r 16000 mono_to_play.wav
``` ```
**Note: Limit for developer using 6-Mics Circular Array Kit(or 4-Mics Linear Array Kit) doing capture & playback the same time: **Note: Limit for developer using 6-Mics Circular Array Kit(or 4-Mics Linear Array Kit) doing capture & playback the same time:
1. capture must be start first, or else the capture channels will possibly be disorder. 1. capture must be start first, or else the capture channels will possibly be disorder.
2. playback output channels must fill with 8 same channels data or 4 same stereo channels data, or else the speaker or headphone will output nothing possily.** 2. playback output channels must fill with 8 same channels data or 4 same stereo channels data, or else the speaker or headphone will output nothing possibly.**
### Coherence ### Coherence

81
ac101.c
View file

@ -290,21 +290,21 @@ static int ac101_sysclk_started(void) {
return (reg_val & (0x1<<SYSCLK_ENA)); return (reg_val & (0x1<<SYSCLK_ENA));
} }
static int ac101_aif1clk(struct snd_soc_codec* codec, int event) { static int ac101_aif1clk(struct snd_soc_codec* codec, int event, int quick) {
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
unsigned long flags;
int ret; int ret;
/* I know it will degrades performance, but I have no choice */ /* spin_lock move to simple_card_trigger */
spin_lock_irqsave(&ac10x->lock, flags);
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_PRE_PMU:
if (ac10x->aif1_clken == 0){ if (ac10x->aif1_clken == 0){
/* enable aif1clk & sysclk */
ret = ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA), (0x1<<AIF1CLK_ENA)); ret = ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA), (0x1<<AIF1CLK_ENA));
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1)); if(!quick || _MASTER_MULTI_CODEC != _MASTER_AC101) {
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1)); /* enable aif1clk & sysclk */
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1));
}
ret = ret || ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA), (0x1<<SYSCLK_ENA)); ret = ret || ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA), (0x1<<SYSCLK_ENA));
if (ret) { if (ret) {
@ -332,7 +332,6 @@ static int ac101_aif1clk(struct snd_soc_codec* codec, int event) {
break; break;
} }
} }
spin_unlock_irqrestore(&ac10x->lock, flags);
AC101_DBG("%s() L%d event=%d pre_up/%d post_down/%d\n", __func__, __LINE__, AC101_DBG("%s() L%d event=%d pre_up/%d post_down/%d\n", __func__, __LINE__,
event, SND_SOC_DAPM_PRE_PMU, SND_SOC_DAPM_POST_PMD); event, SND_SOC_DAPM_PRE_PMU, SND_SOC_DAPM_POST_PMD);
@ -571,7 +570,7 @@ int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
#if _MASTER_MULTI_CODEC != _MASTER_AC101 #if _MASTER_MULTI_CODEC != _MASTER_AC101
/* enable global clock */ /* enable global clock */
ac10x->aif1_clken = 0; ac10x->aif1_clken = 0;
ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU); ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU, 0);
ac101_aif_play(ac10x); ac101_aif_play(ac10x);
#else #else
schedule_delayed_work(&ac10x->dlywork, msecs_to_jiffies(50)); schedule_delayed_work(&ac10x->dlywork, msecs_to_jiffies(50));
@ -582,7 +581,7 @@ int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
#endif #endif
if (ac10x->gpiod_spk_amp_gate) { if (ac10x->gpiod_spk_amp_gate) {
gpiod_set_value(ac10x->gpiod_spk_amp_gate, 1); gpiod_set_value(ac10x->gpiod_spk_amp_gate, 0);
} }
/* Disable Left & Right Speaker */ /* Disable Left & Right Speaker */
ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPK_EN) | (0x1 << RSPK_EN), (0x0 << LSPK_EN) | (0x0 << RSPK_EN)); ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPK_EN) | (0x1 << RSPK_EN), (0x0 << LSPK_EN) | (0x0 << RSPK_EN));
@ -594,7 +593,7 @@ int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
#if _MASTER_MULTI_CODEC != _MASTER_AC101 #if _MASTER_MULTI_CODEC != _MASTER_AC101
ac10x->aif1_clken = 1; ac10x->aif1_clken = 1;
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD); ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
#endif #endif
} }
return 0; return 0;
@ -612,9 +611,9 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
if (!codec_dai->active) { if (!codec_dai->active) {
ac10x->aif1_clken = 1; ac10x->aif1_clken = 1;
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD); ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
} else { } else {
ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU); ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU, 0);
} }
} }
@ -776,7 +775,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
#if _MASTER_MULTI_CODEC == _MASTER_AC101 #if _MASTER_MULTI_CODEC == _MASTER_AC101
/* Master mode, to clear cpu_dai fifos, disable output bclk & lrck */ /* Master mode, to clear cpu_dai fifos, disable output bclk & lrck */
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD); ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
#endif #endif
AC101_DBG("rate: %d , channels: %d , samp_res: %d", AC101_DBG("rate: %d , channels: %d , samp_res: %d",
@ -892,11 +891,11 @@ int ac101_audio_startup(struct snd_pcm_substream *substream,
static int ac101_set_clock(int y_start_n_stop) { static int ac101_set_clock(int y_start_n_stop) {
if (y_start_n_stop) { if (y_start_n_stop) {
/* enable global clock */ /* enable global clock */
ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_PRE_PMU); ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_PRE_PMU, 1);
} else { } else {
/* disable global clock */ /* disable global clock */
static_ac10x->aif1_clken = 1; static_ac10x->aif1_clken = 1;
ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_POST_PMD); ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_POST_PMD, 0);
} }
return 0; return 0;
} }
@ -905,6 +904,8 @@ static int ac101_set_clock(int y_start_n_stop) {
int ac101_trigger(struct snd_pcm_substream *substream, int cmd, int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct snd_soc_codec *codec = dai->codec;
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
int ret = 0; int ret = 0;
AC101_DBG("%s() stream=%s cmd=%d\n", AC101_DBG("%s() stream=%s cmd=%d\n",
@ -916,6 +917,17 @@ int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
#if _MASTER_MULTI_CODEC == _MASTER_AC101
if (ac10x->aif1_clken == 0){
/*
* enable aif1clk, it' here due to reduce time between 'AC108 Sysclk Enable' and 'AC101 Sysclk Enable'
* Or else the two AC108 chips lost the sync.
*/
ret = 0;
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1));
}
#endif
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
@ -1035,10 +1047,9 @@ int ac101_codec_probe(struct snd_soc_codec *codec)
ac10x->dac_enable = 0; ac10x->dac_enable = 0;
ac10x->aif1_clken = 0; ac10x->aif1_clken = 0;
mutex_init(&ac10x->dac_mutex); mutex_init(&ac10x->dac_mutex);
spin_lock_init(&ac10x->lock);
#if _MASTER_MULTI_CODEC == _MASTER_AC101 #if _MASTER_MULTI_CODEC == _MASTER_AC101
asoc_simple_card_register_set_clock(ac101_set_clock); asoc_simple_card_register_set_clock(SNDRV_PCM_STREAM_PLAYBACK, ac101_set_clock);
#endif #endif
set_configuration(ac10x->codec); set_configuration(ac10x->codec);
@ -1059,6 +1070,7 @@ int ac101_codec_probe(struct snd_soc_codec *codec)
pr_err("[ac10x] Failed to register audio mode control, " pr_err("[ac10x] Failed to register audio mode control, "
"will continue without it.\n"); "will continue without it.\n");
} }
return 0; return 0;
} }
@ -1159,9 +1171,34 @@ static const struct regmap_config ac101_regmap = {
.val_bits = 16, .val_bits = 16,
.reg_stride = 1, .reg_stride = 1,
.max_register = 0xB5, .max_register = 0xB5,
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_FLAT,
}; };
/* Sync reg_cache from the hardware */
int ac10x_fill_regcache(struct device* dev, struct regmap* map) {
int r, i, n;
int v;
n = regmap_get_max_register(map);
for (i = 0; i < n; i++) {
regcache_cache_bypass(map, true);
r = regmap_read(map, i, &v);
if (r) {
dev_err(dev, "failed to read register %d\n", i);
continue;
}
regcache_cache_bypass(map, false);
regcache_cache_only(map, true);
r = regmap_write(map, i, v);
regcache_cache_only(map, false);
}
regcache_cache_bypass(map, false);
regcache_cache_only(map, false);
return 0;
}
int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id) int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{ {
struct ac10x_priv *ac10x = i2c_get_clientdata(i2c); struct ac10x_priv *ac10x = i2c_get_clientdata(i2c);
@ -1179,6 +1216,8 @@ int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
return ret; return ret;
} }
ac10x_fill_regcache(&i2c->dev, ac10x->regmap101);
/* Chip reset */ /* Chip reset */
/* /*
ret = regmap_write(ac10x->regmap101, CHIP_AUDIO_RST, 0); ret = regmap_write(ac10x->regmap101, CHIP_AUDIO_RST, 0);
@ -1192,7 +1231,7 @@ int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
} }
if (v != AC101_CHIP_ID) { if (v != AC101_CHIP_ID) {
dev_err(&i2c->dev, "chip is not AC101\n"); dev_err(&i2c->dev, "chip is not AC101 (%X)\n", v);
dev_err(&i2c->dev, "Expected %X\n", AC101_CHIP_ID); dev_err(&i2c->dev, "Expected %X\n", AC101_CHIP_ID);
return -ENODEV; return -ENODEV;
} }

79
ac108.c
View file

@ -22,6 +22,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
@ -37,9 +38,8 @@
/** /**
* TODO: * TODO:
* 1, add PM API: ac108_suspend,ac108_resume * 1, add PM API: ac108_suspend,ac108_resume
* 2, add set_pll ,set_clkdiv * 2,0x65-0x6a
* 3,0x65-0x6a * 3,0x76-0x79 high 4bit
* 4,0x76-0x79 high 4bit
*/ */
struct pll_div { struct pll_div {
unsigned int freq_in; unsigned int freq_in;
@ -794,6 +794,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
/*0x22: Module reset de-asserted<I2S, ADC digital, MIC offset Calibration, ADC analog>*/ /*0x22: Module reset de-asserted<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
ac108_multi_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x); ac108_multi_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x);
dev_dbg(dai->dev, "%s() stream=%s ---\n", __func__, dev_dbg(dai->dev, "%s() stream=%s ---\n", __func__,
snd_pcm_stream_str(substream)); snd_pcm_stream_str(substream));
@ -865,7 +866,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
* 0x30:chip is slave mode, BCLK & LRCK input,enable SDO1_EN and * 0x30:chip is slave mode, BCLK & LRCK input,enable SDO1_EN and
* SDO2_EN, Transmitter Block Enable, Globe Enable * SDO2_EN, Transmitter Block Enable, Globe Enable
*/ */
ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN, ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN, ac10x); 0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN, ac10x);
break; break;
default: default:
@ -982,31 +983,44 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
* due to miss channels order in cpu_dai, we meed defer the clock starting. * due to miss channels order in cpu_dai, we meed defer the clock starting.
*/ */
static int ac108_set_clock(int y_start_n_stop) { static int ac108_set_clock(int y_start_n_stop) {
unsigned long flags;
u8 r; u8 r;
dev_dbg(ac10x->codec->dev, "%s() L%d start:%d\n", __func__, __LINE__, y_start_n_stop); dev_dbg(ac10x->codec->dev, "%s() L%d cmd:%d\n", __func__, __LINE__, y_start_n_stop);
/* spin_lock move to simple_card_trigger */
if (y_start_n_stop) {
if (ac10x->sysclk_en == 0) {
spin_lock_irqsave(&ac10x->lock, flags);
if (y_start_n_stop) {
/* enable lrck clock */ /* enable lrck clock */
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]); ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
if (r & (0x01 << BCLK_IOEN)) { if (r & (0x01 << BCLK_IOEN)) {
ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]); ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
} }
/*0x10: PLL Common voltage enable, PLL enable */
ac108_multi_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
0x01 << PLL_EN | 0x01 << PLL_COM_EN, ac10x);
/* enable global clock */ /* enable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x); ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x);
} else {
ac10x->sysclk_en = 1UL;
}
} else if (ac10x->sysclk_en != 0) {
/* disable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
/*0x10: PLL Common voltage disable, PLL disable */
ac108_multi_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
0x00 << PLL_EN | 0x00 << PLL_COM_EN, ac10x);
/* disable lrck clock if it's enabled */ /* disable lrck clock if it's enabled */
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]); ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
if (r & (0x01 << LRCK_IOEN)) { if (r & (0x01 << LRCK_IOEN)) {
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x);
ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x01 << BCLK_IOEN, ac10x->i2cmap[_MASTER_INDEX]); ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x01 << BCLK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x);
} }
ac10x->sysclk_en = 0UL;
} }
spin_unlock_irqrestore(&ac10x->lock, flags);
return 0; return 0;
} }
@ -1052,29 +1066,14 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]); ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) { if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
/* disable global clock */ /* disable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x); ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
} }
/*0x10: PLL Common voltage enable, PLL enable */
ac108_multi_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
0x01 << PLL_EN | 0x01 << PLL_COM_EN, ac10x);
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
/* enable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac10x);
}
/* delayed clock starting, move to simple_card_trigger() */ /* delayed clock starting, move to simple_card_trigger() */
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
/*0x10: PLL Common voltage disable, PLL disable */
ac108_multi_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
0x00 << PLL_EN | 0x00 << PLL_COM_EN, ac10x);
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
/* disable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
}
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
@ -1104,6 +1103,13 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec); struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
/*0x21: Module clock disable <I2S, ADC digital, MIC offset Calibration, ADC analog>*/
ac108_multi_write(MOD_CLK_EN, 0x0, ac10x);
/*0x22: Module reset asserted <I2S, ADC digital, MIC offset Calibration, ADC analog>*/
ac108_multi_write(MOD_RST_CTRL, 0x0, ac10x);
}
if (ac10x->i2c101) { if (ac10x->i2c101) {
ac101_aif_shutdown(substream, dai); ac101_aif_shutdown(substream, dai);
} }
@ -1204,7 +1210,10 @@ static int ac108_add_widgets(struct snd_soc_codec *codec) {
return 0; return 0;
} }
static int ac108_probe(struct snd_soc_codec *codec) { static int ac108_codec_probe(struct snd_soc_codec *codec) {
spin_lock_init(&ac10x->lock);
ac10x->codec = codec; ac10x->codec = codec;
dev_set_drvdata(codec->dev, ac10x); dev_set_drvdata(codec->dev, ac10x);
ac108_add_widgets(codec); ac108_add_widgets(codec);
@ -1212,6 +1221,7 @@ static int ac108_probe(struct snd_soc_codec *codec) {
if (ac10x->i2c101) { if (ac10x->i2c101) {
ac101_codec_probe(codec); ac101_codec_probe(codec);
} }
return 0; return 0;
} }
@ -1293,7 +1303,7 @@ int ac108_codec_resume(struct snd_soc_codec *codec) {
} }
static struct snd_soc_codec_driver ac10x_soc_codec_driver = { static struct snd_soc_codec_driver ac10x_soc_codec_driver = {
.probe = ac108_probe, .probe = ac108_codec_probe,
.remove = ac108_codec_remove, .remove = ac108_codec_remove,
.suspend = ac108_codec_suspend, .suspend = ac108_codec_suspend,
.resume = ac108_codec_resume, .resume = ac108_codec_resume,
@ -1371,7 +1381,7 @@ static const struct regmap_config ac108_regmap = {
.val_bits = 8, .val_bits = 8,
.reg_stride = 1, .reg_stride = 1,
.max_register = 0xDF, .max_register = 0xDF,
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_FLAT,
}; };
static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) {
struct device_node *np = i2c->dev.of_node; struct device_node *np = i2c->dev.of_node;
@ -1392,6 +1402,7 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
i2c_set_clientdata(i2c, ac10x); i2c_set_clientdata(i2c, ac10x);
ret = ac101_probe(i2c, i2c_id); ret = ac101_probe(i2c, i2c_id);
if (ret) { if (ret) {
ac10x->i2c101 = NULL;
return ret; return ret;
} }
goto __ret; goto __ret;
@ -1418,6 +1429,8 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
return ret; return ret;
} }
ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
/* /*
* Writing this register with 0x12 * Writing this register with 0x12
* will resets all register to their default state. * will resets all register to their default state.
@ -1437,9 +1450,7 @@ __ret:
/* It's time to bind codec to i2c[_MASTER_INDEX] when all i2c are ready */ /* It's time to bind codec to i2c[_MASTER_INDEX] when all i2c are ready */
if ((ac10x->codec_cnt != 0 && ac10x->tdm_chips_cnt < 2) if ((ac10x->codec_cnt != 0 && ac10x->tdm_chips_cnt < 2)
|| (ac10x->i2c[0] && ac10x->i2c[1] && ac10x->i2c101)) { || (ac10x->i2c[0] && ac10x->i2c[1] && ac10x->i2c101)) {
if (! ac10x->i2c101 || _MASTER_MULTI_CODEC == _MASTER_AC108) { asoc_simple_card_register_set_clock(SNDRV_PCM_STREAM_CAPTURE, ac108_set_clock);
asoc_simple_card_register_set_clock(ac108_set_clock);
}
/* no playback stream */ /* no playback stream */
if (! ac10x->i2c101) { if (! ac10x->i2c101) {
memset(&ac108_dai[_MASTER_INDEX]->playback, '\0', sizeof ac108_dai[_MASTER_INDEX]->playback); memset(&ac108_dai[_MASTER_INDEX]->playback, '\0', sizeof ac108_dai[_MASTER_INDEX]->playback);

View file

@ -46,6 +46,7 @@ struct ac10x_priv {
unsigned char data_protocol; unsigned char data_protocol;
struct delayed_work dlywork; struct delayed_work dlywork;
int tdm_chips_cnt; int tdm_chips_cnt;
int sysclk_en;
/* member for ac101 .begin */ /* member for ac101 .begin */
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
@ -86,6 +87,8 @@ void ac101_shutdown(struct i2c_client *i2c);
int ac101_remove(struct i2c_client *i2c); int ac101_remove(struct i2c_client *i2c);
/* simple card export */ /* simple card export */
int asoc_simple_card_register_set_clock(int (*set_clock)(int)); int asoc_simple_card_register_set_clock(int stream, int (*set_clock)(int));
int ac10x_fill_regcache(struct device* dev, struct regmap* map);
#endif//__AC10X_H__ #endif//__AC10X_H__

View file

@ -51,6 +51,7 @@ struct simple_card_data {
struct asoc_simple_jack hp_jack; struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack; struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
spinlock_t lock;
}; };
#define simple_priv_to_dev(priv) ((priv)->snd_card.dev) #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
@ -203,10 +204,13 @@ err:
return ret; return ret;
} }
static int (* _set_clock)(int y_start_n_stop); #define _SET_CLOCK_CNT 2
static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
int asoc_simple_card_register_set_clock(int (*set_clock)(int)) { int asoc_simple_card_register_set_clock(int stream, int (*set_clock)(int)) {
_set_clock = set_clock; if (! _set_clock[stream]) {
_set_clock[stream] = set_clock;
}
return 0; return 0;
} }
EXPORT_SYMBOL(asoc_simple_card_register_set_clock); EXPORT_SYMBOL(asoc_simple_card_register_set_clock);
@ -215,17 +219,23 @@ 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_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned long flags;
int ret = 0; int ret = 0;
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n", dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
__FUNCTION__, snd_pcm_stream_str(substream), cmd, __FUNCTION__, snd_pcm_stream_str(substream), cmd,
dai->playback_active, dai->capture_active); dai->playback_active, dai->capture_active);
/* I know it will degrades performance, but I have no choice */
spin_lock_irqsave(&priv->lock, flags);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (_set_clock) _set_clock(1); if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
@ -235,12 +245,15 @@ static int asoc_simple_card_trigger(struct snd_pcm_substream *substream, int cmd
if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
break; break;
} }
if (_set_clock) _set_clock(0); if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
spin_unlock_irqrestore(&priv->lock, flags);
return ret; return ret;
} }
@ -605,9 +618,12 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&priv->snd_card, priv); snd_soc_card_set_drvdata(&priv->snd_card, priv);
spin_lock_init(&priv->lock);
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
if (ret >= 0) if (ret >= 0)
return ret; return ret;
err: err:
asoc_simple_card_clean_reference(&priv->snd_card); asoc_simple_card_clean_reference(&priv->snd_card);