mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
ASoC: rockchip: i2s-tdm; Fix frame sync duty cycle
There maybe a risk that FRAME sync is not 50% duty cycle
on TRCM mode, which will cause sound noise.
This patch wraps XFER-start with reset to fix this issue.
- Hold reset
- Enable XFER
- Release reset
e.g. RK3308
Enable TRCM:
&i2s_8ch_0 {
assigned-clocks = <&cru SCLK_I2S0_8CH_RX>;
assigned-clock-parents = <&cru SCLK_I2S0_8CH_TX_MUX>;
rockchip,clk-trcm = <1>;
}
StressTest:
/#!/bin/sh
count=0
while true
do
yes `echo -en "\x11\x11\x22\x22"` | tr -d '\n' | \
aplay -D hw:1,0 --period-size=1024 --buffer-size=4096 -r 192000 -c 2 -f s16_le &>/dev/null &
sleep 2
rxd=`io -4 0xff300028 | awk '{print $2}'`
echo "[$count]: $rxd"
if [ "$rxd" != "22221111" ]; then
echo "FAIL: mismatch: $rxd, expected: 22221111"
break
fi
count=$((count + 1))
killall aplay
sleep 1
done
Result:
Before:
[35]: 22221111
[36]: 22221111
[37]: 11110888
FAIL: mismatch: 11110888, expected: 22221111
[253]: 22221111
[254]: 22221111
[255]: 11110888
FAIL: mismatch: 11110888, expected: 22221111
[319]: 22221111
[320]: 22221111
[321]: 11110888
FAIL: mismatch: 11110888, expected: 22221111
After this patch:
PASS on 100000+ loop count.
[ 99998]: 22221111
[ 99999]: 22221111
[100000]: 22221111
[100001]: 22221111
...
Change-Id: I77931c529acb43ef0bf7468e2c74ac9ff419218e
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
@@ -181,14 +181,30 @@ static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
|
||||
#define writeq(v,c) ({ __iowmb(); __raw_writeq((__force u64) cpu_to_le64(v), c); })
|
||||
#endif
|
||||
|
||||
static void rockchip_snd_xfer_reset_assert(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
int tx_bank, int tx_offset,
|
||||
int rx_bank, int rx_offset)
|
||||
static void rockchip_snd_xfer_reset_assert(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
int tx_bank, rx_bank, tx_offset, rx_offset, tx_id, rx_id;
|
||||
void __iomem *cru_reset, *addr;
|
||||
unsigned long flags;
|
||||
u64 val;
|
||||
|
||||
if (!i2s_tdm->cru_base || !i2s_tdm->soc_data || !i2s_tdm->is_master_mode)
|
||||
return;
|
||||
|
||||
tx_id = i2s_tdm->tx_reset_id;
|
||||
rx_id = i2s_tdm->rx_reset_id;
|
||||
if (tx_id < 0 || rx_id < 0)
|
||||
return;
|
||||
|
||||
tx_bank = tx_id / 16;
|
||||
tx_offset = tx_id % 16;
|
||||
rx_bank = rx_id / 16;
|
||||
rx_offset = rx_id % 16;
|
||||
|
||||
dev_dbg(i2s_tdm->dev,
|
||||
"tx_bank: %d, rx_bank: %d,tx_offset: %d, rx_offset: %d\n",
|
||||
tx_bank, rx_bank, tx_offset, rx_offset);
|
||||
|
||||
cru_reset = i2s_tdm->cru_base + i2s_tdm->soc_data->softrst_offset;
|
||||
|
||||
switch (abs(tx_bank - rx_bank)) {
|
||||
@@ -228,14 +244,30 @@ static void rockchip_snd_xfer_reset_assert(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
static void rockchip_snd_xfer_reset_deassert(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
int tx_bank, int tx_offset,
|
||||
int rx_bank, int rx_offset)
|
||||
static void rockchip_snd_xfer_reset_deassert(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
int tx_bank, rx_bank, tx_offset, rx_offset, tx_id, rx_id;
|
||||
void __iomem *cru_reset, *addr;
|
||||
unsigned long flags;
|
||||
u64 val;
|
||||
|
||||
if (!i2s_tdm->cru_base || !i2s_tdm->soc_data || !i2s_tdm->is_master_mode)
|
||||
return;
|
||||
|
||||
tx_id = i2s_tdm->tx_reset_id;
|
||||
rx_id = i2s_tdm->rx_reset_id;
|
||||
if (tx_id < 0 || rx_id < 0)
|
||||
return;
|
||||
|
||||
tx_bank = tx_id / 16;
|
||||
tx_offset = tx_id % 16;
|
||||
rx_bank = rx_id / 16;
|
||||
rx_offset = rx_id % 16;
|
||||
|
||||
dev_dbg(i2s_tdm->dev,
|
||||
"tx_bank: %d, rx_bank: %d,tx_offset: %d, rx_offset: %d\n",
|
||||
tx_bank, rx_bank, tx_offset, rx_offset);
|
||||
|
||||
cru_reset = i2s_tdm->cru_base + i2s_tdm->soc_data->softrst_offset;
|
||||
|
||||
switch (abs(tx_bank - rx_bank)) {
|
||||
@@ -280,31 +312,16 @@ static void rockchip_snd_xfer_reset_deassert(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
*/
|
||||
static void rockchip_snd_xfer_sync_reset(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
int tx_id, rx_id;
|
||||
int tx_bank, rx_bank, tx_offset, rx_offset;
|
||||
|
||||
if (!i2s_tdm->cru_base || !i2s_tdm->soc_data || !i2s_tdm->is_master_mode)
|
||||
return;
|
||||
|
||||
tx_id = i2s_tdm->tx_reset_id;
|
||||
rx_id = i2s_tdm->rx_reset_id;
|
||||
if (tx_id < 0 || rx_id < 0)
|
||||
return;
|
||||
|
||||
tx_bank = tx_id / 16;
|
||||
tx_offset = tx_id % 16;
|
||||
rx_bank = rx_id / 16;
|
||||
rx_offset = rx_id % 16;
|
||||
dev_dbg(i2s_tdm->dev,
|
||||
"tx_bank: %d, rx_bank: %d,tx_offset: %d, rx_offset: %d\n",
|
||||
tx_bank, rx_bank, tx_offset, rx_offset);
|
||||
|
||||
rockchip_snd_xfer_reset_assert(i2s_tdm, tx_bank, tx_offset,
|
||||
rx_bank, rx_offset);
|
||||
rockchip_snd_xfer_reset_deassert(i2s_tdm, tx_bank, tx_offset,
|
||||
rx_bank, rx_offset);
|
||||
rockchip_snd_xfer_reset_assert(i2s_tdm);
|
||||
rockchip_snd_xfer_reset_deassert(i2s_tdm);
|
||||
}
|
||||
#else
|
||||
static inline void rockchip_snd_xfer_reset_assert(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
}
|
||||
static inline void rockchip_snd_xfer_reset_deassert(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
}
|
||||
static inline void rockchip_snd_xfer_sync_reset(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
{
|
||||
}
|
||||
@@ -331,12 +348,13 @@ static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,
|
||||
I2S_DMACR_RDE_ENABLE);
|
||||
|
||||
if (atomic_inc_return(&i2s_tdm->refcount) == 1) {
|
||||
rockchip_snd_xfer_sync_reset(i2s_tdm);
|
||||
rockchip_snd_xfer_reset_assert(i2s_tdm);
|
||||
regmap_update_bits(i2s_tdm->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START);
|
||||
rockchip_snd_xfer_reset_deassert(i2s_tdm);
|
||||
}
|
||||
} else {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
@@ -699,11 +717,13 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream,
|
||||
I2S_DMACR_RDE_ENABLE,
|
||||
I2S_DMACR_RDE_ENABLE);
|
||||
|
||||
rockchip_snd_xfer_reset_assert(i2s_tdm);
|
||||
regmap_update_bits(i2s_tdm->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START);
|
||||
rockchip_snd_xfer_reset_deassert(i2s_tdm);
|
||||
}
|
||||
|
||||
static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
|
||||
Reference in New Issue
Block a user