Bugfix: miss channels order in cpu_dai
This commit is contained in:
parent
5028a91201
commit
878027066d
1 changed files with 82 additions and 26 deletions
104
ac108.c
104
ac108.c
|
@ -16,13 +16,13 @@
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/workqueue.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>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
#include <sound/tlv.h>
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include "ac108.h"
|
#include "ac108.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +42,6 @@ struct pll_div {
|
||||||
unsigned int k2;
|
unsigned int k2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ac108_priv {
|
struct ac108_priv {
|
||||||
struct i2c_client *i2c[4];
|
struct i2c_client *i2c[4];
|
||||||
int codec_index;
|
int codec_index;
|
||||||
|
@ -51,6 +50,7 @@ struct ac108_priv {
|
||||||
int clk_id;
|
int clk_id;
|
||||||
unsigned char i2s_mode;
|
unsigned char i2s_mode;
|
||||||
unsigned char data_protocol;
|
unsigned char data_protocol;
|
||||||
|
struct delayed_work dlywork;
|
||||||
};
|
};
|
||||||
static struct ac108_priv *ac108;
|
static struct ac108_priv *ac108;
|
||||||
|
|
||||||
|
@ -157,7 +157,6 @@ static const struct pll_div ac108_pll_div_list[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//AC108 define
|
//AC108 define
|
||||||
#define AC108_CHANNELS_MAX 16 //range[1, 16]
|
#define AC108_CHANNELS_MAX 16 //range[1, 16]
|
||||||
#define AC108_RATES (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_KNOT)
|
#define AC108_RATES (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_KNOT)
|
||||||
|
@ -379,7 +378,6 @@ static const struct soc_enum ac108_enum[] = {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const struct snd_kcontrol_new ac108_snd_controls[] = {
|
static const struct snd_kcontrol_new ac108_snd_controls[] = {
|
||||||
|
|
||||||
SOC_SINGLE("OUT1 Mute", I2S_FMT_CTRL3, 3, 1, 0),
|
SOC_SINGLE("OUT1 Mute", I2S_FMT_CTRL3, 3, 1, 0),
|
||||||
|
@ -747,10 +745,7 @@ static int ac108_configure_clocking(struct ac108_priv *ac108, unsigned int rate)
|
||||||
0x00 << PLLCLK_EN | 0x00 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac108);
|
0x00 << PLLCLK_EN | 0x00 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac108);
|
||||||
ac108->mclk = ac108->sysclk;
|
ac108->mclk = ac108->sysclk;
|
||||||
}
|
}
|
||||||
/*0x21: Module clock enable<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
|
|
||||||
ac108_multi_chips_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108);
|
|
||||||
/*0x22: Module reset de-asserted<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
|
|
||||||
ac108_multi_chips_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,11 +782,18 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec);
|
struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec);
|
||||||
unsigned bclkdiv;
|
unsigned bclkdiv;
|
||||||
|
u8 r;
|
||||||
|
|
||||||
dev_dbg(dai->dev, "%s\n", __FUNCTION__);
|
dev_dbg(dai->dev, "%s\n", __FUNCTION__);
|
||||||
|
|
||||||
channels = params_channels(params);
|
channels = params_channels(params);
|
||||||
|
|
||||||
|
/* Master mode, to clear cpu_dai fifos, output bclk without lrck */
|
||||||
|
ac108_read(I2S_CTRL, &r, ac108->i2c[0]);
|
||||||
|
if (r & (0x02 << LRCK_IOEN)) {
|
||||||
|
ac108_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x02 << LRCK_IOEN, ac108->i2c[0]);
|
||||||
|
}
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
case SNDRV_PCM_FORMAT_S8:
|
||||||
sample_resolution = 0;
|
sample_resolution = 0;
|
||||||
|
@ -900,15 +902,19 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
* slots allocation for each chip
|
* slots allocation for each chip
|
||||||
*/
|
*/
|
||||||
ac108_multi_chips_slots(ac108, channels);
|
ac108_multi_chips_slots(ac108, channels);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) {
|
static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) {
|
||||||
|
|
||||||
struct ac108_priv *ac108 = snd_soc_dai_get_drvdata(dai);
|
struct ac108_priv *ac108 = snd_soc_dai_get_drvdata(dai);
|
||||||
|
|
||||||
freq = 24000000;
|
freq = 24000000;
|
||||||
clk_id = SYSCLK_SRC_PLL;
|
clk_id = SYSCLK_SRC_PLL;
|
||||||
|
|
||||||
pr_info("%s :%d\n", __FUNCTION__, freq);
|
pr_info("%s :%d\n", __FUNCTION__, freq);
|
||||||
|
|
||||||
switch (clk_id) {
|
switch (clk_id) {
|
||||||
case SYSCLK_SRC_MCLK:
|
case SYSCLK_SRC_MCLK:
|
||||||
ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, SYSCLK_SRC_MCLK << SYSCLK_SRC, ac108);
|
ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, SYSCLK_SRC_MCLK << SYSCLK_SRC, ac108);
|
||||||
|
@ -943,6 +949,8 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
|
||||||
struct ac108_priv *ac108 = dev_get_drvdata(dai->dev);
|
struct ac108_priv *ac108 = dev_get_drvdata(dai->dev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
dev_dbg(dai->dev, "%s\n", __FUNCTION__);
|
||||||
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||||
case SND_SOC_DAIFMT_CBM_CFM: /*AC108 Master*/
|
case SND_SOC_DAIFMT_CBM_CFM: /*AC108 Master*/
|
||||||
dev_dbg(dai->dev, "AC108 set to work as Master\n");
|
dev_dbg(dai->dev, "AC108 set to work as Master\n");
|
||||||
|
@ -950,7 +958,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
|
||||||
* 0x30:chip is master mode ,BCLK & LRCK output
|
* 0x30:chip is master mode ,BCLK & LRCK output
|
||||||
*/
|
*/
|
||||||
ac108_multi_chips_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
|
ac108_multi_chips_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
|
||||||
0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac108);
|
0x02 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac108);
|
||||||
/* multi_chips: only one chip set as Master, and the others also need to set as Slave */
|
/* multi_chips: only one chip set as Master, and the others also need to set as Slave */
|
||||||
for (i = 1; i < ac108->codec_index; i++) {
|
for (i = 1; i < ac108->codec_index; i++) {
|
||||||
ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac108->i2c[i]);
|
ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac108->i2c[i]);
|
||||||
|
@ -1068,32 +1076,81 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
|
||||||
ac108_multi_chips_update_bits(I2S_FMT_CTRL3, 0x01 << TX_MLS | 0x03 << SEXT | 0x01 << LRCK_WIDTH | 0x03 << TX_PDM,
|
ac108_multi_chips_update_bits(I2S_FMT_CTRL3, 0x01 << TX_MLS | 0x03 << SEXT | 0x01 << LRCK_WIDTH | 0x03 << TX_PDM,
|
||||||
0x00 << TX_MLS | 0x03 << SEXT | 0x00 << LRCK_WIDTH | 0x00 << TX_PDM, ac108);
|
0x00 << TX_MLS | 0x03 << SEXT | 0x00 << LRCK_WIDTH | 0x00 << TX_PDM, ac108);
|
||||||
|
|
||||||
/**???*/
|
|
||||||
ac108_multi_chips_write(HPF_EN, 0x00, ac108);
|
ac108_multi_chips_write(HPF_EN, 0x00, ac108);
|
||||||
|
|
||||||
return 0;
|
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 ac108_priv *ac108 = container_of(work, struct ac108_priv, dlywork.work);
|
||||||
|
u8 r;
|
||||||
|
|
||||||
|
/* enable lrck clock */
|
||||||
|
ac108_read(I2S_CTRL, &r, ac108->i2c[0]);
|
||||||
|
if (r & (0x02 << LRCK_IOEN)) {
|
||||||
|
ac108_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac108->i2c[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable global clock */
|
||||||
|
ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x1 << GEN, ac108);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
|
struct snd_soc_dai *dai)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dev_dbg(dai->dev, "%s()\n", __FUNCTION__);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
|
/* disable global clock */
|
||||||
|
ac108_multi_chips_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x1 << TXEN | 0x0 << GEN, ac108);
|
||||||
|
|
||||||
|
/*0x21: Module clock enable<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
|
||||||
|
ac108_multi_chips_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108);
|
||||||
|
|
||||||
|
/*0x22: Module reset de-asserted<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
|
||||||
|
ac108_multi_chips_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108);
|
||||||
|
|
||||||
|
/* delayed clock starting */
|
||||||
|
schedule_delayed_work(&ac108->dlywork, msecs_to_jiffies(50));
|
||||||
|
break;
|
||||||
|
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 ac108_dai_ops = {
|
static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||||
/*DAI clocking configuration*/
|
/*DAI clocking configuration*/
|
||||||
.set_sysclk = ac108_set_sysclk,
|
.set_sysclk = ac108_set_sysclk,
|
||||||
|
|
||||||
|
|
||||||
/*ALSA PCM audio operations*/
|
/*ALSA PCM audio operations*/
|
||||||
.hw_params = ac108_hw_params,
|
.hw_params = ac108_hw_params,
|
||||||
// .trigger = ac108_trigger,
|
.trigger = ac108_trigger,
|
||||||
|
|
||||||
// .hw_free = ac108_hw_free,
|
// .hw_free = ac108_hw_free,
|
||||||
//
|
|
||||||
// /*DAI format configuration*/
|
/*DAI format configuration*/
|
||||||
.set_fmt = ac108_set_fmt,
|
.set_fmt = ac108_set_fmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const struct regmap_config ac108_regmap_config = {
|
|
||||||
.reg_bits = 8,
|
|
||||||
.val_bits = 8,
|
|
||||||
.max_register = PRNG_CLK_CTRL,
|
|
||||||
.cache_type = REGCACHE_RBTREE,
|
|
||||||
};
|
|
||||||
static struct snd_soc_dai_driver ac108_dai0 = {
|
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||||
.name = "ac108-codec0",
|
.name = "ac108-codec0",
|
||||||
.capture = {
|
.capture = {
|
||||||
|
@ -1283,8 +1340,6 @@ static struct attribute_group ac108_debug_attr_group = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int ac108_i2c_probe(struct i2c_client *i2c,
|
static int ac108_i2c_probe(struct i2c_client *i2c,
|
||||||
const struct i2c_device_id *i2c_id) {
|
const struct i2c_device_id *i2c_id) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1297,7 +1352,9 @@ static int ac108_i2c_probe(struct i2c_client *i2c,
|
||||||
dev_err(&i2c->dev, "Unable to allocate ac108 private data\n");
|
dev_err(&i2c->dev, "Unable to allocate ac108 private data\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
INIT_DELAYED_WORK(&ac108->dlywork, ac108_work_start_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_property_read_u32(np, "data-protocol", &val);
|
ret = of_property_read_u32(np, "data-protocol", &val);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Please set data-protocol.\n");
|
pr_err("Please set data-protocol.\n");
|
||||||
|
@ -1305,7 +1362,6 @@ static int ac108_i2c_probe(struct i2c_client *i2c,
|
||||||
}
|
}
|
||||||
ac108->data_protocol = val;
|
ac108->data_protocol = val;
|
||||||
|
|
||||||
|
|
||||||
/*Writing this register 0x12 resets all register to their default state.*/
|
/*Writing this register 0x12 resets all register to their default state.*/
|
||||||
ac108_write(CHIP_RST, CHIP_RST_VAL, i2c);
|
ac108_write(CHIP_RST, CHIP_RST_VAL, i2c);
|
||||||
msleep(1);
|
msleep(1);
|
||||||
|
|
Loading…
Reference in a new issue