This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 8a5153490313279ed9c28708200d9815f0bdc36e
Author: Tiago Medicci Serrano <[email protected]>
AuthorDate: Wed Aug 30 09:10:28 2023 -0300

    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 2a9e681a45..34bda4b3c1 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);

Reply via email to