linux/drivers/media/pci/cx23885/cx23885-ir.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Driver for the Conexant CX23885/7/8 PCIe bridge
   4 *
   5 *  Infrared device support routines - non-input, non-vl42_subdev routines
   6 *
   7 *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
   8 */
   9
  10#include "cx23885.h"
  11#include "cx23885-ir.h"
  12#include "cx23885-input.h"
  13
  14#include <media/v4l2-device.h>
  15
  16#define CX23885_IR_RX_FIFO_SERVICE_REQ          0
  17#define CX23885_IR_RX_END_OF_RX_DETECTED        1
  18#define CX23885_IR_RX_HW_FIFO_OVERRUN           2
  19#define CX23885_IR_RX_SW_FIFO_OVERRUN           3
  20
  21#define CX23885_IR_TX_FIFO_SERVICE_REQ          0
  22
  23
  24void cx23885_ir_rx_work_handler(struct work_struct *work)
  25{
  26        struct cx23885_dev *dev =
  27                             container_of(work, struct cx23885_dev, ir_rx_work);
  28        u32 events = 0;
  29        unsigned long *notifications = &dev->ir_rx_notifications;
  30
  31        if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
  32                events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
  33        if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
  34                events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
  35        if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
  36                events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
  37        if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
  38                events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
  39
  40        if (events == 0)
  41                return;
  42
  43        if (dev->kernel_ir)
  44                cx23885_input_rx_work_handler(dev, events);
  45}
  46
  47void cx23885_ir_tx_work_handler(struct work_struct *work)
  48{
  49        struct cx23885_dev *dev =
  50                             container_of(work, struct cx23885_dev, ir_tx_work);
  51        u32 events = 0;
  52        unsigned long *notifications = &dev->ir_tx_notifications;
  53
  54        if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
  55                events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
  56
  57        if (events == 0)
  58                return;
  59
  60}
  61
  62/* Possibly called in an IRQ context */
  63void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
  64{
  65        struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
  66        unsigned long *notifications = &dev->ir_rx_notifications;
  67
  68        if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
  69                set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
  70        if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
  71                set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
  72        if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
  73                set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
  74        if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
  75                set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
  76
  77        /*
  78         * For the integrated AV core, we are already in a workqueue context.
  79         * For the CX23888 integrated IR, we are in an interrupt context.
  80         */
  81        if (sd == dev->sd_cx25840)
  82                cx23885_ir_rx_work_handler(&dev->ir_rx_work);
  83        else
  84                schedule_work(&dev->ir_rx_work);
  85}
  86
  87/* Possibly called in an IRQ context */
  88void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
  89{
  90        struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
  91        unsigned long *notifications = &dev->ir_tx_notifications;
  92
  93        if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
  94                set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
  95
  96        /*
  97         * For the integrated AV core, we are already in a workqueue context.
  98         * For the CX23888 integrated IR, we are in an interrupt context.
  99         */
 100        if (sd == dev->sd_cx25840)
 101                cx23885_ir_tx_work_handler(&dev->ir_tx_work);
 102        else
 103                schedule_work(&dev->ir_tx_work);
 104}
 105