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 <Zhe.Wang@amlogic.com>
This commit is contained in:
Zhe Wang
2019-03-28 18:31:04 +08:00
committed by Tao Zeng
parent 867ae48973
commit 6e71db4f03
7 changed files with 115 additions and 50 deletions

View File

@@ -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>;
};

View File

@@ -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)

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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,
},

View File

@@ -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,
},