From 6e71db4f03dfc8b6cc55467b1826911c92e375de Mon Sep 17 00:00:00 2001 From: Zhe Wang Date: Thu, 28 Mar 2019 18:31:04 +0800 Subject: [PATCH] audio: support 16ch i2s playback for SM1 [1/1] PD#SWPL-5430 Problem: new function lane 6 and lane 8 Solution: support max 16 channel playback Verify: sm1_ac200, verify pass Change-Id: I3af42a0b68bca8804afa042ad4a506a379b9bf86 Signed-off-by: Zhe Wang --- arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts | 14 ++++- sound/soc/amlogic/auge/sm1,clocks.c | 6 +- sound/soc/amlogic/auge/tdm.c | 82 +++++++++++++++++--------- sound/soc/amlogic/auge/tdm_hw.c | 53 +++++++++++++---- sound/soc/amlogic/auge/tdm_hw.h | 6 +- sound/soc/codecs/amlogic/ad82584f.c | 2 +- sound/soc/codecs/amlogic/aml_codec_t9015.c | 2 +- 7 files changed, 115 insertions(+), 50 deletions(-) diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts index f73b280..ddc373e 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts @@ -916,6 +916,8 @@ #sound-dai-cells = <0>; dai-tdm-lane-slot-mask-in = <0 1 0 0>; dai-tdm-lane-slot-mask-out = <1 0 0 0>; + //dai-tdm-lane-slot-mask-in = <0 0 0 0 0 0 0 0>; + //dai-tdm-lane-slot-mask-out = <1 1 1 1 1 1 1 1>; dai-tdm-clk-sel = <1>; clocks = <&clkaudio CLKID_AUDIO_MCLK_B &clkc CLKID_MPLL1 @@ -1084,11 +1086,21 @@ drive-strength = <2>; }; }; + tdmout_b: tdmout_b { - mux { /* GPIOA_1, GPIOA_2, GPIOA_3 */ + mux { /* GPIOA_1, GPIOA_2, GPIOA_3, GPIOA_4, */ + /* GPIOA_5, GPIOA_6, GPIOA_7, GPIOA_8, */ + /* GPIOA_9, GPIOA_0*/ groups = "tdmb_sclk", "tdmb_fs", "tdmb_dout0"; + //"tdmb_dout1", + //"tdmb_dout2", + //"tdmb_dout3_a", + //"tdmb_dout4_a", + //"tdmb_dout5_a", + //"tdmb_dout6_a", + //"tdmb_dout7_a0"; function = "tdmb_out"; drive-strength = <2>; }; diff --git a/sound/soc/amlogic/auge/sm1,clocks.c b/sound/soc/amlogic/auge/sm1,clocks.c index 762186e..6a234b2 100644 --- a/sound/soc/amlogic/auge/sm1,clocks.c +++ b/sound/soc/amlogic/auge/sm1,clocks.c @@ -70,7 +70,7 @@ CLOCK_GATE(audio_reserved5, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 31); CLOCK_GATE(audio_frddrd, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 0); CLOCK_GATE(audio_toddrd, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 1); CLOCK_GATE(audio_loopbackb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 2); -CLOCK_GATE(audio_earc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 6); +CLOCK_GATE(audio_earcrx, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 6); static struct clk_gate *sm1_audio_clk_gates[] = { &audio_ddr_arb, @@ -109,7 +109,7 @@ static struct clk_gate *sm1_audio_clk_gates[] = { &audio_frddrd, &audio_toddrd, &audio_loopbackb, - &audio_earc, + &audio_earcrx, }; /* Array of all clocks provided by this provider */ @@ -150,7 +150,7 @@ static struct clk_hw *sm1_audio_clk_hws[] = { [CLKID_AUDIO_GATE_FRDDRD] = &audio_frddrd.hw, [CLKID_AUDIO_GATE_TODDRD] = &audio_toddrd.hw, [CLKID_AUDIO_GATE_LOOPBACKB] = &audio_loopbackb.hw, - [CLKID_AUDIO_GATE_EARCRX] = &audio_earc.hw, + [CLKID_AUDIO_GATE_EARCRX] = &audio_earcrx.hw, }; static int sm1_clk_gates_init(struct clk **clks, void __iomem *iobase) diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index c1a98cf..8c824cc 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -123,7 +123,7 @@ static const struct snd_pcm_hardware aml_tdm_hardware = { .period_bytes_max = 256 * 1024, .periods_min = 2, .periods_max = 1024, - .buffer_bytes_max = 512 * 1024, + .buffer_bytes_max = 1024 * 1024, .rate_min = 8000, .rate_max = 192000, @@ -617,7 +617,8 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd, aml_tdm_enable(p_tdm->actrl, substream->stream, p_tdm->id, true); udelay(100); - aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, false); + aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, + false, p_tdm->lane_cnt); if (p_tdm->chipinfo && p_tdm->chipinfo->same_src_fn && (p_tdm->samesource_sel >= 0) @@ -647,7 +648,8 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dev_info(substream->pcm->card->dev, "tdm playback stop\n"); aml_frddr_enable(p_tdm->fddr, 0); - aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, true); + aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, + true, p_tdm->lane_cnt); if (p_tdm->chipinfo && p_tdm->chipinfo->same_src_fn && (p_tdm->samesource_sel >= 0) @@ -696,32 +698,31 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, unsigned int channels, int stream) { struct pcm_setting *setting = &p_tdm->setting; - unsigned int lanes, swap_val; + unsigned int lanes, swap_val = 0, swap_val1 = 0; unsigned int lane_mask; unsigned int set_num = 0; unsigned int i; - //unsigned int swap0_val = 0, swap1_val = 0, lane_chs = 0; - pr_debug("asoc channels:%d, slots:%d\n", channels, setting->slots); + pr_debug("asoc channels:%d, slots:%d, lane_cnt:%d\n", + channels, setting->slots, p_tdm->lane_cnt); - swap_val = 0; - // calc lanes by channels and slots + /* calc lanes by channels and slots */ lanes = (channels - 1) / setting->slots + 1; - if (lanes > 4) { + if (lanes > p_tdm->lane_cnt) { pr_err("lanes setting error\n"); return -EINVAL; } #if 1 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - // set lanes mask acordingly + /* set lanes mask acordingly */ if (p_tdm->chipinfo && p_tdm->chipinfo->oe_fn && p_tdm->setting.lane_oe_mask_out) lane_mask = setting->lane_oe_mask_out; else lane_mask = setting->lane_mask_out; - for (i = 0; i < 4; i++) { + for (i = 0; i < p_tdm->lane_cnt; i++) { if (((1 << i) & lane_mask) && lanes) { aml_tdm_set_channel_mask(p_tdm->actrl, stream, p_tdm->id, i, setting->tx_mask); @@ -729,8 +730,10 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, } } swap_val = 0x76543210; + if (p_tdm->lane_cnt > LANE_MAX1) + swap_val1 = 0xfedcba98; aml_tdm_set_lane_channel_swap(p_tdm->actrl, - stream, p_tdm->id, swap_val, 0x0); + stream, p_tdm->id, swap_val, swap_val1); } else { if (p_tdm->chipinfo && p_tdm->chipinfo->oe_fn @@ -739,20 +742,31 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, else lane_mask = setting->lane_mask_in; - for (i = 0; i < 4; i++) { + for (i = 0; i < p_tdm->lane_cnt; i++) { if (i < lanes) aml_tdm_set_channel_mask(p_tdm->actrl, stream, p_tdm->id, i, setting->rx_mask); - if ((1 << i) & lane_mask) { - // each lane only L/R masked - pr_info("tdmin set lane %d\n", i); - swap_val |= (i * 2) << (set_num++ * 4); - swap_val |= (i * 2 + 1) << (set_num++ * 4); + if (((1 << i) & lane_mask) && (i < LANE_MAX1)) { + /* each lane only L/R masked */ + pr_debug("tdmin set lane %d\n", i); + swap_val |= (i * 2) << + (set_num++ * LANE_MAX1); + swap_val |= (i * 2 + 1) << + (set_num++ * LANE_MAX1); + } + if (((1 << i) & lane_mask) && (i >= LANE_MAX1) + && (i < LANE_MAX3)) { + /* each lane only L/R masked */ + pr_debug("tdmin set lane %d\n", i); + swap_val1 |= (i * 2) << + (set_num++ * LANE_MAX1); + swap_val1 |= (i * 2 + 1) << + (set_num++ * LANE_MAX1); } } aml_tdm_set_lane_channel_swap(p_tdm->actrl, - stream, p_tdm->id, swap_val, 0x0); + stream, p_tdm->id, swap_val, swap_val1); } #else @@ -1129,6 +1143,7 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, lanes_lb_cnt); pr_debug("\tslots(%d), slot_width(%d)\n", slots, slot_width); + p_tdm->setting.tx_mask = tx_mask; p_tdm->setting.rx_mask = rx_mask; p_tdm->setting.slots = slots; @@ -1193,11 +1208,11 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, in_src = ACODEC_ADC; } - if (in_lanes >= 0 && in_lanes <= 4) + if (in_lanes > 0 && in_lanes <= LANE_MAX3) aml_tdm_set_slot_in(p_tdm->actrl, p_tdm->id, in_src, slot_width); - if (out_lanes >= 0 && out_lanes <= 4) + if (out_lanes > 0 && out_lanes <= LANE_MAX3) aml_tdm_set_slot_out(p_tdm->actrl, p_tdm->id, slots, slot_width, force_oe, oe_val); @@ -1237,11 +1252,14 @@ static int aml_dai_tdm_mute_stream(struct snd_soc_dai *cpu_dai, struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - pr_debug("tdm playback mute: %d\n", mute); - //aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, mute); + pr_debug("tdm playback mute: %d, lane_cnt = %d\n", + mute, p_tdm->lane_cnt); + //aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, + // mute, p_tdm->lane_cnt); } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { pr_debug("tdm capture mute: %d\n", mute); - aml_tdm_mute_capture(p_tdm->actrl, p_tdm->id, mute); + aml_tdm_mute_capture(p_tdm->actrl, p_tdm->id, + mute, p_tdm->lane_cnt); } return 0; } @@ -1291,7 +1309,7 @@ static struct snd_soc_dai_driver aml_tdm_dai[] = { .remove = aml_dai_tdm_remove, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = 32, .rates = AML_DAI_TDM_RATES, .formats = AML_DAI_TDM_FORMATS, }, @@ -1311,7 +1329,7 @@ static struct snd_soc_dai_driver aml_tdm_dai[] = { .remove = aml_dai_tdm_remove, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = 32, .rates = AML_DAI_TDM_RATES, .formats = AML_DAI_TDM_FORMATS, }, @@ -1401,9 +1419,10 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) p_tdm->id = p_chipinfo->id; if (!p_chipinfo->lane_cnt) p_chipinfo->lane_cnt = LANE_MAX1; - else - p_tdm->lane_cnt = p_chipinfo->lane_cnt; - pr_info("%s, tdm ID = %u\n", __func__, p_tdm->id); + + p_tdm->lane_cnt = p_chipinfo->lane_cnt; + pr_info("%s, tdm ID = %u, lane_cnt = %d\n", __func__, + p_tdm->id, p_tdm->lane_cnt); /* get audio controller */ node_prt = of_get_parent(node); @@ -1506,6 +1525,11 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) if (ret < 0) p_tdm->setting.lane_lb_mask_in = 0x0; + dev_info(&pdev->dev, + "lane_mask_out = %x, lane_oe_mask_out = %x\n", + p_tdm->setting.lane_mask_out, + p_tdm->setting.lane_oe_mask_out); + p_tdm->clk = devm_clk_get(&pdev->dev, "clk_srcpll"); if (IS_ERR(p_tdm->clk)) { dev_err(&pdev->dev, "Can't retrieve mpll2 clock\n"); diff --git a/sound/soc/amlogic/auge/tdm_hw.c b/sound/soc/amlogic/auge/tdm_hw.c index c3d9863..08cc846 100644 --- a/sound/soc/amlogic/auge/tdm_hw.c +++ b/sound/soc/amlogic/auge/tdm_hw.c @@ -545,21 +545,27 @@ void aml_tdm_set_channel_mask( unsigned int offset, reg; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (lane >= LANE_MAX1) + if (lane >= LANE_MAX1) { offset = EE_AUDIO_TDMOUT_B_MASK4 - EE_AUDIO_TDMOUT_A_MASK4; - else + reg = EE_AUDIO_TDMOUT_A_MASK4 + offset * index; + lane -= LANE_MAX1; + } else { offset = EE_AUDIO_TDMOUT_B_MASK0 - EE_AUDIO_TDMOUT_A_MASK0; - reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index; + reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index; + } } else { - if (lane >= LANE_MAX1) + if (lane >= LANE_MAX1) { offset = EE_AUDIO_TDMIN_B_MASK4 - EE_AUDIO_TDMIN_A_MASK4; - else + reg = EE_AUDIO_TDMIN_A_MASK4 + offset * index; + lane -= LANE_MAX1; + } else { offset = EE_AUDIO_TDMIN_B_MASK0 - EE_AUDIO_TDMIN_A_MASK0; - reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index; + reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index; + } } aml_audiobus_write(actrl, reg + lane, mask); @@ -744,12 +750,13 @@ void i2s_to_hdmitx_ctrl(int tdm_index) void aml_tdm_mute_playback( struct aml_audio_controller *actrl, int tdm_index, - bool mute) + bool mute, + int lane_cnt) { unsigned int offset, reg; unsigned int mute_mask = 0xffffffff; unsigned int mute_val = 0; - int i = 0, lanes = 4; + int i = 0; if (mute) mute_val = 0xffffffff; @@ -757,19 +764,29 @@ void aml_tdm_mute_playback( offset = EE_AUDIO_TDMOUT_B_MUTE0 - EE_AUDIO_TDMOUT_A_MUTE0; reg = EE_AUDIO_TDMOUT_A_MUTE0 + offset * tdm_index; - for (i = 0; i < lanes; i++) + for (i = 0; i < LANE_MAX1; i++) aml_audiobus_update_bits(actrl, reg + i, mute_mask, mute_val); + + if (lane_cnt > LANE_MAX1) { + offset = EE_AUDIO_TDMOUT_B_MUTE4 + - EE_AUDIO_TDMOUT_A_MUTE4; + reg = EE_AUDIO_TDMOUT_A_MUTE4 + offset * tdm_index; + for (i = 0; i < LANE_MAX1; i++) + aml_audiobus_update_bits(actrl, reg + i, + mute_mask, mute_val); + } } void aml_tdm_mute_capture( struct aml_audio_controller *actrl, int tdm_index, - bool mute) + bool mute, + int lane_cnt) { unsigned int offset, reg; unsigned int mute_mask = 0xffffffff; unsigned int mute_val = 0; - int i = 0, lanes = 4; + int i = 0; if (mute) mute_val = 0xffffffff; @@ -777,7 +794,17 @@ void aml_tdm_mute_capture( offset = EE_AUDIO_TDMIN_B_MUTE0 - EE_AUDIO_TDMIN_A_MUTE0; reg = EE_AUDIO_TDMIN_A_MUTE0 + offset * tdm_index; - for (i = 0; i < lanes; i++) - aml_audiobus_update_bits(actrl, reg + i, mute_mask, mute_val); + for (i = 0; i < LANE_MAX1; i++) + aml_audiobus_update_bits(actrl, reg + i, + mute_mask, mute_val); + + if (lane_cnt > LANE_MAX1) { + offset = EE_AUDIO_TDMIN_B_MUTE4 + - EE_AUDIO_TDMIN_A_MUTE4; + reg = EE_AUDIO_TDMIN_A_MUTE4 + offset * tdm_index; + for (i = 0; i < LANE_MAX1; i++) + aml_audiobus_update_bits(actrl, reg + i, + mute_mask, mute_val); + } } diff --git a/sound/soc/amlogic/auge/tdm_hw.h b/sound/soc/amlogic/auge/tdm_hw.h index dc12289..9bb21ac 100644 --- a/sound/soc/amlogic/auge/tdm_hw.h +++ b/sound/soc/amlogic/auge/tdm_hw.h @@ -155,9 +155,11 @@ extern void i2s_to_hdmitx_ctrl(int tdm_index); void aml_tdm_mute_playback( struct aml_audio_controller *actrl, int index, - bool mute); + bool mute, + int lane_cnt); void aml_tdm_mute_capture( struct aml_audio_controller *actrl, int tdm_index, - bool mute); + bool mute, + int lane_cnt); #endif diff --git a/sound/soc/codecs/amlogic/ad82584f.c b/sound/soc/codecs/amlogic/ad82584f.c index 8e68ad5..1cfb5c2 100644 --- a/sound/soc/codecs/amlogic/ad82584f.c +++ b/sound/soc/codecs/amlogic/ad82584f.c @@ -728,7 +728,7 @@ static struct snd_soc_dai_driver ad82584f_dai = { .playback = { .stream_name = "HIFI Playback", .channels_min = 2, - .channels_max = 8, + .channels_max = 16, .rates = AD82584F_RATES, .formats = AD82584F_FORMATS, }, diff --git a/sound/soc/codecs/amlogic/aml_codec_t9015.c b/sound/soc/codecs/amlogic/aml_codec_t9015.c index 9085aa6d..2fbfe60 100644 --- a/sound/soc/codecs/amlogic/aml_codec_t9015.c +++ b/sound/soc/codecs/amlogic/aml_codec_t9015.c @@ -465,7 +465,7 @@ struct snd_soc_dai_driver aml_T9015_audio_dai[] = { .playback = { .stream_name = "HIFI Playback", .channels_min = 2, - .channels_max = 8, + .channels_max = 16, .rates = T9015_AUDIO_STEREO_RATES, .formats = T9015_AUDIO_FORMATS, }, -- 2.7.4