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 */ 22static 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 */ 50void 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 */ 70static 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 87void 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 103int 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(); 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 rdev->driver_type = RC_DRIVER_IR_RAW; 122 123 /* Register raw decoder */ 124 error = rc_register_device(rdev); 125 if (error) { 126 dev_err(priv->dev, "failed to register raw IR input device\n"); 127 rc_free_device(rdev); 128 raw->rdev = NULL; 129 return error; 130 } 131 132 return 0; 133} 134 135void img_ir_remove_raw(struct img_ir_priv *priv) 136{ 137 struct img_ir_priv_raw *raw = &priv->raw; 138 struct rc_dev *rdev = raw->rdev; 139 u32 irq_en; 140 141 if (!rdev) 142 return; 143 144 /* switch off and disable raw (edge) interrupts */ 145 spin_lock_irq(&priv->lock); 146 raw->rdev = NULL; 147 irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); 148 irq_en &= ~IMG_IR_IRQ_EDGE; 149 img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); 150 img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); 151 spin_unlock_irq(&priv->lock); 152 153 rc_unregister_device(rdev); 154 155 del_timer_sync(&raw->timer); 156} 157