From a3986eeba34ae6d776ce3d7baeaa802017a310fc Mon Sep 17 00:00:00 2001
From: Michal Lenc <michallenc@seznam.cz>
Date: Wed, 4 Aug 2021 23:05:27 +0200
Subject: [PATCH] arch/arm/src/imxrt/imxrt_flexpwm.c: Set LDOK bits after all
 channels are set

This commit changes the FLexPWM driver for iMXRT MCU so that LDOK bits in
Master Control Register are set at once after all channels are configured.
Setting LDOK bit enables the driver to load prescaler, modulus and PWM
values of corresponging submodule and start PWM output. Setting all bits
at once instead of doing it separately can help avoiding the channels to
be out of sync with each other.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
---
 arch/arm/src/imxrt/imxrt_flexpwm.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/arch/arm/src/imxrt/imxrt_flexpwm.c b/arch/arm/src/imxrt/imxrt_flexpwm.c
index 16885db51e..64913cbdc6 100644
--- a/arch/arm/src/imxrt/imxrt_flexpwm.c
+++ b/arch/arm/src/imxrt/imxrt_flexpwm.c
@@ -616,10 +616,6 @@ static int pwm_change_freq(FAR struct pwm_lowerhalf_s *dev,
   putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0VAL5_OFFSET
                               + MODULE_OFFSET * shift);
 
-  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
-  regval |= MCTRL_LDOK(1 << shift);
-  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
-
   return OK;
 }
 
@@ -683,10 +679,6 @@ static int pwm_set_output(FAR struct pwm_lowerhalf_s *dev, uint8_t channel,
       putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
     }
 
-  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
-  regval |= MCTRL_LDOK(1 << shift);
-  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
-
   return OK;
 }
 
@@ -887,6 +879,7 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
 {
   FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
   int ret = OK;
+  uint8_t ldok_map = 0;
 
   /* Change frequency only if it is needed */
 
@@ -894,6 +887,7 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
     {
       for (int i = 0; i < PWM_NCHANNELS; i++)
         {
+#ifdef CONFIG_PWM_MULTICHAN
           /* Break the loop if all following channels are not configured */
 
           if (info->channels[i].channel == -1)
@@ -907,6 +901,9 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
             {
               ret = pwm_change_freq(dev, info, i);
             }
+#else
+          ret = pwm_change_freq(dev, info, i);
+#endif
         }
 
       /* Save current frequency */
@@ -933,14 +930,28 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
         {
           ret = pwm_set_output(dev, info->channels[i].channel,
                                     info->channels[i].duty);
+
+          /* Remember the channel number in bitmap */
+
+          ldok_map |= 1 << (info->channels[i].channel - 1);
         }
     }
 #else
   /* Enable PWM output just for first channel */
 
   ret = pwm_set_output(dev, priv->modules[0].module, info->duty);
+
+  /* Remember the channel number in bitmap */
+
+  ldok_map = 1 << (priv->modules[0].module - 1);
 #endif /* CONFIG_PWM_MULTICHAN */
 
+  /* Set Load Okay bits */
+
+  uint16_t regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+  regval |= MCTRL_LDOK(ldok_map);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
   return ret;
 }