media: gpio-ir-tx: fix transmit with long spaces on Orange Pi PC
authorSean Young <sean@mess.org>
Sun, 20 Feb 2022 14:28:24 +0000 (15:28 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Mon, 7 Mar 2022 15:29:33 +0000 (16:29 +0100)
Calling udelay for than 1000us does not always yield the correct
results.

Cc: stable@vger.kernel.org
Reported-by: Михаил <vrserver1@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/rc/gpio-ir-tx.c

index c6cd2e6..a50701c 100644 (file)
@@ -48,11 +48,29 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier)
        return 0;
 }
 
+static void delay_until(ktime_t until)
+{
+       /*
+        * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on
+        * m68k ndelay(s64) does not compile; so use s32 rather than s64.
+        */
+       s32 delta;
+
+       while (true) {
+               delta = ktime_us_delta(until, ktime_get());
+               if (delta <= 0)
+                       return;
+
+               /* udelay more than 1ms may not work */
+               delta = min(delta, 1000);
+               udelay(delta);
+       }
+}
+
 static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
                                   uint count)
 {
        ktime_t edge;
-       s32 delta;
        int i;
 
        local_irq_disable();
@@ -63,9 +81,7 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
                gpiod_set_value(gpio_ir->gpio, !(i % 2));
 
                edge = ktime_add_us(edge, txbuf[i]);
-               delta = ktime_us_delta(edge, ktime_get());
-               if (delta > 0)
-                       udelay(delta);
+               delay_until(edge);
        }
 
        gpiod_set_value(gpio_ir->gpio, 0);
@@ -97,9 +113,7 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
                if (i % 2) {
                        // space
                        edge = ktime_add_us(edge, txbuf[i]);
-                       delta = ktime_us_delta(edge, ktime_get());
-                       if (delta > 0)
-                               udelay(delta);
+                       delay_until(edge);
                } else {
                        // pulse
                        ktime_t last = ktime_add_us(edge, txbuf[i]);