ASoC: rockchip: i2s-tdm: Fix channels order for TDM_ONE_FRAME

This patch fix multi-channels order for TDM_ONE_FRAME on SLAVE
mode.

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: Ib6543cf0740516d5df1570245abf07fcce9082c3
This commit is contained in:
Sugar Zhang
2023-12-29 17:06:00 +08:00
parent ce189549b0
commit 13dde084df

View File

@@ -51,8 +51,6 @@
*
*/
#define CLK_MAX_COUNT 1000
#define NSAMPLES 4
#define XFER_EN 0x3
#define XFER_DIS 0x0
#define CKR_V(m, r, t) ((m - 1) << 16 | (r - 1) << 8 | (t - 1) << 0)
@@ -61,6 +59,8 @@
#define I2S_XCR_IBM_LSJM I2S_TXCR_IBM_LSJM
#endif
#define CLK_MAX_COUNT 1000
#define NSAMPLES 4
#define DEFAULT_MCLK_FS 256
#define DEFAULT_FS 48000
#define CH_GRP_MAX 4 /* The max channel 8 / 2 */
@@ -156,9 +156,9 @@ struct rk_i2s_tdm_dev {
bool has_playback;
bool has_capture;
struct snd_soc_dai_driver *dai;
struct gpio_desc *i2s_lrck_gpio;
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
struct snd_soc_dai *clk_src_dai;
struct gpio_desc *i2s_lrck_gpio;
struct gpio_desc *tdm_fsync_gpio;
unsigned int tx_lanes;
unsigned int rx_lanes;
@@ -580,6 +580,87 @@ static void rockchip_i2s_tdm_dma_ctrl(struct rk_i2s_tdm_dev *i2s_tdm,
rockchip_i2s_tdm_fifo_xrun_detect(i2s_tdm, stream, 1);
}
static inline int rockchip_i2s_tdm_clk_assert_h(const struct gpio_desc *desc)
{
int cnt = CLK_MAX_COUNT;
while (gpiod_get_raw_value(desc) && --cnt)
;
return cnt;
}
static inline int rockchip_i2s_tdm_clk_assert_l(const struct gpio_desc *desc)
{
int cnt = CLK_MAX_COUNT;
while (!gpiod_get_raw_value(desc) && --cnt)
;
return cnt;
}
static inline bool rockchip_i2s_tdm_clk_valid(struct rk_i2s_tdm_dev *i2s_tdm,
bool has_fsync)
{
int dc_h = CLK_MAX_COUNT, dc_l = CLK_MAX_COUNT;
/*
* TBD: optimize debounce and get value
*
* debounce at least one cycle found, otherwise, the clk ref maybe
* not on the fly.
*/
/* check HIGH-Level */
dc_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
if (!dc_h)
return false;
/* check LOW-Level */
dc_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
if (!dc_l)
return false;
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
if (!has_fsync)
return true;
/* check HIGH-Level */
dc_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
if (!dc_h)
return false;
/* check LOW-Level */
dc_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
if (!dc_l)
return false;
#endif
return true;
}
static void __maybe_unused rockchip_i2s_tdm_gpio_clk_meas(struct rk_i2s_tdm_dev *i2s_tdm,
const struct gpio_desc *desc,
const char *name)
{
int h[NSAMPLES], l[NSAMPLES], i;
dev_dbg(i2s_tdm->dev, "%s:\n", name);
if (!rockchip_i2s_tdm_clk_valid(i2s_tdm, 1))
return;
for (i = 0; i < NSAMPLES; i++) {
h[i] = rockchip_i2s_tdm_clk_assert_h(desc);
l[i] = rockchip_i2s_tdm_clk_assert_l(desc);
}
for (i = 0; i < NSAMPLES; i++)
dev_dbg(i2s_tdm->dev, "H[%d]: %2d, L[%d]: %2d\n",
i, CLK_MAX_COUNT - h[i], i, CLK_MAX_COUNT - l[i]);
}
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
static const char * const tx_lanes_text[] = { "Auto", "SDOx1", "SDOx2", "SDOx3", "SDOx4" };
static const char * const rx_lanes_text[] = { "Auto", "SDIx1", "SDIx2", "SDIx3", "SDIx4" };
@@ -697,81 +778,6 @@ static int rockchip_i2s_tdm_multi_lanes_set_clk(struct snd_pcm_substream *substr
return 0;
}
static inline int tdm_multi_lanes_clk_assert_h(const struct gpio_desc *desc)
{
int cnt = CLK_MAX_COUNT;
while (gpiod_get_raw_value(desc) && --cnt)
;
return cnt;
}
static inline int tdm_multi_lanes_clk_assert_l(const struct gpio_desc *desc)
{
int cnt = CLK_MAX_COUNT;
while (!gpiod_get_raw_value(desc) && --cnt)
;
return cnt;
}
static inline bool rockchip_i2s_tdm_clk_valid(struct rk_i2s_tdm_dev *i2s_tdm)
{
int dc_h = CLK_MAX_COUNT, dc_l = CLK_MAX_COUNT;
/*
* TBD: optimize debounce and get value
*
* debounce at least one cycle found, otherwise, the clk ref maybe
* not on the fly.
*/
/* check HIGH-Level */
dc_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
if (!dc_h)
return false;
/* check LOW-Level */
dc_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
if (!dc_l)
return false;
/* check HIGH-Level */
dc_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
if (!dc_h)
return false;
/* check LOW-Level */
dc_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
if (!dc_l)
return false;
return true;
}
static void __maybe_unused rockchip_i2s_tdm_gpio_clk_meas(struct rk_i2s_tdm_dev *i2s_tdm,
const struct gpio_desc *desc,
const char *name)
{
int h[NSAMPLES], l[NSAMPLES], i;
dev_dbg(i2s_tdm->dev, "%s:\n", name);
if (!rockchip_i2s_tdm_clk_valid(i2s_tdm))
return;
for (i = 0; i < NSAMPLES; i++) {
h[i] = tdm_multi_lanes_clk_assert_h(desc);
l[i] = tdm_multi_lanes_clk_assert_l(desc);
}
for (i = 0; i < NSAMPLES; i++)
dev_dbg(i2s_tdm->dev, "H[%d]: %2d, L[%d]: %2d\n",
i, CLK_MAX_COUNT - h[i], i, CLK_MAX_COUNT - l[i]);
}
static int rockchip_i2s_tdm_multi_lanes_start(struct rk_i2s_tdm_dev *i2s_tdm, int stream)
{
unsigned int tdm_h = 0, tdm_l = 0, i2s_h = 0, i2s_l = 0;
@@ -799,7 +805,7 @@ static int rockchip_i2s_tdm_multi_lanes_start(struct rk_i2s_tdm_dev *i2s_tdm, in
local_irq_save(flags);
if (!rockchip_i2s_tdm_clk_valid(i2s_tdm)) {
if (!rockchip_i2s_tdm_clk_valid(i2s_tdm, 1)) {
local_irq_restore(flags);
dev_err(i2s_tdm->dev, "Invalid LRCK / FSYNC measured by ref IO\n");
return -EINVAL;
@@ -807,36 +813,36 @@ static int rockchip_i2s_tdm_multi_lanes_start(struct rk_i2s_tdm_dev *i2s_tdm, in
switch (fmt) {
case I2S_XCR_IBM_NORMAL:
tdm_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
tdm_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
tdm_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
tdm_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
if (i2s_tdm->lrck_ratio == 8) {
tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
}
i2s_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
i2s_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
if (stream == SNDRV_PCM_STREAM_CAPTURE)
i2s_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
i2s_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
break;
case I2S_XCR_IBM_LSJM:
tdm_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
tdm_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
tdm_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->tdm_fsync_gpio);
tdm_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->tdm_fsync_gpio);
if (i2s_tdm->lrck_ratio == 8) {
tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
}
tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
i2s_l = tdm_multi_lanes_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
i2s_h = tdm_multi_lanes_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
i2s_l = rockchip_i2s_tdm_clk_assert_l(i2s_tdm->i2s_lrck_gpio);
i2s_h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
break;
default:
local_irq_restore(flags);
@@ -879,19 +885,6 @@ static int rockchip_i2s_tdm_multi_lanes_parse(struct rk_i2s_tdm_dev *i2s_tdm)
i2s_tdm->rx_lanes = val;
}
/*
* Should use flag GPIOD_ASIS not to reclaim LRCK pin as GPIO function,
* because we use the same PIN and just read EXT_PORT value which show
* the pin status.
*/
i2s_tdm->i2s_lrck_gpio = devm_gpiod_get_optional(i2s_tdm->dev, "i2s-lrck",
GPIOD_ASIS);
if (IS_ERR(i2s_tdm->i2s_lrck_gpio)) {
ret = PTR_ERR(i2s_tdm->i2s_lrck_gpio);
dev_err(i2s_tdm->dev, "Failed to get i2s_lrck_gpio %d\n", ret);
return ret;
}
/* It's optional, required when use soc clk src, such as: i2s2_2ch */
clk_src_node = of_parse_phandle(i2s_tdm->dev->of_node, "rockchip,clk-src", 0);
gpiod_flags = clk_src_node ? GPIOD_ASIS : GPIOD_IN;
@@ -931,6 +924,47 @@ static int rockchip_i2s_tdm_multi_lanes_parse(struct rk_i2s_tdm_dev *i2s_tdm)
}
#endif
static int rockchip_i2s_tdm_slave_one_frame_start(struct rk_i2s_tdm_dev *i2s_tdm,
int stream)
{
unsigned int msk, val, h;
unsigned long flags;
bool sof;
sof = i2s_tdm->tdm_mode && !i2s_tdm->is_master_mode &&
!i2s_tdm->tdm_fsync_half_frame;
if (!sof)
return -ENOSYS;
if (!i2s_tdm->i2s_lrck_gpio) {
dev_err(i2s_tdm->dev, "SOF: should assign 'i2s-lrck-gpio' the pin used in DT\n");
return -EINVAL;
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
msk = I2S_XFER_TXS_MASK;
val = I2S_XFER_TXS_START;
} else {
msk = I2S_XFER_RXS_MASK;
val = I2S_XFER_RXS_START;
}
local_irq_save(flags);
if (!rockchip_i2s_tdm_clk_valid(i2s_tdm, 0)) {
local_irq_restore(flags);
dev_err(i2s_tdm->dev, "SOF: invalid LRCK, please check 'i2s-lrck-gpio' in DT\n");
return -EINVAL;
}
h = rockchip_i2s_tdm_clk_assert_h(i2s_tdm->i2s_lrck_gpio);
regmap_update_bits(i2s_tdm->regmap, I2S_XFER, msk, val);
local_irq_restore(flags);
dev_dbg(i2s_tdm->dev, "STREAM[%d]: TDM-H: %d\n", stream, CLK_MAX_COUNT - h);
return 0;
}
static void rockchip_i2s_tdm_xfer_start(struct rk_i2s_tdm_dev *i2s_tdm,
int stream)
{
@@ -940,6 +974,9 @@ static void rockchip_i2s_tdm_xfer_start(struct rk_i2s_tdm_dev *i2s_tdm,
return;
}
#endif
if (rockchip_i2s_tdm_slave_one_frame_start(i2s_tdm, stream) != -ENOSYS)
return;
if (i2s_tdm->clk_trcm) {
rockchip_i2s_tdm_reset_assert(i2s_tdm);
regmap_update_bits(i2s_tdm->regmap, I2S_XFER,
@@ -2931,6 +2968,19 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
i2s_tdm->dev = &pdev->dev;
i2s_tdm->lrck_ratio = 1;
/*
* Should use flag GPIOD_ASIS not to reclaim LRCK pin as GPIO function,
* because we use the same PIN and just read EXT_PORT value which show
* the pin status.
*/
i2s_tdm->i2s_lrck_gpio = devm_gpiod_get_optional(i2s_tdm->dev, "i2s-lrck",
GPIOD_ASIS);
if (IS_ERR(i2s_tdm->i2s_lrck_gpio)) {
ret = PTR_ERR(i2s_tdm->i2s_lrck_gpio);
dev_err(i2s_tdm->dev, "Failed to get i2s_lrck_gpio %d\n", ret);
return ret;
}
of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
if (!of_id)
return -EINVAL;