From 7f4b5849a7c199cdff1fab1d935643e4592c739c Mon Sep 17 00:00:00 2001 From: "peter.yang" Date: Fri, 10 Nov 2017 09:00:23 +0000 Subject: [PATCH] pcm format 4 channels: no need ac108_plugin --- ac108.c | 49 ++++++++++++++---- asound_4mic.conf | 7 +-- seeed-4mic-voicecard-overlay.dts | 83 +++++++++++++++++-------------- seeed-4mic-voicecard.dtbo | Bin 2074 -> 2238 bytes simple-card.c | 14 ++++++ 5 files changed, 102 insertions(+), 51 deletions(-) diff --git a/ac108.c b/ac108.c index 0823660..635e316 100644 --- a/ac108.c +++ b/ac108.c @@ -48,6 +48,7 @@ struct ac108_priv { struct i2c_client *i2c[4]; int codec_index; int sysclk; + unsigned mclk; /* master clock or aif_clock/aclk */ int clk_id; unsigned char i2s_mode; unsigned char data_protocol; @@ -82,6 +83,13 @@ static const struct real_val_to_reg_val ac108_sample_resolution[] = { { 32, 7 }, }; +static const unsigned ac108_bclkdivs[] = { + 0, 1, 2, 4, + 6, 8, 12, 16, + 24, 32, 48, 64, + 96, 128, 176, 192, +}; + /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] ; M1[0,31], M2[0,1], N[0,1023], K1[0,31], K2[0,1] */ static const struct pll_div ac108_pll_div_list[] = { { 400000, 24576000, 0, 0, 614, 4, 1 }, @@ -700,6 +708,7 @@ static void ac108_configure_power(struct ac108_priv *ac108) { static int ac108_configure_clocking(struct ac108_priv *ac108, unsigned int rate) { unsigned int i = 0; struct pll_div ac108_pll_div = { 0 }; + if (ac108->clk_id == SYSCLK_SRC_PLL) { /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] */ for (i = 0; i < ARRAY_SIZE(ac108_pll_div_list); i++) { @@ -729,6 +738,7 @@ static int ac108_configure_clocking(struct ac108_priv *ac108, unsigned int rate) */ ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x01 << PLLCLK_EN | 0x03 << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, 0x01 << PLLCLK_EN | 0x00 << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac108); + ac108->mclk = ac108_pll_div.freq_out; } if (ac108->clk_id == SYSCLK_SRC_MCLK) { /** @@ -736,6 +746,7 @@ static int ac108_configure_clocking(struct ac108_priv *ac108, unsigned int rate) */ ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x01 << PLLCLK_EN | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, 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); @@ -748,7 +759,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h unsigned int i, channels, sample_resolution, rate; struct snd_soc_codec *codec = dai->codec; struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec); - rate = 99; + unsigned bclkdiv; + dev_dbg(dai->dev, "%s\n", __FUNCTION__); channels = params_channels(params); @@ -774,14 +786,17 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h return -EINVAL; } - dev_dbg(dai->dev,"rate:%d \n", params_rate(params)); + dev_dbg(dai->dev, "rate:%d \n", params_rate(params)); + for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) { - if (ac108_sample_rate[i].real_val ==( params_rate(params)/2)) { + if (ac108_sample_rate[i].real_val == params_rate(params) / (ac108->data_protocol + 1UL)) { rate = i; break; } } - if (rate == 99) return -EINVAL; + if (i >= ARRAY_SIZE(ac108_sample_rate)) { + return -EINVAL; + } dev_dbg(dai->dev, "rate: %d , channels: %d , sample_resolution: %d", @@ -817,12 +832,13 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h /** * TODO: need test. */ + ac108_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac108); } } else { - /** - * TODO: need test. - */ + /*TDM mode or normal mode*/ + ac108_multi_chips_write(I2S_LRCK_CTRL2, ac108_sample_resolution[sample_resolution].real_val * channels - 1, ac108); + ac108_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac108); } /** @@ -841,6 +857,18 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h ac108_multi_chips_update_bits(ADC_SPRC, 0x0f << ADC_FS_I2S1, ac108_sample_rate[rate].reg_val << ADC_FS_I2S1, ac108); ac108_multi_chips_write(HPF_EN,0x0f,ac108); ac108_configure_clocking(ac108, ac108_sample_rate[rate].real_val); + + /* + * master mode only + */ + bclkdiv = ac108->mclk / (ac108_sample_rate[rate].real_val * channels * ac108_sample_resolution[sample_resolution].real_val); + for (i = 0; i < ARRAY_SIZE(ac108_bclkdivs) - 1; i++) { + if (ac108_bclkdivs[i] >= bclkdiv) { + break; + } + } + + ac108_multi_chips_update_bits(I2S_BCLK_CTRL, 0x0F << BCLKDIV, i << BCLKDIV, ac108); return 0; } @@ -888,7 +916,8 @@ 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 << LRCK_IOEN, ac108); + 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); /* multi_chips: only one chip set as Master, and the others also need to set as Slave */ if (ac108->codec_index > 1) ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac108->i2c[1]); @@ -900,7 +929,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { * SDO2_EN, Transmitter Block Enable, Globe Enable */ ac108_multi_chips_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, - 0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac108); + 0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac108); break; default: pr_err("AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12); @@ -1003,7 +1032,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { * TODO:pcm mode, bit[0:1] and bit[2] is special */ 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); diff --git a/asound_4mic.conf b/asound_4mic.conf index a5c9edb..013e5e3 100644 --- a/asound_4mic.conf +++ b/asound_4mic.conf @@ -21,7 +21,8 @@ pcm.dmixed { pcm.ac108 { - type ac108 - slavepcm "hw:1,0" - channels 4 + type hw + card 1 + device 0 + channels 4 } diff --git a/seeed-4mic-voicecard-overlay.dts b/seeed-4mic-voicecard-overlay.dts index 4b81453..f526a3b 100644 --- a/seeed-4mic-voicecard-overlay.dts +++ b/seeed-4mic-voicecard-overlay.dts @@ -2,25 +2,28 @@ /plugin/; / { - compatible = "brcm,bcm2708"; + compatible = "brcm,bcm2708"; + fragment@0 { target = <&i2s>; __overlay__ { #sound-dai-cells = <0>; status = "okay"; - }; + }; }; - fragment@1 { - target-path = "/clocks"; - __overlay__ { - ac108_mclk: codec-mclk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; - }; - }; - fragment@2 { + + fragment@1 { + target-path = "/clocks"; + __overlay__ { + ac108_mclk: codec-mclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; + }; + + fragment@2 { target = <&i2c1>; __overlay__ { #address-cells = <1>; @@ -31,36 +34,40 @@ compatible = "x-power,ac108_0"; reg = <0x3b>; #sound-dai-cells = <0>; - data-protocol = <1>; + data-protocol = <0>; }; }; - }; + }; + fragment@3 { + target = <&sound>; - fragment@3 { - target = <&sound>; - sound_overlay: __overlay__ { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "seeed-4mic-voicecard"; - status = "okay"; - - simple-audio-card,bitclock-master = <&dailink0_slave>; - simple-audio-card,frame-slave = <&dailink0_slave>; - dailink0_slave: simple-audio-card,cpu { - sound-dai = <&i2s>; - }; - codec_dai: simple-audio-card,codec { - sound-dai = <&ac108_a>; - clocks = <&ac108_mclk>; - }; - }; - }; - __overrides__ { - card-name = <&sound_overlay>,"seeed-voicecard,name"; - }; + sound_overlay: __overlay__ { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,name = "seeed-4mic-voicecard"; + status = "okay"; + + simple-audio-card,bitclock-master = <&codec_dai>; + simple-audio-card,frame-master = <&codec_dai>; - + cpu_dai: simple-audio-card,cpu { + sound-dai = <&i2s>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + dai-tdm-slot-tx-mask = <1 1 0 0>; + dai-tdm-slot-rx-mask = <1 1 0 0>; + }; + codec_dai: simple-audio-card,codec { + sound-dai = <&ac108_a>; + clocks = <&ac108_mclk>; + }; + }; + }; + + __overrides__ { + card-name = <&sound_overlay>,"seeed-voicecard,name"; + }; }; diff --git a/seeed-4mic-voicecard.dtbo b/seeed-4mic-voicecard.dtbo index 4ea2ece612c955799306b03e80007198b0409657..171004707692737cd44627f9d4ebff1dbc06e323 100644 GIT binary patch delta 421 zcmbOwuuo9q0`I@K3=ACm7#J8V7#P?^fV2h>3j(nK5CZ|@Dh39&I~z5=GcqzvR$yx8 zVFL>Gr4$#$Co(WhUd^;1_CE*!1(|`E1*m}&NHZbvrGRV&C?9Ajqb`um2*p4O3_yB8 za!x=RMQ-v2X7$PC%qpTF8<0&62lAOG2LNTSGpjJhP5#4d&6qLSf<>RPcyb1itezap zDn5BV3lC!_kfl4>mYIvy0BHC`AWwU;GOG&X?8zRi(TwvaFJVuj(cKx5%P z0olPY`2w>#E687Qo0qWhFvjI37MG+JF%;*Q=B4PSBxW)Iv2IC9u5NKoeu-{gX)dZj ld1gvU2C7g=g)Y#LY*fJ_h~VV??8fZL1*P#oQzvmq0RZ=4TmAq5 delta 272 zcmdldI7>j|0`I@K3=AAn3=9kw3=C{LfV2h>3j(nK5CZ{Y5>UKhqsDheM#jksOwAlD zK*7FDqvFZynHI4A`ws+@d05mZUuISj{Rfm{0%B$$1}bCZ0I?^pVOF1P%%Z}`KRJTM zno)A{6c&9(mB~kdq|W3oEXs^llXtS}@&lEER0FXAP^TwQOnY)Ys|sWAcpu_dai.clk); + rtd->cpu_dai->driver->playback.channels_min = 4; + rtd->cpu_dai->driver->playback.channels_max = 4; + rtd->cpu_dai->driver->capture.channels_min = 4; + rtd->cpu_dai->driver->capture.channels_max = 4; + return ret; } @@ -135,6 +140,11 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + rtd->cpu_dai->driver->playback.channels_min = 2; + rtd->cpu_dai->driver->playback.channels_max = 2; + rtd->cpu_dai->driver->capture.channels_min = 2; + rtd->cpu_dai->driver->capture.channels_max = 2; + clk_disable_unprepare(dai_props->cpu_dai.clk); clk_disable_unprepare(dai_props->codec_dai.clk); @@ -268,6 +278,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, &cpu_dai->rx_slot_mask, &cpu_dai->slots, &cpu_dai->slot_width); + dev_dbg(dev, "cpu_dai : slot,width,tx,rx = %d,%d,%d,%d\n", + cpu_dai->slots, cpu_dai->slot_width, + cpu_dai->tx_slot_mask, cpu_dai->rx_slot_mask + ); if (ret < 0) goto dai_link_of_err;