linux/drivers/media/rc/img-ir/img-ir-raw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * ImgTec IR Raw Decoder found in PowerDown Controller.
   4 *
   5 * Copyright 2010-2014 Imagination Technologies Ltd.
   6 *
   7 * This ties into the input subsystem using the RC-core in raw mode. Raw IR
   8 * signal edges are reported and decoded by generic software decoders.
   9 */
  10
  11#include <linux/spinlock.h>
  12#include <media/rc-core.h>
  13#include "img-ir.h"
  14
  15#define ECHO_TIMEOUT_MS 150     /* ms between echos */
  16
  17/* must be called with priv->lock held */
  18static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
  19{
  20        struct img_ir_priv_raw *raw = &priv->raw;
  21        struct rc_dev *rc_dev = priv->raw.rdev;
  22        int multiple;
  23        u32 ir_status;
  24
  25        /* find whether both rise and fall was detected */
  26        multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
  27        /*
  28         * If so, we need to see if the level has actually changed.
  29         * If it's just noise that we didn't have time to process,
  30         * there's no point reporting it.
  31         */
  32        ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
  33        if (multiple && ir_status == raw->last_status)
  34                return;
  35        raw->last_status = ir_status;
  36
  37        /* report the edge to the IR raw decoders */
  38        if (ir_status) /* low */
  39                ir_raw_event_store_edge(rc_dev, false);
  40        else /* high */
  41                ir_raw_event_store_edge(rc_dev, true);
  42        ir_raw_event_handle(rc_dev);
  43}
  44
  45/* called with priv->lock held */
  46void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
  47{
  48        struct img_ir_priv_raw *raw = &priv->raw;
  49
  50        /* check not removing */
  51        if (!raw->rdev)
  52                return;
  53
  54        img_ir_refresh_raw(priv, irq_status);
  55
  56        /* start / push back the echo timer */
  57        mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
  58}
  59
  60/*
  61 * Echo timer callback function.
  62 * The raw decoders expect to get a final sample even if there are no edges, in
  63 * order to be assured of the final space. If there are no edges for a certain
  64 * time we use this timer to emit a final sample to satisfy them.
  65 */
  66static void img_ir_echo_timer(struct timer_list *t)
  67{
  68        struct img_ir_priv *priv = from_timer(priv, t, raw.timer);
  69
  70        spin_lock_irq(&priv->lock);
  71
  72        /* check not removing */
  73        if (priv->raw.rdev)
  74                /*
  75                 * It's safe to pass irq_status=0 since it's only used to check
  76                 * for double edges.
  77                 */
  78                img_ir_refresh_raw(priv, 0);
  79
  80        spin_unlock_irq(&priv->lock);
  81}
  82
  83void img_ir_setup_raw(struct img_ir_priv *priv)
  84{
  85        u32 irq_en;
  86
  87        if (!priv->raw.rdev)
  88                return;
  89
  90        /* clear and enable edge interrupts */
  91        spin_lock_irq(&priv->lock);
  92        irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
  93        irq_en |= IMG_IR_IRQ_EDGE;
  94        img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
  95        img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
  96        spin_unlock_irq(&priv->lock);
  97}
  98
  99int img_ir_probe_raw(struct img_ir_priv *priv)
 100{
 101        struct img_ir_priv_raw *raw = &priv->raw;
 102        struct rc_dev *rdev;
 103        int error;
 104
 105        /* Set up the echo timer */
 106        timer_setup(&raw->timer, img_ir_echo_timer, 0);
 107
 108        /* Allocate raw decoder */
 109        raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
 110        if (!rdev) {
 111                dev_err(priv->dev, "cannot allocate raw input device\n");
 112                return -ENOMEM;
 113        }
 114        rdev->priv = priv;
 115        rdev->map_name = RC_MAP_EMPTY;
 116        rdev->device_name = "IMG Infrared Decoder Raw";
 117
 118        /* Register raw decoder */
 119        error = rc_register_device(rdev);
 120        if (error) {
 121                dev_err(priv->dev, "failed to register raw IR input device\n");
 122                rc_free_device(rdev);
 123                raw->rdev = NULL;
 124                return error;
 125        }
 126
 127        return 0;
 128}
 129
 130void img_ir_remove_raw(struct img_ir_priv *priv)
 131{
 132        struct img_ir_priv_raw *raw = &priv->raw;
 133        struct rc_dev *rdev = raw->rdev;
 134        u32 irq_en;
 135
 136        if (!rdev)
 137                return;
 138
 139        /* switch off and disable raw (edge) interrupts */
 140        spin_lock_irq(&priv->lock);
 141        raw->rdev = NULL;
 142        irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
 143        irq_en &= ~IMG_IR_IRQ_EDGE;
 144        img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
 145        img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
 146        spin_unlock_irq(&priv->lock);
 147
 148        rc_unregister_device(rdev);
 149
 150        del_timer_sync(&raw->timer);
 151}
 152