img-ir-raw.c (3917B)
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 = 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 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 del_timer_sync(&raw->timer); 151}