diff --git a/ac108.c b/ac108.c index 0aa7fdb..e6d09ed 100644 --- a/ac108.c +++ b/ac108.c @@ -16,13 +16,13 @@ #include #include #include +#include #include #include #include #include #include #include - #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*/ - 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*/ - 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); + 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*/ + 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*/ + 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, -// .hw_free = ac108_hw_free, -// -// /*DAI format configuration*/ + .trigger = ac108_trigger, + + // .hw_free = ac108_hw_free, + + /*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);