diff mbox series

[2/2] media: sunxi-cir: allow timeout to be set at runtime

Message ID 20201110091557.25680-2-sean@mess.org (mailing list archive)
State New, archived
Headers show
Series [1/2] media: sunxi-cir: ensure IR is handled when it is continuous | expand

Commit Message

Sean Young Nov. 10, 2020, 9:15 a.m. UTC
This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl.

The timeout was hardcoded at just over 20ms, but returned 120ms when
queried with the LIRC_GET_REC_TIMEOUT ioctl.

This also ensures the idle threshold is set correctly with a base clock
other than 8000000Mhz.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/sunxi-cir.c | 46 +++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 8 deletions(-)

Comments

Maxime Ripard Nov. 10, 2020, 12:11 p.m. UTC | #1
On Tue, Nov 10, 2020 at 09:15:57AM +0000, Sean Young wrote:
> This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl.
> 
> The timeout was hardcoded at just over 20ms, but returned 120ms when
> queried with the LIRC_GET_REC_TIMEOUT ioctl.
> 
> This also ensures the idle threshold is set correctly with a base clock
> other than 8000000Mhz.

That's some pretty hardcore overclocking :)

I guess you meant 8MHz?

Other than that, for both patches

Acked-by: Maxime Ripard <mripard@kernel.org>

Thanks!
Maxime
Sean Young Nov. 13, 2020, 3:36 p.m. UTC | #2
On Tue, Nov 10, 2020 at 01:11:22PM +0100, maxime@cerno.tech wrote:
> On Tue, Nov 10, 2020 at 09:15:57AM +0000, Sean Young wrote:
> > This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl.
> > 
> > The timeout was hardcoded at just over 20ms, but returned 120ms when
> > queried with the LIRC_GET_REC_TIMEOUT ioctl.
> > 
> > This also ensures the idle threshold is set correctly with a base clock
> > other than 8000000Mhz.
> 
> That's some pretty hardcore overclocking :)
> 
> I guess you meant 8MHz?

Yes, I did.

> Other than that, for both patches
> 
> Acked-by: Maxime Ripard <mripard@kernel.org>

Thanks!

Sean
diff mbox series

Patch

diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 4afc5895bee74..3c25db25e55c6 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -73,10 +73,6 @@ 
 #define SUNXI_IR_BASE_CLK     8000000
 /* Noise threshold in samples  */
 #define SUNXI_IR_RXNOISE      1
-/* Idle Threshold in samples */
-#define SUNXI_IR_RXIDLE       20
-/* Time after which device stops sending data in ms */
-#define SUNXI_IR_TIMEOUT      120
 
 /**
  * struct sunxi_ir_quirks - Differences between SoC variants.
@@ -146,6 +142,39 @@  static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/* Convert idle threshold to usec */
+static unsigned int sunxi_ithr_to_usec(unsigned int base_clk, unsigned int ithr)
+{
+	return (USEC_PER_SEC * (ithr + 1)) / (base_clk / (128 * 64));
+}
+
+/* Convert usec to idle threshold */
+static unsigned int sunxi_usec_to_ithr(unsigned int base_clk, unsigned int usec)
+{
+	return ((base_clk / (128 * 64)) * usec) / USEC_PER_SEC;
+}
+
+static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout)
+{
+	struct sunxi_ir *ir = rc_dev->priv;
+	unsigned int base_clk = clk_get_rate(ir->clk);
+	unsigned long flags;
+
+	unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout);
+
+	dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr);
+
+	spin_lock_irqsave(&ir->ir_lock, flags);
+	/* Set noise threshold and idle threshold */
+	writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr),
+	       ir->base + SUNXI_IR_CIR_REG);
+	spin_unlock_irqrestore(&ir->ir_lock, flags);
+
+	rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr);
+
+	return 0;
+}
+
 static int sunxi_ir_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -242,9 +271,11 @@  static int sunxi_ir_probe(struct platform_device *pdev)
 	ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
 	ir->rc->dev.parent = dev;
 	ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
-	/* Frequency after IR internal divider with sample period in ns */
+	/* Frequency after IR internal divider with sample period in us */
 	ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64));
-	ir->rc->timeout = MS_TO_US(SUNXI_IR_TIMEOUT);
+	ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0);
+	ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255);
+	ir->rc->s_timeout = sunxi_ir_set_timeout;
 	ir->rc->driver_name = SUNXI_IR_DEV;
 
 	ret = rc_register_device(ir->rc);
@@ -272,8 +303,7 @@  static int sunxi_ir_probe(struct platform_device *pdev)
 	writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);
 
 	/* Set noise threshold and idle threshold */
-	writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE),
-	       ir->base + SUNXI_IR_CIR_REG);
+	sunxi_ir_set_timeout(ir->rc, IR_DEFAULT_TIMEOUT);
 
 	/* Invert Input Signal */
 	writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);