linux/drivers/media/rc/img-ir/img-ir-sony.c
<<
>>
Prefs
   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};
 162