summaryrefslogtreecommitdiff
path: root/drivers/media/rc/sunxi-cir.c
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2020-11-10 11:30:38 +0300
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>2020-11-25 16:51:34 +0300
commit371443de3c991f7b025d5203754a3497b7ea7c32 (patch)
tree9fac2f917b4ecca5799beae4b939b1e0343d7c11 /drivers/media/rc/sunxi-cir.c
parent3f56df4c8ffeb120ed41906d3aae71799b7e726a (diff)
downloadlinux-371443de3c991f7b025d5203754a3497b7ea7c32.tar.xz
media: sunxi-cir: allow timeout to be set at runtime
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 8Mhz. Acked-by: Maxime Ripard <mripard@kernel.org> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/rc/sunxi-cir.c')
-rw-r--r--drivers/media/rc/sunxi-cir.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 4afc5895bee7..8555c7798706 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,41 @@ 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 DIV_ROUND_CLOSEST(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)
+{
+ /* make sure we don't end up with a timeout less than requested */
+ return DIV_ROUND_UP((base_clk / (128 * 64)) * usec, USEC_PER_SEC) - 1;
+}
+
+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 +273,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 +305,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);