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