Fix: i2c access fail when AC108 as master, support make DEBUG=1

This commit is contained in:
Peter.Yang 2018-03-26 08:24:12 +00:00
parent 1901914b56
commit 860d38fc47
4 changed files with 70 additions and 42 deletions

View file

@ -7,6 +7,12 @@ obj-m += snd-soc-wm8960.o
obj-m += snd-soc-ac108.o
obj-m += snd-soc-simple-card.o
ifdef DEBUG
ifneq ($(DEBUG),0)
ccflags-y += -DDEBUG -DAC101_DEBG
endif
endif
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

28
ac101.c
View file

@ -20,7 +20,10 @@
* the License, or (at your option) any later version.
*
*/
#undef AC101_DEBG
/* #undef AC101_DEBG
* use 'make DEBUG=1' to enable debugging
*/
#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@ -292,22 +295,17 @@ static int ac101_aif1clk(struct snd_soc_codec* codec, int event) {
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);
/* I know it will degrades performance, but I have no choice */
spin_lock_irqsave(&ac10x->lock, flags);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (ac10x->aif1_clken == 0){
/* I know it will degrades performance, but I have no choice */
spin_lock_irqsave(&ac10x->lock, flags);
/* 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__);
@ -319,15 +317,11 @@ static int ac101_aif1clk(struct snd_soc_codec* codec, int event) {
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__);
@ -338,6 +332,10 @@ static int ac101_aif1clk(struct snd_soc_codec* codec, int event) {
break;
}
}
spin_unlock_irqrestore(&ac10x->lock, flags);
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);
return 0;
}
@ -1178,6 +1176,12 @@ int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
return ret;
}
/* Chip reset */
/*
ret = regmap_write(ac10x->regmap101, CHIP_AUDIO_RST, 0);
msleep(50);
*/
ret = regmap_read(ac10x->regmap101, CHIP_AUDIO_RST, &v);
if (ret < 0) {
dev_err(&i2c->dev, "failed to read vendor ID: %d\n", ret);

70
ac108.c
View file

@ -8,7 +8,10 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
/* #undef DEBUG
* use 'make DEBUG=1' to enable debugging
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@ -547,10 +550,6 @@ static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lr
/*0x18: PLL clk lock enable*/
ac108_multi_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_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN | 0x01 << PLL_NDET,
0x01 << PLL_EN | 0x01 << PLL_COM_EN | 0x01 << PLL_NDET, ac10x);
/**
* 0x20: enable pll, pll source from mclk/bclk, sysclk source from pll, enable sysclk
*/
@ -670,8 +669,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
/* Master mode, to clear cpu_dai fifos, output bclk without lrck */
ac10x_read(I2S_CTRL, &v, ac10x->i2cmap[_MASTER_INDEX]);
if (v & (0x02 << LRCK_IOEN)) {
ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x02 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
if (v & (0x01 << BCLK_IOEN)) {
ac10x_update_bits(I2S_CTRL, 0x1 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
}
switch (params_format(params)) {
@ -792,6 +791,11 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
*/
ac108_multi_chips_slots(ac10x, channels);
/*0x21: Module clock enable<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
ac108_multi_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x);
/*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);
dev_dbg(dai->dev, "%s() stream=%s ---\n", __func__,
snd_pcm_stream_str(substream));
@ -851,7 +855,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac10x);
/* multi_chips: only one chip set as Master, and the others also need to set as Slave */
ac10x_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x2 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
ac10x_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x01 << BCLK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
break;
} else {
/* TODO: Both cpu_dai and codec_dai(AC108) be set as slave in DTS */
@ -863,8 +867,8 @@ 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
* SDO2_EN, Transmitter Block Enable, Globe Enable
*/
ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac10x);
ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN,
0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN, ac10x);
break;
default:
pr_err("AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12);
@ -930,13 +934,6 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
return -EINVAL;
}
#if 0
/* revert LRCK polarity if it's single chip (master mode) */
if (ac10x->tdm_chips_cnt < 2) {
lrck_polarity = (lrck_polarity == LRCK_LEFT_HIGH_RIGHT_LOW)?
LRCK_LEFT_LOW_RIGHT_HIGH: LRCK_LEFT_HIGH_RIGHT_LOW;
}
#endif
ac108_configure_power(ac10x);
/**
@ -987,14 +984,16 @@ 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.
*/
static int ac108_set_clock(int y_start_n_stop) {
unsigned long flags;
u8 r;
dev_dbg(ac10x->codec->dev, "%s() L%d start:%d\n", __func__, __LINE__, y_start_n_stop);
spin_lock_irqsave(&ac10x->lock, flags);
if (y_start_n_stop) {
/* enable lrck clock */
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
if (r & (0x02 << LRCK_IOEN)) {
if (r & (0x01 << BCLK_IOEN)) {
ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
}
@ -1005,10 +1004,11 @@ static int ac108_set_clock(int y_start_n_stop) {
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
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, 0x02 << LRCK_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);
}
}
spin_unlock_irqrestore(&ac10x->lock, flags);
return 0;
}
@ -1028,6 +1028,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);
unsigned long flags;
int ret = 0;
u8 r;
@ -1036,10 +1037,12 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
snd_pcm_stream_str(substream),
cmd);
spin_lock_irqsave(&ac10x->lock, flags);
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
ac101_trigger(substream, cmd, dai);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
return 0;
goto __ret;
}
}
@ -1049,27 +1052,39 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* disable global clock if lrck disabled */
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
if ((r & (0x02 << LRCK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
/* disable global clock */
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac10x);
}
/*0x21: Module clock enable<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
ac108_multi_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x);
/*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);
/*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() */
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
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;
default:
ret = -EINVAL;
}
__ret:
spin_unlock_irqrestore(&ac10x->lock, flags);
return ret;
}
@ -1378,6 +1393,9 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
ac10x->i2c101 = i2c;
i2c_set_clientdata(i2c, ac10x);
ret = ac101_probe(i2c, i2c_id);
if (ret) {
return ret;
}
goto __ret;
}

View file

@ -8,7 +8,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
/* #undef DEBUG */
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio.h>
@ -240,7 +240,7 @@ static int asoc_simple_card_trigger(struct snd_pcm_substream *substream, int cmd
ret = -EINVAL;
}
return 0;
return ret;
}
static struct snd_soc_ops asoc_simple_card_ops = {