Fix: i2c access fail when AC108 as master, support make DEBUG=1
This commit is contained in:
parent
1901914b56
commit
860d38fc47
4 changed files with 70 additions and 42 deletions
6
Makefile
6
Makefile
|
@ -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
|
||||
|
|
32
ac101.c
32
ac101.c
|
@ -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;
|
||||
}
|
||||
|
@ -478,8 +476,8 @@ static const struct pll_div codec_pll_div[] = {
|
|||
{5644800, _FREQ_22_579K, 1, 12, 0}, /* accurate, 22050 * 256 */
|
||||
{6000000, _FREQ_22_579K, 38, 429, 0}, /*((429+0*0.2)*6000000)/(38*(2*1+1))*/
|
||||
{11289600, _FREQ_22_579K, 1, 6, 0}, /* accurate, 44100 * 256 */
|
||||
{13000000, _FREQ_22_579K, 19, 99, 0},
|
||||
{19200000, _FREQ_22_579K, 25, 88, 1},
|
||||
{13000000, _FREQ_22_579K, 19, 99, 0},
|
||||
{19200000, _FREQ_22_579K, 25, 88, 1},
|
||||
{24000000, _FREQ_22_579K, 63, 177, 4}, /* 22577778 Hz */
|
||||
|
||||
{128000, _FREQ_24_576K, 1, 576, 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
70
ac108.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in a new issue