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