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/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ac108.h"
|
||||
|
||||
/**
|
||||
|
@ -42,7 +42,6 @@ struct pll_div {
|
|||
unsigned int k2;
|
||||
};
|
||||
|
||||
|
||||
struct ac108_priv {
|
||||
struct i2c_client *i2c[4];
|
||||
int codec_index;
|
||||
|
@ -51,6 +50,7 @@ struct ac108_priv {
|
|||
int clk_id;
|
||||
unsigned char i2s_mode;
|
||||
unsigned char data_protocol;
|
||||
struct delayed_work dlywork;
|
||||
};
|
||||
static struct ac108_priv *ac108;
|
||||
|
||||
|
@ -157,7 +157,6 @@ static const struct pll_div ac108_pll_div_list[] = {
|
|||
};
|
||||
|
||||
|
||||
|
||||
//AC108 define
|
||||
#define AC108_CHANNELS_MAX 16 //range[1, 16]
|
||||
#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[] = {
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned bclkdiv;
|
||||
u8 r;
|
||||
|
||||
dev_dbg(dai->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
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)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
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
|
||||
*/
|
||||
ac108_multi_chips_slots(ac108, channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
freq = 24000000;
|
||||
clk_id = SYSCLK_SRC_PLL;
|
||||
|
||||
pr_info("%s :%d\n", __FUNCTION__, freq);
|
||||
|
||||
switch (clk_id) {
|
||||
case SYSCLK_SRC_MCLK:
|
||||
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);
|
||||
int i;
|
||||
|
||||
dev_dbg(dai->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM: /*AC108 Master*/
|
||||
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
|
||||
*/
|
||||
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 */
|
||||
for (i = 1; i < ac108->codec_index; 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,
|
||||
0x00 << TX_MLS | 0x03 << SEXT | 0x00 << LRCK_WIDTH | 0x00 << TX_PDM, ac108);
|
||||
|
||||
/**???*/
|
||||
ac108_multi_chips_write(HPF_EN, 0x00, ac108);
|
||||
|
||||
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 = {
|
||||
/*DAI clocking configuration*/
|
||||
.set_sysclk = ac108_set_sysclk,
|
||||
|
||||
|
||||
/*ALSA PCM audio operations*/
|
||||
.hw_params = ac108_hw_params,
|
||||
// .trigger = ac108_trigger,
|
||||
.trigger = ac108_trigger,
|
||||
|
||||
// .hw_free = ac108_hw_free,
|
||||
//
|
||||
// /*DAI format configuration*/
|
||||
|
||||
/*DAI format configuration*/
|
||||
.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 = {
|
||||
.name = "ac108-codec0",
|
||||
.capture = {
|
||||
|
@ -1283,8 +1340,6 @@ static struct attribute_group ac108_debug_attr_group = {
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static int ac108_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *i2c_id) {
|
||||
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");
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_DELAYED_WORK(&ac108->dlywork, ac108_work_start_clock);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "data-protocol", &val);
|
||||
if (ret) {
|
||||
pr_err("Please set data-protocol.\n");
|
||||
|
@ -1305,7 +1362,6 @@ static int ac108_i2c_probe(struct i2c_client *i2c,
|
|||
}
|
||||
ac108->data_protocol = val;
|
||||
|
||||
|
||||
/*Writing this register 0x12 resets all register to their default state.*/
|
||||
ac108_write(CHIP_RST, CHIP_RST_VAL, i2c);
|
||||
msleep(1);
|
||||
|
|
Loading…
Reference in a new issue