2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-02-28 20:28:56 -03:00
/*
* ImgTec IR Decoder setup for NEC protocol .
*
* Copyright 2010 - 2014 Imagination Technologies Ltd .
*/
# include "img-ir-hw.h"
2014-04-04 19:05:56 -03:00
# include <linux/bitrev.h>
2016-12-05 17:08:35 -02:00
# include <linux/log2.h>
2014-02-28 20:28:56 -03:00
/* Convert NEC data to a scancode */
2014-12-11 17:06:22 -03:00
static int img_ir_nec_scancode ( int len , u64 raw , u64 enabled_protocols ,
struct img_ir_scancode_req * request )
2014-02-28 20:28:56 -03:00
{
unsigned int addr , addr_inv , data , data_inv ;
/* a repeat code has no data */
if ( ! len )
return IMG_IR_REPEATCODE ;
if ( len ! = 32 )
return - EINVAL ;
/* raw encoding: ddDDaaAA */
addr = ( raw > > 0 ) & 0xff ;
addr_inv = ( raw > > 8 ) & 0xff ;
data = ( raw > > 16 ) & 0xff ;
data_inv = ( raw > > 24 ) & 0xff ;
if ( ( data_inv ^ data ) ! = 0xff ) {
/* 32-bit NEC (used by Apple and TiVo remotes) */
2014-04-04 19:05:56 -03:00
/* scan encoding: as transmitted, MSBit = first received bit */
2014-12-11 17:06:22 -03:00
request - > scancode = bitrev8 ( addr ) < < 24 |
bitrev8 ( addr_inv ) < < 16 |
bitrev8 ( data ) < < 8 |
bitrev8 ( data_inv ) ;
2017-08-07 16:20:58 -04:00
request - > protocol = RC_PROTO_NEC32 ;
2014-02-28 20:28:56 -03:00
} else if ( ( addr_inv ^ addr ) ! = 0xff ) {
/* Extended NEC */
/* scan encoding: AAaaDD */
2014-12-11 17:06:22 -03:00
request - > scancode = addr < < 16 |
addr_inv < < 8 |
data ;
2017-08-07 16:20:58 -04:00
request - > protocol = RC_PROTO_NECX ;
2014-02-28 20:28:56 -03:00
} else {
/* Normal NEC */
/* scan encoding: AADD */
2014-12-11 17:06:22 -03:00
request - > scancode = addr < < 8 |
data ;
2017-08-07 16:20:58 -04:00
request - > protocol = RC_PROTO_NEC ;
2014-02-28 20:28:56 -03:00
}
return IMG_IR_SCANCODE ;
}
/* Convert NEC scancode to NEC data filter */
static int img_ir_nec_filter ( const struct rc_scancode_filter * in ,
struct img_ir_filter * out , u64 protocols )
{
unsigned int addr , addr_inv , data , data_inv ;
unsigned int addr_m , addr_inv_m , data_m , data_inv_m ;
data = in - > data & 0xff ;
data_m = in - > mask & 0xff ;
2017-08-07 16:20:58 -04:00
protocols & = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 ;
2016-12-05 17:08:35 -02:00
/*
* If only one bit is set , we were requested to do an exact
* protocol . This should be the case for wakeup filters ; for
* normal filters , guess the protocol from the scancode .
*/
if ( ! is_power_of_2 ( protocols ) ) {
if ( ( in - > data | in - > mask ) & 0xff000000 )
2017-08-07 16:20:58 -04:00
protocols = RC_PROTO_BIT_NEC32 ;
2016-12-05 17:08:35 -02:00
else if ( ( in - > data | in - > mask ) & 0x00ff0000 )
2017-08-07 16:20:58 -04:00
protocols = RC_PROTO_BIT_NECX ;
2016-12-05 17:08:35 -02:00
else
2017-08-07 16:20:58 -04:00
protocols = RC_PROTO_BIT_NEC ;
2016-12-05 17:08:35 -02:00
}
2017-08-07 16:20:58 -04:00
if ( protocols = = RC_PROTO_BIT_NEC32 ) {
2014-02-28 20:28:56 -03:00
/* 32-bit NEC (used by Apple and TiVo remotes) */
2014-04-04 19:05:56 -03:00
/* scan encoding: as transmitted, MSBit = first received bit */
addr = bitrev8 ( in - > data > > 24 ) ;
addr_m = bitrev8 ( in - > mask > > 24 ) ;
addr_inv = bitrev8 ( in - > data > > 16 ) ;
addr_inv_m = bitrev8 ( in - > mask > > 16 ) ;
data = bitrev8 ( in - > data > > 8 ) ;
data_m = bitrev8 ( in - > mask > > 8 ) ;
data_inv = bitrev8 ( in - > data > > 0 ) ;
data_inv_m = bitrev8 ( in - > mask > > 0 ) ;
2017-08-07 16:20:58 -04:00
} else if ( protocols = = RC_PROTO_BIT_NECX ) {
2014-02-28 20:28:56 -03:00
/* Extended NEC */
/* scan encoding AAaaDD */
addr = ( in - > data > > 16 ) & 0xff ;
addr_m = ( in - > mask > > 16 ) & 0xff ;
addr_inv = ( in - > data > > 8 ) & 0xff ;
addr_inv_m = ( in - > mask > > 8 ) & 0xff ;
data_inv = data ^ 0xff ;
data_inv_m = data_m ;
} else {
/* Normal NEC */
/* scan encoding: AADD */
addr = ( in - > data > > 8 ) & 0xff ;
addr_m = ( in - > mask > > 8 ) & 0xff ;
addr_inv = addr ^ 0xff ;
addr_inv_m = addr_m ;
data_inv = data ^ 0xff ;
data_inv_m = data_m ;
}
/* raw encoding: ddDDaaAA */
out - > data = data_inv < < 24 |
data < < 16 |
addr_inv < < 8 |
addr ;
out - > mask = data_inv_m < < 24 |
data_m < < 16 |
addr_inv_m < < 8 |
addr_m ;
return 0 ;
}
/*
* NEC decoder
* See also http : //www.sbprojects.com/knowledge/ir/nec.php
* http : //wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol
*/
struct img_ir_decoder img_ir_nec = {
2017-08-07 16:20:58 -04:00
. type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 ,
2014-02-28 20:28:56 -03:00
. control = {
. decoden = 1 ,
. code_type = IMG_IR_CODETYPE_PULSEDIST ,
} ,
/* main timings */
. unit = 562500 , /* 562.5 us */
. timings = {
/* leader symbol */
. ldr = {
. pulse = { 16 /* 9ms */ } ,
. space = { 8 /* 4.5ms */ } ,
} ,
/* 0 symbol */
. s00 = {
. pulse = { 1 /* 562.5 us */ } ,
. space = { 1 /* 562.5 us */ } ,
} ,
/* 1 symbol */
. s01 = {
. pulse = { 1 /* 562.5 us */ } ,
. space = { 3 /* 1687.5 us */ } ,
} ,
/* free time */
. ft = {
. minlen = 32 ,
. maxlen = 32 ,
. ft_min = 10 , /* 5.625 ms */
} ,
} ,
/* repeat codes */
. repeat = 108 , /* 108 ms */
. rtimings = {
/* leader symbol */
. ldr = {
. space = { 4 /* 2.25 ms */ } ,
} ,
/* free time */
. ft = {
. minlen = 0 , /* repeat code has no data */
. maxlen = 0 ,
} ,
} ,
/* scancode logic */
. scancode = img_ir_nec_scancode ,
. filter = img_ir_nec_filter ,
} ;