img-ir-nec.c (4607B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * ImgTec IR Decoder setup for NEC protocol. 4 * 5 * Copyright 2010-2014 Imagination Technologies Ltd. 6 */ 7 8#include "img-ir-hw.h" 9#include <linux/bitrev.h> 10#include <linux/log2.h> 11 12/* Convert NEC data to a scancode */ 13static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, 14 struct img_ir_scancode_req *request) 15{ 16 unsigned int addr, addr_inv, data, data_inv; 17 /* a repeat code has no data */ 18 if (!len) 19 return IMG_IR_REPEATCODE; 20 if (len != 32) 21 return -EINVAL; 22 /* raw encoding: ddDDaaAA */ 23 addr = (raw >> 0) & 0xff; 24 addr_inv = (raw >> 8) & 0xff; 25 data = (raw >> 16) & 0xff; 26 data_inv = (raw >> 24) & 0xff; 27 if ((data_inv ^ data) != 0xff) { 28 /* 32-bit NEC (used by Apple and TiVo remotes) */ 29 /* scan encoding: as transmitted, MSBit = first received bit */ 30 request->scancode = bitrev8(addr) << 24 | 31 bitrev8(addr_inv) << 16 | 32 bitrev8(data) << 8 | 33 bitrev8(data_inv); 34 request->protocol = RC_PROTO_NEC32; 35 } else if ((addr_inv ^ addr) != 0xff) { 36 /* Extended NEC */ 37 /* scan encoding: AAaaDD */ 38 request->scancode = addr << 16 | 39 addr_inv << 8 | 40 data; 41 request->protocol = RC_PROTO_NECX; 42 } else { 43 /* Normal NEC */ 44 /* scan encoding: AADD */ 45 request->scancode = addr << 8 | 46 data; 47 request->protocol = RC_PROTO_NEC; 48 } 49 return IMG_IR_SCANCODE; 50} 51 52/* Convert NEC scancode to NEC data filter */ 53static int img_ir_nec_filter(const struct rc_scancode_filter *in, 54 struct img_ir_filter *out, u64 protocols) 55{ 56 unsigned int addr, addr_inv, data, data_inv; 57 unsigned int addr_m, addr_inv_m, data_m, data_inv_m; 58 59 data = in->data & 0xff; 60 data_m = in->mask & 0xff; 61 62 protocols &= RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32; 63 64 /* 65 * If only one bit is set, we were requested to do an exact 66 * protocol. This should be the case for wakeup filters; for 67 * normal filters, guess the protocol from the scancode. 68 */ 69 if (!is_power_of_2(protocols)) { 70 if ((in->data | in->mask) & 0xff000000) 71 protocols = RC_PROTO_BIT_NEC32; 72 else if ((in->data | in->mask) & 0x00ff0000) 73 protocols = RC_PROTO_BIT_NECX; 74 else 75 protocols = RC_PROTO_BIT_NEC; 76 } 77 78 if (protocols == RC_PROTO_BIT_NEC32) { 79 /* 32-bit NEC (used by Apple and TiVo remotes) */ 80 /* scan encoding: as transmitted, MSBit = first received bit */ 81 addr = bitrev8(in->data >> 24); 82 addr_m = bitrev8(in->mask >> 24); 83 addr_inv = bitrev8(in->data >> 16); 84 addr_inv_m = bitrev8(in->mask >> 16); 85 data = bitrev8(in->data >> 8); 86 data_m = bitrev8(in->mask >> 8); 87 data_inv = bitrev8(in->data >> 0); 88 data_inv_m = bitrev8(in->mask >> 0); 89 } else if (protocols == RC_PROTO_BIT_NECX) { 90 /* Extended NEC */ 91 /* scan encoding AAaaDD */ 92 addr = (in->data >> 16) & 0xff; 93 addr_m = (in->mask >> 16) & 0xff; 94 addr_inv = (in->data >> 8) & 0xff; 95 addr_inv_m = (in->mask >> 8) & 0xff; 96 data_inv = data ^ 0xff; 97 data_inv_m = data_m; 98 } else { 99 /* Normal NEC */ 100 /* scan encoding: AADD */ 101 addr = (in->data >> 8) & 0xff; 102 addr_m = (in->mask >> 8) & 0xff; 103 addr_inv = addr ^ 0xff; 104 addr_inv_m = addr_m; 105 data_inv = data ^ 0xff; 106 data_inv_m = data_m; 107 } 108 109 /* raw encoding: ddDDaaAA */ 110 out->data = data_inv << 24 | 111 data << 16 | 112 addr_inv << 8 | 113 addr; 114 out->mask = data_inv_m << 24 | 115 data_m << 16 | 116 addr_inv_m << 8 | 117 addr_m; 118 return 0; 119} 120 121/* 122 * NEC decoder 123 * See also http://www.sbprojects.com/knowledge/ir/nec.php 124 * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol 125 */ 126struct img_ir_decoder img_ir_nec = { 127 .type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32, 128 .control = { 129 .decoden = 1, 130 .code_type = IMG_IR_CODETYPE_PULSEDIST, 131 }, 132 /* main timings */ 133 .unit = 562500, /* 562.5 us */ 134 .timings = { 135 /* leader symbol */ 136 .ldr = { 137 .pulse = { 16 /* 9ms */ }, 138 .space = { 8 /* 4.5ms */ }, 139 }, 140 /* 0 symbol */ 141 .s00 = { 142 .pulse = { 1 /* 562.5 us */ }, 143 .space = { 1 /* 562.5 us */ }, 144 }, 145 /* 1 symbol */ 146 .s01 = { 147 .pulse = { 1 /* 562.5 us */ }, 148 .space = { 3 /* 1687.5 us */ }, 149 }, 150 /* free time */ 151 .ft = { 152 .minlen = 32, 153 .maxlen = 32, 154 .ft_min = 10, /* 5.625 ms */ 155 }, 156 }, 157 /* repeat codes */ 158 .repeat = 108, /* 108 ms */ 159 .rtimings = { 160 /* leader symbol */ 161 .ldr = { 162 .space = { 4 /* 2.25 ms */ }, 163 }, 164 /* free time */ 165 .ft = { 166 .minlen = 0, /* repeat code has no data */ 167 .maxlen = 0, 168 }, 169 }, 170 /* scancode logic */ 171 .scancode = img_ir_nec_scancode, 172 .filter = img_ir_nec_filter, 173};