img-ir-sony.c (3936B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * ImgTec IR Decoder setup for Sony (SIRC) protocol. 4 * 5 * Copyright 2012-2014 Imagination Technologies Ltd. 6 */ 7 8#include "img-ir-hw.h" 9 10/* Convert Sony data to a scancode */ 11static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols, 12 struct img_ir_scancode_req *request) 13{ 14 unsigned int dev, subdev, func; 15 16 switch (len) { 17 case 12: 18 if (!(enabled_protocols & RC_PROTO_BIT_SONY12)) 19 return -EINVAL; 20 func = raw & 0x7f; /* first 7 bits */ 21 raw >>= 7; 22 dev = raw & 0x1f; /* next 5 bits */ 23 subdev = 0; 24 request->protocol = RC_PROTO_SONY12; 25 break; 26 case 15: 27 if (!(enabled_protocols & RC_PROTO_BIT_SONY15)) 28 return -EINVAL; 29 func = raw & 0x7f; /* first 7 bits */ 30 raw >>= 7; 31 dev = raw & 0xff; /* next 8 bits */ 32 subdev = 0; 33 request->protocol = RC_PROTO_SONY15; 34 break; 35 case 20: 36 if (!(enabled_protocols & RC_PROTO_BIT_SONY20)) 37 return -EINVAL; 38 func = raw & 0x7f; /* first 7 bits */ 39 raw >>= 7; 40 dev = raw & 0x1f; /* next 5 bits */ 41 raw >>= 5; 42 subdev = raw & 0xff; /* next 8 bits */ 43 request->protocol = RC_PROTO_SONY20; 44 break; 45 default: 46 return -EINVAL; 47 } 48 request->scancode = dev << 16 | subdev << 8 | func; 49 return IMG_IR_SCANCODE; 50} 51 52/* Convert NEC scancode to NEC data filter */ 53static int img_ir_sony_filter(const struct rc_scancode_filter *in, 54 struct img_ir_filter *out, u64 protocols) 55{ 56 unsigned int dev, subdev, func; 57 unsigned int dev_m, subdev_m, func_m; 58 unsigned int len = 0; 59 60 dev = (in->data >> 16) & 0xff; 61 dev_m = (in->mask >> 16) & 0xff; 62 subdev = (in->data >> 8) & 0xff; 63 subdev_m = (in->mask >> 8) & 0xff; 64 func = (in->data >> 0) & 0x7f; 65 func_m = (in->mask >> 0) & 0x7f; 66 67 protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | 68 RC_PROTO_BIT_SONY20; 69 70 /* 71 * If only one bit is set, we were requested to do an exact 72 * protocol. This should be the case for wakeup filters; for 73 * normal filters, guess the protocol from the scancode. 74 */ 75 if (!is_power_of_2(protocols)) { 76 if (subdev & subdev_m) 77 protocols = RC_PROTO_BIT_SONY20; 78 else if (dev & dev_m & 0xe0) 79 protocols = RC_PROTO_BIT_SONY15; 80 else 81 protocols = RC_PROTO_BIT_SONY12; 82 } 83 84 if (protocols == RC_PROTO_BIT_SONY20) { 85 /* can't encode subdev and higher device bits */ 86 if (dev & dev_m & 0xe0) 87 return -EINVAL; 88 len = 20; 89 dev_m &= 0x1f; 90 } else if (protocols == RC_PROTO_BIT_SONY15) { 91 len = 15; 92 subdev_m = 0; 93 } else { 94 /* 95 * The hardware mask cannot distinguish high device bits and low 96 * extended bits, so logically AND those bits of the masks 97 * together. 98 */ 99 subdev_m &= (dev_m >> 5) | 0xf8; 100 dev_m &= 0x1f; 101 } 102 103 /* ensure there aren't any bits straying between fields */ 104 dev &= dev_m; 105 subdev &= subdev_m; 106 107 /* write the hardware filter */ 108 out->data = func | 109 dev << 7 | 110 subdev << 15; 111 out->mask = func_m | 112 dev_m << 7 | 113 subdev_m << 15; 114 115 if (len) { 116 out->minlen = len; 117 out->maxlen = len; 118 } 119 return 0; 120} 121 122/* 123 * Sony SIRC decoder 124 * See also http://www.sbprojects.com/knowledge/ir/sirc.php 125 * http://picprojects.org.uk/projects/sirc/sonysirc.pdf 126 */ 127struct img_ir_decoder img_ir_sony = { 128 .type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20, 129 .control = { 130 .decoden = 1, 131 .code_type = IMG_IR_CODETYPE_PULSELEN, 132 }, 133 /* main timings */ 134 .unit = 600000, /* 600 us */ 135 .timings = { 136 /* leader symbol */ 137 .ldr = { 138 .pulse = { 4 /* 2.4 ms */ }, 139 .space = { 1 /* 600 us */ }, 140 }, 141 /* 0 symbol */ 142 .s00 = { 143 .pulse = { 1 /* 600 us */ }, 144 .space = { 1 /* 600 us */ }, 145 }, 146 /* 1 symbol */ 147 .s01 = { 148 .pulse = { 2 /* 1.2 ms */ }, 149 .space = { 1 /* 600 us */ }, 150 }, 151 /* free time */ 152 .ft = { 153 .minlen = 12, 154 .maxlen = 20, 155 .ft_min = 10, /* 6 ms */ 156 }, 157 }, 158 /* scancode logic */ 159 .scancode = img_ir_sony_scancode, 160 .filter = img_ir_sony_filter, 161};