Fix: i2c access fail & channels miss order
This commit is contained in:
parent
22f495491a
commit
d3d95d0296
4 changed files with 151 additions and 87 deletions
179
ac101.c
179
ac101.c
|
@ -36,6 +36,15 @@
|
|||
#include "ac101_regs.h"
|
||||
#include "ac10x.h"
|
||||
|
||||
/*
|
||||
* *** To sync channels ***
|
||||
* 1. disable clock in codec hw_params()
|
||||
* 2. clear fifo in bcm2835 hw_params()
|
||||
* 3. clear fifo in bcm2385 prepare()
|
||||
* 4. enable RX in bcm2835 trigger()
|
||||
* 5. enable clock in machine trigger()
|
||||
*/
|
||||
|
||||
/*Default initialize configuration*/
|
||||
static bool speaker_double_used = 1;
|
||||
static int double_speaker_val = 0x1B;
|
||||
|
@ -219,6 +228,7 @@ void set_configuration(struct snd_soc_codec *codec)
|
|||
|
||||
static int late_enable_dac(struct snd_soc_codec* codec, int event) {
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
mutex_lock(&ac10x->dac_mutex);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
|
@ -276,49 +286,66 @@ static int ac101_headphone_event(struct snd_soc_codec* codec, int event) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac101_sysclk_started(void) {
|
||||
int reg_val;
|
||||
|
||||
reg_val = ac101_read(static_ac10x->codec, SYSCLK_CTRL);
|
||||
return (reg_val & (0x1<<SYSCLK_ENA));
|
||||
}
|
||||
|
||||
static int ac101_aif1clk(struct snd_soc_codec* codec, int event) {
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
mutex_lock(&ac10x->aifclk_mutex);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (ac10x->aif1_clken == 0){
|
||||
/*enable AIF1CLK*/
|
||||
ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA), (0x1<<AIF1CLK_ENA));
|
||||
ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
|
||||
ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1));
|
||||
/*enable systemclk*/
|
||||
if (ac10x->aif2_clken == 0)
|
||||
ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA), (0x1<<SYSCLK_ENA));
|
||||
}
|
||||
ac10x->aif1_clken++;
|
||||
/* I know it will degrades performance, but I have no choice */
|
||||
spin_lock_irqsave(&ac10x->lock, flags);
|
||||
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
#if 0
|
||||
if (ac10x->aif1_clken > 0){
|
||||
ac10x->aif1_clken--;
|
||||
if (ac10x->aif1_clken == 0){
|
||||
#else
|
||||
{
|
||||
if (ac10x->aif1_clken != 0) {
|
||||
ac10x->aif1_clken = 0;
|
||||
#endif
|
||||
/*disable AIF1CLK*/
|
||||
ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA), (0x0<<AIF1CLK_ENA));
|
||||
ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x0<<MOD_CLK_AIF1));
|
||||
ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x0<<MOD_RESET_AIF1));
|
||||
/*DISABLE systemclk*/
|
||||
if (ac10x->aif2_clken == 0)
|
||||
ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA), (0x0<<SYSCLK_ENA));
|
||||
/* enable aif1clk & sysclk */
|
||||
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));
|
||||
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));
|
||||
spin_unlock_irqrestore(&ac10x->lock, flags);
|
||||
|
||||
if (ret) {
|
||||
AC101_DBG("%s() L%d start sysclk failed\n", __func__, __LINE__);
|
||||
} else {
|
||||
AC101_DBG("%s() L%d hw sysclk enable\n", __func__, __LINE__);
|
||||
ac10x->aif1_clken++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
if (ac10x->aif1_clken != 0) {
|
||||
/* I know it will degrades performance, but I have no choice */
|
||||
spin_lock_irqsave(&ac10x->lock, flags);
|
||||
|
||||
/* disable aif1clk & sysclk */
|
||||
ret = ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA),(0x0<<AIF1CLK_ENA));
|
||||
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x0<<MOD_CLK_AIF1));
|
||||
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x0<<MOD_RESET_AIF1));
|
||||
ret = ret || ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA), (0x0<<SYSCLK_ENA));
|
||||
spin_unlock_irqrestore(&ac10x->lock, flags);
|
||||
|
||||
if (ret) {
|
||||
AC101_DBG("%s() L%d stop sysclk failed\n", __func__, __LINE__);
|
||||
} else {
|
||||
AC101_DBG("%s() L%d hw sysclk disable\n", __func__, __LINE__);
|
||||
ac10x->aif1_clken = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ac10x->aifclk_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -555,8 +582,10 @@ int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
ac101_headphone_event(codec, SND_SOC_DAPM_PRE_PMD);
|
||||
late_enable_dac(codec, SND_SOC_DAPM_POST_PMD);
|
||||
|
||||
#if _MASTER_MULTI_CODEC != _MASTER_AC101
|
||||
ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -564,27 +593,24 @@ int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
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;
|
||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
AC101_DBG("%s,line:%d stream = %d, play-active = %d\n", __func__, __LINE__,
|
||||
substream->stream, codec_dai->playback_active);
|
||||
AC101_DBG("%s,line:%d stream = %s, play: %d, capt: %d, active: %d\n", __func__, __LINE__,
|
||||
snd_pcm_stream_str(substream),
|
||||
codec_dai->playback_active, codec_dai->capture_active,
|
||||
codec_dai->active);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
reg_val = (ac101_read(codec, AIF_SR_CTRL) >> 12) & 0xF;
|
||||
if (codec_dai->playback_active && dmic_used && reg_val == 0x4) {
|
||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x7<<AIF1_FS));
|
||||
}
|
||||
if (!codec_dai->active) {
|
||||
ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD);
|
||||
}
|
||||
}
|
||||
|
||||
static int ac101_set_pll(struct snd_soc_dai *codec_dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
int i = 0;
|
||||
int m = 0;
|
||||
int n_i = 0;
|
||||
int n_f = 0;
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
int i, m, n_i, n_f;
|
||||
|
||||
AC101_DBG("%s, line:%d, pll_id:%d\n", __func__, __LINE__, pll_id);
|
||||
|
||||
|
@ -617,8 +643,9 @@ static int ac101_set_pll(struct snd_soc_dai *codec_dai, int pll_id, int source,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* freq_out = freq_in * n/(m*(2k+1)) , k=1,N=N_i+N_f */
|
||||
for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
|
||||
for (i = m = n_i = n_f = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
|
||||
if ((codec_pll_div[i].pll_in == freq_in) && (codec_pll_div[i].pll_out == freq_out)) {
|
||||
m = codec_pll_div[i].m;
|
||||
n_i = codec_pll_div[i].n_i;
|
||||
|
@ -656,11 +683,10 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
AC101_DBG("%s() L%d +++\n", __func__, __LINE__);
|
||||
|
||||
/* Master mode, to clear cpu_dai fifos, disable output bclk & lrck */
|
||||
#if 0
|
||||
ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD);
|
||||
#endif
|
||||
if (_MASTER_MULTI_CODEC == _MASTER_AC101 && ac101_sysclk_started()) {
|
||||
/* not configure hw_param twice, tell the caller it's started */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get channels count & slot size */
|
||||
channels = params_channels(params);
|
||||
|
@ -731,6 +757,11 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
|||
ac101_set_pll(codec_dai, AC101_BCLK1, 0, aif1_lrck_div * params_rate(params), freq_out);
|
||||
}
|
||||
|
||||
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
||||
/* Master mode, to clear cpu_dai fifos, disable output bclk & lrck */
|
||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD);
|
||||
#endif
|
||||
|
||||
AC101_DBG("rate: %d , channels: %d , samp_res: %d",
|
||||
params_rate(params), channels, aif1_slot_size);
|
||||
|
||||
|
@ -846,15 +877,39 @@ static int ac101_set_clock(int y_start_n_stop) {
|
|||
/* enable global clock */
|
||||
ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_PRE_PMU);
|
||||
} else {
|
||||
#if 0
|
||||
/* disable global clock */
|
||||
static_ac10x->aif1_clken = 1;
|
||||
ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_POST_PMD);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
AC101_DBG("%s() stream=%s cmd=%d\n",
|
||||
__FUNCTION__,
|
||||
snd_pcm_stream_str(substream),
|
||||
cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int ac101_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
|
@ -870,29 +925,6 @@ static int ac101_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
AC101_DBG("%s() stream=%d cmd=%d\n",
|
||||
__FUNCTION__, substream->stream, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ac101_aif1_dai_ops = {
|
||||
//.startup = ac101_audio_startup,
|
||||
//.shutdown = ac101_aif_shutdown,
|
||||
|
@ -984,9 +1016,8 @@ int ac101_codec_probe(struct snd_soc_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->aifclk_mutex);
|
||||
spin_lock_init(&ac10x->lock);
|
||||
|
||||
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
||||
asoc_simple_card_register_set_clock(ac101_set_clock);
|
||||
|
|
44
ac108.c
44
ac108.c
|
@ -647,16 +647,23 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
|||
int ret = 0;
|
||||
u8 v;
|
||||
|
||||
dev_dbg(dai->dev, "%s() stream=%d play:%d capt:%d +++\n", __func__,
|
||||
substream->stream, dai->playback_active, dai->capture_active);
|
||||
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||
snd_pcm_stream_str(substream),
|
||||
dai->playback_active, dai->capture_active);
|
||||
|
||||
if (ac10x->i2c101) {
|
||||
ret = ac101_hw_params(substream, params, dai);
|
||||
if (ret > 0) {
|
||||
dev_dbg(dai->dev, "%s() L%d returned\n", __func__, __LINE__);
|
||||
/* not configure hw_param twice */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing should be done when it isn't capturing stream. */
|
||||
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
|
||||
// TODO:
|
||||
if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
||||
|| (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
||||
/* not configure hw_param twice */
|
||||
/* return 0; */
|
||||
}
|
||||
|
||||
channels = params_channels(params);
|
||||
|
@ -785,7 +792,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
|||
*/
|
||||
ac108_multi_chips_slots(ac10x, channels);
|
||||
|
||||
dev_dbg(dai->dev, "%s() stream=%d ---\n", __func__, substream->stream);
|
||||
dev_dbg(dai->dev, "%s() stream=%s ---\n", __func__,
|
||||
snd_pcm_stream_str(substream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1005,6 +1013,16 @@ static int ac108_set_clock(int y_start_n_stop) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ac108_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
dev_dbg(dai->dev, "%s() stream=%s\n",
|
||||
__func__,
|
||||
snd_pcm_stream_str(substream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -1013,8 +1031,17 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
int ret = 0;
|
||||
u8 r;
|
||||
|
||||
dev_dbg(dai->dev, "%s() stream=%d cmd=%d\n",
|
||||
__FUNCTION__, substream->stream, cmd);
|
||||
dev_dbg(dai->dev, "%s() stream=%s cmd=%d\n",
|
||||
__FUNCTION__,
|
||||
snd_pcm_stream_str(substream),
|
||||
cmd);
|
||||
|
||||
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
|
||||
ac101_trigger(substream, cmd, dai);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
@ -1088,6 +1115,7 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
|||
|
||||
/*ALSA PCM audio operations*/
|
||||
.hw_params = ac108_hw_params,
|
||||
.prepare = ac108_prepare,
|
||||
.trigger = ac108_trigger,
|
||||
.digital_mute = ac108_aif_mute,
|
||||
|
||||
|
|
7
ac10x.h
7
ac10x.h
|
@ -47,16 +47,15 @@ struct ac10x_priv {
|
|||
struct delayed_work dlywork;
|
||||
int tdm_chips_cnt;
|
||||
|
||||
/* memboer for ac101 .begin */
|
||||
/* member for ac101 .begin */
|
||||
struct snd_soc_codec *codec;
|
||||
struct i2c_client *i2c101;
|
||||
struct regmap* regmap101;
|
||||
|
||||
struct mutex dac_mutex;
|
||||
u8 dac_enable;
|
||||
struct mutex aifclk_mutex;
|
||||
spinlock_t lock;
|
||||
u8 aif1_clken;
|
||||
u8 aif2_clken;
|
||||
|
||||
struct work_struct codec_resume;
|
||||
struct delayed_work dlywork101;
|
||||
|
@ -71,6 +70,8 @@ int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
|
|||
int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *codec_dai);
|
||||
int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai);
|
||||
int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute);
|
||||
|
||||
/* codec driver specific */
|
||||
|
|
|
@ -216,8 +216,8 @@ static int asoc_simple_card_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%d cmd=%d play:%d, capt:%d\n",
|
||||
__FUNCTION__, substream->stream, cmd,
|
||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||
dai->playback_active, dai->capture_active);
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -230,6 +230,10 @@ static int asoc_simple_card_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
/* capture channel resync, if overrun */
|
||||
if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
break;
|
||||
}
|
||||
if (_set_clock) _set_clock(0);
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue