brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · 8b0bdd9 Raw
152 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 IR8 * 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, in63 * order to be assured of the final space. If there are no edges for a certain64 * 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 = from_timer(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 check76		 * 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	del_timer_sync(&raw->timer);151}152