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