File Index
Files and directories
Sign in
FILE

img-ir-raw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/rc/img-ir/img-ir-raw.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * ImgTec IR Raw Decoder found in PowerDown Controller.
  4 *
  5 * Copyright 2010-2014 Imagination Technologies Ltd.
  6 *
  7 * This ties into the input subsystem using the RC-core in raw mode. Raw IR
  8 * signal edges are reported and decoded by generic software decoders.
  9 */
 10
 11#include <linux/spinlock.h>
 12#include <media/rc-core.h>
 13#include "img-ir.h"
 14
 15#define ECHO_TIMEOUT_MS 150	/* ms between echos */
 16
 17/* must be called with priv->lock held */
 18static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
 19{
 20	struct img_ir_priv_raw *raw = &priv->raw;
 21	struct rc_dev *rc_dev = priv->raw.rdev;
 22	int multiple;
 23	u32 ir_status;
 24
 25	/* find whether both rise and fall was detected */
 26	multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
 27	/*
 28	 * If so, we need to see if the level has actually changed.
 29	 * If it's just noise that we didn't have time to process,
 30	 * there's no point reporting it.
 31	 */
 32	ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
 33	if (multiple && ir_status == raw->last_status)
 34		return;
 35	raw->last_status = ir_status;
 36
 37	/* report the edge to the IR raw decoders */
 38	if (ir_status) /* low */
 39		ir_raw_event_store_edge(rc_dev, false);
 40	else /* high */
 41		ir_raw_event_store_edge(rc_dev, true);
 42	ir_raw_event_handle(rc_dev);
 43}
 44
 45/* called with priv->lock held */
 46void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
 47{
 48	struct img_ir_priv_raw *raw = &priv->raw;
 49
 50	/* check not removing */
 51	if (!raw->rdev)
 52		return;
 53
 54	img_ir_refresh_raw(priv, irq_status);
 55
 56	/* start / push back the echo timer */
 57	mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
 58}
 59
 60/*
 61 * Echo timer callback function.
 62 * The raw decoders expect to get a final sample even if there are no edges, in
 63 * order to be assured of the final space. If there are no edges for a certain
 64 * time we use this timer to emit a final sample to satisfy them.
 65 */
 66static void img_ir_echo_timer(struct timer_list *t)
 67{
 68	struct img_ir_priv *priv = timer_container_of(priv, t, raw.timer);
 69
 70	spin_lock_irq(&priv->lock);
 71
 72	/* check not removing */
 73	if (priv->raw.rdev)
 74		/*
 75		 * It's safe to pass irq_status=0 since it's only used to check
 76		 * for double edges.
 77		 */
 78		img_ir_refresh_raw(priv, 0);
 79
 80	spin_unlock_irq(&priv->lock);
 81}
 82
 83void img_ir_setup_raw(struct img_ir_priv *priv)
 84{
 85	u32 irq_en;
 86
 87	if (!priv->raw.rdev)
 88		return;
 89
 90	/* clear and enable edge interrupts */
 91	spin_lock_irq(&priv->lock);
 92	irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
 93	irq_en |= IMG_IR_IRQ_EDGE;
 94	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
 95	img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
 96	spin_unlock_irq(&priv->lock);
 97}
 98
 99int img_ir_probe_raw(struct img_ir_priv *priv)
100{
101	struct img_ir_priv_raw *raw = &priv->raw;
102	struct rc_dev *rdev;
103	int error;
104
105	/* Set up the echo timer */
106	timer_setup(&raw->timer, img_ir_echo_timer, 0);
107
108	/* Allocate raw decoder */
109	raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
110	if (!rdev) {
111		dev_err(priv->dev, "cannot allocate raw input device\n");
112		return -ENOMEM;
113	}
114	rdev->priv = priv;
115	rdev->map_name = RC_MAP_EMPTY;
116	rdev->device_name = "IMG Infrared Decoder Raw";
117
118	/* Register raw decoder */
119	error = rc_register_device(rdev);
120	if (error) {
121		dev_err(priv->dev, "failed to register raw IR input device\n");
122		rc_free_device(rdev);
123		raw->rdev = NULL;
124		return error;
125	}
126
127	return 0;
128}
129
130void img_ir_remove_raw(struct img_ir_priv *priv)
131{
132	struct img_ir_priv_raw *raw = &priv->raw;
133	struct rc_dev *rdev = raw->rdev;
134	u32 irq_en;
135
136	if (!rdev)
137		return;
138
139	/* switch off and disable raw (edge) interrupts */
140	spin_lock_irq(&priv->lock);
141	raw->rdev = NULL;
142	irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
143	irq_en &= ~IMG_IR_IRQ_EDGE;
144	img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
145	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
146	spin_unlock_irq(&priv->lock);
147
148	rc_unregister_device(rdev);
149
150	timer_delete_sync(&raw->timer);
151}
~/ Read-only file preview.