From 8a5153490313279ed9c28708200d9815f0bdc36e Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Wed, 30 Aug 2023 09:10:28 -0300 Subject: [PATCH] esp32s3/i2s: Check compatibility of the current master clock set The master clock frequency should be multiple of the sample rate and bit clock at the same time. Then, check if the current master clock satisfies such a condition and set it accordingly otherwise. --- arch/xtensa/src/esp32s3/esp32s3_i2s.c | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/arch/xtensa/src/esp32s3/esp32s3_i2s.c b/arch/xtensa/src/esp32s3/esp32s3_i2s.c index 2a9e681a451..34bda4b3c18 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_i2s.c +++ b/arch/xtensa/src/esp32s3/esp32s3_i2s.c @@ -364,6 +364,7 @@ static void i2s_rx_schedule(struct esp32s3_i2s_s *priv, /* I2S methods (and close friends) */ +static int32_t i2s_check_mclkfrequency(struct esp32s3_i2s_s *priv); static uint32_t i2s_set_datawidth(struct esp32s3_i2s_s *priv); static uint32_t i2s_set_clock(struct esp32s3_i2s_s *priv); static uint32_t i2s_getmclkfrequency(struct i2s_dev_s *dev); @@ -1710,6 +1711,58 @@ static void i2s_configure(struct esp32s3_i2s_s *priv) } } +/**************************************************************************** + * Name: i2s_check_mclkfrequency + * + * Description: + * Check if MCLK frequency is compatible with the current data width and + * bits/sample set. Master clock should be multiple of the sample rate and + * bclk at the same time. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * Returns the current master clock or a negated errno value on failure. + * + ****************************************************************************/ + +static int32_t i2s_check_mclkfrequency(struct esp32s3_i2s_s *priv) +{ + uint32_t mclk_freq; + uint32_t mclk_multiple = priv->mclk_multiple; + uint32_t bclk = priv->rate * priv->config->total_slot * priv->data_width; + int i; + + /* If the master clock is divisible by both the sample rate and the bit + * clock, everything is as expected and we can return the current master + * clock frequency. + */ + + if (priv->mclk_freq % priv->rate == 0 && priv->mclk_freq % bclk == 0) + { + priv->mclk_multiple = priv->mclk_freq / priv->rate; + return priv->mclk_freq; + } + + /* Select the lowest multiplier for setting the master clock */ + + for (mclk_multiple = I2S_MCLK_MULTIPLE_128; + mclk_multiple <= I2S_MCLK_MULTIPLE_512; + mclk_multiple += I2S_MCLK_MULTIPLE_128) + { + mclk_freq = priv->rate * mclk_multiple; + if (mclk_freq % priv->rate == 0 && mclk_freq % bclk == 0) + { + priv->mclk_multiple = mclk_multiple; + i2s_setmclkfrequency((struct i2s_dev_s *)priv, mclk_freq); + return priv->mclk_freq; + } + } + + return -EINVAL; +} + /**************************************************************************** * Name: i2s_set_datawidth * @@ -2540,6 +2593,11 @@ static uint32_t i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate) priv->rate = rate; + if (i2s_check_mclkfrequency(priv) < OK) + { + return 0; + } + rate = i2s_set_clock(priv); i2s_tx_channel_start(priv); @@ -2577,6 +2635,11 @@ static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate) priv->rate = rate; + if (i2s_check_mclkfrequency(priv) < OK) + { + return 0; + } + rate = i2s_set_clock(priv); i2s_rx_channel_start(priv);