diff mbox series

media: gpio-ir-tx: re-introduce sleeping for periods of > 50us

Message ID 20200922121743.17701-1-sean@mess.org (mailing list archive)
State New, archived
Headers show
Series media: gpio-ir-tx: re-introduce sleeping for periods of > 50us | expand

Commit Message

Sean Young Sept. 22, 2020, 12:17 p.m. UTC
After commit ea8912b788f8 ("media: gpio-ir-tx: improve precision of
transmitted signal due to scheduling"), the gpio-ir-tx driver disables
interrupts for the entire duration of an IR frame, which is 500ms.

Experimentation on an raspberry pi 3 model b under various loads shows that
sleeping can be done using usleep_range() for periods > 40us.

Fixes: ea8912b788f8 ("media: gpio-ir-tx: improve precision of transmitted signal due to scheduling")
Link: https://lkml.org/lkml/2020/9/2/304
Suggested-by: Pavel Machek <pavel@denx.de>
Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/gpio-ir-tx.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c
index c6cd2e6d8e65..be77c5b0d9d0 100644
--- a/drivers/media/rc/gpio-ir-tx.c
+++ b/drivers/media/rc/gpio-ir-tx.c
@@ -51,11 +51,12 @@  static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier)
 static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
 				   uint count)
 {
+	unsigned long flags;
 	ktime_t edge;
 	s32 delta;
 	int i;
 
-	local_irq_disable();
+	local_irq_save(flags);
 
 	edge = ktime_get();
 
@@ -64,16 +65,25 @@  static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
 
 		edge = ktime_add_us(edge, txbuf[i]);
 		delta = ktime_us_delta(edge, ktime_get());
+		if (delta > 50) {
+			local_irq_restore(flags);
+			usleep_range(delta - 40, delta - 40);
+			local_irq_save(flags);
+			delta = ktime_us_delta(edge, ktime_get());
+		}
 		if (delta > 0)
 			udelay(delta);
 	}
 
 	gpiod_set_value(gpio_ir->gpio, 0);
+
+	local_irq_restore(flags);
 }
 
 static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
 				 uint count)
 {
+	unsigned long flags;
 	ktime_t edge;
 	/*
 	 * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on
@@ -89,7 +99,7 @@  static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
 	space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) *
 				  (NSEC_PER_SEC / 100), gpio_ir->carrier);
 
-	local_irq_disable();
+	local_irq_save(flags);
 
 	edge = ktime_get();
 
@@ -98,6 +108,12 @@  static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
 			// space
 			edge = ktime_add_us(edge, txbuf[i]);
 			delta = ktime_us_delta(edge, ktime_get());
+			if (delta > 50) {
+				local_irq_restore(flags);
+				usleep_range(delta - 40, delta - 40);
+				local_irq_save(flags);
+				delta = ktime_us_delta(edge, ktime_get());
+			}
 			if (delta > 0)
 				udelay(delta);
 		} else {
@@ -122,20 +138,19 @@  static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
 			edge = last;
 		}
 	}
+
+	local_irq_restore(flags);
 }
 
 static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
 		      unsigned int count)
 {
 	struct gpio_ir *gpio_ir = dev->priv;
-	unsigned long flags;
 
-	local_irq_save(flags);
 	if (gpio_ir->carrier)
 		gpio_ir_tx_modulated(gpio_ir, txbuf, count);
 	else
 		gpio_ir_tx_unmodulated(gpio_ir, txbuf, count);
-	local_irq_restore(flags);
 
 	return count;
 }